diff options
author | Julian Eisel <eiseljulian@gmail.com> | 2018-01-30 00:53:32 +0300 |
---|---|---|
committer | Julian Eisel <eiseljulian@gmail.com> | 2018-01-30 01:24:11 +0300 |
commit | 3f0871dfcfbb1dda15c176dba92d36639305385a (patch) | |
tree | de7ffeeef7a99fc6103d413ebfa564596811087d /source/blender | |
parent | 53d94dafc474380651fc529f9c03f84ce7142b13 (diff) | |
parent | 1fe2b4bf608b22ae4513051e01cf45e5012c2409 (diff) |
Merge branch 'blender2.8' into topbar
Diffstat (limited to 'source/blender')
602 files changed, 23561 insertions, 11917 deletions
diff --git a/source/blender/alembic/intern/abc_customdata.cc b/source/blender/alembic/intern/abc_customdata.cc index d6e7a80d174..b3b015c7abf 100644 --- a/source/blender/alembic/intern/abc_customdata.cc +++ b/source/blender/alembic/intern/abc_customdata.cc @@ -235,17 +235,19 @@ static void read_uvs(const CDStreamConfig &config, void *data, MPoly *mpolys = config.mpoly; MLoopUV *mloopuvs = static_cast<MLoopUV *>(data); - unsigned int uv_index, loop_index; + unsigned int uv_index, loop_index, rev_loop_index; for (int i = 0; i < config.totpoly; ++i) { MPoly &poly = mpolys[i]; + unsigned int rev_loop_offset = poly.loopstart + poly.totloop - 1; for (int f = 0; f < poly.totloop; ++f) { loop_index = poly.loopstart + f; + rev_loop_index = rev_loop_offset - f; uv_index = (*indices)[loop_index]; const Imath::V2f &uv = (*uvs)[uv_index]; - MLoopUV &loopuv = mloopuvs[loop_index]; + MLoopUV &loopuv = mloopuvs[rev_loop_index]; loopuv.uv[0] = uv[0]; loopuv.uv[1] = uv[1]; } @@ -283,6 +285,7 @@ static void read_custom_data_mcols(const std::string & iobject_full_name, { C3fArraySamplePtr c3f_ptr = C3fArraySamplePtr(); C4fArraySamplePtr c4f_ptr = C4fArraySamplePtr(); + Alembic::Abc::UInt32ArraySamplePtr indices; bool use_c3f_ptr; bool is_facevarying; @@ -297,6 +300,7 @@ static void read_custom_data_mcols(const std::string & iobject_full_name, config.totloop == sample.getIndices()->size(); c3f_ptr = sample.getVals(); + indices = sample.getIndices(); use_c3f_ptr = true; } else if (IC4fGeomParam::matches(prop_header)) { @@ -309,6 +313,7 @@ static void read_custom_data_mcols(const std::string & iobject_full_name, config.totloop == sample.getIndices()->size(); c4f_ptr = sample.getVals(); + indices = sample.getIndices(); use_c3f_ptr = false; } else { @@ -329,6 +334,12 @@ static void read_custom_data_mcols(const std::string & iobject_full_name, size_t color_index; bool bounds_warning_given = false; + /* The colors can go through two layers of indexing. Often the 'indices' + * array doesn't do anything (i.e. indices[n] = n), but when it does, it's + * important. Blender 2.79 writes indices incorrectly (see T53745), which + * is why we have to check for indices->size() > 0 */ + bool use_dual_indexing = is_facevarying && indices->size() > 0; + for (int i = 0; i < config.totpoly; ++i) { MPoly *poly = &mpolys[i]; MCol *cface = &cfaces[poly->loopstart + poly->totloop]; @@ -338,9 +349,13 @@ static void read_custom_data_mcols(const std::string & iobject_full_name, --cface; --mloop; + color_index = is_facevarying ? face_index : mloop->v; + if (use_dual_indexing) { + color_index = (*indices)[color_index]; + } if (use_c3f_ptr) { color_index = mcols_out_of_bounds_check( - is_facevarying ? face_index : mloop->v, + color_index, c3f_ptr->size(), iobject_full_name, prop_header, bounds_warning_given); @@ -353,7 +368,7 @@ static void read_custom_data_mcols(const std::string & iobject_full_name, } else { color_index = mcols_out_of_bounds_check( - is_facevarying ? face_index : mloop->v, + color_index, c4f_ptr->size(), iobject_full_name, prop_header, bounds_warning_given); diff --git a/source/blender/avi/CMakeLists.txt b/source/blender/avi/CMakeLists.txt index 292206d8cb9..5009bd2a30b 100644 --- a/source/blender/avi/CMakeLists.txt +++ b/source/blender/avi/CMakeLists.txt @@ -26,6 +26,7 @@ set(INC . ../blenlib + ../imbuf ../../../intern/guardedalloc ) diff --git a/source/blender/avi/intern/avi.c b/source/blender/avi/intern/avi.c index 9601d6e5002..6695998fd35 100644 --- a/source/blender/avi/intern/avi.c +++ b/source/blender/avi/intern/avi.c @@ -285,13 +285,15 @@ bool AVI_is_avi(const char *name) fseek(movie.fp, movie.header->size - 14 * 4, SEEK_CUR); - if (movie.header->Streams < 1) { - DEBUG_PRINT("streams less than 1\n"); + /* Limit number of streams to some reasonable amount to prevent + * buffer oveflow vulnerabilities. */ + if (movie.header->Streams < 1 || movie.header->Streams > 65536) { + DEBUG_PRINT("Number of streams should be in range 1-65536\n"); fclose(movie.fp); return 0; } - movie.streams = (AviStreamRec *) MEM_callocN(sizeof(AviStreamRec) * movie.header->Streams, "moviestreams"); + movie.streams = (AviStreamRec *) MEM_calloc_arrayN(movie.header->Streams, sizeof(AviStreamRec), "moviestreams"); for (temp = 0; temp < movie.header->Streams; temp++) { @@ -486,12 +488,14 @@ AviError AVI_open_movie(const char *name, AviMovie *movie) fseek(movie->fp, movie->header->size - 14 * 4, SEEK_CUR); - if (movie->header->Streams < 1) { - DEBUG_PRINT("streams less than 1\n"); + /* Limit number of streams to some reasonable amount to prevent + * buffer oveflow vulnerabilities. */ + if (movie->header->Streams < 1 || movie->header->Streams > 65536) { + DEBUG_PRINT("Number of streams should be in range 1-65536\n"); return AVI_ERROR_FORMAT; } - movie->streams = (AviStreamRec *) MEM_callocN(sizeof(AviStreamRec) * movie->header->Streams, "moviestreams"); + movie->streams = (AviStreamRec *) MEM_calloc_arrayN(movie->header->Streams, sizeof(AviStreamRec), "moviestreams"); for (temp = 0; temp < movie->header->Streams; temp++) { @@ -689,7 +693,7 @@ AviError AVI_open_movie(const char *name, AviMovie *movie) void *AVI_read_frame(AviMovie *movie, AviFormat format, int frame, int stream) { - int cur_frame = -1, temp, i = 0, rewind = 1; + int cur_frame = -1, i = 0, rewind = 1; void *buffer; /* Retrieve the record number of the desired frame in the index @@ -720,16 +724,16 @@ void *AVI_read_frame(AviMovie *movie, AviFormat format, int frame, int stream) fseek(movie->fp, movie->read_offset + movie->entries[i - 1].Offset, SEEK_SET); - temp = GET_FCC(movie->fp); - buffer = MEM_mallocN(temp, "readbuffer"); + size_t size = GET_FCC(movie->fp); + buffer = MEM_mallocN(size, "readbuffer"); - if (fread(buffer, 1, temp, movie->fp) != temp) { + if (fread(buffer, 1, size, movie->fp) != size) { MEM_freeN(buffer); return NULL; } - buffer = avi_format_convert(movie, stream, buffer, movie->streams[stream].format, format, &temp); + buffer = avi_format_convert(movie, stream, buffer, movie->streams[stream].format, format, &size); return buffer; } @@ -801,6 +805,13 @@ AviError AVI_open_compress(char *name, AviMovie *movie, int streams, ...) movie->header->Reserved[2] = 0; movie->header->Reserved[3] = 0; + /* Limit number of streams to some reasonable amount to prevent + * buffer oveflow vulnerabilities. */ + if (movie->header->Streams < 0 || movie->header->Streams > 65536) { + DEBUG_PRINT("Number of streams should be in range 0-65536\n"); + return AVI_ERROR_FORMAT; + } + movie->streams = (AviStreamRec *) MEM_mallocN(sizeof(AviStreamRec) * movie->header->Streams, "moviestreams"); va_start(ap, streams); @@ -968,7 +979,6 @@ AviError AVI_write_frame(AviMovie *movie, int frame_num, ...) int64_t rec_off; AviFormat format; void *buffer; - int size; if (frame_num < 0) return AVI_ERROR_OPTION; @@ -1002,7 +1012,7 @@ AviError AVI_write_frame(AviMovie *movie, int frame_num, ...) format = va_arg(ap, AviFormat); buffer = va_arg(ap, void *); - size = va_arg(ap, int); + size_t size = va_arg(ap, int); /* Convert the buffer into the output format */ buffer = avi_format_convert(movie, stream, buffer, format, movie->streams[stream].format, &size); diff --git a/source/blender/avi/intern/avi_codecs.c b/source/blender/avi/intern/avi_codecs.c index c14d088c8ea..f52ec44faab 100644 --- a/source/blender/avi/intern/avi_codecs.c +++ b/source/blender/avi/intern/avi_codecs.c @@ -39,7 +39,7 @@ #include "avi_mjpeg.h" #include "avi_rgb32.h" -void *avi_format_convert(AviMovie *movie, int stream, void *buffer, AviFormat from, AviFormat to, int *size) +void *avi_format_convert(AviMovie *movie, int stream, void *buffer, AviFormat from, AviFormat to, size_t *size) { if (from == to) return buffer; diff --git a/source/blender/avi/intern/avi_intern.h b/source/blender/avi/intern/avi_intern.h index 0b494047612..b2fec1edfc1 100644 --- a/source/blender/avi/intern/avi_intern.h +++ b/source/blender/avi/intern/avi_intern.h @@ -59,7 +59,7 @@ unsigned int GET_TCC(FILE *fp); putc(ch2[1], fp); \ } (void)0 -void *avi_format_convert(AviMovie *movie, int stream, void *buffer, AviFormat from, AviFormat to, int *size); +void *avi_format_convert(AviMovie *movie, int stream, void *buffer, AviFormat from, AviFormat to, size_t *size); int avi_get_data_id(AviFormat format, int stream); int avi_get_format_type(AviFormat format); diff --git a/source/blender/avi/intern/avi_mjpeg.c b/source/blender/avi/intern/avi_mjpeg.c index 1fa9da6b3a2..258426809fb 100644 --- a/source/blender/avi/intern/avi_mjpeg.c +++ b/source/blender/avi/intern/avi_mjpeg.c @@ -39,15 +39,17 @@ #include "MEM_guardedalloc.h" +#include "IMB_imbuf.h" + #include "jpeglib.h" #include "jerror.h" #include "avi_mjpeg.h" -static void jpegmemdestmgr_build(j_compress_ptr cinfo, unsigned char *buffer, int bufsize); -static void jpegmemsrcmgr_build(j_decompress_ptr dinfo, unsigned char *buffer, int bufsize); +static void jpegmemdestmgr_build(j_compress_ptr cinfo, unsigned char *buffer, size_t bufsize); +static void jpegmemsrcmgr_build(j_decompress_ptr dinfo, unsigned char *buffer, size_t bufsize); -static int numbytes; +static size_t numbytes; static void add_huff_table(j_decompress_ptr dinfo, JHUFF_TBL **htblptr, const UINT8 *bits, const UINT8 *val) { @@ -151,10 +153,8 @@ static void std_huff_tables(j_decompress_ptr dinfo) bits_ac_chrominance, val_ac_chrominance); } -static int Decode_JPEG(unsigned char *inBuffer, unsigned char *outBuffer, unsigned int width, unsigned int height, int bufsize) +static int Decode_JPEG(unsigned char *inBuffer, unsigned char *outBuffer, unsigned int width, unsigned int height, size_t bufsize) { - int rowstride; - unsigned int y; struct jpeg_decompress_struct dinfo; struct jpeg_error_mgr jerr; @@ -174,8 +174,8 @@ static int Decode_JPEG(unsigned char *inBuffer, unsigned char *outBuffer, unsign jpeg_start_decompress(&dinfo); - rowstride = dinfo.output_width * dinfo.output_components; - for (y = 0; y < dinfo.output_height; y++) { + size_t rowstride = dinfo.output_width * dinfo.output_components; + for (size_t y = 0; y < dinfo.output_height; y++) { jpeg_read_scanlines(&dinfo, (JSAMPARRAY) &outBuffer, 1); outBuffer += rowstride; } @@ -194,7 +194,7 @@ static int Decode_JPEG(unsigned char *inBuffer, unsigned char *outBuffer, unsign jpeg_start_decompress(&dinfo); rowstride = dinfo.output_width * dinfo.output_components; - for (y = 0; y < dinfo.output_height; y++) { + for (size_t y = 0; y < dinfo.output_height; y++) { jpeg_read_scanlines(&dinfo, (JSAMPARRAY) &outBuffer, 1); outBuffer += rowstride; } @@ -204,10 +204,8 @@ static int Decode_JPEG(unsigned char *inBuffer, unsigned char *outBuffer, unsign return 1; } -static void Compress_JPEG(int quality, unsigned char *outbuffer, const unsigned char *inBuffer, int width, int height, int bufsize) +static void Compress_JPEG(int quality, unsigned char *outbuffer, const unsigned char *inBuffer, int width, int height, size_t bufsize) { - int i, rowstride; - unsigned int y; struct jpeg_compress_struct cinfo; struct jpeg_error_mgr jerr; unsigned char marker[60]; @@ -240,7 +238,7 @@ static void Compress_JPEG(int quality, unsigned char *outbuffer, const unsigned jpeg_start_compress(&cinfo, false); - i = 0; + int i = 0; marker[i++] = 'A'; marker[i++] = 'V'; marker[i++] = 'I'; @@ -257,8 +255,8 @@ static void Compress_JPEG(int quality, unsigned char *outbuffer, const unsigned jpeg_write_marker(&cinfo, JPEG_COM, marker, 60); - rowstride = cinfo.image_width * cinfo.input_components; - for (y = 0; y < cinfo.image_height; y++) { + size_t rowstride = cinfo.image_width * cinfo.input_components; + for (size_t y = 0; y < cinfo.image_height; y++) { jpeg_write_scanlines(&cinfo, (JSAMPARRAY) &inBuffer, 1); inBuffer += rowstride; } @@ -268,7 +266,7 @@ static void Compress_JPEG(int quality, unsigned char *outbuffer, const unsigned static void interlace(unsigned char *to, unsigned char *from, int width, int height) { - int i, rowstride = width * 3; + size_t i, rowstride = width * 3; for (i = 0; i < height; i++) { if (i & 1) @@ -280,7 +278,7 @@ static void interlace(unsigned char *to, unsigned char *from, int width, int hei static void deinterlace(int odd, unsigned char *to, unsigned char *from, int width, int height) { - int i, rowstride = width * 3; + size_t i, rowstride = width * 3; for (i = 0; i < height; i++) { if ((i & 1) == odd) @@ -290,22 +288,27 @@ static void deinterlace(int odd, unsigned char *to, unsigned char *from, int wid } } -void *avi_converter_from_mjpeg(AviMovie *movie, int stream, unsigned char *buffer, int *size) +void *avi_converter_from_mjpeg(AviMovie *movie, int stream, unsigned char *buffer, size_t *size) { int deint; unsigned char *buf; (void)stream; /* unused */ - buf = MEM_mallocN(movie->header->Height * movie->header->Width * 3, "avi.avi_converter_from_mjpeg 1"); + buf = imb_alloc_pixels(movie->header->Height, movie->header->Width, 3, sizeof(unsigned char), "avi.avi_converter_from_mjpeg 1"); + if (!buf) { + return NULL; + } deint = Decode_JPEG(buffer, buf, movie->header->Width, movie->header->Height, *size); MEM_freeN(buffer); if (deint) { - buffer = MEM_mallocN(movie->header->Height * movie->header->Width * 3, "avi.avi_converter_from_mjpeg 2"); - interlace(buffer, buf, movie->header->Width, movie->header->Height); + buffer = imb_alloc_pixels(movie->header->Height, movie->header->Width, 3, sizeof(unsigned char), "avi.avi_converter_from_mjpeg 2"); + if (buffer) { + interlace(buffer, buf, movie->header->Width, movie->header->Height); + } MEM_freeN(buf); buf = buffer; @@ -314,43 +317,50 @@ void *avi_converter_from_mjpeg(AviMovie *movie, int stream, unsigned char *buffe return buf; } -void *avi_converter_to_mjpeg(AviMovie *movie, int stream, unsigned char *buffer, int *size) +void *avi_converter_to_mjpeg(AviMovie *movie, int stream, unsigned char *buffer, size_t *size) { unsigned char *buf; - int bufsize = *size; + size_t bufsize = *size; numbytes = 0; *size = 0; - buf = MEM_mallocN(movie->header->Height * movie->header->Width * 3, "avi.avi_converter_to_mjpeg 1"); + buf = imb_alloc_pixels(movie->header->Height, movie->header->Width, 3, sizeof(unsigned char), "avi.avi_converter_to_mjpeg 1"); + if (!buf) { + return NULL; + } + if (!movie->interlace) { Compress_JPEG(movie->streams[stream].sh.Quality / 100, buf, buffer, movie->header->Width, movie->header->Height, bufsize); + *size += numbytes; } else { deinterlace(movie->odd_fields, buf, buffer, movie->header->Width, movie->header->Height); MEM_freeN(buffer); buffer = buf; - buf = MEM_mallocN(movie->header->Height * movie->header->Width * 3, "avi.avi_converter_to_mjpeg 2"); - - Compress_JPEG(movie->streams[stream].sh.Quality / 100, - buf, buffer, - movie->header->Width, - movie->header->Height / 2, - bufsize / 2); - *size += numbytes; - numbytes = 0; - Compress_JPEG(movie->streams[stream].sh.Quality / 100, - buf + *size, buffer + (movie->header->Height / 2) * movie->header->Width * 3, - movie->header->Width, - movie->header->Height / 2, - bufsize / 2); + buf = imb_alloc_pixels(movie->header->Height, movie->header->Width, 3, sizeof(unsigned char), "avi.avi_converter_to_mjpeg 1"); + + if (buf) { + Compress_JPEG(movie->streams[stream].sh.Quality / 100, + buf, buffer, + movie->header->Width, + movie->header->Height / 2, + bufsize / 2); + *size += numbytes; + numbytes = 0; + Compress_JPEG(movie->streams[stream].sh.Quality / 100, + buf + *size, buffer + (size_t)(movie->header->Height / 2) * (size_t)movie->header->Width * 3, + movie->header->Width, + movie->header->Height / 2, + bufsize / 2); + *size += numbytes; + } } - *size += numbytes; MEM_freeN(buffer); return buf; @@ -377,7 +387,7 @@ static void jpegmemdestmgr_term_destination(j_compress_ptr cinfo) MEM_freeN(cinfo->dest); } -static void jpegmemdestmgr_build(j_compress_ptr cinfo, unsigned char *buffer, int bufsize) +static void jpegmemdestmgr_build(j_compress_ptr cinfo, unsigned char *buffer, size_t bufsize) { cinfo->dest = MEM_mallocN(sizeof(*(cinfo->dest)), "avi.jpegmemdestmgr_build"); @@ -430,7 +440,7 @@ static void jpegmemsrcmgr_term_source(j_decompress_ptr dinfo) MEM_freeN(dinfo->src); } -static void jpegmemsrcmgr_build(j_decompress_ptr dinfo, unsigned char *buffer, int bufsize) +static void jpegmemsrcmgr_build(j_decompress_ptr dinfo, unsigned char *buffer, size_t bufsize) { dinfo->src = MEM_mallocN(sizeof(*(dinfo->src)), "avi.jpegmemsrcmgr_build"); diff --git a/source/blender/avi/intern/avi_mjpeg.h b/source/blender/avi/intern/avi_mjpeg.h index e8cba1849e7..e1e3cdf1fd8 100644 --- a/source/blender/avi/intern/avi_mjpeg.h +++ b/source/blender/avi/intern/avi_mjpeg.h @@ -32,7 +32,7 @@ #ifndef __AVI_MJPEG_H__ #define __AVI_MJPEG_H__ -void *avi_converter_from_mjpeg(AviMovie *movie, int stream, unsigned char *buffer, int *size); -void *avi_converter_to_mjpeg(AviMovie *movie, int stream, unsigned char *buffer, int *size); +void *avi_converter_from_mjpeg(AviMovie *movie, int stream, unsigned char *buffer, size_t *size); +void *avi_converter_to_mjpeg(AviMovie *movie, int stream, unsigned char *buffer, size_t *size); #endif /* __AVI_MJPEG_H__ */ diff --git a/source/blender/avi/intern/avi_rgb.c b/source/blender/avi/intern/avi_rgb.c index 632ecad61a6..f0baf7c6c14 100644 --- a/source/blender/avi/intern/avi_rgb.c +++ b/source/blender/avi/intern/avi_rgb.c @@ -40,11 +40,12 @@ #include "AVI_avi.h" #include "avi_rgb.h" +#include "IMB_imbuf.h" + /* implementation */ -void *avi_converter_from_avi_rgb(AviMovie *movie, int stream, unsigned char *buffer, int *size) +void *avi_converter_from_avi_rgb(AviMovie *movie, int stream, unsigned char *buffer, size_t *size) { - int x, y, i, rowstride; unsigned char *buf; AviBitmapInfoHeader *bi; short bits = 32; @@ -60,33 +61,35 @@ void *avi_converter_from_avi_rgb(AviMovie *movie, int stream, unsigned char *buf #ifdef __BIG_ENDIAN__ unsigned char *pxla; #endif - - buf = MEM_mallocN(movie->header->Height * movie->header->Width * 3, "fromavirgbbuf"); - y = movie->header->Height; - to = buf; + buf = imb_alloc_pixels(movie->header->Height, movie->header->Width, 3, sizeof(unsigned char), "fromavirgbbuf"); + + if (buf) { + size_t y = movie->header->Height; + to = buf; + + while (y--) { + pxl = (unsigned short *) (buffer + y * movie->header->Width * 2); - while (y--) { - pxl = (unsigned short *) (buffer + y * movie->header->Width * 2); - #ifdef __BIG_ENDIAN__ - pxla = (unsigned char *)pxl; + pxla = (unsigned char *)pxl; #endif - x = movie->header->Width; - while (x--) { + size_t x = movie->header->Width; + while (x--) { #ifdef __BIG_ENDIAN__ - i = pxla[0]; - pxla[0] = pxla[1]; - pxla[1] = i; - - pxla += 2; + int i = pxla[0]; + pxla[0] = pxla[1]; + pxla[1] = i; + + pxla += 2; #endif - - *(to++) = ((*pxl >> 10) & 0x1f) * 8; - *(to++) = ((*pxl >> 5) & 0x1f) * 8; - *(to++) = (*pxl & 0x1f) * 8; - pxl++; + + *(to++) = ((*pxl >> 10) & 0x1f) * 8; + *(to++) = ((*pxl >> 5) & 0x1f) * 8; + *(to++) = (*pxl & 0x1f) * 8; + pxl++; + } } } @@ -95,48 +98,49 @@ void *avi_converter_from_avi_rgb(AviMovie *movie, int stream, unsigned char *buf return buf; } else { - buf = MEM_mallocN(movie->header->Height * movie->header->Width * 3, "fromavirgbbuf"); - - rowstride = movie->header->Width * 3; - if ((bits != 16) && (movie->header->Width % 2)) rowstride++; - - for (y = 0; y < movie->header->Height; y++) { - memcpy(&buf[y * movie->header->Width * 3], &buffer[((movie->header->Height - 1) - y) * rowstride], movie->header->Width * 3); - } + buf = imb_alloc_pixels(movie->header->Height, movie->header->Width, 3, sizeof(unsigned char), "fromavirgbbuf"); - for (y = 0; y < movie->header->Height * movie->header->Width * 3; y += 3) { - i = buf[y]; - buf[y] = buf[y + 2]; - buf[y + 2] = i; + if (buf) { + size_t rowstride = movie->header->Width * 3; + if ((bits != 16) && (movie->header->Width % 2)) rowstride++; + + for (size_t y = 0; y < movie->header->Height; y++) { + memcpy(&buf[y * movie->header->Width * 3], &buffer[((movie->header->Height - 1) - y) * rowstride], movie->header->Width * 3); + } + + for (size_t y = 0; y < (size_t)movie->header->Height * (size_t)movie->header->Width * 3; y += 3) { + int i = buf[y]; + buf[y] = buf[y + 2]; + buf[y + 2] = i; + } } - + MEM_freeN(buffer); - + return buf; } } -void *avi_converter_to_avi_rgb(AviMovie *movie, int stream, unsigned char *buffer, int *size) +void *avi_converter_to_avi_rgb(AviMovie *movie, int stream, unsigned char *buffer, size_t *size) { - int y, x, i, rowstride; unsigned char *buf; (void)stream; /* unused */ - rowstride = movie->header->Width * 3; + size_t rowstride = movie->header->Width * 3; /* AVI files has uncompressed lines 4-byte aligned */ rowstride = (rowstride + 3) & ~3; *size = movie->header->Height * rowstride; buf = MEM_mallocN(*size, "toavirgbbuf"); - for (y = 0; y < movie->header->Height; y++) { + for (size_t y = 0; y < movie->header->Height; y++) { memcpy(&buf[y * rowstride], &buffer[((movie->header->Height - 1) - y) * movie->header->Width * 3], movie->header->Width * 3); } - for (y = 0; y < movie->header->Height; y++) { - for (x = 0; x < movie->header->Width * 3; x += 3) { - i = buf[y * rowstride + x]; + for (size_t y = 0; y < movie->header->Height; y++) { + for (size_t x = 0; x < movie->header->Width * 3; x += 3) { + int i = buf[y * rowstride + x]; buf[y * rowstride + x] = buf[y * rowstride + x + 2]; buf[y * rowstride + x + 2] = i; } diff --git a/source/blender/avi/intern/avi_rgb.h b/source/blender/avi/intern/avi_rgb.h index 773166e9fab..67bb4172769 100644 --- a/source/blender/avi/intern/avi_rgb.h +++ b/source/blender/avi/intern/avi_rgb.h @@ -32,7 +32,7 @@ #ifndef __AVI_RGB_H__ #define __AVI_RGB_H__ -void *avi_converter_from_avi_rgb(AviMovie *movie, int stream, unsigned char *buffer, int *size); -void *avi_converter_to_avi_rgb(AviMovie *movie, int stream, unsigned char *buffer, int *size); +void *avi_converter_from_avi_rgb(AviMovie *movie, int stream, unsigned char *buffer, size_t *size); +void *avi_converter_to_avi_rgb(AviMovie *movie, int stream, unsigned char *buffer, size_t *size); #endif /* __AVI_RGB_H__ */ diff --git a/source/blender/avi/intern/avi_rgb32.c b/source/blender/avi/intern/avi_rgb32.c index c9cbcb05bb8..051fdba1cd2 100644 --- a/source/blender/avi/intern/avi_rgb32.c +++ b/source/blender/avi/intern/avi_rgb32.c @@ -37,24 +37,28 @@ #include "MEM_guardedalloc.h" +#include "IMB_imbuf.h" + #include "AVI_avi.h" #include "avi_rgb32.h" -void *avi_converter_from_rgb32(AviMovie *movie, int stream, unsigned char *buffer, int *size) +void *avi_converter_from_rgb32(AviMovie *movie, int stream, unsigned char *buffer, size_t *size) { - int y, x, rowstridea, rowstrideb; unsigned char *buf; (void)stream; /* unused */ - buf = MEM_mallocN(movie->header->Height * movie->header->Width * 3, "fromrgb32buf"); - *size = movie->header->Height * movie->header->Width * 3; + *size = (size_t)movie->header->Height * (size_t)movie->header->Width * 3; + buf = imb_alloc_pixels(movie->header->Height, movie->header->Width, 3, sizeof(unsigned char), "fromrgb32buf"); + if (!buf) { + return NULL; + } - rowstridea = movie->header->Width * 3; - rowstrideb = movie->header->Width * 4; + size_t rowstridea = movie->header->Width * 3; + size_t rowstrideb = movie->header->Width * 4; - for (y = 0; y < movie->header->Height; y++) { - for (x = 0; x < movie->header->Width; x++) { + for (size_t y = 0; y < movie->header->Height; y++) { + for (size_t x = 0; x < movie->header->Width; x++) { buf[y * rowstridea + x * 3 + 0] = buffer[y * rowstrideb + x * 4 + 3]; buf[y * rowstridea + x * 3 + 1] = buffer[y * rowstrideb + x * 4 + 2]; buf[y * rowstridea + x * 3 + 2] = buffer[y * rowstrideb + x * 4 + 1]; @@ -66,21 +70,23 @@ void *avi_converter_from_rgb32(AviMovie *movie, int stream, unsigned char *buffe return buf; } -void *avi_converter_to_rgb32(AviMovie *movie, int stream, unsigned char *buffer, int *size) +void *avi_converter_to_rgb32(AviMovie *movie, int stream, unsigned char *buffer, size_t *size) { - int i; unsigned char *buf; unsigned char *to, *from; (void)stream; /* unused */ - *size = movie->header->Height * movie->header->Width * 4; - buf = MEM_mallocN(*size, "torgb32buf"); + *size = (size_t)movie->header->Height * (size_t)movie->header->Width * 4; + buf = imb_alloc_pixels(movie->header->Height, movie->header->Width, 3, sizeof(unsigned char), "torgb32buf"); + if (!buf) { + return NULL; + } memset(buf, 255, *size); to = buf; from = buffer; - i = movie->header->Height * movie->header->Width; + size_t i = (size_t)movie->header->Height * (size_t)movie->header->Width; while (i--) { memcpy(to, from, 3); diff --git a/source/blender/avi/intern/avi_rgb32.h b/source/blender/avi/intern/avi_rgb32.h index 523f9e795fd..a9373a69821 100644 --- a/source/blender/avi/intern/avi_rgb32.h +++ b/source/blender/avi/intern/avi_rgb32.h @@ -32,7 +32,7 @@ #ifndef __AVI_RGB32_H__ #define __AVI_RGB32_H__ -void *avi_converter_from_rgb32(AviMovie *movie, int stream, unsigned char *buffer, int *size); -void *avi_converter_to_rgb32(AviMovie *movie, int stream, unsigned char *buffer, int *size); +void *avi_converter_from_rgb32(AviMovie *movie, int stream, unsigned char *buffer, size_t *size); +void *avi_converter_to_rgb32(AviMovie *movie, int stream, unsigned char *buffer, size_t *size); #endif /* __AVI_RGB32_H__ */ diff --git a/source/blender/blenkernel/BKE_action.h b/source/blender/blenkernel/BKE_action.h index 28be2b04c71..f7ebe85bcef 100644 --- a/source/blender/blenkernel/BKE_action.h +++ b/source/blender/blenkernel/BKE_action.h @@ -55,7 +55,7 @@ extern "C" { /* Action Lib Stuff ----------------- */ /* Allocate a new bAction with the given name */ -struct bAction *add_empty_action(struct Main *bmain, const char name[]); +struct bAction *BKE_action_add(struct Main *bmain, const char name[]); void BKE_action_copy_data(struct Main *bmain, struct bAction *act_dst, const struct bAction *act_src, const int flag); /* Allocate a copy of the given Action and all its data */ diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h index 8d326c6441c..ceb466ebdcd 100644 --- a/source/blender/blenkernel/BKE_blender_version.h +++ b/source/blender/blenkernel/BKE_blender_version.h @@ -28,7 +28,7 @@ * and keep comment above the defines. * Use STRINGIFY() rather than defining with quotes */ #define BLENDER_VERSION 280 -#define BLENDER_SUBVERSION 2 +#define BLENDER_SUBVERSION 4 /* Several breakages with 270, e.g. constraint deg vs rad */ #define BLENDER_MINVERSION 270 #define BLENDER_MINSUBVERSION 6 diff --git a/source/blender/blenkernel/BKE_bvhutils.h b/source/blender/blenkernel/BKE_bvhutils.h index cb72f0859d5..b3122f8adb9 100644 --- a/source/blender/blenkernel/BKE_bvhutils.h +++ b/source/blender/blenkernel/BKE_bvhutils.h @@ -46,7 +46,7 @@ struct MFace; typedef struct LinkNode BVHCache; /** - * struct that kepts basic information about a BVHTree build from a editmesh + * Struct that stores basic information about a BVHTree built from a edit-mesh. */ typedef struct BVHTreeFromEditMesh { struct BVHTree *tree; @@ -66,7 +66,7 @@ typedef struct BVHTreeFromEditMesh { } BVHTreeFromEditMesh; /** - * struct that kepts basic information about a BVHTree build from a mesh + * Struct that stores basic information about a BVHTree built from a mesh. */ typedef struct BVHTreeFromMesh { struct BVHTree *tree; diff --git a/source/blender/blenkernel/BKE_camera.h b/source/blender/blenkernel/BKE_camera.h index f69ac7e01cd..d5bf2177f71 100644 --- a/source/blender/blenkernel/BKE_camera.h +++ b/source/blender/blenkernel/BKE_camera.h @@ -39,6 +39,7 @@ extern "C" { #include "DNA_vec_types.h" struct Camera; +struct Depsgraph; struct Main; struct Object; struct RegionView3D; @@ -113,7 +114,7 @@ typedef struct CameraParams { void BKE_camera_params_init(CameraParams *params); void BKE_camera_params_from_object(CameraParams *params, const struct Object *camera); -void BKE_camera_params_from_view3d(CameraParams *params, const struct View3D *v3d, const struct RegionView3D *rv3d); +void BKE_camera_params_from_view3d(CameraParams *params, const struct Depsgraph *depsgraph, const struct View3D *v3d, const struct RegionView3D *rv3d); void BKE_camera_params_compute_viewplane(CameraParams *params, int winx, int winy, float aspx, float aspy); void BKE_camera_params_compute_matrix(CameraParams *params); diff --git a/source/blender/blenkernel/BKE_colorband.h b/source/blender/blenkernel/BKE_colorband.h new file mode 100644 index 00000000000..edb724d2aec --- /dev/null +++ b/source/blender/blenkernel/BKE_colorband.h @@ -0,0 +1,52 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * ***** END GPL LICENSE BLOCK ***** + */ +#ifndef __BKE_COLORBAND_H__ +#define __BKE_COLORBAND_H__ + +/** \file BKE_colorband.h + */ + +#ifdef __cplusplus +extern "C" { +#endif + +struct ColorBand; + +/* in ColorBand struct */ +#define MAXCOLORBAND 32 + +void BKE_colorband_init(struct ColorBand *coba, bool rangetype); +void BKE_colorband_init_from_table_rgba( + struct ColorBand *coba, const float (*array)[4], const int array_len, bool filter_sample); +struct ColorBand *BKE_colorband_add(bool rangetype); +bool BKE_colorband_evaluate(const struct ColorBand *coba, float in, float out[4]); +void BKE_colorband_evaluate_table_rgba(const struct ColorBand *coba, float **array, int *size); +struct CBData *BKE_colorband_element_add(struct ColorBand *coba, float position); +int BKE_colorband_element_remove(struct ColorBand *coba, int index); +void BKE_colorband_update_sort(struct ColorBand *coba); + +#ifdef __cplusplus +} +#endif + +#endif /* __BKE_COLORBAND_H__ */ diff --git a/source/blender/blenkernel/BKE_context.h b/source/blender/blenkernel/BKE_context.h index 31d26d5d4fa..3d53f28c185 100644 --- a/source/blender/blenkernel/BKE_context.h +++ b/source/blender/blenkernel/BKE_context.h @@ -118,7 +118,8 @@ enum { CTX_MODE_PAINT_VERTEX, CTX_MODE_PAINT_TEXTURE, CTX_MODE_PARTICLE, - CTX_MODE_OBJECT + CTX_MODE_OBJECT, + CTX_MODE_NUM /* must be last */ }; /* Context */ diff --git a/source/blender/blenkernel/BKE_font.h b/source/blender/blenkernel/BKE_font.h index 60ad061bf77..e5eea4423c9 100644 --- a/source/blender/blenkernel/BKE_font.h +++ b/source/blender/blenkernel/BKE_font.h @@ -86,7 +86,7 @@ struct VFont *BKE_vfont_load_exists(struct Main *bmain, const char *filepath); void BKE_vfont_make_local(struct Main *bmain, struct VFont *vfont, const bool lib_local); -bool BKE_vfont_to_curve_ex(struct Main *bmain, struct Object *ob, int mode, +bool BKE_vfont_to_curve_ex(struct Main *bmain, struct Object *ob, struct Curve *cu, int mode, struct ListBase *r_nubase, const wchar_t **r_text, int *r_text_len, bool *r_text_free, struct CharTrans **r_chartransdata); diff --git a/source/blender/blenkernel/BKE_freestyle.h b/source/blender/blenkernel/BKE_freestyle.h index 1045fde0039..f7368683d93 100644 --- a/source/blender/blenkernel/BKE_freestyle.h +++ b/source/blender/blenkernel/BKE_freestyle.h @@ -49,7 +49,7 @@ typedef struct FreestyleModuleSettings FreestyleModuleSettings; /* FreestyleConfig */ void BKE_freestyle_config_init(FreestyleConfig *config); -void BKE_freestyle_config_free(FreestyleConfig *config); +void BKE_freestyle_config_free(FreestyleConfig *config, const bool do_id_user); void BKE_freestyle_config_copy(FreestyleConfig *new_config, FreestyleConfig *config, const int flag); /* FreestyleConfig.modules */ diff --git a/source/blender/blenkernel/BKE_group.h b/source/blender/blenkernel/BKE_group.h index ac436876dc4..74255cfc941 100644 --- a/source/blender/blenkernel/BKE_group.h +++ b/source/blender/blenkernel/BKE_group.h @@ -55,10 +55,17 @@ bool BKE_group_is_animated(struct Group *group, struct Object *parent); void BKE_group_handle_recalc_and_update(const struct EvaluationContext *eval_ctx, struct Scene *scene, struct Object *parent, struct Group *group); +/* Dependency graph evaluation. */ + +void BKE_group_eval_view_layers(const struct EvaluationContext *eval_ctx, + struct Group *group); + +/* Helper macros. */ + #define FOREACH_GROUP_BASE(_group, _base) \ for (Base *_base = (Base *)(_group)->view_layer->object_bases.first; \ _base; \ - _base = _base->next) \ + _base = _base->next) \ { #define FOREACH_GROUP_BASE_END \ @@ -67,7 +74,7 @@ void BKE_group_handle_recalc_and_update(const struct EvaluationContext #define FOREACH_GROUP_OBJECT(_group, _object) \ for (Base *_base = (Base *)(_group)->view_layer->object_bases.first; \ _base; \ - _base = _base->next) \ + _base = _base->next) \ { \ Object *_object = _base->object; \ BLI_assert(_object != NULL); diff --git a/source/blender/blenkernel/BKE_idprop.h b/source/blender/blenkernel/BKE_idprop.h index 055c530d255..02912739e86 100644 --- a/source/blender/blenkernel/BKE_idprop.h +++ b/source/blender/blenkernel/BKE_idprop.h @@ -32,6 +32,10 @@ #include "BLI_compiler_attrs.h" +#ifdef __cplusplus +extern "C" { +#endif + struct IDProperty; struct ID; @@ -119,6 +123,8 @@ void IDP_ClearProperty(IDProperty *prop); void IDP_RelinkProperty(struct IDProperty *prop); +void IDP_Reset(IDProperty *prop, const IDProperty *reference); + #define IDP_Int(prop) ((prop)->data.val) #define IDP_Array(prop) ((prop)->data.pointer) /* C11 const correctness for casts */ @@ -151,4 +157,8 @@ void IDP_RelinkProperty(struct IDProperty *prop); void IDP_spit(IDProperty *prop); #endif +#ifdef __cplusplus +} +#endif + #endif /* __BKE_IDPROP_H__ */ diff --git a/source/blender/blenkernel/BKE_lamp.h b/source/blender/blenkernel/BKE_lamp.h index 56b72282513..aa655c66477 100644 --- a/source/blender/blenkernel/BKE_lamp.h +++ b/source/blender/blenkernel/BKE_lamp.h @@ -46,7 +46,7 @@ void BKE_lamp_init(struct Lamp *la); struct Lamp *BKE_lamp_add(struct Main *bmain, const char *name) ATTR_WARN_UNUSED_RESULT; void BKE_lamp_copy_data(struct Main *bmain, struct Lamp *la_dst, const struct Lamp *la_src, const int flag); struct Lamp *BKE_lamp_copy(struct Main *bmain, const struct Lamp *la) ATTR_WARN_UNUSED_RESULT; -struct Lamp *localize_lamp(struct Lamp *la) ATTR_WARN_UNUSED_RESULT; +struct Lamp *BKE_lamp_localize(struct Lamp *la) ATTR_WARN_UNUSED_RESULT; void BKE_lamp_make_local(struct Main *bmain, struct Lamp *la, const bool lib_local); void BKE_lamp_free(struct Lamp *la); diff --git a/source/blender/blenkernel/BKE_layer.h b/source/blender/blenkernel/BKE_layer.h index e4f8b8790f6..b605b208f66 100644 --- a/source/blender/blenkernel/BKE_layer.h +++ b/source/blender/blenkernel/BKE_layer.h @@ -33,7 +33,6 @@ extern "C" { #endif -#define TODO_LAYER_SYNC_FILTER /* syncing of filter_objects across all trees */ #define TODO_LAYER_OVERRIDE /* CollectionOverride */ #define TODO_LAYER_OPERATORS /* collection mamanger and property panel operators */ #define TODO_LAYER /* generic todo */ @@ -66,6 +65,7 @@ struct ViewLayer *BKE_view_layer_group_add(struct Group *group); struct ViewLayer *BKE_view_layer_context_active_PLACEHOLDER(const struct Scene *scene); void BKE_view_layer_free(struct ViewLayer *view_layer); +void BKE_view_layer_free_ex(struct ViewLayer *view_layer, const bool do_id_user); void BKE_view_layer_selected_objects_tag(struct ViewLayer *view_layer, const int tag); @@ -102,7 +102,6 @@ struct LayerCollection *BKE_collection_link(struct ViewLayer *view_layer, struct void BKE_collection_unlink(struct ViewLayer *view_layer, struct LayerCollection *lc); void BKE_collection_enable(struct ViewLayer *view_layer, struct LayerCollection *lc); -void BKE_collection_disable(struct ViewLayer *view_layer, struct LayerCollection *lc); bool BKE_view_layer_has_collection(struct ViewLayer *view_layer, const struct SceneCollection *sc); bool BKE_scene_has_object(struct Scene *scene, struct Object *ob); diff --git a/source/blender/blenkernel/BKE_library.h b/source/blender/blenkernel/BKE_library.h index 0abf99415c7..f3df8b9b363 100644 --- a/source/blender/blenkernel/BKE_library.h +++ b/source/blender/blenkernel/BKE_library.h @@ -51,9 +51,9 @@ struct PointerRNA; struct PropertyRNA; size_t BKE_libblock_get_alloc_info(short type, const char **name); -void *BKE_libblock_alloc_notest(short type); -void *BKE_libblock_alloc(struct Main *bmain, short type, const char *name, const int flag) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); -void BKE_libblock_init_empty(struct ID *id); +void *BKE_libblock_alloc_notest(short type) ATTR_WARN_UNUSED_RESULT; +void *BKE_libblock_alloc(struct Main *bmain, short type, const char *name, const int flag) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1); +void BKE_libblock_init_empty(struct ID *id) ATTR_NONNULL(1); /** * New ID creation/copying options. diff --git a/source/blender/blenkernel/BKE_library_override.h b/source/blender/blenkernel/BKE_library_override.h index 1ba009660f2..35672cb5ded 100644 --- a/source/blender/blenkernel/BKE_library_override.h +++ b/source/blender/blenkernel/BKE_library_override.h @@ -43,7 +43,8 @@ void BKE_override_static_copy(struct ID *dst_id, const struct ID *src_id); void BKE_override_static_clear(struct IDOverrideStatic *override); void BKE_override_static_free(struct IDOverrideStatic **override); -struct ID *BKE_override_static_create_from(struct Main *bmain, struct ID *reference_id); +struct ID *BKE_override_static_create_from_id(struct Main *bmain, struct ID *reference_id); +bool BKE_override_static_create_from_tag(struct Main *bmain); struct IDOverrideStaticProperty *BKE_override_static_property_find(struct IDOverrideStatic *override, const char *rna_path); struct IDOverrideStaticProperty *BKE_override_static_property_get(struct IDOverrideStatic *override, const char *rna_path, bool *r_created); diff --git a/source/blender/blenkernel/BKE_main.h b/source/blender/blenkernel/BKE_main.h index faa91fd4f79..79f56cf25ef 100644 --- a/source/blender/blenkernel/BKE_main.h +++ b/source/blender/blenkernel/BKE_main.h @@ -147,7 +147,8 @@ typedef struct Main { #define BLEN_THUMB_SIZE 128 -#define BLEN_THUMB_MEMSIZE(_x, _y) (sizeof(BlendThumbnail) + (size_t)((_x) * (_y)) * sizeof(int)) +#define BLEN_THUMB_MEMSIZE(_x, _y) (sizeof(BlendThumbnail) + ((size_t)(_x) * (size_t)(_y)) * sizeof(int)) +#define BLEN_THUMB_SAFE_MEMSIZE(_x, _y) ((uint64_t)_x * (uint64_t)_y < (SIZE_MAX / (sizeof(int) * 4))) #ifdef __cplusplus } diff --git a/source/blender/blenkernel/BKE_mask.h b/source/blender/blenkernel/BKE_mask.h index 5598f0dc473..8b9fea071b0 100644 --- a/source/blender/blenkernel/BKE_mask.h +++ b/source/blender/blenkernel/BKE_mask.h @@ -145,7 +145,6 @@ void BKE_mask_update_display(struct Mask *mask, float ctime); void BKE_mask_evaluate_all_masks(struct Main *bmain, float ctime, const bool do_newframe); void BKE_mask_evaluate(struct Mask *mask, const float ctime, const bool do_newframe); void BKE_mask_layer_evaluate(struct MaskLayer *masklay, const float ctime, const bool do_newframe); -void BKE_mask_update_scene(struct Main *bmain, struct Scene *scene); void BKE_mask_parent_init(struct MaskParent *parent); void BKE_mask_calc_handle_adjacent_interp(struct MaskSpline *spline, struct MaskSplinePoint *point, const float u); void BKE_mask_calc_tangent_polyline(struct MaskSpline *spline, struct MaskSplinePoint *point, float t[2]); diff --git a/source/blender/blenkernel/BKE_material.h b/source/blender/blenkernel/BKE_material.h index cb4ee9c2543..f4c98fc0aea 100644 --- a/source/blender/blenkernel/BKE_material.h +++ b/source/blender/blenkernel/BKE_material.h @@ -56,7 +56,7 @@ void BKE_material_remap_object_calc(struct Object *ob_dst, struct Object *ob_sr struct Material *BKE_material_add(struct Main *bmain, const char *name); void BKE_material_copy_data(struct Main *bmain, struct Material *ma_dst, const struct Material *ma_src, const int flag); struct Material *BKE_material_copy(struct Main *bmain, const struct Material *ma); -struct Material *localize_material(struct Material *ma); +struct Material *BKE_material_localize(struct Material *ma); struct Material *give_node_material(struct Material *ma); /* returns node material or self */ void BKE_material_make_local(struct Main *bmain, struct Material *ma, const bool lib_local); diff --git a/source/blender/blenkernel/BKE_movieclip.h b/source/blender/blenkernel/BKE_movieclip.h index 0bdff3eb795..bd193b82b9e 100644 --- a/source/blender/blenkernel/BKE_movieclip.h +++ b/source/blender/blenkernel/BKE_movieclip.h @@ -74,8 +74,8 @@ void BKE_movieclip_build_proxy_frame(struct MovieClip *clip, int clip_flag, stru void BKE_movieclip_build_proxy_frame_for_ibuf(struct MovieClip *clip, struct ImBuf *ibuf, struct MovieDistortion *distortion, int cfra, int *build_sizes, int build_count, bool undistorted); -float BKE_movieclip_remap_scene_to_clip_frame(struct MovieClip *clip, float framenr); -float BKE_movieclip_remap_clip_to_scene_frame(struct MovieClip *clip, float framenr); +float BKE_movieclip_remap_scene_to_clip_frame(const struct MovieClip *clip, float framenr); +float BKE_movieclip_remap_clip_to_scene_frame(const struct MovieClip *clip, float framenr); void BKE_movieclip_filename_for_frame(struct MovieClip *clip, struct MovieClipUser *user, char *name); struct ImBuf *BKE_movieclip_anim_ibuf_for_frame(struct MovieClip *clip, struct MovieClipUser *user); diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index 39535ffd403..4e30cb076d4 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -448,6 +448,7 @@ struct bNodeSocket *nodeInsertStaticSocket(struct bNodeTree *ntree, struct bNode struct bNodeSocket *next_sock, const char *identifier, const char *name); void nodeRemoveSocket(struct bNodeTree *ntree, struct bNode *node, struct bNodeSocket *sock); void nodeRemoveAllSockets(struct bNodeTree *ntree, struct bNode *node); +void nodeModifySocketType(struct bNodeTree *ntree, struct bNode *node, struct bNodeSocket *sock, int type, int subtype); struct bNode *nodeAddNode(const struct bContext *C, struct bNodeTree *ntree, const char *idname); struct bNode *nodeAddStaticNode(const struct bContext *C, struct bNodeTree *ntree, int type); @@ -514,7 +515,7 @@ int BKE_node_clipboard_get_type(void); /* Node Instance Hash */ typedef struct bNodeInstanceHash { - GHash *ghash; /* XXX should be made a direct member, GHash allocation needs to support it */ + GHash *ghash; /* XXX should be made a direct member, GHash allocation needs to support it */ } bNodeInstanceHash; typedef void (*bNodeInstanceValueFP)(void *value); @@ -799,6 +800,7 @@ struct ShadeResult; #define SH_NODE_BSDF_PRINCIPLED 193 #define SH_NODE_EEVEE_SPECULAR 195 #define SH_NODE_BEVEL 197 +#define SH_NODE_DISPLACEMENT 198 /* custom defines options for Material node */ #define SH_NODE_MAT_DIFF 1 diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h index 2b183906f57..d98c52aa91a 100644 --- a/source/blender/blenkernel/BKE_object.h +++ b/source/blender/blenkernel/BKE_object.h @@ -82,7 +82,14 @@ bool BKE_object_exists_check(struct Object *obtest); bool BKE_object_is_in_editmode(struct Object *ob); bool BKE_object_is_in_editmode_vgroup(struct Object *ob); bool BKE_object_is_in_wpaint_select_vert(struct Object *ob); -bool BKE_object_is_visible(struct Object *ob); + +typedef enum eObjectVisibilityCheck { + OB_VISIBILITY_CHECK_FOR_VIEWPORT, + OB_VISIBILITY_CHECK_FOR_RENDER, + OB_VISIBILITY_CHECK_UNKNOWN_RENDER_MODE, +} eObjectVisibilityCheck; + +bool BKE_object_is_visible(struct Object *ob, const eObjectVisibilityCheck mode); void BKE_object_init(struct Object *ob); struct Object *BKE_object_add_only_object( diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h index 31f4695201c..b952859e508 100644 --- a/source/blender/blenkernel/BKE_paint.h +++ b/source/blender/blenkernel/BKE_paint.h @@ -157,7 +157,7 @@ float paint_grid_paint_mask(const struct GridPaintMask *gpm, unsigned level, unsigned x, unsigned y); /* stroke related */ -void paint_calculate_rake_rotation(struct UnifiedPaintSettings *ups, struct Brush *brush, const float mouse_pos[2]); +bool paint_calculate_rake_rotation(struct UnifiedPaintSettings *ups, struct Brush *brush, const float mouse_pos[2]); void paint_update_brush_rake_rotation(struct UnifiedPaintSettings *ups, struct Brush *brush, float rotation); void BKE_paint_stroke_get_average(struct Scene *scene, struct Object *ob, float stroke[3]); @@ -196,6 +196,7 @@ typedef struct SculptSession { /* PBVH acceleration structure */ struct PBVH *pbvh; bool show_diffuse_color; + bool show_mask; /* Painting on deformed mesh */ bool modifiers_active; /* object is deformed with some modifiers */ diff --git a/source/blender/blenkernel/BKE_particle.h b/source/blender/blenkernel/BKE_particle.h index 1776872f455..8bc521c515f 100644 --- a/source/blender/blenkernel/BKE_particle.h +++ b/source/blender/blenkernel/BKE_particle.h @@ -246,7 +246,8 @@ typedef struct ParticleDrawData { float *cdata, *cd; /* color data */ float *vedata, *ved; /* velocity data */ float *ma_col; - int tot_vec_size, flag; + int totpart, partsize; + int flag; int totpoint, totve; } ParticleDrawData; @@ -326,7 +327,7 @@ struct ParticleSystemModifierData *psys_get_modifier(struct Object *ob, struct P struct ModifierData *object_add_particle_system(struct Scene *scene, struct Object *ob, const char *name); void object_remove_particle_system(struct Scene *scene, struct Object *ob); -struct ParticleSettings *psys_new_settings(const char *name, struct Main *main); +struct ParticleSettings *BKE_particlesettings_add(struct Main *main, const char *name); void BKE_particlesettings_copy_data( struct Main *bmain, struct ParticleSettings *part_dst, const struct ParticleSettings *part_src, const int flag); diff --git a/source/blender/blenkernel/BKE_pbvh.h b/source/blender/blenkernel/BKE_pbvh.h index 9aea5dc95a0..5f37aa25de7 100644 --- a/source/blender/blenkernel/BKE_pbvh.h +++ b/source/blender/blenkernel/BKE_pbvh.h @@ -375,5 +375,6 @@ bool BKE_pbvh_node_vert_update_check_any(PBVH *bvh, PBVHNode *node); bool pbvh_has_mask(PBVH *bvh); void pbvh_show_diffuse_color_set(PBVH *bvh, bool show_diffuse_color); +void pbvh_show_mask_set(PBVH *bvh, bool show_mask); #endif /* __BKE_PBVH_H__ */ diff --git a/source/blender/blenkernel/BKE_subsurf.h b/source/blender/blenkernel/BKE_subsurf.h index 92170325113..96320415b16 100644 --- a/source/blender/blenkernel/BKE_subsurf.h +++ b/source/blender/blenkernel/BKE_subsurf.h @@ -34,6 +34,9 @@ /* struct DerivedMesh is used directly */ #include "BKE_DerivedMesh.h" +/* Thread sync primitives used directly. */ +#include "BLI_threads.h" + struct CCGElem; struct DMFlagMat; struct DMGridAdjacency; @@ -140,6 +143,9 @@ typedef struct CCGDerivedMesh { } multires; struct EdgeHash *ehash; + + ThreadMutex loops_cache_lock; + ThreadRWMutex origindex_cache_rwlock; } CCGDerivedMesh; #ifdef WITH_OPENSUBDIV diff --git a/source/blender/blenkernel/BKE_texture.h b/source/blender/blenkernel/BKE_texture.h index 8a9171673ea..4e98852c995 100644 --- a/source/blender/blenkernel/BKE_texture.h +++ b/source/blender/blenkernel/BKE_texture.h @@ -60,14 +60,6 @@ struct World; #define MAXCOLORBAND 32 -void init_colorband(struct ColorBand *coba, bool rangetype); -struct ColorBand *add_colorband(bool rangetype); -bool do_colorband(const struct ColorBand *coba, float in, float out[4]); -void colorband_table_RGBA(struct ColorBand *coba, float **array, int *size); -struct CBData *colorband_element_add(struct ColorBand *coba, float position); -int colorband_element_remove(struct ColorBand *coba, int index); -void colorband_update_sort(struct ColorBand *coba); - void BKE_texture_free(struct Tex *tex); void BKE_texture_default(struct Tex *tex); void BKE_texture_copy_data(struct Main *bmain, struct Tex *tex_dst, const struct Tex *tex_src, const int flag); diff --git a/source/blender/blenkernel/BKE_tracking.h b/source/blender/blenkernel/BKE_tracking.h index b4ca1b79238..5da87de1cc9 100644 --- a/source/blender/blenkernel/BKE_tracking.h +++ b/source/blender/blenkernel/BKE_tracking.h @@ -289,6 +289,46 @@ void BKE_tracking_stabilization_data_to_mat4(int width, int height, float aspect void BKE_tracking_dopesheet_tag_update(struct MovieTracking *tracking); void BKE_tracking_dopesheet_update(struct MovieTracking *tracking); +/* **** Query/search **** */ + +struct MovieTrackingObject *BKE_tracking_find_object_for_track( + const struct MovieTracking *tracking, + const struct MovieTrackingTrack *track); +struct ListBase *BKE_tracking_find_tracks_list_for_track( + struct MovieTracking *tracking, + const struct MovieTrackingTrack *track); + +struct MovieTrackingObject *BKE_tracking_find_object_for_plane_track( + const struct MovieTracking *tracking, + const struct MovieTrackingPlaneTrack *plane_track); +struct ListBase *BKE_tracking_find_tracks_list_for_plane_track( + struct MovieTracking *tracking, + const struct MovieTrackingPlaneTrack *plane_track); + + +void BKE_tracking_get_rna_path_for_track( + const struct MovieTracking *tracking, + const struct MovieTrackingTrack *track, + char *rna_path, + size_t rna_path_len); +void BKE_tracking_get_rna_path_prefix_for_track( + const struct MovieTracking *tracking, + const struct MovieTrackingTrack *track, + char *rna_path, + size_t rna_path_len); +void BKE_tracking_get_rna_path_for_plane_track( + const struct MovieTracking *tracking, + const struct MovieTrackingPlaneTrack *plane_track, + char *rna_path, + size_t rna_path_len); +void BKE_tracking_get_rna_path_prefix_for_plane_track( + const struct MovieTracking *tracking, + const struct MovieTrackingPlaneTrack *plane_track, + char *rna_path, + size_t rna_path_len); + +/* **** Utility macros **** */ + #define TRACK_SELECTED(track) ((track)->flag & SELECT || (track)->pat_flag & SELECT || (track)->search_flag & SELECT) #define TRACK_AREA_SELECTED(track, area) ((area) == TRACK_AREA_POINT ? (track)->flag & SELECT : \ diff --git a/source/blender/blenkernel/BKE_world.h b/source/blender/blenkernel/BKE_world.h index ea0cd125b06..b45d7a7e6ec 100644 --- a/source/blender/blenkernel/BKE_world.h +++ b/source/blender/blenkernel/BKE_world.h @@ -38,10 +38,10 @@ struct World; void BKE_world_free(struct World *sc); void BKE_world_init(struct World *wrld); -struct World *add_world(struct Main *bmian, const char *name); +struct World *BKE_world_add(struct Main *bmain, const char *name); void BKE_world_copy_data(struct Main *bmain, struct World *wrld_dst, const struct World *wrld_src, const int flag); struct World *BKE_world_copy(struct Main *bmain, const struct World *wrld); -struct World *localize_world(struct World *wrld); +struct World *BKE_world_localize(struct World *wrld); void BKE_world_make_local(struct Main *bmain, struct World *wrld, const bool lib_local); /* Evaluation. */ diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index c99c3d6ffa9..279068c440e 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -89,6 +89,7 @@ set(SRC intern/cloth.c intern/collection.c intern/collision.c + intern/colorband.c intern/colortools.c intern/constraint.c intern/context.c @@ -225,6 +226,7 @@ set(SRC BKE_cloth.h BKE_collection.h BKE_collision.h + BKE_colorband.h BKE_colortools.h BKE_constraint.h BKE_context.h diff --git a/source/blender/blenkernel/intern/CCGSubSurf.h b/source/blender/blenkernel/intern/CCGSubSurf.h index 4c913e79586..8cdbd2a7a98 100644 --- a/source/blender/blenkernel/intern/CCGSubSurf.h +++ b/source/blender/blenkernel/intern/CCGSubSurf.h @@ -73,6 +73,9 @@ typedef enum { #define CCG_OMP_LIMIT 1000000 +/* TODO(sergey): This actually depends on subsurf level as well. */ +#define CCG_TASK_LIMIT 16 + /***/ CCGSubSurf* ccgSubSurf_new (CCGMeshIFC *ifc, int subdivisionLevels, CCGAllocatorIFC *allocatorIFC, CCGAllocatorHDL allocator); diff --git a/source/blender/blenkernel/intern/CCGSubSurf_legacy.c b/source/blender/blenkernel/intern/CCGSubSurf_legacy.c index f68d1a2697c..756935b50ba 100644 --- a/source/blender/blenkernel/intern/CCGSubSurf_legacy.c +++ b/source/blender/blenkernel/intern/CCGSubSurf_legacy.c @@ -136,7 +136,10 @@ typedef struct CCGSubSurfCalcSubdivData { int curLvl; } CCGSubSurfCalcSubdivData; -static void ccgSubSurf__calcVertNormals_faces_accumulate_cb(void *userdata, int ptrIdx) +static void ccgSubSurf__calcVertNormals_faces_accumulate_cb( + void *__restrict userdata, + const int ptrIdx, + const ParallelRangeTLS *__restrict UNUSED(tls)) { CCGSubSurfCalcSubdivData *data = userdata; @@ -227,7 +230,10 @@ static void ccgSubSurf__calcVertNormals_faces_accumulate_cb(void *userdata, int } } -static void ccgSubSurf__calcVertNormals_faces_finalize_cb(void *userdata, int ptrIdx) +static void ccgSubSurf__calcVertNormals_faces_finalize_cb( + void *__restrict userdata, + const int ptrIdx, + const ParallelRangeTLS *__restrict UNUSED(tls)) { CCGSubSurfCalcSubdivData *data = userdata; @@ -265,7 +271,10 @@ static void ccgSubSurf__calcVertNormals_faces_finalize_cb(void *userdata, int pt } } -static void ccgSubSurf__calcVertNormals_edges_accumulate_cb(void *userdata, int ptrIdx) +static void ccgSubSurf__calcVertNormals_edges_accumulate_cb( + void *__restrict userdata, + const int ptrIdx, + const ParallelRangeTLS *__restrict UNUSED(tls)) { CCGSubSurfCalcSubdivData *data = userdata; @@ -328,10 +337,15 @@ static void ccgSubSurf__calcVertNormals(CCGSubSurf *ss, .numEffectedF = numEffectedF }; - BLI_task_parallel_range(0, numEffectedF, - &data, - ccgSubSurf__calcVertNormals_faces_accumulate_cb, - numEffectedF * edgeSize * edgeSize * 4 >= CCG_OMP_LIMIT); + { + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.min_iter_per_thread = CCG_TASK_LIMIT; + BLI_task_parallel_range(0, numEffectedF, + &data, + ccgSubSurf__calcVertNormals_faces_accumulate_cb, + &settings); + } /* XXX can I reduce the number of normalisations here? */ for (ptrIdx = 0; ptrIdx < numEffectedV; ptrIdx++) { @@ -357,15 +371,25 @@ static void ccgSubSurf__calcVertNormals(CCGSubSurf *ss, } } - BLI_task_parallel_range(0, numEffectedE, - &data, - ccgSubSurf__calcVertNormals_edges_accumulate_cb, - numEffectedE * edgeSize * 4 >= CCG_OMP_LIMIT); + { + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.min_iter_per_thread = CCG_TASK_LIMIT; + BLI_task_parallel_range(0, numEffectedE, + &data, + ccgSubSurf__calcVertNormals_edges_accumulate_cb, + &settings); + } - BLI_task_parallel_range(0, numEffectedF, - &data, - ccgSubSurf__calcVertNormals_faces_finalize_cb, - numEffectedF * edgeSize * edgeSize * 4 >= CCG_OMP_LIMIT); + { + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.min_iter_per_thread = CCG_TASK_LIMIT; + BLI_task_parallel_range(0, numEffectedF, + &data, + ccgSubSurf__calcVertNormals_faces_finalize_cb, + &settings); + } for (ptrIdx = 0; ptrIdx < numEffectedE; ptrIdx++) { CCGEdge *e = (CCGEdge *) effectedE[ptrIdx]; @@ -396,7 +420,10 @@ static void ccgSubSurf__calcVertNormals(CCGSubSurf *ss, } -static void ccgSubSurf__calcSubdivLevel_interior_faces_edges_midpoints_cb(void *userdata, int ptrIdx) +static void ccgSubSurf__calcSubdivLevel_interior_faces_edges_midpoints_cb( + void *__restrict userdata, + const int ptrIdx, + const ParallelRangeTLS *__restrict UNUSED(tls)) { CCGSubSurfCalcSubdivData *data = userdata; @@ -483,7 +510,10 @@ static void ccgSubSurf__calcSubdivLevel_interior_faces_edges_midpoints_cb(void * } } -static void ccgSubSurf__calcSubdivLevel_interior_faces_edges_centerpoints_shift_cb(void *userdata, int ptrIdx) +static void ccgSubSurf__calcSubdivLevel_interior_faces_edges_centerpoints_shift_cb( + void *__restrict userdata, + const int ptrIdx, + const ParallelRangeTLS *__restrict UNUSED(tls)) { CCGSubSurfCalcSubdivData *data = userdata; @@ -588,7 +618,10 @@ static void ccgSubSurf__calcSubdivLevel_interior_faces_edges_centerpoints_shift_ } } -static void ccgSubSurf__calcSubdivLevel_verts_copydata_cb(void *userdata, int ptrIdx) +static void ccgSubSurf__calcSubdivLevel_verts_copydata_cb( + void *__restrict userdata, + const int ptrIdx, + const ParallelRangeTLS *__restrict UNUSED(tls)) { CCGSubSurfCalcSubdivData *data = userdata; @@ -647,10 +680,15 @@ static void ccgSubSurf__calcSubdivLevel( .curLvl = curLvl }; - BLI_task_parallel_range(0, numEffectedF, - &data, - ccgSubSurf__calcSubdivLevel_interior_faces_edges_midpoints_cb, - numEffectedF * edgeSize * edgeSize * 4 >= CCG_OMP_LIMIT); + { + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.min_iter_per_thread = CCG_TASK_LIMIT; + BLI_task_parallel_range(0, numEffectedF, + &data, + ccgSubSurf__calcSubdivLevel_interior_faces_edges_midpoints_cb, + &settings); + } /* exterior edge midpoints * - old exterior edge points @@ -925,10 +963,15 @@ static void ccgSubSurf__calcSubdivLevel( } } - BLI_task_parallel_range(0, numEffectedF, - &data, - ccgSubSurf__calcSubdivLevel_interior_faces_edges_centerpoints_shift_cb, - numEffectedF * edgeSize * edgeSize * 4 >= CCG_OMP_LIMIT); + { + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.min_iter_per_thread = CCG_TASK_LIMIT; + BLI_task_parallel_range(0, numEffectedF, + &data, + ccgSubSurf__calcSubdivLevel_interior_faces_edges_centerpoints_shift_cb, + &settings); + } /* copy down */ edgeSize = ccg_edgesize(nextLvl); @@ -940,10 +983,15 @@ static void ccgSubSurf__calcSubdivLevel( VertDataCopy(EDGE_getCo(e, nextLvl, edgeSize - 1), VERT_getCo(e->v1, nextLvl), ss); } - BLI_task_parallel_range(0, numEffectedF, - &data, - ccgSubSurf__calcSubdivLevel_verts_copydata_cb, - numEffectedF * edgeSize * edgeSize * 4 >= CCG_OMP_LIMIT); + { + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.min_iter_per_thread = CCG_TASK_LIMIT; + BLI_task_parallel_range(0, numEffectedF, + &data, + ccgSubSurf__calcSubdivLevel_verts_copydata_cb, + &settings); + } } void ccgSubSurf__sync_legacy(CCGSubSurf *ss) diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c index 1367157c13c..cfeca50a751 100644 --- a/source/blender/blenkernel/intern/DerivedMesh.c +++ b/source/blender/blenkernel/intern/DerivedMesh.c @@ -52,6 +52,7 @@ #include "BLI_task.h" #include "BKE_cdderivedmesh.h" +#include "BKE_colorband.h" #include "BKE_editmesh.h" #include "BKE_key.h" #include "BKE_layer.h" @@ -64,7 +65,6 @@ #include "BKE_object.h" #include "BKE_object_deform.h" #include "BKE_paint.h" -#include "BKE_texture.h" #include "BKE_multires.h" #include "BKE_bvhutils.h" #include "BKE_deform.h" @@ -187,7 +187,7 @@ static MPoly *dm_getPolyArray(DerivedMesh *dm) static MVert *dm_dupVertArray(DerivedMesh *dm) { - MVert *tmp = MEM_mallocN(sizeof(*tmp) * dm->getNumVerts(dm), + MVert *tmp = MEM_malloc_arrayN(dm->getNumVerts(dm), sizeof(*tmp), "dm_dupVertArray tmp"); if (tmp) dm->copyVertArray(dm, tmp); @@ -197,7 +197,7 @@ static MVert *dm_dupVertArray(DerivedMesh *dm) static MEdge *dm_dupEdgeArray(DerivedMesh *dm) { - MEdge *tmp = MEM_mallocN(sizeof(*tmp) * dm->getNumEdges(dm), + MEdge *tmp = MEM_malloc_arrayN(dm->getNumEdges(dm), sizeof(*tmp), "dm_dupEdgeArray tmp"); if (tmp) dm->copyEdgeArray(dm, tmp); @@ -207,7 +207,7 @@ static MEdge *dm_dupEdgeArray(DerivedMesh *dm) static MFace *dm_dupFaceArray(DerivedMesh *dm) { - MFace *tmp = MEM_mallocN(sizeof(*tmp) * dm->getNumTessFaces(dm), + MFace *tmp = MEM_malloc_arrayN(dm->getNumTessFaces(dm), sizeof(*tmp), "dm_dupFaceArray tmp"); if (tmp) dm->copyTessFaceArray(dm, tmp); @@ -217,7 +217,7 @@ static MFace *dm_dupFaceArray(DerivedMesh *dm) static MLoop *dm_dupLoopArray(DerivedMesh *dm) { - MLoop *tmp = MEM_mallocN(sizeof(*tmp) * dm->getNumLoops(dm), + MLoop *tmp = MEM_malloc_arrayN(dm->getNumLoops(dm), sizeof(*tmp), "dm_dupLoopArray tmp"); if (tmp) dm->copyLoopArray(dm, tmp); @@ -227,7 +227,7 @@ static MLoop *dm_dupLoopArray(DerivedMesh *dm) static MPoly *dm_dupPolyArray(DerivedMesh *dm) { - MPoly *tmp = MEM_mallocN(sizeof(*tmp) * dm->getNumPolys(dm), + MPoly *tmp = MEM_malloc_arrayN(dm->getNumPolys(dm), sizeof(*tmp), "dm_dupPolyArray tmp"); if (tmp) dm->copyPolyArray(dm, tmp); @@ -529,7 +529,7 @@ void DM_ensure_looptri_data(DerivedMesh *dm) if (totpoly) { if (dm->looptris.array_wip == NULL) { - dm->looptris.array_wip = MEM_mallocN(sizeof(*dm->looptris.array_wip) * looptris_num, __func__); + dm->looptris.array_wip = MEM_malloc_arrayN(looptris_num, sizeof(*dm->looptris.array_wip), __func__); dm->looptris.num_alloc = looptris_num; } @@ -577,7 +577,7 @@ void DM_update_tessface_data(DerivedMesh *dm) CustomData_has_layer(fdata, CD_TESSLOOPNORMAL) || CustomData_has_layer(fdata, CD_TANGENT)) { - loopindex = MEM_mallocN(sizeof(*loopindex) * totface, __func__); + loopindex = MEM_malloc_arrayN(totface, sizeof(*loopindex), __func__); for (mf_idx = 0, mf = mface; mf_idx < totface; mf_idx++, mf++) { const int mf_len = mf->v4 ? 4 : 3; @@ -637,7 +637,7 @@ void DM_generate_tangent_tessface_data(DerivedMesh *dm, bool generate) CustomData_bmesh_update_active_layers(fdata, ldata); if (!loopindex) { - loopindex = MEM_mallocN(sizeof(*loopindex) * totface, __func__); + loopindex = MEM_malloc_arrayN(totface, sizeof(*loopindex), __func__); for (mf_idx = 0, mf = mface; mf_idx < totface; mf_idx++, mf++) { const int mf_len = mf->v4 ? 4 : 3; unsigned int *ml_idx = loopindex[mf_idx]; @@ -682,7 +682,7 @@ void DM_update_materials(DerivedMesh *dm, Object *ob) if (dm->mat) MEM_freeN(dm->mat); - dm->mat = MEM_mallocN(totmat * sizeof(*dm->mat), "DerivedMesh.mat"); + dm->mat = MEM_malloc_arrayN(totmat, sizeof(*dm->mat), "DerivedMesh.mat"); } /* we leave last material as empty - rationale here is being able to index @@ -872,7 +872,7 @@ void DM_to_meshkey(DerivedMesh *dm, Mesh *me, KeyBlock *kb) } if (kb->data) MEM_freeN(kb->data); - kb->data = MEM_mallocN(me->key->elemsize * me->totvert, "kb->data"); + kb->data = MEM_malloc_arrayN(me->key->elemsize, me->totvert, "kb->data"); kb->totelem = totvert; fp = kb->data; @@ -1208,7 +1208,7 @@ static float (*get_editbmesh_orco_verts(BMEditMesh *em))[3] /* these may not really be the orco's, but it's only for preview. * could be solver better once, but isn't simple */ - orco = MEM_mallocN(sizeof(float) * 3 * em->bm->totvert, "BMEditMesh Orco"); + orco = MEM_malloc_arrayN(em->bm->totvert, sizeof(float) * 3, "BMEditMesh Orco"); BM_ITER_MESH_INDEX (eve, &iter, em->bm, BM_VERTS_OF_MESH, i) { copy_v3_v3(orco[i], eve->co); @@ -1282,7 +1282,7 @@ static void add_orco_dm( totvert = dm->getNumVerts(dm); if (orcodm) { - orco = MEM_callocN(sizeof(float[3]) * totvert, "dm orco"); + orco = MEM_calloc_arrayN(totvert, sizeof(float[3]), "dm orco"); free = 1; if (orcodm->getNumVerts(orcodm) == totvert) @@ -1379,7 +1379,7 @@ static void weightpaint_color(unsigned char r_col[4], DMWeightColorInfo *dm_wcin float colf[4]; if (dm_wcinfo && dm_wcinfo->coba) { - do_colorband(dm_wcinfo->coba, input, colf); + BKE_colorband_evaluate(dm_wcinfo->coba, input, colf); } else { weight_to_rgb(colf, input); @@ -1564,7 +1564,7 @@ void DM_update_weight_mcol( wtcol_v = em->derivedVertColor; } else { - wtcol_v = MEM_mallocN(sizeof(*wtcol_v) * numVerts, __func__); + wtcol_v = MEM_malloc_arrayN(numVerts, sizeof(*wtcol_v), __func__); } /* Weights are given by caller. */ @@ -1573,7 +1573,7 @@ void DM_update_weight_mcol( /* If indices is not NULL, it means we do not have weights for all vertices, * so we must create them (and set them to zero)... */ if (indices) { - w = MEM_callocN(sizeof(float) * numVerts, "Temp weight array DM_update_weight_mcol"); + w = MEM_calloc_arrayN(numVerts, sizeof(float), "Temp weight array DM_update_weight_mcol"); i = num; while (i--) w[indices[i]] = weights[i]; @@ -1605,7 +1605,7 @@ void DM_update_weight_mcol( /* now add to loops, so the data can be passed through the modifier stack * If no CD_PREVIEW_MLOOPCOL existed yet, we have to add a new one! */ if (!wtcol_l) { - wtcol_l = MEM_mallocN(sizeof(*wtcol_l) * dm_totloop, __func__); + wtcol_l = MEM_malloc_arrayN(dm_totloop, sizeof(*wtcol_l), __func__); CustomData_add_layer(&dm->loopData, CD_PREVIEW_MLOOPCOL, CD_ASSIGN, wtcol_l, dm_totloop); } @@ -1660,7 +1660,7 @@ static void shapekey_layers_to_keyblocks(DerivedMesh *dm, Mesh *me, int actshape cos = CustomData_get_layer_n(&dm->vertData, CD_SHAPEKEY, i); kb->totelem = dm->numVertData; - kb->data = kbcos = MEM_mallocN(sizeof(float) * 3 * kb->totelem, "kbcos DerivedMesh.c"); + kb->data = kbcos = MEM_malloc_arrayN(kb->totelem, sizeof(float), "kbcos DerivedMesh.c"); if (kb->uid == actshape_uid) { MVert *mvert = dm->getVertArray(dm); @@ -1681,7 +1681,7 @@ static void shapekey_layers_to_keyblocks(DerivedMesh *dm, Mesh *me, int actshape MEM_freeN(kb->data); kb->totelem = dm->numVertData; - kb->data = MEM_callocN(sizeof(float) * 3 * kb->totelem, "kb->data derivedmesh.c"); + kb->data = MEM_calloc_arrayN(kb->totelem, 3 * sizeof(float), "kb->data derivedmesh.c"); fprintf(stderr, "%s: lost a shapekey layer: '%s'! (bmesh internal error)\n", __func__, kb->name); } } @@ -1692,7 +1692,6 @@ static void add_shapekey_layers(DerivedMesh *dm, Mesh *me, Object *UNUSED(ob)) KeyBlock *kb; Key *key = me->key; int i; - const size_t shape_alloc_len = sizeof(float) * 3 * me->totvert; if (!me->key) return; @@ -1713,11 +1712,11 @@ static void add_shapekey_layers(DerivedMesh *dm, Mesh *me, Object *UNUSED(ob)) fprintf(stderr, "%s: vertex size mismatch (Mesh '%s':%d != KeyBlock '%s':%d)\n", __func__, me->id.name + 2, me->totvert, kb->name, kb->totelem); - array = MEM_callocN(shape_alloc_len, __func__); + array = MEM_calloc_arrayN((size_t)me->totvert, 3 * sizeof(float), __func__); } else { - array = MEM_mallocN(shape_alloc_len, __func__); - memcpy(array, kb->data, shape_alloc_len); + array = MEM_malloc_arrayN((size_t)me->totvert, 3 * sizeof(float), __func__); + memcpy(array, kb->data, (size_t)me->totvert * 3 * sizeof(float)); } CustomData_add_layer_named(&dm->vertData, CD_SHAPEKEY, CD_ASSIGN, array, dm->numVertData, kb->name); @@ -1990,7 +1989,7 @@ static void mesh_calc_modifiers( */ numVerts = dm->getNumVerts(dm); deformedVerts = - MEM_mallocN(sizeof(*deformedVerts) * numVerts, "dfmv"); + MEM_malloc_arrayN(numVerts, sizeof(*deformedVerts), "dfmv"); dm->getVertCos(dm, deformedVerts); } else { @@ -2283,7 +2282,7 @@ float (*editbmesh_get_vertex_cos(BMEditMesh *em, int *r_numVerts))[3] *r_numVerts = em->bm->totvert; - cos = MEM_mallocN(sizeof(float) * 3 * em->bm->totvert, "vertexcos"); + cos = MEM_malloc_arrayN(em->bm->totvert, 3 * sizeof(float), "vertexcos"); BM_ITER_MESH_INDEX (eve, &iter, em->bm, BM_VERTS_OF_MESH, i) { copy_v3_v3(cos[i], eve->co); @@ -2389,7 +2388,7 @@ static void editbmesh_calc_modifiers( */ numVerts = dm->getNumVerts(dm); deformedVerts = - MEM_mallocN(sizeof(*deformedVerts) * numVerts, "dfmv"); + MEM_malloc_arrayN(numVerts, sizeof(*deformedVerts), "dfmv"); dm->getVertCos(dm, deformedVerts); } else { @@ -3010,11 +3009,11 @@ DMCoNo *mesh_get_mapped_verts_nors(Scene *scene, Object *ob) dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH | CD_MASK_ORIGINDEX); if (dm->foreachMappedVert) { - vertexcosnos = MEM_callocN(sizeof(DMCoNo) * me->totvert, "vertexcosnos map"); + vertexcosnos = MEM_calloc_arrayN(me->totvert, sizeof(DMCoNo), "vertexcosnos map"); dm->foreachMappedVert(dm, make_vertexcosnos__mapFunc, vertexcosnos); } else { - DMCoNo *v_co_no = vertexcosnos = MEM_mallocN(sizeof(DMCoNo) * me->totvert, "vertexcosnos map"); + DMCoNo *v_co_no = vertexcosnos = MEM_malloc_arrayN(me->totvert, sizeof(DMCoNo), "vertexcosnos map"); int a; for (a = 0; a < me->totvert; a++, v_co_no++) { dm->getVertCo(dm, a, v_co_no->co); @@ -3907,7 +3906,7 @@ MVert *DM_get_vert_array(DerivedMesh *dm, bool *allocated) *allocated = false; if (mvert == NULL) { - mvert = MEM_mallocN(sizeof(MVert) * dm->getNumVerts(dm), "dmvh vert data array"); + mvert = MEM_malloc_arrayN(dm->getNumVerts(dm), sizeof(MVert), "dmvh vert data array"); dm->copyVertArray(dm, mvert); *allocated = true; } @@ -3922,7 +3921,7 @@ MEdge *DM_get_edge_array(DerivedMesh *dm, bool *allocated) *allocated = false; if (medge == NULL) { - medge = MEM_mallocN(sizeof(MEdge) * dm->getNumEdges(dm), "dm medge data array"); + medge = MEM_malloc_arrayN(dm->getNumEdges(dm), sizeof(MEdge), "dm medge data array"); dm->copyEdgeArray(dm, medge); *allocated = true; } @@ -3937,7 +3936,7 @@ MLoop *DM_get_loop_array(DerivedMesh *dm, bool *r_allocated) *r_allocated = false; if (mloop == NULL) { - mloop = MEM_mallocN(sizeof(MLoop) * dm->getNumLoops(dm), "dm loop data array"); + mloop = MEM_malloc_arrayN(dm->getNumLoops(dm), sizeof(MLoop), "dm loop data array"); dm->copyLoopArray(dm, mloop); *r_allocated = true; } @@ -3952,7 +3951,7 @@ MPoly *DM_get_poly_array(DerivedMesh *dm, bool *r_allocated) *r_allocated = false; if (mpoly == NULL) { - mpoly = MEM_mallocN(sizeof(MPoly) * dm->getNumPolys(dm), "dm poly data array"); + mpoly = MEM_malloc_arrayN(dm->getNumPolys(dm), sizeof(MPoly), "dm poly data array"); dm->copyPolyArray(dm, mpoly); *r_allocated = true; } @@ -3970,7 +3969,7 @@ MFace *DM_get_tessface_array(DerivedMesh *dm, bool *r_allocated) int numTessFaces = dm->getNumTessFaces(dm); if (numTessFaces > 0) { - mface = MEM_mallocN(sizeof(MFace) * numTessFaces, "bvh mface data array"); + mface = MEM_malloc_arrayN(numTessFaces, sizeof(MFace), "bvh mface data array"); dm->copyTessFaceArray(dm, mface); *r_allocated = true; } diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c index 88c0aa6f35a..acb2db8d7ad 100644 --- a/source/blender/blenkernel/intern/action.c +++ b/source/blender/blenkernel/intern/action.c @@ -85,7 +85,7 @@ /* ***************** Library data level operations on action ************** */ -bAction *add_empty_action(Main *bmain, const char name[]) +bAction *BKE_action_add(Main *bmain, const char name[]) { bAction *act; diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c index 07de2ad6342..844a2a50bb3 100644 --- a/source/blender/blenkernel/intern/anim_sys.c +++ b/source/blender/blenkernel/intern/anim_sys.c @@ -75,6 +75,8 @@ #include "nla_private.h" +#include "atomic_ops.h" + /* ***************************************** */ /* AnimData API */ @@ -527,7 +529,7 @@ void BKE_animdata_separate_by_basepath(ID *srcID, ID *dstID, ListBase *basepaths if (srcAdt->action) { /* set up an action if necessary, and name it in a similar way so that it can be easily found again */ if (dstAdt->action == NULL) { - dstAdt->action = add_empty_action(G.main, srcAdt->action->id.name + 2); + dstAdt->action = BKE_action_add(G.main, srcAdt->action->id.name + 2); } else if (dstAdt->action == srcAdt->action) { printf("Argh! Source and Destination share animation! ('%s' and '%s' both use '%s') Making new empty action\n", @@ -535,7 +537,7 @@ void BKE_animdata_separate_by_basepath(ID *srcID, ID *dstID, ListBase *basepaths /* TODO: review this... */ id_us_min(&dstAdt->action->id); - dstAdt->action = add_empty_action(G.main, dstAdt->action->id.name + 2); + dstAdt->action = BKE_action_add(G.main, dstAdt->action->id.name + 2); } /* loop over base paths, trying to fix for each one... */ @@ -818,7 +820,7 @@ char *BKE_animsys_fix_rna_path_rename(ID *owner_id, char *old_path, const char * /* if no action, no need to proceed */ if (ELEM(NULL, owner_id, old_path)) { - printf("early abort\n"); + if (G.debug & G_DEBUG) printf("%s: early abort\n", __func__); return old_path; } @@ -841,9 +843,9 @@ char *BKE_animsys_fix_rna_path_rename(ID *owner_id, char *old_path, const char * } /* fix given path */ - printf("%s | %s | oldpath = %p ", oldN, newN, old_path); + if (G.debug & G_DEBUG) printf("%s | %s | oldpath = %p ", oldN, newN, old_path); result = rna_path_rename_fix(owner_id, prefix, oldN, newN, old_path, verify_paths); - printf("result = %p\n", result); + if (G.debug & G_DEBUG) printf("path rename result = %p\n", result); /* free the temp names */ MEM_freeN(oldN); @@ -1563,12 +1565,6 @@ static bool animsys_write_rna_setting(PathResolvedRNA *anim_rna, const float val /* caller must ensure this is animatable */ BLI_assert(RNA_property_animateable(ptr, prop) || ptr->id.data == NULL); - /* set value for animatable numerical values only - * HACK: some local F-Curves (e.g. those on NLA Strips) are evaluated - * without an ID provided, which causes the animateable test to fail! - */ - bool written = false; - switch (RNA_property_type(prop)) { case PROP_BOOLEAN: { @@ -1576,13 +1572,11 @@ static bool animsys_write_rna_setting(PathResolvedRNA *anim_rna, const float val if (array_index != -1) { if (RNA_property_boolean_get_index(ptr, prop, array_index) != value_coerce) { RNA_property_boolean_set_index(ptr, prop, array_index, value_coerce); - written = true; } } else { if (RNA_property_boolean_get(ptr, prop) != value_coerce) { RNA_property_boolean_set(ptr, prop, value_coerce); - written = true; } } break; @@ -1594,13 +1588,11 @@ static bool animsys_write_rna_setting(PathResolvedRNA *anim_rna, const float val if (array_index != -1) { if (RNA_property_int_get_index(ptr, prop, array_index) != value_coerce) { RNA_property_int_set_index(ptr, prop, array_index, value_coerce); - written = true; } } else { if (RNA_property_int_get(ptr, prop) != value_coerce) { RNA_property_int_set(ptr, prop, value_coerce); - written = true; } } break; @@ -1612,13 +1604,11 @@ static bool animsys_write_rna_setting(PathResolvedRNA *anim_rna, const float val if (array_index != -1) { if (RNA_property_float_get_index(ptr, prop, array_index) != value_coerce) { RNA_property_float_set_index(ptr, prop, array_index, value_coerce); - written = true; } } else { if (RNA_property_float_get(ptr, prop) != value_coerce) { RNA_property_float_set(ptr, prop, value_coerce); - written = true; } } break; @@ -1628,7 +1618,6 @@ static bool animsys_write_rna_setting(PathResolvedRNA *anim_rna, const float val const int value_coerce = (int)value; if (RNA_property_enum_get(ptr, prop) != value_coerce) { RNA_property_enum_set(ptr, prop, value_coerce); - written = true; } break; } @@ -1657,20 +1646,6 @@ static bool animsys_write_rna_setting(PathResolvedRNA *anim_rna, const float val } #endif - /* as long as we don't do property update, we still tag datablock - * as having been updated. this flag does not cause any updates to - * be run, it's for e.g. render engines to synchronize data */ - if (written && ptr->id.data) { - ID *id = ptr->id.data; - - /* for cases like duplifarmes it's only a temporary so don't - * notify anyone of updates */ - if (!(id->tag & LIB_TAG_ANIM_NO_RECALC)) { - BKE_id_tag_set_atomic(id, LIB_TAG_ID_RECALC); - DEG_id_type_tag(G.main, GS(id->name)); - } - } - /* successful */ return true; } @@ -2614,17 +2589,6 @@ static void animsys_evaluate_nla(ListBase *echannels, PointerRNA *ptr, AnimData /* 3. free temporary evaluation data that's not used elsewhere */ BLI_freelistN(&estrips); - - /* Tag ID as updated so render engines will recognize changes in data - * which is animated but doesn't have actions. - */ - if (ptr->id.data != NULL) { - ID *id = ptr->id.data; - if (!(id->tag & LIB_TAG_ANIM_NO_RECALC)) { - id->tag |= LIB_TAG_ID_RECALC; - DEG_id_type_tag(G.main, GS(id->name)); - } - } } /* NLA Evaluation function (mostly for use through do_animdata) @@ -2921,7 +2885,7 @@ void BKE_animsys_eval_animdata(const EvaluationContext *eval_ctx, ID *id) { AnimData *adt = BKE_animdata_from_id(id); Scene *scene = NULL; /* XXX: this is only needed for flushing RNA updates, - * which should get handled as part of the graph instead... + * which should get handled as part of the dependency graph instead... */ DEBUG_PRINT("%s on %s, time=%f\n\n", __func__, id->name, (double)eval_ctx->ctime); BKE_animsys_evaluate_animdata(scene, id, adt, eval_ctx->ctime, ADT_RECALC_ANIM); diff --git a/source/blender/blenkernel/intern/blender.c b/source/blender/blenkernel/intern/blender.c index 50764e10ceb..182b88c1c57 100644 --- a/source/blender/blenkernel/intern/blender.c +++ b/source/blender/blenkernel/intern/blender.c @@ -247,7 +247,6 @@ void BKE_blender_userdef_data_free(UserDef *userdef, bool clear_fonts) void BKE_blender_userdef_app_template_data_swap(UserDef *userdef_a, UserDef *userdef_b) { /* TODO: - * - keymaps * - various minor settings (add as needed). */ @@ -263,9 +262,15 @@ void BKE_blender_userdef_app_template_data_swap(UserDef *userdef_a, UserDef *use SWAP(ListBase, userdef_a->id, userdef_b->id); \ } ((void)0) - /* for some types we need custom free functions */ - LIST_SWAP(addons); - LIST_SWAP(user_keymaps); +#define FLAG_SWAP(id, ty, flags) { \ + CHECK_TYPE(&(userdef_a->id), ty *); \ + const ty f = flags; \ + const ty a = userdef_a->id; \ + const ty b = userdef_b->id; \ + userdef_a->id = (userdef_a->id & ~f) | (b & f); \ + userdef_b->id = (userdef_b->id & ~f) | (a & f); \ +} ((void)0) + LIST_SWAP(uistyles); LIST_SWAP(uifonts); @@ -277,10 +282,18 @@ void BKE_blender_userdef_app_template_data_swap(UserDef *userdef_a, UserDef *use DATA_SWAP(font_path_ui); DATA_SWAP(font_path_ui_mono); + DATA_SWAP(keyconfigstr); + + DATA_SWAP(manipulator_flag); + DATA_SWAP(app_flag); + + /* We could add others. */ + FLAG_SWAP(uiflag, int, USER_QUIT_PROMPT); #undef SWAP_TYPELESS -#undef LIST_SWAP #undef DATA_SWAP +#undef LIST_SWAP +#undef FLAG_SWAP } void BKE_blender_userdef_app_template_data_set(UserDef *userdef) diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c index 230db6dccff..8d63c1cfb44 100644 --- a/source/blender/blenkernel/intern/brush.c +++ b/source/blender/blenkernel/intern/brush.c @@ -148,6 +148,9 @@ void BKE_brush_init(Brush *brush) BKE_brush_curve_preset(brush, CURVE_PRESET_SMOOTH); } +/** + * \note Resulting brush will have two users: one as a fake user, another is assumed to be used by the caller. + */ Brush *BKE_brush_add(Main *bmain, const char *name, short ob_mode) { Brush *brush; @@ -1063,7 +1066,8 @@ struct ImBuf *BKE_brush_gen_radial_control_imbuf(Brush *br, bool secondary) for (i = 0; i < side; ++i) { for (j = 0; j < side; ++j) { const int col = texcache[i * side + j]; - im->rect_float[i * side + j] *= (((char *)&col)[0] + ((char *)&col)[1] + ((char *)&col)[2]) / 3.0f / 255.0f; + im->rect_float[i * side + j] *= + (((char *)&col)[0] + ((char *)&col)[1] + ((char *)&col)[2]) / 3.0f / 255.0f; } } diff --git a/source/blender/blenkernel/intern/camera.c b/source/blender/blenkernel/intern/camera.c index 4993caf14f1..869e312614e 100644 --- a/source/blender/blenkernel/intern/camera.c +++ b/source/blender/blenkernel/intern/camera.c @@ -57,6 +57,8 @@ #include "BKE_scene.h" #include "BKE_screen.h" +#include "DEG_depsgraph_query.h" + #include "MEM_guardedalloc.h" #include "GPU_compositing.h" @@ -262,7 +264,7 @@ void BKE_camera_params_from_object(CameraParams *params, const Object *ob) } } -void BKE_camera_params_from_view3d(CameraParams *params, const View3D *v3d, const RegionView3D *rv3d) +void BKE_camera_params_from_view3d(CameraParams *params, const Depsgraph *depsgraph, const View3D *v3d, const RegionView3D *rv3d) { /* common */ params->lens = v3d->lens; @@ -271,7 +273,8 @@ void BKE_camera_params_from_view3d(CameraParams *params, const View3D *v3d, cons if (rv3d->persp == RV3D_CAMOB) { /* camera view */ - BKE_camera_params_from_object(params, v3d->camera); + Object *camera_object = DEG_get_evaluated_object(depsgraph, v3d->camera); + BKE_camera_params_from_object(params, camera_object); params->zoom = BKE_screen_view3d_zoom_to_fac(rv3d->camzoom); diff --git a/source/blender/blenkernel/intern/cdderivedmesh.c b/source/blender/blenkernel/intern/cdderivedmesh.c index d1282c1a0fe..ea54548ab09 100644 --- a/source/blender/blenkernel/intern/cdderivedmesh.c +++ b/source/blender/blenkernel/intern/cdderivedmesh.c @@ -288,6 +288,7 @@ static PBVH *cdDM_getPBVH(Object *ob, DerivedMesh *dm) ob->sculpt->cd_face_node_offset); pbvh_show_diffuse_color_set(cddm->pbvh, ob->sculpt->show_diffuse_color); + pbvh_show_mask_set(cddm->pbvh, ob->sculpt->show_mask); } @@ -303,7 +304,7 @@ static PBVH *cdDM_getPBVH(Object *ob, DerivedMesh *dm) cddm->pbvh = BKE_pbvh_new(); cddm->pbvh_draw = can_pbvh_draw(ob, dm); - looptri = MEM_mallocN(sizeof(*looptri) * looptris_num, __func__); + looptri = MEM_malloc_arrayN(looptris_num, sizeof(*looptri), __func__); BKE_mesh_recalc_looptri( me->mloop, me->mpoly, @@ -318,6 +319,7 @@ static PBVH *cdDM_getPBVH(Object *ob, DerivedMesh *dm) looptri, looptris_num); pbvh_show_diffuse_color_set(cddm->pbvh, ob->sculpt->show_diffuse_color); + pbvh_show_mask_set(cddm->pbvh, ob->sculpt->show_mask); deformed = check_sculpt_object_deformed(ob, true); @@ -327,7 +329,7 @@ static PBVH *cdDM_getPBVH(Object *ob, DerivedMesh *dm) int totvert; totvert = deformdm->getNumVerts(deformdm); - vertCos = MEM_mallocN(totvert * sizeof(float[3]), "cdDM_getPBVH vertCos"); + vertCos = MEM_malloc_arrayN(totvert, sizeof(float[3]), "cdDM_getPBVH vertCos"); deformdm->getVertCos(deformdm, vertCos); BKE_pbvh_apply_vertCos(cddm->pbvh, vertCos); MEM_freeN(vertCos); @@ -891,9 +893,9 @@ static void cdDM_drawMappedFacesGLSL( tot_active_mat = dm->drawObject->totmaterial; - matconv = MEM_callocN(sizeof(*matconv) * tot_active_mat, + matconv = MEM_calloc_arrayN(tot_active_mat, sizeof(*matconv), "cdDM_drawMappedFacesGLSL.matconv"); - mat_orig_to_new = MEM_mallocN(sizeof(*mat_orig_to_new) * dm->totmat, + mat_orig_to_new = MEM_malloc_arrayN(dm->totmat, sizeof(*mat_orig_to_new), "cdDM_drawMappedFacesGLSL.mat_orig_to_new"); /* part one, check what attributes are needed per material */ @@ -1182,7 +1184,7 @@ static void cdDM_buffer_copy_triangles( const MLoopTri *lt = dm->getLoopTriArray(dm); const int totpoly = dm->getNumPolys(dm); - FaceCount *fc = MEM_mallocN(sizeof(*fc) * gpu_totmat, "gpumaterial.facecount"); + FaceCount *fc = MEM_malloc_arrayN(gpu_totmat, sizeof(*fc), "gpumaterial.facecount"); for (i = 0; i < gpu_totmat; i++) { fc[i].i_visible = 0; @@ -1363,7 +1365,7 @@ static void cdDM_buffer_copy_uv_texpaint( /* should have been checked for before, reassert */ BLI_assert(DM_get_loop_data_layer(dm, CD_MLOOPUV)); - uv_base = MEM_mallocN(totmaterial * sizeof(*uv_base), "texslots"); + uv_base = MEM_malloc_arrayN(totmaterial, sizeof(*uv_base), "texslots"); for (i = 0; i < totmaterial; i++) { uv_base[i] = DM_paint_uvlayer_active_get(dm, i); @@ -1577,10 +1579,10 @@ static void cdDM_drawobject_init_vert_points( int tot_loops = 0; /* allocate the array and space for links */ - gdo->vert_points = MEM_mallocN(sizeof(GPUVertPointLink) * gdo->totvert, + gdo->vert_points = MEM_malloc_arrayN(gdo->totvert, sizeof(GPUVertPointLink), "GPUDrawObject.vert_points"); #ifdef USE_GPU_POINT_LINK - gdo->vert_points_mem = MEM_callocN(sizeof(GPUVertPointLink) * gdo->totvert, + gdo->vert_points_mem = MEM_calloc_arrayN(gdo->totvert, sizeof(GPUVertPointLink), "GPUDrawObject.vert_points_mem"); gdo->vert_points_usage = 0; #endif @@ -1635,7 +1637,7 @@ static GPUDrawObject *cdDM_GPUobject_new(DerivedMesh *dm) /* get the number of points used by each material, treating * each quad as two triangles */ - mat_info = MEM_callocN(sizeof(*mat_info) * dm_totmat, "GPU_drawobject_new.mat_orig_to_new"); + mat_info = MEM_calloc_arrayN(dm_totmat, sizeof(*mat_info), "GPU_drawobject_new.mat_orig_to_new"); for (i = 0; i < totpolys; i++) { const short mat_nr = ME_MAT_NR_TEST(mpoly[i].mat_nr, dm_totmat); @@ -2474,7 +2476,7 @@ void CDDM_calc_normals_mapping_ex(DerivedMesh *dm, const bool only_face_normals) } #endif - face_nors = MEM_mallocN(sizeof(*face_nors) * dm->numPolyData, "face_nors"); + face_nors = MEM_malloc_arrayN(dm->numPolyData, sizeof(*face_nors), "face_nors"); /* calculate face normals */ BKE_mesh_calc_normals_poly( @@ -2855,31 +2857,31 @@ DerivedMesh *CDDM_merge_verts(DerivedMesh *dm, const int *vtargetmap, const int const int totvert_final = totvert - tot_vtargetmap; - MVert *mv, *mvert = MEM_mallocN(sizeof(*mvert) * totvert_final, __func__); - int *oldv = MEM_mallocN(sizeof(*oldv) * totvert_final, __func__); - int *newv = MEM_mallocN(sizeof(*newv) * totvert, __func__); + MVert *mv, *mvert = MEM_malloc_arrayN(totvert_final, sizeof(*mvert), __func__); + int *oldv = MEM_malloc_arrayN(totvert_final, sizeof(*oldv), __func__); + int *newv = MEM_malloc_arrayN(totvert, sizeof(*newv), __func__); STACK_DECLARE(mvert); STACK_DECLARE(oldv); /* Note: create (totedge + totloop) elements because partially invalid polys due to merge may require * generating new edges, and while in 99% cases we'll still end with less final edges than totedge, * cases can be forged that would end requiring more... */ - MEdge *med, *medge = MEM_mallocN(sizeof(*medge) * (totedge + totloop), __func__); - int *olde = MEM_mallocN(sizeof(*olde) * (totedge + totloop), __func__); - int *newe = MEM_mallocN(sizeof(*newe) * (totedge + totloop), __func__); + MEdge *med, *medge = MEM_malloc_arrayN((totedge + totloop), sizeof(*medge), __func__); + int *olde = MEM_malloc_arrayN((totedge + totloop), sizeof(*olde), __func__); + int *newe = MEM_malloc_arrayN((totedge + totloop), sizeof(*newe), __func__); STACK_DECLARE(medge); STACK_DECLARE(olde); - MLoop *ml, *mloop = MEM_mallocN(sizeof(*mloop) * totloop, __func__); - int *oldl = MEM_mallocN(sizeof(*oldl) * totloop, __func__); + MLoop *ml, *mloop = MEM_malloc_arrayN(totloop, sizeof(*mloop), __func__); + int *oldl = MEM_malloc_arrayN(totloop, sizeof(*oldl), __func__); #ifdef USE_LOOPS - int newl = MEM_mallocN(sizeof(*newl) * totloop, __func__); + int newl = MEM_malloc_arrayN(totloop, sizeof(*newl), __func__); #endif STACK_DECLARE(mloop); STACK_DECLARE(oldl); - MPoly *mp, *mpoly = MEM_mallocN(sizeof(*medge) * totpoly, __func__); - int *oldp = MEM_mallocN(sizeof(*oldp) * totpoly, __func__); + MPoly *mp, *mpoly = MEM_malloc_arrayN(totpoly, sizeof(*medge), __func__); + int *oldp = MEM_malloc_arrayN(totpoly, sizeof(*oldp), __func__); STACK_DECLARE(mpoly); STACK_DECLARE(oldp); @@ -2957,7 +2959,7 @@ DerivedMesh *CDDM_merge_verts(DerivedMesh *dm, const int *vtargetmap, const int /* if the targets already make up a poly, in which case the new poly is dropped */ /* This poly equality check is rather complex. We use a BLI_ghash to speed it up with a first level check */ PolyKey *mpgh; - poly_keys = MEM_mallocN(sizeof(PolyKey) * totpoly, __func__); + poly_keys = MEM_malloc_arrayN(totpoly, sizeof(PolyKey), __func__); poly_gset = BLI_gset_new_ex(poly_gset_hash_fn, poly_gset_compare_fn, __func__, totpoly); /* Duplicates allowed because our compare function is not pure equality */ BLI_gset_flag_set(poly_gset, GHASH_FLAG_ALLOW_DUPES); diff --git a/source/blender/blenkernel/intern/collection.c b/source/blender/blenkernel/intern/collection.c index 8d69563f5ff..ca77969ccaa 100644 --- a/source/blender/blenkernel/intern/collection.c +++ b/source/blender/blenkernel/intern/collection.c @@ -30,6 +30,7 @@ #include "BLI_ghash.h" #include "BLI_iterator.h" #include "BLI_listbase.h" +#include "BLI_math_base.h" #include "BLT_translation.h" #include "BLI_string_utils.h" @@ -50,6 +51,7 @@ #include "MEM_guardedalloc.h" /* Prototypes. */ +static SceneCollection *find_collection_parent(const struct SceneCollection *sc_child, struct SceneCollection *sc_parent); static bool is_collection_in_tree(const struct SceneCollection *sc_reference, struct SceneCollection *sc_parent); static SceneCollection *collection_master_from_id(const ID *owner_id) @@ -69,24 +71,40 @@ static SceneCollection *collection_master_from_id(const ID *owner_id) * Add a collection to a collection ListBase and syncronize all render layers * The ListBase is NULL when the collection is to be added to the master collection */ -SceneCollection *BKE_collection_add(ID *owner_id, SceneCollection *sc_parent, const int type, const char *name) +SceneCollection *BKE_collection_add(ID *owner_id, SceneCollection *sc_parent, const int type, const char *name_custom) { SceneCollection *sc_master = collection_master_from_id(owner_id); SceneCollection *sc = MEM_callocN(sizeof(SceneCollection), "New Collection"); sc->type = type; - - if (!name) { - name = DATA_("New Collection"); - } + const char *name = name_custom; if (!sc_parent) { sc_parent = sc_master; } - BKE_collection_rename((Scene *)owner_id, sc, name); + if (!name) { + if (sc_parent == sc_master) { + name = BLI_sprintfN("Collection %d", BLI_listbase_count(&sc_master->scene_collections) + 1); + } + else { + const int number = BLI_listbase_count(&sc_parent->scene_collections) + 1; + const int digits = integer_digits_i(number); + const int max_len = sizeof(sc_parent->name) + - 1 /* NULL terminator */ + - (1 + digits) /* " %d" */; + name = BLI_sprintfN("%.*s %d", max_len, sc_parent->name, number); + } + } + BLI_addtail(&sc_parent->scene_collections, sc); + BKE_collection_rename((Scene *)owner_id, sc, name); BKE_layer_sync_new_scene_collection(owner_id, sc_parent, sc); + + if (name != name_custom) { + MEM_freeN((char *)name); + } + return sc; } @@ -99,13 +117,9 @@ static void collection_free(SceneCollection *sc, const bool do_id_user) for (LinkData *link = sc->objects.first; link; link = link->next) { id_us_min(link->data); } - for (LinkData *link = sc->filter_objects.first; link; link = link->next) { - id_us_min(link->data); - } } BLI_freelistN(&sc->objects); - BLI_freelistN(&sc->filter_objects); for (SceneCollection *nsc = sc->scene_collections.first; nsc; nsc = nsc->next) { collection_free(nsc, do_id_user); @@ -164,6 +178,8 @@ static void layer_collection_remove(ViewLayer *view_layer, ListBase *lb, const S /** * Remove a collection from the scene, and syncronize all render layers + * + * If an object is in any other collection, link the object to the master collection. */ bool BKE_collection_remove(ID *owner_id, SceneCollection *sc) { @@ -174,11 +190,50 @@ bool BKE_collection_remove(ID *owner_id, SceneCollection *sc) return false; } + /* We need to do bottom up removal, otherwise we get a crash when we remove a collection that + * has one of its nested collections linked to a view layer. */ + SceneCollection *scene_collection_nested = sc->scene_collections.first; + while (scene_collection_nested != NULL) { + SceneCollection *scene_collection_next = scene_collection_nested->next; + BKE_collection_remove(owner_id, scene_collection_nested); + scene_collection_nested = scene_collection_next; + } + /* Unlink from the respective collection tree. */ if (!collection_remlink(sc_master, sc)) { BLI_assert(false); } + /* If an object is no longer in any collection, we add it to the master collection. */ + ListBase collection_objects; + BLI_duplicatelist(&collection_objects, &sc->objects); + + FOREACH_SCENE_COLLECTION(owner_id, scene_collection_iter) + { + if (scene_collection_iter == sc) { + continue; + } + + LinkData *link_next, *link = collection_objects.first; + while (link) { + link_next = link->next; + + if (BLI_findptr(&scene_collection_iter->objects, link->data, offsetof(LinkData, data))) { + BLI_remlink(&collection_objects, link); + MEM_freeN(link); + } + + link = link_next; + } + } + FOREACH_SCENE_COLLECTION_END + + for (LinkData *link = collection_objects.first; link; link = link->next) { + BKE_collection_object_add(owner_id, sc_master, link->data); + } + + BLI_freelistN(&collection_objects); + /* Clear the collection items. */ collection_free(sc, true); @@ -206,13 +261,6 @@ void BKE_collection_copy_data(SceneCollection *sc_dst, SceneCollection *sc_src, } } - BLI_duplicatelist(&sc_dst->filter_objects, &sc_src->filter_objects); - if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) { - for (LinkData *link = sc_dst->filter_objects.first; link; link = link->next) { - id_us_plus(link->data); - } - } - BLI_duplicatelist(&sc_dst->scene_collections, &sc_src->scene_collections); for (SceneCollection *nsc_src = sc_src->scene_collections.first, *nsc_dst = sc_dst->scene_collections.first; nsc_src; @@ -243,38 +291,11 @@ SceneCollection *BKE_collection_master(const ID *owner_id) return master_collection_from_id(owner_id); } -struct UniqueNameCheckData { - ListBase *lb; - SceneCollection *lookup_sc; -}; - -static bool collection_unique_name_check(void *arg, const char *name) -{ - struct UniqueNameCheckData *data = arg; - - for (SceneCollection *sc = data->lb->first; sc; sc = sc->next) { - struct UniqueNameCheckData child_data = {.lb = &sc->scene_collections, .lookup_sc = data->lookup_sc}; - - if (sc != data->lookup_sc) { - if (STREQ(sc->name, name)) { - return true; - } - } - if (collection_unique_name_check(&child_data, name)) { - return true; - } - } - - return false; -} - static void collection_rename(const ID *owner_id, SceneCollection *sc, const char *name) { - SceneCollection *sc_master = collection_master_from_id(owner_id); - struct UniqueNameCheckData data = {.lb = &sc_master->scene_collections, .lookup_sc = sc}; - + SceneCollection *sc_parent = find_collection_parent(sc, collection_master_from_id(owner_id)); BLI_strncpy(sc->name, name, sizeof(sc->name)); - BLI_uniquename_cb(collection_unique_name_check, &data, DATA_("Collection"), '.', sc->name, sizeof(sc->name)); + BLI_uniquename(&sc_parent->scene_collections, sc, DATA_("Collection"), '.', offsetof(SceneCollection, name), sizeof(sc->name)); } void BKE_collection_rename(const Scene *scene, SceneCollection *sc, const char *name) @@ -283,6 +304,15 @@ void BKE_collection_rename(const Scene *scene, SceneCollection *sc, const char * } /** + * Make sure the collection name is still unique within its siblings. + */ +static void collection_name_check(const ID *owner_id, SceneCollection *sc) +{ + /* It's a bit of a hack, we simply try to make sure the collection name is valid. */ + collection_rename(owner_id, sc, sc->name); +} + +/** * Free (or release) any data used by the master collection (does not free the master collection itself). * Used only to clear the entire scene or group data since it's not doing re-syncing of the LayerCollection tree */ @@ -363,7 +393,6 @@ bool BKE_collection_object_remove(Main *bmain, ID *owner_id, SceneCollection *sc BLI_remlink(&sc->objects, link); MEM_freeN(link); - TODO_LAYER_SYNC_FILTER; /* need to remove all instances of ob in scene collections -> filter_objects */ BKE_layer_sync_object_unlink(owner_id, sc, ob); if (GS(owner_id->name) == ID_SCE) { @@ -386,8 +415,9 @@ bool BKE_collection_object_remove(Main *bmain, ID *owner_id, SceneCollection *sc */ void BKE_collection_object_move(ID *owner_id, SceneCollection *sc_dst, SceneCollection *sc_src, Object *ob) { - BKE_collection_object_add(owner_id, sc_dst, ob); - BKE_collection_object_remove(NULL, owner_id, sc_src, ob, false); + if (BKE_collection_object_add(owner_id, sc_dst, ob)) { + BKE_collection_object_remove(NULL, owner_id, sc_src, ob, false); + } } /** @@ -556,6 +586,9 @@ bool BKE_collection_move_above(const ID *owner_id, SceneCollection *sc_dst, Scen BKE_layer_collection_resync(owner_id, sc_src_parent); BKE_layer_collection_resync(owner_id, sc_dst_parent); + /* Keep names unique. */ + collection_name_check(owner_id, sc_src); + return true; } @@ -595,6 +628,9 @@ bool BKE_collection_move_below(const ID *owner_id, SceneCollection *sc_dst, Scen BKE_layer_collection_resync(owner_id, sc_src_parent); BKE_layer_collection_resync(owner_id, sc_dst_parent); + /* Keep names unique. */ + collection_name_check(owner_id, sc_src); + return true; } @@ -630,6 +666,9 @@ bool BKE_collection_move_into(const ID *owner_id, SceneCollection *sc_dst, Scene BKE_layer_collection_resync(owner_id, sc_src_parent); BKE_layer_collection_resync(owner_id, sc_dst); + /* Keep names unique. */ + collection_name_check(owner_id, sc_src); + return true; } @@ -699,6 +738,7 @@ void BKE_scene_collections_iterator_begin(BLI_Iterator *iter, void *data_in) data->owner_id = owner_id; iter->data = data; + iter->valid = true; scene_collections_array(owner_id, (SceneCollection ***)&data->array, &data->tot); BLI_assert(data->tot != 0); diff --git a/source/blender/blenkernel/intern/colorband.c b/source/blender/blenkernel/intern/colorband.c new file mode 100644 index 00000000000..d35e797ddac --- /dev/null +++ b/source/blender/blenkernel/intern/colorband.c @@ -0,0 +1,629 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/blenkernel/intern/colorband.c + * \ingroup bke + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_math.h" +#include "BLI_utildefines.h" +#include "BLI_math_color.h" +#include "BLI_heap.h" + +#include "DNA_key_types.h" +#include "DNA_texture_types.h" + +#include "BKE_colorband.h" +#include "BKE_material.h" +#include "BKE_key.h" + +void BKE_colorband_init(ColorBand *coba, bool rangetype) +{ + int a; + + coba->data[0].pos = 0.0; + coba->data[1].pos = 1.0; + + if (rangetype == 0) { + coba->data[0].r = 0.0; + coba->data[0].g = 0.0; + coba->data[0].b = 0.0; + coba->data[0].a = 0.0; + + coba->data[1].r = 1.0; + coba->data[1].g = 1.0; + coba->data[1].b = 1.0; + coba->data[1].a = 1.0; + } + else { + coba->data[0].r = 0.0; + coba->data[0].g = 0.0; + coba->data[0].b = 0.0; + coba->data[0].a = 1.0; + + coba->data[1].r = 1.0; + coba->data[1].g = 1.0; + coba->data[1].b = 1.0; + coba->data[1].a = 1.0; + } + + for (a = 2; a < MAXCOLORBAND; a++) { + coba->data[a].r = 0.5; + coba->data[a].g = 0.5; + coba->data[a].b = 0.5; + coba->data[a].a = 1.0; + coba->data[a].pos = 0.5; + } + + coba->tot = 2; + coba->color_mode = COLBAND_BLEND_RGB; +} + +static void colorband_init_from_table_rgba_simple( + ColorBand *coba, + const float (*array)[4], const int array_len) +{ + /* No Re-sample, just de-duplicate. */ + const float eps = (1.0f / 255.0f) + 1e-6f; + BLI_assert(array_len < MAXCOLORBAND); + int stops = min_ii(MAXCOLORBAND, array_len); + if (stops) { + const float step_size = 1.0f / (float)max_ii(stops - 1, 1); + int i_curr = -1; + for (int i_step = 0; i_step < stops; i_step++) { + if ((i_curr != -1) && compare_v4v4(&coba->data[i_curr].r, array[i_step], eps)) { + continue; + } + i_curr += 1; + copy_v4_v4(&coba->data[i_curr].r, array[i_step]); + coba->data[i_curr].pos = i_step * step_size; + coba->data[i_curr].cur = i_curr; + } + coba->tot = i_curr + 1; + coba->cur = 0; + } + else { + /* coba is empty, set 1 black stop */ + zero_v3(&coba->data[0].r); + coba->data[0].a = 1.0f; + coba->cur = 0; + coba->tot = 1; + } +} + + +/* -------------------------------------------------------------------- */ +/** \name Color Ramp Re-Sample + * + * Local functions for #BKE_colorband_init_from_table_rgba + * \{ */ + +/** + * Used for calculating which samples of a color-band to remove (when simplifying). + */ +struct ColorResampleElem { + struct ColorResampleElem *next, *prev; + HeapNode *node; + float rgba[4]; + float pos; +}; + +/** + * Measure the 'area' of each channel and combine to use as a cost for this samples removal. + */ +static float color_sample_remove_cost(const struct ColorResampleElem *c) +{ + if (c->next == NULL || c->prev == NULL) { + return -1.0f; + } + float area = 0.0f; +#if 0 + float xy_prev[2], xy_curr[2], xy_next[2]; + xy_prev[0] = c->prev->pos; + xy_curr[0] = c->pos; + xy_next[0] = c->next->pos; + for (int i = 0; i < 4; i++) { + xy_prev[1] = c->prev->rgba[i]; + xy_curr[1] = c->rgba[i]; + xy_next[1] = c->next->rgba[i]; + area += fabsf(cross_tri_v2(xy_prev, xy_curr, xy_next)); + } +#else + /* Above logic, optimized (p: previous, c: current, n: next). */ + const float xpc = c->prev->pos - c->pos; + const float xnc = c->next->pos - c->pos; + for (int i = 0; i < 4; i++) { + const float ycn = c->rgba[i] - c->next->rgba[i]; + const float ypc = c->prev->rgba[i] - c->rgba[i]; + area += fabsf((xpc * ycn) + (ypc * xnc)); + } +#endif + return area; +} + +/* TODO(campbell): create BLI_math_filter? */ +static float filter_gauss(float x) +{ + const float gaussfac = 1.6f; + const float two_gaussfac2 = 2.0f * gaussfac * gaussfac; + x *= 3.0f * gaussfac; + return 1.0f / sqrtf((float)M_PI * two_gaussfac2) * expf(-x * x / two_gaussfac2); +} + +static void colorband_init_from_table_rgba_resample( + ColorBand *coba, + const float (*array)[4], const int array_len, + bool filter_samples) +{ + BLI_assert(array_len >= 2); + const float eps_2x = ((1.0f / 255.0f) + 1e-6f); + struct ColorResampleElem *c, *carr = MEM_mallocN(sizeof(*carr) * array_len, __func__); + int carr_len = array_len; + c = carr; + { + const float step_size = 1.0f / (float)(array_len - 1); + for (int i = 0; i < array_len; i++, c++) { + copy_v4_v4(carr[i].rgba, array[i]); + c->next = c + 1; + c->prev = c - 1; + c->pos = i * step_size; + } + } + carr[0].prev = NULL; + carr[array_len - 1].next = NULL; + + /* -2 to remove endpoints. */ + Heap *heap = BLI_heap_new_ex(array_len - 2); + c = carr; + for (int i = 0; i < array_len; i++, c++) { + float cost = color_sample_remove_cost(c); + if (cost != -1.0f) { + c->node = BLI_heap_insert(heap, cost, c); + } + else { + c->node = NULL; + } + } + + while ((carr_len > 1 && !BLI_heap_is_empty(heap)) && + ((carr_len >= MAXCOLORBAND) || (BLI_heap_node_value(BLI_heap_top(heap)) <= eps_2x))) + { + c = BLI_heap_popmin(heap); + struct ColorResampleElem *c_next = c->next, *c_prev = c->prev; + c_prev->next = c_next; + c_next->prev = c_prev; + /* Clear data (not essential, avoid confusion). */ + c->prev = c->next = NULL; + c->node = NULL; + + /* Update adjacent */ + for (int i = 0; i < 2; i++) { + struct ColorResampleElem *c_other = i ? c_next : c_prev; + if (c_other->node != NULL) { + const float cost = color_sample_remove_cost(c_other); + if (cost != -1.0) { + BLI_heap_node_value_update(heap, c_other->node, cost); + } + else { + BLI_heap_remove(heap, c_other->node); + c_other->node = NULL; + } + } + } + carr_len -= 1; + } + BLI_heap_free(heap, NULL); + + /* First member is never removed. */ + int i = 0; + BLI_assert(carr_len < MAXCOLORBAND); + if (filter_samples == false) { + for (c = carr; c != NULL; c = c->next, i++) { + copy_v4_v4(&coba->data[i].r, c->rgba); + coba->data[i].pos = c->pos; + coba->data[i].cur = i; + } + } + else { + for (c = carr; c != NULL; c = c->next, i++) { + const int steps_prev = c->prev ? (c - c->prev) - 1 : 0; + const int steps_next = c->next ? (c->next - c) - 1 : 0; + if (steps_prev == 0 && steps_next == 0) { + copy_v4_v4(&coba->data[i].r, c->rgba); + } + else { + float rgba[4]; + float rgba_accum = 1; + copy_v4_v4(rgba, c->rgba); + + if (steps_prev) { + const float step_size = 1.0 / (float)(steps_prev + 1); + int j = steps_prev; + for (struct ColorResampleElem *c_other = c - 1; c_other != c->prev; c_other--, j--) { + const float step_pos = (float)j * step_size; + BLI_assert(step_pos > 0.0f && step_pos < 1.0f); + const float f = filter_gauss(step_pos); + madd_v4_v4fl(rgba, c_other->rgba, f); + rgba_accum += f; + } + } + if (steps_next) { + const float step_size = 1.0 / (float)(steps_next + 1); + int j = steps_next; + for (struct ColorResampleElem *c_other = c + 1; c_other != c->next; c_other++, j--) { + const float step_pos = (float)j * step_size; + BLI_assert(step_pos > 0.0f && step_pos < 1.0f); + const float f = filter_gauss(step_pos); + madd_v4_v4fl(rgba, c_other->rgba, f); + rgba_accum += f; + } + } + + mul_v4_v4fl(&coba->data[i].r, rgba, 1.0f / rgba_accum); + } + coba->data[i].pos = c->pos; + coba->data[i].cur = i; + } + } + BLI_assert(i == carr_len); + coba->tot = i; + coba->cur = 0; + + MEM_freeN(carr); +} + +void BKE_colorband_init_from_table_rgba( + ColorBand *coba, + const float (*array)[4], const int array_len, + bool filter_samples) +{ + /* Note, we could use MAXCOLORBAND here, but results of re-sampling are nicer, + * avoid different behavior when limit is hit. */ + if (array_len < 2) { + /* No Re-sample, just de-duplicate. */ + colorband_init_from_table_rgba_simple(coba, array, array_len); + } + else { + /* Re-sample */ + colorband_init_from_table_rgba_resample(coba, array, array_len, filter_samples); + } +} + +/** \} */ + +ColorBand *BKE_colorband_add(bool rangetype) +{ + ColorBand *coba; + + coba = MEM_callocN(sizeof(ColorBand), "colorband"); + BKE_colorband_init(coba, rangetype); + + return coba; +} + +/* ------------------------------------------------------------------------- */ + +static float colorband_hue_interp( + const int ipotype_hue, + const float mfac, const float fac, + float h1, float h2) +{ + float h_interp; + int mode = 0; + +#define HUE_INTERP(h_a, h_b) ((mfac * (h_a)) + (fac * (h_b))) +#define HUE_MOD(h) (((h) < 1.0f) ? (h) : (h) - 1.0f) + + h1 = HUE_MOD(h1); + h2 = HUE_MOD(h2); + + BLI_assert(h1 >= 0.0f && h1 < 1.0f); + BLI_assert(h2 >= 0.0f && h2 < 1.0f); + + switch (ipotype_hue) { + case COLBAND_HUE_NEAR: + { + if ((h1 < h2) && (h2 - h1) > +0.5f) mode = 1; + else if ((h1 > h2) && (h2 - h1) < -0.5f) mode = 2; + else mode = 0; + break; + } + case COLBAND_HUE_FAR: + { + if ((h1 < h2) && (h2 - h1) < +0.5f) mode = 1; + else if ((h1 > h2) && (h2 - h1) > -0.5f) mode = 2; + else mode = 0; + break; + } + case COLBAND_HUE_CCW: + { + if (h1 > h2) mode = 2; + else mode = 0; + break; + } + case COLBAND_HUE_CW: + { + if (h1 < h2) mode = 1; + else mode = 0; + break; + } + } + + switch (mode) { + case 0: + h_interp = HUE_INTERP(h1, h2); + break; + case 1: + h_interp = HUE_INTERP(h1 + 1.0f, h2); + h_interp = HUE_MOD(h_interp); + break; + case 2: + h_interp = HUE_INTERP(h1, h2 + 1.0f); + h_interp = HUE_MOD(h_interp); + break; + } + + BLI_assert(h_interp >= 0.0f && h_interp < 1.0f); + +#undef HUE_INTERP +#undef HUE_MOD + + return h_interp; +} + +bool BKE_colorband_evaluate(const ColorBand *coba, float in, float out[4]) +{ + const CBData *cbd1, *cbd2, *cbd0, *cbd3; + float fac; + int ipotype; + int a; + + if (coba == NULL || coba->tot == 0) return false; + + cbd1 = coba->data; + + ipotype = (coba->color_mode == COLBAND_BLEND_RGB) ? coba->ipotype : COLBAND_INTERP_LINEAR; + + if (coba->tot == 1) { + out[0] = cbd1->r; + out[1] = cbd1->g; + out[2] = cbd1->b; + out[3] = cbd1->a; + } + else if ((in <= cbd1->pos) && ELEM(ipotype, COLBAND_INTERP_LINEAR, COLBAND_INTERP_EASE)) { + out[0] = cbd1->r; + out[1] = cbd1->g; + out[2] = cbd1->b; + out[3] = cbd1->a; + } + else { + CBData left, right; + + /* we're looking for first pos > in */ + for (a = 0; a < coba->tot; a++, cbd1++) { + if (cbd1->pos > in) { + break; + } + } + + if (a == coba->tot) { + cbd2 = cbd1 - 1; + right = *cbd2; + right.pos = 1.0f; + cbd1 = &right; + } + else if (a == 0) { + left = *cbd1; + left.pos = 0.0f; + cbd2 = &left; + } + else { + cbd2 = cbd1 - 1; + } + + if ((in >= cbd1->pos) && ELEM(ipotype, COLBAND_INTERP_LINEAR, COLBAND_INTERP_EASE)) { + out[0] = cbd1->r; + out[1] = cbd1->g; + out[2] = cbd1->b; + out[3] = cbd1->a; + } + else { + + if (cbd2->pos != cbd1->pos) { + fac = (in - cbd1->pos) / (cbd2->pos - cbd1->pos); + } + else { + /* was setting to 0.0 in 2.56 & previous, but this + * is incorrect for the last element, see [#26732] */ + fac = (a != coba->tot) ? 0.0f : 1.0f; + } + + if (ipotype == COLBAND_INTERP_CONSTANT) { + /* constant */ + out[0] = cbd2->r; + out[1] = cbd2->g; + out[2] = cbd2->b; + out[3] = cbd2->a; + } + else if (ipotype >= COLBAND_INTERP_B_SPLINE) { + /* ipo from right to left: 3 2 1 0 */ + float t[4]; + + if (a >= coba->tot - 1) cbd0 = cbd1; + else cbd0 = cbd1 + 1; + if (a < 2) cbd3 = cbd2; + else cbd3 = cbd2 - 1; + + CLAMP(fac, 0.0f, 1.0f); + + if (ipotype == COLBAND_INTERP_CARDINAL) { + key_curve_position_weights(fac, t, KEY_CARDINAL); + } + else { + key_curve_position_weights(fac, t, KEY_BSPLINE); + } + + out[0] = t[3] * cbd3->r + t[2] * cbd2->r + t[1] * cbd1->r + t[0] * cbd0->r; + out[1] = t[3] * cbd3->g + t[2] * cbd2->g + t[1] * cbd1->g + t[0] * cbd0->g; + out[2] = t[3] * cbd3->b + t[2] * cbd2->b + t[1] * cbd1->b + t[0] * cbd0->b; + out[3] = t[3] * cbd3->a + t[2] * cbd2->a + t[1] * cbd1->a + t[0] * cbd0->a; + CLAMP(out[0], 0.0f, 1.0f); + CLAMP(out[1], 0.0f, 1.0f); + CLAMP(out[2], 0.0f, 1.0f); + CLAMP(out[3], 0.0f, 1.0f); + } + else { + float mfac; + + if (ipotype == COLBAND_INTERP_EASE) { + mfac = fac * fac; + fac = 3.0f * mfac - 2.0f * mfac * fac; + } + + mfac = 1.0f - fac; + + if (UNLIKELY(coba->color_mode == COLBAND_BLEND_HSV)) { + float col1[3], col2[3]; + + rgb_to_hsv_v(&cbd1->r, col1); + rgb_to_hsv_v(&cbd2->r, col2); + + out[0] = colorband_hue_interp(coba->ipotype_hue, mfac, fac, col1[0], col2[0]); + out[1] = mfac * col1[1] + fac * col2[1]; + out[2] = mfac * col1[2] + fac * col2[2]; + out[3] = mfac * cbd1->a + fac * cbd2->a; + + hsv_to_rgb_v(out, out); + } + else if (UNLIKELY(coba->color_mode == COLBAND_BLEND_HSL)) { + float col1[3], col2[3]; + + rgb_to_hsl_v(&cbd1->r, col1); + rgb_to_hsl_v(&cbd2->r, col2); + + out[0] = colorband_hue_interp(coba->ipotype_hue, mfac, fac, col1[0], col2[0]); + out[1] = mfac * col1[1] + fac * col2[1]; + out[2] = mfac * col1[2] + fac * col2[2]; + out[3] = mfac * cbd1->a + fac * cbd2->a; + + hsl_to_rgb_v(out, out); + } + else { + /* COLBAND_BLEND_RGB */ + out[0] = mfac * cbd1->r + fac * cbd2->r; + out[1] = mfac * cbd1->g + fac * cbd2->g; + out[2] = mfac * cbd1->b + fac * cbd2->b; + out[3] = mfac * cbd1->a + fac * cbd2->a; + } + } + } + } + return true; /* OK */ +} + +void BKE_colorband_evaluate_table_rgba(const ColorBand *coba, float **array, int *size) +{ + int a; + + *size = CM_TABLE + 1; + *array = MEM_callocN(sizeof(float) * (*size) * 4, "ColorBand"); + + for (a = 0; a < *size; a++) + BKE_colorband_evaluate(coba, (float)a / (float)CM_TABLE, &(*array)[a * 4]); +} + +static int vergcband(const void *a1, const void *a2) +{ + const CBData *x1 = a1, *x2 = a2; + + if (x1->pos > x2->pos) return 1; + else if (x1->pos < x2->pos) return -1; + return 0; +} + +void BKE_colorband_update_sort(ColorBand *coba) +{ + int a; + + if (coba->tot < 2) + return; + + for (a = 0; a < coba->tot; a++) + coba->data[a].cur = a; + + qsort(coba->data, coba->tot, sizeof(CBData), vergcband); + + for (a = 0; a < coba->tot; a++) { + if (coba->data[a].cur == coba->cur) { + coba->cur = a; + break; + } + } +} + +CBData *BKE_colorband_element_add(struct ColorBand *coba, float position) +{ + if (coba->tot == MAXCOLORBAND) { + return NULL; + } + else { + CBData *xnew; + + xnew = &coba->data[coba->tot]; + xnew->pos = position; + + if (coba->tot != 0) { + BKE_colorband_evaluate(coba, position, &xnew->r); + } + else { + zero_v4(&xnew->r); + } + } + + coba->tot++; + coba->cur = coba->tot - 1; + + BKE_colorband_update_sort(coba); + + return coba->data + coba->cur; +} + +int BKE_colorband_element_remove(struct ColorBand *coba, int index) +{ + int a; + + if (coba->tot < 2) + return 0; + + if (index < 0 || index >= coba->tot) + return 0; + + coba->tot--; + for (a = index; a < coba->tot; a++) { + coba->data[a] = coba->data[a + 1]; + } + if (coba->cur) coba->cur--; + return 1; +} diff --git a/source/blender/blenkernel/intern/colortools.c b/source/blender/blenkernel/intern/colortools.c index 310255a15c1..0fe429312db 100644 --- a/source/blender/blenkernel/intern/colortools.c +++ b/source/blender/blenkernel/intern/colortools.c @@ -1165,7 +1165,9 @@ typedef struct ScopesUpdateDataChunk { float min[3], max[3]; } ScopesUpdateDataChunk; -static void scopes_update_cb(void *userdata, void *userdata_chunk, const int y, const int UNUSED(threadid)) +static void scopes_update_cb(void *__restrict userdata, + const int y, + const ParallelRangeTLS *__restrict tls) { const ScopesUpdateData *data = userdata; @@ -1175,7 +1177,7 @@ static void scopes_update_cb(void *userdata, void *userdata_chunk, const int y, const unsigned char *display_buffer = data->display_buffer; const int ycc_mode = data->ycc_mode; - ScopesUpdateDataChunk *data_chunk = userdata_chunk; + ScopesUpdateDataChunk *data_chunk = tls->userdata_chunk; unsigned int *bin_lum = data_chunk->bin_lum; unsigned int *bin_r = data_chunk->bin_r; unsigned int *bin_g = data_chunk->bin_g; @@ -1259,7 +1261,8 @@ static void scopes_update_cb(void *userdata, void *userdata_chunk, const int y, } } -static void scopes_update_finalize(void *userdata, void *userdata_chunk) +static void scopes_update_finalize(void *__restrict userdata, + void *__restrict userdata_chunk) { const ScopesUpdateData *data = userdata; const ScopesUpdateDataChunk *data_chunk = userdata_chunk; @@ -1387,8 +1390,16 @@ void scopes_update(Scopes *scopes, ImBuf *ibuf, const ColorManagedViewSettings * ScopesUpdateDataChunk data_chunk = {{0}}; INIT_MINMAX(data_chunk.min, data_chunk.max); - BLI_task_parallel_range_finalize(0, ibuf->y, &data, &data_chunk, sizeof(data_chunk), - scopes_update_cb, scopes_update_finalize, ibuf->y > 256, false); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = (ibuf->y > 256); + settings.userdata_chunk = &data_chunk; + settings.userdata_chunk_size = sizeof(data_chunk); + settings.func_finalize = scopes_update_finalize; + BLI_task_parallel_range(0, ibuf->y, + &data, + scopes_update_cb, + &settings); /* test for nicer distribution even - non standard, leave it out for a while */ #if 0 diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c index d429149f0c4..b8dc7944a75 100644 --- a/source/blender/blenkernel/intern/constraint.c +++ b/source/blender/blenkernel/intern/constraint.c @@ -1013,8 +1013,11 @@ static void vectomat(const float vec[3], const float target_up[3], short axis, s u[2] = 1; } + /* note: even though 'n' is normalized, don't use 'project_v3_v3v3_normalized' below + * because precision issues cause a problem in near degenerate states, see: T53455. */ + /* project the up vector onto the plane specified by n */ - project_v3_v3v3_normalized(proj, u, n); /* first u onto n... */ + project_v3_v3v3(proj, u, n); /* first u onto n... */ sub_v3_v3v3(proj, u, proj); /* then onto the plane */ /* proj specifies the transformation of the up axis */ diff --git a/source/blender/blenkernel/intern/context.c b/source/blender/blenkernel/intern/context.c index 1f673d2c15f..a92299810ec 100644 --- a/source/blender/blenkernel/intern/context.c +++ b/source/blender/blenkernel/intern/context.c @@ -976,11 +976,11 @@ RenderEngineType *CTX_data_engine_type(const bContext *C) LayerCollection *CTX_data_layer_collection(const bContext *C) { ViewLayer *view_layer = CTX_data_view_layer(C); - LayerCollection *lc; + LayerCollection *layer_collection; - if (ctx_data_pointer_verify(C, "layer_collection", (void *)&lc)) { - if (BKE_view_layer_has_collection(view_layer, lc->scene_collection)) { - return lc; + if (ctx_data_pointer_verify(C, "layer_collection", (void *)&layer_collection)) { + if (BKE_view_layer_has_collection(view_layer, layer_collection->scene_collection)) { + return layer_collection; } } @@ -990,16 +990,14 @@ LayerCollection *CTX_data_layer_collection(const bContext *C) SceneCollection *CTX_data_scene_collection(const bContext *C) { - SceneCollection *sc; - if (ctx_data_pointer_verify(C, "scene_collection", (void *)&sc)) { - if (BKE_view_layer_has_collection(CTX_data_view_layer(C), sc)) { - return sc; - } + SceneCollection *scene_collection; + if (ctx_data_pointer_verify(C, "scene_collection", (void *)&scene_collection)) { + return scene_collection; } - LayerCollection *lc = CTX_data_layer_collection(C); - if (lc) { - return lc->scene_collection; + LayerCollection *layer_collection = CTX_data_layer_collection(C); + if (layer_collection) { + return layer_collection->scene_collection; } /* fallback */ @@ -1069,6 +1067,7 @@ static const char *data_mode_strings[] = { "objectmode", NULL }; +BLI_STATIC_ASSERT(ARRAY_SIZE(data_mode_strings) == CTX_MODE_NUM + 1, "Must have a string for each context mode") const char *CTX_data_mode_string(const bContext *C) { return data_mode_strings[CTX_data_mode_enum(C)]; diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c index ba9ccf94303..2a27bad0fb5 100644 --- a/source/blender/blenkernel/intern/curve.c +++ b/source/blender/blenkernel/intern/curve.c @@ -169,12 +169,12 @@ void BKE_curve_init(Curve *cu) if (cu->type == OB_FONT) { cu->vfont = cu->vfontb = cu->vfonti = cu->vfontbi = BKE_vfont_builtin_get(); cu->vfont->id.us += 4; - cu->str = MEM_mallocN(12, "str"); + cu->str = MEM_malloc_arrayN(12, sizeof(unsigned char), "str"); BLI_strncpy(cu->str, "Text", 12); cu->len = cu->len_wchar = cu->pos = 4; - cu->strinfo = MEM_callocN(12 * sizeof(CharInfo), "strinfo new"); + cu->strinfo = MEM_calloc_arrayN(12, sizeof(CharInfo), "strinfo new"); cu->totbox = cu->actbox = 1; - cu->tb = MEM_callocN(MAXTEXTBOX * sizeof(TextBox), "textbox"); + cu->tb = MEM_calloc_arrayN(MAXTEXTBOX, sizeof(TextBox), "textbox"); cu->tb[0].w = cu->tb[0].h = 0.0; } } @@ -481,13 +481,13 @@ Nurb *BKE_nurb_duplicate(const Nurb *nu) if (nu->bezt) { newnu->bezt = - (BezTriple *)MEM_mallocN((nu->pntsu) * sizeof(BezTriple), "duplicateNurb2"); + (BezTriple *)MEM_malloc_arrayN(nu->pntsu, sizeof(BezTriple), "duplicateNurb2"); memcpy(newnu->bezt, nu->bezt, nu->pntsu * sizeof(BezTriple)); } else { len = nu->pntsu * nu->pntsv; newnu->bp = - (BPoint *)MEM_mallocN((len) * sizeof(BPoint), "duplicateNurb3"); + (BPoint *)MEM_malloc_arrayN(len, sizeof(BPoint), "duplicateNurb3"); memcpy(newnu->bp, nu->bp, len * sizeof(BPoint)); newnu->knotsu = newnu->knotsv = NULL; @@ -495,14 +495,14 @@ Nurb *BKE_nurb_duplicate(const Nurb *nu) if (nu->knotsu) { len = KNOTSU(nu); if (len) { - newnu->knotsu = MEM_mallocN(len * sizeof(float), "duplicateNurb4"); + newnu->knotsu = MEM_malloc_arrayN(len, sizeof(float), "duplicateNurb4"); memcpy(newnu->knotsu, nu->knotsu, sizeof(float) * len); } } if (nu->pntsv > 1 && nu->knotsv) { len = KNOTSV(nu); if (len) { - newnu->knotsv = MEM_mallocN(len * sizeof(float), "duplicateNurb5"); + newnu->knotsv = MEM_malloc_arrayN(len, sizeof(float), "duplicateNurb5"); memcpy(newnu->knotsv, nu->knotsv, sizeof(float) * len); } } @@ -525,10 +525,10 @@ Nurb *BKE_nurb_copy(Nurb *src, int pntsu, int pntsv) newnu->knotsv = NULL; if (src->bezt) { - newnu->bezt = (BezTriple *)MEM_mallocN(pntsu * pntsv * sizeof(BezTriple), "copyNurb2"); + newnu->bezt = (BezTriple *)MEM_malloc_arrayN(pntsu * pntsv, sizeof(BezTriple), "copyNurb2"); } else { - newnu->bp = (BPoint *)MEM_mallocN(pntsu * pntsv * sizeof(BPoint), "copyNurb3"); + newnu->bp = (BPoint *)MEM_malloc_arrayN(pntsu * pntsv, sizeof(BPoint), "copyNurb3"); } return newnu; @@ -975,7 +975,7 @@ static void makeknots(Nurb *nu, short uv) if (nu->knotsu) MEM_freeN(nu->knotsu); if (BKE_nurb_check_valid_u(nu)) { - nu->knotsu = MEM_callocN(4 + sizeof(float) * KNOTSU(nu), "makeknots"); + nu->knotsu = MEM_calloc_arrayN(KNOTSU(nu) + 1, sizeof(float), "makeknots"); if (nu->flagu & CU_NURB_CYCLIC) { calcknots(nu->knotsu, nu->pntsu, nu->orderu, 0); /* cyclic should be uniform */ makecyclicknots(nu->knotsu, nu->pntsu, nu->orderu); @@ -991,7 +991,7 @@ static void makeknots(Nurb *nu, short uv) if (nu->knotsv) MEM_freeN(nu->knotsv); if (BKE_nurb_check_valid_v(nu)) { - nu->knotsv = MEM_callocN(4 + sizeof(float) * KNOTSV(nu), "makeknots"); + nu->knotsv = MEM_calloc_arrayN(KNOTSV(nu) + 1, sizeof(float), "makeknots"); if (nu->flagv & CU_NURB_CYCLIC) { calcknots(nu->knotsv, nu->pntsv, nu->orderv, 0); /* cyclic should be uniform */ makecyclicknots(nu->knotsv, nu->pntsv, nu->orderv); @@ -1108,7 +1108,7 @@ void BKE_nurb_makeFaces(Nurb *nu, float *coord_array, int rowstride, int resolu, if (len == 0) return; - sum = (float *)MEM_callocN(sizeof(float) * len, "makeNurbfaces1"); + sum = (float *)MEM_calloc_arrayN(len, sizeof(float), "makeNurbfaces1"); bp = nu->bp; i = nu->pntsu * nu->pntsv; @@ -1129,7 +1129,7 @@ void BKE_nurb_makeFaces(Nurb *nu, float *coord_array, int rowstride, int resolu, uend = fp[nu->pntsu]; ustep = (uend - ustart) / ((nu->flagu & CU_NURB_CYCLIC) ? totu : totu - 1); - basisu = (float *)MEM_mallocN(sizeof(float) * KNOTSU(nu), "makeNurbfaces3"); + basisu = (float *)MEM_malloc_arrayN(KNOTSU(nu), sizeof(float), "makeNurbfaces3"); fp = nu->knotsv; vstart = fp[nu->orderv - 1]; @@ -1141,9 +1141,9 @@ void BKE_nurb_makeFaces(Nurb *nu, float *coord_array, int rowstride, int resolu, vstep = (vend - vstart) / ((nu->flagv & CU_NURB_CYCLIC) ? totv : totv - 1); len = KNOTSV(nu); - basisv = (float *)MEM_mallocN(sizeof(float) * len * totv, "makeNurbfaces3"); - jstart = (int *)MEM_mallocN(sizeof(float) * totv, "makeNurbfaces4"); - jend = (int *)MEM_mallocN(sizeof(float) * totv, "makeNurbfaces5"); + basisv = (float *)MEM_malloc_arrayN(len * totv, sizeof(float), "makeNurbfaces3"); + jstart = (int *)MEM_malloc_arrayN(totv, sizeof(float), "makeNurbfaces4"); + jend = (int *)MEM_malloc_arrayN(totv, sizeof(float), "makeNurbfaces5"); /* precalculation of basisv and jstart, jend */ if (nu->flagv & CU_NURB_CYCLIC) @@ -1281,7 +1281,7 @@ void BKE_nurb_makeCurve(Nurb *nu, float *coord_array, float *tilt_array, float * len = nu->pntsu; if (len == 0) return; - sum = (float *)MEM_callocN(sizeof(float) * len, "makeNurbcurve1"); + sum = (float *)MEM_calloc_arrayN(len, sizeof(float), "makeNurbcurve1"); resolu = (resolu * SEGMENTSU(nu)); @@ -1298,7 +1298,7 @@ void BKE_nurb_makeCurve(Nurb *nu, float *coord_array, float *tilt_array, float * uend = fp[nu->pntsu]; ustep = (uend - ustart) / (resolu - ((nu->flagu & CU_NURB_CYCLIC) ? 0 : 1)); - basisu = (float *)MEM_mallocN(sizeof(float) * KNOTSU(nu), "makeNurbcurve3"); + basisu = (float *)MEM_malloc_arrayN(KNOTSU(nu), sizeof(float), "makeNurbcurve3"); if (nu->flagu & CU_NURB_CYCLIC) cycl = nu->orderu - 1; @@ -1549,7 +1549,7 @@ float *BKE_curve_surf_make_orco(Object *ob) nu = nu->next; } /* makeNurbfaces wants zeros */ - fp = coord_array = MEM_callocN(3 * sizeof(float) * tot, "make_orco"); + fp = coord_array = MEM_calloc_arrayN(tot, 3 * sizeof(float), "make_orco"); nu = cu->nurb.first; while (nu) { @@ -1660,7 +1660,7 @@ float *BKE_curve_make_orco(const EvaluationContext *eval_ctx, Scene *scene, Obje if (r_numVerts) *r_numVerts = numVerts; - fp = coord_array = MEM_mallocN(3 * sizeof(float) * numVerts, "cu_orco"); + fp = coord_array = MEM_malloc_arrayN(numVerts, 3 * sizeof(float), "cu_orco"); for (dl = disp.first; dl; dl = dl->next) { if (dl->type == DL_INDEX3) { for (u = 0; u < dl->nr; u++, fp += 3) { @@ -1764,7 +1764,7 @@ void BKE_curve_bevel_make( if (ELEM(dl->type, DL_POLY, DL_SEGM)) { dlnew = MEM_mallocN(sizeof(DispList), "makebevelcurve1"); *dlnew = *dl; - dlnew->verts = MEM_mallocN(3 * sizeof(float) * dl->parts * dl->nr, "makebevelcurve1"); + dlnew->verts = MEM_malloc_arrayN(dl->parts * dl->nr, 3 * sizeof(float), "makebevelcurve1"); memcpy(dlnew->verts, dl->verts, 3 * sizeof(float) * dl->parts * dl->nr); if (dlnew->type == DL_SEGM) @@ -1791,7 +1791,7 @@ void BKE_curve_bevel_make( } else if (cu->ext2 == 0.0f) { dl = MEM_callocN(sizeof(DispList), "makebevelcurve2"); - dl->verts = MEM_mallocN(2 * sizeof(float[3]), "makebevelcurve2"); + dl->verts = MEM_malloc_arrayN(2, sizeof(float[3]), "makebevelcurve2"); BLI_addtail(disp, dl); dl->type = DL_SEGM; dl->parts = 1; @@ -1808,7 +1808,7 @@ void BKE_curve_bevel_make( nr = 4 + 2 * cu->bevresol; dl = MEM_callocN(sizeof(DispList), "makebevelcurve p1"); - dl->verts = MEM_mallocN(nr * sizeof(float[3]), "makebevelcurve p1"); + dl->verts = MEM_malloc_arrayN(nr, sizeof(float[3]), "makebevelcurve p1"); BLI_addtail(disp, dl); dl->type = DL_POLY; dl->parts = 1; @@ -1840,7 +1840,7 @@ void BKE_curve_bevel_make( nr = 3 + 2 * cu->bevresol; } dl = MEM_callocN(sizeof(DispList), "makebevelcurve p1"); - dl->verts = MEM_mallocN(nr * sizeof(float[3]), "makebevelcurve p1"); + dl->verts = MEM_malloc_arrayN(nr, sizeof(float[3]), "makebevelcurve p1"); BLI_addtail(disp, dl); dl->type = DL_SEGM; dl->parts = 1; @@ -1866,7 +1866,7 @@ void BKE_curve_bevel_make( nr = 2; dl = MEM_callocN(sizeof(DispList), "makebevelcurve p2"); - dl->verts = MEM_mallocN(nr * sizeof(float[3]), "makebevelcurve p2"); + dl->verts = MEM_malloc_arrayN(nr, sizeof(float[3]), "makebevelcurve p2"); BLI_addtail(disp, dl); dl->type = DL_SEGM; dl->parts = 1; @@ -1898,7 +1898,7 @@ void BKE_curve_bevel_make( nr = 3 + 2 * cu->bevresol; } dl = MEM_callocN(sizeof(DispList), "makebevelcurve p3"); - dl->verts = MEM_mallocN(nr * sizeof(float[3]), "makebevelcurve p3"); + dl->verts = MEM_malloc_arrayN(nr, sizeof(float[3]), "makebevelcurve p3"); BLI_addtail(disp, dl); dl->type = DL_SEGM; dl->flag = DL_FRONT_CURVE; @@ -2628,6 +2628,9 @@ void BKE_curve_bevelList_free(ListBase *bev) if (bl->segbevcount != NULL) { MEM_freeN(bl->segbevcount); } + if (bl->bevpoints != NULL) { + MEM_freeN(bl->bevpoints); + } MEM_freeN(bl); } @@ -2692,7 +2695,8 @@ void BKE_curve_bevelList_make(Object *ob, ListBase *nurbs, bool for_render) /* check we are a single point? also check we are not a surface and that the orderu is sane, * enforced in the UI but can go wrong possibly */ if (!BKE_nurb_check_valid_u(nu)) { - bl = MEM_callocN(sizeof(BevList) + 1 * sizeof(BevPoint), "makeBevelList1"); + bl = MEM_callocN(sizeof(BevList), "makeBevelList1"); + bl->bevpoints = MEM_calloc_arrayN(1, sizeof(BevPoint), "makeBevelPoints1"); BLI_addtail(bev, bl); bl->nr = 0; bl->charidx = nu->charidx; @@ -2709,10 +2713,11 @@ void BKE_curve_bevelList_make(Object *ob, ListBase *nurbs, bool for_render) if (nu->type == CU_POLY) { len = nu->pntsu; - bl = MEM_callocN(sizeof(BevList) + len * sizeof(BevPoint), "makeBevelList2"); + bl = MEM_callocN(sizeof(BevList), "makeBevelList2"); + bl->bevpoints = MEM_calloc_arrayN(len, sizeof(BevPoint), "makeBevelPoints2"); if (need_seglen && (nu->flagu & CU_NURB_CYCLIC) == 0) { - bl->seglen = MEM_mallocN(segcount * sizeof(float), "makeBevelList2_seglen"); - bl->segbevcount = MEM_mallocN(segcount * sizeof(int), "makeBevelList2_segbevcount"); + bl->seglen = MEM_malloc_arrayN(segcount, sizeof(float), "makeBevelList2_seglen"); + bl->segbevcount = MEM_malloc_arrayN(segcount, sizeof(int), "makeBevelList2_segbevcount"); } BLI_addtail(bev, bl); @@ -2755,10 +2760,11 @@ void BKE_curve_bevelList_make(Object *ob, ListBase *nurbs, bool for_render) /* in case last point is not cyclic */ len = segcount * resolu + 1; - bl = MEM_callocN(sizeof(BevList) + len * sizeof(BevPoint), "makeBevelBPoints"); + bl = MEM_callocN(sizeof(BevList), "makeBevelBPoints"); + bl->bevpoints = MEM_calloc_arrayN(len, sizeof(BevPoint), "makeBevelBPointsPoints"); if (need_seglen && (nu->flagu & CU_NURB_CYCLIC) == 0) { - bl->seglen = MEM_mallocN(segcount * sizeof(float), "makeBevelBPoints_seglen"); - bl->segbevcount = MEM_mallocN(segcount * sizeof(int), "makeBevelBPoints_segbevcount"); + bl->seglen = MEM_malloc_arrayN(segcount, sizeof(float), "makeBevelBPoints_seglen"); + bl->segbevcount = MEM_malloc_arrayN(segcount, sizeof(int), "makeBevelBPoints_segbevcount"); } BLI_addtail(bev, bl); @@ -2891,10 +2897,11 @@ void BKE_curve_bevelList_make(Object *ob, ListBase *nurbs, bool for_render) if (nu->pntsv == 1) { len = (resolu * segcount); - bl = MEM_callocN(sizeof(BevList) + len * sizeof(BevPoint), "makeBevelList3"); + bl = MEM_callocN(sizeof(BevList), "makeBevelList3"); + bl->bevpoints = MEM_calloc_arrayN(len, sizeof(BevPoint), "makeBevelPoints3"); if (need_seglen && (nu->flagu & CU_NURB_CYCLIC) == 0) { - bl->seglen = MEM_mallocN(segcount * sizeof(float), "makeBevelList3_seglen"); - bl->segbevcount = MEM_mallocN(segcount * sizeof(int), "makeBevelList3_segbevcount"); + bl->seglen = MEM_malloc_arrayN(segcount, sizeof(float), "makeBevelList3_seglen"); + bl->segbevcount = MEM_malloc_arrayN(segcount, sizeof(int), "makeBevelList3_segbevcount"); } BLI_addtail(bev, bl); bl->nr = len; @@ -2989,8 +2996,13 @@ void BKE_curve_bevelList_make(Object *ob, ListBase *nurbs, bool for_render) blnext = bl->next; if (bl->nr && bl->dupe_nr) { nr = bl->nr - bl->dupe_nr + 1; /* +1 because vectorbezier sets flag too */ - blnew = MEM_mallocN(sizeof(BevList) + nr * sizeof(BevPoint), "makeBevelList4"); + blnew = MEM_callocN(sizeof(BevList), "makeBevelList4"); memcpy(blnew, bl, sizeof(BevList)); + blnew->bevpoints = MEM_calloc_arrayN(nr, sizeof(BevPoint), "makeBevelPoints4"); + if (!blnew->bevpoints) { + MEM_freeN(blnew); + break; + } blnew->segbevcount = bl->segbevcount; blnew->seglen = bl->seglen; blnew->nr = 0; @@ -3007,6 +3019,9 @@ void BKE_curve_bevelList_make(Object *ob, ListBase *nurbs, bool for_render) } bevp0++; } + if (bl->bevpoints != NULL) { + MEM_freeN(bl->bevpoints); + } MEM_freeN(bl); blnew->dupe_nr = 0; } @@ -3027,7 +3042,7 @@ void BKE_curve_bevelList_make(Object *ob, ListBase *nurbs, bool for_render) /* find extreme left points, also test (turning) direction */ if (poly > 0) { - sd = sortdata = MEM_mallocN(sizeof(struct BevelSort) * poly, "makeBevelList5"); + sd = sortdata = MEM_malloc_arrayN(poly, sizeof(struct BevelSort), "makeBevelList5"); bl = bev->first; while (bl) { if (bl->poly > 0) { @@ -3445,7 +3460,7 @@ static void calchandlesNurb_intern(Nurb *nu, bool skip_align) */ static void *allocate_arrays(int count, float ***floats, char ***chars, const char *name) { - int num_floats = 0, num_chars = 0; + size_t num_floats = 0, num_chars = 0; while (floats && floats[num_floats]) { num_floats++; @@ -3455,7 +3470,7 @@ static void *allocate_arrays(int count, float ***floats, char ***chars, const ch num_chars++; } - void *buffer = (float *)MEM_mallocN(count * (sizeof(float) * num_floats + num_chars), name); + void *buffer = (float *)MEM_malloc_arrayN(count, (sizeof(float) * num_floats + num_chars), name); if (!buffer) return NULL; @@ -4429,7 +4444,7 @@ void BKE_nurb_direction_switch(Nurb *nu) /* and make in increasing order again */ a = KNOTSU(nu); fp1 = nu->knotsu; - fp2 = tempf = MEM_mallocN(sizeof(float) * a, "switchdirect"); + fp2 = tempf = MEM_malloc_arrayN(a, sizeof(float), "switchdirect"); a--; fp2[a] = fp1[a]; while (a--) { @@ -4473,7 +4488,7 @@ void BKE_nurb_direction_switch(Nurb *nu) float (*BKE_curve_nurbs_vertexCos_get(ListBase *lb, int *r_numVerts))[3] { int i, numVerts = *r_numVerts = BKE_nurbList_verts_count(lb); - float *co, (*cos)[3] = MEM_mallocN(sizeof(*cos) * numVerts, "cu_vcos"); + float *co, (*cos)[3] = MEM_malloc_arrayN(numVerts, sizeof(*cos), "cu_vcos"); Nurb *nu; co = cos[0]; @@ -4530,7 +4545,7 @@ void BK_curve_nurbs_vertexCos_apply(ListBase *lb, float (*vertexCos)[3]) float (*BKE_curve_nurbs_keyVertexCos_get(ListBase *lb, float *key))[3] { int i, numVerts = BKE_nurbList_verts_count(lb); - float *co, (*cos)[3] = MEM_mallocN(sizeof(*cos) * numVerts, "cu_vcos"); + float *co, (*cos)[3] = MEM_malloc_arrayN(numVerts, sizeof(*cos), "cu_vcos"); Nurb *nu; co = cos[0]; @@ -4677,7 +4692,7 @@ bool BKE_nurb_type_convert(Nurb *nu, const short type, const bool use_handles) if (nu->type == CU_POLY) { if (type == CU_BEZIER) { /* to Bezier with vecthandles */ nr = nu->pntsu; - bezt = (BezTriple *)MEM_callocN(nr * sizeof(BezTriple), "setsplinetype2"); + bezt = (BezTriple *)MEM_calloc_arrayN(nr, sizeof(BezTriple), "setsplinetype2"); nu->bezt = bezt; a = nr; bp = nu->bp; @@ -4713,7 +4728,7 @@ bool BKE_nurb_type_convert(Nurb *nu, const short type, const bool use_handles) else if (nu->type == CU_BEZIER) { /* Bezier */ if (type == CU_POLY || type == CU_NURBS) { nr = use_handles ? (3 * nu->pntsu) : nu->pntsu; - nu->bp = MEM_callocN(nr * sizeof(BPoint), "setsplinetype"); + nu->bp = MEM_calloc_arrayN(nr, sizeof(BPoint), "setsplinetype"); a = nu->pntsu; bezt = nu->bezt; bp = nu->bp; @@ -4776,7 +4791,7 @@ bool BKE_nurb_type_convert(Nurb *nu, const short type, const bool use_handles) return false; /* conversion impossible */ } else { - bezt = MEM_callocN(nr * sizeof(BezTriple), "setsplinetype2"); + bezt = MEM_calloc_arrayN(nr, sizeof(BezTriple), "setsplinetype2"); nu->bezt = bezt; a = nr; bp = nu->bp; @@ -4938,12 +4953,27 @@ void BKE_curve_nurb_vert_active_validate(Curve *cu) bool BKE_curve_minmax(Curve *cu, bool use_radius, float min[3], float max[3]) { ListBase *nurb_lb = BKE_curve_nurbs_get(cu); - Nurb *nu; - - for (nu = nurb_lb->first; nu; nu = nu->next) + ListBase temp_nurb_lb = {NULL, NULL}; + const bool is_font = (BLI_listbase_is_empty(nurb_lb)) && (cu->len != 0); + /* For font curves we generate temp list of splines. + * + * This is likely to be fine, this function is not supposed to be called + * often, and it's the only way to get meaningful bounds for fonts. + */ + if (is_font) { + nurb_lb = &temp_nurb_lb; + BKE_vfont_to_curve_ex(G.main, NULL, cu, FO_EDIT, nurb_lb, + NULL, NULL, NULL, NULL); + use_radius = false; + } + /* Do bounding box based on splines. */ + for (Nurb *nu = nurb_lb->first; nu; nu = nu->next) { BKE_nurb_minmax(nu, use_radius, min, max); - - return (BLI_listbase_is_empty(nurb_lb) == false); + } + const bool result = (BLI_listbase_is_empty(nurb_lb) == false); + /* Cleanup if needed. */ + BKE_nurbList_free(&temp_nurb_lb); + return result; } bool BKE_curve_center_median(Curve *cu, float cent[3]) diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c index 3bf5784e674..9c0ace2f654 100644 --- a/source/blender/blenkernel/intern/customdata.c +++ b/source/blender/blenkernel/intern/customdata.c @@ -157,7 +157,7 @@ static void layerCopy_mdeformvert(const void *source, void *dest, MDeformVert *dvert = POINTER_OFFSET(dest, i * size); if (dvert->totweight) { - MDeformWeight *dw = MEM_mallocN(dvert->totweight * sizeof(*dw), + MDeformWeight *dw = MEM_malloc_arrayN(dvert->totweight, sizeof(*dw), "layerCopy_mdeformvert dw"); memcpy(dw, dvert->dw, dvert->totweight * sizeof(*dw)); @@ -281,7 +281,7 @@ static void layerInterp_mdeformvert( } if (totweight) { - dvert->dw = MEM_mallocN(sizeof(*dvert->dw) * totweight, __func__); + dvert->dw = MEM_malloc_arrayN(totweight, sizeof(*dvert->dw), __func__); } } @@ -518,11 +518,11 @@ static void layerSwap_mdisps(void *data, const int *ci) MEM_freeN(s->disps); s->totdisp = (s->totdisp / corners) * nverts; - s->disps = MEM_callocN(s->totdisp * sizeof(float) * 3, "mdisp swap"); + s->disps = MEM_calloc_arrayN(s->totdisp, sizeof(float) * 3, "mdisp swap"); return; } - d = MEM_callocN(sizeof(float) * 3 * s->totdisp, "mdisps swap"); + d = MEM_calloc_arrayN(s->totdisp, 3 * sizeof(float), "mdisps swap"); for (S = 0; S < corners; S++) memcpy(d + cornersize * S, s->disps + cornersize * ci[S], cornersize * 3 * sizeof(float)); @@ -578,7 +578,7 @@ static int layerRead_mdisps(CDataFile *cdf, void *data, int count) for (i = 0; i < count; ++i) { if (!d[i].disps) - d[i].disps = MEM_callocN(sizeof(float) * 3 * d[i].totdisp, "mdisps read"); + d[i].disps = MEM_calloc_arrayN(d[i].totdisp, 3 * sizeof(float), "mdisps read"); if (!cdf_read_data(cdf, d[i].totdisp * 3 * sizeof(float), d[i].disps)) { printf("failed to read multires displacement %d/%d %d\n", i, count, d[i].totdisp); @@ -1796,7 +1796,7 @@ void CustomData_set_layer_flag(struct CustomData *data, int type, int flag) static int customData_resize(CustomData *data, int amount) { - CustomDataLayer *tmp = MEM_callocN(sizeof(*tmp) * (data->maxlayer + amount), + CustomDataLayer *tmp = MEM_calloc_arrayN((data->maxlayer + amount), sizeof(*tmp), "CustomData->layers"); if (!tmp) return 0; @@ -1814,7 +1814,6 @@ static CustomDataLayer *customData_add_layer__internal(CustomData *data, int typ int totelem, const char *name) { const LayerTypeInfo *typeInfo = layerType_getInfo(type); - const size_t size = (size_t)totelem * typeInfo->size; int flag = 0, index = data->totlayer; void *newlayerdata = NULL; @@ -1831,12 +1830,12 @@ static CustomDataLayer *customData_add_layer__internal(CustomData *data, int typ if ((alloctype == CD_ASSIGN) || (alloctype == CD_REFERENCE)) { newlayerdata = layerdata; } - else if (size > 0) { + else if (totelem > 0 && typeInfo->size > 0) { if (alloctype == CD_DUPLICATE && layerdata) { - newlayerdata = MEM_mallocN(size, layerType_getName(type)); + newlayerdata = MEM_malloc_arrayN((size_t)totelem, typeInfo->size, layerType_getName(type)); } else { - newlayerdata = MEM_callocN(size, layerType_getName(type)); + newlayerdata = MEM_calloc_arrayN((size_t)totelem, typeInfo->size, layerType_getName(type)); } if (!newlayerdata) @@ -1847,7 +1846,7 @@ static CustomDataLayer *customData_add_layer__internal(CustomData *data, int typ if (typeInfo->copy) typeInfo->copy(layerdata, newlayerdata, totelem); else - memcpy(newlayerdata, layerdata, size); + memcpy(newlayerdata, layerdata, (size_t)totelem * typeInfo->size); } else if (alloctype == CD_DEFAULT) { if (typeInfo->set_default) @@ -2038,7 +2037,7 @@ static void *customData_duplicate_referenced_layer_index(CustomData *data, const const LayerTypeInfo *typeInfo = layerType_getInfo(layer->type); if (typeInfo->copy) { - void *dst_data = MEM_mallocN((size_t)totelem * typeInfo->size, "CD duplicate ref layer"); + void *dst_data = MEM_malloc_arrayN((size_t)totelem, typeInfo->size, "CD duplicate ref layer"); typeInfo->copy(layer->data, dst_data, totelem); layer->data = dst_data; } @@ -2267,7 +2266,7 @@ void CustomData_interp(const CustomData *source, CustomData *dest, * elements */ if (count > SOURCE_BUF_SIZE) - sources = MEM_mallocN(sizeof(*sources) * count, __func__); + sources = MEM_malloc_arrayN(count, sizeof(*sources), __func__); /* interpolates a layer at a time */ dest_i = 0; @@ -3122,7 +3121,7 @@ void CustomData_bmesh_interp( * elements */ if (count > SOURCE_BUF_SIZE) - sources = MEM_mallocN(sizeof(*sources) * count, __func__); + sources = MEM_malloc_arrayN(count, sizeof(*sources), __func__); /* interpolates a layer at a time */ for (i = 0; i < data->totlayer; ++i) { @@ -3312,7 +3311,7 @@ void CustomData_file_write_prepare( else { if (UNLIKELY((size_t)j >= write_layers_size)) { if (write_layers == write_layers_buff) { - write_layers = MEM_mallocN(sizeof(*write_layers) * (write_layers_size + chunk_size), __func__); + write_layers = MEM_malloc_arrayN((write_layers_size + chunk_size), sizeof(*write_layers), __func__); if (write_layers_buff) { memcpy(write_layers, write_layers_buff, sizeof(*write_layers) * write_layers_size); } @@ -3980,7 +3979,7 @@ void CustomData_data_transfer(const MeshPairRemap *me_remap, const CustomDataTra } if (data_src) { - tmp_data_src = MEM_mallocN(sizeof(*tmp_data_src) * tmp_buff_size, __func__); + tmp_data_src = MEM_malloc_arrayN(tmp_buff_size, sizeof(*tmp_data_src), __func__); } if (data_type & CD_FAKE) { diff --git a/source/blender/blenkernel/intern/customdata_file.c b/source/blender/blenkernel/intern/customdata_file.c index 41579aaa568..d17c9ef5cc6 100644 --- a/source/blender/blenkernel/intern/customdata_file.c +++ b/source/blender/blenkernel/intern/customdata_file.c @@ -210,9 +210,13 @@ static int cdf_read_header(CDataFile *cdf) if (fseek(f, offset, SEEK_SET) != 0) return 0; - cdf->layer = MEM_callocN(sizeof(CDataFileLayer) * header->totlayer, "CDataFileLayer"); + cdf->layer = MEM_calloc_arrayN(header->totlayer, sizeof(CDataFileLayer), "CDataFileLayer"); cdf->totlayer = header->totlayer; + if (!cdf->layer) { + return 0; + } + for (a = 0; a < header->totlayer; a++) { layer = &cdf->layer[a]; @@ -429,7 +433,7 @@ CDataFileLayer *cdf_layer_add(CDataFile *cdf, int type, const char *name, size_t CDataFileLayer *newlayer, *layer; /* expand array */ - newlayer = MEM_callocN(sizeof(CDataFileLayer) * (cdf->totlayer + 1), "CDataFileLayer"); + newlayer = MEM_calloc_arrayN((cdf->totlayer + 1), sizeof(CDataFileLayer), "CDataFileLayer"); memcpy(newlayer, cdf->layer, sizeof(CDataFileLayer) * cdf->totlayer); cdf->layer = newlayer; diff --git a/source/blender/blenkernel/intern/deform.c b/source/blender/blenkernel/intern/deform.c index 1fc83b69bfe..d4ff9bd5c0c 100644 --- a/source/blender/blenkernel/intern/deform.c +++ b/source/blender/blenkernel/intern/deform.c @@ -628,7 +628,7 @@ float defvert_array_find_weight_safe(const struct MDeformVert *dvert, const int * (i.e. maximum weight, as if no vgroup was selected). * But in case of valid defgroup and NULL dvert data pointer, it means that vgroup **is** valid, * and just totally empty, so we shall return '0.0' value then! - */ + */ if (defgroup == -1) { return 1.0f; } diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c index 80a31697424..2591c3c3c47 100644 --- a/source/blender/blenkernel/intern/dynamicpaint.c +++ b/source/blender/blenkernel/intern/dynamicpaint.c @@ -55,6 +55,7 @@ #include "BKE_animsys.h" #include "BKE_armature.h" #include "BKE_bvhutils.h" /* bvh tree */ +#include "BKE_colorband.h" #include "BKE_cdderivedmesh.h" #include "BKE_constraint.h" #include "BKE_customdata.h" @@ -72,7 +73,6 @@ #include "BKE_particle.h" #include "BKE_pointcache.h" #include "BKE_scene.h" -#include "BKE_texture.h" #include "DEG_depsgraph.h" @@ -604,16 +604,19 @@ static void freeGrid(PaintSurfaceData *data) bData->grid = NULL; } -static void grid_bound_insert_cb_ex(void *userdata, void *userdata_chunk, const int i, const int UNUSED(thread_id)) +static void grid_bound_insert_cb_ex(void *__restrict userdata, + const int i, + const ParallelRangeTLS *__restrict tls) { PaintBakeData *bData = userdata; - Bounds3D *grid_bound = userdata_chunk; + Bounds3D *grid_bound = tls->userdata_chunk; boundInsert(grid_bound, bData->realCoord[bData->s_pos[i]].v); } -static void grid_bound_insert_finalize(void *userdata, void *userdata_chunk) +static void grid_bound_insert_finalize(void *__restrict userdata, + void *__restrict userdata_chunk) { PaintBakeData *bData = userdata; VolumeGrid *grid = bData->grid; @@ -624,12 +627,14 @@ static void grid_bound_insert_finalize(void *userdata, void *userdata_chunk) boundInsert(&grid->grid_bounds, grid_bound->max); } -static void grid_cell_points_cb_ex(void *userdata, void *userdata_chunk, const int i, const int UNUSED(thread_id)) +static void grid_cell_points_cb_ex(void *__restrict userdata, + const int i, + const ParallelRangeTLS *__restrict tls) { PaintBakeData *bData = userdata; VolumeGrid *grid = bData->grid; int *temp_t_index = grid->temp_t_index; - int *s_num = userdata_chunk; + int *s_num = tls->userdata_chunk; int co[3]; @@ -643,7 +648,8 @@ static void grid_cell_points_cb_ex(void *userdata, void *userdata_chunk, const i s_num[temp_t_index[i]]++; } -static void grid_cell_points_finalize(void *userdata, void *userdata_chunk) +static void grid_cell_points_finalize(void *__restrict userdata, + void *__restrict userdata_chunk) { PaintBakeData *bData = userdata; VolumeGrid *grid = bData->grid; @@ -657,7 +663,9 @@ static void grid_cell_points_finalize(void *userdata, void *userdata_chunk) } } -static void grid_cell_bounds_cb(void *userdata, const int x) +static void grid_cell_bounds_cb(void *__restrict userdata, + const int x, + const ParallelRangeTLS *__restrict UNUSED(tls)) { PaintBakeData *bData = userdata; VolumeGrid *grid = bData->grid; @@ -702,10 +710,19 @@ static void surfaceGenerateGrid(struct DynamicPaintSurface *surface) /* calculate canvas dimensions */ /* Important to init correctly our ref grid_bound... */ boundInsert(&grid->grid_bounds, bData->realCoord[bData->s_pos[0]].v); - BLI_task_parallel_range_finalize( - 0, sData->total_points, bData, &grid->grid_bounds, sizeof(grid->grid_bounds), - grid_bound_insert_cb_ex, grid_bound_insert_finalize, sData->total_points > 1000, false); - + { + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = (sData->total_points > 1000); + settings.userdata_chunk = &grid->grid_bounds; + settings.userdata_chunk_size = sizeof(grid->grid_bounds); + settings.func_finalize = grid_bound_insert_finalize; + BLI_task_parallel_range( + 0, sData->total_points, + bData, + grid_bound_insert_cb_ex, + &settings); + } /* get dimensions */ sub_v3_v3v3(dim, grid->grid_bounds.max, grid->grid_bounds.min); copy_v3_v3(td, dim); @@ -754,9 +771,19 @@ static void surfaceGenerateGrid(struct DynamicPaintSurface *surface) if (!error) { /* calculate number of points withing each cell */ - BLI_task_parallel_range_finalize( - 0, sData->total_points, bData, grid->s_num, sizeof(*grid->s_num) * grid_cells, - grid_cell_points_cb_ex, grid_cell_points_finalize, sData->total_points > 1000, false); + { + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = (sData->total_points > 1000); + settings.userdata_chunk = grid->s_num; + settings.userdata_chunk_size = sizeof(*grid->s_num) * grid_cells; + settings.func_finalize = grid_cell_points_finalize; + BLI_task_parallel_range( + 0, sData->total_points, + bData, + grid_cell_points_cb_ex, + &settings); + } /* calculate grid indexes (not needed for first cell, which is zero). */ for (i = 1; i < grid_cells; i++) { @@ -772,7 +799,15 @@ static void surfaceGenerateGrid(struct DynamicPaintSurface *surface) } /* calculate cell bounds */ - BLI_task_parallel_range(0, grid->dim[0], bData, grid_cell_bounds_cb, grid_cells > 1000); + { + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = (grid_cells > 1000); + BLI_task_parallel_range(0, grid->dim[0], + bData, + grid_cell_bounds_cb, + &settings); + } } if (temp_s_num) @@ -1085,7 +1120,7 @@ bool dynamicPaint_createType(struct DynamicPaintModifierData *pmd, int type, str { CBData *ramp; - brush->paint_ramp = add_colorband(false); + brush->paint_ramp = BKE_colorband_add(false); if (!brush->paint_ramp) return false; ramp = brush->paint_ramp->data; @@ -1101,7 +1136,7 @@ bool dynamicPaint_createType(struct DynamicPaintModifierData *pmd, int type, str { CBData *ramp; - brush->vel_ramp = add_colorband(false); + brush->vel_ramp = BKE_colorband_add(false); if (!brush->vel_ramp) return false; ramp = brush->vel_ramp->data; @@ -1390,7 +1425,10 @@ typedef struct DynamicPaintSetInitColorData { const bool scene_color_manage; } DynamicPaintSetInitColorData; -static void dynamic_paint_set_init_color_tex_to_vcol_cb(void *userdata, const int i) +static void dynamic_paint_set_init_color_tex_to_vcol_cb( + void *__restrict userdata, + const int i, + const ParallelRangeTLS *__restrict UNUSED(tls)) { const DynamicPaintSetInitColorData *data = userdata; @@ -1424,7 +1462,10 @@ static void dynamic_paint_set_init_color_tex_to_vcol_cb(void *userdata, const in } } -static void dynamic_paint_set_init_color_tex_to_imseq_cb(void *userdata, const int i) +static void dynamic_paint_set_init_color_tex_to_imseq_cb( + void *__restrict userdata, + const int i, + const ParallelRangeTLS *__restrict UNUSED(tls)) { const DynamicPaintSetInitColorData *data = userdata; @@ -1462,7 +1503,10 @@ static void dynamic_paint_set_init_color_tex_to_imseq_cb(void *userdata, const i pPoint[i].color[3] = texres.tin; } -static void dynamic_paint_set_init_color_vcol_to_imseq_cb(void *userdata, const int i) +static void dynamic_paint_set_init_color_vcol_to_imseq_cb( + void *__restrict userdata, + const int i, + const ParallelRangeTLS *__restrict UNUSED(tls)) { const DynamicPaintSetInitColorData *data = userdata; @@ -1540,7 +1584,13 @@ static void dynamicPaint_setInitialColor(const Scene *scene, DynamicPaintSurface .mloop = mloop, .mlooptri = mlooptri, .mloopuv = mloopuv, .pool = pool, .scene_color_manage = scene_color_manage }; - BLI_task_parallel_range(0, tottri, &data, dynamic_paint_set_init_color_tex_to_vcol_cb, tottri > 1000); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = (tottri > 1000); + BLI_task_parallel_range(0, tottri, + &data, + dynamic_paint_set_init_color_tex_to_vcol_cb, + &settings); BKE_image_pool_free(pool); } else if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) { @@ -1549,8 +1599,13 @@ static void dynamicPaint_setInitialColor(const Scene *scene, DynamicPaintSurface .mlooptri = mlooptri, .mloopuv = mloopuv, .scene_color_manage = scene_color_manage }; - BLI_task_parallel_range(0, sData->total_points, &data, dynamic_paint_set_init_color_tex_to_imseq_cb, - sData->total_points > 1000); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = (sData->total_points > 1000); + BLI_task_parallel_range(0, sData->total_points, + &data, + dynamic_paint_set_init_color_tex_to_imseq_cb, + &settings); } } /* vertex color layer */ @@ -1578,8 +1633,13 @@ static void dynamicPaint_setInitialColor(const Scene *scene, DynamicPaintSurface .surface = surface, .mlooptri = mlooptri, .mloopcol = col, }; - BLI_task_parallel_range(0, sData->total_points, &data, dynamic_paint_set_init_color_vcol_to_imseq_cb, - sData->total_points > 1000); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = (sData->total_points > 1000); + BLI_task_parallel_range(0, sData->total_points, + &data, + dynamic_paint_set_init_color_vcol_to_imseq_cb, + &settings); } } } @@ -1666,7 +1726,10 @@ typedef struct DynamicPaintModifierApplyData { MLoopCol *mloopcol_preview; } DynamicPaintModifierApplyData; -static void dynamic_paint_apply_surface_displace_cb(void *userdata, const int i) +static void dynamic_paint_apply_surface_displace_cb( + void *__restrict userdata, + const int i, + const ParallelRangeTLS *__restrict UNUSED(tls)) { const DynamicPaintModifierApplyData *data = userdata; @@ -1696,12 +1759,20 @@ static void dynamicPaint_applySurfaceDisplace(DynamicPaintSurface *surface, Deri MVert *mvert = result->getVertArray(result); DynamicPaintModifierApplyData data = {.surface = surface, .mvert = mvert}; - BLI_task_parallel_range(0, sData->total_points, &data, dynamic_paint_apply_surface_displace_cb, - sData->total_points > 10000); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = (sData->total_points > 10000); + BLI_task_parallel_range(0, sData->total_points, + &data, + dynamic_paint_apply_surface_displace_cb, + &settings); } } -static void dynamic_paint_apply_surface_vpaint_blend_cb(void *userdata, const int i) +static void dynamic_paint_apply_surface_vpaint_blend_cb( + void *__restrict userdata, + const int i, + const ParallelRangeTLS *__restrict UNUSED(tls)) { const DynamicPaintModifierApplyData *data = userdata; @@ -1712,7 +1783,10 @@ static void dynamic_paint_apply_surface_vpaint_blend_cb(void *userdata, const in blendColors(pPoint[i].color, pPoint[i].color[3], pPoint[i].e_color, pPoint[i].e_color[3], fcolor[i]); } -static void dynamic_paint_apply_surface_vpaint_cb(void *userdata, const int p_index) +static void dynamic_paint_apply_surface_vpaint_cb( + void *__restrict userdata, + const int p_index, + const ParallelRangeTLS *__restrict UNUSED(tls)) { const DynamicPaintModifierApplyData *data = userdata; Object *ob = data->ob; @@ -1782,7 +1856,10 @@ static void dynamic_paint_apply_surface_vpaint_cb(void *userdata, const int p_in } } -static void dynamic_paint_apply_surface_wave_cb(void *userdata, const int i) +static void dynamic_paint_apply_surface_wave_cb( + void *__restrict userdata, + const int i, + const ParallelRangeTLS *__restrict UNUSED(tls)) { const DynamicPaintModifierApplyData *data = userdata; @@ -1829,9 +1906,16 @@ static DerivedMesh *dynamicPaint_Modifier_apply( float (*fcolor)[4] = MEM_callocN(sizeof(*fcolor) * sData->total_points, "Temp paint color"); DynamicPaintModifierApplyData data = {.surface = surface, .fcolor = fcolor}; - BLI_task_parallel_range(0, sData->total_points, &data, - dynamic_paint_apply_surface_vpaint_blend_cb, - sData->total_points > 1000); + { + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = (sData->total_points > 1000); + BLI_task_parallel_range( + 0, sData->total_points, + &data, + dynamic_paint_apply_surface_vpaint_blend_cb, + &settings); + } /* paint layer */ MLoopCol *mloopcol = CustomData_get_layer_named(&result->loopData, CD_MLOOPCOL, surface->output_name); @@ -1866,8 +1950,16 @@ static DerivedMesh *dynamicPaint_Modifier_apply( data.mloopcol_wet = mloopcol_wet; data.mloopcol_preview = mloopcol_preview; - BLI_task_parallel_range(0, totpoly, &data, dynamic_paint_apply_surface_vpaint_cb, - totpoly > 1000); + { + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = (totpoly > 1000); + BLI_task_parallel_range( + 0, totpoly, + &data, + dynamic_paint_apply_surface_vpaint_cb, + &settings); + } MEM_freeN(fcolor); @@ -1917,8 +2009,14 @@ static DerivedMesh *dynamicPaint_Modifier_apply( MVert *mvert = result->getVertArray(result); DynamicPaintModifierApplyData data = {.surface = surface, .mvert = mvert}; - BLI_task_parallel_range(0, sData->total_points, &data, dynamic_paint_apply_surface_wave_cb, - sData->total_points > 1000); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = (sData->total_points > 1000); + BLI_task_parallel_range( + 0, sData->total_points, + &data, + dynamic_paint_apply_surface_wave_cb, + &settings); update_normals = true; } @@ -2103,7 +2201,10 @@ typedef struct DynamicPaintCreateUVSurfaceData { uint32_t *active_points; } DynamicPaintCreateUVSurfaceData; -static void dynamic_paint_create_uv_surface_direct_cb(void *userdata, const int ty) +static void dynamic_paint_create_uv_surface_direct_cb( + void *__restrict userdata, + const int ty, + const ParallelRangeTLS *__restrict UNUSED(tls)) { const DynamicPaintCreateUVSurfaceData *data = userdata; @@ -2200,7 +2301,10 @@ static void dynamic_paint_create_uv_surface_direct_cb(void *userdata, const int } } -static void dynamic_paint_create_uv_surface_neighbor_cb(void *userdata, const int ty) +static void dynamic_paint_create_uv_surface_neighbor_cb( + void *__restrict userdata, + const int ty, + const ParallelRangeTLS *__restrict UNUSED(tls)) { const DynamicPaintCreateUVSurfaceData *data = userdata; @@ -2760,7 +2864,15 @@ int dynamicPaint_createUVSurface(Scene *scene, DynamicPaintSurface *surface, flo .mlooptri = mlooptri, .mloopuv = mloopuv, .mloop = mloop, .tottri = tottri, .faceBB = faceBB, }; - BLI_task_parallel_range(0, h, &data, dynamic_paint_create_uv_surface_direct_cb, h > 64 || tottri > 1000); + { + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = (h > 64 || tottri > 1000); + BLI_task_parallel_range(0, h, + &data, + dynamic_paint_create_uv_surface_direct_cb, + &settings); + } *progress = 0.04f; *do_update = true; @@ -2772,7 +2884,15 @@ int dynamicPaint_createUVSurface(Scene *scene, DynamicPaintSurface *surface, flo * (To avoid seams on uv island edges) */ data.active_points = &active_points; - BLI_task_parallel_range(0, h, &data, dynamic_paint_create_uv_surface_neighbor_cb, h > 64); + { + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = (h > 64); + BLI_task_parallel_range(0, h, + &data, + dynamic_paint_create_uv_surface_neighbor_cb, + &settings); + } *progress = 0.06f; *do_update = true; @@ -2931,7 +3051,7 @@ int dynamicPaint_createUVSurface(Scene *scene, DynamicPaintSurface *surface, flo if (tempPoints[index].tri_index != -1) { memcpy(&f_data->uv_p[cursor], &tempPoints[index], sizeof(PaintUVPoint)); memcpy(&f_data->barycentricWeights[cursor * aa_samples], &tempWeights[index * aa_samples], - sizeof(*tempWeights) * aa_samples); + sizeof(*tempWeights) * aa_samples); cursor++; } } @@ -2992,7 +3112,10 @@ typedef struct DynamicPaintOutputSurfaceImageData { ImBuf *ibuf; } DynamicPaintOutputSurfaceImageData; -static void dynamic_paint_output_surface_image_paint_cb(void *userdata, const int index) +static void dynamic_paint_output_surface_image_paint_cb( + void *__restrict userdata, + const int index, + const ParallelRangeTLS *__restrict UNUSED(tls)) { const DynamicPaintOutputSurfaceImageData *data = userdata; @@ -3012,7 +3135,10 @@ static void dynamic_paint_output_surface_image_paint_cb(void *userdata, const in } } -static void dynamic_paint_output_surface_image_displace_cb(void *userdata, const int index) +static void dynamic_paint_output_surface_image_displace_cb( + void *__restrict userdata, + const int index, + const ParallelRangeTLS *__restrict UNUSED(tls)) { const DynamicPaintOutputSurfaceImageData *data = userdata; @@ -3036,7 +3162,10 @@ static void dynamic_paint_output_surface_image_displace_cb(void *userdata, const ibuf->rect_float[pos + 3] = 1.0f; } -static void dynamic_paint_output_surface_image_wave_cb(void *userdata, const int index) +static void dynamic_paint_output_surface_image_wave_cb( + void *__restrict userdata, + const int index, + const ParallelRangeTLS *__restrict UNUSED(tls)) { const DynamicPaintOutputSurfaceImageData *data = userdata; @@ -3058,7 +3187,10 @@ static void dynamic_paint_output_surface_image_wave_cb(void *userdata, const int ibuf->rect_float[pos + 3] = 1.0f; } -static void dynamic_paint_output_surface_image_wetmap_cb(void *userdata, const int index) +static void dynamic_paint_output_surface_image_wetmap_cb( + void *__restrict userdata, + const int index, + const ParallelRangeTLS *__restrict UNUSED(tls)) { const DynamicPaintOutputSurfaceImageData *data = userdata; @@ -3109,13 +3241,29 @@ void dynamicPaint_outputSurfaceImage(DynamicPaintSurface *surface, char *filenam case MOD_DPAINT_SURFACE_T_PAINT: switch (output_layer) { case 0: - BLI_task_parallel_range(0, sData->total_points, &data, - dynamic_paint_output_surface_image_paint_cb, sData->total_points > 10000); + { + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = (sData->total_points > 10000); + BLI_task_parallel_range( + 0, sData->total_points, + &data, + dynamic_paint_output_surface_image_paint_cb, + &settings); break; + } case 1: - BLI_task_parallel_range(0, sData->total_points, &data, - dynamic_paint_output_surface_image_wetmap_cb, sData->total_points > 10000); + { + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = (sData->total_points > 10000); + BLI_task_parallel_range( + 0, sData->total_points, + &data, + dynamic_paint_output_surface_image_wetmap_cb, + &settings); break; + } default: BLI_assert(0); break; @@ -3124,9 +3272,17 @@ void dynamicPaint_outputSurfaceImage(DynamicPaintSurface *surface, char *filenam case MOD_DPAINT_SURFACE_T_DISPLACE: switch (output_layer) { case 0: - BLI_task_parallel_range(0, sData->total_points, &data, - dynamic_paint_output_surface_image_displace_cb, sData->total_points > 10000); + { + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = (sData->total_points > 10000); + BLI_task_parallel_range( + 0, sData->total_points, + &data, + dynamic_paint_output_surface_image_displace_cb, + &settings); break; + } case 1: break; default: @@ -3137,9 +3293,17 @@ void dynamicPaint_outputSurfaceImage(DynamicPaintSurface *surface, char *filenam case MOD_DPAINT_SURFACE_T_WAVE: switch (output_layer) { case 0: - BLI_task_parallel_range(0, sData->total_points, &data, - dynamic_paint_output_surface_image_wave_cb, sData->total_points > 10000); + { + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = (sData->total_points > 10000); + BLI_task_parallel_range( + 0, sData->total_points, + &data, + dynamic_paint_output_surface_image_wave_cb, + &settings); break; + } case 1: break; default: @@ -3459,7 +3623,7 @@ static void dynamicPaint_updatePointData( vel_factor /= brush->max_velocity; CLAMP(vel_factor, 0.0f, 1.0f); - if (do_colorband(brush->vel_ramp, vel_factor, coba_res)) { + if (BKE_colorband_evaluate(brush->vel_ramp, vel_factor, coba_res)) { if (brush->flags & MOD_DPAINT_VELOCITY_COLOR) { copy_v3_v3(paint, coba_res); } @@ -3546,7 +3710,10 @@ typedef struct DynamicPaintBrushVelocityData { const float timescale; } DynamicPaintBrushVelocityData; -static void dynamic_paint_brush_velocity_compute_cb(void *userdata, const int i) +static void dynamic_paint_brush_velocity_compute_cb( + void *__restrict userdata, + const int i, + const ParallelRangeTLS *__restrict UNUSED(tls)) { const DynamicPaintBrushVelocityData *data = userdata; @@ -3626,7 +3793,13 @@ static void dynamicPaint_brushMeshCalculateVelocity( .mvert_p = mvert_p, .mvert_c = mvert_c, .obmat = ob->obmat, .prev_obmat = prev_obmat, .timescale = timescale, }; - BLI_task_parallel_range(0, numOfVerts_c, &data, dynamic_paint_brush_velocity_compute_cb, numOfVerts_c > 10000); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = (numOfVerts_c > 10000); + BLI_task_parallel_range(0, numOfVerts_c, + &data, + dynamic_paint_brush_velocity_compute_cb, + &settings); dm_p->release(dm_p); } @@ -3697,7 +3870,9 @@ typedef struct DynamicPaintPaintData { * Paint a brush object mesh to the surface */ static void dynamic_paint_paint_mesh_cell_point_cb_ex( - void *userdata, void *UNUSED(userdata_chunk), const int id, const int UNUSED(threadid)) + void *__restrict userdata, + const int id, + const ParallelRangeTLS *__restrict UNUSED(tls)) { const DynamicPaintPaintData *data = userdata; @@ -3906,7 +4081,7 @@ static void dynamic_paint_paint_mesh_cell_point_cb_ex( else if (hit_found == HIT_PROXIMITY) { /* apply falloff curve to the proximity_factor */ if (brush->proximity_falloff == MOD_DPAINT_PRFALL_RAMP && - do_colorband(brush->paint_ramp, (1.0f - proximity_factor), prox_colorband)) + BKE_colorband_evaluate(brush->paint_ramp, (1.0f - proximity_factor), prox_colorband)) { proximity_factor = prox_colorband[3]; } @@ -4115,9 +4290,13 @@ static int dynamicPaint_paintMesh(const struct EvaluationContext *eval_ctx, Dyna .brush_radius = brush_radius, .avg_brushNor = avg_brushNor, .brushVelocity = brushVelocity, .treeData = &treeData }; - BLI_task_parallel_range_ex(0, grid->s_num[c_index], &data, NULL, 0, - dynamic_paint_paint_mesh_cell_point_cb_ex, - grid->s_num[c_index] > 250, true); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = (grid->s_num[c_index] > 250); + BLI_task_parallel_range(0, grid->s_num[c_index], + &data, + dynamic_paint_paint_mesh_cell_point_cb_ex, + &settings); } } } @@ -4138,7 +4317,9 @@ static int dynamicPaint_paintMesh(const struct EvaluationContext *eval_ctx, Dyna * Paint a particle system to the surface */ static void dynamic_paint_paint_particle_cell_point_cb_ex( - void *userdata, void *UNUSED(userdata_chunk), const int id, const int UNUSED(threadid)) + void *__restrict userdata, + const int id, + const ParallelRangeTLS *__restrict UNUSED(tls)) { const DynamicPaintPaintData *data = userdata; @@ -4400,9 +4581,13 @@ static int dynamicPaint_paintParticles(DynamicPaintSurface *surface, .solidradius = solidradius, .timescale = timescale, .c_index = c_index, .treeData = tree, }; - BLI_task_parallel_range_ex(0, grid->s_num[c_index], &data, NULL, 0, - dynamic_paint_paint_particle_cell_point_cb_ex, - grid->s_num[c_index] > 250, true); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = (grid->s_num[c_index] > 250); + BLI_task_parallel_range(0, grid->s_num[c_index], + &data, + dynamic_paint_paint_particle_cell_point_cb_ex, + &settings); } } BLI_end_threaded_malloc(); @@ -4413,7 +4598,9 @@ static int dynamicPaint_paintParticles(DynamicPaintSurface *surface, /* paint a single point of defined proximity radius to the surface */ static void dynamic_paint_paint_single_point_cb_ex( - void *userdata, void *UNUSED(userdata_chunk), const int index, const int UNUSED(threadid)) + void *__restrict userdata, + const int index, + const ParallelRangeTLS *__restrict UNUSED(tls)) { const DynamicPaintPaintData *data = userdata; @@ -4470,7 +4657,7 @@ static void dynamic_paint_paint_single_point_cb_ex( /* color ramp */ if (brush->proximity_falloff == MOD_DPAINT_PRFALL_RAMP && - do_colorband(brush->paint_ramp, (1.0f - strength), colorband)) + BKE_colorband_evaluate(brush->paint_ramp, (1.0f - strength), colorband)) { strength = colorband[3]; } @@ -4545,9 +4732,13 @@ static int dynamicPaint_paintSinglePoint( .brush_radius = brush_radius, .brushVelocity = &brushVel, .pointCoord = pointCoord, }; - BLI_task_parallel_range_ex(0, sData->total_points, &data, NULL, 0, - dynamic_paint_paint_single_point_cb_ex, - sData->total_points > 1000, true); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = (sData->total_points > 1000); + BLI_task_parallel_range(0, sData->total_points, + &data, + dynamic_paint_paint_single_point_cb_ex, + &settings); return 1; } @@ -4559,7 +4750,10 @@ static int dynamicPaint_paintSinglePoint( * Calculate current frame distances and directions for adjacency data */ -static void dynamic_paint_prepare_adjacency_cb(void *userdata, const int index) +static void dynamic_paint_prepare_adjacency_cb( + void *__restrict userdata, + const int index, + const ParallelRangeTLS *__restrict UNUSED(tls)) { PaintSurfaceData *sData = userdata; PaintBakeData *bData = sData->bData; @@ -4598,8 +4792,13 @@ static void dynamicPaint_prepareAdjacencyData(DynamicPaintSurface *surface, cons if (!bNeighs) return; - BLI_task_parallel_range( - 0, sData->total_points, sData, dynamic_paint_prepare_adjacency_cb, sData->total_points > 1000); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = (sData->total_points > 1000); + BLI_task_parallel_range(0, sData->total_points, + sData, + dynamic_paint_prepare_adjacency_cb, + &settings); /* calculate average values (single thread). * Note: tried to put this in threaded callback (using _finalize feature), but gave ~30% slower result! */ @@ -4786,7 +4985,10 @@ typedef struct DynamicPaintEffectData { * Prepare data required by effects for current frame. * Returns number of steps required */ -static void dynamic_paint_prepare_effect_cb(void *userdata, const int index) +static void dynamic_paint_prepare_effect_cb( + void *__restrict userdata, + const int index, + const ParallelRangeTLS *__restrict UNUSED(tls)) { const DynamicPaintEffectData *data = userdata; @@ -4858,8 +5060,13 @@ static int dynamicPaint_prepareEffectStep( .surface = surface, .scene = scene, .force = *force, .effectors = effectors, }; - BLI_task_parallel_range( - 0, sData->total_points, &data, dynamic_paint_prepare_effect_cb, sData->total_points > 1000); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = (sData->total_points > 1000); + BLI_task_parallel_range(0, sData->total_points, + &data, + dynamic_paint_prepare_effect_cb, + &settings); /* calculate average values (single thread) */ for (int index = 0; index < sData->total_points; index++) { @@ -4891,7 +5098,10 @@ static int dynamicPaint_prepareEffectStep( /** * Processes active effect step. */ -static void dynamic_paint_effect_spread_cb(void *userdata, const int index) +static void dynamic_paint_effect_spread_cb( + void *__restrict userdata, + const int index, + const ParallelRangeTLS *__restrict UNUSED(tls)) { const DynamicPaintEffectData *data = userdata; @@ -4936,7 +5146,10 @@ static void dynamic_paint_effect_spread_cb(void *userdata, const int index) } } -static void dynamic_paint_effect_shrink_cb(void *userdata, const int index) +static void dynamic_paint_effect_shrink_cb( + void *__restrict userdata, + const int index, + const ParallelRangeTLS *__restrict UNUSED(tls)) { const DynamicPaintEffectData *data = userdata; @@ -4986,7 +5199,10 @@ static void dynamic_paint_effect_shrink_cb(void *userdata, const int index) } } -static void dynamic_paint_effect_drip_cb(void *userdata, const int index) +static void dynamic_paint_effect_drip_cb( + void *__restrict userdata, + const int index, + const ParallelRangeTLS *__restrict UNUSED(tls)) { const DynamicPaintEffectData *data = userdata; @@ -5119,8 +5335,13 @@ static void dynamicPaint_doEffectStep( DynamicPaintEffectData data = { .surface = surface, .prevPoint = prevPoint, .eff_scale = eff_scale, }; - BLI_task_parallel_range( - 0, sData->total_points, &data, dynamic_paint_effect_spread_cb, sData->total_points > 1000); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = (sData->total_points > 1000); + BLI_task_parallel_range(0, sData->total_points, + &data, + dynamic_paint_effect_spread_cb, + &settings); } /* @@ -5135,8 +5356,13 @@ static void dynamicPaint_doEffectStep( DynamicPaintEffectData data = { .surface = surface, .prevPoint = prevPoint, .eff_scale = eff_scale, }; - BLI_task_parallel_range( - 0, sData->total_points, &data, dynamic_paint_effect_shrink_cb, sData->total_points > 1000); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = (sData->total_points > 1000); + BLI_task_parallel_range(0, sData->total_points, + &data, + dynamic_paint_effect_shrink_cb, + &settings); } /* @@ -5157,14 +5383,22 @@ static void dynamicPaint_doEffectStep( .eff_scale = eff_scale, .force = force, .point_locks = point_locks, }; - BLI_task_parallel_range( - 0, sData->total_points, &data, dynamic_paint_effect_drip_cb, sData->total_points > 1000); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = (sData->total_points > 1000); + BLI_task_parallel_range(0, sData->total_points, + &data, + dynamic_paint_effect_drip_cb, + &settings); MEM_freeN(point_locks); } } -static void dynamic_paint_border_cb(void *userdata, const int b_index) +static void dynamic_paint_border_cb( + void *__restrict userdata, + const int b_index, + const ParallelRangeTLS *__restrict UNUSED(tls)) { const DynamicPaintEffectData *data = userdata; @@ -5234,11 +5468,19 @@ static void dynamicPaint_doBorderStep(DynamicPaintSurface *surface) .surface = surface }; - BLI_task_parallel_range( - 0, sData->adj_data->total_border, &data, dynamic_paint_border_cb, sData->adj_data->total_border > 1000); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = (sData->adj_data->total_border > 1000); + BLI_task_parallel_range(0, sData->adj_data->total_border, + &data, + dynamic_paint_border_cb, + &settings); } -static void dynamic_paint_wave_step_cb(void *userdata, const int index) +static void dynamic_paint_wave_step_cb( + void *__restrict userdata, + const int index, + const ParallelRangeTLS *__restrict UNUSED(tls)) { const DynamicPaintEffectData *data = userdata; @@ -5380,8 +5622,12 @@ static void dynamicPaint_doWaveStep(DynamicPaintSurface *surface, float timescal .wave_speed = wave_speed, .wave_scale = wave_scale, .wave_max_slope = wave_max_slope, .dt = dt, .min_dist = min_dist, .damp_factor = damp_factor, .reset_wave = (ss == steps - 1), }; - BLI_task_parallel_range( - 0, sData->total_points, &data, dynamic_paint_wave_step_cb, sData->total_points > 1000); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = (sData->total_points > 1000); + BLI_task_parallel_range(0, sData->total_points, + &data, dynamic_paint_wave_step_cb, + &settings); } MEM_freeN(prevPoint); @@ -5401,7 +5647,10 @@ typedef struct DynamicPaintDissolveDryData { const float timescale; } DynamicPaintDissolveDryData; -static void dynamic_paint_surface_pre_step_cb(void *userdata, const int index) +static void dynamic_paint_surface_pre_step_cb( + void *__restrict userdata, + const int index, + const ParallelRangeTLS *__restrict UNUSED(tls)) { const DynamicPaintDissolveDryData *data = userdata; @@ -5524,7 +5773,10 @@ typedef struct DynamicPaintGenerateBakeData { const bool new_bdata; } DynamicPaintGenerateBakeData; -static void dynamic_paint_generate_bake_data_cb(void *userdata, const int index) +static void dynamic_paint_generate_bake_data_cb( + void *__restrict userdata, + const int index, + const ParallelRangeTLS *__restrict UNUSED(tls)) { const DynamicPaintGenerateBakeData *data = userdata; @@ -5728,8 +5980,13 @@ static int dynamicPaint_generateBakeData(DynamicPaintSurface *surface, const Vie .mvert = mvert, .canvas_verts = canvas_verts, .do_velocity_data = do_velocity_data, .new_bdata = new_bdata, }; - BLI_task_parallel_range( - 0, sData->total_points, &data, dynamic_paint_generate_bake_data_cb, sData->total_points > 1000); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = (sData->total_points > 1000); + BLI_task_parallel_range(0, sData->total_points, + &data, + dynamic_paint_generate_bake_data_cb, + &settings); MEM_freeN(canvas_verts); @@ -5762,8 +6019,13 @@ static int dynamicPaint_doStep(const struct EvaluationContext *eval_ctx, Scene * if (dynamic_paint_surface_needs_dry_dissolve(surface)) { DynamicPaintDissolveDryData data = {.surface = surface, .timescale = timescale}; - BLI_task_parallel_range(0, sData->total_points, &data, - dynamic_paint_surface_pre_step_cb, sData->total_points > 1000); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = (sData->total_points > 1000); + BLI_task_parallel_range(0, sData->total_points, + &data, + dynamic_paint_surface_pre_step_cb, + &settings); } /* diff --git a/source/blender/blenkernel/intern/font.c b/source/blender/blenkernel/intern/font.c index d6b28cfaf70..a314cc0a131 100644 --- a/source/blender/blenkernel/intern/font.c +++ b/source/blender/blenkernel/intern/font.c @@ -382,7 +382,7 @@ static void build_underline(Curve *cu, ListBase *nubase, const rctf *rect, nu2->orderv = 1; nu2->flagu = CU_NURB_CYCLIC; - bp = (BPoint *)MEM_callocN(4 * sizeof(BPoint), "underline_bp"); + bp = (BPoint *)MEM_calloc_arrayN(4, sizeof(BPoint), "underline_bp"); copy_v4_fl4(bp[0].vec, rect->xmin, (rect->ymax + yofs), 0.0f, 1.0f); copy_v4_fl4(bp[1].vec, rect->xmax, (rect->ymax + yofs), 0.0f, 1.0f); @@ -481,7 +481,7 @@ static void buildchar(Main *bmain, Curve *cu, ListBase *nubase, unsigned int cha /* nu2->trim.last = 0; */ i = nu2->pntsu; - bezt2 = (BezTriple *)MEM_mallocN(i * sizeof(BezTriple), "duplichar_bezt2"); + bezt2 = (BezTriple *)MEM_malloc_arrayN(i, sizeof(BezTriple), "duplichar_bezt2"); if (bezt2 == NULL) { MEM_freeN(nu2); break; @@ -635,11 +635,10 @@ struct TempLineInfo { int wspace_nr; /* number of whitespaces of line */ }; -bool BKE_vfont_to_curve_ex(Main *bmain, Object *ob, int mode, ListBase *r_nubase, +bool BKE_vfont_to_curve_ex(Main *bmain, Object *ob, Curve *cu, int mode, ListBase *r_nubase, const wchar_t **r_text, int *r_text_len, bool *r_text_free, struct CharTrans **r_chartransdata) { - Curve *cu = ob->data; EditFont *ef = cu->editfont; EditFontSelBox *selboxes = NULL; VFont *vfont, *oldvfont; @@ -670,7 +669,7 @@ bool BKE_vfont_to_curve_ex(Main *bmain, Object *ob, int mode, ListBase *r_nubase /* remark: do calculations including the trailing '\0' of a string * because the cursor can be at that location */ - BLI_assert(ob->type == OB_FONT); + BLI_assert(ob == NULL || ob->type == OB_FONT); /* Set font data */ vfont = cu->vfont; @@ -693,28 +692,34 @@ bool BKE_vfont_to_curve_ex(Main *bmain, Object *ob, int mode, ListBase *r_nubase slen = cu->len_wchar; /* Create unicode string */ - mem_tmp = MEM_mallocN(((slen + 1) * sizeof(wchar_t)), "convertedmem"); + mem_tmp = MEM_malloc_arrayN((slen + 1), sizeof(wchar_t), "convertedmem"); + if (!mem_tmp) { + return ok; + } BLI_strncpy_wchar_from_utf8(mem_tmp, cu->str, slen + 1); if (cu->strinfo == NULL) { /* old file */ - cu->strinfo = MEM_callocN((slen + 4) * sizeof(CharInfo), "strinfo compat"); + cu->strinfo = MEM_calloc_arrayN((slen + 4), sizeof(CharInfo), "strinfo compat"); } custrinfo = cu->strinfo; + if (!custrinfo) { + return ok; + } mem = mem_tmp; } if (cu->tb == NULL) - cu->tb = MEM_callocN(MAXTEXTBOX * sizeof(TextBox), "TextBox compat"); + cu->tb = MEM_calloc_arrayN(MAXTEXTBOX, sizeof(TextBox), "TextBox compat"); - if (ef) { + if (ef != NULL && ob != NULL) { if (ef->selboxes) MEM_freeN(ef->selboxes); if (BKE_vfont_select_get(ob, &selstart, &selend)) { ef->selboxes_len = (selend - selstart) + 1; - ef->selboxes = MEM_callocN(ef->selboxes_len * sizeof(EditFontSelBox), "font selboxes"); + ef->selboxes = MEM_calloc_arrayN(ef->selboxes_len, sizeof(EditFontSelBox), "font selboxes"); } else { ef->selboxes_len = 0; @@ -725,10 +730,10 @@ bool BKE_vfont_to_curve_ex(Main *bmain, Object *ob, int mode, ListBase *r_nubase } /* calc offset and rotation of each char */ - ct = chartransdata = MEM_callocN((slen + 1) * sizeof(struct CharTrans), "buildtext"); + ct = chartransdata = MEM_calloc_arrayN((slen + 1), sizeof(struct CharTrans), "buildtext"); /* We assume the worst case: 1 character per line (is freed at end anyway) */ - lineinfo = MEM_mallocN(sizeof(*lineinfo) * (slen * 2 + 1), "lineinfo"); + lineinfo = MEM_malloc_arrayN((slen * 2 + 1), sizeof(*lineinfo), "lineinfo"); linedist = cu->linedist; @@ -1258,7 +1263,7 @@ makebreak: cha = towupper(cha); } - if (info->mat_nr > (ob->totcol)) { + if (ob == NULL || info->mat_nr > (ob->totcol)) { /* printf("Error: Illegal material index (%d) in text object, setting to 0\n", info->mat_nr); */ info->mat_nr = 0; } @@ -1334,7 +1339,7 @@ bool BKE_vfont_to_curve_nubase(Main *bmain, Object *ob, int mode, ListBase *r_nu { BLI_assert(ob->type == OB_FONT); - return BKE_vfont_to_curve_ex(bmain, ob, mode, r_nubase, + return BKE_vfont_to_curve_ex(bmain, ob, ob->data, mode, r_nubase, NULL, NULL, NULL, NULL); } @@ -1342,7 +1347,7 @@ bool BKE_vfont_to_curve(Main *bmain, Object *ob, int mode) { Curve *cu = ob->data; - return BKE_vfont_to_curve_ex(bmain, ob, mode, &cu->nurb, NULL, NULL, NULL, NULL); + return BKE_vfont_to_curve_ex(bmain, ob, ob->data, mode, &cu->nurb, NULL, NULL, NULL, NULL); } @@ -1374,12 +1379,12 @@ void BKE_vfont_clipboard_set(const wchar_t *text_buf, const CharInfo *info_buf, /* clean previous buffers*/ BKE_vfont_clipboard_free(); - text = MEM_mallocN((len + 1) * sizeof(wchar_t), __func__); + text = MEM_malloc_arrayN((len + 1), sizeof(wchar_t), __func__); if (text == NULL) { return; } - info = MEM_mallocN(len * sizeof(CharInfo), __func__); + info = MEM_malloc_arrayN(len, sizeof(CharInfo), __func__); if (info == NULL) { MEM_freeN(text); return; diff --git a/source/blender/blenkernel/intern/freestyle.c b/source/blender/blenkernel/intern/freestyle.c index 686fe3bda93..b656d2cf7c0 100644 --- a/source/blender/blenkernel/intern/freestyle.c +++ b/source/blender/blenkernel/intern/freestyle.c @@ -61,17 +61,21 @@ void BKE_freestyle_config_init(FreestyleConfig *config) BLI_listbase_clear(&config->linesets); } -void BKE_freestyle_config_free(FreestyleConfig *config) +void BKE_freestyle_config_free(FreestyleConfig *config, const bool do_id_user) { FreestyleLineSet *lineset; for (lineset = (FreestyleLineSet *)config->linesets.first; lineset; lineset = lineset->next) { if (lineset->group) { - id_us_min(&lineset->group->id); + if (do_id_user) { + id_us_min(&lineset->group->id); + } lineset->group = NULL; } if (lineset->linestyle) { - id_us_min(&lineset->linestyle->id); + if (do_id_user) { + id_us_min(&lineset->linestyle->id); + } lineset->linestyle = NULL; } } diff --git a/source/blender/blenkernel/intern/group.c b/source/blender/blenkernel/intern/group.c index 7c2eefe657c..ca6d92efa80 100644 --- a/source/blender/blenkernel/intern/group.c +++ b/source/blender/blenkernel/intern/group.c @@ -55,6 +55,8 @@ #include "BKE_object.h" #include "BKE_scene.h" +#define DEBUG_PRINT if (G.debug & G_DEBUG_DEPSGRAPH) printf + /** Free (or release) any data used by this group (does not free the group itself). */ void BKE_group_free(Group *group) { @@ -80,17 +82,13 @@ void BKE_group_init(Group *group) { group->collection = MEM_callocN(sizeof(SceneCollection), __func__); BLI_strncpy(group->collection->name, "Master Collection", sizeof(group->collection->name)); - group->view_layer = NULL; /* groups are not calloced. */ group->view_layer = BKE_view_layer_group_add(group); /* Unlink the master collection. */ BKE_collection_unlink(group->view_layer, group->view_layer->layer_collections.first); /* Create and link a new default collection. */ - SceneCollection *defaut_collection = BKE_collection_add(&group->id, - NULL, - COLLECTION_TYPE_GROUP_INTERNAL, - "Default Collection"); + SceneCollection *defaut_collection = BKE_collection_add(&group->id, NULL, COLLECTION_TYPE_GROUP_INTERNAL, NULL); BKE_collection_link(group->view_layer, defaut_collection); } @@ -137,9 +135,10 @@ void BKE_group_copy_data(Main *UNUSED(bmain), Group *group_dst, const Group *gro BKE_collection_copy_data(master_collection_dst, master_collection_src, flag_subdata); + group_dst->view_layer = MEM_dupallocN(group_src->view_layer); BKE_view_layer_copy_data(group_dst->view_layer, group_src->view_layer, - master_collection_dst, master_collection_src, - flag_subdata); + master_collection_dst, master_collection_src, + flag_subdata); } Group *BKE_group_copy(Main *bmain, const Group *group) @@ -372,10 +371,43 @@ void BKE_group_handle_recalc_and_update(const struct EvaluationContext *eval_ctx /* only do existing tags, as set by regular depsgraph */ FOREACH_GROUP_OBJECT(group, object) { - if (object->id.tag & LIB_TAG_ID_RECALC_ALL) { + if (object->id.recalc & ID_RECALC_ALL) { BKE_object_handle_update(eval_ctx, scene, object); } } FOREACH_GROUP_OBJECT_END } } + +/* ******** Dependency graph evaluation ******** */ + +static void group_eval_layer_collections( + const struct EvaluationContext *eval_ctx, + Group *group, + ListBase *layer_collections, + LayerCollection *parent_layer_collection) +{ + BLI_LISTBASE_FOREACH (LayerCollection *, layer_collection, layer_collections) { + /* Evaluate layer collection itself. */ + BKE_layer_eval_layer_collection(eval_ctx, + layer_collection, + parent_layer_collection); + /* Evaluate nested collections. */ + group_eval_layer_collections(eval_ctx, + group, + &layer_collection->layer_collections, + layer_collection); + } +} + +void BKE_group_eval_view_layers(const struct EvaluationContext *eval_ctx, + Group *group) +{ + DEBUG_PRINT("%s on %s (%p)\n", __func__, group->id.name, group); + BKE_layer_eval_layer_collection_pre(eval_ctx, &group->id, group->view_layer); + group_eval_layer_collections(eval_ctx, + group, + &group->view_layer->layer_collections, + NULL); + BKE_layer_eval_layer_collection_post(eval_ctx, group->view_layer); +} diff --git a/source/blender/blenkernel/intern/idprop.c b/source/blender/blenkernel/intern/idprop.c index b00a62a1a87..33a665ba06e 100644 --- a/source/blender/blenkernel/intern/idprop.c +++ b/source/blender/blenkernel/intern/idprop.c @@ -1094,4 +1094,15 @@ void IDP_ClearProperty(IDProperty *prop) prop->len = prop->totallen = 0; } +void IDP_Reset(IDProperty *prop, const IDProperty *reference) +{ + if (prop == NULL) { + return; + } + IDP_ClearProperty(prop); + if (reference != NULL) { + IDP_MergeGroup(prop, reference, true); + } +} + /** \} */ diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c index 59fadffe22a..d720dc41abf 100644 --- a/source/blender/blenkernel/intern/image.c +++ b/source/blender/blenkernel/intern/image.c @@ -113,9 +113,9 @@ static void image_add_view(Image *ima, const char *viewname, const char *filepat /* quick lookup: supports 1 million frames, thousand passes */ #define IMA_MAKE_INDEX(frame, index) (((frame) << 10) + (index)) #define IMA_INDEX_FRAME(index) ((index) >> 10) -/* +#if 0 #define IMA_INDEX_PASS(index) (index & ~1023) -*/ +#endif /* ******** IMAGE CACHE ************* */ @@ -1696,7 +1696,7 @@ static void stampdata(Scene *scene, Object *camera, StampData *stamp_data, int d int digits = 1; if (scene->r.efra > 9) - digits = 1 + (int) log10(scene->r.efra); + digits = integer_digits_i(scene->r.efra); BLI_snprintf(fmtstr, sizeof(fmtstr), do_prefix ? "Frame %%0%di" : "%%0%di", digits); BLI_snprintf(stamp_data->frame, sizeof(stamp_data->frame), fmtstr, scene->r.cfra); diff --git a/source/blender/blenkernel/intern/ipo.c b/source/blender/blenkernel/intern/ipo.c index 90247441631..00cf40f06cd 100644 --- a/source/blender/blenkernel/intern/ipo.c +++ b/source/blender/blenkernel/intern/ipo.c @@ -1559,7 +1559,7 @@ static void ipo_to_animdata(ID *id, Ipo *ipo, char actname[], char constname[], BLI_snprintf(nameBuf, sizeof(nameBuf), "CDA:%s", ipo->id.name + 2); - adt->action = add_empty_action(G.main, nameBuf); + adt->action = BKE_action_add(G.main, nameBuf); if (G.debug & G_DEBUG) printf("\t\tadded new action - '%s'\n", nameBuf); } @@ -2107,7 +2107,7 @@ void do_versions_ipos_to_animato(Main *main) bAction *new_act; /* add a new action for this, and convert all data into that action */ - new_act = add_empty_action(main, id->name + 2); + new_act = BKE_action_add(main, id->name + 2); ipo_to_animato(NULL, ipo, NULL, NULL, NULL, NULL, &new_act->curves, &drivers); new_act->idroot = ipo->blocktype; } diff --git a/source/blender/blenkernel/intern/lamp.c b/source/blender/blenkernel/intern/lamp.c index d8b9b14d755..931fc09d235 100644 --- a/source/blender/blenkernel/intern/lamp.c +++ b/source/blender/blenkernel/intern/lamp.c @@ -165,7 +165,7 @@ Lamp *BKE_lamp_copy(Main *bmain, const Lamp *la) return la_copy; } -Lamp *localize_lamp(Lamp *la) +Lamp *BKE_lamp_localize(Lamp *la) { /* TODO replace with something like * Lamp *la_copy; @@ -181,7 +181,7 @@ Lamp *localize_lamp(Lamp *la) for (a = 0; a < MAX_MTEX; a++) { if (lan->mtex[a]) { - lan->mtex[a] = MEM_mallocN(sizeof(MTex), "localize_lamp"); + lan->mtex[a] = MEM_mallocN(sizeof(MTex), __func__); memcpy(lan->mtex[a], la->mtex[a], sizeof(MTex)); } } diff --git a/source/blender/blenkernel/intern/layer.c b/source/blender/blenkernel/intern/layer.c index 84eb4ee2e33..c6515d0c47a 100644 --- a/source/blender/blenkernel/intern/layer.c +++ b/source/blender/blenkernel/intern/layer.c @@ -42,6 +42,8 @@ #include "BKE_node.h" #include "BKE_workspace.h" +#include "DEG_depsgraph.h" + #include "DNA_group_types.h" #include "DNA_ID.h" #include "DNA_layer_types.h" @@ -97,7 +99,7 @@ ViewLayer *BKE_view_layer_from_workspace_get(const struct Scene *scene, const st /** * This is a placeholder to know which areas of the code need to be addressed for the Workspace changes. - * Never use this, you should either use BKE_view_layer_workspace_active or get ViewLayer explicitly. + * Never use this, you should either use BKE_view_layer_from_workspace_get or get ViewLayer explicitly. */ ViewLayer *BKE_view_layer_context_active_PLACEHOLDER(const Scene *scene) { @@ -161,10 +163,15 @@ ViewLayer *BKE_view_layer_group_add(Group *group) return view_layer; } +void BKE_view_layer_free(ViewLayer *view_layer) +{ + BKE_view_layer_free_ex(view_layer, true); +} + /** * Free (or release) any data used by this ViewLayer. */ -void BKE_view_layer_free(ViewLayer *view_layer) +void BKE_view_layer_free_ex(ViewLayer *view_layer, const bool do_id_user) { view_layer->basact = NULL; @@ -203,7 +210,7 @@ void BKE_view_layer_free(ViewLayer *view_layer) MEM_SAFE_FREE(view_layer->stats); - BKE_freestyle_config_free(&view_layer->freestyle_config); + BKE_freestyle_config_free(&view_layer->freestyle_config, do_id_user); if (view_layer->id_properties) { IDP_FreeProperty(view_layer->id_properties); @@ -1018,7 +1025,8 @@ static void layer_collection_enable(ViewLayer *view_layer, LayerCollection *lc) /** * Enable collection * Add its objects bases to ViewLayer - * Depsgraph needs to be rebuilt afterwards + * + * Only around for doversion. */ void BKE_collection_enable(ViewLayer *view_layer, LayerCollection *lc) { @@ -1030,45 +1038,16 @@ void BKE_collection_enable(ViewLayer *view_layer, LayerCollection *lc) layer_collection_enable(view_layer, lc); } -/** - * Recursively disable nested collections - */ -static void layer_collection_disable(ViewLayer *view_layer, LayerCollection *lc) -{ - layer_collection_objects_unpopulate(view_layer, lc); - - for (LayerCollection *nlc = lc->layer_collections.first; nlc; nlc = nlc->next) { - layer_collection_disable(view_layer, nlc); - } -} - -/** - * Disable collection - * Remove all its object bases from ViewLayer - * Depsgraph needs to be rebuilt afterwards - */ -void BKE_collection_disable(ViewLayer *view_layer, LayerCollection *lc) -{ - if ((lc->flag & COLLECTION_DISABLED) != 0) { - return; - } - - lc->flag |= COLLECTION_DISABLED; - layer_collection_disable(view_layer, lc); -} - static void layer_collection_object_add(ViewLayer *view_layer, LayerCollection *lc, Object *ob) { Base *base = object_base_add(view_layer, ob); - /* Only add an object once - prevent SceneCollection->objects and - * SceneCollection->filter_objects to add the same object. */ - + /* Only add an object once. */ if (BLI_findptr(&lc->object_bases, base, offsetof(LinkData, data))) { return; } - bool is_visible = (lc->flag & COLLECTION_VISIBLE) != 0; + bool is_visible = ((lc->flag & COLLECTION_VIEWPORT) != 0) && ((lc->flag & COLLECTION_DISABLED) == 0); bool is_selectable = is_visible && ((lc->flag & COLLECTION_SELECTABLE) != 0); if (is_visible) { @@ -1104,7 +1083,6 @@ static void layer_collection_objects_populate(ViewLayer *view_layer, LayerCollec static void layer_collection_populate(ViewLayer *view_layer, LayerCollection *lc, SceneCollection *sc) { layer_collection_objects_populate(view_layer, lc, &sc->objects); - layer_collection_objects_populate(view_layer, lc, &sc->filter_objects); for (SceneCollection *nsc = sc->scene_collections.first; nsc; nsc = nsc->next) { layer_collection_add(view_layer, lc, nsc); @@ -1117,7 +1095,7 @@ static LayerCollection *layer_collection_add(ViewLayer *view_layer, LayerCollect LayerCollection *lc = MEM_callocN(sizeof(LayerCollection), "Collection Base"); lc->scene_collection = sc; - lc->flag = COLLECTION_VISIBLE | COLLECTION_SELECTABLE; + lc->flag = COLLECTION_SELECTABLE | COLLECTION_VIEWPORT | COLLECTION_RENDER; lc->properties = IDP_New(IDP_GROUP, &val, ROOT_PROP); collection_engine_settings_init(lc->properties, false); @@ -1214,7 +1192,6 @@ void BKE_layer_sync_object_link(const ID *owner_id, SceneCollection *sc, Object /** * Remove the equivalent object base to all layers that have this collection - * also remove all reference to ob in the filter_objects */ void BKE_layer_sync_object_unlink(const ID *owner_id, SceneCollection *sc, Object *ob) { @@ -2118,7 +2095,25 @@ static const char *collection_type_lookup[] = "Group Internal", /* COLLECTION_TYPE_GROUP_INTERNAL */ }; -void BKE_layer_eval_layer_collection(const struct EvaluationContext *UNUSED(eval_ctx), +/** + * \note We can't use layer_collection->flag because of 3 level nesting (where parent is visible, but not grand-parent) + * So layer_collection->flag_evaluated is expected to be up to date with layer_collection->flag. + */ +static bool layer_collection_visible_get(const EvaluationContext *eval_ctx, LayerCollection *layer_collection) +{ + if (layer_collection->flag_evaluated & COLLECTION_DISABLED) { + return false; + } + + if (eval_ctx->mode == DAG_EVAL_VIEWPORT) { + return (layer_collection->flag_evaluated & COLLECTION_VIEWPORT) != 0; + } + else { + return (layer_collection->flag_evaluated & COLLECTION_RENDER) != 0; + } +} + +void BKE_layer_eval_layer_collection(const EvaluationContext *eval_ctx, LayerCollection *layer_collection, LayerCollection *parent_layer_collection) { @@ -2134,15 +2129,22 @@ void BKE_layer_eval_layer_collection(const struct EvaluationContext *UNUSED(eval /* visibility */ layer_collection->flag_evaluated = layer_collection->flag; - bool is_visible = (layer_collection->flag & COLLECTION_VISIBLE) != 0; - bool is_selectable = is_visible && ((layer_collection->flag & COLLECTION_SELECTABLE) != 0); if (parent_layer_collection != NULL) { - is_visible &= (parent_layer_collection->flag_evaluated & COLLECTION_VISIBLE) != 0; - is_selectable &= (parent_layer_collection->flag_evaluated & COLLECTION_SELECTABLE) != 0; - layer_collection->flag_evaluated &= parent_layer_collection->flag_evaluated; + if (layer_collection_visible_get(eval_ctx, parent_layer_collection) == false) { + layer_collection->flag_evaluated |= COLLECTION_DISABLED; + } + + if ((parent_layer_collection->flag_evaluated & COLLECTION_DISABLED) || + (parent_layer_collection->flag_evaluated & COLLECTION_SELECTABLE) == 0) + { + layer_collection->flag_evaluated &= ~COLLECTION_SELECTABLE; + } } + const bool is_visible = layer_collection_visible_get(eval_ctx, layer_collection); + const bool is_selectable = is_visible && ((layer_collection->flag_evaluated & COLLECTION_SELECTABLE) != 0); + /* overrides */ if (is_visible) { if (parent_layer_collection == NULL) { diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c index 0ef1fe52994..066b3e34b0d 100644 --- a/source/blender/blenkernel/intern/library.c +++ b/source/blender/blenkernel/intern/library.c @@ -2249,8 +2249,8 @@ void BKE_library_make_local( * was not used locally would be a nasty bug! */ if (is_local || is_lib) { printf("Warning, made-local proxy object %s will loose its link to %s, " - "because the linked-in proxy is referenced (is_local=%i, is_lib=%i).\n", - id->newid->name, ob->proxy->id.name, is_local, is_lib); + "because the linked-in proxy is referenced (is_local=%i, is_lib=%i).\n", + id->newid->name, ob->proxy->id.name, is_local, is_lib); } else { /* we can switch the proxy'ing from the linked-in to the made-local proxy. @@ -2306,8 +2306,8 @@ void BKE_library_make_local( * was not used locally would be a nasty bug! */ else if (is_local || is_lib) { printf("Warning, made-local proxy object %s will loose its link to %s, " - "because the linked-in proxy is referenced (is_local=%i, is_lib=%i).\n", - id->newid->name, ob->proxy->id.name, is_local, is_lib); + "because the linked-in proxy is referenced (is_local=%i, is_lib=%i).\n", + id->newid->name, ob->proxy->id.name, is_local, is_lib); } else { /* we can switch the proxy'ing from the linked-in to the made-local proxy. diff --git a/source/blender/blenkernel/intern/library_override.c b/source/blender/blenkernel/intern/library_override.c index 22896cff64a..8b8658921b5 100644 --- a/source/blender/blenkernel/intern/library_override.c +++ b/source/blender/blenkernel/intern/library_override.c @@ -66,16 +66,26 @@ IDOverrideStatic *BKE_override_static_init(ID *local_id, ID *reference_id) BLI_assert(reference_id == NULL || reference_id->lib != NULL); BLI_assert(local_id->override_static == NULL); - if (reference_id != NULL && reference_id->override_static != NULL && reference_id->override_static->reference == NULL) { - /* reference ID has an override template, use it! */ - BKE_override_static_copy(local_id, reference_id); + ID *ancestor_id; + for (ancestor_id = reference_id; + ancestor_id != NULL && ancestor_id->override_static != NULL && ancestor_id->override_static->reference != NULL; + ancestor_id = ancestor_id->override_static->reference); + + if (ancestor_id != NULL && ancestor_id->override_static != NULL) { + /* Original ID has a template, use it! */ + BKE_override_static_copy(local_id, ancestor_id); + if (local_id->override_static->reference != reference_id) { + id_us_min(local_id->override_static->reference); + local_id->override_static->reference = reference_id; + id_us_plus(local_id->override_static->reference); + } return local_id->override_static; } /* Else, generate new empty override. */ local_id->override_static = MEM_callocN(sizeof(*local_id->override_static), __func__); local_id->override_static->reference = reference_id; - id_us_plus(reference_id); + id_us_plus(local_id->override_static->reference); local_id->tag &= ~LIB_TAG_OVERRIDESTATIC_OK; /* TODO do we want to add tag or flag to referee to mark it as such? */ return local_id->override_static; @@ -142,12 +152,8 @@ void BKE_override_static_free(struct IDOverrideStatic **override) *override = NULL; } -/** Create an overriden local copy of linked reference. */ -ID *BKE_override_static_create_from(Main *bmain, ID *reference_id) +static ID *override_static_create_from(Main *bmain, ID *reference_id) { - BLI_assert(reference_id != NULL); - BLI_assert(reference_id->lib != NULL); - ID *local_id; if (!id_copy(bmain, reference_id, (ID **)&local_id, false)) { @@ -158,12 +164,63 @@ ID *BKE_override_static_create_from(Main *bmain, ID *reference_id) BKE_override_static_init(local_id, reference_id); local_id->flag |= LIB_OVERRIDE_STATIC_AUTO; + return local_id; +} + + +/** Create an overriden local copy of linked reference. */ +ID *BKE_override_static_create_from_id(Main *bmain, ID *reference_id) +{ + BLI_assert(reference_id != NULL); + BLI_assert(reference_id->lib != NULL); + + ID *local_id = override_static_create_from(bmain, reference_id); + /* Remapping, we obviously only want to affect local data (and not our own reference pointer to overriden ID). */ BKE_libblock_remap(bmain, reference_id, local_id, ID_REMAP_SKIP_INDIRECT_USAGE | ID_REMAP_SKIP_STATIC_OVERRIDE); return local_id; } +/** Create overriden local copies of all tagged data-blocks in given Main. + * + * \note Set id->newid of overridden libs with newly created overrides, caller is responsible to clean those pointers + * before/after usage as needed. + * + * \return \a true on success, \a false otherwise. + */ +bool BKE_override_static_create_from_tag(Main *bmain) +{ + ListBase *lbarray[MAX_LIBARRAY]; + int a; + bool ret = true; + + const int num_types = a = set_listbasepointers(bmain, lbarray); + while (a--) { + for (ID *reference_id = lbarray[a]->first; reference_id != NULL; reference_id = reference_id->next) { + if ((reference_id->tag & LIB_TAG_DOIT) != 0 && reference_id->lib != NULL) { + if ((reference_id->newid = override_static_create_from(bmain, reference_id)) == NULL) { + ret = false; + } + } + } + } + + /* Remapping, we obviously only want to affect local data (and not our own reference pointer to overriden ID). */ + a = num_types; + while (a--) { + for (ID *reference_id = lbarray[a]->first; reference_id != NULL; reference_id = reference_id->next) { + if ((reference_id->tag & LIB_TAG_DOIT) != 0 && reference_id->lib != NULL && reference_id->newid != NULL) { + ID *local_id = reference_id->newid; + BKE_libblock_remap(bmain, reference_id, local_id, + ID_REMAP_SKIP_INDIRECT_USAGE | ID_REMAP_SKIP_STATIC_OVERRIDE); + } + } + } + + return ret; +} + /** * Find override property from given RNA path, if it exists. */ @@ -384,7 +441,10 @@ bool BKE_override_static_status_check_local(ID *local) RNA_id_pointer_create(local, &rnaptr_local); RNA_id_pointer_create(reference, &rnaptr_reference); - if (!RNA_struct_override_matches(&rnaptr_local, &rnaptr_reference, local->override_static, true, true)) { + if (!RNA_struct_override_matches( + &rnaptr_local, &rnaptr_reference, NULL, local->override_static, + RNA_OVERRIDE_COMPARE_IGNORE_NON_OVERRIDABLE | RNA_OVERRIDE_COMPARE_IGNORE_OVERRIDDEN, NULL)) + { local->tag &= ~LIB_TAG_OVERRIDESTATIC_OK; return false; } @@ -428,7 +488,10 @@ bool BKE_override_static_status_check_reference(ID *local) RNA_id_pointer_create(local, &rnaptr_local); RNA_id_pointer_create(reference, &rnaptr_reference); - if (!RNA_struct_override_matches(&rnaptr_local, &rnaptr_reference, local->override_static, false, true)) { + if (!RNA_struct_override_matches( + &rnaptr_local, &rnaptr_reference, NULL, local->override_static, + RNA_OVERRIDE_COMPARE_IGNORE_OVERRIDDEN, NULL)) + { local->tag &= ~LIB_TAG_OVERRIDESTATIC_OK; return false; } @@ -459,8 +522,17 @@ bool BKE_override_static_operations_create(ID *local) RNA_id_pointer_create(local, &rnaptr_local); RNA_id_pointer_create(local->override_static->reference, &rnaptr_reference); - ret = RNA_struct_auto_override(&rnaptr_local, &rnaptr_reference, local->override_static, NULL); + eRNAOverrideMatchResult report_flags = 0; + RNA_struct_override_matches( + &rnaptr_local, &rnaptr_reference, NULL, local->override_static, + RNA_OVERRIDE_COMPARE_CREATE | RNA_OVERRIDE_COMPARE_RESTORE, &report_flags); + if (report_flags & RNA_OVERRIDE_MATCH_RESULT_CREATED) { + ret = true; + } #ifndef NDEBUG + if (report_flags & RNA_OVERRIDE_MATCH_RESULT_RESTORED) { + printf("We did restore some properties of %s from its reference.\n", local->name); + } if (ret) { printf("We did generate static override rules for %s\n", local->name); } diff --git a/source/blender/blenkernel/intern/library_query.c b/source/blender/blenkernel/intern/library_query.c index e25a354c8af..6c5931263d8 100644 --- a/source/blender/blenkernel/intern/library_query.c +++ b/source/blender/blenkernel/intern/library_query.c @@ -449,10 +449,6 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call for (LinkData *link = sc->objects.first; link; link = link->next) { CALLBACK_INVOKE_ID(link->data, IDWALK_CB_USER); } - - for (LinkData *link = sc->filter_objects.first; link; link = link->next) { - CALLBACK_INVOKE_ID(link->data, IDWALK_CB_USER); - } } FOREACH_SCENE_COLLECTION_END @@ -773,11 +769,11 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call case ID_GR: { Group *group = (Group *) id; - FOREACH_GROUP_OBJECT(group, object) + FOREACH_GROUP_BASE(group, base) { - CALLBACK_INVOKE(object, IDWALK_CB_USER_ONE); + CALLBACK_INVOKE(base->object, IDWALK_CB_USER_ONE); } - FOREACH_GROUP_OBJECT_END + FOREACH_GROUP_BASE_END break; } @@ -984,6 +980,8 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call for (WorkSpaceLayout *layout = layouts->first; layout; layout = layout->next) { bScreen *screen = BKE_workspace_layout_screen_get(layout); + /* CALLBACK_INVOKE expects an actual pointer, not a variable holding the pointer. + * However we can't acess layout->screen here since we are outside the workspace project. */ CALLBACK_INVOKE(screen, IDWALK_CB_NOP); /* allow callback to set a different screen */ BKE_workspace_layout_screen_set(layout, screen); @@ -1092,7 +1090,7 @@ bool BKE_library_id_can_use_idtype(ID *id_owner, const short id_type_used) return true; #endif case ID_ME: - return ELEM(id_type_used, ID_ME, ID_KE, ID_MA); + return ELEM(id_type_used, ID_ME, ID_KE, ID_MA, ID_IM); case ID_CU: return ELEM(id_type_used, ID_OB, ID_KE, ID_MA, ID_VF); case ID_MB: diff --git a/source/blender/blenkernel/intern/library_remap.c b/source/blender/blenkernel/intern/library_remap.c index fb672cb8b9f..6d4c4082810 100644 --- a/source/blender/blenkernel/intern/library_remap.c +++ b/source/blender/blenkernel/intern/library_remap.c @@ -205,9 +205,11 @@ static int foreach_libblock_remap_callback(void *user_data, ID *id_self, ID **id id->tag |= LIB_TAG_DOIT; } - /* Special hack in case it's Object->data and we are in edit mode (skipped_direct too). */ + /* Special hack in case it's Object->data and we are in edit mode, and new_id is not NULL + * (otherwise, we follow common NEVER_NULL flags). + * (skipped_indirect too). */ if ((is_never_null && skip_never_null) || - (is_obj_editmode && (((Object *)id)->data == *id_p)) || + (is_obj_editmode && (((Object *)id)->data == *id_p) && new_id != NULL) || (skip_indirect && is_indirect) || (is_reference && skip_reference)) { diff --git a/source/blender/blenkernel/intern/lightprobe.c b/source/blender/blenkernel/intern/lightprobe.c index d5dbbe873a2..057b6aaaf65 100644 --- a/source/blender/blenkernel/intern/lightprobe.c +++ b/source/blender/blenkernel/intern/lightprobe.c @@ -52,6 +52,7 @@ void BKE_lightprobe_init(LightProbe *probe) probe->clipend = 40.0f; probe->vis_bias = 1.0f; probe->vis_blur = 0.2f; + probe->intensity = 1.0f; probe->data_draw_size = 1.0f; probe->flag = LIGHTPROBE_FLAG_SHOW_INFLUENCE | LIGHTPROBE_FLAG_SHOW_DATA; diff --git a/source/blender/blenkernel/intern/linestyle.c b/source/blender/blenkernel/intern/linestyle.c index 3a69eb2b86b..2fc4c81cb0b 100644 --- a/source/blender/blenkernel/intern/linestyle.c +++ b/source/blender/blenkernel/intern/linestyle.c @@ -44,13 +44,13 @@ #include "BLI_string_utils.h" #include "BLI_utildefines.h" +#include "BKE_colorband.h" #include "BKE_context.h" #include "BKE_freestyle.h" #include "BKE_global.h" #include "BKE_library.h" #include "BKE_linestyle.h" #include "BKE_node.h" -#include "BKE_texture.h" #include "BKE_colortools.h" #include "BKE_animsys.h" @@ -296,39 +296,39 @@ LineStyleModifier *BKE_linestyle_color_modifier_add(FreestyleLineStyle *linestyl switch (type) { case LS_MODIFIER_ALONG_STROKE: - ((LineStyleColorModifier_AlongStroke *)m)->color_ramp = add_colorband(1); + ((LineStyleColorModifier_AlongStroke *)m)->color_ramp = BKE_colorband_add(true); break; case LS_MODIFIER_DISTANCE_FROM_CAMERA: - ((LineStyleColorModifier_DistanceFromCamera *)m)->color_ramp = add_colorband(1); + ((LineStyleColorModifier_DistanceFromCamera *)m)->color_ramp = BKE_colorband_add(true); ((LineStyleColorModifier_DistanceFromCamera *)m)->range_min = 0.0f; ((LineStyleColorModifier_DistanceFromCamera *)m)->range_max = 10000.0f; break; case LS_MODIFIER_DISTANCE_FROM_OBJECT: ((LineStyleColorModifier_DistanceFromObject *)m)->target = NULL; - ((LineStyleColorModifier_DistanceFromObject *)m)->color_ramp = add_colorband(1); + ((LineStyleColorModifier_DistanceFromObject *)m)->color_ramp = BKE_colorband_add(true); ((LineStyleColorModifier_DistanceFromObject *)m)->range_min = 0.0f; ((LineStyleColorModifier_DistanceFromObject *)m)->range_max = 10000.0f; break; case LS_MODIFIER_MATERIAL: - ((LineStyleColorModifier_Material *)m)->color_ramp = add_colorband(1); + ((LineStyleColorModifier_Material *)m)->color_ramp = BKE_colorband_add(true); ((LineStyleColorModifier_Material *)m)->mat_attr = LS_MODIFIER_MATERIAL_LINE; break; case LS_MODIFIER_TANGENT: - ((LineStyleColorModifier_Tangent *)m)->color_ramp = add_colorband(1); + ((LineStyleColorModifier_Tangent *)m)->color_ramp = BKE_colorband_add(true); break; case LS_MODIFIER_NOISE: - ((LineStyleColorModifier_Noise *)m)->color_ramp = add_colorband(1); + ((LineStyleColorModifier_Noise *)m)->color_ramp = BKE_colorband_add(true); ((LineStyleColorModifier_Noise *)m)->amplitude = 10.0f; ((LineStyleColorModifier_Noise *)m)->period = 10.0f; ((LineStyleColorModifier_Noise *)m)->seed = 512; break; case LS_MODIFIER_CREASE_ANGLE: - ((LineStyleColorModifier_CreaseAngle *)m)->color_ramp = add_colorband(1); + ((LineStyleColorModifier_CreaseAngle *)m)->color_ramp = BKE_colorband_add(true); ((LineStyleColorModifier_CreaseAngle *)m)->min_angle = 0.0f; ((LineStyleColorModifier_CreaseAngle *)m)->max_angle = DEG2RADF(180.0f); break; case LS_MODIFIER_CURVATURE_3D: - ((LineStyleColorModifier_Curvature_3D *)m)->color_ramp = add_colorband(1); + ((LineStyleColorModifier_Curvature_3D *)m)->color_ramp = BKE_colorband_add(true); ((LineStyleColorModifier_Curvature_3D *)m)->min_curvature = 0.0f; ((LineStyleColorModifier_Curvature_3D *)m)->max_curvature = 0.5f; break; diff --git a/source/blender/blenkernel/intern/mask.c b/source/blender/blenkernel/intern/mask.c index eaa2f89ab82..3256c16e2f6 100644 --- a/source/blender/blenkernel/intern/mask.c +++ b/source/blender/blenkernel/intern/mask.c @@ -1459,18 +1459,6 @@ void BKE_mask_evaluate_all_masks(Main *bmain, float ctime, const bool do_newfram } } -void BKE_mask_update_scene(Main *bmain, Scene *scene) -{ - Mask *mask; - - for (mask = bmain->mask.first; mask; mask = mask->id.next) { - if (mask->id.tag & (LIB_TAG_ID_RECALC | LIB_TAG_ID_RECALC_DATA)) { - bool do_new_frame = (mask->id.tag & LIB_TAG_ID_RECALC_DATA) != 0; - BKE_mask_evaluate_all_masks(bmain, CFRA, do_new_frame); - } - } -} - void BKE_mask_parent_init(MaskParent *parent) { parent->id_type = ID_MC; diff --git a/source/blender/blenkernel/intern/mask_rasterize.c b/source/blender/blenkernel/intern/mask_rasterize.c index 104bb0c07a6..76d16334630 100644 --- a/source/blender/blenkernel/intern/mask_rasterize.c +++ b/source/blender/blenkernel/intern/mask_rasterize.c @@ -1434,7 +1434,10 @@ typedef struct MaskRasterizeBufferData { float *buffer; } MaskRasterizeBufferData; -static void maskrasterize_buffer_cb(void *userdata, int y) +static void maskrasterize_buffer_cb( + void *__restrict userdata, + const int y, + const ParallelRangeTLS *__restrict UNUSED(tls)) { MaskRasterizeBufferData *data = userdata; @@ -1474,5 +1477,11 @@ void BKE_maskrasterize_buffer(MaskRasterHandle *mr_handle, .width = width, .buffer = buffer }; - BLI_task_parallel_range(0, (int)height, &data, maskrasterize_buffer_cb, height * width > 10000); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = ((size_t)height * width > 10000); + BLI_task_parallel_range(0, (int)height, + &data, + maskrasterize_buffer_cb, + &settings); } diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c index 585567b6665..7235aa0aaf6 100644 --- a/source/blender/blenkernel/intern/material.c +++ b/source/blender/blenkernel/intern/material.c @@ -272,7 +272,7 @@ Material *BKE_material_copy(Main *bmain, const Material *ma) } /* XXX (see above) material copy without adding to main dbase */ -Material *localize_material(Material *ma) +Material *BKE_material_localize(Material *ma) { /* TODO replace with something like * Material *ma_copy; @@ -1159,7 +1159,6 @@ bool material_in_material(Material *parmat, Material *mat) bool BKE_object_material_slot_remove(Object *ob) { Material *mao, ***matarar; - Object *obt; short *totcolp; short a, actcol; @@ -1207,11 +1206,13 @@ bool BKE_object_material_slot_remove(Object *ob) } actcol = ob->actcol; - obt = G.main->object.first; - while (obt) { - + + for (Object *obt = G.main->object.first; obt; obt = obt->id.next) { if (obt->data == ob->data) { - + /* Can happen when object material lists are used, see: T52953 */ + if (actcol > obt->totcol) { + continue; + } /* WATCH IT: do not use actcol from ob or from obt (can become zero) */ mao = obt->mat[actcol - 1]; if (mao) @@ -1231,7 +1232,6 @@ bool BKE_object_material_slot_remove(Object *ob) obt->matbits = NULL; } } - obt = obt->id.next; } /* check indices from mesh */ diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c index 8f41f0611d4..3217c234718 100644 --- a/source/blender/blenkernel/intern/mesh.c +++ b/source/blender/blenkernel/intern/mesh.c @@ -823,7 +823,7 @@ float (*BKE_mesh_orco_verts_get(Object *ob))[3] float (*vcos)[3] = NULL; /* Get appropriate vertex coordinates */ - vcos = MEM_callocN(sizeof(*vcos) * me->totvert, "orco mesh"); + vcos = MEM_calloc_arrayN(me->totvert, sizeof(*vcos), "orco mesh"); mvert = tme->mvert; totvert = min_ii(tme->totvert, me->totvert); @@ -1062,7 +1062,7 @@ static void make_edges_mdata_extend(MEdge **r_alledge, int *r_totedge, unsigned int e_index = totedge; *r_alledge = medge = (*r_alledge ? MEM_reallocN(*r_alledge, sizeof(MEdge) * (totedge + totedge_new)) : - MEM_callocN(sizeof(MEdge) * totedge_new, __func__)); + MEM_calloc_arrayN(totedge_new, sizeof(MEdge), __func__)); medge += totedge; totedge += totedge_new; @@ -1182,13 +1182,13 @@ int BKE_mesh_nurbs_displist_to_mdata( return -1; } - *r_allvert = mvert = MEM_callocN(sizeof(MVert) * totvert, "nurbs_init mvert"); - *r_alledge = medge = MEM_callocN(sizeof(MEdge) * totedge, "nurbs_init medge"); - *r_allloop = mloop = MEM_callocN(sizeof(MLoop) * totvlak * 4, "nurbs_init mloop"); // totloop - *r_allpoly = mpoly = MEM_callocN(sizeof(MPoly) * totvlak, "nurbs_init mloop"); + *r_allvert = mvert = MEM_calloc_arrayN(totvert, sizeof(MVert), "nurbs_init mvert"); + *r_alledge = medge = MEM_calloc_arrayN(totedge, sizeof(MEdge), "nurbs_init medge"); + *r_allloop = mloop = MEM_calloc_arrayN(totvlak, 4 * sizeof(MLoop), "nurbs_init mloop"); // totloop + *r_allpoly = mpoly = MEM_calloc_arrayN(totvlak, sizeof(MPoly), "nurbs_init mloop"); if (r_alluv) - *r_alluv = mloopuv = MEM_callocN(sizeof(MLoopUV) * totvlak * 4, "nurbs_init mloopuv"); + *r_alluv = mloopuv = MEM_calloc_arrayN(totvlak, 4 * sizeof(MLoopUV), "nurbs_init mloopuv"); /* verts and faces */ vertcount = 0; @@ -1436,6 +1436,17 @@ void BKE_mesh_from_nurbs_displist(Object *ob, ListBase *dispbase, const bool use me->totcol = cu->totcol; me->mat = cu->mat; + /* Copy evaluated texture space from curve to mesh. + * + * Note that we disable auto texture space feature since that will cause + * texture space to evaluate differently for curve and mesh, since curve + * uses CV to calculate bounding box, and mesh uses what is coming from + * tessellated curve. + */ + me->texflag = cu->texflag & ~CU_AUTOSPACE; + copy_v3_v3(me->loc, cu->loc); + copy_v3_v3(me->size, cu->size); + copy_v3_v3(me->rot, cu->rot); BKE_mesh_texspace_calc(me); cu->mat = NULL; @@ -1516,7 +1527,7 @@ void BKE_mesh_to_curve_nurblist(DerivedMesh *dm, ListBase *nurblist, const int e ListBase edges = {NULL, NULL}; /* get boundary edges */ - edge_users = MEM_callocN(sizeof(int) * dm_totedge, __func__); + edge_users = MEM_calloc_arrayN(dm_totedge, sizeof(int), __func__); for (i = 0, mp = mpoly; i < dm_totpoly; i++, mp++) { MLoop *ml = &mloop[mp->loopstart]; int j; @@ -1612,7 +1623,7 @@ void BKE_mesh_to_curve_nurblist(DerivedMesh *dm, ListBase *nurblist, const int e nu->flagu = CU_NURB_ENDPOINT | (closed ? CU_NURB_CYCLIC : 0); /* endpoint */ nu->resolu = 12; - nu->bp = (BPoint *)MEM_callocN(sizeof(BPoint) * totpoly, "bpoints"); + nu->bp = (BPoint *)MEM_calloc_arrayN(totpoly, sizeof(BPoint), "bpoints"); /* add points */ vl = polyline.first; @@ -1768,7 +1779,7 @@ void BKE_mesh_smooth_flag_set(Object *meshOb, int enableSmooth) float (*BKE_mesh_vertexCos_get(const Mesh *me, int *r_numVerts))[3] { int i, numVerts = me->totvert; - float (*cos)[3] = MEM_mallocN(sizeof(*cos) * numVerts, "vertexcos1"); + float (*cos)[3] = MEM_malloc_arrayN(numVerts, sizeof(*cos), "vertexcos1"); if (r_numVerts) *r_numVerts = numVerts; for (i = 0; i < numVerts; i++) @@ -1904,7 +1915,7 @@ void BKE_mesh_ensure_navmesh(Mesh *me) int i; int numFaces = me->totpoly; int *recastData; - recastData = (int *)MEM_mallocN(numFaces * sizeof(int), __func__); + recastData = (int *)MEM_malloc_arrayN(numFaces, sizeof(int), __func__); for (i = 0; i < numFaces; i++) { recastData[i] = i + 1; } @@ -1992,7 +2003,7 @@ void BKE_mesh_mselect_validate(Mesh *me) return; mselect_src = me->mselect; - mselect_dst = MEM_mallocN(sizeof(MSelect) * (me->totselect), "Mesh selection history"); + mselect_dst = MEM_malloc_arrayN((me->totselect), sizeof(MSelect), "Mesh selection history"); for (i_src = 0, i_dst = 0; i_src < me->totselect; i_src++) { int index = mselect_src[i_src].index; @@ -2135,7 +2146,7 @@ void BKE_mesh_calc_normals_split_ex(Mesh *mesh, MLoopNorSpaceArray *r_lnors_spac free_polynors = false; } else { - polynors = MEM_mallocN(sizeof(float[3]) * mesh->totpoly, __func__); + polynors = MEM_malloc_arrayN(mesh->totpoly, sizeof(float[3]), __func__); BKE_mesh_calc_normals_poly( mesh->mvert, NULL, mesh->totvert, mesh->mloop, mesh->mpoly, mesh->totloop, mesh->totpoly, polynors, false); @@ -2460,6 +2471,11 @@ Mesh *BKE_mesh_new_from_object( /* copies the data */ copycu = tmpobj->data = BKE_curve_copy(bmain, (Curve *) ob->data); + /* make sure texture space is calculated for a copy of curve, + * it will be used for the final result. + */ + BKE_curve_texspace_calc(copycu); + /* temporarily set edit so we get updates from edit mode, but * also because for text datablocks copying it while in edit * mode gives invalid data structures */ @@ -2490,8 +2506,6 @@ Mesh *BKE_mesh_new_from_object( return NULL; } - BKE_mesh_texspace_copy_from_object(tmpmesh, ob); - BKE_libblock_free_us(bmain, tmpobj); /* XXX The curve to mesh conversion is convoluted... But essentially, BKE_mesh_from_nurbs_displist() diff --git a/source/blender/blenkernel/intern/mesh_evaluate.c b/source/blender/blenkernel/intern/mesh_evaluate.c index c21c16adc85..00d1b29caf8 100644 --- a/source/blender/blenkernel/intern/mesh_evaluate.c +++ b/source/blender/blenkernel/intern/mesh_evaluate.c @@ -127,8 +127,8 @@ void BKE_mesh_calc_normals_mapping_ex( return; } - if (!pnors) pnors = MEM_callocN(sizeof(float[3]) * (size_t)numPolys, __func__); - /* if (!fnors) fnors = MEM_callocN(sizeof(float[3]) * numFaces, "face nors mesh.c"); */ /* NO NEED TO ALLOC YET */ + if (!pnors) pnors = MEM_calloc_arrayN((size_t)numPolys, sizeof(float[3]), __func__); + /* if (!fnors) fnors = MEM_calloc_arrayN(numFaces, sizeof(float[3]), "face nors mesh.c"); */ /* NO NEED TO ALLOC YET */ if (only_face_normals == false) { @@ -173,10 +173,14 @@ typedef struct MeshCalcNormalsData { const MLoop *mloop; MVert *mverts; float (*pnors)[3]; + float (*lnors_weighted)[3]; float (*vnors)[3]; } MeshCalcNormalsData; -static void mesh_calc_normals_poly_task_cb(void *userdata, const int pidx) +static void mesh_calc_normals_poly_cb( + void *__restrict userdata, + const int pidx, + const ParallelRangeTLS *__restrict UNUSED(tls)) { MeshCalcNormalsData *data = userdata; const MPoly *mp = &data->mpolys[pidx]; @@ -184,7 +188,10 @@ static void mesh_calc_normals_poly_task_cb(void *userdata, const int pidx) BKE_mesh_calc_poly_normal(mp, data->mloop + mp->loopstart, data->mverts, data->pnors[pidx]); } -static void mesh_calc_normals_poly_accum_task_cb(void *userdata, const int pidx) +static void mesh_calc_normals_poly_prepare_cb( + void *__restrict userdata, + const int pidx, + const ParallelRangeTLS *__restrict UNUSED(tls)) { MeshCalcNormalsData *data = userdata; const MPoly *mp = &data->mpolys[pidx]; @@ -193,7 +200,7 @@ static void mesh_calc_normals_poly_accum_task_cb(void *userdata, const int pidx) float pnor_temp[3]; float *pnor = data->pnors ? data->pnors[pidx] : pnor_temp; - float (*vnors)[3] = data->vnors; + float (*lnors_weighted)[3] = data->lnors_weighted; const int nverts = mp->totloop; float (*edgevecbuf)[3] = BLI_array_alloca(edgevecbuf, (size_t)nverts); @@ -220,42 +227,71 @@ static void mesh_calc_normals_poly_accum_task_cb(void *userdata, const int pidx) v_prev = v_curr; } if (UNLIKELY(normalize_v3(pnor) == 0.0f)) { - pnor[2] = 1.0f; /* other axis set to 0.0 */ + pnor[2] = 1.0f; /* other axes set to 0.0 */ } } /* accumulate angle weighted face normal */ - /* inline version of #accumulate_vertex_normals_poly_v3 */ + /* inline version of #accumulate_vertex_normals_poly_v3, + * split between this threaded callback and #mesh_calc_normals_poly_accum_cb. */ { const float *prev_edge = edgevecbuf[nverts - 1]; for (i = 0; i < nverts; i++) { + const int lidx = mp->loopstart + i; const float *cur_edge = edgevecbuf[i]; /* calculate angle between the two poly edges incident on * this vertex */ const float fac = saacos(-dot_v3v3(cur_edge, prev_edge)); - /* accumulate */ - for (int k = 3; k--; ) { - atomic_add_and_fetch_fl(&vnors[ml[i].v][k], pnor[k] * fac); - } + /* Store for later accumulation */ + mul_v3_v3fl(lnors_weighted[lidx], pnor, fac); + prev_edge = cur_edge; } } +} +static void mesh_calc_normals_poly_accum_cb( + void *__restrict userdata, + const int lidx, + const ParallelRangeTLS *__restrict UNUSED(tls)) +{ + MeshCalcNormalsData *data = userdata; + + add_v3_v3(data->vnors[data->mloop[lidx].v], data->lnors_weighted[lidx]); +} + +static void mesh_calc_normals_poly_finalize_cb( + void *__restrict userdata, + const int vidx, + const ParallelRangeTLS *__restrict UNUSED(tls)) +{ + MeshCalcNormalsData *data = userdata; + + MVert *mv = &data->mverts[vidx]; + float *no = data->vnors[vidx]; + + if (UNLIKELY(normalize_v3(no) == 0.0f)) { + /* following Mesh convention; we use vertex coordinate itself for normal in this case */ + normalize_v3_v3(no, mv->co); + } + + normal_float_to_short_v3(mv->no, no); } void BKE_mesh_calc_normals_poly( MVert *mverts, float (*r_vertnors)[3], int numVerts, const MLoop *mloop, const MPoly *mpolys, - int UNUSED(numLoops), int numPolys, float (*r_polynors)[3], + int numLoops, int numPolys, float (*r_polynors)[3], const bool only_face_normals) { float (*pnors)[3] = r_polynors; - float (*vnors)[3] = r_vertnors; - bool free_vnors = false; - int i; + + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.min_iter_per_thread = 1024; if (only_face_normals) { BLI_assert((pnors != NULL) || (numPolys == 0)); @@ -265,13 +301,17 @@ void BKE_mesh_calc_normals_poly( .mpolys = mpolys, .mloop = mloop, .mverts = mverts, .pnors = pnors, }; - BLI_task_parallel_range(0, numPolys, &data, mesh_calc_normals_poly_task_cb, (numPolys > BKE_MESH_OMP_LIMIT)); + BLI_task_parallel_range(0, numPolys, &data, mesh_calc_normals_poly_cb, &settings); return; } + float (*vnors)[3] = r_vertnors; + float (*lnors_weighted)[3] = MEM_malloc_arrayN((size_t)numLoops, sizeof(*lnors_weighted), __func__); + bool free_vnors = false; + /* first go through and calculate normals for all the polys */ if (vnors == NULL) { - vnors = MEM_callocN(sizeof(*vnors) * (size_t)numVerts, __func__); + vnors = MEM_calloc_arrayN((size_t)numVerts, sizeof(*vnors), __func__); free_vnors = true; } else { @@ -279,26 +319,23 @@ void BKE_mesh_calc_normals_poly( } MeshCalcNormalsData data = { - .mpolys = mpolys, .mloop = mloop, .mverts = mverts, .pnors = pnors, .vnors = vnors, + .mpolys = mpolys, .mloop = mloop, .mverts = mverts, + .pnors = pnors, .lnors_weighted = lnors_weighted, .vnors = vnors }; - BLI_task_parallel_range(0, numPolys, &data, mesh_calc_normals_poly_accum_task_cb, (numPolys > BKE_MESH_OMP_LIMIT)); + /* Compute poly normals, and prepare weighted loop normals. */ + BLI_task_parallel_range(0, numPolys, &data, mesh_calc_normals_poly_prepare_cb, &settings); - for (i = 0; i < numVerts; i++) { - MVert *mv = &mverts[i]; - float *no = vnors[i]; + /* Actually accumulate weighted loop normals into vertex ones. */ + BLI_task_parallel_range(0, numLoops, &data, mesh_calc_normals_poly_accum_cb, &settings); - if (UNLIKELY(normalize_v3(no) == 0.0f)) { - /* following Mesh convention; we use vertex coordinate itself for normal in this case */ - normalize_v3_v3(no, mv->co); - } - - normal_float_to_short_v3(mv->no, no); - } + /* Normalize and validate computed vertex normals. */ + BLI_task_parallel_range(0, numVerts, &data, mesh_calc_normals_poly_finalize_cb, &settings); if (free_vnors) { MEM_freeN(vnors); } + MEM_freeN(lnors_weighted); } void BKE_mesh_calc_normals(Mesh *mesh) @@ -319,10 +356,14 @@ void BKE_mesh_calc_normals_tessface( const MFace *mfaces, int numFaces, float (*r_faceNors)[3]) { - float (*tnorms)[3] = MEM_callocN(sizeof(*tnorms) * (size_t)numVerts, "tnorms"); - float (*fnors)[3] = (r_faceNors) ? r_faceNors : MEM_callocN(sizeof(*fnors) * (size_t)numFaces, "meshnormals"); + float (*tnorms)[3] = MEM_calloc_arrayN((size_t)numVerts, sizeof(*tnorms), "tnorms"); + float (*fnors)[3] = (r_faceNors) ? r_faceNors : MEM_calloc_arrayN((size_t)numFaces, sizeof(*fnors), "meshnormals"); int i; + if (!tnorms || !fnors) { + goto cleanup; + } + for (i = 0; i < numFaces; i++) { const MFace *mf = &mfaces[i]; float *f_no = fnors[i]; @@ -351,6 +392,7 @@ void BKE_mesh_calc_normals_tessface( normal_float_to_short_v3(mv->no, no); } +cleanup: MEM_freeN(tnorms); if (fnors != r_faceNors) @@ -363,10 +405,14 @@ void BKE_mesh_calc_normals_looptri( const MLoopTri *looptri, int looptri_num, float (*r_tri_nors)[3]) { - float (*tnorms)[3] = MEM_callocN(sizeof(*tnorms) * (size_t)numVerts, "tnorms"); - float (*fnors)[3] = (r_tri_nors) ? r_tri_nors : MEM_callocN(sizeof(*fnors) * (size_t)looptri_num, "meshnormals"); + float (*tnorms)[3] = MEM_calloc_arrayN((size_t)numVerts, sizeof(*tnorms), "tnorms"); + float (*fnors)[3] = (r_tri_nors) ? r_tri_nors : MEM_calloc_arrayN((size_t)looptri_num, sizeof(*fnors), "meshnormals"); int i; + if (!tnorms || !fnors) { + goto cleanup; + } + for (i = 0; i < looptri_num; i++) { const MLoopTri *lt = &looptri[i]; float *f_no = fnors[i]; @@ -397,6 +443,7 @@ void BKE_mesh_calc_normals_looptri( normal_float_to_short_v3(mv->no, no); } +cleanup: MEM_freeN(tnorms); if (fnors != r_tri_nors) @@ -1137,7 +1184,7 @@ static void loop_split_generator(TaskPool *pool, LoopSplitTaskDataCommon *common if (pool) { if (data_idx == 0) { - data_buff = MEM_callocN(sizeof(*data_buff) * LOOP_SPLIT_TASK_BLOCK_SIZE, __func__); + data_buff = MEM_calloc_arrayN(LOOP_SPLIT_TASK_BLOCK_SIZE, sizeof(*data_buff), __func__); } data = &data_buff[data_idx]; } @@ -1267,10 +1314,10 @@ void BKE_mesh_normals_loop_split( * store the negated value of loop index instead of INDEX_INVALID to retrieve the real value later in code). * Note also that lose edges always have both values set to 0! */ - int (*edge_to_loops)[2] = MEM_callocN(sizeof(*edge_to_loops) * (size_t)numEdges, __func__); + int (*edge_to_loops)[2] = MEM_calloc_arrayN((size_t)numEdges, sizeof(*edge_to_loops), __func__); /* Simple mapping from a loop to its polygon index. */ - int *loop_to_poly = r_loop_to_poly ? r_loop_to_poly : MEM_mallocN(sizeof(*loop_to_poly) * (size_t)numLoops, __func__); + int *loop_to_poly = r_loop_to_poly ? r_loop_to_poly : MEM_malloc_arrayN((size_t)numLoops, sizeof(*loop_to_poly), __func__); MPoly *mp; int mp_index; @@ -1424,8 +1471,8 @@ static void mesh_normals_loop_custom_set( */ MLoopNorSpaceArray lnors_spacearr = {NULL}; BLI_bitmap *done_loops = BLI_BITMAP_NEW((size_t)numLoops, __func__); - float (*lnors)[3] = MEM_callocN(sizeof(*lnors) * (size_t)numLoops, __func__); - int *loop_to_poly = MEM_mallocN(sizeof(int) * (size_t)numLoops, __func__); + float (*lnors)[3] = MEM_calloc_arrayN((size_t)numLoops, sizeof(*lnors), __func__); + int *loop_to_poly = MEM_malloc_arrayN((size_t)numLoops, sizeof(int), __func__); /* In this case we always consider split nors as ON, and do not want to use angle to define smooth fans! */ const bool use_split_normals = true; const float split_angle = (float)M_PI; @@ -1640,7 +1687,7 @@ void BKE_mesh_normals_loop_to_vertex( const MLoop *ml; int i; - int *vert_loops_nbr = MEM_callocN(sizeof(*vert_loops_nbr) * (size_t)numVerts, __func__); + int *vert_loops_nbr = MEM_calloc_arrayN((size_t)numVerts, sizeof(*vert_loops_nbr), __func__); copy_vn_fl((float *)r_vert_clnors, 3 * numVerts, 0.0f); @@ -2479,9 +2526,9 @@ int BKE_mesh_recalc_tessellation( /* allocate the length of totfaces, avoid many small reallocs, * if all faces are tri's it will be correct, quads == 2x allocs */ /* take care. we are _not_ calloc'ing so be sure to initialize each field */ - mface_to_poly_map = MEM_mallocN(sizeof(*mface_to_poly_map) * (size_t)looptri_num, __func__); - mface = MEM_mallocN(sizeof(*mface) * (size_t)looptri_num, __func__); - lindices = MEM_mallocN(sizeof(*lindices) * (size_t)looptri_num, __func__); + mface_to_poly_map = MEM_malloc_arrayN((size_t)looptri_num, sizeof(*mface_to_poly_map), __func__); + mface = MEM_malloc_arrayN((size_t)looptri_num, sizeof(*mface), __func__); + lindices = MEM_malloc_arrayN((size_t)looptri_num, sizeof(*lindices), __func__); mface_index = 0; mp = mpoly; @@ -2861,7 +2908,7 @@ int BKE_mesh_mpoly_to_mface(struct CustomData *fdata, struct CustomData *ldata, const bool hasLNor = CustomData_has_layer(ldata, CD_NORMAL); /* over-alloc, ngons will be skipped */ - mface = MEM_mallocN(sizeof(*mface) * (size_t)totpoly, __func__); + mface = MEM_malloc_arrayN((size_t)totpoly, sizeof(*mface), __func__); mpoly = CustomData_get_layer(pdata, CD_MPOLY); mloop = CustomData_get_layer(ldata, CD_MLOOP); @@ -3028,7 +3075,6 @@ static void bm_corners_to_loops_ex( else { const int side = (int)sqrtf((float)(fd->totdisp / corners)); const int side_sq = side * side; - const size_t disps_size = sizeof(float[3]) * (size_t)side_sq; for (i = 0; i < tot; i++, disps += side_sq, ld++) { ld->totdisp = side_sq; @@ -3037,12 +3083,12 @@ static void bm_corners_to_loops_ex( if (ld->disps) MEM_freeN(ld->disps); - ld->disps = MEM_mallocN(disps_size, "converted loop mdisps"); + ld->disps = MEM_malloc_arrayN((size_t)side_sq, sizeof(float[3]), "converted loop mdisps"); if (fd->disps) { - memcpy(ld->disps, disps, disps_size); + memcpy(ld->disps, disps, (size_t)side_sq * sizeof(float[3])); } else { - memset(ld->disps, 0, disps_size); + memset(ld->disps, 0, (size_t)side_sq * sizeof(float[3])); } } } @@ -3104,7 +3150,7 @@ void BKE_mesh_convert_mfaces_to_mpolys_ex(ID *id, CustomData *fdata, CustomData CustomData_free(pdata, totpoly_i); totpoly = totface_i; - mpoly = MEM_callocN(sizeof(MPoly) * (size_t)totpoly, "mpoly converted"); + mpoly = MEM_calloc_arrayN((size_t)totpoly, sizeof(MPoly), "mpoly converted"); CustomData_add_layer(pdata, CD_MPOLY, CD_ASSIGN, mpoly, totpoly); numTex = CustomData_number_of_layers(fdata, CD_MTFACE); @@ -3116,7 +3162,7 @@ void BKE_mesh_convert_mfaces_to_mpolys_ex(ID *id, CustomData *fdata, CustomData totloop += mf->v4 ? 4 : 3; } - mloop = MEM_callocN(sizeof(MLoop) * (size_t)totloop, "mloop converted"); + mloop = MEM_calloc_arrayN((size_t)totloop, sizeof(MLoop), "mloop converted"); CustomData_add_layer(ldata, CD_MLOOP, CD_ASSIGN, mloop, totloop); @@ -3515,7 +3561,7 @@ void BKE_mesh_calc_relative_deform( const MPoly *mp; int i; - int *vert_accum = MEM_callocN(sizeof(*vert_accum) * (size_t)totvert, __func__); + int *vert_accum = MEM_calloc_arrayN((size_t)totvert, sizeof(*vert_accum), __func__); memset(vert_cos_new, '\0', sizeof(*vert_cos_new) * (size_t)totvert); diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c index 8eb1a7733c1..8bfeacd256c 100644 --- a/source/blender/blenkernel/intern/modifier.c +++ b/source/blender/blenkernel/intern/modifier.c @@ -434,6 +434,11 @@ bool modifiers_isParticleEnabled(Object *ob) return (md && md->mode & (eModifierMode_Realtime | eModifierMode_Render)); } +/** + * Check whether is enabled. + * + * \param scene Current scene, may be NULL, in which case isDisabled callback of the modifier is never called. + */ bool modifier_isEnabled(struct Scene *scene, ModifierData *md, int required_mode) { const ModifierTypeInfo *mti = modifierType_getInfo(md->type); @@ -441,7 +446,7 @@ bool modifier_isEnabled(struct Scene *scene, ModifierData *md, int required_mode md->scene = scene; if ((md->mode & required_mode) != required_mode) return false; - if (mti->isDisabled && mti->isDisabled(md, required_mode == eModifierMode_Render)) return false; + if (scene != NULL && mti->isDisabled && mti->isDisabled(md, required_mode == eModifierMode_Render)) return false; if (md->mode & eModifierMode_DisableTemporary) return false; if ((required_mode & eModifierMode_Editmode) && !(mti->flags & eModifierTypeFlag_SupportsEditmode)) return false; diff --git a/source/blender/blenkernel/intern/movieclip.c b/source/blender/blenkernel/intern/movieclip.c index db05939b1cc..08df976941b 100644 --- a/source/blender/blenkernel/intern/movieclip.c +++ b/source/blender/blenkernel/intern/movieclip.c @@ -1524,12 +1524,12 @@ void BKE_movieclip_make_local(Main *bmain, MovieClip *clip, const bool lib_local BKE_id_make_local_generic(bmain, &clip->id, true, lib_local); } -float BKE_movieclip_remap_scene_to_clip_frame(MovieClip *clip, float framenr) +float BKE_movieclip_remap_scene_to_clip_frame(const MovieClip *clip, float framenr) { return framenr - (float) clip->start_frame + 1.0f; } -float BKE_movieclip_remap_clip_to_scene_frame(MovieClip *clip, float framenr) +float BKE_movieclip_remap_clip_to_scene_frame(const MovieClip *clip, float framenr) { return framenr + (float) clip->start_frame - 1.0f; } diff --git a/source/blender/blenkernel/intern/multires.c b/source/blender/blenkernel/intern/multires.c index 7ef4b588dcd..55f11604710 100644 --- a/source/blender/blenkernel/intern/multires.c +++ b/source/blender/blenkernel/intern/multires.c @@ -44,6 +44,7 @@ #include "BLI_blenlib.h" #include "BLI_math.h" #include "BLI_utildefines.h" +#include "BLI_task.h" #include "BKE_pbvh.h" #include "BKE_ccg.h" @@ -439,7 +440,7 @@ int multiresModifier_reshapeFromDeformMod(const struct EvaluationContext *eval_c /* Create DerivedMesh for deformation modifier */ dm = get_multires_dm(eval_ctx, scene, mmd, ob); numVerts = dm->getNumVerts(dm); - deformedVerts = MEM_mallocN(sizeof(float[3]) * numVerts, "multiresReshape_deformVerts"); + deformedVerts = MEM_malloc_arrayN(numVerts, sizeof(float[3]), "multiresReshape_deformVerts"); dm->getVertCos(dm, deformedVerts); mti->deformVerts(md, eval_ctx, ob, dm, deformedVerts, numVerts, 0); @@ -532,7 +533,7 @@ static void multires_reallocate_mdisps(int totloop, MDisps *mdisps, int lvl) /* reallocate displacements to be filled in */ for (i = 0; i < totloop; ++i) { int totdisp = multires_grid_tot[lvl]; - float (*disps)[3] = MEM_callocN(sizeof(float) * 3 * totdisp, "multires disps"); + float (*disps)[3] = MEM_calloc_arrayN(totdisp, 3 * sizeof(float), "multires disps"); if (mdisps[i].disps) MEM_freeN(mdisps[i].disps); @@ -596,7 +597,7 @@ static void multires_grid_paint_mask_downsample(GridPaintMask *gpm, int level) { if (level < gpm->level) { int gridsize = BKE_ccg_gridsize(level); - float *data = MEM_callocN(sizeof(float) * SQUARE(gridsize), + float *data = MEM_calloc_arrayN(SQUARE(gridsize), sizeof(float), "multires_grid_paint_mask_downsample"); int x, y; @@ -641,7 +642,7 @@ static void multires_del_higher(MultiresModifierData *mmd, Object *ob, int lvl) float (*disps)[3], (*ndisps)[3], (*hdisps)[3]; int totdisp = multires_grid_tot[lvl]; - disps = MEM_callocN(sizeof(float) * 3 * totdisp, "multires disps"); + disps = MEM_calloc_arrayN(totdisp, 3 * sizeof(float), "multires disps"); ndisps = disps; hdisps = mdisp->disps; @@ -784,7 +785,7 @@ void multiresModifier_base_apply(MultiresModifierData *mmd, Object *ob) cddm = CDDM_from_mesh(me); pmap = cddm->getPolyMap(ob, cddm); - origco = MEM_callocN(sizeof(float) * 3 * me->totvert, "multires apply base origco"); + origco = MEM_calloc_arrayN(me->totvert, 3 * sizeof(float), "multires apply base origco"); for (i = 0; i < me->totvert; ++i) copy_v3_v3(origco[i], me->mvert[i].co); @@ -824,8 +825,8 @@ void multiresModifier_base_apply(MultiresModifierData *mmd, Object *ob) * BKE_mesh_calc_poly_normal_coords() */ fake_poly.totloop = p->totloop; fake_poly.loopstart = 0; - fake_loops = MEM_mallocN(sizeof(MLoop) * p->totloop, "fake_loops"); - fake_co = MEM_mallocN(sizeof(float) * 3 * p->totloop, "fake_co"); + fake_loops = MEM_malloc_arrayN(p->totloop, sizeof(MLoop), "fake_loops"); + fake_co = MEM_malloc_arrayN(p->totloop, 3 * sizeof(float), "fake_co"); for (k = 0; k < p->totloop; ++k) { int vndx = me->mloop[p->loopstart + k].v; @@ -922,11 +923,11 @@ static void multires_subdivide(MultiresModifierData *mmd, Object *ob, int totlvl lowGridData = lowdm->getGridData(lowdm); lowdm->getGridKey(lowdm, &lowGridKey); - subGridData = MEM_callocN(sizeof(float *) * numGrids, "subGridData*"); + subGridData = MEM_calloc_arrayN(numGrids, sizeof(float *), "subGridData*"); for (i = 0; i < numGrids; ++i) { /* backup subsurf grids */ - subGridData[i] = MEM_callocN(highGridKey.elem_size * highGridSize * highGridSize, "subGridData"); + subGridData[i] = MEM_calloc_arrayN(highGridKey.elem_size, highGridSize * highGridSize, "subGridData"); memcpy(subGridData[i], highGridData[i], highGridKey.elem_size * highGridSize * highGridSize); /* overwrite with current displaced grids */ @@ -1002,6 +1003,117 @@ static void grid_tangent_matrix(float mat[3][3], const CCGKey *key, copy_v3_v3(mat[2], CCG_grid_elem_no(key, grid, x, y)); } + +typedef struct MultiresThreadedData { + DispOp op; + CCGElem **gridData, **subGridData; + CCGKey *key; + CCGKey *sub_key; + MPoly *mpoly; + MDisps *mdisps; + GridPaintMask *grid_paint_mask; + int *gridOffset; + int gridSize, dGridSize, dSkip; + float (*smat)[3]; +} MultiresThreadedData; + +static void multires_disp_run_cb( + void *__restrict userdata, + const int pidx, + const ParallelRangeTLS *__restrict UNUSED(tls)) +{ + MultiresThreadedData *tdata = userdata; + + DispOp op = tdata->op; + CCGElem **gridData = tdata->gridData; + CCGElem **subGridData = tdata->subGridData; + CCGKey *key = tdata->key; + MPoly *mpoly = tdata->mpoly; + MDisps *mdisps = tdata->mdisps; + GridPaintMask *grid_paint_mask = tdata->grid_paint_mask; + int *gridOffset = tdata->gridOffset; + int gridSize = tdata->gridSize; + int dGridSize = tdata->dGridSize; + int dSkip = tdata->dSkip; + + const int numVerts = mpoly[pidx].totloop; + int S, x, y, gIndex = gridOffset[pidx]; + + for (S = 0; S < numVerts; ++S, ++gIndex) { + GridPaintMask *gpm = grid_paint_mask ? &grid_paint_mask[gIndex] : NULL; + MDisps *mdisp = &mdisps[mpoly[pidx].loopstart + S]; + CCGElem *grid = gridData[gIndex]; + CCGElem *subgrid = subGridData[gIndex]; + float (*dispgrid)[3] = NULL; + + dispgrid = mdisp->disps; + + /* if needed, reallocate multires paint mask */ + if (gpm && gpm->level < key->level) { + gpm->level = key->level; + if (gpm->data) { + MEM_freeN(gpm->data); + } + gpm->data = MEM_calloc_arrayN(key->grid_area, sizeof(float), "gpm.data"); + } + + for (y = 0; y < gridSize; y++) { + for (x = 0; x < gridSize; x++) { + float *co = CCG_grid_elem_co(key, grid, x, y); + float *sco = CCG_grid_elem_co(key, subgrid, x, y); + float *data = dispgrid[dGridSize * y * dSkip + x * dSkip]; + float mat[3][3], disp[3], d[3], mask; + + /* construct tangent space matrix */ + grid_tangent_matrix(mat, key, x, y, subgrid); + + switch (op) { + case APPLY_DISPLACEMENTS: + /* Convert displacement to object space + * and add to grid points */ + mul_v3_m3v3(disp, mat, data); + add_v3_v3v3(co, sco, disp); + break; + case CALC_DISPLACEMENTS: + /* Calculate displacement between new and old + * grid points and convert to tangent space */ + sub_v3_v3v3(disp, co, sco); + invert_m3(mat); + mul_v3_m3v3(data, mat, disp); + break; + case ADD_DISPLACEMENTS: + /* Convert subdivided displacements to tangent + * space and add to the original displacements */ + invert_m3(mat); + mul_v3_m3v3(d, mat, co); + add_v3_v3(data, d); + break; + } + + if (gpm) { + switch (op) { + case APPLY_DISPLACEMENTS: + /* Copy mask from gpm to DM */ + *CCG_grid_elem_mask(key, grid, x, y) = + paint_grid_paint_mask(gpm, key->level, x, y); + break; + case CALC_DISPLACEMENTS: + /* Copy mask from DM to gpm */ + mask = *CCG_grid_elem_mask(key, grid, x, y); + gpm->data[y * gridSize + x] = CLAMPIS(mask, 0, 1); + break; + case ADD_DISPLACEMENTS: + /* Add mask displacement to gpm */ + gpm->data[y * gridSize + x] += + *CCG_grid_elem_mask(key, grid, x, y); + break; + } + } + } + } + } +} + /* XXX WARNING: subsurf elements from dm and oldGridData *must* be of the same format (size), * because this code uses CCGKey's info from dm to access oldGridData's normals * (through the call to grid_tangent_matrix())! */ @@ -1014,7 +1126,7 @@ static void multiresModifier_disp_run(DerivedMesh *dm, Mesh *me, DerivedMesh *dm MDisps *mdisps = CustomData_get_layer(&me->ldata, CD_MDISPS); GridPaintMask *grid_paint_mask = NULL; int *gridOffset; - int i, k, /*numGrids, */ gridSize, dGridSize, dSkip; + int i, gridSize, dGridSize, dSkip; int totloop, totpoly; /* this happens in the dm made by bmesh_mdisps_space_set */ @@ -1050,98 +1162,34 @@ static void multiresModifier_disp_run(DerivedMesh *dm, Mesh *me, DerivedMesh *dm if (key.has_mask) grid_paint_mask = CustomData_get_layer(&me->ldata, CD_GRID_PAINT_MASK); - k = 0; /*current loop/mdisp index within the mloop array*/ - -#pragma omp parallel for private(i) if (totloop * gridSize * gridSize >= CCG_OMP_LIMIT) - - for (i = 0; i < totpoly; ++i) { - const int numVerts = mpoly[i].totloop; - int S, x, y, gIndex = gridOffset[i]; - - for (S = 0; S < numVerts; ++S, ++gIndex, ++k) { - GridPaintMask *gpm = grid_paint_mask ? &grid_paint_mask[gIndex] : NULL; - MDisps *mdisp = &mdisps[mpoly[i].loopstart + S]; - CCGElem *grid = gridData[gIndex]; - CCGElem *subgrid = subGridData[gIndex]; - float (*dispgrid)[3] = NULL; - - /* when adding new faces in edit mode, need to allocate disps */ - if (!mdisp->disps) -#pragma omp critical - { - multires_reallocate_mdisps(totloop, mdisps, totlvl); - } - - dispgrid = mdisp->disps; - - /* if needed, reallocate multires paint mask */ - if (gpm && gpm->level < key.level) { - gpm->level = key.level; -#pragma omp critical - { - if (gpm->data) - MEM_freeN(gpm->data); - gpm->data = MEM_callocN(sizeof(float) * key.grid_area, "gpm.data"); - } - } + /* when adding new faces in edit mode, need to allocate disps */ + for (i = 0; i < totloop; ++i) { + if (mdisps[i].disps == NULL) { + multires_reallocate_mdisps(totloop, mdisps, totlvl); + break; + } + } - for (y = 0; y < gridSize; y++) { - for (x = 0; x < gridSize; x++) { - float *co = CCG_grid_elem_co(&key, grid, x, y); - float *sco = CCG_grid_elem_co(&key, subgrid, x, y); - float *data = dispgrid[dGridSize * y * dSkip + x * dSkip]; - float mat[3][3], disp[3], d[3], mask; + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.min_iter_per_thread = CCG_TASK_LIMIT; - /* construct tangent space matrix */ - grid_tangent_matrix(mat, &key, x, y, subgrid); + MultiresThreadedData data = { + .op = op, + .gridData = gridData, + .subGridData = subGridData, + .key = &key, + .mpoly = mpoly, + .mdisps = mdisps, + .grid_paint_mask = grid_paint_mask, + .gridOffset = gridOffset, + .gridSize = gridSize, + .dGridSize = dGridSize, + .dSkip = dSkip + }; - switch (op) { - case APPLY_DISPLACEMENTS: - /* Convert displacement to object space - * and add to grid points */ - mul_v3_m3v3(disp, mat, data); - add_v3_v3v3(co, sco, disp); - break; - case CALC_DISPLACEMENTS: - /* Calculate displacement between new and old - * grid points and convert to tangent space */ - sub_v3_v3v3(disp, co, sco); - invert_m3(mat); - mul_v3_m3v3(data, mat, disp); - break; - case ADD_DISPLACEMENTS: - /* Convert subdivided displacements to tangent - * space and add to the original displacements */ - invert_m3(mat); - mul_v3_m3v3(d, mat, co); - add_v3_v3(data, d); - break; - } + BLI_task_parallel_range(0, totpoly, &data, multires_disp_run_cb, &settings); - if (gpm) { - switch (op) { - case APPLY_DISPLACEMENTS: - /* Copy mask from gpm to DM */ - *CCG_grid_elem_mask(&key, grid, x, y) = - paint_grid_paint_mask(gpm, key.level, x, y); - break; - case CALC_DISPLACEMENTS: - /* Copy mask from DM to gpm */ - mask = *CCG_grid_elem_mask(&key, grid, x, y); - gpm->data[y * gridSize + x] = CLAMPIS(mask, 0, 1); - break; - case ADD_DISPLACEMENTS: - /* Add mask displacement to gpm */ - gpm->data[y * gridSize + x] += - *CCG_grid_elem_mask(&key, grid, x, y); - break; - } - } - } - } - } - } - if (op == APPLY_DISPLACEMENTS) { ccgSubSurf_stitchFaces(ccgdm->ss, 0, NULL, 0); ccgSubSurf_updateNormals(ccgdm->ss, NULL, 0); @@ -1199,12 +1247,12 @@ void multires_modifier_update_mdisps(struct DerivedMesh *dm) BLI_assert(highGridKey.elem_size == lowGridKey.elem_size); - subGridData = MEM_callocN(sizeof(CCGElem *) * numGrids, "subGridData*"); - diffGrid = MEM_callocN(lowGridKey.elem_size * lowGridSize * lowGridSize, "diff"); + subGridData = MEM_calloc_arrayN(numGrids, sizeof(CCGElem *), "subGridData*"); + diffGrid = MEM_calloc_arrayN(lowGridKey.elem_size, lowGridSize * lowGridSize, "diff"); for (i = 0; i < numGrids; ++i) { /* backup subsurf grids */ - subGridData[i] = MEM_callocN(highGridKey.elem_size * highGridSize * highGridSize, "subGridData"); + subGridData[i] = MEM_calloc_arrayN(highGridKey.elem_size, highGridSize * highGridSize, "subGridData"); memcpy(subGridData[i], highGridData[i], highGridKey.elem_size * highGridSize * highGridSize); /* write difference of subsurf and displaced low level into high subsurf */ @@ -1315,10 +1363,10 @@ void multires_set_space(DerivedMesh *dm, Object *ob, int from, int to) gridData = subsurf->getGridData(subsurf); subsurf->getGridKey(subsurf, &key); - subGridData = MEM_callocN(sizeof(CCGElem *) * numGrids, "subGridData*"); + subGridData = MEM_calloc_arrayN(numGrids, sizeof(CCGElem *), "subGridData*"); for (i = 0; i < numGrids; i++) { - subGridData[i] = MEM_callocN(key.elem_size * gridSize * gridSize, "subGridData"); + subGridData[i] = MEM_calloc_arrayN(key.elem_size, gridSize * gridSize, "subGridData"); memcpy(subGridData[i], gridData[i], key.elem_size * gridSize * gridSize); } @@ -1332,8 +1380,7 @@ void multires_set_space(DerivedMesh *dm, Object *ob, int from, int to) k = 0; /*current loop/mdisp index within the mloop array*/ - //#pragma omp parallel for private(i) if (dm->numLoopData * gridSize * gridSize >= CCG_OMP_LIMIT) - + /* TODO: Use BLI_task parallel range for that one too? */ for (i = 0; i < dm->numPolyData; ++i) { const int numVerts = mpoly[i].totloop; int S, x, y, gIndex = gridOffset[i]; @@ -1348,7 +1395,7 @@ void multires_set_space(DerivedMesh *dm, Object *ob, int from, int to) if (!mdisp->disps) { mdisp->totdisp = gridSize * gridSize; mdisp->level = totlvl; - mdisp->disps = MEM_callocN(sizeof(float) * 3 * mdisp->totdisp, "disp in multires_set_space"); + mdisp->disps = MEM_calloc_arrayN(mdisp->totdisp, 3 * sizeof(float), "disp in multires_set_space"); } dispgrid = mdisp->disps; @@ -1463,10 +1510,10 @@ DerivedMesh *multires_make_derived_from_derived(DerivedMesh *dm, gridData = result->getGridData(result); result->getGridKey(result, &key); - subGridData = MEM_mallocN(sizeof(CCGElem *) * numGrids, "subGridData*"); + subGridData = MEM_malloc_arrayN(numGrids, sizeof(CCGElem *), "subGridData*"); for (i = 0; i < numGrids; i++) { - subGridData[i] = MEM_mallocN(key.elem_size * gridSize * gridSize, "subGridData"); + subGridData[i] = MEM_malloc_arrayN(key.elem_size, gridSize * gridSize, "subGridData"); memcpy(subGridData[i], gridData[i], key.elem_size * gridSize * gridSize); } @@ -1556,7 +1603,7 @@ static void old_mdisps_convert(MFace *mface, MDisps *mdisp) int x, y, S; float (*disps)[3], (*out)[3], u = 0.0f, v = 0.0f; /* Quite gcc barking. */ - disps = MEM_callocN(sizeof(float) * 3 * newtotdisp, "multires disps"); + disps = MEM_calloc_arrayN(newtotdisp, 3 * sizeof(float), "multires disps"); out = disps; for (S = 0; S < nvert; S++) { @@ -1603,7 +1650,7 @@ void multires_load_old_250(Mesh *me) int totdisp = mdisps[i].totdisp / nvert; for (j = 0; j < nvert; j++, k++) { - mdisps2[k].disps = MEM_callocN(sizeof(float) * 3 * totdisp, "multires disp in conversion"); + mdisps2[k].disps = MEM_calloc_arrayN(totdisp, 3 * sizeof(float), "multires disp in conversion"); mdisps2[k].totdisp = totdisp; mdisps2[k].level = mdisps[i].level; memcpy(mdisps2[k].disps, mdisps[i].disps + totdisp * j, totdisp); @@ -1663,8 +1710,8 @@ static void create_old_vert_face_map(ListBase **map, IndexNode **mem, const Mult int i, j; IndexNode *node = NULL; - (*map) = MEM_callocN(sizeof(ListBase) * totvert, "vert face map"); - (*mem) = MEM_callocN(sizeof(IndexNode) * totface * 4, "vert face map mem"); + (*map) = MEM_calloc_arrayN(totvert, sizeof(ListBase), "vert face map"); + (*mem) = MEM_calloc_arrayN(totface, 4 * sizeof(IndexNode), "vert face map mem"); node = *mem; /* Find the users */ @@ -1682,8 +1729,8 @@ static void create_old_vert_edge_map(ListBase **map, IndexNode **mem, const Mult int i, j; IndexNode *node = NULL; - (*map) = MEM_callocN(sizeof(ListBase) * totvert, "vert edge map"); - (*mem) = MEM_callocN(sizeof(IndexNode) * totedge * 2, "vert edge map mem"); + (*map) = MEM_calloc_arrayN(totvert, sizeof(ListBase), "vert edge map"); + (*mem) = MEM_calloc_arrayN(totedge, 2 * sizeof(IndexNode), "vert edge map mem"); node = *mem; /* Find the users */ @@ -1865,7 +1912,11 @@ static void multires_load_old_dm(DerivedMesh *dm, Mesh *me, int totlvl) vsrc = mr->verts; vdst = dm->getVertArray(dm); totvert = (unsigned int)dm->getNumVerts(dm); - vvmap = MEM_callocN(sizeof(int) * totvert, "multires vvmap"); + vvmap = MEM_calloc_arrayN(totvert, sizeof(int), "multires vvmap"); + + if (!vvmap) { + return; + } lvl1 = mr->levels.first; /* Load base verts */ @@ -1950,10 +2001,10 @@ static void multires_load_old_dm(DerivedMesh *dm, Mesh *me, int totlvl) } /* calculate vert to edge/face maps for each level (except the last) */ - fmap = MEM_callocN(sizeof(ListBase *) * (mr->level_count - 1), "multires fmap"); - emap = MEM_callocN(sizeof(ListBase *) * (mr->level_count - 1), "multires emap"); - fmem = MEM_callocN(sizeof(IndexNode *) * (mr->level_count - 1), "multires fmem"); - emem = MEM_callocN(sizeof(IndexNode *) * (mr->level_count - 1), "multires emem"); + fmap = MEM_calloc_arrayN((mr->level_count - 1), sizeof(ListBase *), "multires fmap"); + emap = MEM_calloc_arrayN((mr->level_count - 1), sizeof(ListBase *), "multires emap"); + fmem = MEM_calloc_arrayN((mr->level_count - 1), sizeof(IndexNode *), "multires fmem"); + emem = MEM_calloc_arrayN((mr->level_count - 1), sizeof(IndexNode *), "multires emem"); lvl = lvl1; for (i = 0; i < (unsigned int)mr->level_count - 1; ++i) { create_old_vert_face_map(fmap + i, fmem + i, lvl->faces, lvl->totvert, lvl->totface); @@ -2174,6 +2225,56 @@ static void multires_sync_levels(Scene *scene, Object *ob_src, Object *ob_dst) } } +static void multires_apply_smat_cb( + void *__restrict userdata, + const int pidx, + const ParallelRangeTLS *__restrict UNUSED(tls)) +{ + MultiresThreadedData *tdata = userdata; + + CCGElem **gridData = tdata->gridData; + CCGElem **subGridData = tdata->subGridData; + CCGKey *dm_key = tdata->key; + CCGKey *subdm_key = tdata->sub_key; + MPoly *mpoly = tdata->mpoly; + MDisps *mdisps = tdata->mdisps; + int *gridOffset = tdata->gridOffset; + int gridSize = tdata->gridSize; + int dGridSize = tdata->dGridSize; + int dSkip = tdata->dSkip; + float (*smat)[3] = tdata->smat; + + const int numVerts = mpoly[pidx].totloop; + MDisps *mdisp = &mdisps[mpoly[pidx].loopstart]; + int S, x, y, gIndex = gridOffset[pidx]; + + for (S = 0; S < numVerts; ++S, ++gIndex, mdisp++) { + CCGElem *grid = gridData[gIndex]; + CCGElem *subgrid = subGridData[gIndex]; + float (*dispgrid)[3] = mdisp->disps; + + for (y = 0; y < gridSize; y++) { + for (x = 0; x < gridSize; x++) { + float *co = CCG_grid_elem_co(dm_key, grid, x, y); + float *sco = CCG_grid_elem_co(subdm_key, subgrid, x, y); + float *data = dispgrid[dGridSize * y * dSkip + x * dSkip]; + float mat[3][3], disp[3]; + + /* construct tangent space matrix */ + grid_tangent_matrix(mat, dm_key, x, y, grid); + + /* scale subgrid coord and calculate displacement */ + mul_m3_v3(smat, sco); + sub_v3_v3v3(disp, sco, co); + + /* convert difference to tangent space */ + invert_m3(mat); + mul_v3_m3v3(data, mat, disp); + } + } + } +} + static void multires_apply_smat(const struct EvaluationContext *eval_ctx, Scene *scene, Object *ob, float smat[3][3]) { DerivedMesh *dm = NULL, *cddm = NULL, *subdm = NULL; @@ -2205,7 +2306,7 @@ static void multires_apply_smat(const struct EvaluationContext *eval_ctx, Scene cddm = mesh_get_derived_deform(eval_ctx, scene, ob, CD_MASK_BAREMESH); totvert = cddm->getNumVerts(cddm); - vertCos = MEM_mallocN(sizeof(*vertCos) * totvert, "multiresScale vertCos"); + vertCos = MEM_malloc_arrayN(totvert, sizeof(*vertCos), "multiresScale vertCos"); cddm->getVertCos(cddm, vertCos); for (i = 0; i < totvert; i++) mul_m3_v3(smat, vertCos[i]); @@ -2226,38 +2327,25 @@ static void multires_apply_smat(const struct EvaluationContext *eval_ctx, Scene dGridSize = multires_side_tot[high_mmd.totlvl]; dSkip = (dGridSize - 1) / (gridSize - 1); -#pragma omp parallel for private(i) if (me->totloop * gridSize * gridSize >= CCG_OMP_LIMIT) - for (i = 0; i < me->totpoly; ++i) { - const int numVerts = mpoly[i].totloop; - MDisps *mdisp = &mdisps[mpoly[i].loopstart]; - int S, x, y, gIndex = gridOffset[i]; - - for (S = 0; S < numVerts; ++S, ++gIndex, mdisp++) { - CCGElem *grid = gridData[gIndex]; - CCGElem *subgrid = subGridData[gIndex]; - float (*dispgrid)[3] = mdisp->disps; - - for (y = 0; y < gridSize; y++) { - for (x = 0; x < gridSize; x++) { - float *co = CCG_grid_elem_co(&dm_key, grid, x, y); - float *sco = CCG_grid_elem_co(&subdm_key, subgrid, x, y); - float *data = dispgrid[dGridSize * y * dSkip + x * dSkip]; - float mat[3][3], disp[3]; - - /* construct tangent space matrix */ - grid_tangent_matrix(mat, &dm_key, x, y, grid); - - /* scale subgrid coord and calculate displacement */ - mul_m3_v3(smat, sco); - sub_v3_v3v3(disp, sco, co); - - /* convert difference to tangent space */ - invert_m3(mat); - mul_v3_m3v3(data, mat, disp); - } - } - } - } + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.min_iter_per_thread = CCG_TASK_LIMIT; + + MultiresThreadedData data = { + .gridData = gridData, + .subGridData = subGridData, + .key = &dm_key, + .sub_key = &subdm_key, + .mpoly = mpoly, + .mdisps = mdisps, + .gridOffset = gridOffset, + .gridSize = gridSize, + .dGridSize = dGridSize, + .dSkip = dSkip, + .smat = smat + }; + + BLI_task_parallel_range(0, me->totpoly, &data, multires_apply_smat_cb, &settings); dm->release(dm); subdm->release(subdm); @@ -2326,7 +2414,7 @@ void multires_topology_changed(Mesh *me) if (!mdisp->totdisp || !mdisp->disps) { if (grid) { mdisp->totdisp = grid; - mdisp->disps = MEM_callocN(3 * mdisp->totdisp * sizeof(float), "mdisp topology"); + mdisp->disps = MEM_calloc_arrayN(3 * sizeof(float), mdisp->totdisp, "mdisp topology"); } continue; diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c index b76fd49fc9c..cac2aab26dd 100644 --- a/source/blender/blenkernel/intern/node.c +++ b/source/blender/blenkernel/intern/node.c @@ -506,6 +506,26 @@ static bNodeSocket *make_socket(bNodeTree *ntree, bNode *UNUSED(node), int in_ou return sock; } +void nodeModifySocketType(bNodeTree *ntree, bNode *UNUSED(node), bNodeSocket *sock, + int type, int subtype) +{ + const char *idname = nodeStaticSocketType(type, subtype); + + if (!idname) { + printf("Error: static node socket type %d undefined\n", type); + return; + } + + if (sock->default_value) { + MEM_freeN(sock->default_value); + sock->default_value = NULL; + } + + sock->type = type; + BLI_strncpy(sock->idname, idname, sizeof(sock->idname)); + node_socket_set_typeinfo(ntree, sock, nodeSocketTypeFind(idname)); +} + bNodeSocket *nodeAddSocket(bNodeTree *ntree, bNode *node, int in_out, const char *idname, const char *identifier, const char *name) { @@ -3173,13 +3193,17 @@ void nodeSynchronizeID(bNode *node, bool copy_to_id) void nodeLabel(bNodeTree *ntree, bNode *node, char *label, int maxlen) { + label[0] = '\0'; + if (node->label[0] != '\0') { BLI_strncpy(label, node->label, maxlen); } else if (node->typeinfo->labelfunc) { node->typeinfo->labelfunc(ntree, node, label, maxlen); } - else { + + /* The previous methods (labelfunc) could not provide an adequate label for the node. */ + if (label[0] == '\0') { /* Kind of hacky and weak... Ideally would be better to use RNA here. :| */ const char *tmp = CTX_IFACE_(BLT_I18NCONTEXT_ID_NODETREE, node->typeinfo->ui_name); if (tmp == node->typeinfo->ui_name) { @@ -3565,6 +3589,7 @@ static void registerShaderNodes(void) register_node_type_sh_attribute(); register_node_type_sh_bevel(); + register_node_type_sh_displacement(); register_node_type_sh_geometry(); register_node_type_sh_light_path(); register_node_type_sh_light_falloff(); diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index bea9e3bdcac..8c85a0413b8 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -356,7 +356,7 @@ void BKE_object_free_derived_caches(Object *ob) if (ob->mesh_evaluated != NULL) { /* Restore initial pointer. */ - ob->data = ob->mesh_evaluated->id.newid; + ob->data = ob->mesh_evaluated->id.orig_id; /* Evaluated mesh points to edit mesh, but does not own it. */ ob->mesh_evaluated->edit_btmesh = NULL; BKE_mesh_free(ob->mesh_evaluated); @@ -458,11 +458,8 @@ void BKE_object_free(Object *ob) GPU_lamp_free(ob); for (ObjectEngineData *oed = ob->drawdata.first; oed; oed = oed->next) { - if (oed->storage) { - if (oed->free) { - oed->free(oed->storage); - } - MEM_freeN(oed->storage); + if (oed->free != NULL) { + oed->free(oed); } } BLI_freelistN(&ob->drawdata); @@ -552,11 +549,32 @@ bool BKE_object_is_in_wpaint_select_vert(Object *ob) /** * Return if the object is visible, as evaluated by depsgraph - * Keep in sync with rna_object.c (object.is_visible). */ -bool BKE_object_is_visible(Object *ob) +bool BKE_object_is_visible(Object *ob, const eObjectVisibilityCheck mode) { - return (ob->base_flag & BASE_VISIBLED) != 0; + if ((ob->base_flag & BASE_VISIBLED) == 0) { + return false; + } + + if (mode == OB_VISIBILITY_CHECK_UNKNOWN_RENDER_MODE) { + return true; + } + + if (((ob->transflag & OB_DUPLI) == 0) && + (ob->particlesystem.first == NULL)) + { + return true; + } + + switch (mode) { + case OB_VISIBILITY_CHECK_FOR_VIEWPORT: + return ((ob->duplicator_visibility_flag & OB_DUPLI_FLAG_VIEWPORT) != 0); + case OB_VISIBILITY_CHECK_FOR_RENDER: + return ((ob->duplicator_visibility_flag & OB_DUPLI_FLAG_RENDER) != 0); + default: + BLI_assert(!"Object visible test mode not supported."); + return false; + } } bool BKE_object_exists_check(Object *obtest) @@ -684,6 +702,7 @@ void BKE_object_init(Object *ob) ob->col_group = 0x01; ob->col_mask = 0xffff; ob->preview = NULL; + ob->duplicator_visibility_flag = OB_DUPLI_FLAG_VIEWPORT | OB_DUPLI_FLAG_RENDER; /* NT fluid sim defaults */ ob->fluidsimSettings = NULL; @@ -2699,8 +2718,11 @@ void BKE_object_handle_update_ex(const EvaluationContext *eval_ctx, RigidBodyWorld *rbw, const bool do_proxy_update) { - const bool recalc_object = (ob->id.tag & LIB_TAG_ID_RECALC) != 0; - const bool recalc_data = (ob->id.tag & LIB_TAG_ID_RECALC_DATA) != 0; + const ID *object_data = ob->data; + const bool recalc_object = (ob->id.recalc & ID_RECALC) != 0; + const bool recalc_data = + (object_data != NULL) ? ((object_data->recalc & ID_RECALC_ALL) != 0) + : 0; if (!recalc_object && ! recalc_data) { object_handle_update_proxy(eval_ctx, scene, ob, do_proxy_update); return; @@ -2739,7 +2761,7 @@ void BKE_object_handle_update_ex(const EvaluationContext *eval_ctx, BKE_object_handle_data_update(eval_ctx, scene, ob); } - ob->id.tag &= ~LIB_TAG_ID_RECALC_ALL; + ob->id.recalc &= ID_RECALC_ALL; object_handle_update_proxy(eval_ctx, scene, ob, do_proxy_update); } @@ -3722,7 +3744,7 @@ bool BKE_object_modifier_update_subframe( /* was originally OB_RECALC_ALL - TODO - which flags are really needed??? */ /* TODO(sergey): What about animation? */ - ob->id.tag |= LIB_TAG_ID_RECALC_ALL; + ob->id.recalc |= ID_RECALC_ALL; BKE_animsys_evaluate_animdata(scene, &ob->id, ob->adt, frame, ADT_RECALC_ANIM); if (update_mesh) { /* ignore cache clear during subframe updates diff --git a/source/blender/blenkernel/intern/object_dupli.c b/source/blender/blenkernel/intern/object_dupli.c index a16acd9d564..13589866e48 100644 --- a/source/blender/blenkernel/intern/object_dupli.c +++ b/source/blender/blenkernel/intern/object_dupli.c @@ -364,10 +364,6 @@ static void make_duplis_frames(const DupliContext *ctx) /* duplicate over the required range */ if (ob->transflag & OB_DUPLINOSPEED) enable_cu_speed = 0; - /* special flag to avoid setting recalc flags to notify the depsgraph of - * updates, as this is not a permanent change to the object */ - ob->id.tag |= LIB_TAG_ANIM_NO_RECALC; - for (scene->r.cfra = ob->dupsta; scene->r.cfra <= dupend; scene->r.cfra++) { int ok = 1; @@ -617,7 +613,7 @@ static void make_duplis_font(const DupliContext *ctx) /* in par the family name is stored, use this to find the other objects */ - BKE_vfont_to_curve_ex(G.main, par, FO_DUPLI, NULL, + BKE_vfont_to_curve_ex(G.main, par, par->data, FO_DUPLI, NULL, &text, &text_len, &text_free, &chartransdata); if (text == NULL || chartransdata == NULL) { diff --git a/source/blender/blenkernel/intern/object_update.c b/source/blender/blenkernel/intern/object_update.c index 71d8c1981af..bc183ba95a6 100644 --- a/source/blender/blenkernel/intern/object_update.c +++ b/source/blender/blenkernel/intern/object_update.c @@ -361,7 +361,7 @@ void BKE_object_eval_uber_data(const EvaluationContext *eval_ctx, * This way we can restore original object data when we are freeing * evaluated mesh. */ - new_mesh->id.newid = &mesh->id; + new_mesh->id.orig_id = &mesh->id; } #if 0 if (ob->derivedFinal != NULL) { @@ -438,10 +438,14 @@ void BKE_object_eval_flush_base_flags(const EvaluationContext *UNUSED(eval_ctx), Object *object, Base *base, bool is_from_set) { DEBUG_PRINT("%s on %s (%p)\n", __func__, object->id.name, object); + /* Make sure we have the base collection settings is already populated. - * This will fail when BKE_layer_eval_layer_collection_pre hasn't run yet - * Which usually means a missing call to DEG_id_tag_update(). */ + * This will fail when BKE_layer_eval_layer_collection_pre hasn't run yet. + * + * Which usually means a missing call to DEG_id_tag_update(id, DEG_TAG_BASE_FLAGS_UPDATE). + * Either of the entire scene, or of the newly added objects.*/ BLI_assert(!BLI_listbase_is_empty(&base->collection_properties->data.group)); + /* Copy flags and settings from base. */ object->base_flag = base->flag; if (is_from_set) { diff --git a/source/blender/blenkernel/intern/ocean.c b/source/blender/blenkernel/intern/ocean.c index 537c8926a5b..0b4bc39627e 100644 --- a/source/blender/blenkernel/intern/ocean.c +++ b/source/blender/blenkernel/intern/ocean.c @@ -502,7 +502,10 @@ typedef struct OceanSimulateData { float chop_amount; } OceanSimulateData; -static void ocean_compute_htilda(void *userdata, const int i) +static void ocean_compute_htilda( + void *__restrict userdata, + const int i, + const ParallelRangeTLS *__restrict UNUSED(tls)) { OceanSimulateData *osd = userdata; const Ocean *o = osd->o; @@ -748,7 +751,10 @@ void BKE_ocean_simulate(struct Ocean *o, float t, float scale, float chop_amount * This is not optimal in all cases, but remains reasonably simple and should be OK most of the time. */ /* compute a new htilda */ - BLI_task_parallel_range(0, o->_M, &osd, ocean_compute_htilda, o->_M > 16); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = (o->_M > 16); + BLI_task_parallel_range(0, o->_M, &osd, ocean_compute_htilda, &settings); if (o->_do_disp_y) { BLI_task_pool_push(pool, ocean_compute_displacement_y, NULL, false, TASK_PRIORITY_HIGH); diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c index c88642a8164..152a882de97 100644 --- a/source/blender/blenkernel/intern/paint.c +++ b/source/blender/blenkernel/intern/paint.c @@ -532,8 +532,10 @@ void BKE_paint_init(Scene *sce, ePaintMode mode, const char col[3]) short ob_mode = BKE_paint_object_mode_from_paint_mode(mode); brush = BKE_brush_first_search(G.main, ob_mode); - if (!brush) + if (!brush) { brush = BKE_brush_add(G.main, "Brush", ob_mode); + id_us_min(&brush->id); /* fake user only */ + } BKE_paint_brush_set(paint, brush); } @@ -641,8 +643,9 @@ void paint_update_brush_rake_rotation(UnifiedPaintSettings *ups, Brush *brush, f ups->brush_rotation_sec = 0.0f; } -void paint_calculate_rake_rotation(UnifiedPaintSettings *ups, Brush *brush, const float mouse_pos[2]) +bool paint_calculate_rake_rotation(UnifiedPaintSettings *ups, Brush *brush, const float mouse_pos[2]) { + bool ok = false; if ((brush->mtex.brush_angle_mode & MTEX_ANGLE_RAKE) || (brush->mask_mtex.brush_angle_mode & MTEX_ANGLE_RAKE)) { const float r = RAKE_THRESHHOLD; float rotation; @@ -658,16 +661,20 @@ void paint_calculate_rake_rotation(UnifiedPaintSettings *ups, Brush *brush, cons ups->last_rake_angle = rotation; paint_update_brush_rake_rotation(ups, brush, rotation); + ok = true; } /* make sure we reset here to the last rotation to avoid accumulating * values in case a random rotation is also added */ else { paint_update_brush_rake_rotation(ups, brush, ups->last_rake_angle); + ok = false; } } else { ups->brush_rotation = ups->brush_rotation_sec = 0.0f; + ok = true; } + return ok; } void BKE_sculptsession_free_deformMats(SculptSession *ss) @@ -881,6 +888,7 @@ void BKE_sculpt_update_mesh_elements( ss->modifiers_active = sculpt_modifiers_active(scene, sd, ob); ss->show_diffuse_color = (sd->flags & SCULPT_SHOW_DIFFUSE) != 0; + ss->show_mask = (sd->flags & SCULPT_HIDE_MASK) == 0; ss->building_vp_handle = false; @@ -935,6 +943,7 @@ void BKE_sculpt_update_mesh_elements( ss->pmap = (need_pmap && dm->getPolyMap) ? dm->getPolyMap(ob, dm) : NULL; pbvh_show_diffuse_color_set(ss->pbvh, ss->show_diffuse_color); + pbvh_show_mask_set(ss->pbvh, ss->show_mask); if (ss->modifiers_active) { if (!ss->orig_cos) { diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c index 7d1c80dca41..5e2cd89a750 100644 --- a/source/blender/blenkernel/intern/particle.c +++ b/source/blender/blenkernel/intern/particle.c @@ -555,7 +555,8 @@ void psys_free_pdd(ParticleSystem *psys) psys->pdd->vedata = NULL; psys->pdd->totpoint = 0; - psys->pdd->tot_vec_size = 0; + psys->pdd->totpart = 0; + psys->pdd->partsize = 0; } } /* free everything */ @@ -672,8 +673,9 @@ void psys_render_set(Object *ob, ParticleSystem *psys, float viewmat[4][4], floa psys->renderdata = data; /* Hair can and has to be recalculated if everything isn't displayed. */ - if (psys->part->disp != 100 && psys->part->type == PART_HAIR) + if (psys->part->disp != 100 && ELEM(psys->part->type, PART_HAIR, PART_FLUID)) { psys->recalc |= PSYS_RECALC_RESET; + } } void psys_render_restore(Object *ob, ParticleSystem *psys) @@ -746,7 +748,7 @@ void psys_render_restore(Object *ob, ParticleSystem *psys) if (disp != render_disp) { /* Hair can and has to be recalculated if everything isn't displayed. */ - if (psys->part->type == PART_HAIR) { + if (ELEM(psys->part->type, PART_HAIR, PART_FLUID)) { psys->recalc |= PSYS_RECALC_RESET; } else { @@ -2801,7 +2803,9 @@ void psys_cache_edit_paths(const EvaluationContext *eval_ctx, Scene *scene, Obje /* frs_sec = (psys || edit->pid.flag & PTCACHE_VEL_PER_SEC) ? 25.0f : 1.0f; */ /* UNUSED */ - if (pset->brushtype == PE_BRUSH_WEIGHT) { + const bool use_weight = (pset->brushtype == PE_BRUSH_WEIGHT) && (psys != NULL) && (psys->particles != NULL); + + if (use_weight) { ; /* use weight painting colors now... */ } else { @@ -2831,10 +2835,11 @@ void psys_cache_edit_paths(const EvaluationContext *eval_ctx, Scene *scene, Obje /* should init_particle_interpolation set this ? */ - if (pset->brushtype == PE_BRUSH_WEIGHT) { + if (use_weight) { pind.hkey[0] = NULL; /* pa != NULL since the weight brush is only available for hair */ - pind.hkey[1] = pa->hair; + pind.hkey[0] = pa->hair; + pind.hkey[1] = pa->hair + 1; } @@ -2891,13 +2896,27 @@ void psys_cache_edit_paths(const EvaluationContext *eval_ctx, Scene *scene, Obje } /* selection coloring in edit mode */ - if (pset->brushtype == PE_BRUSH_WEIGHT) { - float t2; - + if (use_weight) { if (k == 0) { weight_to_rgb(ca->col, pind.hkey[1]->weight); } else { + /* warning: copied from 'do_particle_interpolation' (without 'mvert' array stepping) */ + float real_t; + if (result.time < 0.0f) { + real_t = -result.time; + } + else { + real_t = pind.hkey[0]->time + t * (pind.hkey[0][pa->totkey - 1].time - pind.hkey[0]->time); + } + + while (pind.hkey[1]->time < real_t) { + pind.hkey[1]++; + } + pind.hkey[0] = pind.hkey[1] - 1; + /* end copy */ + + float w1[3], w2[3]; keytime = (t - (*pind.ekey[0]->time)) / ((*pind.ekey[1]->time) - (*pind.ekey[0]->time)); @@ -2906,13 +2925,6 @@ void psys_cache_edit_paths(const EvaluationContext *eval_ctx, Scene *scene, Obje interp_v3_v3v3(ca->col, w1, w2, keytime); } - - /* at the moment this is only used for weight painting. - * will need to move out of this check if its used elsewhere. */ - t2 = birthtime + ((float)k / (float)segments) * (dietime - birthtime); - - while (pind.hkey[1]->time < t2) pind.hkey[1]++; - pind.hkey[0] = pind.hkey[1] - 1; } else { if ((ekey + (pind.ekey[0] - point->keys))->flag & PEK_SELECT) { @@ -3145,7 +3157,7 @@ ModifierData *object_add_particle_system(Scene *scene, Object *ob, const char *n psys->pointcache = BKE_ptcache_add(&psys->ptcaches); BLI_addtail(&ob->particlesystem, psys); - psys->part = psys_new_settings(DATA_("ParticleSettings"), NULL); + psys->part = BKE_particlesettings_add(NULL, DATA_("ParticleSettings")); if (BLI_listbase_count_ex(&ob->particlesystem, 2) > 1) BLI_snprintf(psys->name, sizeof(psys->name), DATA_("ParticleSystem %i"), BLI_listbase_count(&ob->particlesystem)); @@ -3278,7 +3290,7 @@ static void default_particle_settings(ParticleSettings *part) part->clength = 1.0f; part->clength_thres = 0.0f; - part->draw = PART_DRAW_EMITTER; + part->draw = 0; part->draw_line[0] = 0.5; part->path_start = 0.0f; part->path_end = 1.0f; @@ -3304,7 +3316,7 @@ static void default_particle_settings(ParticleSettings *part) } -ParticleSettings *psys_new_settings(const char *name, Main *main) +ParticleSettings *BKE_particlesettings_add(Main *main, const char *name) { ParticleSettings *part; diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c index da227514512..ac10ad44bf1 100644 --- a/source/blender/blenkernel/intern/particle_system.c +++ b/source/blender/blenkernel/intern/particle_system.c @@ -3375,14 +3375,16 @@ typedef struct DynamicStepSolverTaskData { } DynamicStepSolverTaskData; static void dynamics_step_sph_ddr_task_cb_ex( - void *userdata, void *userdata_chunk, const int p, const int UNUSED(thread_id)) + void *__restrict userdata, + const int p, + const ParallelRangeTLS *__restrict tls) { DynamicStepSolverTaskData *data = userdata; ParticleSimulationData *sim = data->sim; ParticleSystem *psys = sim->psys; ParticleSettings *part = psys->part; - SPHData *sphdata = userdata_chunk; + SPHData *sphdata = tls->userdata_chunk; ParticleData *pa; @@ -3409,7 +3411,9 @@ static void dynamics_step_sph_ddr_task_cb_ex( } static void dynamics_step_sph_classical_basic_integrate_task_cb_ex( - void *userdata, void *UNUSED(userdata_chunk), const int p, const int UNUSED(thread_id)) + void *__restrict userdata, + const int p, + const ParallelRangeTLS *__restrict UNUSED(tls)) { DynamicStepSolverTaskData *data = userdata; ParticleSimulationData *sim = data->sim; @@ -3425,13 +3429,15 @@ static void dynamics_step_sph_classical_basic_integrate_task_cb_ex( } static void dynamics_step_sph_classical_calc_density_task_cb_ex( - void *userdata, void *userdata_chunk, const int p, const int UNUSED(thread_id)) + void *__restrict userdata, + const int p, + const ParallelRangeTLS *__restrict tls) { DynamicStepSolverTaskData *data = userdata; ParticleSimulationData *sim = data->sim; ParticleSystem *psys = sim->psys; - SPHData *sphdata = userdata_chunk; + SPHData *sphdata = tls->userdata_chunk; ParticleData *pa; @@ -3443,14 +3449,16 @@ static void dynamics_step_sph_classical_calc_density_task_cb_ex( } static void dynamics_step_sph_classical_integrate_task_cb_ex( - void *userdata, void *userdata_chunk, const int p, const int UNUSED(thread_id)) + void *__restrict userdata, + const int p, + const ParallelRangeTLS *__restrict tls) { DynamicStepSolverTaskData *data = userdata; ParticleSimulationData *sim = data->sim; ParticleSystem *psys = sim->psys; ParticleSettings *part = psys->part; - SPHData *sphdata = userdata_chunk; + SPHData *sphdata = tls->userdata_chunk; ParticleData *pa; @@ -3641,9 +3649,16 @@ static void dynamics_step(ParticleSimulationData *sim, float cfra) /* Apply SPH forces using double-density relaxation algorithm * (Clavat et. al.) */ - BLI_task_parallel_range_ex( - 0, psys->totpart, &task_data, &sphdata, sizeof(sphdata), - dynamics_step_sph_ddr_task_cb_ex, psys->totpart > 100, true); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = (psys->totpart > 100); + settings.userdata_chunk = &sphdata; + settings.userdata_chunk_size = sizeof(sphdata); + BLI_task_parallel_range( + 0, psys->totpart, + &task_data, + dynamics_step_sph_ddr_task_cb_ex, + &settings); sph_springs_modify(psys, timestep); } @@ -3653,21 +3668,46 @@ static void dynamics_step(ParticleSimulationData *sim, float cfra) * and Monaghan). Note that, unlike double-density relaxation, * this algorithm is separated into distinct loops. */ - BLI_task_parallel_range_ex( - 0, psys->totpart, &task_data, NULL, 0, - dynamics_step_sph_classical_basic_integrate_task_cb_ex, psys->totpart > 100, true); + { + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = (psys->totpart > 100); + BLI_task_parallel_range( + 0, psys->totpart, + &task_data, + dynamics_step_sph_classical_basic_integrate_task_cb_ex, + &settings); + } /* calculate summation density */ /* Note that we could avoid copying sphdata for each thread here (it's only read here), * but doubt this would gain us anything except confusion... */ - BLI_task_parallel_range_ex( - 0, psys->totpart, &task_data, &sphdata, sizeof(sphdata), - dynamics_step_sph_classical_calc_density_task_cb_ex, psys->totpart > 100, true); + { + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = (psys->totpart > 100); + settings.userdata_chunk = &sphdata; + settings.userdata_chunk_size = sizeof(sphdata); + BLI_task_parallel_range( + 0, psys->totpart, + &task_data, + dynamics_step_sph_classical_calc_density_task_cb_ex, + &settings); + } /* do global forces & effectors */ - BLI_task_parallel_range_ex( - 0, psys->totpart, &task_data, &sphdata, sizeof(sphdata), - dynamics_step_sph_classical_integrate_task_cb_ex, psys->totpart > 100, true); + { + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = (psys->totpart > 100); + settings.userdata_chunk = &sphdata; + settings.userdata_chunk_size = sizeof(sphdata); + BLI_task_parallel_range( + 0, psys->totpart, + &task_data, + dynamics_step_sph_classical_integrate_task_cb_ex, + &settings); + } } BLI_spin_end(&task_data.spin); diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c index 585a18cdad5..63f2c7e5452 100644 --- a/source/blender/blenkernel/intern/pbvh.c +++ b/source/blender/blenkernel/intern/pbvh.c @@ -939,7 +939,10 @@ typedef struct PBVHUpdateData { int flag; } PBVHUpdateData; -static void pbvh_update_normals_accum_task_cb(void *userdata, const int n) +static void pbvh_update_normals_accum_task_cb( + void *__restrict userdata, + const int n, + const ParallelRangeTLS *__restrict UNUSED(tls)) { PBVHUpdateData *data = userdata; @@ -992,7 +995,10 @@ static void pbvh_update_normals_accum_task_cb(void *userdata, const int n) } } -static void pbvh_update_normals_store_task_cb(void *userdata, const int n) +static void pbvh_update_normals_store_task_cb( + void *__restrict userdata, + const int n, + const ParallelRangeTLS *__restrict UNUSED(tls)) { PBVHUpdateData *data = userdata; PBVH *bvh = data->bvh; @@ -1051,14 +1057,21 @@ static void pbvh_update_normals(PBVH *bvh, PBVHNode **nodes, .fnors = fnors, .vnors = vnors, }; - BLI_task_parallel_range(0, totnode, &data, pbvh_update_normals_accum_task_cb, totnode > PBVH_THREADED_LIMIT); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = (totnode > PBVH_THREADED_LIMIT); - BLI_task_parallel_range(0, totnode, &data, pbvh_update_normals_store_task_cb, totnode > PBVH_THREADED_LIMIT); + BLI_task_parallel_range(0, totnode, &data, pbvh_update_normals_accum_task_cb, &settings); + + BLI_task_parallel_range(0, totnode, &data, pbvh_update_normals_store_task_cb, &settings); MEM_freeN(vnors); } -static void pbvh_update_BB_redraw_task_cb(void *userdata, const int n) +static void pbvh_update_BB_redraw_task_cb( + void *__restrict userdata, + const int n, + const ParallelRangeTLS *__restrict UNUSED(tls)) { PBVHUpdateData *data = userdata; PBVH *bvh = data->bvh; @@ -1085,7 +1098,18 @@ void pbvh_update_BB_redraw(PBVH *bvh, PBVHNode **nodes, int totnode, int flag) .flag = flag, }; - BLI_task_parallel_range(0, totnode, &data, pbvh_update_BB_redraw_task_cb, totnode > PBVH_THREADED_LIMIT); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = (totnode > PBVH_THREADED_LIMIT); + BLI_task_parallel_range(0, totnode, &data, pbvh_update_BB_redraw_task_cb, &settings); +} + +static int pbvh_get_buffers_update_flags(PBVH *bvh) +{ + int update_flags = 0; + update_flags |= bvh->show_diffuse_color ? GPU_PBVH_BUFFERS_SHOW_DIFFUSE_COLOR : 0; + update_flags |= bvh->show_mask ? GPU_PBVH_BUFFERS_SHOW_MASK : 0; + return update_flags; } static void pbvh_update_draw_buffers(PBVH *bvh, PBVHNode **nodes, int totnode) @@ -1123,6 +1147,7 @@ static void pbvh_update_draw_buffers(PBVH *bvh, PBVHNode **nodes, int totnode) } if (node->flag & PBVH_UpdateDrawBuffers) { + const int update_flags = pbvh_get_buffers_update_flags(bvh); switch (bvh->type) { case PBVH_GRIDS: GPU_pbvh_grid_buffers_update( @@ -1132,7 +1157,7 @@ static void pbvh_update_draw_buffers(PBVH *bvh, PBVHNode **nodes, int totnode) node->prim_indices, node->totprim, &bvh->gridkey, - bvh->show_diffuse_color); + update_flags); break; case PBVH_FACES: GPU_pbvh_mesh_buffers_update( @@ -1143,7 +1168,7 @@ static void pbvh_update_draw_buffers(PBVH *bvh, PBVHNode **nodes, int totnode) node->face_verts, CustomData_get_layer(bvh->vdata, CD_PAINT_MASK), node->face_vert_indices, - bvh->show_diffuse_color); + update_flags); break; case PBVH_BMESH: GPU_pbvh_bmesh_buffers_update( @@ -1152,7 +1177,7 @@ static void pbvh_update_draw_buffers(PBVH *bvh, PBVHNode **nodes, int totnode) node->bm_faces, node->bm_unique_verts, node->bm_other_verts, - bvh->show_diffuse_color); + update_flags); break; } @@ -2069,6 +2094,16 @@ static void pbvh_node_check_diffuse_changed(PBVH *bvh, PBVHNode *node) node->flag |= PBVH_UpdateDrawBuffers; } +static void pbvh_node_check_mask_changed(PBVH *bvh, PBVHNode *node) +{ + if (!node->draw_buffers) { + return; + } + if (GPU_pbvh_buffers_mask_changed(node->draw_buffers, bvh->show_mask)) { + node->flag |= PBVH_UpdateDrawBuffers; + } +} + void BKE_pbvh_draw(PBVH *bvh, float (*planes)[4], float (*fnors)[3], DMSetMaterial setMaterial, bool wireframe, bool fast) { @@ -2076,8 +2111,10 @@ void BKE_pbvh_draw(PBVH *bvh, float (*planes)[4], float (*fnors)[3], PBVHNode **nodes; int totnode; - for (int a = 0; a < bvh->totnode; a++) + for (int a = 0; a < bvh->totnode; a++) { pbvh_node_check_diffuse_changed(bvh, &bvh->nodes[a]); + pbvh_node_check_mask_changed(bvh, &bvh->nodes[a]); + } BKE_pbvh_search_gather(bvh, update_search_cb, SET_INT_IN_POINTER(PBVH_UpdateNormals | PBVH_UpdateDrawBuffers), &nodes, &totnode); @@ -2388,3 +2425,8 @@ void pbvh_show_diffuse_color_set(PBVH *bvh, bool show_diffuse_color) { bvh->show_diffuse_color = !pbvh_has_mask(bvh) || show_diffuse_color; } + +void pbvh_show_mask_set(PBVH *bvh, bool show_mask) +{ + bvh->show_mask = show_mask; +} diff --git a/source/blender/blenkernel/intern/pbvh_intern.h b/source/blender/blenkernel/intern/pbvh_intern.h index e05a3068682..afd539b2273 100644 --- a/source/blender/blenkernel/intern/pbvh_intern.h +++ b/source/blender/blenkernel/intern/pbvh_intern.h @@ -164,6 +164,7 @@ struct PBVH { bool deformed; bool show_diffuse_color; + bool show_mask; /* Dynamic topology */ BMesh *bm; diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index c095236733f..16e9844241d 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -540,7 +540,7 @@ void BKE_scene_free_ex(Scene *sce, const bool do_id_user) view_layer_next = view_layer->next; BLI_remlink(&sce->view_layers, view_layer); - BKE_view_layer_free(view_layer); + BKE_view_layer_free_ex(view_layer, do_id_user); } /* Master Collection */ @@ -756,7 +756,8 @@ void BKE_scene_init(Scene *sce) pset->draw_step = 2; pset->fade_frames = 2; pset->selectmode = SCE_SELECT_PATH; - for (a = 0; a < PE_TOT_BRUSH; a++) { + + for (a = 0; a < ARRAY_SIZE(pset->brush); a++) { pset->brush[a].strength = 0.5f; pset->brush[a].size = 50; pset->brush[a].step = 10; @@ -1171,6 +1172,10 @@ Scene *BKE_scene_find_from_collection(const Main *bmain, const SceneCollection * #ifdef DURIAN_CAMERA_SWITCH Object *BKE_scene_camera_switch_find(Scene *scene) { + if (scene->r.mode & R_NO_CAMERA_SWITCH) { + return NULL; + } + TimeMarker *m; int cfra = scene->r.cfra; int frame = -(MAXFRAME + 1); @@ -1391,8 +1396,8 @@ static void prepare_mesh_for_viewport_render(Main *bmain, Scene *scene) if (obedit) { Mesh *mesh = obedit->data; if ((obedit->type == OB_MESH) && - ((obedit->id.tag & LIB_TAG_ID_RECALC_ALL) || - (mesh->id.tag & LIB_TAG_ID_RECALC_ALL))) + ((obedit->id.recalc & ID_RECALC_ALL) || + (mesh->id.recalc & ID_RECALC_ALL))) { if (check_rendered_viewport_visible(bmain)) { BMesh *bm = mesh->edit_btmesh->bm; @@ -1435,7 +1440,7 @@ void BKE_scene_graph_update_tagged(EvaluationContext *eval_ctx, /* Update sound system animation (TODO, move to depsgraph). */ BKE_sound_update_scene(bmain, scene); /* Inform editors about possible changes. */ - DEG_ids_check_recalc(bmain, scene, view_layer, false); + DEG_ids_check_recalc(bmain, depsgraph, scene, view_layer, false); /* Clear recalc flags. */ DEG_ids_clear_recalc(bmain); } @@ -1482,7 +1487,7 @@ void BKE_scene_graph_update_for_newframe(EvaluationContext *eval_ctx, /* Notify editors and python about recalc. */ BLI_callback_exec(bmain, &scene->id, BLI_CB_EVT_FRAME_CHANGE_POST); /* Inform editors about possible changes. */ - DEG_ids_check_recalc(bmain, scene, view_layer, true); + DEG_ids_check_recalc(bmain, depsgraph, scene, view_layer, true); /* clear recalc flags */ DEG_ids_clear_recalc(bmain); } diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c index 50d397cc150..ef9c22f1661 100644 --- a/source/blender/blenkernel/intern/screen.c +++ b/source/blender/blenkernel/intern/screen.c @@ -429,6 +429,9 @@ void BKE_screen_free(bScreen *sc) BLI_freelistN(&sc->areabase); BKE_previewimg_free(&sc->preview); + + /* Region and timer are freed by the window manager. */ + MEM_SAFE_FREE(sc->tool_tip); } /* for depsgraph */ diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c index 2319d36ab16..424f4269f3c 100644 --- a/source/blender/blenkernel/intern/sequencer.c +++ b/source/blender/blenkernel/intern/sequencer.c @@ -3203,11 +3203,12 @@ static ImBuf *seq_render_scene_strip(const SeqRenderData *context, Sequence *seq int scemode; int cfra; float subframe; + #ifdef DURIAN_CAMERA_SWITCH - ListBase markers; + int mode; #endif } orig_data; - + /* Old info: * Hack! This function can be called from do_render_seq(), in that case * the seq->scene can already have a Render initialized with same name, @@ -3271,7 +3272,7 @@ static ImBuf *seq_render_scene_strip(const SeqRenderData *context, Sequence *seq orig_data.cfra = scene->r.cfra; orig_data.subframe = scene->r.subframe; #ifdef DURIAN_CAMERA_SWITCH - orig_data.markers = scene->markers; + orig_data.mode = scene->r.mode; #endif BKE_scene_frame_set(scene, frame); @@ -3294,10 +3295,10 @@ static ImBuf *seq_render_scene_strip(const SeqRenderData *context, Sequence *seq /* prevent eternal loop */ scene->r.scemode &= ~R_DOSEQ; - + #ifdef DURIAN_CAMERA_SWITCH /* stooping to new low's in hackyness :( */ - BLI_listbase_clear(&scene->markers); + scene->r.mode |= R_NO_CAMERA_SWITCH; #endif is_frame_update = (orig_data.cfra != scene->r.cfra) || (orig_data.subframe != scene->r.subframe); @@ -3426,7 +3427,7 @@ finally: #ifdef DURIAN_CAMERA_SWITCH /* stooping to new low's in hackyness :( */ - scene->markers = orig_data.markers; + scene->r.mode &= ~(orig_data.mode & R_NO_CAMERA_SWITCH); #endif return ibuf; @@ -4501,8 +4502,11 @@ Sequence *BKE_sequencer_foreground_frame_get(Scene *scene, int frame) for (seq = ed->seqbasep->first; seq; seq = seq->next) { if (seq->flag & SEQ_MUTE || seq->startdisp > frame || seq->enddisp <= frame) continue; - /* only use elements you can see - not */ - if (ELEM(seq->type, SEQ_TYPE_IMAGE, SEQ_TYPE_META, SEQ_TYPE_SCENE, SEQ_TYPE_MOVIE, SEQ_TYPE_COLOR)) { + /* Only use strips that generate an image, not ones that combine + * other strips or apply some effect. */ + if (ELEM(seq->type, SEQ_TYPE_IMAGE, SEQ_TYPE_META, SEQ_TYPE_SCENE, + SEQ_TYPE_MOVIE, SEQ_TYPE_COLOR, SEQ_TYPE_TEXT)) + { if (seq->machine > best_machine) { best_seq = seq; best_machine = seq->machine; diff --git a/source/blender/blenkernel/intern/shrinkwrap.c b/source/blender/blenkernel/intern/shrinkwrap.c index f9d1793d7cb..618f495dbf1 100644 --- a/source/blender/blenkernel/intern/shrinkwrap.c +++ b/source/blender/blenkernel/intern/shrinkwrap.c @@ -88,13 +88,15 @@ typedef struct ShrinkwrapCalcCBData { * for each vertex performs a nearest vertex search on the tree */ static void shrinkwrap_calc_nearest_vertex_cb_ex( - void *userdata, void *userdata_chunk, const int i, const int UNUSED(threadid)) + void *__restrict userdata, + const int i, + const ParallelRangeTLS *__restrict tls) { ShrinkwrapCalcCBData *data = userdata; ShrinkwrapCalcData *calc = data->calc; BVHTreeFromMesh *treeData = data->treeData; - BVHTreeNearest *nearest = userdata_chunk; + BVHTreeNearest *nearest = tls->userdata_chunk; float *co = calc->vertexCos[i]; float tmp_co[3]; @@ -167,9 +169,14 @@ static void shrinkwrap_calc_nearest_vertex(ShrinkwrapCalcData *calc) nearest.dist_sq = FLT_MAX; ShrinkwrapCalcCBData data = {.calc = calc, .treeData = &treeData}; - BLI_task_parallel_range_ex( - 0, calc->numVerts, &data, &nearest, sizeof(nearest), shrinkwrap_calc_nearest_vertex_cb_ex, - calc->numVerts > BKE_MESH_OMP_LIMIT, false); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = (calc->numVerts > BKE_MESH_OMP_LIMIT); + settings.userdata_chunk = &nearest; + settings.userdata_chunk_size = sizeof(nearest); + BLI_task_parallel_range(0, calc->numVerts, + &data, shrinkwrap_calc_nearest_vertex_cb_ex, + &settings); free_bvhtree_from_mesh(&treeData); } @@ -257,7 +264,9 @@ bool BKE_shrinkwrap_project_normal( } static void shrinkwrap_calc_normal_projection_cb_ex( - void *userdata, void *userdata_chunk, const int i, const int UNUSED(threadid)) + void *__restrict userdata, + const int i, + const ParallelRangeTLS *__restrict tls) { ShrinkwrapCalcCBData *data = userdata; @@ -272,7 +281,7 @@ static void shrinkwrap_calc_normal_projection_cb_ex( float *proj_axis = data->proj_axis; SpaceTransform *local2aux = data->local2aux; - BVHTreeRayHit *hit = userdata_chunk; + BVHTreeRayHit *hit = tls->userdata_chunk; const float proj_limit_squared = calc->smd->projLimit * calc->smd->projLimit; float *co = calc->vertexCos[i]; @@ -463,9 +472,15 @@ static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc, bool for .auxData = auxData, .aux_tree = aux_tree, .aux_callback = aux_callback, .proj_axis = proj_axis, .local2aux = &local2aux, }; - BLI_task_parallel_range_ex( - 0, calc->numVerts, &data, &hit, sizeof(hit), shrinkwrap_calc_normal_projection_cb_ex, - calc->numVerts > BKE_MESH_OMP_LIMIT, false); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = (calc->numVerts > BKE_MESH_OMP_LIMIT); + settings.userdata_chunk = &hit; + settings.userdata_chunk_size = sizeof(hit); + BLI_task_parallel_range(0, calc->numVerts, + &data, + shrinkwrap_calc_normal_projection_cb_ex, + &settings); } /* free data structures */ @@ -495,13 +510,15 @@ static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc, bool for * NN matches for each vertex */ static void shrinkwrap_calc_nearest_surface_point_cb_ex( - void *userdata, void *userdata_chunk, const int i, const int UNUSED(threadid)) + void *__restrict userdata, + const int i, + const ParallelRangeTLS *__restrict tls) { ShrinkwrapCalcCBData *data = userdata; ShrinkwrapCalcData *calc = data->calc; BVHTreeFromMesh *treeData = data->treeData; - BVHTreeNearest *nearest = userdata_chunk; + BVHTreeNearest *nearest = tls->userdata_chunk; float *co = calc->vertexCos[i]; float tmp_co[3]; @@ -583,9 +600,15 @@ static void shrinkwrap_calc_nearest_surface_point(ShrinkwrapCalcData *calc) /* Find the nearest vertex */ ShrinkwrapCalcCBData data = {.calc = calc, .treeData = &treeData}; - BLI_task_parallel_range_ex( - 0, calc->numVerts, &data, &nearest, sizeof(nearest), shrinkwrap_calc_nearest_surface_point_cb_ex, - calc->numVerts > BKE_MESH_OMP_LIMIT, false); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = (calc->numVerts > BKE_MESH_OMP_LIMIT); + settings.userdata_chunk = &nearest; + settings.userdata_chunk_size = sizeof(nearest); + BLI_task_parallel_range(0, calc->numVerts, + &data, + shrinkwrap_calc_nearest_surface_point_cb_ex, + &settings); free_bvhtree_from_mesh(&treeData); } diff --git a/source/blender/blenkernel/intern/smoke.c b/source/blender/blenkernel/intern/smoke.c index b5eed6c78de..9f9818127bc 100644 --- a/source/blender/blenkernel/intern/smoke.c +++ b/source/blender/blenkernel/intern/smoke.c @@ -740,7 +740,10 @@ typedef struct ObstaclesFromDMData { int *num_obstacles; } ObstaclesFromDMData; -static void obstacles_from_derivedmesh_task_cb(void *userdata, const int z) +static void obstacles_from_derivedmesh_task_cb( + void *__restrict userdata, + const int z, + const ParallelRangeTLS *__restrict UNUSED(tls)) { ObstaclesFromDMData *data = userdata; SmokeDomainSettings *sds = data->sds; @@ -870,8 +873,13 @@ static void obstacles_from_derivedmesh( .velocityX = velocityX, .velocityY = velocityY, .velocityZ = velocityZ, .num_obstacles = num_obstacles }; - BLI_task_parallel_range( - sds->res_min[2], sds->res_max[2], &data, obstacles_from_derivedmesh_task_cb, true); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC; + BLI_task_parallel_range(sds->res_min[2], sds->res_max[2], + &data, + obstacles_from_derivedmesh_task_cb, + &settings); } /* free bvh tree */ free_bvhtree_from_mesh(&treeData); @@ -1186,7 +1194,10 @@ typedef struct EmitFromParticlesData { float hr_smooth; } EmitFromParticlesData; -static void emit_from_particles_task_cb(void *userdata, const int z) +static void emit_from_particles_task_cb( + void *__restrict userdata, + const int z, + const ParallelRangeTLS *__restrict UNUSED(tls)) { EmitFromParticlesData *data = userdata; SmokeFlowSettings *sfs = data->sfs; @@ -1397,7 +1408,13 @@ static void emit_from_particles( .solid = solid, .smooth = smooth, .hr_smooth = hr_smooth, }; - BLI_task_parallel_range(min[2], max[2], &data, emit_from_particles_task_cb, true); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC; + BLI_task_parallel_range(min[2], max[2], + &data, + emit_from_particles_task_cb, + &settings); } if (sfs->flags & MOD_SMOKE_FLOW_USE_PART_SIZE) { @@ -1569,7 +1586,10 @@ typedef struct EmitFromDMData { int *min, *max, *res; } EmitFromDMData; -static void emit_from_derivedmesh_task_cb(void *userdata, const int z) +static void emit_from_derivedmesh_task_cb( + void *__restrict userdata, + const int z, + const ParallelRangeTLS *__restrict UNUSED(tls)) { EmitFromDMData *data = userdata; EmissionMap *em = data->em; @@ -1722,7 +1742,13 @@ static void emit_from_derivedmesh(Object *flow_ob, SmokeDomainSettings *sds, Smo .flow_center = flow_center, .min = min, .max = max, .res = res, }; - BLI_task_parallel_range(min[2], max[2], &data, emit_from_derivedmesh_task_cb, true); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC; + BLI_task_parallel_range(min[2], max[2], + &data, + emit_from_derivedmesh_task_cb, + &settings); } /* free bvh tree */ free_bvhtree_from_mesh(&treeData); @@ -2438,7 +2464,10 @@ typedef struct UpdateEffectorsData { unsigned char *obstacle; } UpdateEffectorsData; -static void update_effectors_task_cb(void *userdata, const int x) +static void update_effectors_task_cb( + void *__restrict userdata, + const int x, + const ParallelRangeTLS *__restrict UNUSED(tls)) { UpdateEffectorsData *data = userdata; SmokeDomainSettings *sds = data->sds; @@ -2512,7 +2541,13 @@ static void update_effectors(const struct EvaluationContext *eval_ctx, Scene *sc data.velocity_z = smoke_get_velocity_z(sds->fluid); data.obstacle = smoke_get_obstacle(sds->fluid); - BLI_task_parallel_range(0, sds->res[0], &data, update_effectors_task_cb, true); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC; + BLI_task_parallel_range(0, sds->res[0], + &data, + update_effectors_task_cb, + &settings); } pdEndEffectors(&effectors); diff --git a/source/blender/blenkernel/intern/softbody.c b/source/blender/blenkernel/intern/softbody.c index e3af77166a9..3cfa8787f4b 100644 --- a/source/blender/blenkernel/intern/softbody.c +++ b/source/blender/blenkernel/intern/softbody.c @@ -1991,7 +1991,8 @@ static int _softbody_calc_forces_slice_in_a_thread(Scene *scene, Object *ob, flo float compare; float bstune = sb->ballstiff; - for (c=sb->totpoint, obp= sb->bpoint; c>=ifirst+bb; c--, obp++) { + /* running in a slice we must not assume anything done with obp neither alter the data of obp */ + for (c=sb->totpoint, obp= sb->bpoint; c>0; c--, obp++) { compare = (obp->colball + bp->colball); sub_v3_v3v3(def, bp->pos, obp->pos); /* rather check the AABBoxes before ever calulating the real distance */ @@ -2016,13 +2017,6 @@ static int _softbody_calc_forces_slice_in_a_thread(Scene *scene, Object *ob, flo madd_v3_v3fl(bp->force, def, f * (1.0f - sb->balldamp)); madd_v3_v3fl(bp->force, dvel, sb->balldamp); - - /* exploit force(a, b) == -force(b, a) part2/2 */ - sub_v3_v3v3(dvel, velcenter, obp->vec); - mul_v3_fl(dvel, _final_mass(ob, bp)); - - madd_v3_v3fl(obp->force, dvel, sb->balldamp); - madd_v3_v3fl(obp->force, def, -f * (1.0f - sb->balldamp)); } } } diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c index 2f9a7090caf..1c3ff352126 100644 --- a/source/blender/blenkernel/intern/subsurf_ccg.c +++ b/source/blender/blenkernel/intern/subsurf_ccg.c @@ -58,6 +58,7 @@ #include "BLI_edgehash.h" #include "BLI_math.h" #include "BLI_memarena.h" +#include "BLI_task.h" #include "BLI_threads.h" #include "BKE_pbvh.h" @@ -66,6 +67,7 @@ #include "BKE_global.h" #include "BKE_mesh.h" #include "BKE_mesh_mapping.h" +#include "BKE_modifier.h" #include "BKE_multires.h" #include "BKE_paint.h" #include "BKE_scene.h" @@ -90,9 +92,6 @@ /* assumes MLoop's are layed out 4 for each poly, in order */ #define USE_LOOP_LAYOUT_FAST -static ThreadRWMutex loops_cache_rwlock = BLI_RWLOCK_INITIALIZER; -static ThreadRWMutex origindex_cache_rwlock = BLI_RWLOCK_INITIALIZER; - static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss, int drawInteriorEdges, int useSubsurfUv, @@ -1479,77 +1478,107 @@ static void ccgDM_copyFinalFaceArray(DerivedMesh *dm, MFace *mface) } } +typedef struct CopyFinalLoopArrayData { + CCGDerivedMesh *ccgdm; + MLoop *mloop; + int grid_size; + int *grid_offset; + int edge_size; + size_t mloop_index; +} CopyFinalLoopArrayData; + +static void copyFinalLoopArray_task_cb( + void *__restrict userdata, + const int iter, + const ParallelRangeTLS *__restrict UNUSED(tls)) +{ + CopyFinalLoopArrayData *data = userdata; + CCGDerivedMesh *ccgdm = data->ccgdm; + CCGSubSurf *ss = ccgdm->ss; + const int grid_size = data->grid_size; + const int edge_size = data->edge_size; + CCGFace *f = ccgdm->faceMap[iter].face; + const int num_verts = ccgSubSurf_getFaceNumVerts(f); + const int grid_index = data->grid_offset[iter]; + const size_t loop_index = 4 * (size_t)grid_index * (grid_size - 1) * (grid_size - 1); + MLoop *ml = &data->mloop[loop_index]; + for (int S = 0; S < num_verts; S++) { + for (int y = 0; y < grid_size - 1; y++) { + for (int x = 0; x < grid_size - 1; x++) { + + uint v1 = getFaceIndex(ss, f, S, x + 0, y + 0, + edge_size, grid_size); + uint v2 = getFaceIndex(ss, f, S, x + 0, y + 1, + edge_size, grid_size); + uint v3 = getFaceIndex(ss, f, S, x + 1, y + 1, + edge_size, grid_size); + uint v4 = getFaceIndex(ss, f, S, x + 1, y + 0, + edge_size, grid_size); + + ml->v = v1; + ml->e = GET_UINT_FROM_POINTER(BLI_edgehash_lookup(ccgdm->ehash, v1, v2)); + ml++; + + ml->v = v2; + ml->e = GET_UINT_FROM_POINTER(BLI_edgehash_lookup(ccgdm->ehash, v2, v3)); + ml++; + + ml->v = v3; + ml->e = GET_UINT_FROM_POINTER(BLI_edgehash_lookup(ccgdm->ehash, v3, v4)); + ml++; + + ml->v = v4; + ml->e = GET_UINT_FROM_POINTER(BLI_edgehash_lookup(ccgdm->ehash, v4, v1)); + ml++; + } + } + } +} + static void ccgDM_copyFinalLoopArray(DerivedMesh *dm, MLoop *mloop) { CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm; CCGSubSurf *ss = ccgdm->ss; - int index; - int totface; - int gridSize = ccgSubSurf_getGridSize(ss); - int edgeSize = ccgSubSurf_getEdgeSize(ss); - int i = 0; - MLoop *mv; - /* DMFlagMat *faceFlags = ccgdm->faceFlags; */ /* UNUSED */ if (!ccgdm->ehash) { - BLI_rw_mutex_lock(&loops_cache_rwlock, THREAD_LOCK_WRITE); + BLI_mutex_lock(&ccgdm->loops_cache_lock); if (!ccgdm->ehash) { MEdge *medge; + EdgeHash *ehash; - ccgdm->ehash = BLI_edgehash_new_ex(__func__, ccgdm->dm.numEdgeData); + ehash = BLI_edgehash_new_ex(__func__, ccgdm->dm.numEdgeData); medge = ccgdm->dm.getEdgeArray((DerivedMesh *)ccgdm); - for (i = 0; i < ccgdm->dm.numEdgeData; i++) { - BLI_edgehash_insert(ccgdm->ehash, medge[i].v1, medge[i].v2, SET_INT_IN_POINTER(i)); + for (int i = 0; i < ccgdm->dm.numEdgeData; i++) { + BLI_edgehash_insert(ehash, medge[i].v1, medge[i].v2, SET_INT_IN_POINTER(i)); } + + atomic_cas_ptr((void **)&ccgdm->ehash, ccgdm->ehash, ehash); } - BLI_rw_mutex_unlock(&loops_cache_rwlock); + BLI_mutex_unlock(&ccgdm->loops_cache_lock); } - BLI_rw_mutex_lock(&loops_cache_rwlock, THREAD_LOCK_READ); - totface = ccgSubSurf_getNumFaces(ss); - mv = mloop; - for (index = 0; index < totface; index++) { - CCGFace *f = ccgdm->faceMap[index].face; - int x, y, S, numVerts = ccgSubSurf_getFaceNumVerts(f); - /* int flag = (faceFlags) ? faceFlags[index * 2]: ME_SMOOTH; */ /* UNUSED */ - /* int mat_nr = (faceFlags) ? faceFlags[index * 2 + 1]: 0; */ /* UNUSED */ - - for (S = 0; S < numVerts; S++) { - for (y = 0; y < gridSize - 1; y++) { - for (x = 0; x < gridSize - 1; x++) { - unsigned int v1, v2, v3, v4; + CopyFinalLoopArrayData data; + data.ccgdm = ccgdm; + data.mloop = mloop; + data.grid_size = ccgSubSurf_getGridSize(ss); + data.grid_offset = dm->getGridOffset(dm); + data.edge_size = ccgSubSurf_getEdgeSize(ss); - v1 = getFaceIndex(ss, f, S, x + 0, y + 0, - edgeSize, gridSize); - - v2 = getFaceIndex(ss, f, S, x + 0, y + 1, - edgeSize, gridSize); - v3 = getFaceIndex(ss, f, S, x + 1, y + 1, - edgeSize, gridSize); - v4 = getFaceIndex(ss, f, S, x + 1, y + 0, - edgeSize, gridSize); - - mv->v = v1; - mv->e = GET_UINT_FROM_POINTER(BLI_edgehash_lookup(ccgdm->ehash, v1, v2)); - mv++; i++; - - mv->v = v2; - mv->e = GET_UINT_FROM_POINTER(BLI_edgehash_lookup(ccgdm->ehash, v2, v3)); - mv++; i++; + /* NOTE: For a dense subdivision we've got enough work for each face and + * hence can dedicate whole thread to single face. For less dense + * subdivision we handle multiple faces per thread. + */ + data.mloop_index = data.grid_size >= 5 ? 1 : 8; - mv->v = v3; - mv->e = GET_UINT_FROM_POINTER(BLI_edgehash_lookup(ccgdm->ehash, v3, v4)); - mv++; i++; + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.min_iter_per_thread = 1; - mv->v = v4; - mv->e = GET_UINT_FROM_POINTER(BLI_edgehash_lookup(ccgdm->ehash, v4, v1)); - mv++; i++; - } - } - } - } - BLI_rw_mutex_unlock(&loops_cache_rwlock); + BLI_task_parallel_range(0, ccgSubSurf_getNumFaces(ss), + &data, + copyFinalLoopArray_task_cb, + &settings); } static void ccgDM_copyFinalPolyArray(DerivedMesh *dm, MPoly *mpoly) @@ -3796,6 +3825,10 @@ static void ccgDM_release(DerivedMesh *dm) MEM_freeN(ccgdm->edgeMap); MEM_freeN(ccgdm->faceMap); } + + BLI_mutex_end(&ccgdm->loops_cache_lock); + BLI_rw_mutex_end(&ccgdm->origindex_cache_rwlock); + MEM_freeN(ccgdm); } } @@ -3810,14 +3843,14 @@ static void *ccgDM_get_vert_data_layer(DerivedMesh *dm, int type) int a, index, totnone, totorig; /* Avoid re-creation if the layer exists already */ - BLI_rw_mutex_lock(&origindex_cache_rwlock, THREAD_LOCK_READ); + BLI_rw_mutex_lock(&ccgdm->origindex_cache_rwlock, THREAD_LOCK_READ); origindex = DM_get_vert_data_layer(dm, CD_ORIGINDEX); - BLI_rw_mutex_unlock(&origindex_cache_rwlock); + BLI_rw_mutex_unlock(&ccgdm->origindex_cache_rwlock); if (origindex) { return origindex; } - BLI_rw_mutex_lock(&origindex_cache_rwlock, THREAD_LOCK_WRITE); + BLI_rw_mutex_lock(&ccgdm->origindex_cache_rwlock, THREAD_LOCK_WRITE); DM_add_vert_layer(dm, CD_ORIGINDEX, CD_CALLOC, NULL); origindex = DM_get_vert_data_layer(dm, CD_ORIGINDEX); @@ -3832,7 +3865,7 @@ static void *ccgDM_get_vert_data_layer(DerivedMesh *dm, int type) CCGVert *v = ccgdm->vertMap[index].vert; origindex[a] = ccgDM_getVertMapIndex(ccgdm->ss, v); } - BLI_rw_mutex_unlock(&origindex_cache_rwlock); + BLI_rw_mutex_unlock(&ccgdm->origindex_cache_rwlock); return origindex; } @@ -4158,7 +4191,7 @@ static struct PBVH *ccgDM_getPBVH(Object *ob, DerivedMesh *dm) { CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm; CCGKey key; - int numGrids, grid_pbvh; + int numGrids; CCG_key_top_level(&key, ccgdm->ss); @@ -4170,35 +4203,85 @@ static struct PBVH *ccgDM_getPBVH(Object *ob, DerivedMesh *dm) if (!ob->sculpt) return NULL; - /* In vwpaint, we always use a grid_pbvh for multires/subsurf */ - grid_pbvh = (!(ob->mode & OB_MODE_SCULPT) || ccgDM_use_grid_pbvh(ccgdm)); + bool grid_pbvh = ccgDM_use_grid_pbvh(ccgdm); + if ((ob->mode & OB_MODE_SCULPT) == 0) { + /* In vwpaint, we may use a grid_pbvh for multires/subsurf, under certain conditions. + * More complex cases break 'history' trail back to original vertices, in that case we fall back to + * deformed cage only (i.e. original deformed mesh). */ + VirtualModifierData virtualModifierData; + ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData); + + grid_pbvh = true; + bool has_one_ccg_modifier = false; + for (; md; md = md->next) { + /* We can only accept to use this ccgdm if: + * - it's the only active ccgdm in the stack. + * - there is no topology-modifying modifier in the stack. + * Otherwise, there is no way to map back to original geometry from grid-generated PBVH. + */ + const ModifierTypeInfo *mti = modifierType_getInfo(md->type); + + if (!modifier_isEnabled(NULL, md, eModifierMode_Realtime)) { + continue; + } + if (ELEM(mti->type, eModifierTypeType_OnlyDeform, eModifierTypeType_NonGeometrical)) { + continue; + } + + if (ELEM(md->type, eModifierType_Subsurf, eModifierType_Multires)) { + if (has_one_ccg_modifier) { + /* We only allow a single active ccg modifier in the stack. */ + grid_pbvh = false; + break; + } + has_one_ccg_modifier = true; + continue; + } + + /* Any other non-deforming modifier makes it impossible to use grid pbvh. */ + grid_pbvh = false; + break; + } + } if (ob->sculpt->pbvh) { + /* Note that we have to clean up exisitng pbvh instead of updating it in case it does not match current + * grid_pbvh status. */ if (grid_pbvh) { - /* pbvh's grids, gridadj and gridfaces points to data inside ccgdm - * but this can be freed on ccgdm release, this updates the pointers - * when the ccgdm gets remade, the assumption is that the topology - * does not change. */ - ccgdm_create_grids(dm); - BKE_pbvh_grids_update(ob->sculpt->pbvh, ccgdm->gridData, (void **)ccgdm->gridFaces, - ccgdm->gridFlagMats, ccgdm->gridHidden); + if (BKE_pbvh_get_ccgdm(ob->sculpt->pbvh) != NULL) { + /* pbvh's grids, gridadj and gridfaces points to data inside ccgdm + * but this can be freed on ccgdm release, this updates the pointers + * when the ccgdm gets remade, the assumption is that the topology + * does not change. */ + ccgdm_create_grids(dm); + BKE_pbvh_grids_update(ob->sculpt->pbvh, ccgdm->gridData, (void **)ccgdm->gridFaces, + ccgdm->gridFlagMats, ccgdm->gridHidden); + } + else { + BKE_pbvh_free(ob->sculpt->pbvh); + ob->sculpt->pbvh = NULL; + } + } + else if (BKE_pbvh_get_ccgdm(ob->sculpt->pbvh) != NULL) { + BKE_pbvh_free(ob->sculpt->pbvh); + ob->sculpt->pbvh = NULL; } ccgdm->pbvh = ob->sculpt->pbvh; } if (ccgdm->pbvh) { - /* For vertex paint, keep track of ccgdm */ - if (!(ob->mode & OB_MODE_SCULPT)) { + /* For grid pbvh, keep track of ccgdm */ + if (grid_pbvh) { BKE_pbvh_set_ccgdm(ccgdm->pbvh, ccgdm); } return ccgdm->pbvh; } - /* no pbvh exists yet, we need to create one. only in case of multires + /* No pbvh exists yet, we need to create one. only in case of multires * we build a pbvh over the modified mesh, in other cases the base mesh * is being sculpted, so we build a pbvh from that. */ - /* Note: vwpaint always builds a pbvh over the modified mesh. */ + /* Note: vwpaint tries to always build a pbvh over the modified mesh. */ if (grid_pbvh) { ccgdm_create_grids(dm); @@ -4224,13 +4307,27 @@ static struct PBVH *ccgDM_getPBVH(Object *ob, DerivedMesh *dm) ob->sculpt->pbvh = ccgdm->pbvh = BKE_pbvh_new(); BKE_pbvh_build_mesh(ccgdm->pbvh, me->mpoly, me->mloop, me->mvert, me->totvert, &me->vdata, looptri, looptris_num); + + if (ob->sculpt->modifiers_active && ob->derivedDeform != NULL) { + DerivedMesh *deformdm = ob->derivedDeform; + float (*vertCos)[3]; + int totvert; + + totvert = deformdm->getNumVerts(deformdm); + vertCos = MEM_malloc_arrayN(totvert, sizeof(float[3]), "ccgDM_getPBVH vertCos"); + deformdm->getVertCos(deformdm, vertCos); + BKE_pbvh_apply_vertCos(ccgdm->pbvh, vertCos); + MEM_freeN(vertCos); + } } - if (ccgdm->pbvh) + if (ccgdm->pbvh != NULL) { pbvh_show_diffuse_color_set(ccgdm->pbvh, ob->sculpt->show_diffuse_color); + pbvh_show_mask_set(ccgdm->pbvh, ob->sculpt->show_mask); + } - /* For vertex paint, keep track of ccgdm */ - if (!(ob->mode & OB_MODE_SCULPT) && ccgdm->pbvh) { + /* For grid pbvh, keep track of ccgdm. */ + if (grid_pbvh && ccgdm->pbvh) { BKE_pbvh_set_ccgdm(ccgdm->pbvh, ccgdm); } return ccgdm->pbvh; @@ -4784,6 +4881,9 @@ static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss, ccgdm->dm.numLoopData = ccgdm->dm.numPolyData * 4; ccgdm->dm.numTessFaceData = 0; + BLI_mutex_init(&ccgdm->loops_cache_lock); + BLI_rw_mutex_init(&ccgdm->origindex_cache_rwlock); + return ccgdm; } diff --git a/source/blender/blenkernel/intern/texture.c b/source/blender/blenkernel/intern/texture.c index 122b605f160..fcedd880615 100644 --- a/source/blender/blenkernel/intern/texture.c +++ b/source/blender/blenkernel/intern/texture.c @@ -58,6 +58,7 @@ #include "BKE_global.h" #include "BKE_main.h" +#include "BKE_colorband.h" #include "BKE_library.h" #include "BKE_library_query.h" #include "BKE_library_remap.h" @@ -185,7 +186,7 @@ void BKE_texture_colormapping_default(ColorMapping *colormap) { memset(colormap, 0, sizeof(ColorMapping)); - init_colorband(&colormap->coba, true); + BKE_colorband_init(&colormap->coba, true); colormap->bright = 1.0; colormap->contrast = 1.0; @@ -198,365 +199,6 @@ void BKE_texture_colormapping_default(ColorMapping *colormap) colormap->blend_factor = 0.0f; } -/* ****************** COLORBAND ******************* */ - -void init_colorband(ColorBand *coba, bool rangetype) -{ - int a; - - coba->data[0].pos = 0.0; - coba->data[1].pos = 1.0; - - if (rangetype == 0) { - coba->data[0].r = 0.0; - coba->data[0].g = 0.0; - coba->data[0].b = 0.0; - coba->data[0].a = 0.0; - - coba->data[1].r = 1.0; - coba->data[1].g = 1.0; - coba->data[1].b = 1.0; - coba->data[1].a = 1.0; - } - else { - coba->data[0].r = 0.0; - coba->data[0].g = 0.0; - coba->data[0].b = 0.0; - coba->data[0].a = 1.0; - - coba->data[1].r = 1.0; - coba->data[1].g = 1.0; - coba->data[1].b = 1.0; - coba->data[1].a = 1.0; - } - - for (a = 2; a < MAXCOLORBAND; a++) { - coba->data[a].r = 0.5; - coba->data[a].g = 0.5; - coba->data[a].b = 0.5; - coba->data[a].a = 1.0; - coba->data[a].pos = 0.5; - } - - coba->tot = 2; - coba->color_mode = COLBAND_BLEND_RGB; -} - -ColorBand *add_colorband(bool rangetype) -{ - ColorBand *coba; - - coba = MEM_callocN(sizeof(ColorBand), "colorband"); - init_colorband(coba, rangetype); - - return coba; -} - -/* ------------------------------------------------------------------------- */ - -static float colorband_hue_interp( - const int ipotype_hue, - const float mfac, const float fac, - float h1, float h2) -{ - float h_interp; - int mode = 0; - -#define HUE_INTERP(h_a, h_b) ((mfac * (h_a)) + (fac * (h_b))) -#define HUE_MOD(h) (((h) < 1.0f) ? (h) : (h) - 1.0f) - - h1 = HUE_MOD(h1); - h2 = HUE_MOD(h2); - - BLI_assert(h1 >= 0.0f && h1 < 1.0f); - BLI_assert(h2 >= 0.0f && h2 < 1.0f); - - switch (ipotype_hue) { - case COLBAND_HUE_NEAR: - { - if ((h1 < h2) && (h2 - h1) > +0.5f) mode = 1; - else if ((h1 > h2) && (h2 - h1) < -0.5f) mode = 2; - else mode = 0; - break; - } - case COLBAND_HUE_FAR: - { - if ((h1 < h2) && (h2 - h1) < +0.5f) mode = 1; - else if ((h1 > h2) && (h2 - h1) > -0.5f) mode = 2; - else mode = 0; - break; - } - case COLBAND_HUE_CCW: - { - if (h1 > h2) mode = 2; - else mode = 0; - break; - } - case COLBAND_HUE_CW: - { - if (h1 < h2) mode = 1; - else mode = 0; - break; - } - } - - switch (mode) { - case 0: - h_interp = HUE_INTERP(h1, h2); - break; - case 1: - h_interp = HUE_INTERP(h1 + 1.0f, h2); - h_interp = HUE_MOD(h_interp); - break; - case 2: - h_interp = HUE_INTERP(h1, h2 + 1.0f); - h_interp = HUE_MOD(h_interp); - break; - } - - BLI_assert(h_interp >= 0.0f && h_interp < 1.0f); - -#undef HUE_INTERP -#undef HUE_MOD - - return h_interp; -} - -bool do_colorband(const ColorBand *coba, float in, float out[4]) -{ - const CBData *cbd1, *cbd2, *cbd0, *cbd3; - float fac; - int ipotype; - int a; - - if (coba == NULL || coba->tot == 0) return false; - - cbd1 = coba->data; - - ipotype = (coba->color_mode == COLBAND_BLEND_RGB) ? coba->ipotype : COLBAND_INTERP_LINEAR; - - if (coba->tot == 1) { - out[0] = cbd1->r; - out[1] = cbd1->g; - out[2] = cbd1->b; - out[3] = cbd1->a; - } - else if ((in <= cbd1->pos) && ELEM(ipotype, COLBAND_INTERP_LINEAR, COLBAND_INTERP_EASE)) { - out[0] = cbd1->r; - out[1] = cbd1->g; - out[2] = cbd1->b; - out[3] = cbd1->a; - } - else { - CBData left, right; - - /* we're looking for first pos > in */ - for (a = 0; a < coba->tot; a++, cbd1++) { - if (cbd1->pos > in) { - break; - } - } - - if (a == coba->tot) { - cbd2 = cbd1 - 1; - right = *cbd2; - right.pos = 1.0f; - cbd1 = &right; - } - else if (a == 0) { - left = *cbd1; - left.pos = 0.0f; - cbd2 = &left; - } - else { - cbd2 = cbd1 - 1; - } - - if ((in >= cbd1->pos) && ELEM(ipotype, COLBAND_INTERP_LINEAR, COLBAND_INTERP_EASE)) { - out[0] = cbd1->r; - out[1] = cbd1->g; - out[2] = cbd1->b; - out[3] = cbd1->a; - } - else { - - if (cbd2->pos != cbd1->pos) { - fac = (in - cbd1->pos) / (cbd2->pos - cbd1->pos); - } - else { - /* was setting to 0.0 in 2.56 & previous, but this - * is incorrect for the last element, see [#26732] */ - fac = (a != coba->tot) ? 0.0f : 1.0f; - } - - if (ipotype == COLBAND_INTERP_CONSTANT) { - /* constant */ - out[0] = cbd2->r; - out[1] = cbd2->g; - out[2] = cbd2->b; - out[3] = cbd2->a; - } - else if (ipotype >= COLBAND_INTERP_B_SPLINE) { - /* ipo from right to left: 3 2 1 0 */ - float t[4]; - - if (a >= coba->tot - 1) cbd0 = cbd1; - else cbd0 = cbd1 + 1; - if (a < 2) cbd3 = cbd2; - else cbd3 = cbd2 - 1; - - CLAMP(fac, 0.0f, 1.0f); - - if (ipotype == COLBAND_INTERP_CARDINAL) { - key_curve_position_weights(fac, t, KEY_CARDINAL); - } - else { - key_curve_position_weights(fac, t, KEY_BSPLINE); - } - - out[0] = t[3] * cbd3->r + t[2] * cbd2->r + t[1] * cbd1->r + t[0] * cbd0->r; - out[1] = t[3] * cbd3->g + t[2] * cbd2->g + t[1] * cbd1->g + t[0] * cbd0->g; - out[2] = t[3] * cbd3->b + t[2] * cbd2->b + t[1] * cbd1->b + t[0] * cbd0->b; - out[3] = t[3] * cbd3->a + t[2] * cbd2->a + t[1] * cbd1->a + t[0] * cbd0->a; - CLAMP(out[0], 0.0f, 1.0f); - CLAMP(out[1], 0.0f, 1.0f); - CLAMP(out[2], 0.0f, 1.0f); - CLAMP(out[3], 0.0f, 1.0f); - } - else { - float mfac; - - if (ipotype == COLBAND_INTERP_EASE) { - mfac = fac * fac; - fac = 3.0f * mfac - 2.0f * mfac * fac; - } - - mfac = 1.0f - fac; - - if (UNLIKELY(coba->color_mode == COLBAND_BLEND_HSV)) { - float col1[3], col2[3]; - - rgb_to_hsv_v(&cbd1->r, col1); - rgb_to_hsv_v(&cbd2->r, col2); - - out[0] = colorband_hue_interp(coba->ipotype_hue, mfac, fac, col1[0], col2[0]); - out[1] = mfac * col1[1] + fac * col2[1]; - out[2] = mfac * col1[2] + fac * col2[2]; - out[3] = mfac * cbd1->a + fac * cbd2->a; - - hsv_to_rgb_v(out, out); - } - else if (UNLIKELY(coba->color_mode == COLBAND_BLEND_HSL)) { - float col1[3], col2[3]; - - rgb_to_hsl_v(&cbd1->r, col1); - rgb_to_hsl_v(&cbd2->r, col2); - - out[0] = colorband_hue_interp(coba->ipotype_hue, mfac, fac, col1[0], col2[0]); - out[1] = mfac * col1[1] + fac * col2[1]; - out[2] = mfac * col1[2] + fac * col2[2]; - out[3] = mfac * cbd1->a + fac * cbd2->a; - - hsl_to_rgb_v(out, out); - } - else { - /* COLBAND_BLEND_RGB */ - out[0] = mfac * cbd1->r + fac * cbd2->r; - out[1] = mfac * cbd1->g + fac * cbd2->g; - out[2] = mfac * cbd1->b + fac * cbd2->b; - out[3] = mfac * cbd1->a + fac * cbd2->a; - } - } - } - } - return true; /* OK */ -} - -void colorband_table_RGBA(ColorBand *coba, float **array, int *size) -{ - int a; - - *size = CM_TABLE + 1; - *array = MEM_callocN(sizeof(float) * (*size) * 4, "ColorBand"); - - for (a = 0; a < *size; a++) - do_colorband(coba, (float)a / (float)CM_TABLE, &(*array)[a * 4]); -} - -static int vergcband(const void *a1, const void *a2) -{ - const CBData *x1 = a1, *x2 = a2; - - if (x1->pos > x2->pos) return 1; - else if (x1->pos < x2->pos) return -1; - return 0; -} - -void colorband_update_sort(ColorBand *coba) -{ - int a; - - if (coba->tot < 2) - return; - - for (a = 0; a < coba->tot; a++) - coba->data[a].cur = a; - - qsort(coba->data, coba->tot, sizeof(CBData), vergcband); - - for (a = 0; a < coba->tot; a++) { - if (coba->data[a].cur == coba->cur) { - coba->cur = a; - break; - } - } -} - -CBData *colorband_element_add(struct ColorBand *coba, float position) -{ - if (coba->tot == MAXCOLORBAND) { - return NULL; - } - else { - CBData *xnew; - - xnew = &coba->data[coba->tot]; - xnew->pos = position; - - if (coba->tot != 0) { - do_colorband(coba, position, &xnew->r); - } - else { - zero_v4(&xnew->r); - } - } - - coba->tot++; - coba->cur = coba->tot - 1; - - colorband_update_sort(coba); - - return coba->data + coba->cur; -} - -int colorband_element_remove(struct ColorBand *coba, int index) -{ - int a; - - if (coba->tot < 2) - return 0; - - if (index < 0 || index >= coba->tot) - return 0; - - coba->tot--; - for (a = index; a < coba->tot; a++) { - coba->data[a] = coba->data[a + 1]; - } - if (coba->cur) coba->cur--; - return 1; -} - /* ******************* TEX ************************ */ /** Free (or release) any data used by this texture (does not free the texure itself). */ @@ -1357,7 +999,7 @@ void BKE_texture_pointdensity_init_data(PointDensity *pd) pd->noise_depth = 1; pd->noise_fac = 1.0f; pd->noise_influence = TEX_PD_NOISE_STATIC; - pd->coba = add_colorband(true); + pd->coba = BKE_colorband_add(true); pd->speed_scale = 1.0f; pd->totpoints = 0; pd->object = NULL; diff --git a/source/blender/blenkernel/intern/tracking.c b/source/blender/blenkernel/intern/tracking.c index 07e071df04a..ebd4c04e8ce 100644 --- a/source/blender/blenkernel/intern/tracking.c +++ b/source/blender/blenkernel/intern/tracking.c @@ -2905,3 +2905,155 @@ void BKE_tracking_dopesheet_update(MovieTracking *tracking) dopesheet->ok = true; } + +/* NOTE: Returns NULL if the track comes from camera object, */ +MovieTrackingObject *BKE_tracking_find_object_for_track( + const MovieTracking *tracking, + const MovieTrackingTrack *track) +{ + const ListBase *tracksbase = &tracking->tracks; + if (BLI_findindex(tracksbase, track) != -1) { + return NULL; + } + MovieTrackingObject *object = tracking->objects.first; + while (object != NULL) { + if (BLI_findindex(&object->tracks, track) != -1) { + return object; + } + object = object->next; + } + return NULL; +} + +ListBase *BKE_tracking_find_tracks_list_for_track( + MovieTracking *tracking, + const MovieTrackingTrack *track) +{ + MovieTrackingObject *object = BKE_tracking_find_object_for_track(tracking, + track); + if (object != NULL) { + return &object->tracks; + } + return &tracking->tracks; +} + +/* NOTE: Returns NULL if the track comes from camera object, */ +MovieTrackingObject *BKE_tracking_find_object_for_plane_track( + const MovieTracking *tracking, + const MovieTrackingPlaneTrack *plane_track) +{ + const ListBase *plane_tracks_base = &tracking->plane_tracks; + if (BLI_findindex(plane_tracks_base, plane_track) != -1) { + return NULL; + } + MovieTrackingObject *object = tracking->objects.first; + while (object != NULL) { + if (BLI_findindex(&object->plane_tracks, plane_track) != -1) { + return object; + } + object = object->next; + } + return NULL; +} + +ListBase *BKE_tracking_find_tracks_list_for_plane_track( + MovieTracking *tracking, + const MovieTrackingPlaneTrack *plane_track) +{ + MovieTrackingObject *object = + BKE_tracking_find_object_for_plane_track(tracking, plane_track); + if (object != NULL) { + return &object->plane_tracks; + } + return &tracking->plane_tracks; +} + +void BKE_tracking_get_rna_path_for_track( + const struct MovieTracking *tracking, + const struct MovieTrackingTrack *track, + char *rna_path, + size_t rna_path_len) +{ + MovieTrackingObject *object = + BKE_tracking_find_object_for_track(tracking, track); + char track_name_esc[MAX_NAME * 2]; + BLI_strescape(track_name_esc, track->name, sizeof(track_name_esc)); + if (object == NULL) { + BLI_snprintf(rna_path, rna_path_len, + "tracking.tracks[\"%s\"]", + track_name_esc); + } + else { + char object_name_esc[MAX_NAME * 2]; + BLI_strescape(object_name_esc, object->name, sizeof(object_name_esc)); + BLI_snprintf(rna_path, rna_path_len, + "tracking.objects[\"%s\"].tracks[\"%s\"]", + object_name_esc, + track_name_esc); + } +} + +void BKE_tracking_get_rna_path_prefix_for_track( + const struct MovieTracking *tracking, + const struct MovieTrackingTrack *track, + char *rna_path, + size_t rna_path_len) +{ + MovieTrackingObject *object = + BKE_tracking_find_object_for_track(tracking, track); + if (object == NULL) { + BLI_snprintf(rna_path, rna_path_len, "tracking.tracks"); + } + else { + char object_name_esc[MAX_NAME * 2]; + BLI_strescape(object_name_esc, object->name, sizeof(object_name_esc)); + BLI_snprintf(rna_path, rna_path_len, + "tracking.objects[\"%s\"]", + object_name_esc); + } +} + +void BKE_tracking_get_rna_path_for_plane_track( + const struct MovieTracking *tracking, + const struct MovieTrackingPlaneTrack *plane_track, + char *rna_path, + size_t rna_path_len) +{ + MovieTrackingObject *object = + BKE_tracking_find_object_for_plane_track(tracking, plane_track); + char track_name_esc[MAX_NAME * 2]; + BLI_strescape(track_name_esc, plane_track->name, sizeof(track_name_esc)); + if (object == NULL) { + BLI_snprintf(rna_path, rna_path_len, + "tracking.plane_tracks[\"%s\"]", + track_name_esc); + } + else { + char object_name_esc[MAX_NAME * 2]; + BLI_strescape(object_name_esc, object->name, sizeof(object_name_esc)); + BLI_snprintf(rna_path, rna_path_len, + "tracking.objects[\"%s\"].plane_tracks[\"%s\"]", + object_name_esc, + track_name_esc); + } +} + +void BKE_tracking_get_rna_path_prefix_for_plane_track( + const struct MovieTracking *tracking, + const struct MovieTrackingPlaneTrack *plane_track, + char *rna_path, + size_t rna_path_len) +{ + MovieTrackingObject *object = + BKE_tracking_find_object_for_plane_track(tracking, plane_track); + if (object == NULL) { + BLI_snprintf(rna_path, rna_path_len, "tracking.plane_tracks"); + } + else { + char object_name_esc[MAX_NAME * 2]; + BLI_strescape(object_name_esc, object->name, sizeof(object_name_esc)); + BLI_snprintf(rna_path, rna_path_len, + "tracking.objects[\"%s\"].plane_tracks", + object_name_esc); + } +} diff --git a/source/blender/blenkernel/intern/tracking_auto.c b/source/blender/blenkernel/intern/tracking_auto.c index 4ff4a129768..1cb474e6202 100644 --- a/source/blender/blenkernel/intern/tracking_auto.c +++ b/source/blender/blenkernel/intern/tracking_auto.c @@ -236,17 +236,15 @@ static void libmv_marker_to_dna_marker(libmv_Marker *libmv_marker, } } -static bool check_track_trackable(MovieClip *clip, +static bool check_track_trackable(const MovieClip *clip, MovieTrackingTrack *track, - MovieClipUser *user) + const MovieClipUser *user) { if (TRACK_SELECTED(track) && (track->flag & (TRACK_LOCKED | TRACK_HIDDEN)) == 0) { - MovieTrackingMarker *marker; - int frame; - frame = BKE_movieclip_remap_scene_to_clip_frame(clip, user->framenr); - marker = BKE_tracking_marker_get(track, frame); + int frame = BKE_movieclip_remap_scene_to_clip_frame(clip, user->framenr); + const MovieTrackingMarker *marker = BKE_tracking_marker_get(track, frame); return (marker->flag & MARKER_DISABLED) == 0; } return false; @@ -283,6 +281,108 @@ static bool tracking_check_marker_margin(libmv_Marker *libmv_marker, return true; } +/* Provide Libmv side of auto track all information about given tracks. */ +static void fill_autotrack_tracks(const int frame_width, + const int frame_height, + const ListBase *tracksbase, + const bool backwards, + struct libmv_AutoTrack *autotrack) +{ + /* Count number of markers to be put to a context. */ + size_t num_trackable_markers = 0; + for (MovieTrackingTrack *track = tracksbase->first; + track != NULL; + track = track->next) + { + for (int i = 0; i < track->markersnr; ++i) { + const MovieTrackingMarker *marker = track->markers + i; + if ((marker->flag & MARKER_DISABLED) == 0) { + num_trackable_markers++; + } + } + } + /* Early output if we don't have any markers. */ + if (num_trackable_markers == 0) { + return; + } + /* Allocate memory for all the markers. */ + libmv_Marker *libmv_markers = MEM_mallocN( + sizeof(libmv_Marker) * num_trackable_markers, + "libmv markers array"); + /* Fill in markers array. */ + int track_index = 0, num_filled_libmv_markers = 0; + for (MovieTrackingTrack *track = tracksbase->first; + track != NULL; + track = track->next) + { + for (int i = 0; i < track->markersnr; ++i) { + MovieTrackingMarker *marker = track->markers + i; + if ((marker->flag & MARKER_DISABLED) != 0) { + continue; + } + dna_marker_to_libmv_marker( + track, + marker, + 0, + track_index, + frame_width, frame_height, + backwards, + &libmv_markers[num_filled_libmv_markers++]); + } + /* Put all markers to autotrack at once. */ + track_index++; + } + /* Add all markers to autotrack. */ + libmv_autoTrackSetMarkers(autotrack, + libmv_markers, + num_trackable_markers); + /* Free temporary memory. */ + MEM_freeN(libmv_markers); +} + +static void create_per_track_tracking_options(const MovieClip *clip, + const MovieClipUser *user, + const ListBase *tracksbase, + AutoTrackContext *context) +{ + /* Count number of trackable tracks. */ + for (MovieTrackingTrack *track = tracksbase->first; + track != NULL; + track = track->next) + { + if (check_track_trackable(clip, track, user)) { + context->num_tracks++; + } + } + /* Allocate required memory. */ + context->options = + MEM_callocN(sizeof(AutoTrackOptions) * context->num_tracks, + "auto track options"); + /* Fill in all the settings. */ + int i = 0, track_index = 0; + for (MovieTrackingTrack *track = tracksbase->first; + track != NULL; + track = track->next) + { + if (!check_track_trackable(clip, track, user)) { + ++track_index; + continue; + } + AutoTrackOptions *options = &context->options[i++]; + /* TODO(sergey): Single clip only for now. */ + options->clip_index = 0; + options->track_index = track_index; + options->track = track; + tracking_configure_tracker(track, + NULL, + &options->track_region_options); + options->use_keyframe_match = + track->pattern_match == TRACK_MATCH_KEYFRAME; + context->tracks[track_index] = track; + ++track_index; + } +} + AutoTrackContext *BKE_autotrack_context_new(MovieClip *clip, MovieClipUser *user, const bool backwards, @@ -291,16 +391,13 @@ AutoTrackContext *BKE_autotrack_context_new(MovieClip *clip, AutoTrackContext *context = MEM_callocN(sizeof(AutoTrackContext), "autotrack context"); MovieTracking *tracking = &clip->tracking; - MovieTrackingTrack *track; ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking); - int i, track_index, frame_width, frame_height; - + int frame_width, frame_height; + /* get size of frame to convert normalized coordinates to a picture ones. */ BKE_movieclip_get_size(clip, user, &frame_width, &frame_height); - /* TODO(sergey): Currently using only a single clip. */ context->clips[0] = clip; context->num_clips = 1; - context->user = *user; context->user.render_size = MCLIP_PROXY_RENDER_SIZE_FULL; context->user.render_flag = 0; @@ -311,79 +408,34 @@ AutoTrackContext *BKE_autotrack_context_new(MovieClip *clip, context->first_frame = user->framenr; context->sync_frame = user->framenr; context->first_sync = true; - BLI_spin_init(&context->spin_lock); - - int num_total_tracks = BLI_listbase_count(tracksbase); + const int num_total_tracks = BLI_listbase_count(tracksbase); context->tracks = - MEM_callocN(sizeof(MovieTrackingTrack *) * num_total_tracks, - "auto track pointers"); - + MEM_callocN(sizeof(MovieTrackingTrack *) * num_total_tracks, + "auto track pointers"); + /* Initialize image accessor. */ context->image_accessor = tracking_image_accessor_new(context->clips, 1, context->tracks, num_total_tracks, user->framenr); + /* Initialize auto track context and provide all information about currently + * tracked markers. + */ context->autotrack = - libmv_autoTrackNew(context->image_accessor->libmv_accessor); - - /* Fill in Autotrack with all markers we know. */ - track_index = 0; - for (track = tracksbase->first; - track; - track = track->next) - { - if (check_track_trackable(clip, track, user)) { - context->num_tracks++; - } - - for (i = 0; i < track->markersnr; ++i) { - MovieTrackingMarker *marker = track->markers + i; - if ((marker->flag & MARKER_DISABLED) == 0) { - libmv_Marker libmv_marker; - dna_marker_to_libmv_marker(track, - marker, - 0, - track_index, - frame_width, - frame_height, - backwards, - &libmv_marker); - libmv_autoTrackAddMarker(context->autotrack, - &libmv_marker); - } - } - track_index++; - } - + libmv_autoTrackNew(context->image_accessor->libmv_accessor); + fill_autotrack_tracks(frame_width, frame_height, + tracksbase, + backwards, + context->autotrack); /* Create per-track tracking options. */ - context->options = - MEM_callocN(sizeof(AutoTrackOptions) * context->num_tracks, - "auto track options"); - i = track_index = 0; - for (track = tracksbase->first; - track; - track = track->next) - { - if (check_track_trackable(clip, track, user)) { - AutoTrackOptions *options = &context->options[i++]; - /* TODO(sergey): Single clip only for now. */ - options->clip_index = 0; - options->track_index = track_index; - options->track = track; - tracking_configure_tracker(track, - NULL, - &options->track_region_options); - options->use_keyframe_match = - track->pattern_match == TRACK_MATCH_KEYFRAME; - } - context->tracks[track_index] = track; - ++track_index; - } - + create_per_track_tracking_options(clip, user, tracksbase, context); return context; } -static void autotrack_context_step_cb(void *userdata, int track) +static void autotrack_context_step_cb( + void *__restrict userdata, + const int track, + const ParallelRangeTLS *__restrict UNUSED(tls)) { AutoTrackContext *context = userdata; const int frame_delta = context->backwards ? -1 : 1; @@ -461,10 +513,13 @@ bool BKE_autotrack_context_step(AutoTrackContext *context) const int frame_delta = context->backwards ? -1 : 1; context->step_ok = false; + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = (context->num_tracks > 1); BLI_task_parallel_range(0, context->num_tracks, context, autotrack_context_step_cb, - context->num_tracks > 1); + &settings); /* Advance the frame. */ BLI_spin_lock(&context->spin_lock); diff --git a/source/blender/blenkernel/intern/tracking_stabilize.c b/source/blender/blenkernel/intern/tracking_stabilize.c index edddeb41cc8..cbf1a02a46c 100644 --- a/source/blender/blenkernel/intern/tracking_stabilize.c +++ b/source/blender/blenkernel/intern/tracking_stabilize.c @@ -1503,7 +1503,10 @@ typedef struct TrackingStabilizeFrameInterpolationData { interpolation_func interpolation; } TrackingStabilizeFrameInterpolationData; -static void tracking_stabilize_frame_interpolation_cb(void *userdata, int j) +static void tracking_stabilize_frame_interpolation_cb( + void *__restrict userdata, + const int j, + const ParallelRangeTLS *__restrict UNUSED(tls)) { TrackingStabilizeFrameInterpolationData *data = userdata; ImBuf *ibuf = data->ibuf; @@ -1597,10 +1600,14 @@ ImBuf *BKE_tracking_stabilize_frame(MovieClip *clip, .ibuf = ibuf, .tmpibuf = tmpibuf, .mat = mat, .interpolation = interpolation }; + + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = (tmpibuf->y > 128); BLI_task_parallel_range(0, tmpibuf->y, &data, tracking_stabilize_frame_interpolation_cb, - tmpibuf->y > 128); + &settings); if (tmpibuf->rect_float) tmpibuf->userflags |= IB_RECT_INVALID; diff --git a/source/blender/blenkernel/intern/world.c b/source/blender/blenkernel/intern/world.c index 4abd2a01d40..5da8dc563e2 100644 --- a/source/blender/blenkernel/intern/world.c +++ b/source/blender/blenkernel/intern/world.c @@ -108,7 +108,7 @@ void BKE_world_init(World *wrld) wrld->mistdist = 25.0f; } -World *add_world(Main *bmain, const char *name) +World *BKE_world_add(Main *bmain, const char *name) { World *wrld; @@ -158,7 +158,7 @@ World *BKE_world_copy(Main *bmain, const World *wrld) return wrld_copy; } -World *localize_world(World *wrld) +World *BKE_world_localize(World *wrld) { /* TODO replace with something like * World *wrld_copy; @@ -174,7 +174,7 @@ World *localize_world(World *wrld) for (a = 0; a < MAX_MTEX; a++) { if (wrld->mtex[a]) { - wrldn->mtex[a] = MEM_mallocN(sizeof(MTex), "localize_world"); + wrldn->mtex[a] = MEM_mallocN(sizeof(MTex), __func__); memcpy(wrldn->mtex[a], wrld->mtex[a], sizeof(MTex)); } } diff --git a/source/blender/blenkernel/intern/writeffmpeg.c b/source/blender/blenkernel/intern/writeffmpeg.c index 60a1bdb0458..f745a840cea 100644 --- a/source/blender/blenkernel/intern/writeffmpeg.c +++ b/source/blender/blenkernel/intern/writeffmpeg.c @@ -158,7 +158,7 @@ static int write_audio_frame(FFMpegContext *context) for (channel = 0; channel < c->channels; channel++) { for (i = 0; i < frame->nb_samples; i++) { memcpy(context->audio_deinterleave_buffer + (i + channel * frame->nb_samples) * context->audio_sample_size, - context->audio_input_buffer + (c->channels * i + channel) * context->audio_sample_size, context->audio_sample_size); + context->audio_input_buffer + (c->channels * i + channel) * context->audio_sample_size, context->audio_sample_size); } } diff --git a/source/blender/blenlib/BLI_linklist.h b/source/blender/blenlib/BLI_linklist.h index 367f1bb9de5..7eec54e67e1 100644 --- a/source/blender/blenlib/BLI_linklist.h +++ b/source/blender/blenlib/BLI_linklist.h @@ -30,9 +30,6 @@ /** \file BLI_linklist.h * \ingroup bli - * \brief Routines for working with singly linked lists - * of 'links' - pointers to other data. - * */ #include "BLI_compiler_attrs.h" diff --git a/source/blender/blenlib/BLI_listbase.h b/source/blender/blenlib/BLI_listbase.h index 1e931e6f0d7..2a0f4e6f814 100644 --- a/source/blender/blenlib/BLI_listbase.h +++ b/source/blender/blenlib/BLI_listbase.h @@ -128,9 +128,9 @@ if ((lb)->last && (lb_init || (lb_init = (lb)->last))) { \ (lb_iter != lb_init)); \ } -#define LINKLIST_FOREACH(type, var, list) \ - for (type var = (type)((list)->first); \ - var != NULL; \ +#define BLI_LISTBASE_FOREACH(type, var, list) \ + for (type var = (type)((list)->first); \ + var != NULL; \ var = (type)(((Link*)(var))->next)) #ifdef __cplusplus diff --git a/source/blender/blenlib/BLI_math_base.h b/source/blender/blenlib/BLI_math_base.h index e6a72298ae7..377b9325717 100644 --- a/source/blender/blenlib/BLI_math_base.h +++ b/source/blender/blenlib/BLI_math_base.h @@ -129,6 +129,9 @@ MINLINE int max_iii(int a, int b, int c); MINLINE int min_iiii(int a, int b, int c, int d); MINLINE int max_iiii(int a, int b, int c, int d); +MINLINE size_t min_zz(size_t a, size_t b); +MINLINE size_t max_zz(size_t a, size_t b); + MINLINE int compare_ff(float a, float b, const float max_diff); MINLINE int compare_ff_relative(float a, float b, const float max_diff, const int max_ulps); @@ -140,6 +143,7 @@ MINLINE float power_of_2(float f); MINLINE int integer_digits_f(const float f); MINLINE int integer_digits_d(const double d); +MINLINE int integer_digits_i(const int i); /* these don't really fit anywhere but were being copied about a lot */ MINLINE int is_power_of_2_i(int n); diff --git a/source/blender/blenlib/BLI_math_bits.h b/source/blender/blenlib/BLI_math_bits.h index 1ac98a682d1..86213dc271f 100644 --- a/source/blender/blenlib/BLI_math_bits.h +++ b/source/blender/blenlib/BLI_math_bits.h @@ -31,7 +31,24 @@ extern "C" { #include "BLI_math_inline.h" -MINLINE unsigned int highest_order_bit_i(unsigned int n); +/* Search the value from LSB to MSB for a set bit. Returns index of this bit. */ +MINLINE int bitscan_forward_i(int a); +MINLINE unsigned int bitscan_forward_uint(unsigned int a); + +/* Similar to above, but also clears the bit. */ +MINLINE int bitscan_forward_clear_i(int *a); +MINLINE unsigned int bitscan_forward_clear_uint(unsigned int *a); + +/* Search the value from MSB to LSB for a set bit. Returns index of this bit. */ +MINLINE int bitscan_reverse_i(int a); +MINLINE unsigned int bitscan_reverse_uint(unsigned int a); + +/* Similar to above, but also clears the bit. */ +MINLINE int bitscan_reverse_clear_i(int *a); +MINLINE unsigned int bitscan_reverse_clear_uint(unsigned int *a); + +/* NOTE: Those functions returns 2 to the power of index of highest order bit. */ +MINLINE unsigned int highest_order_bit_uint(unsigned int n); MINLINE unsigned short highest_order_bit_s(unsigned short n); #ifdef __GNUC__ diff --git a/source/blender/blenlib/BLI_math_rotation.h b/source/blender/blenlib/BLI_math_rotation.h index e059327a490..1f206e5e234 100644 --- a/source/blender/blenlib/BLI_math_rotation.h +++ b/source/blender/blenlib/BLI_math_rotation.h @@ -97,6 +97,11 @@ float angle_normalized_qtqt(const float q1[4], const float q2[4]); float angle_qt(const float q[4]); float angle_qtqt(const float q1[4], const float q2[4]); +float angle_signed_normalized_qt(const float q[4]); +float angle_signed_normalized_qtqt(const float q1[4], const float q2[4]); +float angle_signed_qt(const float q[4]); +float angle_signed_qtqt(const float q1[4], const float q2[4]); + /* TODO: don't what this is, but it's not the same as mat3_to_quat */ void mat3_to_quat_is_ok(float q[4], float mat[3][3]); diff --git a/source/blender/blenlib/BLI_task.h b/source/blender/blenlib/BLI_task.h index ccfa2b6e2e7..d03010af8d2 100644 --- a/source/blender/blenlib/BLI_task.h +++ b/source/blender/blenlib/BLI_task.h @@ -19,7 +19,9 @@ */ #ifndef __BLI_TASK_H__ -#define __BLI_TASK_H__ +#define __BLI_TASK_H__ + +#include <string.h> /* for memset() */ struct Link; struct ListBase; @@ -116,32 +118,77 @@ void BLI_task_pool_delayed_push_begin(TaskPool *pool, int thread_id); void BLI_task_pool_delayed_push_end(TaskPool *pool, int thread_id); /* Parallel for routines */ -typedef void (*TaskParallelRangeFunc)(void *userdata, const int iter); -typedef void (*TaskParallelRangeFuncEx)(void *userdata, void *userdata_chunk, const int iter, const int thread_id); -typedef void (*TaskParallelRangeFuncFinalize)(void *userdata, void *userdata_chunk); -void BLI_task_parallel_range_ex( - int start, int stop, - void *userdata, - void *userdata_chunk, - const size_t userdata_chunk_size, - TaskParallelRangeFuncEx func_ex, - const bool use_threading, - const bool use_dynamic_scheduling); + +typedef enum eTaskSchedulingMode { + /* Task scheduler will divide overall work into equal chunks, scheduling + * even chunks to all worker threads. + * Least run time benefit, ideal for cases when each task requires equal + * amount of compute power. + */ + TASK_SCHEDULING_STATIC, + /* Task scheduler will schedule small amount of work to each worker thread. + * Has more run time overhead, but deals much better with cases when each + * part of the work requires totally different amount of compute power. + */ + TASK_SCHEDULING_DYNAMIC, +} eTaskSchedulingMode; + +/* Per-thread specific data passed to the callback. */ +typedef struct ParallelRangeTLS { + /* Identifier of the thread who this data belongs to. */ + int thread_id; + /* Copy of user-specifier chunk, which is copied from original chunk to all + * worker threads. This is similar to OpenMP's firstprivate. + */ + void *userdata_chunk; +} ParallelRangeTLS; + +typedef void (*TaskParallelRangeFunc)(void *__restrict userdata, + const int iter, + const ParallelRangeTLS *__restrict tls); +typedef void (*TaskParallelRangeFuncFinalize)(void *__restrict userdata, + void *__restrict userdata_chunk); + +typedef struct ParallelRangeSettings { + /* Whether caller allows to do threading of the particular range. + * Usually set by some equation, which forces threading off when threading + * overhead becomes higher than speed benefit. + * BLI_task_parallel_range() by itself will always use threading when range + * is higher than a chunk size. As in, threading will always be performed. + */ + bool use_threading; + /* Scheduling mode to use for this parallel range invocation. */ + eTaskSchedulingMode scheduling_mode; + /* Each instance of looping chunks will get a copy of this data + * (similar to OpenMP's firstprivate). + */ + void *userdata_chunk; /* Pointer to actual data. */ + size_t userdata_chunk_size; /* Size of that data. */ + /* Function called from calling thread once whole range have been + * processed. + */ + TaskParallelRangeFuncFinalize func_finalize; + /* Minimum allowed number of range iterators to be handled by a single + * thread. This allows to achieve following: + * - Reduce amount of threading overhead. + * - Partially occupy thread pool with ranges which are computationally + * expensive, but which are smaller than amount of available threads. + * For example, it's possible to multi-thread [0 .. 64] range into 4 + * thread which will be doing 16 iterators each. + * This is a preferred way to tell scheduler when to start threading than + * having a global use_threading switch based on just range size. + */ + int min_iter_per_thread; +} ParallelRangeSettings; + +BLI_INLINE void BLI_parallel_range_settings_defaults( + ParallelRangeSettings *settings); + void BLI_task_parallel_range( - int start, int stop, + const int start, const int stop, void *userdata, TaskParallelRangeFunc func, - const bool use_threading); - -void BLI_task_parallel_range_finalize( - int start, int stop, - void *userdata, - void *userdata_chunk, - const size_t userdata_chunk_size, - TaskParallelRangeFuncEx func_ex, - TaskParallelRangeFuncFinalize func_finalize, - const bool use_threading, - const bool use_dynamic_scheduling); + const ParallelRangeSettings *settings); typedef void (*TaskParallelListbaseFunc)(void *userdata, struct Link *iter, @@ -161,6 +208,20 @@ void BLI_task_parallel_mempool( TaskParallelMempoolFunc func, const bool use_threading); +/* TODO(sergey): Think of a better place for this. */ +BLI_INLINE void BLI_parallel_range_settings_defaults( + ParallelRangeSettings *settings) +{ + memset(settings, 0, sizeof(*settings)); + settings->use_threading = true; + settings->scheduling_mode = TASK_SCHEDULING_STATIC; + /* NOTE: Current value mimics old behavior, but it's not ideal by any + * means. Would be cool to find a common value which will work good enough + * for both static and dynamic scheduling. + */ + settings->min_iter_per_thread = 1; +} + #ifdef __cplusplus } #endif diff --git a/source/blender/blenlib/intern/BLI_ghash.c b/source/blender/blenlib/intern/BLI_ghash.c index 28e98c17a9d..bf2f25fae69 100644 --- a/source/blender/blenlib/intern/BLI_ghash.c +++ b/source/blender/blenlib/intern/BLI_ghash.c @@ -50,18 +50,27 @@ #include "BLI_ghash.h" #include "BLI_strict_flags.h" +/* -------------------------------------------------------------------- */ +/** \name Structs & Constants + * \{ */ + #define GHASH_USE_MODULO_BUCKETS -/* Also used by smallhash! */ +/** + * Next prime after `2^n` (skipping 2 & 3). + * + * \note Also used by: `BLI_edgehash` & `BLI_smallhash`. + */ const uint hashsizes[] = { - 5, 11, 17, 37, 67, 131, 257, 521, 1031, 2053, 4099, 8209, - 16411, 32771, 65537, 131101, 262147, 524309, 1048583, 2097169, - 4194319, 8388617, 16777259, 33554467, 67108879, 134217757, + 5, 11, 17, 37, 67, 131, 257, 521, 1031, 2053, 4099, 8209, + 16411, 32771, 65537, 131101, 262147, 524309, 1048583, 2097169, + 4194319, 8388617, 16777259, 33554467, 67108879, 134217757, 268435459 }; #ifdef GHASH_USE_MODULO_BUCKETS # define GHASH_MAX_SIZE 27 +BLI_STATIC_ASSERT(ARRAY_SIZE(hashsizes) == GHASH_MAX_SIZE, "Invalid 'hashsizes' size"); #else # define GHASH_BUCKET_BIT_MIN 2 # define GHASH_BUCKET_BIT_MAX 28 /* About 268M of buckets... */ @@ -77,8 +86,6 @@ const uint hashsizes[] = { #define GHASH_LIMIT_GROW(_nbkt) (((_nbkt) * 3) / 4) #define GHASH_LIMIT_SHRINK(_nbkt) (((_nbkt) * 3) / 16) -/***/ - /* WARNING! Keep in sync with ugly _gh_Entry in header!!! */ typedef struct Entry { struct Entry *next; @@ -115,10 +122,9 @@ struct GHash { uint flag; }; +/** \} */ /* -------------------------------------------------------------------- */ -/* GHash API */ - /** \name Internal Utility API * \{ */ @@ -429,8 +435,9 @@ BLI_INLINE Entry *ghash_lookup_entry(GHash *gh, const void *key) return ghash_lookup_entry_ex(gh, key, bucket_index); } -static GHash *ghash_new(GHashHashFP hashfp, GHashCmpFP cmpfp, const char *info, - const uint nentries_reserve, const uint flag) +static GHash *ghash_new( + GHashHashFP hashfp, GHashCmpFP cmpfp, const char *info, + const uint nentries_reserve, const uint flag) { GHash *gh = MEM_mallocN(sizeof(*gh), info); @@ -685,8 +692,8 @@ static GHash *ghash_copy(GHash *gh, GHashKeyCopyFP keycopyfp, GHashValCopyFP val /** \} */ - -/** \name Public API +/* -------------------------------------------------------------------- */ +/** \name GHash Public API * \{ */ /** @@ -699,8 +706,9 @@ static GHash *ghash_copy(GHash *gh, GHashKeyCopyFP keycopyfp, GHashValCopyFP val * Use this to avoid resizing buckets if the size is known or can be closely approximated. * \return An empty GHash. */ -GHash *BLI_ghash_new_ex(GHashHashFP hashfp, GHashCmpFP cmpfp, const char *info, - const uint nentries_reserve) +GHash *BLI_ghash_new_ex( + GHashHashFP hashfp, GHashCmpFP cmpfp, const char *info, + const uint nentries_reserve) { return ghash_new(hashfp, cmpfp, info, nentries_reserve, 0); } @@ -974,8 +982,9 @@ bool BLI_ghash_pop( * \param valfreefp Optional callback to free the value. * \param nentries_reserve Optionally reserve the number of members that the hash will hold. */ -void BLI_ghash_clear_ex(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp, - const uint nentries_reserve) +void BLI_ghash_clear_ex( + GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp, + const uint nentries_reserve) { if (keyfreefp || valfreefp) ghash_free_cb(gh, keyfreefp, valfreefp); @@ -1028,11 +1037,8 @@ void BLI_ghash_flag_clear(GHash *gh, uint flag) /** \} */ - /* -------------------------------------------------------------------- */ -/* GHash Iterator API */ - -/** \name Iterator API +/** \name GHash Iterator API * \{ */ /** @@ -1154,7 +1160,7 @@ bool BLI_ghashIterator_done(GHashIterator *ghi) /** \} */ - +/* -------------------------------------------------------------------- */ /** \name Generic Key Hash & Comparison Functions * \{ */ @@ -1325,7 +1331,7 @@ void BLI_ghashutil_pairfree(void *ptr) /** \} */ - +/* -------------------------------------------------------------------- */ /** \name Convenience GHash Creation Functions * \{ */ @@ -1367,16 +1373,14 @@ GHash *BLI_ghash_pair_new(const char *info) /** \} */ - /* -------------------------------------------------------------------- */ -/* GSet API */ - -/* Use ghash API to give 'set' functionality */ - -/** \name GSet Functions +/** \name GSet Public API + * + * Use ghash API to give 'set' functionality * \{ */ -GSet *BLI_gset_new_ex(GSetHashFP hashfp, GSetCmpFP cmpfp, const char *info, - const uint nentries_reserve) +GSet *BLI_gset_new_ex( + GSetHashFP hashfp, GSetCmpFP cmpfp, const char *info, + const uint nentries_reserve) { return (GSet *)ghash_new(hashfp, cmpfp, info, nentries_reserve, GHASH_FLAG_IS_GSET); } @@ -1504,11 +1508,13 @@ bool BLI_gset_pop( } } -void BLI_gset_clear_ex(GSet *gs, GSetKeyFreeFP keyfreefp, - const uint nentries_reserve) +void BLI_gset_clear_ex( + GSet *gs, GSetKeyFreeFP keyfreefp, + const uint nentries_reserve) { - BLI_ghash_clear_ex((GHash *)gs, keyfreefp, NULL, - nentries_reserve); + BLI_ghash_clear_ex( + (GHash *)gs, keyfreefp, NULL, + nentries_reserve); } void BLI_gset_clear(GSet *gs, GSetKeyFreeFP keyfreefp) @@ -1533,6 +1539,7 @@ void BLI_gset_flag_clear(GSet *gs, uint flag) /** \} */ +/* -------------------------------------------------------------------- */ /** \name GSet Combined Key/Value Usage * * \note Not typical ``set`` use, only use when the pointer identity matters. @@ -1569,6 +1576,7 @@ void *BLI_gset_pop_key(GSet *gs, const void *key) /** \} */ +/* -------------------------------------------------------------------- */ /** \name Convenience GSet Creation Functions * \{ */ @@ -1601,7 +1609,7 @@ GSet *BLI_gset_pair_new(const char *info) /** \} */ - +/* -------------------------------------------------------------------- */ /** \name Debugging & Introspection * \{ */ @@ -1713,8 +1721,9 @@ double BLI_gset_calc_quality_ex( GSet *gs, double *r_load, double *r_variance, double *r_prop_empty_buckets, double *r_prop_overloaded_buckets, int *r_biggest_bucket) { - return BLI_ghash_calc_quality_ex((GHash *)gs, r_load, r_variance, - r_prop_empty_buckets, r_prop_overloaded_buckets, r_biggest_bucket); + return BLI_ghash_calc_quality_ex( + (GHash *)gs, r_load, r_variance, + r_prop_empty_buckets, r_prop_overloaded_buckets, r_biggest_bucket); } double BLI_ghash_calc_quality(GHash *gh) diff --git a/source/blender/blenlib/intern/BLI_kdopbvh.c b/source/blender/blenlib/intern/BLI_kdopbvh.c index bd16bc1a9c6..9c055a227a9 100644 --- a/source/blender/blenlib/intern/BLI_kdopbvh.c +++ b/source/blender/blenlib/intern/BLI_kdopbvh.c @@ -798,7 +798,10 @@ typedef struct BVHDivNodesData { int first_of_next_level; } BVHDivNodesData; -static void non_recursive_bvh_div_nodes_task_cb(void *userdata, const int j) +static void non_recursive_bvh_div_nodes_task_cb( + void *__restrict userdata, + const int j, + const ParallelRangeTLS *__restrict UNUSED(tls)) { BVHDivNodesData *data = userdata; @@ -872,7 +875,7 @@ static void non_recursive_bvh_div_nodes_task_cb(void *userdata, const int j) * to use multithread building. * * To archive this is necessary to find how much leafs are accessible from a certain branch, BVHBuildHelper - * implicit_needed_branches and implicit_leafs_index are auxiliary functions to solve that "optimal-split". + * #implicit_needed_branches and #implicit_leafs_index are auxiliary functions to solve that "optimal-split". */ static void non_recursive_bvh_div_nodes( const BVHTree *tree, BVHNode *branches_array, BVHNode **leafs_array, int num_leafs) @@ -885,24 +888,23 @@ static void non_recursive_bvh_div_nodes( BVHBuildHelper data; int depth; - - /* set parent from root node to NULL */ - BVHNode *tmp = &branches_array[0]; - tmp->parent = NULL; - - /* Most of bvhtree code relies on 1-leaf trees having at least one branch - * We handle that special case here */ - if (num_leafs == 1) { - BVHNode *root = &branches_array[0]; - refit_kdop_hull(tree, root, 0, num_leafs); - root->main_axis = get_largest_axis(root->bv) / 2; - root->totnode = 1; - root->children[0] = leafs_array[0]; - root->children[0]->parent = root; - return; - } - branches_array--; /* Implicit trees use 1-based indexs */ + { + /* set parent from root node to NULL */ + BVHNode *root = &branches_array[1]; + root->parent = NULL; + + /* Most of bvhtree code relies on 1-leaf trees having at least one branch + * We handle that special case here */ + if (num_leafs == 1) { + refit_kdop_hull(tree, root, 0, num_leafs); + root->main_axis = get_largest_axis(root->bv) / 2; + root->totnode = 1; + root->children[0] = leafs_array[0]; + root->children[0]->parent = root; + return; + } + } build_implicit_tree_helper(tree, &data); @@ -923,14 +925,20 @@ static void non_recursive_bvh_div_nodes( cb_data.depth = depth; if (true) { + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = (num_leafs > KDOPBVH_THREAD_LEAF_THRESHOLD); BLI_task_parallel_range( - i, i_stop, &cb_data, non_recursive_bvh_div_nodes_task_cb, - num_leafs > KDOPBVH_THREAD_LEAF_THRESHOLD); + i, i_stop, + &cb_data, + non_recursive_bvh_div_nodes_task_cb, + &settings); } else { /* Less hassle for debugging. */ + ParallelRangeTLS tls = {0}; for (int i_task = i; i_task < i_stop; i_task++) { - non_recursive_bvh_div_nodes_task_cb(&cb_data, i_task); + non_recursive_bvh_div_nodes_task_cb(&cb_data, i_task, &tls); } } } @@ -1044,9 +1052,6 @@ void BLI_bvhtree_free(BVHTree *tree) void BLI_bvhtree_balance(BVHTree *tree) { - int i; - - BVHNode *branches_array = tree->nodearray + tree->totleaf; BVHNode **leafs_array = tree->nodes; /* This function should only be called once @@ -1054,13 +1059,14 @@ void BLI_bvhtree_balance(BVHTree *tree) BLI_assert(tree->totbranch == 0); /* Build the implicit tree */ - non_recursive_bvh_div_nodes(tree, branches_array, leafs_array, tree->totleaf); + non_recursive_bvh_div_nodes(tree, tree->nodearray + (tree->totleaf - 1), leafs_array, tree->totleaf); /* current code expects the branches to be linked to the nodes array * we perform that linkage here */ tree->totbranch = implicit_needed_branches(tree->tree_type, tree->totleaf); - for (i = 0; i < tree->totbranch; i++) - tree->nodes[tree->totleaf + i] = branches_array + i; + for (int i = 0; i < tree->totbranch; i++) { + tree->nodes[tree->totleaf + i] = &tree->nodearray[tree->totleaf + i]; + } #ifdef USE_SKIP_LINKS build_skip_links(tree, tree->nodes[tree->totleaf], NULL, NULL); @@ -1276,7 +1282,10 @@ int BLI_bvhtree_overlap_thread_num(const BVHTree *tree) return (int)MIN2(tree->tree_type, tree->nodes[tree->totleaf]->totnode); } -static void bvhtree_overlap_task_cb(void *userdata, const int j) +static void bvhtree_overlap_task_cb( + void *__restrict userdata, + const int j, + const ParallelRangeTLS *__restrict UNUSED(tls)) { BVHOverlapData_Thread *data = &((BVHOverlapData_Thread *)userdata)[j]; BVHOverlapData_Shared *data_shared = data->shared; @@ -1341,9 +1350,14 @@ BVHTreeOverlap *BLI_bvhtree_overlap( data[j].thread = j; } + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = (tree1->totleaf > KDOPBVH_THREAD_LEAF_THRESHOLD); BLI_task_parallel_range( - 0, thread_num, data, bvhtree_overlap_task_cb, - tree1->totleaf > KDOPBVH_THREAD_LEAF_THRESHOLD); + 0, thread_num, + data, + bvhtree_overlap_task_cb, + &settings); for (j = 0; j < thread_num; j++) total += BLI_stack_count(data[j].overlap); diff --git a/source/blender/blenlib/intern/BLI_linklist.c b/source/blender/blenlib/intern/BLI_linklist.c index 1500e23d72e..051792f7f7c 100644 --- a/source/blender/blenlib/intern/BLI_linklist.c +++ b/source/blender/blenlib/intern/BLI_linklist.c @@ -28,6 +28,10 @@ /** \file blender/blenlib/intern/BLI_linklist.c * \ingroup bli + * + * Routines for working with single linked lists of 'links' - pointers to other data. + * + * For double linked lists see 'BLI_listbase.h'. */ #include <stdlib.h> diff --git a/source/blender/blenlib/intern/bitmap_draw_2d.c b/source/blender/blenlib/intern/bitmap_draw_2d.c index e77e8cf40d0..fefd4b4587c 100644 --- a/source/blender/blenlib/intern/bitmap_draw_2d.c +++ b/source/blender/blenlib/intern/bitmap_draw_2d.c @@ -162,7 +162,7 @@ static int draw_poly_v2i_n__span_y_sort(const void *a_p, const void *b_p, void * } /** - * Draws a filled polyon with support for self intersections. + * Draws a filled polygon with support for self intersections. * * \param callback: Takes the x, y coords and x-span (\a x_end is not inclusive), * note that \a x_end will always be greater than \a x, so we can use: diff --git a/source/blender/blenlib/intern/listbase.c b/source/blender/blenlib/intern/listbase.c index d2cf0cf49a2..96c3972d802 100644 --- a/source/blender/blenlib/intern/listbase.c +++ b/source/blender/blenlib/intern/listbase.c @@ -29,7 +29,9 @@ /** \file blender/blenlib/intern/listbase.c * \ingroup bli * - * Manipulations on ListBase structs + * Manipulations on double-linked list (#ListBase structs). + * + * For single linked lists see 'BLI_linklist.h' */ #include <string.h> diff --git a/source/blender/blenlib/intern/math_base_inline.c b/source/blender/blenlib/intern/math_base_inline.c index 749c18fc0ce..2f5b0f420b1 100644 --- a/source/blender/blenlib/intern/math_base_inline.c +++ b/source/blender/blenlib/intern/math_base_inline.c @@ -315,6 +315,15 @@ MINLINE int max_iiii(int a, int b, int c, int d) return max_ii(max_iii(a, b, c), d); } +MINLINE size_t min_zz(size_t a, size_t b) +{ + return (a < b) ? a : b; +} +MINLINE size_t max_zz(size_t a, size_t b) +{ + return (b < a) ? a : b; +} + /** * Almost-equal for IEEE floats, using absolute difference method. * @@ -388,6 +397,10 @@ MINLINE int integer_digits_d(const double d) return (d == 0.0) ? 0 : (int)floor(log10(fabs(d))) + 1; } +MINLINE int integer_digits_i(const int i) +{ + return (int)log10((double)i) + 1; +} /* Internal helpers for SSE2 implementation. * diff --git a/source/blender/blenlib/intern/math_bits_inline.c b/source/blender/blenlib/intern/math_bits_inline.c index 82d7e2114c2..37fdcd7878a 100644 --- a/source/blender/blenlib/intern/math_bits_inline.c +++ b/source/blender/blenlib/intern/math_bits_inline.c @@ -25,16 +25,77 @@ #ifndef __MATH_BITS_INLINE_C__ #define __MATH_BITS_INLINE_C__ +#ifdef _MSC_VER +# include <intrin.h> +#endif + #include "BLI_math_bits.h" -MINLINE unsigned int highest_order_bit_i(unsigned int n) +MINLINE int bitscan_forward_i(int a) { - n |= (n >> 1); - n |= (n >> 2); - n |= (n >> 4); - n |= (n >> 8); - n |= (n >> 16); - return n - (n >> 1); + BLI_assert(a != 0); +# ifdef _MSC_VER + unsigned long ctz; + _BitScanForward(&ctz, a); + return ctz; +#else + return __builtin_ctz((unsigned int)a); +#endif +} + +MINLINE unsigned int bitscan_forward_uint(unsigned int a) +{ + return (unsigned int)bitscan_forward_i((int)a); +} + +MINLINE int bitscan_forward_clear_i(int *a) +{ + int i = bitscan_forward_i(*a); + *a &= (*a) - 1; + return i; +} + +MINLINE unsigned int bitscan_forward_clear_uint(unsigned int *a) +{ + return (unsigned int)bitscan_forward_clear_i((int *)a); +} + +MINLINE int bitscan_reverse_i(int a) +{ + BLI_assert(a != 0); +# ifdef _MSC_VER + unsigned long clz; + _BitScanReverse(&clz, a); + return clz; +#else + return __builtin_clz((unsigned int)a); +#endif +} + +MINLINE unsigned int bitscan_reverse_uint(unsigned int a) +{ + return (unsigned int)bitscan_reverse_i((int)a); +} + +MINLINE int bitscan_reverse_clear_i(int *a) +{ + int i = bitscan_reverse_i(*a); + /* TODO(sergey): This could probably be optimized. */ + *a &= ~(1 << (sizeof(int) * 8 - i - 1)); + return i; +} + +MINLINE unsigned int bitscan_reverse_clear_uint(unsigned int *a) +{ + return (unsigned int)bitscan_reverse_clear_i((int *)a); +} + +MINLINE unsigned int highest_order_bit_uint(unsigned int n) +{ + if (n == 0) { + return 0; + } + return 1 << (sizeof(unsigned int) * 8 - bitscan_reverse_uint(n)); } MINLINE unsigned short highest_order_bit_s(unsigned short n) diff --git a/source/blender/blenlib/intern/math_rotation.c b/source/blender/blenlib/intern/math_rotation.c index 23bd5e60e22..29e7cf32ddc 100644 --- a/source/blender/blenlib/intern/math_rotation.c +++ b/source/blender/blenlib/intern/math_rotation.c @@ -511,6 +511,14 @@ void rotation_between_quats_to_quat(float q[4], const float q1[4], const float q } +/* -------------------------------------------------------------------- */ +/** \name Quaternion Angle + * + * Unlike the angle between vectors, this does NOT return the shortest angle. + * See signed functions below for this. + * + * \{ */ + float angle_normalized_qt(const float q[4]) { BLI_ASSERT_UNIT_QUAT(q); @@ -548,6 +556,64 @@ float angle_qtqt(const float q1[4], const float q2[4]) return angle_normalized_qtqt(quat1, quat2); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Quaternion Angle (Signed) + * + * Angles with quaternion calculation can exceed 180d, + * Having signed versions of these functions allows 'fabsf(angle_signed_qtqt(...))' + * to give us the shortest angle between quaternions. + * With higher precision than subtracting pi afterwards. + * + * \{ */ + +float angle_signed_normalized_qt(const float q[4]) +{ + BLI_ASSERT_UNIT_QUAT(q); + if (q[0] >= 0.0f) { + return 2.0f * saacos(q[0]); + } + else { + return -2.0f * saacos(-q[0]); + } +} + +float angle_signed_normalized_qtqt(const float q1[4], const float q2[4]) +{ + if (dot_qtqt(q1, q2) >= 0.0f) { + return angle_normalized_qtqt(q1, q2); + } + else { + float q2_copy[4]; + negate_v4_v4(q2_copy, q2); + return -angle_normalized_qtqt(q1, q2_copy); + } +} + +float angle_signed_qt(const float q[4]) +{ + float tquat[4]; + + normalize_qt_qt(tquat, q); + + return angle_signed_normalized_qt(tquat); +} + +float angle_signed_qtqt(const float q1[4], const float q2[4]) +{ + if (dot_qtqt(q1, q2) >= 0.0f) { + return angle_qtqt(q1, q2); + } + else { + float q2_copy[4]; + negate_v4_v4(q2_copy, q2); + return -angle_qtqt(q1, q2_copy); + } +} + +/** \} */ + void vec_to_quat(float q[4], const float vec[3], short axis, const short upflag) { const float eps = 1e-4f; diff --git a/source/blender/blenlib/intern/math_statistics.c b/source/blender/blenlib/intern/math_statistics.c index fd7418a8f7b..3a19f1d3603 100644 --- a/source/blender/blenlib/intern/math_statistics.c +++ b/source/blender/blenlib/intern/math_statistics.c @@ -46,7 +46,10 @@ typedef struct CovarianceData { int nbr_cos_vn; } CovarianceData; -static void covariance_m_vn_ex_task_cb(void *userdata, const int a) +static void covariance_m_vn_ex_task_cb( + void *__restrict userdata, + const int a, + const ParallelRangeTLS *__restrict UNUSED(tls)) { CovarianceData *data = userdata; const float *cos_vn = data->cos_vn; @@ -117,8 +120,14 @@ void BLI_covariance_m_vn_ex( .covfac = covfac, .n = n, .nbr_cos_vn = nbr_cos_vn, }; + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = ((nbr_cos_vn * n * n) >= 10000); BLI_task_parallel_range( - 0, n * n, &data, covariance_m_vn_ex_task_cb, (nbr_cos_vn * n * n) >= 10000); + 0, n * n, + &data, + covariance_m_vn_ex_task_cb, + &settings); } /** diff --git a/source/blender/blenlib/intern/rct.c b/source/blender/blenlib/intern/rct.c index 3adc6b30f6e..764b12431d0 100644 --- a/source/blender/blenlib/intern/rct.c +++ b/source/blender/blenlib/intern/rct.c @@ -128,7 +128,7 @@ bool BLI_rctf_isect_pt_v(const rctf *rect, const float xy[2]) /** * \returns shortest distance from \a rect to x/y (0 if inside) -*/ + */ int BLI_rcti_length_x(const rcti *rect, const int x) { diff --git a/source/blender/blenlib/intern/task.c b/source/blender/blenlib/intern/task.c index eb7f186702b..05cfe4f3972 100644 --- a/source/blender/blenlib/intern/task.c +++ b/source/blender/blenlib/intern/task.c @@ -693,7 +693,7 @@ static TaskPool *task_pool_create_ex(TaskScheduler *scheduler, /* Ensure malloc will go fine from threads, * * This is needed because we could be in main thread here - * and malloc could be non-threda safe at this point because + * and malloc could be non-thread safe at this point because * no other jobs are running. */ BLI_begin_threaded_malloc(); @@ -994,7 +994,6 @@ typedef struct ParallelRangeState { void *userdata; TaskParallelRangeFunc func; - TaskParallelRangeFuncEx func_ex; int iter; int chunk_size; @@ -1015,51 +1014,67 @@ BLI_INLINE bool parallel_range_next_iter_get( static void parallel_range_func( TaskPool * __restrict pool, void *userdata_chunk, - int threadid) + int thread_id) { ParallelRangeState * __restrict state = BLI_task_pool_userdata(pool); + ParallelRangeTLS tls = { + .thread_id = thread_id, + .userdata_chunk = userdata_chunk, + }; int iter, count; - while (parallel_range_next_iter_get(state, &iter, &count)) { - int i; - - if (state->func_ex) { - for (i = 0; i < count; ++i) { - state->func_ex(state->userdata, userdata_chunk, iter + i, threadid); - } - } - else { - for (i = 0; i < count; ++i) { - state->func(state->userdata, iter + i); - } + for (int i = 0; i < count; ++i) { + state->func(state->userdata, iter + i, &tls); } } } +static void palallel_range_single_thread(const int start, int const stop, + void *userdata, + TaskParallelRangeFunc func, + const ParallelRangeSettings *settings) +{ + void *userdata_chunk = settings->userdata_chunk; + const size_t userdata_chunk_size = settings->userdata_chunk_size; + void *userdata_chunk_local = NULL; + const bool use_userdata_chunk = (userdata_chunk_size != 0) && (userdata_chunk != NULL); + if (use_userdata_chunk) { + userdata_chunk_local = MALLOCA(userdata_chunk_size); + memcpy(userdata_chunk_local, userdata_chunk, userdata_chunk_size); + } + ParallelRangeTLS tls = { + .thread_id = 0, + .userdata_chunk = userdata_chunk_local, + }; + for (int i = start; i < stop; ++i) { + func(userdata, i, &tls); + } + if (settings->func_finalize != NULL) { + settings->func_finalize(userdata, userdata_chunk_local); + } + MALLOCA_FREE(userdata_chunk_local, userdata_chunk_size); +} + /** * This function allows to parallelized for loops in a similar way to OpenMP's 'parallel for' statement. * - * See public API doc for description of parameters. + * See public API doc of ParallelRangeSettings for description of all settings. */ -static void task_parallel_range_ex( - int start, int stop, - void *userdata, - void *userdata_chunk, - const size_t userdata_chunk_size, - TaskParallelRangeFunc func, - TaskParallelRangeFuncEx func_ex, - TaskParallelRangeFuncFinalize func_finalize, - const bool use_threading, - const bool use_dynamic_scheduling) +void BLI_task_parallel_range(const int start, const int stop, + void *userdata, + TaskParallelRangeFunc func, + const ParallelRangeSettings *settings) { TaskScheduler *task_scheduler; TaskPool *task_pool; ParallelRangeState state; int i, num_threads, num_tasks; + void *userdata_chunk = settings->userdata_chunk; + const size_t userdata_chunk_size = settings->userdata_chunk_size; void *userdata_chunk_local = NULL; void *userdata_chunk_array = NULL; - const bool use_userdata_chunk = (func_ex != NULL) && (userdata_chunk_size != 0) && (userdata_chunk != NULL); + const bool use_userdata_chunk = (userdata_chunk_size != 0) && (userdata_chunk != NULL); if (start == stop) { return; @@ -1067,63 +1082,61 @@ static void task_parallel_range_ex( BLI_assert(start < stop); if (userdata_chunk_size != 0) { - BLI_assert(func_ex != NULL && func == NULL); BLI_assert(userdata_chunk != NULL); } /* If it's not enough data to be crunched, don't bother with tasks at all, * do everything from the main thread. */ - if (!use_threading) { - if (func_ex) { - if (use_userdata_chunk) { - userdata_chunk_local = MALLOCA(userdata_chunk_size); - memcpy(userdata_chunk_local, userdata_chunk, userdata_chunk_size); - } - - for (i = start; i < stop; ++i) { - func_ex(userdata, userdata_chunk_local, i, 0); - } - - if (func_finalize) { - func_finalize(userdata, userdata_chunk_local); - } - - MALLOCA_FREE(userdata_chunk_local, userdata_chunk_size); - } - else { - for (i = start; i < stop; ++i) { - func(userdata, i); - } - } - + if (!settings->use_threading) { + palallel_range_single_thread(start, stop, + userdata, + func, + settings); return; } task_scheduler = BLI_task_scheduler_get(); - task_pool = BLI_task_pool_create(task_scheduler, &state); num_threads = BLI_task_scheduler_num_threads(task_scheduler); /* The idea here is to prevent creating task for each of the loop iterations * and instead have tasks which are evenly distributed across CPU cores and * pull next iter to be crunched using the queue. */ - num_tasks = num_threads * 2; + num_tasks = num_threads + 2; state.start = start; state.stop = stop; state.userdata = userdata; state.func = func; - state.func_ex = func_ex; state.iter = start; - if (use_dynamic_scheduling) { - state.chunk_size = 32; + switch (settings->scheduling_mode) { + case TASK_SCHEDULING_STATIC: + state.chunk_size = max_ii( + settings->min_iter_per_thread, + (stop - start) / (num_tasks)); + break; + case TASK_SCHEDULING_DYNAMIC: + /* TODO(sergey): Make it configurable from min_iter_per_thread. */ + state.chunk_size = 32; + break; } - else { - state.chunk_size = max_ii(1, (stop - start) / (num_tasks)); + + num_tasks = min_ii(num_tasks, + max_ii(1, (stop - start) / state.chunk_size)); + + if (num_tasks == 1) { + palallel_range_single_thread(start, stop, + userdata, + func, + settings); + return; } - num_tasks = min_ii(num_tasks, (stop - start) / state.chunk_size); + task_pool = BLI_task_pool_create_suspended(task_scheduler, &state); + + /* NOTE: This way we are adding a memory barrier and ensure all worker + * threads can read and modify the value, without any locks. */ atomic_fetch_and_add_int32(&state.iter, 0); if (use_userdata_chunk) { @@ -1147,98 +1160,16 @@ static void task_parallel_range_ex( BLI_task_pool_free(task_pool); if (use_userdata_chunk) { - if (func_finalize) { + if (settings->func_finalize != NULL) { for (i = 0; i < num_tasks; i++) { userdata_chunk_local = (char *)userdata_chunk_array + (userdata_chunk_size * i); - func_finalize(userdata, userdata_chunk_local); + settings->func_finalize(userdata, userdata_chunk_local); } } MALLOCA_FREE(userdata_chunk_array, userdata_chunk_size * num_tasks); } } -/** - * This function allows to parallelize for loops in a similar way to OpenMP's 'parallel for' statement. - * - * \param start First index to process. - * \param stop Index to stop looping (excluded). - * \param userdata Common userdata passed to all instances of \a func. - * \param userdata_chunk Optional, each instance of looping chunks will get a copy of this data - * (similar to OpenMP's firstprivate). - * \param userdata_chunk_size Memory size of \a userdata_chunk. - * \param func_ex Callback function (advanced version). - * \param use_threading If \a true, actually split-execute loop in threads, else just do a sequential forloop - * (allows caller to use any kind of test to switch on parallelization or not). - * \param use_dynamic_scheduling If \a true, the whole range is divided in a lot of small chunks (of size 32 currently), - * otherwise whole range is split in a few big chunks (num_threads * 2 chunks currently). - */ -void BLI_task_parallel_range_ex( - int start, int stop, - void *userdata, - void *userdata_chunk, - const size_t userdata_chunk_size, - TaskParallelRangeFuncEx func_ex, - const bool use_threading, - const bool use_dynamic_scheduling) -{ - task_parallel_range_ex( - start, stop, userdata, userdata_chunk, userdata_chunk_size, NULL, func_ex, NULL, - use_threading, use_dynamic_scheduling); -} - -/** - * A simpler version of \a BLI_task_parallel_range_ex, which does not use \a use_dynamic_scheduling, - * and does not handle 'firstprivate'-like \a userdata_chunk. - * - * \param start First index to process. - * \param stop Index to stop looping (excluded). - * \param userdata Common userdata passed to all instances of \a func. - * \param func Callback function (simple version). - * \param use_threading If \a true, actually split-execute loop in threads, else just do a sequential forloop - * (allows caller to use any kind of test to switch on parallelization or not). - */ -void BLI_task_parallel_range( - int start, int stop, - void *userdata, - TaskParallelRangeFunc func, - const bool use_threading) -{ - task_parallel_range_ex(start, stop, userdata, NULL, 0, func, NULL, NULL, use_threading, false); -} - -/** - * This function allows to parallelize for loops in a similar way to OpenMP's 'parallel for' statement, - * with an additional 'finalize' func called from calling thread once whole range have been processed. - * - * \param start First index to process. - * \param stop Index to stop looping (excluded). - * \param userdata Common userdata passed to all instances of \a func. - * \param userdata_chunk Optional, each instance of looping chunks will get a copy of this data - * (similar to OpenMP's firstprivate). - * \param userdata_chunk_size Memory size of \a userdata_chunk. - * \param func_ex Callback function (advanced version). - * \param func_finalize Callback function, called after all workers have finished, - * useful to finalize accumulative tasks. - * \param use_threading If \a true, actually split-execute loop in threads, else just do a sequential forloop - * (allows caller to use any kind of test to switch on parallelization or not). - * \param use_dynamic_scheduling If \a true, the whole range is divided in a lot of small chunks (of size 32 currently), - * otherwise whole range is split in a few big chunks (num_threads * 2 chunks currently). - */ -void BLI_task_parallel_range_finalize( - int start, int stop, - void *userdata, - void *userdata_chunk, - const size_t userdata_chunk_size, - TaskParallelRangeFuncEx func_ex, - TaskParallelRangeFuncFinalize func_finalize, - const bool use_threading, - const bool use_dynamic_scheduling) -{ - task_parallel_range_ex( - start, stop, userdata, userdata_chunk, userdata_chunk_size, NULL, func_ex, func_finalize, - use_threading, use_dynamic_scheduling); -} - #undef MALLOCA #undef MALLOCA_FREE @@ -1325,14 +1256,14 @@ void BLI_task_parallel_listbase( } task_scheduler = BLI_task_scheduler_get(); - task_pool = BLI_task_pool_create(task_scheduler, &state); + task_pool = BLI_task_pool_create_suspended(task_scheduler, &state); num_threads = BLI_task_scheduler_num_threads(task_scheduler); /* The idea here is to prevent creating task for each of the loop iterations * and instead have tasks which are evenly distributed across CPU cores and * pull next iter to be crunched using the queue. */ - num_tasks = num_threads * 2; + num_tasks = num_threads + 2; state.index = 0; state.link = listbase->first; @@ -1413,14 +1344,14 @@ void BLI_task_parallel_mempool( } task_scheduler = BLI_task_scheduler_get(); - task_pool = BLI_task_pool_create(task_scheduler, &state); + task_pool = BLI_task_pool_create_suspended(task_scheduler, &state); num_threads = BLI_task_scheduler_num_threads(task_scheduler); /* The idea here is to prevent creating task for each of the loop iterations * and instead have tasks which are evenly distributed across CPU cores and * pull next item to be crunched using the threaded-aware BLI_mempool_iter. */ - num_tasks = num_threads * 2; + num_tasks = num_threads + 2; state.userdata = userdata; state.func = func; diff --git a/source/blender/blenloader/BLO_blend_defs.h b/source/blender/blenloader/BLO_blend_defs.h index a6b06a080cc..6776b1c3338 100644 --- a/source/blender/blenloader/BLO_blend_defs.h +++ b/source/blender/blenloader/BLO_blend_defs.h @@ -75,6 +75,6 @@ enum { ENDB = BLEND_MAKE_ID('E', 'N', 'D', 'B'), }; -#define BLEN_THUMB_MEMSIZE_FILE(_x, _y) (sizeof(int) * (size_t)(2 + (_x) * (_y))) +#define BLEN_THUMB_MEMSIZE_FILE(_x, _y) (sizeof(int) * (2 + (size_t)(_x) * (size_t)(_y))) #endif /* __BLO_BLEND_DEFS_H__ */ diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 94f5f790f1c..54444ff5151 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -41,6 +41,7 @@ #include <math.h> // for fabs #include <stdarg.h> /* for va_start/end */ #include <time.h> /* for gmtime */ +#include <ctype.h> /* for isdigit */ #include "BLI_utildefines.h" #ifndef WIN32 @@ -232,6 +233,15 @@ /* Use GHash for restoring pointers by name */ #define USE_GHASH_RESTORE_POINTER +/* Define this to have verbose debug prints. */ +#define USE_DEBUG_PRINT + +#ifdef USE_DEBUG_PRINT +# define DEBUG_PRINTF(...) printf(__VA_ARGS__) +#else +# define DEBUG_PRINTF(...) +#endif + /***/ typedef struct OldNew { @@ -294,7 +304,7 @@ static OldNewMap *oldnewmap_new(void) OldNewMap *onm= MEM_callocN(sizeof(*onm), "OldNewMap"); onm->entriessize = 1024; - onm->entries = MEM_mallocN(sizeof(*onm->entries)*onm->entriessize, "OldNewMap.entries"); + onm->entries = MEM_malloc_arrayN(onm->entriessize, sizeof(*onm->entries), "OldNewMap.entries"); return onm; } @@ -541,7 +551,7 @@ void blo_split_main(ListBase *mainlist, Main *main) /* (Library.temp_index -> Main), lookup table */ const unsigned int lib_main_array_len = BLI_listbase_count(&main->library); - Main **lib_main_array = MEM_mallocN(lib_main_array_len * sizeof(*lib_main_array), __func__); + Main **lib_main_array = MEM_malloc_arrayN(lib_main_array_len, sizeof(*lib_main_array), __func__); int i = 0; for (Library *lib = main->library.first; lib; lib = lib->id.next, i++) { @@ -897,39 +907,42 @@ static void decode_blender_header(FileData *fd) { char header[SIZEOFBLENDERHEADER], num[4]; int readsize; - + /* read in the header data */ readsize = fd->read(fd, header, sizeof(header)); - - if (readsize == sizeof(header)) { - if (STREQLEN(header, "BLENDER", 7)) { - fd->flags |= FD_FLAGS_FILE_OK; - - /* what size are pointers in the file ? */ - if (header[7]=='_') { - fd->flags |= FD_FLAGS_FILE_POINTSIZE_IS_4; - if (sizeof(void *) != 4) { - fd->flags |= FD_FLAGS_POINTSIZE_DIFFERS; - } - } - else { - if (sizeof(void *) != 8) { - fd->flags |= FD_FLAGS_POINTSIZE_DIFFERS; - } + + if (readsize == sizeof(header) && + STREQLEN(header, "BLENDER", 7) && + ELEM(header[7], '_', '-') && + ELEM(header[8], 'v', 'V') && + (isdigit(header[9]) && isdigit(header[10]) && isdigit(header[11]))) + { + fd->flags |= FD_FLAGS_FILE_OK; + + /* what size are pointers in the file ? */ + if (header[7] == '_') { + fd->flags |= FD_FLAGS_FILE_POINTSIZE_IS_4; + if (sizeof(void *) != 4) { + fd->flags |= FD_FLAGS_POINTSIZE_DIFFERS; } - - /* is the file saved in a different endian - * than we need ? - */ - if (((header[8] == 'v') ? L_ENDIAN : B_ENDIAN) != ENDIAN_ORDER) { - fd->flags |= FD_FLAGS_SWITCH_ENDIAN; + } + else { + if (sizeof(void *) != 8) { + fd->flags |= FD_FLAGS_POINTSIZE_DIFFERS; } - - /* get the version number */ - memcpy(num, header + 9, 3); - num[3] = 0; - fd->fileversion = atoi(num); } + + /* is the file saved in a different endian + * than we need ? + */ + if (((header[8] == 'v') ? L_ENDIAN : B_ENDIAN) != ENDIAN_ORDER) { + fd->flags |= FD_FLAGS_SWITCH_ENDIAN; + } + + /* get the version number */ + memcpy(num, header + 9, 3); + num[3] = 0; + fd->fileversion = atoi(num); } } @@ -984,7 +997,13 @@ static int *read_file_thumbnail(FileData *fd) BLI_endian_switch_int32(&data[1]); } - if (bhead->len < BLEN_THUMB_MEMSIZE_FILE(data[0], data[1])) { + int width = data[0]; + int height = data[1]; + + if (!BLEN_THUMB_SAFE_MEMSIZE(width, height)) { + break; + } + if (bhead->len < BLEN_THUMB_MEMSIZE_FILE(width, height)) { break; } @@ -1423,23 +1442,28 @@ bool BLO_library_path_explode(const char *path, char *r_dir, char **r_group, cha BlendThumbnail *BLO_thumbnail_from_file(const char *filepath) { FileData *fd; - BlendThumbnail *data; + BlendThumbnail *data = NULL; int *fd_data; fd = blo_openblenderfile_minimal(filepath); fd_data = fd ? read_file_thumbnail(fd) : NULL; if (fd_data) { - const size_t sz = BLEN_THUMB_MEMSIZE(fd_data[0], fd_data[1]); - data = MEM_mallocN(sz, __func__); + int width = fd_data[0]; + int height = fd_data[1]; - BLI_assert((sz - sizeof(*data)) == (BLEN_THUMB_MEMSIZE_FILE(fd_data[0], fd_data[1]) - (sizeof(*fd_data) * 2))); - data->width = fd_data[0]; - data->height = fd_data[1]; - memcpy(data->rect, &fd_data[2], sz - sizeof(*data)); - } - else { - data = NULL; + /* Protect against buffer overflow vulnerability. */ + if (BLEN_THUMB_SAFE_MEMSIZE(width, height)) { + const size_t sz = BLEN_THUMB_MEMSIZE(width, height); + data = MEM_mallocN(sz, __func__); + + if (data) { + BLI_assert((sz - sizeof(*data)) == (BLEN_THUMB_MEMSIZE_FILE(width, height) - (sizeof(*fd_data) * 2))); + data->width = width; + data->height = height; + memcpy(data->rect, &fd_data[2], sz - sizeof(*data)); + } + } } blo_freefiledata(fd); @@ -1985,7 +2009,7 @@ static void test_pointer_array(FileData *fd, void **mat) len = MEM_allocN_len(*mat)/fd->filesdna->pointerlen; if (fd->filesdna->pointerlen==8 && fd->memsdna->pointerlen==4) { - ipoin=imat= MEM_mallocN(len * 4, "newmatar"); + ipoin=imat= MEM_malloc_arrayN(len, 4, "newmatar"); lpoin= *mat; while (len-- > 0) { @@ -2000,7 +2024,7 @@ static void test_pointer_array(FileData *fd, void **mat) } if (fd->filesdna->pointerlen==4 && fd->memsdna->pointerlen==8) { - lpoin = lmat = MEM_mallocN(len * 8, "newmatar"); + lpoin = lmat = MEM_malloc_arrayN(len, 8, "newmatar"); ipoin = *mat; while (len-- > 0) { @@ -3217,7 +3241,7 @@ static void direct_link_nodetree(FileData *fd, bNodeTree *ntree) ntree->adt = newdataadr(fd, ntree->adt); direct_link_animdata(fd, ntree->adt); - ntree->id.tag &= ~(LIB_TAG_ID_RECALC|LIB_TAG_ID_RECALC_DATA); + ntree->id.recalc &= ~ID_RECALC_ALL; link_list(fd, &ntree->nodes); for (node = ntree->nodes.first; node; node = node->next) { @@ -3987,6 +4011,9 @@ static void direct_link_curve(FileData *fd, Curve *cu) cu->adt= newdataadr(fd, cu->adt); direct_link_animdata(fd, cu->adt); + /* Protect against integer overflow vulnerability. */ + CLAMP(cu->len_wchar, 0, INT_MAX - 4); + cu->mat = newdataadr(fd, cu->mat); test_pointer_array(fd, (void **)&cu->mat); cu->str = newdataadr(fd, cu->str); @@ -3999,7 +4026,7 @@ static void direct_link_curve(FileData *fd, Curve *cu) else { cu->nurb.first=cu->nurb.last= NULL; - tb = MEM_callocN(MAXTEXTBOX*sizeof(TextBox), "TextBoxread"); + tb = MEM_calloc_arrayN(MAXTEXTBOX, sizeof(TextBox), "TextBoxread"); if (cu->tb) { memcpy(tb, cu->tb, cu->totbox*sizeof(TextBox)); MEM_freeN(cu->tb); @@ -4119,10 +4146,6 @@ static void lib_link_material(FileData *fd, Main *main) IDP_LibLinkProperty(ma->id.properties, fd); lib_link_animdata(fd, &ma->id, ma->adt); - /* Link ID Properties -- and copy this comment EXACTLY for easy finding - * of library blocks that implement this.*/ - IDP_LibLinkProperty(ma->id.properties, fd); - ma->ipo = newlibadr_us(fd, ma->id.lib, ma->ipo); // XXX deprecated - old animation system ma->group = newlibadr_us(fd, ma->id.lib, ma->group); @@ -4406,6 +4429,9 @@ static void direct_link_particlesettings(FileData *fd, ParticleSettings *part) for (a = 0; a < MAX_MTEX; a++) { part->mtex[a] = newdataadr(fd, part->mtex[a]); } + + /* Protect against integer overflow vulnerability. */ + CLAMP(part->trail_count, 1, 100000); } static void lib_link_particlesystems(FileData *fd, Object *ob, ID *id, ListBase *particles) @@ -5353,9 +5379,9 @@ static void direct_link_modifiers(FileData *fd, ListBase *lb) collmd->xnew = newdataadr(fd, collmd->xnew); collmd->mfaces = newdataadr(fd, collmd->mfaces); - collmd->current_x = MEM_callocN(sizeof(MVert)*collmd->numverts, "current_x"); - collmd->current_xnew = MEM_callocN(sizeof(MVert)*collmd->numverts, "current_xnew"); - collmd->current_v = MEM_callocN(sizeof(MVert)*collmd->numverts, "current_v"); + collmd->current_x = MEM_calloc_arrayN(collmd->numverts, sizeof(MVert), "current_x"); + collmd->current_xnew = MEM_calloc_arrayN(collmd->numverts, sizeof(MVert), "current_xnew"); + collmd->current_v = MEM_calloc_arrayN(collmd->numverts, sizeof(MVert), "current_v"); #endif collmd->x = NULL; @@ -5824,11 +5850,6 @@ static void lib_link_scene_collection(FileData *fd, Library *lib, SceneCollectio BLI_assert(link->data); } - for (LinkData *link = sc->filter_objects.first; link; link = link->next) { - link->data = newlibadr_us(fd, lib, link->data); - BLI_assert(link->data); - } - for (SceneCollection *nsc = sc->scene_collections.first; nsc; nsc = nsc->next) { lib_link_scene_collection(fd, lib, nsc); } @@ -6113,7 +6134,6 @@ static void direct_link_view_settings(FileData *fd, ColorManagedViewSettings *vi static void direct_link_scene_collection(FileData *fd, SceneCollection *sc) { link_list(fd, &sc->objects); - link_list(fd, &sc->filter_objects); link_list(fd, &sc->scene_collections); for (SceneCollection *nsc = sc->scene_collections.first; nsc; nsc = nsc->next) { @@ -7172,6 +7192,7 @@ static void lib_link_screen(FileData *fd, Main *main) sc->scene = newlibadr(fd, sc->id.lib, sc->scene); sc->animtimer = NULL; /* saved in rare cases */ + sc->tool_tip = NULL; sc->scrubbing = false; for (ScrArea *area = sc->areabase.first; area; area = area->next) { @@ -8458,22 +8479,16 @@ static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, const short if (fd->memfile && ELEM(bhead->code, ID_LI, ID_ID)) { const char *idname = bhead_id_name(fd, bhead); -#ifdef PRINT_DEBUG - printf("Checking %s...\n", idname); -#endif + DEBUG_PRINTF("Checking %s...\n", idname); if (bhead->code == ID_LI) { Main *libmain = fd->old_mainlist->first; /* Skip oldmain itself... */ for (libmain = libmain->next; libmain; libmain = libmain->next) { -#ifdef PRINT_DEBUG - printf("... against %s: ", libmain->curlib ? libmain->curlib->id.name : "<NULL>"); -#endif + DEBUG_PRINTF("... against %s: ", libmain->curlib ? libmain->curlib->id.name : "<NULL>"); if (libmain->curlib && STREQ(idname, libmain->curlib->id.name)) { Main *oldmain = fd->old_mainlist->first; -#ifdef PRINT_DEBUG - printf("FOUND!\n"); -#endif + DEBUG_PRINTF("FOUND!\n"); /* In case of a library, we need to re-add its main to fd->mainlist, because if we have later * a missing ID_ID, we need to get the correct lib it is linked to! * Order is crucial, we cannot bulk-add it in BLO_read_from_memfile() like it used to be... */ @@ -8487,19 +8502,13 @@ static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, const short } return blo_nextbhead(fd, bhead); } -#ifdef PRINT_DEBUG - printf("nothing...\n"); -#endif + DEBUG_PRINTF("nothing...\n"); } } else { -#ifdef PRINT_DEBUG - printf("... in %s (%s): ", main->curlib ? main->curlib->id.name : "<NULL>", main->curlib ? main->curlib->name : "<NULL>"); -#endif + DEBUG_PRINTF("... in %s (%s): ", main->curlib ? main->curlib->id.name : "<NULL>", main->curlib ? main->curlib->name : "<NULL>"); if ((id = BKE_libblock_find_name_ex(main, GS(idname), idname + 2))) { -#ifdef PRINT_DEBUG - printf("FOUND!\n"); -#endif + DEBUG_PRINTF("FOUND!\n"); /* Even though we found our linked ID, there is no guarantee its address is still the same... */ if (id != bhead->old) { oldnewmap_insert(fd->libmap, bhead->old, id, GS(id->name)); @@ -8511,9 +8520,7 @@ static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, const short } return blo_nextbhead(fd, bhead); } -#ifdef PRINT_DEBUG - printf("nothing...\n"); -#endif + DEBUG_PRINTF("nothing...\n"); } } @@ -8521,7 +8528,7 @@ static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, const short id = read_struct(fd, bhead, "lib block"); if (id) { - const short idcode = (bhead->code == ID_ID) ? GS(id->name) : bhead->code; + const short idcode = GS(id->name); /* do after read_struct, for dna reconstruct */ lb = which_libbase(main, idcode); if (lb) { @@ -8546,6 +8553,7 @@ static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, const short id->us = ID_FAKE_USERS(id); id->icon_id = 0; id->newid = NULL; /* Needed because .blend may have been saved with crap value here... */ + id->orig_id = NULL; /* this case cannot be direct_linked: it's just the ID part */ if (bhead->code == ID_ID) { @@ -8957,14 +8965,20 @@ BlendFileData *blo_read_file_internal(FileData *fd, const char *filepath) const int *data = read_file_thumbnail(fd); if (data) { - const size_t sz = BLEN_THUMB_MEMSIZE(data[0], data[1]); - bfd->main->blen_thumb = MEM_mallocN(sz, __func__); + int width = data[0]; + int height = data[1]; + + /* Protect against buffer overflow vulnerability. */ + if (BLEN_THUMB_SAFE_MEMSIZE(width, height)) { + const size_t sz = BLEN_THUMB_MEMSIZE(width, height); + bfd->main->blen_thumb = MEM_mallocN(sz, __func__); - BLI_assert((sz - sizeof(*bfd->main->blen_thumb)) == - (BLEN_THUMB_MEMSIZE_FILE(data[0], data[1]) - (sizeof(*data) * 2))); - bfd->main->blen_thumb->width = data[0]; - bfd->main->blen_thumb->height = data[1]; - memcpy(bfd->main->blen_thumb->rect, &data[2], sz - sizeof(*bfd->main->blen_thumb)); + BLI_assert((sz - sizeof(*bfd->main->blen_thumb)) == + (BLEN_THUMB_MEMSIZE_FILE(width, height) - (sizeof(*data) * 2))); + bfd->main->blen_thumb->width = width; + bfd->main->blen_thumb->height = height; + memcpy(bfd->main->blen_thumb->rect, &data[2], sz - sizeof(*bfd->main->blen_thumb)); + } } } @@ -9085,7 +9099,7 @@ static void sort_bhead_old_map(FileData *fd) fd->tot_bheadmap = tot; if (tot == 0) return; - bhs = fd->bheadmap = MEM_mallocN(tot * sizeof(struct BHeadSort), "BHeadSort"); + bhs = fd->bheadmap = MEM_malloc_arrayN(tot, sizeof(struct BHeadSort), "BHeadSort"); for (bhead = blo_firstbhead(fd); bhead; bhead = blo_nextbhead(fd, bhead), bhs++) { bhs->bhead = bhead; @@ -9923,10 +9937,6 @@ static void expand_scene_collection(FileData *fd, Main *mainvar, SceneCollection expand_doit(fd, mainvar, link->data); } - for (LinkData *link = sc->filter_objects.first; link; link = link->next) { - expand_doit(fd, mainvar, link->data); - } - for (SceneCollection *nsc= sc->scene_collections.first; nsc; nsc = nsc->next) { expand_scene_collection(fd, mainvar, nsc); } @@ -10322,7 +10332,7 @@ static void give_base_to_objects( if (flag & FILE_AUTOSELECT) { /* Note that link_object_postprocess() already checks for FILE_AUTOSELECT flag, - * but it will miss objects from non-instanciated groups... */ + * but it will miss objects from non-instantiated groups... */ if (base->flag & BASE_SELECTABLED) { base->flag |= BASE_SELECTED; BKE_scene_object_base_flag_sync_from_base(base); diff --git a/source/blender/blenloader/intern/versioning_250.c b/source/blender/blenloader/intern/versioning_250.c index 3ee6891f17f..7036470c8e4 100644 --- a/source/blender/blenloader/intern/versioning_250.c +++ b/source/blender/blenloader/intern/versioning_250.c @@ -951,7 +951,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main) if (ob->totcol && ob->matbits == NULL) { int a; - ob->matbits = MEM_callocN(sizeof(char)*ob->totcol, "ob->matbits"); + ob->matbits = MEM_calloc_arrayN(ob->totcol, sizeof(char), "ob->matbits"); for (a = 0; a < ob->totcol; a++) ob->matbits[a] = (ob->colbits & (1<<a)) != 0; } @@ -1783,7 +1783,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main) ParticleEditSettings *pset = &sce->toolsettings->particle; int a; - for (a = 0; a < PE_TOT_BRUSH; a++) + for (a = 0; a < ARRAY_SIZE(pset->brush); a++) pset->brush[a].strength /= 100.0f; } diff --git a/source/blender/blenloader/intern/versioning_260.c b/source/blender/blenloader/intern/versioning_260.c index 77542d8deb9..3ac934f7de7 100644 --- a/source/blender/blenloader/intern/versioning_260.c +++ b/source/blender/blenloader/intern/versioning_260.c @@ -2453,11 +2453,14 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main) if (sl->spacetype == SPACE_OUTLINER) { SpaceOops *so = (SpaceOops *)sl; - if (!ELEM(so->outlinevis, SO_ALL_SCENES, SO_CUR_SCENE, SO_VISIBLE, SO_SELECTED, SO_ACTIVE, - SO_SAME_TYPE, SO_GROUPS, SO_LIBRARIES, SO_SEQUENCE, SO_DATABLOCKS, - SO_USERDEF)) + if (!ELEM(so->outlinevis, + SO_SCENES, + SO_GROUPS, + SO_LIBRARIES, + SO_SEQUENCE, + SO_DATABLOCKS)) { - so->outlinevis = SO_ALL_SCENES; + so->outlinevis = SO_SCENES; } } } diff --git a/source/blender/blenloader/intern/versioning_270.c b/source/blender/blenloader/intern/versioning_270.c index bf2d5c8e326..0800437c3d2 100644 --- a/source/blender/blenloader/intern/versioning_270.c +++ b/source/blender/blenloader/intern/versioning_270.c @@ -1243,7 +1243,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) if (!MAIN_VERSION_ATLEAST(main, 277, 1)) { for (Scene *scene = main->scene.first; scene; scene = scene->id.next) { ParticleEditSettings *pset = &scene->toolsettings->particle; - for (int a = 0; a < PE_TOT_BRUSH; a++) { + for (int a = 0; a < ARRAY_SIZE(pset->brush); a++) { if (pset->brush[a].strength > 1.0f) { pset->brush[a].strength *= 0.01f; } @@ -1593,7 +1593,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) if (scene->toolsettings != NULL) { ToolSettings *ts = scene->toolsettings; ParticleEditSettings *pset = &ts->particle; - for (int a = 0; a < PE_TOT_BRUSH; a++) { + for (int a = 0; a < ARRAY_SIZE(pset->brush); a++) { if (pset->brush[a].count == 0) { pset->brush[a].count = 10; } @@ -1786,6 +1786,19 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) } } } + + /* Simple deform modifier no longer assumes Z axis (X for bend type). + * Must set previous defaults. */ + if (!DNA_struct_elem_find(fd->filesdna, "SimpleDeformModifierData", "char", "deform_axis")) { + for (Object *ob = main->object.first; ob; ob = ob->id.next) { + for (ModifierData *md = ob->modifiers.first; md; md = md->next) { + if (md->type == eModifierType_SimpleDeform) { + SimpleDeformModifierData *smd = (SimpleDeformModifierData *)md; + smd->deform_axis = 2; + } + } + } + } } } diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c index 84aab78ff18..aef1621c93f 100644 --- a/source/blender/blenloader/intern/versioning_280.c +++ b/source/blender/blenloader/intern/versioning_280.c @@ -45,6 +45,7 @@ #include "DNA_lightprobe_types.h" #include "DNA_material_types.h" #include "DNA_mesh_types.h" +#include "DNA_particle_types.h" #include "DNA_scene_types.h" #include "DNA_screen_types.h" #include "DNA_view3d_types.h" @@ -190,21 +191,21 @@ void do_versions_after_linking_280(Main *main) .collections = {NULL}, .created = 0, .suffix = "", - .flag_viewport = COLLECTION_VISIBLE | COLLECTION_SELECTABLE, - .flag_render = COLLECTION_VISIBLE | COLLECTION_SELECTABLE + .flag_viewport = COLLECTION_SELECTABLE, + .flag_render = COLLECTION_SELECTABLE }, { .collections = {NULL}, .created = 0, .suffix = " - Hide Viewport", .flag_viewport = COLLECTION_SELECTABLE, - .flag_render = COLLECTION_VISIBLE | COLLECTION_SELECTABLE + .flag_render = COLLECTION_SELECTABLE }, { .collections = {NULL}, .created = 0, .suffix = " - Hide Render", - .flag_viewport = COLLECTION_VISIBLE | COLLECTION_SELECTABLE, + .flag_viewport = COLLECTION_SELECTABLE, .flag_render = COLLECTION_SELECTABLE | COLLECTION_DISABLED }, { @@ -352,7 +353,7 @@ void do_versions_after_linking_280(Main *main) view_layer->pass_xor = srl->pass_xor; view_layer->pass_alpha_threshold = srl->pass_alpha_threshold; - BKE_freestyle_config_free(&view_layer->freestyle_config); + BKE_freestyle_config_free(&view_layer->freestyle_config, true); view_layer->freestyle_config = srl->freestyleConfig; view_layer->id_properties = srl->prop; @@ -392,13 +393,9 @@ void do_versions_after_linking_280(Main *main) for (int j = 1; j < 4; j++) { if (collections[j].created & (1 << layer)) { - layer_collection_child->flag = - collections[j].flag_render & (~COLLECTION_DISABLED); - - if (collections[j].flag_render & COLLECTION_DISABLED) { - BKE_collection_disable(view_layer, layer_collection_child); - } - + layer_collection_child->flag = COLLECTION_VIEWPORT | + COLLECTION_RENDER | + collections[j].flag_render; layer_collection_child = layer_collection_child->next; } } @@ -429,7 +426,7 @@ void do_versions_after_linking_280(Main *main) IDP_FreeProperty(srl->prop); MEM_freeN(srl->prop); } - BKE_freestyle_config_free(&srl->freestyleConfig); + BKE_freestyle_config_free(&srl->freestyleConfig, true); } } BLI_freelistN(&scene->r.layers); @@ -451,7 +448,7 @@ void do_versions_after_linking_280(Main *main) /* We only need to disable the parent collection. */ if (is_disabled) { - BKE_collection_disable(view_layer, layer_collection_parent); + layer_collection_parent->flag |= COLLECTION_DISABLED; } LayerCollection *layer_collection_child; @@ -459,11 +456,9 @@ void do_versions_after_linking_280(Main *main) for (int j = 1; j < 4; j++) { if (collections[j].created & (1 << layer)) { - layer_collection_child->flag = collections[j].flag_viewport & (~COLLECTION_DISABLED); - - if (collections[j].flag_viewport & COLLECTION_DISABLED) { - BKE_collection_disable(view_layer, layer_collection_child); - } + layer_collection_child->flag = COLLECTION_VIEWPORT | + COLLECTION_RENDER | + collections[j].flag_viewport; layer_collection_child = layer_collection_child->next; } } @@ -488,11 +483,6 @@ void do_versions_after_linking_280(Main *main) base->lay = base->object->lay; } - /* Fallback name if only one layer was found in the original file */ - if (BLI_listbase_is_single(&sc_master->scene_collections)) { - BKE_collection_rename(scene, sc_master->scene_collections.first, "Default Collection"); - } - /* remove bases once and for all */ for (Base *base = scene->base.first; base; base = base->next) { id_us_min(&base->object->id); @@ -514,7 +504,7 @@ void do_versions_after_linking_280(Main *main) if (view_layer->spacetype == SPACE_OUTLINER) { SpaceOops *soutliner = (SpaceOops *)view_layer; - soutliner->outlinevis = SO_ACT_LAYER; + soutliner->outlinevis = SO_VIEW_LAYER; if (BLI_listbase_count_ex(&layer->layer_collections, 2) == 1) { if (soutliner->treestore == NULL) { @@ -551,7 +541,7 @@ void do_versions_after_linking_280(Main *main) IDP_FreeProperty(srl->prop); MEM_freeN(srl->prop); } - BKE_freestyle_config_free(&srl->freestyleConfig); + BKE_freestyle_config_free(&srl->freestyleConfig, true); } BLI_freelistN(&scene->r.layers); } @@ -580,7 +570,9 @@ void do_versions_after_linking_280(Main *main) } } } - BLI_assert(workspace->view_layer == NULL); + /* While this should apply to most cases, it fails when reading workspaces.blend + * to get its list of workspaces without actually appending any of them. */ +// BLI_assert(workspace->view_layer == NULL); } } @@ -606,11 +598,9 @@ void do_versions_after_linking_280(Main *main) if (sc_hidden != NULL) { LayerCollection *layer_collection_master, *layer_collection_hidden; - layer_collection_master = group->view_layer->layer_collections.first; layer_collection_hidden = layer_collection_master->layer_collections.first; - - layer_collection_hidden->flag &= ~COLLECTION_VISIBLE; + layer_collection_hidden->flag |= COLLECTION_DISABLED; } } @@ -620,6 +610,38 @@ void do_versions_after_linking_280(Main *main) } } } + + { + for (Object *object = main->object.first; object; object = object->id.next) { +#ifndef VERSION_280_SUBVERSION_4 + /* If any object already has an initialized value for + * duplicator_visibility_flag it means we've already doversioned it. + * TODO(all) remove the VERSION_280_SUBVERSION_4 code once the subversion was bumped. */ + if (object->duplicator_visibility_flag != 0) { + break; + } +#endif + if (object->particlesystem.first) { + object->duplicator_visibility_flag = OB_DUPLI_FLAG_VIEWPORT; + for (ParticleSystem *psys = object->particlesystem.first; psys; psys=psys->next) { + if (psys->part->draw & PART_DRAW_EMITTER) { + object->duplicator_visibility_flag |= OB_DUPLI_FLAG_RENDER; +#ifndef VERSION_280_SUBVERSION_4 + psys->part->draw &= ~PART_DRAW_EMITTER; +#else + break; +#endif + } + } + } + else if (object->transflag & OB_DUPLI){ + object->duplicator_visibility_flag = OB_DUPLI_FLAG_VIEWPORT; + } + else { + object->duplicator_visibility_flag = OB_DUPLI_FLAG_VIEWPORT | OB_DUPLI_FLAG_RENDER; + } + } + } } static void do_version_layer_collections_idproperties(ListBase *lb) @@ -641,6 +663,25 @@ static void do_version_layer_collections_idproperties(ListBase *lb) } } +static void do_version_view_layer_visibility(ViewLayer *view_layer) +{ + LayerCollection *layer_collection; + for (layer_collection = view_layer->layer_collections.first; + layer_collection; + layer_collection = layer_collection->next) + { + if (layer_collection->flag & COLLECTION_DISABLED) { + BKE_collection_enable(view_layer, layer_collection); + layer_collection->flag &= ~COLLECTION_DISABLED; + } + + if ((layer_collection->flag & (1 << 0)) == 0) { /* !COLLECTION_VISIBLE */ + layer_collection->flag |= COLLECTION_DISABLED; + } + layer_collection->flag |= COLLECTION_VIEWPORT | COLLECTION_RENDER; + } +} + void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *main) { @@ -840,6 +881,61 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *main) } } + if (!MAIN_VERSION_ATLEAST(main, 280, 3)) { + for (Scene *scene = main->scene.first; scene; scene = scene->id.next) { + ViewLayer *view_layer; + for (view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) { + do_version_view_layer_visibility(view_layer); + } + } + + for (Group *group = main->group.first; group; group = group->id.next) { + if (group->view_layer != NULL){ + do_version_view_layer_visibility(group->view_layer); + } + } + } + + { + if (DNA_struct_elem_find(fd->filesdna, "SpaceOops", "int", "filter") == false) { + bScreen *sc; + ScrArea *sa; + SpaceLink *sl; + + /* Update files using invalid (outdated) outlinevis Outliner values. */ + for (sc = main->screen.first; sc; sc = sc->id.next) { + for (sa = sc->areabase.first; sa; sa = sa->next) { + for (sl = sa->spacedata.first; sl; sl = sl->next) { + if (sl->spacetype == SPACE_OUTLINER) { + SpaceOops *so = (SpaceOops *)sl; + + if (!ELEM(so->outlinevis, + SO_SCENES, + SO_GROUPS, + SO_LIBRARIES, + SO_SEQUENCE, + SO_DATABLOCKS, + SO_ID_ORPHANS, + SO_VIEW_LAYER, + SO_COLLECTIONS)) + { + so->outlinevis = SO_VIEW_LAYER; + } + } + } + } + } + } + } + + { + if (!DNA_struct_elem_find(fd->filesdna, "LightProbe", "float", "intensity")) { + for (LightProbe *probe = main->lightprobe.first; probe; probe = probe->id.next) { + probe->intensity = 1.0f; + } + } + } + if (!DNA_struct_find(fd->filesdna, "SpaceTopBar")) { for (bScreen *screen = main->screen.first; screen; screen = screen->id.next) { for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) { diff --git a/source/blender/blenloader/intern/versioning_defaults.c b/source/blender/blenloader/intern/versioning_defaults.c index e2d4b140311..b09c7d77e59 100644 --- a/source/blender/blenloader/intern/versioning_defaults.c +++ b/source/blender/blenloader/intern/versioning_defaults.c @@ -58,7 +58,7 @@ void BLO_update_defaults_userpref_blend(void) { /* defaults from T37518 */ - U.uiflag |= USER_ZBUF_CURSOR; + U.uiflag |= USER_DEPTH_CURSOR; U.uiflag |= USER_QUIT_PROMPT; U.uiflag |= USER_CONTINUOUS_MOUSE; @@ -203,7 +203,7 @@ void BLO_update_defaults_startup_blend(Main *bmain) ts->gpencil_ima_align = GP_PROJECT_VIEWSPACE; ParticleEditSettings *pset = &ts->particle; - for (int a = 0; a < PE_TOT_BRUSH; a++) { + for (int a = 0; a < ARRAY_SIZE(pset->brush); a++) { pset->brush[a].strength = 0.5f; pset->brush[a].count = 10; } @@ -273,6 +273,7 @@ void BLO_update_defaults_startup_blend(Main *bmain) br = (Brush *)BKE_libblock_find_name_ex(bmain, ID_BR, "Fill"); if (!br) { br = BKE_brush_add(bmain, "Fill", OB_MODE_TEXTURE_PAINT); + id_us_min(&br->id); /* fake user only */ br->imagepaint_tool = PAINT_TOOL_FILL; br->ob_mode = OB_MODE_TEXTURE_PAINT; } @@ -281,12 +282,14 @@ void BLO_update_defaults_startup_blend(Main *bmain) br = (Brush *)BKE_libblock_find_name_ex(bmain, ID_BR, "Average"); if (!br) { br = BKE_brush_add(bmain, "Average", OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT); + id_us_min(&br->id); /* fake user only */ br->vertexpaint_tool = PAINT_BLEND_AVERAGE; br->ob_mode = OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT; } br = (Brush *)BKE_libblock_find_name_ex(bmain, ID_BR, "Smear"); if (!br) { br = BKE_brush_add(bmain, "Smear", OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT); + id_us_min(&br->id); /* fake user only */ br->vertexpaint_tool = PAINT_BLEND_SMEAR; br->ob_mode = OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT; } diff --git a/source/blender/blenloader/intern/versioning_legacy.c b/source/blender/blenloader/intern/versioning_legacy.c index 156a6e3d1c0..0af1c3951ad 100644 --- a/source/blender/blenloader/intern/versioning_legacy.c +++ b/source/blender/blenloader/intern/versioning_legacy.c @@ -113,7 +113,7 @@ static void vcol_to_fcol(Mesh *me) if (me->totface == 0 || me->mcol == NULL) return; - mcoln = mcolmain = MEM_mallocN(4*sizeof(int)*me->totface, "mcoln"); + mcoln = mcolmain = MEM_malloc_arrayN(me->totface, 4 * sizeof(int), "mcoln"); mcol = (unsigned int *)me->mcol; mface = me->mface; for (a = me->totface; a > 0; a--, mface++) { @@ -1871,7 +1871,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) BKE_pose_tag_recalc(main, ob->pose); /* cannot call stuff now (pointers!), done in setup_app_data */ - ob->id.tag |= LIB_TAG_ID_RECALC_ALL; + ob->id.recalc |= ID_RECALC_ALL; /* new generic xray option */ arm = blo_do_versions_newlibadr(fd, lib, ob->data); @@ -2949,7 +2949,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) psys = MEM_callocN(sizeof(ParticleSystem), "particle_system"); psys->pointcache = BKE_ptcache_add(&psys->ptcaches); - part = psys->part = psys_new_settings("ParticleSettings", main); + part = psys->part = BKE_particlesettings_add(main, "ParticleSettings"); /* needed for proper libdata lookup */ blo_do_versions_oldnewmap_insert(fd->libmap, psys->part, psys->part, 0); @@ -3068,7 +3068,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) pset->totaddkey = 5; pset->brushtype = PE_BRUSH_NONE; - for (a = 0; a < PE_TOT_BRUSH; a++) { + for (a = 0; a < ARRAY_SIZE(pset->brush); a++) { pset->brush[a].strength = 50; pset->brush[a].size = 50; pset->brush[a].step = 10; diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index 0f9f509bfde..c5690376305 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -708,8 +708,10 @@ static void write_iddata(void *wd, const ID *id) static void write_previews(WriteData *wd, const PreviewImage *prv_orig) { - /* Never write previews when doing memsave (i.e. undo/redo)! */ - if (prv_orig && !wd->current) { + /* Note we write previews also for undo steps. It takes up some memory, + * but not doing so would causes all previews to be re-rendered after + * undo which is too expensive. */ + if (prv_orig) { PreviewImage prv = *prv_orig; /* don't write out large previews if not requested */ @@ -2594,7 +2596,6 @@ static void write_scene_collection(WriteData *wd, SceneCollection *sc) writestruct(wd, DATA, SceneCollection, 1, sc); writelist(wd, DATA, LinkData, &sc->objects); - writelist(wd, DATA, LinkData, &sc->filter_objects); for (SceneCollection *nsc = sc->scene_collections.first; nsc; nsc = nsc->next) { write_scene_collection(wd, nsc); @@ -3882,6 +3883,7 @@ static void write_global(WriteData *wd, int fileflags, Main *mainvar) memset(fg.pad, 0, sizeof(fg.pad)); memset(fg.filename, 0, sizeof(fg.filename)); memset(fg.build_hash, 0, sizeof(fg.build_hash)); + fg.pad1 = NULL; current_screen_compat(mainvar, is_undo, &screen, &scene, &render_layer); diff --git a/source/blender/bmesh/intern/bmesh_interp.c b/source/blender/bmesh/intern/bmesh_interp.c index 96b2eb17c4c..8a1090891f2 100644 --- a/source/blender/bmesh/intern/bmesh_interp.c +++ b/source/blender/bmesh/intern/bmesh_interp.c @@ -419,7 +419,10 @@ typedef struct BMLoopInterpMultiresData { float d; } BMLoopInterpMultiresData; -static void loop_interp_multires_cb(void *userdata, int ix) +static void loop_interp_multires_cb( + void *__restrict userdata, + const int ix, + const ParallelRangeTLS *__restrict UNUSED(tls)) { BMLoopInterpMultiresData *data = userdata; @@ -507,7 +510,10 @@ void BM_loop_interp_multires_ex( .axis_x = axis_x, .axis_y = axis_y, .v1 = v1, .v4 = v4, .e1 = e1, .e2 = e2, .res = res, .d = 1.0f / (float)(res - 1) }; - BLI_task_parallel_range(0, res, &data, loop_interp_multires_cb, res > 5); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = (res > 5); + BLI_task_parallel_range(0, res, &data, loop_interp_multires_cb, &settings); } /** diff --git a/source/blender/bmesh/operators/bmo_connect_pair.c b/source/blender/bmesh/operators/bmo_connect_pair.c index b474ad9fc7b..60fd9808fcb 100644 --- a/source/blender/bmesh/operators/bmo_connect_pair.c +++ b/source/blender/bmesh/operators/bmo_connect_pair.c @@ -72,14 +72,15 @@ BMO_vert_flag_test(pc->bm_bmoflag, v, VERT_EXCLUDE) == 0) #if 0 -#define ELE_TOUCH_TEST(e) \ - (CHECK_TYPE_ANY(e, BMVert *, BMEdge *, BMElem *, BMElemF *), \ - BMO_elem_flag_test(pc->bm_bmoflag, (BMElemF *)e, ELE_TOUCHED)) +#define ELE_TOUCH_TEST(e) ( \ + CHECK_TYPE_ANY(e, BMVert *, BMEdge *, BMElem *, BMElemF *), \ + BMO_elem_flag_test(pc->bm_bmoflag, (BMElemF *)e, ELE_TOUCHED) \ +) #endif -#define ELE_TOUCH_MARK(e) \ - { CHECK_TYPE_ANY(e, BMVert *, BMEdge *, BMElem *, BMElemF *); \ - BMO_elem_flag_enable(pc->bm_bmoflag, (BMElemF *)e, ELE_TOUCHED); } ((void)0) - +#define ELE_TOUCH_MARK(e) { \ + CHECK_TYPE_ANY(e, BMVert *, BMEdge *, BMElem *, BMElemF *); \ + BMO_elem_flag_enable(pc->bm_bmoflag, (BMElemF *)e, ELE_TOUCHED); \ +} ((void)0) #define ELE_TOUCH_TEST_VERT(v) BMO_vert_flag_test(pc->bm_bmoflag, v, ELE_TOUCHED) // #define ELE_TOUCH_MARK_VERT(v) BMO_vert_flag_enable(pc->bm_bmoflag, (BMElemF *)v, ELE_TOUCHED) diff --git a/source/blender/bmesh/operators/bmo_dupe.c b/source/blender/bmesh/operators/bmo_dupe.c index e35c1f3b66c..394faabbd25 100644 --- a/source/blender/bmesh/operators/bmo_dupe.c +++ b/source/blender/bmesh/operators/bmo_dupe.c @@ -389,12 +389,10 @@ void bmo_split_exec(BMesh *bm, BMOperator *op) BMOperator *splitop = op; BMOperator dupeop; - BMOperator delop; const bool use_only_faces = BMO_slot_bool_get(op->slots_in, "use_only_faces"); /* initialize our sub-operator */ BMO_op_init(bm, &dupeop, op->flag, "duplicate"); - BMO_op_init(bm, &delop, op->flag, "delete"); BMO_slot_copy(splitop, slots_in, "geom", &dupeop, slots_in, "geom"); @@ -437,24 +435,13 @@ void bmo_split_exec(BMesh *bm, BMOperator *op) } /* connect outputs of dupe to delete, exluding keep geometry */ - BMO_slot_int_set(delop.slots_in, "context", DEL_FACES); - BMO_slot_buffer_from_enabled_flag(bm, &delop, delop.slots_in, "geom", BM_ALL_NOLOOP, SPLIT_INPUT); - - BMO_op_exec(bm, &delop); + BMO_mesh_delete_oflag_context(bm, SPLIT_INPUT, DEL_FACES); /* now we make our outputs by copying the dupe output */ BMO_slot_copy(&dupeop, slots_out, "geom.out", splitop, slots_out, "geom.out"); - BMO_slot_copy(&dupeop, slots_out, "boundary_map.out", - splitop, slots_out, "boundary_map.out"); - - BMO_slot_copy(&dupeop, slots_out, "isovert_map.out", - splitop, slots_out, "isovert_map.out"); - - /* cleanup */ - BMO_op_finish(bm, &delop); BMO_op_finish(bm, &dupeop); #undef SPLIT_INPUT diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c index 2c6213dacce..35167835646 100644 --- a/source/blender/bmesh/tools/bmesh_bevel.c +++ b/source/blender/bmesh/tools/bmesh_bevel.c @@ -44,6 +44,8 @@ #include "BKE_customdata.h" #include "BKE_deform.h" +#include "eigen_capi.h" + #include "bmesh.h" #include "bmesh_bevel.h" /* own include */ @@ -58,6 +60,7 @@ #define BEVEL_SMALL_ANG DEG2RADF(10.0f) #define BEVEL_MAX_ADJUST_PCT 10.0f #define BEVEL_MAX_AUTO_ADJUST_PCT 300.0f +#define BEVEL_MATCH_SPEC_WEIGHT 0.2 /* happens far too often, uncomment for development */ // #define BEVEL_ASSERT_PROJECT @@ -139,10 +142,14 @@ typedef struct BoundVert { NewVert nv; EdgeHalf *efirst; /* first of edges attached here: in CCW order */ EdgeHalf *elast; + EdgeHalf *eon; /* the "edge between" that this is on, in offset_on_edge_between case */ EdgeHalf *ebev; /* beveled edge whose left side is attached here, if any */ int index; /* used for vmesh indexing */ + float sinratio; /* when eon set, ratio of sines of angles to eon edge */ + struct BoundVert *adjchain; /* adjustment chain or cycle link pointer */ Profile profile; /* edge profile between this and next BoundVert */ bool any_seam; /* are any of the edges attached here seams? */ + bool visited; /* used during delta adjust pass */ // int _pad; } BoundVert; @@ -192,6 +199,7 @@ typedef struct BevelParams { bool use_weights; /* bevel amount affected by weights on edges or verts */ bool loop_slide; /* should bevel prefer to slide along edges rather than keep widths spec? */ bool limit_offset; /* should offsets be limited by collisions? */ + bool offset_adjust; /* should offsets be adjusted to try to get even widths? */ const struct MDeformVert *dvert; /* vertex group array, maybe set if vertex_only */ int vertex_group; /* vertex group index, maybe set if vertex_only */ int mat_nr; /* if >= 0, material number for bevel; else material comes from adjacent faces */ @@ -207,6 +215,7 @@ static int bev_debug_flags = 0; #define DEBUG_OLD_PROJ_TO_PERP_PLANE (bev_debug_flags & 2) #define DEBUG_OLD_FLAT_MID (bev_debug_flags & 4) + /* this flag values will get set on geom we want to return in 'out' slots for edges and verts */ #define EDGE_OUT 4 #define VERT_OUT 8 @@ -260,6 +269,9 @@ static BoundVert *add_new_bound_vert(MemArena *mem_arena, VMesh *vm, const float vm->boundstart->prev = ans; } ans->profile.super_r = PRO_LINE_R; + ans->adjchain = NULL; + ans->sinratio = 1.0f; + ans->visited = false; vm->count++; return ans; } @@ -342,52 +354,6 @@ static EdgeHalf *find_other_end_edge_half(BevelParams *bp, EdgeHalf *e, BevVert return NULL; } -static bool other_edge_half_visited(BevelParams *bp, EdgeHalf *e) -{ - BevVert *bvo; - - bvo = find_bevvert(bp, e->is_rev ? e->e->v1 : e->e->v2); - if (bvo) - return bvo->visited; - else - return false; -} - -static bool edge_half_offset_changed(EdgeHalf *e) -{ - return e->offset_l != e->offset_l_spec || - e->offset_r != e->offset_r_spec; -} - -static float adjusted_rel_change(float val, float spec) -{ - float relchg; - - relchg = 0.0f; - if (val != spec) { - if (spec == 0) - relchg = 1000.0f; /* arbitrary large value */ - else - relchg = fabsf((val - spec) / spec); - } - return relchg; -} - -static float max_edge_half_offset_rel_change(BevVert *bv) -{ - int i; - float max_rel_change; - EdgeHalf *e; - - max_rel_change = 0.0f; - for (i = 0; i < bv->edgecount; i++) { - e = &bv->edges[i]; - max_rel_change = max_ff(max_rel_change, adjusted_rel_change(e->offset_l, e->offset_l_spec)); - max_rel_change = max_ff(max_rel_change, adjusted_rel_change(e->offset_r, e->offset_r_spec)); - } - return max_rel_change; -} - /* Return the next EdgeHalf after from_e that is beveled. * If from_e is NULL, find the first beveled edge. */ static EdgeHalf *next_bev(BevVert *bv, EdgeHalf *from_e) @@ -718,14 +684,18 @@ static void slide_dist(EdgeHalf *e, BMVert *v, float d, float slideco[3]) /* Is co not on the edge e? if not, return the closer end of e in ret_closer_v */ static bool is_outside_edge(EdgeHalf *e, const float co[3], BMVert **ret_closer_v) { - float d_squared; - - d_squared = dist_squared_to_line_segment_v3(co, e->e->v1->co, e->e->v2->co); - if (d_squared > BEVEL_EPSILON_BIG * BEVEL_EPSILON_BIG) { - if (len_squared_v3v3(co, e->e->v1->co) > len_squared_v3v3(co, e->e->v2->co)) - *ret_closer_v = e->e->v2; - else - *ret_closer_v = e->e->v1; + float h[3], u[3], lambda, lenu, *l1 = e->e->v1->co; + + sub_v3_v3v3(u, e->e->v2->co, l1); + sub_v3_v3v3(h, co, l1); + lenu = normalize_v3(u); + lambda = dot_v3v3(u, h); + if (lambda <= -BEVEL_EPSILON_BIG * lenu) { + *ret_closer_v = e->e->v1; + return true; + } + else if (lambda >= (1.0f + BEVEL_EPSILON_BIG) * lenu) { + *ret_closer_v = e->e->v2; return true; } else { @@ -814,10 +784,6 @@ static void offset_meet(EdgeHalf *e1, EdgeHalf *e2, BMVert *v, BMFace *f, bool e copy_v3_v3(off1a, v->co); d = max_ff(e1->offset_r, e2->offset_l); madd_v3_v3fl(off1a, norm_perp1, d); - if (e1->offset_r != d) - e1->offset_r = d; - else if (e2->offset_l != d) - e2->offset_l = d; copy_v3_v3(meetco, off1a); } else if (fabsf(ang - (float)M_PI) < BEVEL_EPSILON_ANG) { @@ -826,10 +792,6 @@ static void offset_meet(EdgeHalf *e1, EdgeHalf *e2, BMVert *v, BMFace *f, bool e * common line, at offset distance from v. */ d = max_ff(e1->offset_r, e2->offset_l); slide_dist(e2, v, d, meetco); - if (e1->offset_r != d) - e1->offset_r = d; - else if (e2->offset_l != d) - e2->offset_l = d; } else { /* Get normal to plane where meet point should be, @@ -867,7 +829,6 @@ static void offset_meet(EdgeHalf *e1, EdgeHalf *e2, BMVert *v, BMFace *f, bool e negate_v3(norm_v2); } - /* get vectors perp to each edge, perp to norm_v, and pointing into face */ cross_v3_v3v3(norm_perp1, dir1, norm_v1); cross_v3_v3v3(norm_perp2, dir2, norm_v2); @@ -887,9 +848,6 @@ static void offset_meet(EdgeHalf *e1, EdgeHalf *e2, BMVert *v, BMFace *f, bool e if (isect_kind == 0) { /* lines are collinear: we already tested for this, but this used a different epsilon */ copy_v3_v3(meetco, off1a); /* just to do something */ - d = dist_to_line_v3(meetco, v->co, BM_edge_other_vert(e2->e, v)->co); - if (fabsf(d - e2->offset_l) > BEVEL_EPSILON) - e2->offset_l = d; } else { /* The lines intersect, but is it at a reasonable place? @@ -899,11 +857,9 @@ static void offset_meet(EdgeHalf *e1, EdgeHalf *e2, BMVert *v, BMFace *f, bool e * or if the offset amount is > the edge length*/ if (e1->offset_r == 0.0f && is_outside_edge(e1, meetco, &closer_v)) { copy_v3_v3(meetco, closer_v->co); - e2->offset_l = len_v3v3(meetco, v->co); } if (e2->offset_l == 0.0f && is_outside_edge(e2, meetco, &closer_v)) { copy_v3_v3(meetco, closer_v->co); - e1->offset_r = len_v3v3(meetco, v->co); } if (edges_between && e1->offset_r > 0.0f && e2->offset_l > 0.0f) { /* Try to drop meetco to a face between e1 and e2 */ @@ -922,8 +878,6 @@ static void offset_meet(EdgeHalf *e1, EdgeHalf *e2, BMVert *v, BMFace *f, bool e break; } } - e1->offset_r = dist_to_line_v3(meetco, v->co, BM_edge_other_vert(e1->e, v)->co); - e2->offset_l = dist_to_line_v3(meetco, v->co, BM_edge_other_vert(e2->e, v)->co); } } } @@ -990,40 +944,27 @@ static bool good_offset_on_edge_between(EdgeHalf *e1, EdgeHalf *e2, EdgeHalf *em /* Calculate the best place for a meeting point for the offsets from edges e1 and e2 * on the in-between edge emid. Viewed from the vertex normal side, the CCW * order of these edges is e1, emid, e2. - * The offsets probably do not meet at a common point on emid, so need to pick - * one that causes the least problems. If the other end of one of e1 or e2 has been visited - * already, prefer to keep the offset the same on this end. - * Otherwise, pick a point between the two intersection points on emid that minimizes - * the sum of squares of errors from desired offset. */ -static void offset_on_edge_between( - BevelParams *bp, EdgeHalf *e1, EdgeHalf *e2, EdgeHalf *emid, - BMVert *v, float meetco[3]) + * Return true if we placed meetco as compromise between where two edges met. + * If we did, put ration of sines of angles in *r_sinratio too */ +static bool offset_on_edge_between( + EdgeHalf *e1, EdgeHalf *e2, EdgeHalf *emid, + BMVert *v, float meetco[3], float *r_sinratio) { - float d, ang1, ang2, sina1, sina2, lambda; + float ang1, ang2; float meet1[3], meet2[3]; - bool visited1, visited2, ok1, ok2; + bool ok1, ok2; + bool retval = false; BLI_assert(e1->is_bev && e2->is_bev && !emid->is_bev); - visited1 = other_edge_half_visited(bp, e1); - visited2 = other_edge_half_visited(bp, e2); - ok1 = offset_meet_edge(e1, emid, v, meet1, &ang1); ok2 = offset_meet_edge(emid, e2, v, meet2, &ang2); if (ok1 && ok2) { - if (visited1 && !visited2) { - copy_v3_v3(meetco, meet1); - } - else if (!visited1 && visited2) { - copy_v3_v3(meetco, meet2); - } - else { - /* find best compromise meet point */ - sina1 = sinf(ang1); - sina2 = sinf(ang2); - lambda = sina2 * sina2 / (sina1 * sina1 + sina2 * sina2); - interp_v3_v3v3(meetco, meet1, meet2, lambda); - } + mid_v3_v3v3(meetco, meet1, meet2); + if (r_sinratio) + /* ang1 should not be 0, but be paranoid */ + *r_sinratio = (ang1 == 0.0f) ? 1.0f : sinf(ang2) / sinf(ang1); + retval = true; } else if (ok1 && !ok2) { copy_v3_v3(meetco, meet1); @@ -1037,13 +978,7 @@ static void offset_on_edge_between( slide_dist(emid, v, e1->offset_r, meetco); } - /* offsets may have changed now */ - d = dist_to_line_v3(meetco, v->co, BM_edge_other_vert(e1->e, v)->co); - if (fabsf(d - e1->offset_r) > BEVEL_EPSILON) - e1->offset_r = d; - d = dist_to_line_v3(meetco, v->co, BM_edge_other_vert(e2->e, v)->co); - if (fabsf(d - e2->offset_l) > BEVEL_EPSILON) - e2->offset_l = d; + return retval; } /* Offset by e->offset in plane with normal plane_no, on left if left==true, @@ -1688,7 +1623,7 @@ static void build_boundary_vertex_only(BevelParams *bp, BevVert *bv, bool constr * Special case of build_boundary when a single edge is beveled. * The 'width adjust' part of build_boundary has been done already, * and \a efirst is the first beveled edge at vertex \a bv. -*/ + */ static void build_boundary_terminal_edge(BevelParams *bp, BevVert *bv, EdgeHalf *efirst, bool construct) { MemArena *mem_arena = bp->mem_arena; @@ -1802,6 +1737,7 @@ static void build_boundary_terminal_edge(BevelParams *bp, BevVert *bv, EdgeHalf } } +#if 0 /* Return a value that is v if v is within BEVEL_MAX_ADJUST_PCT of the spec (assumed positive), * else clamp to make it at most that far away from spec */ static float clamp_adjust(float v, float spec) @@ -1815,6 +1751,7 @@ static float clamp_adjust(float v, float spec) else return v; } +#endif /* Make a circular list of BoundVerts for bv, each of which has the coordinates * of a vertex on the boundary of the beveled vertex bv->v. @@ -1831,11 +1768,10 @@ static float clamp_adjust(float v, float spec) static void build_boundary(BevelParams *bp, BevVert *bv, bool construct) { MemArena *mem_arena = bp->mem_arena; - EdgeHalf *efirst, *e, *e2, *e3, *enip, *eip, *eother; + EdgeHalf *efirst, *e, *e2, *e3, *enip, *eip, *eon; BoundVert *v; - BevVert *bvother; VMesh *vm; - float co[3]; + float co[3], r; int nip, nnip; /* Current bevel does nothing if only one edge into a vertex */ @@ -1849,30 +1785,9 @@ static void build_boundary(BevelParams *bp, BevVert *bv, bool construct) vm = bv->vmesh; - /* Find a beveled edge to be efirst. Then for each edge, try matching widths to other end. */ + /* Find a beveled edge to be efirst */ e = efirst = next_bev(bv, NULL); BLI_assert(e->is_bev); - do { - eother = find_other_end_edge_half(bp, e, &bvother); - if (eother && bvother->visited && bp->offset_type != BEVEL_AMT_PERCENT) { - /* try to keep bevel even by matching other end offsets */ - /* sometimes, adjustment can accumulate errors so use the bp->limit_offset to - * let user limit the adjustment to within a reasonable range around spec */ - if (bp->limit_offset) { - e->offset_l = clamp_adjust(eother->offset_r, e->offset_l_spec); - e->offset_r = clamp_adjust(eother->offset_l, e->offset_r_spec); - } - else { - e->offset_l = eother->offset_r; - e->offset_r = eother->offset_l; - } - } - else { - /* reset to user spec */ - e->offset_l = e->offset_l_spec; - e->offset_r = e->offset_r_spec; - } - } while ((e = e->next) != efirst); if (bv->selcount == 1) { /* special case: only one beveled edge in */ @@ -1886,6 +1801,7 @@ static void build_boundary(BevelParams *bp, BevVert *bv, bool construct) e = efirst; do { BLI_assert(e->is_bev); + eon = NULL; /* Make the BoundVert for the right side of e; other side will be made * when the beveled edge to the left of e is handled. * Analyze edges until next beveled edge. @@ -1909,7 +1825,8 @@ static void build_boundary(BevelParams *bp, BevVert *bv, bool construct) } else if (nnip > 0) { if (bp->loop_slide && nnip == 1 && good_offset_on_edge_between(e, e2, enip, bv->v)) { - offset_on_edge_between(bp, e, e2, enip, bv->v, co); + if (offset_on_edge_between(e, e2, enip, bv->v, co, &r)) + eon = enip; } else { offset_meet(e, e2, bv->v, NULL, true, co); @@ -1918,7 +1835,8 @@ static void build_boundary(BevelParams *bp, BevVert *bv, bool construct) else { /* nip > 0 and nnip == 0 */ if (bp->loop_slide && nip == 1 && good_offset_on_edge_between(e, e2, eip, bv->v)) { - offset_on_edge_between(bp, e, e2, eip, bv->v, co); + if (offset_on_edge_between(e, e2, eip, bv->v, co, &r)) + eon = eip; } else { offset_meet(e, e2, bv->v, e->fnext, true, co); @@ -1929,6 +1847,9 @@ static void build_boundary(BevelParams *bp, BevVert *bv, bool construct) v->efirst = e; v->elast = e2; v->ebev = e2; + v->eon = eon; + if (eon) + v->sinratio = r; e->rightv = v; e2->leftv = v; for (e3 = e->next; e3 != e2; e3 = e3->next) { @@ -1958,98 +1879,328 @@ static void build_boundary(BevelParams *bp, BevVert *bv, bool construct) } } -/* Do a global pass to try to make offsets as even as possible. - * Consider this graph: - * nodes = BevVerts - * edges = { (u,v) } where u and v are nodes such that u and v - * are connected by a mesh edge that has at least one end - * whose offset does not match the user spec. - * - * Do a breadth-first search on this graph, starting from nodes - * that have any_adjust=true, and changing all - * not-already-changed offsets on EdgeHalfs to match the - * corresponding ones that changed on the other end. - * The graph is dynamic in the sense that having an offset that - * doesn't meet the user spec can be added as the search proceeds. - * We want this search to be deterministic (not dependent - * on order of processing through hash table), so as to avoid - * flicker to to different decisions made if search is different - * while dragging the offset number in the UI. So look for the - * lower vertex number when there is a choice of where to start. +#if 0 +static void print_adjust_stats(BoundVert *vstart) +{ + BoundVert *v; + EdgeHalf *eleft, *eright; + double even_residual2, spec_residual2; + double max_even_r, max_even_r_pct; + double max_spec_r, max_spec_r_pct; + double delta, delta_pct; + + printf("\nSolution analysis\n"); + even_residual2 = 0.0; + spec_residual2 = 0.0; + max_even_r = 0.0; + max_even_r_pct = 0.0; + max_spec_r = 0.0; + max_spec_r_pct = 0.0; + printf("width matching\n"); + v = vstart; + do { + if (v->adjchain != NULL) { + eright = v->efirst; + eleft = v->adjchain->elast; + delta = fabs(eright->offset_r - eleft->offset_l); + delta_pct = 100.0 * delta / eright->offset_r_spec; + printf("e%d r(%f) vs l(%f): abs(delta)=%f, delta_pct=%f\n", + BM_elem_index_get(eright->e), eright->offset_r, eleft->offset_l, delta, delta_pct); + even_residual2 += delta * delta; + if (delta > max_even_r) + max_even_r = delta; + if (delta_pct > max_even_r_pct) + max_even_r_pct = delta_pct; + } + v = v->adjchain; + } while (v && v != vstart); + + printf("spec matching\n"); + v = vstart; + do { + if (v->adjchain != NULL) { + eright = v->efirst; + eleft = v->adjchain->elast; + delta = fabs(eright->offset_r - eright->offset_r_spec); + delta_pct = 100.0 * delta / eright->offset_r_spec; + printf("e%d r(%f) vs r spec(%f): abs(delta)=%f, delta_pct=%f\n", + BM_elem_index_get(eright->e), eright->offset_r, eright->offset_r_spec, delta, delta_pct); + spec_residual2 += delta * delta; + if (delta > max_spec_r) + max_spec_r = delta; + if (delta_pct > max_spec_r_pct) + max_spec_r_pct = delta_pct; + + delta = fabs(eleft->offset_l - eleft->offset_l_spec); + delta_pct = 100.0 * delta / eright->offset_l_spec; + printf("e%d l(%f) vs l spec(%f): abs(delta)=%f, delta_pct=%f\n", + BM_elem_index_get(eright->e), eleft->offset_l, eleft->offset_l_spec, delta, delta_pct); + spec_residual2 += delta * delta; + if (delta > max_spec_r) + max_spec_r = delta; + if (delta_pct > max_spec_r_pct) + max_spec_r_pct = delta_pct; + } + v = v->adjchain; + } while (v && v != vstart); + + printf("Analysis Result:\n"); + printf("even residual2 = %f, spec residual2 = %f\n", even_residual2, spec_residual2); + printf("max even delta = %f, max as percent of spec = %f\n", max_even_r, max_even_r_pct); + printf("max spec delta = %f, max as percent of spec = %f\n", max_spec_r, max_spec_r_pct); +} +#endif + +static bool adjust_the_cycle_or_chain_fast(BoundVert *vstart, int np, bool iscycle) +{ + BoundVert *v; + EdgeHalf *eleft, *eright; + float *g; + float *g_prod; + float gprod, gprod_sum, spec_sum, p; + int i; + + g = MEM_mallocN(np * sizeof(float), "beveladjust"); + g_prod = MEM_mallocN(np * sizeof(float), "beveladjust"); + + v = vstart; + spec_sum = 0.0f; + i = 0; + do { + g[i] = v->sinratio; + if (iscycle || v->adjchain != NULL) { + spec_sum += v->efirst->offset_r; + } + else { + spec_sum += v->elast->offset_l; + } + i++; + v = v->adjchain; + } while (v && v != vstart); + + gprod = 1.00f; + gprod_sum = 1.0f; + for (i = np - 1; i > 0; i--) { + gprod *= g[i]; + g_prod[i] = gprod; + gprod_sum += gprod; + } + if (iscycle) { + gprod *= g[0]; + if (fabs(gprod - 1.0f) > BEVEL_EPSILON) { + /* fast cycle calc only works if total product is 1 */ + MEM_freeN(g); + MEM_freeN(g_prod); + return false; + } + else + g_prod[0] = 1.0f; + } + if (gprod_sum == 0.0f) { + MEM_freeN(g); + MEM_freeN(g_prod); + return false; + } + p = spec_sum / gprod_sum; + + /* apply the new offsets */ + v = vstart; + i = 0; + do { + if (iscycle || v->adjchain != NULL) { + eright = v->efirst; + eleft = v->elast; + eright->offset_r = g_prod[(i + 1) % np] * p; + if (iscycle || v != vstart) { + eleft->offset_l = v->sinratio * eright->offset_r; + } + } + else { + /* not a cycle, and last of chain */ + eleft = v->elast; + eleft->offset_l = p; + } + i++; + v = v->adjchain; + } while (v && v != vstart); + + MEM_freeN(g); + MEM_freeN(g_prod); + return true; +} + +/* Adjust the offsets for a single cycle or chain. + * For chains and some cycles, a fast solution exists. + * Otherwise, we set up and solve a linear least squares problem + * that tries to minimize the squared differences of lengths + * at each end of an edge, and (with smaller weight) the + * squared differences of the offsets from their specs. + */ +static void adjust_the_cycle_or_chain(BoundVert *vstart, bool iscycle) +{ + BoundVert *v; + EdgeHalf *eleft, *eright; + LinearSolver *solver; + double weight, val; + int i, np, nrows, row; + + np = 0; + v = vstart; + do { + np++; + v = v->adjchain; + } while (v && v != vstart); + + if (adjust_the_cycle_or_chain_fast(vstart, np, iscycle)) + return; + + nrows = iscycle ? 2 * np : 2 * np - 1; + + solver = EIG_linear_least_squares_solver_new(nrows, np, 1); + + v = vstart; + i = 0; + weight = BEVEL_MATCH_SPEC_WEIGHT; /* sqrt of factor to weight down importance of spec match */ + do { + /* except at end of chain, v's indep variable is offset_r of v->efirst */ + if (iscycle || v->adjchain != NULL) { + eright = v->efirst; + eleft = v->elast; + + /* residue i: width difference between eright and eleft of next */ + EIG_linear_solver_matrix_add(solver, i, i, 1.0); + EIG_linear_solver_right_hand_side_add(solver, 0, i, 0.0); + if (iscycle) { + EIG_linear_solver_matrix_add(solver, i > 0 ? i - 1 : np - 1, i, -v->sinratio); + } + else { + if (i > 0) + EIG_linear_solver_matrix_add(solver, i - 1, i, -v->sinratio); + } + + /* residue np + i (if cycle) else np - 1 + i: + * right offset for parm i matches its spec; weighted */ + row = iscycle ? np + i : np - 1 + i; + EIG_linear_solver_matrix_add(solver, row, i, weight); + EIG_linear_solver_right_hand_side_add(solver, 0, row, weight * eright->offset_r); + } + else { + /* not a cycle, and last of chain */ + eleft = v->elast; + /* second part of residue i for last i */ + EIG_linear_solver_matrix_add(solver, i - 1, i, -1.0); + /* residue 2 * np -2 : last spec match residue is for left offset of final parm */ + row = 2 * np - 2; + EIG_linear_solver_matrix_add(solver, row, i, weight); + EIG_linear_solver_right_hand_side_add(solver, 0, row, weight * eleft->offset_l); + } + i++; + v = v->adjchain; + } while (v && v != vstart); + EIG_linear_solver_solve(solver); + + /* Use the solution to set new widths */ + v = vstart; + i = 0; + do { + val = EIG_linear_solver_variable_get(solver, 0, i); + if (iscycle || v->adjchain != NULL) { + eright = v->efirst; + eleft = v->elast; + eright->offset_r = (float)val; + if (iscycle || v != vstart) { + eleft->offset_l = (float)(v->sinratio * val); + } + } + else { + /* not a cycle, and last of chain */ + eleft = v->elast; + eleft->offset_l = (float)val; + } + i++; + v = v->adjchain; + } while (v && v != vstart); + + EIG_linear_solver_delete(solver); +} + +/* Adjust the offsets to try to make them, as much as possible, + * have even-width bevels with offsets that match their specs. + * The problem that we can try to amelieroate is that when loop slide + * is active, the meet point will probably not be the one that makes + * both sides have their specified width. And because both ends may be + * on loop slide edges, the widths at each end could be different. * - * Note that this might not process all BevVerts, only the ones - * that need adjustment. + * It turns out that the dependent offsets either form chains or + * cycles, and we can process each of those separatey. */ static void adjust_offsets(BevelParams *bp) { - BevVert *bv, *searchbv, *bvother; - int i, searchi; + BevVert *bv, *bvcur; + BoundVert *v, *vanchor, *vchainstart, *vnext; + EdgeHalf *enext; GHashIterator giter; - EdgeHalf *e, *efirst, *eother; - GSQueue *q; - float max_rel_adj; + bool iscycle; - BLI_assert(!bp->vertex_only); + /* find and process chains and cycles of unvisited BoundVerts that have eon set */ GHASH_ITER(giter, bp->vert_hash) { - bv = BLI_ghashIterator_getValue(&giter); - bv->visited = false; - } + bv = bvcur = BLI_ghashIterator_getValue(&giter); + vanchor = bv->vmesh->boundstart; + do { + if (vanchor->visited || !vanchor->eon) + continue; - q = BLI_gsqueue_new(sizeof(BevVert *)); - /* the following loop terminates because at least one node is visited each time */ - for (;;) { - /* look for root of a connected component in search graph */ - searchbv = NULL; - searchi = -1; - GHASH_ITER(giter, bp->vert_hash) { - bv = BLI_ghashIterator_getValue(&giter); - if (!bv->visited && max_edge_half_offset_rel_change(bv) > 0.0f) { - i = BM_elem_index_get(bv->v); - if (!searchbv || i < searchi) { - searchbv = bv; - searchi = i; + /* Find one of (1) a cycle that starts and ends at v + * where each v has v->eon set and had not been visited before; + * or (2) a chain of v's where the start and end of the chain do not have + * v->eon set but all else do. + * It is OK for the first and last elements to + * have been visited before, but not any of the inner ones. + * We chain the v's together through v->adjchain, and are following + * them in left->right direction, meaning that the left side of one edge + * pairs with the right side of the next edge in the cycle or chain. */ + + /* first follow paired edges in left->right direction */ + v = vchainstart = vanchor; + iscycle = false; + while(v->eon && !v->visited && !iscycle) { + enext = find_other_end_edge_half(bp, v->efirst, &bvcur); + BLI_assert(enext != NULL); + vnext = enext->leftv; + v->adjchain = vnext; + v->visited = true; + if (vnext->visited) { + if (vnext != vchainstart) { + printf("WHOOPS, adjusting offsets, expected cycle!\n"); + break; + } + adjust_the_cycle_or_chain(vchainstart, true); + iscycle = true; } + v = vnext; } - } - if (searchbv == NULL) - break; - - BLI_gsqueue_push(q, &searchbv); - while (!BLI_gsqueue_is_empty(q)) { - BLI_gsqueue_pop(q, &bv); - /* If do this check, don't have to check for already-on-queue before push, below */ - if (bv->visited) - continue; - bv->visited = true; - build_boundary(bp, bv, false); - - e = efirst = &bv->edges[0]; - do { - eother = find_other_end_edge_half(bp, e, &bvother); - if (eother && !bvother->visited && edge_half_offset_changed(e)) { - BLI_gsqueue_push(q, &bvother); - } - } while ((e = e->next) != efirst); - } + if (!iscycle) { + /* right->left direction, changing vchainstart at each step */ + v = vchainstart; + bvcur = bv; + do { + enext = find_other_end_edge_half(bp, v->elast, &bvcur); + BLI_assert(enext != NULL); + vnext = enext->rightv; + vnext->adjchain = v; + vchainstart = vnext; + v->visited = true; + v = vnext; + } while(!v->visited && v->eon); + adjust_the_cycle_or_chain(vchainstart, false); + } + } while ((vanchor = vanchor->next) != bv->vmesh->boundstart); } - BLI_gsqueue_free(q); - /* Should we auto-limit the error accumulation? Typically, spirals can lead to 100x relative adjustments, - * and somewhat hacky mechanism of using bp->limit_offset to indicate "clamp the adjustments" is not - * obvious to users, who almost certainaly want clamping in this situation. - * The reason not to clamp always is that some models work better without it (e.g., Bent_test in regression - * suite, where relative adjust maximum is about .6). */ - if (!bp->limit_offset) { - max_rel_adj = 0.0f; - GHASH_ITER(giter, bp->vert_hash) { - bv = BLI_ghashIterator_getValue(&giter); - max_rel_adj = max_ff(max_rel_adj, max_edge_half_offset_rel_change(bv)); - } - if (max_rel_adj > BEVEL_MAX_AUTO_ADJUST_PCT / 100.0f) { - bp->limit_offset = true; - adjust_offsets(bp); - bp->limit_offset = false; - } + /* Rebuild boundaries with new width specs */ + GHASH_ITER(giter, bp->vert_hash) { + bv = BLI_ghashIterator_getValue(&giter); + build_boundary(bp, bv, false); } } @@ -3194,7 +3345,7 @@ static void bevel_build_rings(BevelParams *bp, BMesh *bm, BevVert *bv) /* If we make a poly out of verts around bv, snapping to rep frep, will uv poly have zero area? * The uv poly is made by snapping all outside-of-frep vertices to the closest edge in frep. - * Assume that this funciton is called when the only inside-of-frep vertex is vm->boundstart. + * Assume that this function is called when the only inside-of-frep vertex is vm->boundstart. * The poly will have zero area if the distance of that first vertex to some edge e is zero, and all * the other vertices snap to e or snap to an edge at a point that is essentially on e too. */ static bool is_bad_uv_poly(BevVert *bv, BMFace *frep) @@ -4929,7 +5080,7 @@ static void bevel_limit_offset(BevelParams *bp) * so we can just multiply them all by the reduction factor * of the offset to have the effect of recalculating the specs * with the new limited_offset. - */ + */ offset_factor = limited_offset / bp->offset; GHASH_ITER(giter, bp->vert_hash) { bv = BLI_ghashIterator_getValue(&giter); @@ -4979,6 +5130,7 @@ void BM_mesh_bevel( bp.use_weights = use_weights; bp.loop_slide = loop_slide; bp.limit_offset = limit_offset; + bp.offset_adjust = true; bp.dvert = dvert; bp.vertex_group = vertex_group; bp.mat_nr = mat; @@ -5015,7 +5167,7 @@ void BM_mesh_bevel( } /* Perhaps do a pass to try to even out widths */ - if (!bp.vertex_only) { + if (!bp.vertex_only && bp.offset_adjust) { adjust_offsets(&bp); } diff --git a/source/blender/collada/AnimationImporter.cpp b/source/blender/collada/AnimationImporter.cpp index 5e6fe84d3a9..65acce41046 100644 --- a/source/blender/collada/AnimationImporter.cpp +++ b/source/blender/collada/AnimationImporter.cpp @@ -816,10 +816,11 @@ void AnimationImporter::apply_matrix_curves(Object *ob, std::vector<FCurve *>& a float rot[4], loc[3], scale[3]; mat4_to_quat(rot, mat); - /*for ( int i = 0 ; i < 4 ; i ++ ) - { - rot[i] = RAD2DEGF(rot[i]); - }*/ +#if 0 + for (int i = 0 ; i < 4; i++) { + rot[i] = RAD2DEGF(rot[i]); + } +#endif copy_v3_v3(loc, mat[3]); mat4_to_size(scale, mat); diff --git a/source/blender/collada/ArmatureImporter.cpp b/source/blender/collada/ArmatureImporter.cpp index 9c8b8fc25d6..8832e0fd577 100644 --- a/source/blender/collada/ArmatureImporter.cpp +++ b/source/blender/collada/ArmatureImporter.cpp @@ -55,9 +55,10 @@ static const char *bc_get_joint_name(T *node) } -ArmatureImporter::ArmatureImporter(UnitConverter *conv, MeshImporterBase *mesh, Scene *sce, const ImportSettings *import_settings) : +ArmatureImporter::ArmatureImporter(UnitConverter *conv, MeshImporterBase *mesh, Scene *sce, ViewLayer *view_layer, const ImportSettings *import_settings) : TransformReader(conv), scene(sce), + view_layer(view_layer), unit_converter(conv), import_settings(import_settings), empty(NULL), @@ -411,7 +412,7 @@ Object *ArmatureImporter::get_empty_for_leaves() { if (empty) return empty; - empty = bc_add_object(scene, OB_EMPTY, NULL); + empty = bc_add_object(scene, view_layer, OB_EMPTY, NULL); empty->empty_drawtype = OB_EMPTY_SPHERE; return empty; @@ -586,7 +587,7 @@ Object *ArmatureImporter::create_armature_bones(SkinInfo& skin) ob_arm = skin.set_armature(shared); } else { - ob_arm = skin.create_armature(scene); //once for every armature + ob_arm = skin.create_armature(scene, view_layer); //once for every armature } // enter armature edit mode diff --git a/source/blender/collada/ArmatureImporter.h b/source/blender/collada/ArmatureImporter.h index 17173f157e5..f260bb2307c 100644 --- a/source/blender/collada/ArmatureImporter.h +++ b/source/blender/collada/ArmatureImporter.h @@ -63,6 +63,7 @@ class ArmatureImporter : private TransformReader { private: Scene *scene; + ViewLayer *view_layer; UnitConverter *unit_converter; const ImportSettings *import_settings; @@ -137,7 +138,7 @@ private: TagsMap uid_tags_map; public: - ArmatureImporter(UnitConverter *conv, MeshImporterBase *mesh, Scene *sce, const ImportSettings *import_settings); + ArmatureImporter(UnitConverter *conv, MeshImporterBase *mesh, Scene *sce, ViewLayer *view_layer, const ImportSettings *import_settings); ~ArmatureImporter(); void add_root_joint(COLLADAFW::Node *node, Object *parent); diff --git a/source/blender/collada/DocumentImporter.cpp b/source/blender/collada/DocumentImporter.cpp index d3e23f740c8..dfd662aa66c 100644 --- a/source/blender/collada/DocumentImporter.cpp +++ b/source/blender/collada/DocumentImporter.cpp @@ -108,8 +108,9 @@ DocumentImporter::DocumentImporter(bContext *C, const ImportSettings *import_set import_settings(import_settings), mImportStage(General), mContext(C), - armature_importer(&unit_converter, &mesh_importer, CTX_data_scene(C), import_settings), - mesh_importer(&unit_converter, &armature_importer, CTX_data_scene(C)), + view_layer(CTX_data_view_layer(mContext)), + armature_importer(&unit_converter, &mesh_importer, CTX_data_scene(C), view_layer, import_settings), + mesh_importer(&unit_converter, &armature_importer, CTX_data_scene(C), view_layer), anim_importer(&unit_converter, &armature_importer, CTX_data_scene(C)) { } @@ -134,7 +135,7 @@ bool DocumentImporter::import() loader.registerExtraDataCallbackHandler(ehandler); // deselect all to select new objects - BKE_view_layer_base_deselect_all(CTX_data_view_layer(mContext)); + BKE_view_layer_base_deselect_all(view_layer); std::string mFilename = std::string(this->import_settings->filepath); const std::string encodedFilename = bc_url_encode(mFilename); @@ -380,7 +381,7 @@ Object *DocumentImporter::create_camera_object(COLLADAFW::InstanceCamera *camera return NULL; } - Object *ob = bc_add_object(sce, OB_CAMERA, NULL); + Object *ob = bc_add_object(sce, view_layer, OB_CAMERA, NULL); Camera *cam = uid_camera_map[cam_uid]; Camera *old_cam = (Camera *)ob->data; ob->data = cam; @@ -396,7 +397,7 @@ Object *DocumentImporter::create_lamp_object(COLLADAFW::InstanceLight *lamp, Sce return NULL; } - Object *ob = bc_add_object(sce, OB_LAMP, NULL); + Object *ob = bc_add_object(sce, view_layer, OB_LAMP, NULL); Lamp *la = uid_lamp_map[lamp_uid]; Lamp *old_lamp = (Lamp *)ob->data; ob->data = la; @@ -512,7 +513,7 @@ std::vector<Object *> *DocumentImporter::write_node(COLLADAFW::Node *node, COLLA if (parent_node == NULL && !is_library_node) { // A Joint on root level is a skeleton without root node. // Here we add the armature "on the fly": - par = bc_add_object(sce, OB_ARMATURE, std::string("Armature").c_str()); + par = bc_add_object(sce, view_layer, OB_ARMATURE, std::string("Armature").c_str()); objects_done->push_back(par); root_objects->push_back(par); object_map.insert(std::pair<COLLADAFW::UniqueId, Object *>(node->getUniqueId(), par)); @@ -626,10 +627,10 @@ std::vector<Object *> *DocumentImporter::write_node(COLLADAFW::Node *node, COLLA if ( (geom_done + camera_done + lamp_done + controller_done + inst_done) < 1) { //Check if Object is armature, by checking if immediate child is a JOINT node. if (is_armature(node)) { - ob = bc_add_object(sce, OB_ARMATURE, name.c_str()); + ob = bc_add_object(sce, view_layer, OB_ARMATURE, name.c_str()); } else { - ob = bc_add_object(sce, OB_EMPTY, NULL); + ob = bc_add_object(sce, view_layer, OB_EMPTY, NULL); } objects_done->push_back(ob); if (parent_node == NULL) { diff --git a/source/blender/collada/DocumentImporter.h b/source/blender/collada/DocumentImporter.h index 62f76dbc022..fd61f3a68da 100644 --- a/source/blender/collada/DocumentImporter.h +++ b/source/blender/collada/DocumentImporter.h @@ -144,6 +144,7 @@ private: ImportStage mImportStage; bContext *mContext; + ViewLayer *view_layer; UnitConverter unit_converter; ArmatureImporter armature_importer; diff --git a/source/blender/collada/EffectExporter.cpp b/source/blender/collada/EffectExporter.cpp index 87392352a48..5e7f92047d3 100644 --- a/source/blender/collada/EffectExporter.cpp +++ b/source/blender/collada/EffectExporter.cpp @@ -67,7 +67,7 @@ EffectsExporter::EffectsExporter(COLLADASW::StreamWriter *sw, const ExportSettin bool EffectsExporter::hasEffects(Scene *sce) { - FOREACH_SCENE_OBJECT(scene, ob) + FOREACH_SCENE_OBJECT(sce, ob) { int a; for (a = 0; a < ob->totcol; a++) { diff --git a/source/blender/collada/GeometryExporter.cpp b/source/blender/collada/GeometryExporter.cpp index 587f30b6eb8..8dbee607b01 100644 --- a/source/blender/collada/GeometryExporter.cpp +++ b/source/blender/collada/GeometryExporter.cpp @@ -421,7 +421,6 @@ void GeometryExporter::createPolylist(short material_index, polylist.finish(); } - // creates <source> for positions void GeometryExporter::createVertsSource(std::string geom_id, Mesh *me) { diff --git a/source/blender/collada/MeshImporter.cpp b/source/blender/collada/MeshImporter.cpp index 9c95d4de695..f8cd487c355 100644 --- a/source/blender/collada/MeshImporter.cpp +++ b/source/blender/collada/MeshImporter.cpp @@ -207,7 +207,11 @@ void VCOLDataWrapper::get_vcol(int v_index, MLoopCol *mloopcol) } -MeshImporter::MeshImporter(UnitConverter *unitconv, ArmatureImporter *arm, Scene *sce) : unitconverter(unitconv), scene(sce), armature_importer(arm) { +MeshImporter::MeshImporter(UnitConverter *unitconv, ArmatureImporter *arm, Scene *sce, ViewLayer *view_layer): + unitconverter(unitconv), + scene(sce), + view_layer(view_layer), + armature_importer(arm) { } bool MeshImporter::set_poly_indices(MPoly *mpoly, MLoop *mloop, int loop_index, unsigned int *indices, int loop_count) @@ -1141,7 +1145,7 @@ Object *MeshImporter::create_mesh_object(COLLADAFW::Node *node, COLLADAFW::Insta const char *name = (id.length()) ? id.c_str() : NULL; // add object - Object *ob = bc_add_object(scene, OB_MESH, name); + Object *ob = bc_add_object(scene, view_layer, OB_MESH, name); bc_set_mark(ob); // used later for material assignement optimization diff --git a/source/blender/collada/MeshImporter.h b/source/blender/collada/MeshImporter.h index e8ae934a393..f57f57e07a7 100644 --- a/source/blender/collada/MeshImporter.h +++ b/source/blender/collada/MeshImporter.h @@ -92,6 +92,8 @@ private: UnitConverter *unitconverter; Scene *scene; + ViewLayer *view_layer; + ArmatureImporter *armature_importer; std::map<std::string, std::string> mesh_geom_map; // needed for correct shape key naming @@ -159,7 +161,7 @@ private: public: - MeshImporter(UnitConverter *unitconv, ArmatureImporter *arm, Scene *sce); + MeshImporter(UnitConverter *unitconv, ArmatureImporter *arm, Scene *sce, ViewLayer *view_layer); virtual Object *get_object_by_geom_uid(const COLLADAFW::UniqueId& geom_uid); diff --git a/source/blender/collada/SkinInfo.cpp b/source/blender/collada/SkinInfo.cpp index c29f1748efc..a2cb8237d08 100644 --- a/source/blender/collada/SkinInfo.cpp +++ b/source/blender/collada/SkinInfo.cpp @@ -159,9 +159,9 @@ void SkinInfo::set_controller(const COLLADAFW::SkinController *co) } // called from write_controller -Object *SkinInfo::create_armature(Scene *scene) +Object *SkinInfo::create_armature(Scene *scene, ViewLayer *view_layer) { - ob_arm = bc_add_object(scene, OB_ARMATURE, NULL); + ob_arm = bc_add_object(scene, view_layer, OB_ARMATURE, NULL); return ob_arm; } diff --git a/source/blender/collada/SkinInfo.h b/source/blender/collada/SkinInfo.h index e074f59cffc..a399bff9e3c 100644 --- a/source/blender/collada/SkinInfo.h +++ b/source/blender/collada/SkinInfo.h @@ -99,7 +99,7 @@ public: void set_controller(const COLLADAFW::SkinController* co); // called from write_controller - Object *create_armature(Scene *scene); + Object *create_armature(Scene *scene, ViewLayer *view_layer); Object* set_armature(Object *ob_arm); diff --git a/source/blender/collada/collada_utils.cpp b/source/blender/collada/collada_utils.cpp index 6a52027fb47..f351ebf7952 100644 --- a/source/blender/collada/collada_utils.cpp +++ b/source/blender/collada/collada_utils.cpp @@ -135,7 +135,7 @@ int bc_set_parent(Object *ob, Object *par, bContext *C, bool is_parent_space) return true; } -Object *bc_add_object(Scene *scene, int type, const char *name) +Object *bc_add_object(Scene *scene, ViewLayer *view_layer, int type, const char *name) { Object *ob = BKE_object_add_only_object(G.main, type, name); @@ -143,9 +143,6 @@ Object *bc_add_object(Scene *scene, int type, const char *name) ob->lay = scene->lay; DEG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); - /* XXX Collada should use the context scene layer, not the scene one. (dfelinto/gaia). */ - ViewLayer *view_layer = BKE_view_layer_context_active_PLACEHOLDER(scene); - LayerCollection *layer_collection = BKE_layer_collection_get_active_ensure(scene, view_layer); BKE_collection_object_add(&scene->id, layer_collection->scene_collection, ob); diff --git a/source/blender/collada/collada_utils.h b/source/blender/collada/collada_utils.h index 75e9fb5dcea..5d6e836b9c3 100644 --- a/source/blender/collada/collada_utils.h +++ b/source/blender/collada/collada_utils.h @@ -67,7 +67,7 @@ typedef std::map<COLLADAFW::TextureMapId, std::vector<MTex *> > TexIndexTextureA extern float bc_get_float_value(const COLLADAFW::FloatOrDoubleArray& array, unsigned int index); extern int bc_test_parent_loop(Object *par, Object *ob); extern int bc_set_parent(Object *ob, Object *par, bContext *C, bool is_parent_space = true); -extern Object *bc_add_object(Scene *scene, int type, const char *name); +extern Object *bc_add_object(Scene *scene, ViewLayer *view_layer, int type, const char *name); extern Mesh *bc_get_mesh_copy(const struct EvaluationContext *eval_ctx, Scene *scene, Object *ob, BC_export_mesh_type export_mesh_type, bool apply_modifiers, bool triangulate); extern Object *bc_get_assigned_armature(Object *ob); diff --git a/source/blender/compositor/intern/COM_ExecutionGroup.h b/source/blender/compositor/intern/COM_ExecutionGroup.h index 99365cdd4a8..d3b11accd96 100644 --- a/source/blender/compositor/intern/COM_ExecutionGroup.h +++ b/source/blender/compositor/intern/COM_ExecutionGroup.h @@ -64,7 +64,7 @@ typedef enum ChunkExecutionState { */ class ExecutionGroup { public: - typedef std::vector<NodeOperation*> Operations; + typedef std::vector<NodeOperation*> Operations; private: // fields diff --git a/source/blender/compositor/nodes/COM_LuminanceMatteNode.cpp b/source/blender/compositor/nodes/COM_LuminanceMatteNode.cpp index 382296a7f3a..de6ad3df030 100644 --- a/source/blender/compositor/nodes/COM_LuminanceMatteNode.cpp +++ b/source/blender/compositor/nodes/COM_LuminanceMatteNode.cpp @@ -37,14 +37,11 @@ void LuminanceMatteNode::convertToOperations(NodeConverter &converter, const Com NodeOutput *outputSocketImage = this->getOutputSocket(0); NodeOutput *outputSocketMatte = this->getOutputSocket(1); - ConvertRGBToYUVOperation *rgbToYUV = new ConvertRGBToYUVOperation(); LuminanceMatteOperation *operationSet = new LuminanceMatteOperation(); operationSet->setSettings((NodeChroma *)editorsnode->storage); - converter.addOperation(rgbToYUV); converter.addOperation(operationSet); - converter.mapInputSocket(inputSocket, rgbToYUV->getInputSocket(0)); - converter.addLink(rgbToYUV->getOutputSocket(), operationSet->getInputSocket(0)); + converter.mapInputSocket(inputSocket, operationSet->getInputSocket(0)); converter.mapOutputSocket(outputSocketMatte, operationSet->getOutputSocket(0)); SetAlphaOperation *operation = new SetAlphaOperation(); diff --git a/source/blender/compositor/operations/COM_ColorRampOperation.cpp b/source/blender/compositor/operations/COM_ColorRampOperation.cpp index 84d36034ec6..c67f906b374 100644 --- a/source/blender/compositor/operations/COM_ColorRampOperation.cpp +++ b/source/blender/compositor/operations/COM_ColorRampOperation.cpp @@ -25,7 +25,7 @@ #ifdef __cplusplus extern "C" { #endif -# include "BKE_texture.h" +# include "BKE_colorband.h" #ifdef __cplusplus } #endif @@ -48,7 +48,7 @@ void ColorRampOperation::executePixelSampled(float output[4], float x, float y, float values[4]; this->m_inputProgram->readSampled(values, x, y, sampler); - do_colorband(this->m_colorBand, values[0], output); + BKE_colorband_evaluate(this->m_colorBand, values[0], output); } void ColorRampOperation::deinitExecution() diff --git a/source/blender/compositor/operations/COM_LuminanceMatteOperation.cpp b/source/blender/compositor/operations/COM_LuminanceMatteOperation.cpp index 3be5447db3b..1401ab56fbd 100644 --- a/source/blender/compositor/operations/COM_LuminanceMatteOperation.cpp +++ b/source/blender/compositor/operations/COM_LuminanceMatteOperation.cpp @@ -22,6 +22,10 @@ #include "COM_LuminanceMatteOperation.h" #include "BLI_math.h" +extern "C" { +#include "IMB_colormanagement.h" +} + LuminanceMatteOperation::LuminanceMatteOperation() : NodeOperation() { addInputSocket(COM_DT_COLOR); @@ -43,41 +47,34 @@ void LuminanceMatteOperation::deinitExecution() void LuminanceMatteOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler) { float inColor[4]; + this->m_inputImageProgram->readSampled(inColor, x, y, sampler); const float high = this->m_settings->t1; const float low = this->m_settings->t2; + const float luminance = IMB_colormanagement_get_luminance(inColor); float alpha; - - this->m_inputImageProgram->readSampled(inColor, x, y, sampler); /* one line thread-friend algorithm: - * output[0] = max(inputValue[3], min(high, max(low, ((inColor[0] - low) / (high - low)))); + * output[0] = min(inputValue[3], min(1.0f, max(0.0f, ((luminance - low) / (high - low)))); */ /* test range */ - if (inColor[0] > high) { + if (luminance > high) { alpha = 1.0f; } - else if (inColor[0] < low) { + else if (luminance < low) { alpha = 0.0f; } else { /*blend */ - alpha = (inColor[0] - low) / (high - low); + alpha = (luminance - low) / (high - low); } - /* store matte(alpha) value in [0] to go with * COM_SetAlphaOperation and the Value output */ /* don't make something that was more transparent less transparent */ - if (alpha < inColor[3]) { - output[0] = alpha; - } - else { - /* leave now it was before */ - output[0] = inColor[3]; - } + output[0] = min_ff(alpha, inColor[3]); } diff --git a/source/blender/compositor/operations/COM_MovieClipAttributeOperation.cpp b/source/blender/compositor/operations/COM_MovieClipAttributeOperation.cpp index 0c2da8415f8..5d682352d46 100644 --- a/source/blender/compositor/operations/COM_MovieClipAttributeOperation.cpp +++ b/source/blender/compositor/operations/COM_MovieClipAttributeOperation.cpp @@ -35,6 +35,9 @@ MovieClipAttributeOperation::MovieClipAttributeOperation() : NodeOperation() void MovieClipAttributeOperation::initExecution() { + if (this->m_clip == NULL) { + return; + } float loc[2], scale, angle; loc[0] = 0.0f; loc[1] = 0.0f; diff --git a/source/blender/depsgraph/CMakeLists.txt b/source/blender/depsgraph/CMakeLists.txt index 9495321a0ff..c42d06bd0a2 100644 --- a/source/blender/depsgraph/CMakeLists.txt +++ b/source/blender/depsgraph/CMakeLists.txt @@ -53,13 +53,17 @@ set(SRC intern/builder/deg_builder_relations_rig.cc intern/builder/deg_builder_relations_view_layer.cc intern/builder/deg_builder_transitive.cc - intern/debug/deg_debug_graphviz.cc + intern/debug/deg_debug_relations_graphviz.cc + intern/debug/deg_debug_stats_gnuplot.cc intern/eval/deg_eval.cc intern/eval/deg_eval_copy_on_write.cc intern/eval/deg_eval_flush.cc + intern/eval/deg_eval_stats.cc intern/nodes/deg_node.cc intern/nodes/deg_node_component.cc + intern/nodes/deg_node_id.cc intern/nodes/deg_node_operation.cc + intern/nodes/deg_node_time.cc intern/depsgraph.cc intern/depsgraph_build.cc intern/depsgraph_debug.cc @@ -85,9 +89,12 @@ set(SRC intern/eval/deg_eval.h intern/eval/deg_eval_copy_on_write.h intern/eval/deg_eval_flush.h + intern/eval/deg_eval_stats.h intern/nodes/deg_node.h intern/nodes/deg_node_component.h + intern/nodes/deg_node_id.h intern/nodes/deg_node_operation.h + intern/nodes/deg_node_time.h intern/depsgraph.h intern/depsgraph_intern.h intern/depsgraph_types.h diff --git a/source/blender/depsgraph/DEG_depsgraph.h b/source/blender/depsgraph/DEG_depsgraph.h index 6bcbff4950b..4d3f36b5fba 100644 --- a/source/blender/depsgraph/DEG_depsgraph.h +++ b/source/blender/depsgraph/DEG_depsgraph.h @@ -140,37 +140,35 @@ void DEG_graph_on_visible_update(struct Main *bmain, Depsgraph *depsgraph); void DEG_on_visible_update(struct Main *bmain, const bool do_time); /* Tag given ID for an update in all the dependency graphs. */ -enum { +typedef enum eDepsgraph_Tag { /* Object transformation changed, corresponds to OB_RECALC_OB. */ DEG_TAG_TRANSFORM = (1 << 0), - - /* Object geoemtry changed, corresponds to OB_RECALC_DATA. */ + /* Object geometry changed, corresponds to OB_RECALC_DATA. */ DEG_TAG_GEOMETRY = (1 << 1), - /* Time changed and animation is to be re-evaluated, OB_RECALC_TIME. */ DEG_TAG_TIME = (1 << 2), - /* Particle system changed. */ - DEG_TAG_PSYSC_REDO = (1 << 3), + DEG_TAG_PSYS_REDO = (1 << 3), DEG_TAG_PSYS_RESET = (1 << 4), DEG_TAG_PSYS_TYPE = (1 << 5), DEG_TAG_PSYS_CHILD = (1 << 6), DEG_TAG_PSYS_PHYS = (1 << 7), - DEG_TAG_PSYS = ((1 << 3) | (1 << 4) | (1 << 5) | (1 << 6) | (1 << 7)), - + DEG_TAG_PSYS_ALL = (DEG_TAG_PSYS_REDO | + DEG_TAG_PSYS_RESET | + DEG_TAG_PSYS_TYPE | + DEG_TAG_PSYS_CHILD | + DEG_TAG_PSYS_PHYS), /* Update copy on write component without flushing down the road. */ DEG_TAG_COPY_ON_WRITE = (1 << 8), - /* Tag shading components for update. * Only parameters of material changed). */ DEG_TAG_SHADING_UPDATE = (1 << 9), DEG_TAG_SELECT_UPDATE = (1 << 10), DEG_TAG_BASE_FLAGS_UPDATE = (1 << 11), - /* Only inform editors about the change. Don't modify datablock itself. */ DEG_TAG_EDITORS_UPDATE = (1 << 12), -}; +} eDepsgraph_Tag; void DEG_id_tag_update(struct ID *id, int flag); void DEG_id_tag_update_ex(struct Main *bmain, struct ID *id, int flag); @@ -196,6 +194,7 @@ void DEG_graph_flush_update(struct Main *bmain, Depsgraph *depsgraph); * editors about this. */ void DEG_ids_check_recalc(struct Main *bmain, + struct Depsgraph *depsgraph, struct Scene *scene, struct ViewLayer *view_layer, bool time); @@ -250,6 +249,7 @@ bool DEG_needs_eval(Depsgraph *graph); typedef struct DEGEditorUpdateContext { struct Main *bmain; + struct Depsgraph *depsgraph; struct Scene *scene; struct ViewLayer *view_layer; } DEGEditorUpdateContext; diff --git a/source/blender/depsgraph/DEG_depsgraph_debug.h b/source/blender/depsgraph/DEG_depsgraph_debug.h index bd03874436b..363749dab26 100644 --- a/source/blender/depsgraph/DEG_depsgraph_debug.h +++ b/source/blender/depsgraph/DEG_depsgraph_debug.h @@ -53,7 +53,14 @@ void DEG_stats_simple(const struct Depsgraph *graph, /* ************************************************ */ /* Diagram-Based Graph Debugging */ -void DEG_debug_graphviz(const struct Depsgraph *graph, FILE *stream, const char *label, bool show_eval); +void DEG_debug_relations_graphviz(const struct Depsgraph *graph, + FILE *stream, + const char *label); + +void DEG_debug_stats_gnuplot(const struct Depsgraph *graph, + FILE *stream, + const char *label, + const char *output_filename); /* ************************************************ */ diff --git a/source/blender/depsgraph/DEG_depsgraph_query.h b/source/blender/depsgraph/DEG_depsgraph_query.h index 7771d35d581..adfda27117e 100644 --- a/source/blender/depsgraph/DEG_depsgraph_query.h +++ b/source/blender/depsgraph/DEG_depsgraph_query.h @@ -53,35 +53,44 @@ extern "C" { bool DEG_id_type_tagged(struct Main *bmain, short id_type); /* Get additional evaluation flags for the given ID. */ -short DEG_get_eval_flags_for_id(struct Depsgraph *graph, struct ID *id); +short DEG_get_eval_flags_for_id(const struct Depsgraph *graph, struct ID *id); /* Get scene the despgraph is created for. */ -struct Scene *DEG_get_evaluated_scene(struct Depsgraph *graph); +struct Scene *DEG_get_evaluated_scene(const struct Depsgraph *graph); /* Get scene layer the despgraph is created for. */ -struct ViewLayer *DEG_get_evaluated_view_layer(struct Depsgraph *graph); +struct ViewLayer *DEG_get_evaluated_view_layer(const struct Depsgraph *graph); /* Get evaluated version of object for given original one. */ -struct Object *DEG_get_evaluated_object(struct Depsgraph *depsgraph, struct Object *object); +struct Object *DEG_get_evaluated_object(const struct Depsgraph *depsgraph, + struct Object *object); /* Get evaluated version of given ID datablock. */ -struct ID *DEG_get_evaluated_id(struct Depsgraph *depsgraph, struct ID *id); +struct ID *DEG_get_evaluated_id(const struct Depsgraph *depsgraph, + struct ID *id); /* ************************ DEG iterators ********************* */ enum { - DEG_ITER_OBJECT_FLAG_SET = (1 << 0), - DEG_ITER_OBJECT_FLAG_DUPLI = (1 << 1), - - DEG_ITER_OBJECT_FLAG_ALL = (DEG_ITER_OBJECT_FLAG_SET | DEG_ITER_OBJECT_FLAG_DUPLI), + DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY = (1 << 0), + DEG_ITER_OBJECT_FLAG_LINKED_INDIRECTLY = (1 << 1), + DEG_ITER_OBJECT_FLAG_LINKED_VIA_SET = (1 << 2), + DEG_ITER_OBJECT_FLAG_VISIBLE = (1 << 3), + DEG_ITER_OBJECT_FLAG_DUPLI = (1 << 4), }; -typedef struct DEGOIterObjectData { +typedef enum eDepsObjectIteratorMode { + DEG_ITER_OBJECT_MODE_VIEWPORT = 0, + DEG_ITER_OBJECT_MODE_RENDER = 1, +} eDepsObjectIteratorMode; + +typedef struct DEGObjectIterData { struct Depsgraph *graph; struct Scene *scene; struct EvaluationContext eval_ctx; int flag; + eDepsObjectIteratorMode mode; /* **** Iteration over dupli-list. *** */ @@ -103,16 +112,22 @@ typedef struct DEGOIterObjectData { /* **** Iteration ober ID nodes **** */ size_t id_node_index; size_t num_id_nodes; -} DEGOIterObjectData; +} DEGObjectIterData; -void DEG_iterator_objects_begin(struct BLI_Iterator *iter, DEGOIterObjectData *data); +void DEG_iterator_objects_begin(struct BLI_Iterator *iter, DEGObjectIterData *data); void DEG_iterator_objects_next(struct BLI_Iterator *iter); void DEG_iterator_objects_end(struct BLI_Iterator *iter); -#define DEG_OBJECT_ITER(graph_, instance_, flag_) \ +/** + * Note: Be careful with DEG_ITER_OBJECT_FLAG_LINKED_INDIRECTLY objects. + * Although they are available they have no overrides (collection_properties) + * and will crash if you try to access it. + */ +#define DEG_OBJECT_ITER(graph_, instance_, mode_, flag_) \ { \ - DEGOIterObjectData data_ = { \ + DEGObjectIterData data_ = { \ .graph = (graph_), \ + .mode = (mode_), \ .flag = (flag_), \ }; \ \ @@ -125,6 +140,19 @@ void DEG_iterator_objects_end(struct BLI_Iterator *iter); ITER_END \ } +/** + * Depsgraph objects iterator for draw manager and final render + */ +#define DEG_OBJECT_ITER_FOR_RENDER_ENGINE(graph_, instance_, mode_) \ + DEG_OBJECT_ITER(graph_, instance_, mode_, \ + DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY | \ + DEG_ITER_OBJECT_FLAG_LINKED_VIA_SET | \ + DEG_ITER_OBJECT_FLAG_VISIBLE | \ + DEG_ITER_OBJECT_FLAG_DUPLI) + +#define DEG_OBJECT_ITER_FOR_RENDER_ENGINE_END \ + DEG_OBJECT_ITER_END + /* ************************ DEG traversal ********************* */ typedef void (*DEGForeachIDCallback)(ID *id, void *user_data); diff --git a/source/blender/depsgraph/intern/builder/deg_builder.cc b/source/blender/depsgraph/intern/builder/deg_builder.cc index 20a93673350..2fcad233044 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder.cc @@ -36,6 +36,7 @@ #include "intern/depsgraph.h" #include "intern/depsgraph_types.h" #include "intern/nodes/deg_node.h" +#include "intern/nodes/deg_node_id.h" #include "util/deg_util_foreach.h" @@ -52,7 +53,7 @@ void deg_graph_build_finalize(Main *bmain, Depsgraph *graph) foreach (IDDepsNode *id_node, graph->id_nodes) { ID *id = id_node->id_orig; id_node->finalize_build(graph); - if ((id->tag & LIB_TAG_ID_RECALC_ALL)) { + if ((id->recalc & ID_RECALC_ALL)) { id_node->tag_update(graph); } /* TODO(sergey): This is not ideal at all, since this forces diff --git a/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc b/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc index 3eed0697b5e..e30b9b44490 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc @@ -46,17 +46,38 @@ namespace DEG { -void deg_graph_detect_cycles(Depsgraph *graph) +typedef enum eCyclicCheckVisitedState { + /* Not is not visited at all during traversal. */ + NODE_NOT_VISITED = 0, + /* Node has been visited during traversal and not in current stack. */ + NODE_VISITED = 1, + /* Node has been visited during traversal and is in current stack. */ + NODE_IN_STACK = 2, +} eCyclicCheckVisitedState; + +BLI_INLINE void set_node_visited_state(DepsNode *node, + eCyclicCheckVisitedState state) { - enum { - /* Not is not visited at all during traversal. */ - NODE_NOT_VISITED = 0, - /* Node has been visited during traversal and not in current stack. */ - NODE_VISITED = 1, - /* Node has been visited during traversal and is in current stack. */ - NODE_IN_STACK = 2, - }; + node->done = (node->done & ~0x3) | (int)state; +} + +BLI_INLINE eCyclicCheckVisitedState get_node_visited_state(DepsNode *node) +{ + return (eCyclicCheckVisitedState)(node->done & 0x3); +} + +BLI_INLINE void set_node_num_visited_children(DepsNode *node, int num_children) +{ + node->done = (node->done & 0x3) | (num_children << 2); +} + +BLI_INLINE int get_node_num_visited_children(DepsNode *node) +{ + return node->done >> 2; +} +void deg_graph_detect_cycles(Depsgraph *graph) +{ struct StackEntry { OperationDepsNode *node; StackEntry *from; @@ -73,29 +94,31 @@ void deg_graph_detect_cycles(Depsgraph *graph) has_inlinks = true; } } + node->done = 0; if (has_inlinks == false) { StackEntry entry; entry.node = node; entry.from = NULL; entry.via_relation = NULL; BLI_stack_push(traversal_stack, &entry); - node->tag = NODE_IN_STACK; + set_node_visited_state(node, NODE_IN_STACK); } else { - node->tag = NODE_NOT_VISITED; + set_node_visited_state(node, NODE_NOT_VISITED); } - node->done = 0; } while (!BLI_stack_is_empty(traversal_stack)) { StackEntry *entry = (StackEntry *)BLI_stack_peek(traversal_stack); OperationDepsNode *node = entry->node; bool all_child_traversed = true; - for (int i = node->done; i < node->outlinks.size(); ++i) { + const int num_visited = get_node_num_visited_children(node); + for (int i = num_visited; i < node->outlinks.size(); ++i) { DepsRelation *rel = node->outlinks[i]; if (rel->to->type == DEG_NODE_TYPE_OPERATION) { OperationDepsNode *to = (OperationDepsNode *)rel->to; - if (to->tag == NODE_IN_STACK) { + eCyclicCheckVisitedState to_state = get_node_visited_state(to); + if (to_state == NODE_IN_STACK) { printf("Dependency cycle detected:\n"); printf(" '%s' depends on '%s' through '%s'\n", to->full_identifier().c_str(), @@ -114,21 +137,21 @@ void deg_graph_detect_cycles(Depsgraph *graph) /* TODO(sergey): So called russian roulette cycle solver. */ rel->flag |= DEPSREL_FLAG_CYCLIC; } - else if (to->tag == NODE_NOT_VISITED) { + else if (to_state == NODE_NOT_VISITED) { StackEntry new_entry; new_entry.node = to; new_entry.from = entry; new_entry.via_relation = rel; BLI_stack_push(traversal_stack, &new_entry); - to->tag = NODE_IN_STACK; + set_node_visited_state(node, NODE_IN_STACK); all_child_traversed = false; - node->done = i; + set_node_num_visited_children(node, i); break; } } } if (all_child_traversed) { - node->tag = NODE_VISITED; + set_node_visited_state(node, NODE_VISITED); BLI_stack_discard(traversal_stack); } } diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc index 8fbd1e7a46d..ddae761cea0 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc @@ -92,7 +92,6 @@ extern "C" { #include "BKE_particle.h" #include "BKE_rigidbody.h" #include "BKE_sound.h" -#include "BKE_texture.h" #include "BKE_tracking.h" #include "BKE_world.h" @@ -107,9 +106,11 @@ extern "C" { #include "intern/eval/deg_eval_copy_on_write.h" #include "intern/nodes/deg_node.h" #include "intern/nodes/deg_node_component.h" +#include "intern/nodes/deg_node_id.h" #include "intern/nodes/deg_node_operation.h" #include "intern/depsgraph_types.h" #include "intern/depsgraph_intern.h" + #include "util/deg_util_foreach.h" namespace DEG { @@ -427,12 +428,24 @@ void DepsgraphNodeBuilder::build_group(Group *group) return; } group_id->tag |= LIB_TAG_DOIT; - - LINKLIST_FOREACH(Base *, base, &group->view_layer->object_bases) { + /* Build group objects. */ + BLI_LISTBASE_FOREACH (Base *, base, &group->view_layer->object_bases) { build_object(NULL, base->object, DEG_ID_LINKED_INDIRECTLY); } - - build_view_layer_collections(&group->id, group->view_layer); + /* Operation to evaluate the whole view layer. + * + * NOTE: We re-use DONE opcode even though the function does everything. + * This way we wouldn't need to worry about possible relations from DONE, + * regardless whether it's a group or scene or something else. + */ + add_id_node(group_id); + Group *group_cow = get_cow_datablock(group); + add_operation_node(group_id, + DEG_NODE_TYPE_LAYER_COLLECTIONS, + function_bind(BKE_group_eval_view_layers, + _1, + group_cow), + DEG_OPCODE_VIEW_LAYER_DONE); } void DepsgraphNodeBuilder::build_object(Base *base, @@ -686,7 +699,7 @@ void DepsgraphNodeBuilder::build_animdata(ID *id) } /* drivers */ - LINKLIST_FOREACH (FCurve *, fcu, &adt->drivers) { + BLI_LISTBASE_FOREACH (FCurve *, fcu, &adt->drivers) { /* create driver */ build_driver(id, fcu); } @@ -804,7 +817,7 @@ void DepsgraphNodeBuilder::build_rigidbody(Scene *scene) /* objects - simulation participants */ if (rbw->group) { - LINKLIST_FOREACH (Base *, base, &rbw->group->view_layer->object_bases) { + BLI_LISTBASE_FOREACH (Base *, base, &rbw->group->view_layer->object_bases) { Object *object = base->object; if (!object || (object->type != OB_MESH)) @@ -857,7 +870,7 @@ void DepsgraphNodeBuilder::build_particles(Object *object) DEG_OPCODE_PARTICLE_SYSTEM_EVAL_INIT); /* particle systems */ - LINKLIST_FOREACH (ParticleSystem *, psys, &object->particlesystem) { + BLI_LISTBASE_FOREACH (ParticleSystem *, psys, &object->particlesystem) { ParticleSettings *part = psys->part; /* Build particle settings operations. @@ -972,8 +985,8 @@ void DepsgraphNodeBuilder::build_obdata_geom(Object *object) // TODO: "Done" operation - /* Cloyth modifier. */ - LINKLIST_FOREACH (ModifierData *, md, &object->modifiers) { + /* Cloth modifier. */ + BLI_LISTBASE_FOREACH (ModifierData *, md, &object->modifiers) { if (md->type == eModifierType_Cloth) { build_cloth(object); } @@ -1218,7 +1231,7 @@ void DepsgraphNodeBuilder::build_nodetree(bNodeTree *ntree) ntree), DEG_OPCODE_MATERIAL_UPDATE); /* nodetree's nodes... */ - LINKLIST_FOREACH (bNode *, bnode, &ntree->nodes) { + BLI_LISTBASE_FOREACH (bNode *, bnode, &ntree->nodes) { ID *id = bnode->id; if (id == NULL) { continue; diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h index c9bdd194227..cc8ad08ea3b 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h @@ -102,7 +102,7 @@ struct DepsgraphNodeBuilder { template<typename T> T *get_orig_datablock(const T *cow) const { if (DEG_depsgraph_use_copy_on_write()) { - return (T *)cow->id.newid; + return (T *)cow->id.orig_id; } else { return (T *)cow; diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes_layer_collection.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes_layer_collection.cc index 79316e47022..137a79e7276 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes_layer_collection.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes_layer_collection.cc @@ -94,7 +94,7 @@ void DepsgraphNodeBuilder::build_layer_collections(ID *owner_id, ListBase *layer_collections, LayerCollectionState *state) { - LINKLIST_FOREACH (LayerCollection *, layer_collection, layer_collections) { + BLI_LISTBASE_FOREACH (LayerCollection *, layer_collection, layer_collections) { build_layer_collection(owner_id, layer_collection, state); } } diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc index 531ea55cf5c..2fc42efa440 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc @@ -247,7 +247,7 @@ void DepsgraphNodeBuilder::build_rig(Object *object) op_node->set_as_exit(); /* bones */ - LINKLIST_FOREACH (bPoseChannel *, pchan, &object_cow->pose->chanbase) { + BLI_LISTBASE_FOREACH (bPoseChannel *, pchan, &object_cow->pose->chanbase) { /* Node for bone evaluation. */ op_node = add_operation_node(&object->id, DEG_NODE_TYPE_BONE, pchan->name, NULL, DEG_OPCODE_BONE_LOCAL); @@ -293,7 +293,7 @@ void DepsgraphNodeBuilder::build_rig(Object *object) * as in ik-tree building * - Animated chain-lengths are a problem. */ - LINKLIST_FOREACH (bConstraint *, con, &pchan->constraints) { + BLI_LISTBASE_FOREACH (bConstraint *, con, &pchan->constraints) { switch (con->type) { case CONSTRAINT_TYPE_KINEMATIC: build_ik_pose(object, pchan, con); @@ -347,7 +347,7 @@ void DepsgraphNodeBuilder::build_proxy_rig(Object *object) object_cow), DEG_OPCODE_POSE_INIT); op_node->set_as_entry(); - LINKLIST_FOREACH (bPoseChannel *, pchan, &object_cow->pose->chanbase) { + BLI_LISTBASE_FOREACH (bPoseChannel *, pchan, &object_cow->pose->chanbase) { /* Local bone transform. */ op_node = add_operation_node(&object->id, DEG_NODE_TYPE_BONE, diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes_view_layer.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes_view_layer.cc index 49772c4f852..4ca19f4e14f 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes_view_layer.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes_view_layer.cc @@ -84,7 +84,7 @@ void DepsgraphNodeBuilder::build_view_layer( * otherwise remapping will not replace objects with their CoW versions * for CoW bases. */ - LINKLIST_FOREACH(Base *, base, &view_layer->object_bases) { + BLI_LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) { Object *object = base->object; add_id_node(&object->id, false); } @@ -145,15 +145,15 @@ void DepsgraphNodeBuilder::build_view_layer( build_gpencil(scene->gpd); } /* Cache file. */ - LINKLIST_FOREACH (CacheFile *, cachefile, &bmain_->cachefiles) { + BLI_LISTBASE_FOREACH (CacheFile *, cachefile, &bmain_->cachefiles) { build_cachefile(cachefile); } /* Masks. */ - LINKLIST_FOREACH (Mask *, mask, &bmain_->mask) { + BLI_LISTBASE_FOREACH (Mask *, mask, &bmain_->mask) { build_mask(mask); } /* Movie clips. */ - LINKLIST_FOREACH (MovieClip *, clip, &bmain_->movieclip) { + BLI_LISTBASE_FOREACH (MovieClip *, clip, &bmain_->movieclip) { build_movieclip(clip); } /* Collections. */ diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc index 14dedef2601..cfb73ecc2ad 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc @@ -89,7 +89,6 @@ extern "C" { #include "BKE_particle.h" #include "BKE_rigidbody.h" #include "BKE_sound.h" -#include "BKE_texture.h" #include "BKE_tracking.h" #include "BKE_world.h" @@ -105,7 +104,9 @@ extern "C" { #include "intern/nodes/deg_node.h" #include "intern/nodes/deg_node_component.h" +#include "intern/nodes/deg_node_id.h" #include "intern/nodes/deg_node_operation.h" +#include "intern/nodes/deg_node_time.h" #include "intern/depsgraph_intern.h" #include "intern/depsgraph_types.h" @@ -193,7 +194,7 @@ static bool particle_system_depends_on_time(ParticleSystem *psys) static bool object_particles_depends_on_time(Object *object) { - LINKLIST_FOREACH (ParticleSystem *, psys, &object->particlesystem) { + BLI_LISTBASE_FOREACH (ParticleSystem *, psys, &object->particlesystem) { if (particle_system_depends_on_time(psys)) { return true; } @@ -346,7 +347,7 @@ void DepsgraphRelationBuilder::add_forcefield_relations( { ListBase *effectors = pdInitEffectors(NULL, scene, object, psys, eff, false); if (effectors != NULL) { - LINKLIST_FOREACH(EffectorCache *, eff, effectors) { + BLI_LISTBASE_FOREACH (EffectorCache *, eff, effectors) { if (eff->ob != object) { ComponentKey eff_key(&eff->ob->id, DEG_NODE_TYPE_TRANSFORM); add_relation(eff_key, key, name); @@ -427,15 +428,13 @@ void DepsgraphRelationBuilder::build_group(Object *object, Group *group) DEG_OPCODE_TRANSFORM_LOCAL); if (!group_done) { - LINKLIST_FOREACH(Base *, base, &group->view_layer->object_bases) { + BLI_LISTBASE_FOREACH (Base *, base, &group->view_layer->object_bases) { build_object(NULL, base->object); } - - build_view_layer_collections(&group->id, group->view_layer); group_id->tag |= LIB_TAG_DOIT; } - LINKLIST_FOREACH (Base *, base, &group->view_layer->object_bases) { + BLI_LISTBASE_FOREACH (Base *, base, &group->view_layer->object_bases) { ComponentKey dupli_transform_key(&base->object->id, DEG_NODE_TYPE_TRANSFORM); add_relation(dupli_transform_key, object_local_transform_key, "Dupligroup"); } @@ -777,7 +776,7 @@ void DepsgraphRelationBuilder::build_constraints(ID *id, else if (cti->get_constraint_targets) { ListBase targets = {NULL, NULL}; cti->get_constraint_targets(con, &targets); - LINKLIST_FOREACH (bConstraintTarget *, ct, &targets) { + BLI_LISTBASE_FOREACH (bConstraintTarget *, ct, &targets) { if (ct->tar == NULL) { continue; } @@ -924,7 +923,7 @@ void DepsgraphRelationBuilder::build_animdata(ID *id) /* Animation curves and NLA. */ build_animdata_curves(id); /* Drivers. */ - build_animdata_drievrs(id); + build_animdata_drivers(id); } void DepsgraphRelationBuilder::build_animdata_curves(ID *id) @@ -962,7 +961,7 @@ void DepsgraphRelationBuilder::build_animdata_curves_targets(ID *id) /* Iterate over all curves and build relations. */ PointerRNA id_ptr; RNA_id_pointer_create(id, &id_ptr); - LINKLIST_FOREACH(FCurve *, fcu, &adt->action->curves) { + BLI_LISTBASE_FOREACH (FCurve *, fcu, &adt->action->curves) { PointerRNA ptr; PropertyRNA *prop; int index; @@ -990,17 +989,29 @@ void DepsgraphRelationBuilder::build_animdata_curves_targets(ID *id) graph_->add_new_relation(operation_from, operation_to, "Animation -> Prop", true); + /* It is possible that animation is writing to a nested ID datablock, + * need to make sure animation is evaluated after target ID is copied. + */ + if (DEG_depsgraph_use_copy_on_write()) { + const IDDepsNode *id_node_from = operation_from->owner->owner; + const IDDepsNode *id_node_to = operation_to->owner->owner; + if (id_node_from != id_node_to) { + ComponentKey cow_key(id_node_to->id_orig, + DEG_NODE_TYPE_COPY_ON_WRITE); + add_relation(cow_key, adt_key, "Target CoW -> Animation", true); + } + } } } -void DepsgraphRelationBuilder::build_animdata_drievrs(ID *id) +void DepsgraphRelationBuilder::build_animdata_drivers(ID *id) { AnimData *adt = BKE_animdata_from_id(id); if (adt == NULL) { return; } ComponentKey adt_key(id, DEG_NODE_TYPE_ANIMATION); - LINKLIST_FOREACH (FCurve *, fcu, &adt->drivers) { + BLI_LISTBASE_FOREACH (FCurve *, fcu, &adt->drivers) { OperationKey driver_key(id, DEG_NODE_TYPE_PARAMETERS, DEG_OPCODE_DRIVER, @@ -1009,7 +1020,6 @@ void DepsgraphRelationBuilder::build_animdata_drievrs(ID *id) /* create the driver's relations to targets */ build_driver(id, fcu); - /* Special case for array drivers: we can not multithread them because * of the way how they work internally: animation system will write the * whole array back to RNA even when changing individual array value. @@ -1024,7 +1034,7 @@ void DepsgraphRelationBuilder::build_animdata_drievrs(ID *id) */ if (fcu->array_index > 0) { FCurve *fcu_prev = NULL; - LINKLIST_FOREACH (FCurve *, fcu_candidate, &adt->drivers) { + BLI_LISTBASE_FOREACH (FCurve *, fcu_candidate, &adt->drivers) { /* Writing to different RNA paths is */ const char *rna_path = fcu->rna_path ? fcu->rna_path : ""; if (!STREQ(fcu_candidate->rna_path, rna_path)) { @@ -1140,6 +1150,25 @@ void DepsgraphRelationBuilder::build_driver_data(ID *id, FCurve *fcu) else { RNAPathKey target_key(id, rna_path); add_relation(driver_key, target_key, "Driver -> Target"); + /* Similar to the case with f-curves, driver might drive a nested + * datablock, which means driver execution should wait for that + * datablock to be copied. + */ + if (DEG_depsgraph_use_copy_on_write()) { + PointerRNA id_ptr; + PointerRNA ptr; + RNA_id_pointer_create(id, &id_ptr); + if (RNA_path_resolve_full(&id_ptr, fcu->rna_path, &ptr, NULL, NULL)) { + if (id_ptr.id.data != ptr.id.data) { + ComponentKey cow_key((ID *)ptr.id.data, + DEG_NODE_TYPE_COPY_ON_WRITE); + add_relation(cow_key, + driver_key, + "Target CoW -> Driver", + true); + } + } + } } } @@ -1154,7 +1183,7 @@ void DepsgraphRelationBuilder::build_driver_variables(ID *id, FCurve *fcu) const char *rna_path = fcu->rna_path ? fcu->rna_path : ""; const RNAPathKey self_key(id, rna_path); - LINKLIST_FOREACH (DriverVar *, dvar, &driver->variables) { + BLI_LISTBASE_FOREACH (DriverVar *, dvar, &driver->variables) { /* Only used targets. */ DRIVER_TARGETS_USED_LOOPER(dvar) { @@ -1174,9 +1203,9 @@ void DepsgraphRelationBuilder::build_driver_variables(ID *id, FCurve *fcu) continue; } OperationKey variable_key(dtar->id, - DEG_NODE_TYPE_BONE, - target_pchan->name, - DEG_OPCODE_BONE_DONE); + DEG_NODE_TYPE_BONE, + target_pchan->name, + DEG_OPCODE_BONE_DONE); if (is_same_bone_dependency(variable_key, self_key)) { continue; } @@ -1201,10 +1230,13 @@ void DepsgraphRelationBuilder::build_driver_variables(ID *id, FCurve *fcu) if (RNA_pointer_is_null(&variable_key.ptr)) { continue; } - if (is_same_bone_dependency(variable_key, self_key)) { + if (is_same_bone_dependency(variable_key, self_key) || + is_same_nodetree_node_dependency(variable_key, self_key) || + is_same_shapekey_dependency(variable_key, self_key)) + { continue; } - add_relation(variable_key, driver_key, "RNA Bone -> Driver"); + add_relation(variable_key, driver_key, "RNA Target -> Driver"); } else { if (dtar->id == id) { @@ -1266,7 +1298,7 @@ void DepsgraphRelationBuilder::build_rigidbody(Scene *scene) /* objects - simulation participants */ if (rbw->group) { - LINKLIST_FOREACH (Base *, base, &rbw->group->view_layer->object_bases) { + BLI_LISTBASE_FOREACH (Base *, base, &rbw->group->view_layer->object_bases) { Object *object = base->object; if (object == NULL || object->type != OB_MESH) { continue; @@ -1320,7 +1352,7 @@ void DepsgraphRelationBuilder::build_rigidbody(Scene *scene) /* constraints */ if (rbw->constraints) { - LINKLIST_FOREACH (Base *, base, &rbw->constraints->view_layer->object_bases) { + BLI_LISTBASE_FOREACH (Base *, base, &rbw->constraints->view_layer->object_bases) { Object *object = base->object; if (object == NULL || !object->rigidbody_constraint) { continue; @@ -1354,12 +1386,9 @@ void DepsgraphRelationBuilder::build_particles(Object *object) OperationKey eval_init_key(&object->id, DEG_NODE_TYPE_EVAL_PARTICLES, DEG_OPCODE_PARTICLE_SYSTEM_EVAL_INIT); - if (object_particles_depends_on_time(object)) { - add_relation(time_src_key, eval_init_key, "TimeSrc -> PSys"); - } /* particle systems */ - LINKLIST_FOREACH (ParticleSystem *, psys, &object->particlesystem) { + BLI_LISTBASE_FOREACH (ParticleSystem *, psys, &object->particlesystem) { ParticleSettings *part = psys->part; /* Build particle settings relations. @@ -1436,8 +1465,8 @@ void DepsgraphRelationBuilder::build_particles(Object *object) /* boids */ if (part->boids) { - LINKLIST_FOREACH (BoidState *, state, &part->boids->states) { - LINKLIST_FOREACH (BoidRule *, rule, &state->rules) { + BLI_LISTBASE_FOREACH (BoidState *, state, &part->boids->states) { + BLI_LISTBASE_FOREACH (BoidRule *, rule, &state->rules) { Object *ruleob = NULL; if (rule->type == eBoidRuleType_Avoid) ruleob = ((BoidRuleGoalAvoid *)rule)->ob; @@ -1455,6 +1484,13 @@ void DepsgraphRelationBuilder::build_particles(Object *object) if (part->ren_as == PART_DRAW_OB && part->dup_ob) { ComponentKey dup_ob_key(&part->dup_ob->id, DEG_NODE_TYPE_TRANSFORM); add_relation(dup_ob_key, psys_key, "Particle Object Visualization"); + if (part->dup_ob->type == OB_MBALL) { + ComponentKey dup_geometry_key(&part->dup_ob->id, + DEG_NODE_TYPE_GEOMETRY); + add_relation(obdata_ubereval_key, + dup_geometry_key, + "Particle MBall Visualization"); + } } } @@ -1577,7 +1613,7 @@ void DepsgraphRelationBuilder::build_obdata_geom(Object *object) /* Modifiers */ if (object->modifiers.first != NULL) { - LINKLIST_FOREACH (ModifierData *, md, &object->modifiers) { + BLI_LISTBASE_FOREACH (ModifierData *, md, &object->modifiers) { const ModifierTypeInfo *mti = modifierType_getInfo((ModifierType)md->type); if (mti->updateDepsgraph) { DepsNodeHandle handle = create_node_handle(obdata_ubereval_key); @@ -1798,7 +1834,7 @@ void DepsgraphRelationBuilder::build_nodetree(bNodeTree *ntree) build_animdata(ntree_id); ComponentKey shading_key(ntree_id, DEG_NODE_TYPE_SHADING); /* nodetree's nodes... */ - LINKLIST_FOREACH (bNode *, bnode, &ntree->nodes) { + BLI_LISTBASE_FOREACH (bNode *, bnode, &ntree->nodes) { ID *id = bnode->id; if (id == NULL) { continue; @@ -1919,7 +1955,8 @@ void DepsgraphRelationBuilder::build_gpencil(bGPdata *gpd) // TODO: parent object (when that feature is implemented) } -void DepsgraphRelationBuilder::build_cachefile(CacheFile *cache_file) { +void DepsgraphRelationBuilder::build_cachefile(CacheFile *cache_file) +{ /* Animation. */ build_animdata(&cache_file->id); } diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.h b/source/blender/depsgraph/intern/builder/deg_builder_relations.h index 9f661b8e825..30b3219f989 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.h +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.h @@ -206,7 +206,7 @@ struct DepsgraphRelationBuilder void build_animdata(ID *id); void build_animdata_curves(ID *id); void build_animdata_curves_targets(ID *id); - void build_animdata_drievrs(ID *id); + void build_animdata_drivers(ID *id); void build_driver(ID *id, FCurve *fcurve); void build_driver_data(ID *id, FCurve *fcurve); void build_driver_variables(ID *id, FCurve *fcurve); @@ -297,9 +297,31 @@ protected: DepsNodeHandle create_node_handle(const KeyType& key, const char *default_name = ""); + /* TODO(sergey): All those is_same* functions are to be generalized. */ + + /* Check whether two keys correponds to the same bone from same armature. + * + * This is used by drivers relations builder to avoid possible fake + * dependency cycle when one bone property drives another property of the + * same bone. + */ template <typename KeyFrom, typename KeyTo> bool is_same_bone_dependency(const KeyFrom& key_from, const KeyTo& key_to); + /* Similar to above, but used to check whether driver is using node from + * the same node tree as a driver variable. + */ + template <typename KeyFrom, typename KeyTo> + bool is_same_nodetree_node_dependency(const KeyFrom& key_from, + const KeyTo& key_to); + + /* Similar to above, but used to check whether driver is using key from + * the same key datablock as a driver variable. + */ + template <typename KeyFrom, typename KeyTo> + bool is_same_shapekey_dependency(const KeyFrom& key_from, + const KeyTo& key_to); + private: /* State which never changes, same for the whole builder time. */ Main *bmain_; diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_impl.h b/source/blender/depsgraph/intern/builder/deg_builder_relations_impl.h index ba55a83b767..485586e844f 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations_impl.h +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_impl.h @@ -30,6 +30,12 @@ #pragma once +#include "intern/nodes/deg_node_id.h" + +extern "C" { +#include "DNA_ID.h" +} + namespace DEG { template <typename KeyType> @@ -140,9 +146,14 @@ bool DepsgraphRelationBuilder::is_same_bone_dependency(const KeyFrom& key_from, if (op_from == NULL || op_to == NULL) { return false; } + /* Different armatures, bone can't be the same. */ + if (op_from->owner->owner != op_to->owner->owner) { + return false; + } /* We are only interested in relations like BONE_DONE -> BONE_LOCAL... */ if (!(op_from->opcode == DEG_OPCODE_BONE_DONE && - op_to->opcode == DEG_OPCODE_BONE_LOCAL)) { + op_to->opcode == DEG_OPCODE_BONE_LOCAL)) + { return false; } /* ... BUT, we also need to check if it's same bone. */ @@ -152,4 +163,64 @@ bool DepsgraphRelationBuilder::is_same_bone_dependency(const KeyFrom& key_from, return true; } +template <typename KeyFrom, typename KeyTo> +bool DepsgraphRelationBuilder::is_same_nodetree_node_dependency( + const KeyFrom& key_from, + const KeyTo& key_to) +{ + /* Get operations for requested keys. */ + DepsNode *node_from = get_node(key_from); + DepsNode *node_to = get_node(key_to); + if (node_from == NULL || node_to == NULL) { + return false; + } + OperationDepsNode *op_from = node_from->get_exit_operation(); + OperationDepsNode *op_to = node_to->get_entry_operation(); + if (op_from == NULL || op_to == NULL) { + return false; + } + /* Check if this is actually a node tree. */ + if (GS(op_from->owner->owner->id_orig->name) != ID_NT) { + return false; + } + /* Different node trees. */ + if (op_from->owner->owner != op_to->owner->owner) { + return false; + } + /* We are only interested in relations like BONE_DONE -> BONE_LOCAL... */ + if (!(op_from->opcode == DEG_OPCODE_PARAMETERS_EVAL && + op_to->opcode == DEG_OPCODE_PARAMETERS_EVAL)) + { + return false; + } + return true; +} + +template <typename KeyFrom, typename KeyTo> +bool DepsgraphRelationBuilder::is_same_shapekey_dependency( + const KeyFrom& key_from, + const KeyTo& key_to) +{ + /* Get operations for requested keys. */ + DepsNode *node_from = get_node(key_from); + DepsNode *node_to = get_node(key_to); + if (node_from == NULL || node_to == NULL) { + return false; + } + OperationDepsNode *op_from = node_from->get_exit_operation(); + OperationDepsNode *op_to = node_to->get_entry_operation(); + if (op_from == NULL || op_to == NULL) { + return false; + } + /* Check if this is actually a shape key datablock. */ + if (GS(op_from->owner->owner->id_orig->name) != ID_KE) { + return false; + } + /* Different key data blocks. */ + if (op_from->owner->owner != op_to->owner->owner) { + return false; + } + return true; +} + } // namespace DEG diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_layer_collection.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations_layer_collection.cc index 452bd7b19e7..9cf82b5fb47 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations_layer_collection.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_layer_collection.cc @@ -92,7 +92,7 @@ void DepsgraphRelationBuilder::build_layer_collections( ListBase *layer_collections, LayerCollectionState *state) { - LINKLIST_FOREACH (LayerCollection *, layer_collection, layer_collections) { + BLI_LISTBASE_FOREACH (LayerCollection *, layer_collection, layer_collections) { /* Recurs into the layer. */ build_layer_collection(owner_id, layer_collection, state); } diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc index 2aff1ca33c7..ad812a4b505 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc @@ -341,8 +341,8 @@ void DepsgraphRelationBuilder::build_rig(Object *object) */ RootPChanMap root_map; bool pose_depends_on_local_transform = false; - LINKLIST_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) { - LINKLIST_FOREACH (bConstraint *, con, &pchan->constraints) { + BLI_LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) { + BLI_LISTBASE_FOREACH (bConstraint *, con, &pchan->constraints) { switch (con->type) { case CONSTRAINT_TYPE_KINEMATIC: build_ik_pose(object, pchan, con, &root_map); @@ -382,7 +382,7 @@ void DepsgraphRelationBuilder::build_rig(Object *object) } /* links between operations for each bone */ - LINKLIST_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) { + BLI_LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) { OperationKey bone_local_key(&object->id, DEG_NODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_LOCAL); OperationKey bone_pose_key(&object->id, DEG_NODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_POSE_PARENT); OperationKey bone_ready_key(&object->id, DEG_NODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_READY); @@ -445,7 +445,7 @@ void DepsgraphRelationBuilder::build_proxy_rig(Object *object) { OperationKey pose_init_key(&object->id, DEG_NODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_INIT); OperationKey pose_done_key(&object->id, DEG_NODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_DONE); - LINKLIST_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) { + BLI_LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) { OperationKey bone_local_key(&object->id, DEG_NODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_LOCAL); OperationKey bone_ready_key(&object->id, DEG_NODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_READY); OperationKey bone_done_key(&object->id, DEG_NODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_DONE); diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_view_layer.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations_view_layer.cc index 29cff0cb28d..cfb98fe2f79 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations_view_layer.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_view_layer.cc @@ -59,6 +59,7 @@ extern "C" { #include "intern/nodes/deg_node.h" #include "intern/nodes/deg_node_component.h" +#include "intern/nodes/deg_node_id.h" #include "intern/nodes/deg_node_operation.h" #include "intern/depsgraph_intern.h" @@ -77,7 +78,7 @@ void DepsgraphRelationBuilder::build_view_layer(Scene *scene, ViewLayer *view_la * passed to the evaluation functions. During relations builder we only * do NULL-pointer check of the base, so it's fine to pass original one. */ - LINKLIST_FOREACH(Base *, base, &view_layer->object_bases) { + BLI_LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) { build_object(base, base->object); } if (scene->camera != NULL) { @@ -104,11 +105,11 @@ void DepsgraphRelationBuilder::build_view_layer(Scene *scene, ViewLayer *view_la build_gpencil(scene->gpd); } /* Masks. */ - LINKLIST_FOREACH (Mask *, mask, &bmain_->mask) { + BLI_LISTBASE_FOREACH (Mask *, mask, &bmain_->mask) { build_mask(mask); } /* Movie clips. */ - LINKLIST_FOREACH (MovieClip *, clip, &bmain_->movieclip) { + BLI_LISTBASE_FOREACH (MovieClip *, clip, &bmain_->movieclip) { build_movieclip(clip); } /* Collections. */ diff --git a/source/blender/depsgraph/intern/builder/deg_builder_transitive.cc b/source/blender/depsgraph/intern/builder/deg_builder_transitive.cc index b12af21fc8d..7731b76c6b9 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_transitive.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_transitive.cc @@ -37,6 +37,7 @@ #include "intern/nodes/deg_node_operation.h" #include "intern/depsgraph.h" +#include "intern/depsgraph_intern.h" #include "util/deg_util_foreach.h" @@ -79,13 +80,13 @@ static void deg_graph_tag_paths_recursive(DepsNode *node) void deg_graph_transitive_reduction(Depsgraph *graph) { + int num_removed_relations = 0; foreach (OperationDepsNode *target, graph->operations) { /* Clear tags. */ foreach (OperationDepsNode *node, graph->operations) { node->done = 0; } - - /* mark nodes from which we can reach the target + /* Mark nodes from which we can reach the target * start with children, so the target node and direct children are not * flagged. */ @@ -93,27 +94,30 @@ void deg_graph_transitive_reduction(Depsgraph *graph) foreach (DepsRelation *rel, target->inlinks) { deg_graph_tag_paths_recursive(rel->from); } - /* Remove redundant paths to the target. */ for (DepsNode::Relations::const_iterator it_rel = target->inlinks.begin(); it_rel != target->inlinks.end(); ) { DepsRelation *rel = *it_rel; - /* Increment in advance, so we can safely remove the relation. */ - ++it_rel; - if (rel->from->type == DEG_NODE_TYPE_TIMESOURCE) { /* HACK: time source nodes don't get "done" flag set/cleared. */ /* TODO: there will be other types in future, so iterators above * need modifying. */ + ++it_rel; } else if (rel->from->done & OP_REACHABLE) { + rel->unlink(); OBJECT_GUARDED_DELETE(rel, DepsRelation); + ++num_removed_relations; + } + else { + ++it_rel; } } } + DEG_DEBUG_PRINTF("Removed %d relations\n", num_removed_relations); } } // namespace DEG diff --git a/source/blender/depsgraph/intern/debug/deg_debug_graphviz.cc b/source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc index 5111db08e03..8fc4c0bcec1 100644 --- a/source/blender/depsgraph/intern/debug/deg_debug_graphviz.cc +++ b/source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc @@ -24,7 +24,7 @@ * ***** END GPL LICENSE BLOCK ***** */ -/** \file blender/depsgraph/intern/debug/deg_debug_graphviz.cc +/** \file blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc * \ingroup depsgraph * * Implementation of tools for debugging the depsgraph @@ -41,6 +41,9 @@ extern "C" { #include "DEG_depsgraph_debug.h" #include "intern/depsgraph_intern.h" +#include "intern/nodes/deg_node_id.h" +#include "intern/nodes/deg_node_time.h" + #include "util/deg_util_foreach.h" /* ****************** */ @@ -115,7 +118,7 @@ static int deg_debug_node_color_index(const DepsNode *node) break; } /* Do others based on class. */ - switch (node->tclass) { + switch (node->get_class()) { case DEG_NODE_CLASS_OPERATION: return 4; case DEG_NODE_CLASS_COMPONENT: @@ -139,7 +142,6 @@ static int deg_debug_node_color_index(const DepsNode *node) struct DebugContext { FILE *file; bool show_tags; - bool show_eval_priority; }; static void deg_debug_fprintf(const DebugContext &ctx, const char *fmt, ...) ATTR_PRINTF_FORMAT(2, 3); @@ -180,7 +182,7 @@ static void deg_debug_graphviz_legend(const DebugContext &ctx) #ifdef COLOR_SCHEME_NODE_TYPE const int (*pair)[2]; for (pair = deg_debug_node_type_color_map; (*pair)[0] >= 0; ++pair) { - DepsNodeFactory *nti = DEG_get_node_factory((eDEG_NODE_TYPE)(*pair)[0]); + DepsNodeFactory *nti = deg_type_get_factory((eDepsNode_Type)(*pair)[0]); deg_debug_graphviz_legend_color(ctx, nti->tname().c_str(), deg_debug_colors_light[(*pair)[1] % deg_debug_max_colors]); @@ -202,7 +204,7 @@ static void deg_debug_graphviz_node_color(const DebugContext &ctx, const char *color_update = "dodgerblue3"; const char *color = color_default; if (ctx.show_tags) { - if (node->tclass == DEG_NODE_CLASS_OPERATION) { + if (node->get_class() == DEG_NODE_CLASS_OPERATION) { OperationDepsNode *op_node = (OperationDepsNode *)node; if (op_node->flag & DEPSOP_FLAG_DIRECTLY_MODIFIED) { color = color_modified; @@ -223,7 +225,7 @@ static void deg_debug_graphviz_node_penwidth(const DebugContext &ctx, float penwidth_update = 4.0f; float penwidth = penwidth_default; if (ctx.show_tags) { - if (node->tclass == DEG_NODE_CLASS_OPERATION) { + if (node->get_class() == DEG_NODE_CLASS_OPERATION) { OperationDepsNode *op_node = (OperationDepsNode *)node; if (op_node->flag & DEPSOP_FLAG_DIRECTLY_MODIFIED) { penwidth = penwidth_modified; @@ -261,14 +263,14 @@ static void deg_debug_graphviz_node_style(const DebugContext &ctx, const DepsNod { const char *base_style = "filled"; /* default style */ if (ctx.show_tags) { - if (node->tclass == DEG_NODE_CLASS_OPERATION) { + if (node->get_class() == DEG_NODE_CLASS_OPERATION) { OperationDepsNode *op_node = (OperationDepsNode *)node; if (op_node->flag & (DEPSOP_FLAG_DIRECTLY_MODIFIED | DEPSOP_FLAG_NEEDS_UPDATE)) { base_style = "striped"; } } } - switch (node->tclass) { + switch (node->get_class()) { case DEG_NODE_CLASS_GENERIC: deg_debug_fprintf(ctx, "\"%s\"", base_style); break; @@ -286,22 +288,11 @@ static void deg_debug_graphviz_node_single(const DebugContext &ctx, { const char *shape = "box"; string name = node->identifier(); - float priority = -1.0f; - if (ctx.show_eval_priority && node->tclass == DEG_NODE_CLASS_OPERATION) { - priority = ((OperationDepsNode *)node)->eval_priority; - } deg_debug_fprintf(ctx, "// %s\n", name.c_str()); deg_debug_fprintf(ctx, "\"node_%p\"", node); deg_debug_fprintf(ctx, "["); // deg_debug_fprintf(ctx, "label=<<B>%s</B>>", name); - if (priority >= 0.0f) { - deg_debug_fprintf(ctx, "label=<%s<BR/>(<I>%.2f</I>)>", - name.c_str(), - priority); - } - else { - deg_debug_fprintf(ctx, "label=<%s>", name.c_str()); - } + deg_debug_fprintf(ctx, "label=<%s>", name.c_str()); deg_debug_fprintf(ctx, ",fontname=\"%s\"", deg_debug_graphviz_fontname); deg_debug_fprintf(ctx, ",fontsize=%f", deg_debug_graphviz_node_label_size); deg_debug_fprintf(ctx, ",shape=%s", shape); @@ -403,6 +394,8 @@ static void deg_debug_graphviz_node(const DebugContext &ctx, case DEG_NODE_TYPE_OPERATION: deg_debug_graphviz_node_single(ctx, node); break; + case NUM_DEG_NODE_TYPES: + break; } } @@ -434,7 +427,7 @@ static bool deg_debug_graphviz_is_cluster(const DepsNode *node) static bool deg_debug_graphviz_is_owner(const DepsNode *node, const DepsNode *other) { - switch (node->tclass) { + switch (node->get_class()) { case DEG_NODE_CLASS_COMPONENT: { ComponentDepsNode *comp_node = (ComponentDepsNode *)node; @@ -474,6 +467,7 @@ static void deg_debug_graphviz_node_relations(const DebugContext &ctx, deg_debug_fprintf(ctx, "["); /* Note: without label an id seem necessary to avoid bugs in graphviz/dot */ deg_debug_fprintf(ctx, "id=\"%s\"", rel->name); + deg_debug_fprintf(ctx, "label=\"%s\"", rel->name); deg_debug_fprintf(ctx, ",color="); deg_debug_graphviz_relation_color(ctx, rel); deg_debug_fprintf(ctx, ",penwidth=\"%f\"", penwidth); /* NOTE: edge from node to own cluster is not possible and gives graphviz @@ -524,7 +518,9 @@ static void deg_debug_graphviz_graph_relations(const DebugContext &ctx, } // namespace DEG -void DEG_debug_graphviz(const Depsgraph *graph, FILE *f, const char *label, bool show_eval) +void DEG_debug_relations_graphviz(const Depsgraph *graph, + FILE *f, + const char *label) { if (!graph) { return; @@ -534,8 +530,6 @@ void DEG_debug_graphviz(const Depsgraph *graph, FILE *f, const char *label, bool DEG::DebugContext ctx; ctx.file = f; - ctx.show_tags = show_eval; - ctx.show_eval_priority = show_eval; DEG::deg_debug_fprintf(ctx, "digraph depgraph {" NL); DEG::deg_debug_fprintf(ctx, "rankdir=LR;" NL); diff --git a/source/blender/depsgraph/intern/debug/deg_debug_stats_gnuplot.cc b/source/blender/depsgraph/intern/debug/deg_debug_stats_gnuplot.cc new file mode 100644 index 00000000000..35888f8d5e3 --- /dev/null +++ b/source/blender/depsgraph/intern/debug/deg_debug_stats_gnuplot.cc @@ -0,0 +1,157 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2017 Blender Foundation. + * All rights reserved. + * + * Original Author: Sergey Sharybin + * Contributor(s): None Yet + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/depsgraph/intern/debug/deg_debug_stats_gnuplot.cc + * \ingroup depsgraph + */ + +#include "DEG_depsgraph_debug.h" + +#include <algorithm> +#include <cstdarg> + +#include "BLI_compiler_attrs.h" +#include "BLI_math_base.h" + +#include "intern/depsgraph.h" +#include "intern/nodes/deg_node_id.h" + +#include "util/deg_util_foreach.h" + +extern "C" { +#include "DNA_ID.h" +} /* extern "C" */ + +#define NL "\r\n" + +namespace DEG { +namespace { + +struct DebugContext { + FILE *file; + const Depsgraph *graph; + const char *label; + const char *output_filename; +}; + +struct StatsEntry { + const IDDepsNode *id_node; + double time; +}; + +/* TODO(sergey): De-duplicate with graphviz relation debugger. */ +static void deg_debug_fprintf(const DebugContext &ctx, + const char *fmt, + ...) ATTR_PRINTF_FORMAT(2, 3); +static void deg_debug_fprintf(const DebugContext &ctx, const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + vfprintf(ctx.file, fmt, args); + va_end(args); +} + +BLI_INLINE double get_node_time(const DebugContext& /*ctx*/, + const DepsNode *node) +{ + // TODO(sergey): Figure out a nice way to define which exact time + // we want to show. + return node->stats.current_time; +} + +bool stat_entry_comparator(const StatsEntry& a, const StatsEntry& b) +{ + return a.time < b.time; +} + +void write_stats_data(const DebugContext& ctx) +{ + // Fill in array of all stats which are to be displayed. + vector<StatsEntry> stats; + stats.reserve(ctx.graph->id_nodes.size()); + foreach (const IDDepsNode *id_node, ctx.graph->id_nodes) { + const double time = get_node_time(ctx, id_node); + if (time == 0.0) { + continue; + } + StatsEntry entry; + entry.id_node = id_node; + entry.time = time; + stats.push_back(entry); + } + // Sort the data. + std::sort(stats.begin(), stats.end(), stat_entry_comparator); + // We limit number of entries, otherwise things become unreadable. + stats.resize(min_ii(stats.size(), 32)); + // Print data to the file stream. + deg_debug_fprintf(ctx, "$data << EOD" NL); + foreach (const StatsEntry& entry, stats) { + deg_debug_fprintf(ctx, "\"%s\",%f" NL, + entry.id_node->id_orig->name + 2, + entry.time); + } + deg_debug_fprintf(ctx, "EOD" NL); +} + +void deg_debug_stats_gnuplot(const DebugContext& ctx) +{ + // Data itself. + write_stats_data(ctx); + // Optional label. + if (ctx.label && ctx.label[0]) { + deg_debug_fprintf(ctx, "set title \"%s\"" NL, ctx.label); + } + // Rest of the commands. + // TODO(sergey): Need to decide on the resolution somehow. + deg_debug_fprintf(ctx, "set terminal pngcairo size 1920,1080" NL); + deg_debug_fprintf(ctx, "set output \"%s\"" NL, ctx.output_filename); + deg_debug_fprintf(ctx, "set grid" NL); + deg_debug_fprintf(ctx, "set datafile separator ','" NL); + deg_debug_fprintf(ctx, "set style fill solid" NL); + deg_debug_fprintf(ctx, "plot \"$data\" using " \ + "($2*0.5):0:($2*0.5):(0.2):yticlabels(1) " + "with boxxyerrorbars t '' lt rgb \"#406090\"" NL); + +} + +} // namespace +} // namespace DEG + +void DEG_debug_stats_gnuplot(const Depsgraph *depsgraph, + FILE *f, + const char *label, + const char *output_filename) +{ + if (depsgraph == NULL) { + return; + } + DEG::DebugContext ctx; + ctx.file = f; + ctx.graph = (DEG::Depsgraph *)depsgraph; + ctx.label = label; + ctx.output_filename = output_filename; + DEG::deg_debug_stats_gnuplot(ctx); +} diff --git a/source/blender/depsgraph/intern/depsgraph.cc b/source/blender/depsgraph/intern/depsgraph.cc index 4fea8b49706..3a78c9050f7 100644 --- a/source/blender/depsgraph/intern/depsgraph.cc +++ b/source/blender/depsgraph/intern/depsgraph.cc @@ -49,6 +49,7 @@ extern "C" { #include "RNA_access.h" } +#include <algorithm> #include <cstring> #include "DEG_depsgraph.h" @@ -57,7 +58,9 @@ extern "C" { #include "intern/nodes/deg_node.h" #include "intern/nodes/deg_node_component.h" +#include "intern/nodes/deg_node_id.h" #include "intern/nodes/deg_node_operation.h" +#include "intern/nodes/deg_node_time.h" #include "intern/depsgraph_intern.h" #include "util/deg_util_foreach.h" @@ -79,6 +82,14 @@ namespace DEG { static DEG_EditorUpdateIDCb deg_editor_update_id_cb = NULL; static DEG_EditorUpdateSceneCb deg_editor_update_scene_cb = NULL; +/* TODO(sergey): Find a better place for this. */ +template <typename T> +static void remove_from_vector(vector<T> *vector, const T& value) +{ + vector->erase(std::remove(vector->begin(), vector->end(), value), + vector->end()); +} + Depsgraph::Depsgraph() : time_source(NULL), need_update(true), @@ -156,7 +167,7 @@ static bool pointer_to_component_node_criteria( return true; } else if (object->pose != NULL) { - LINKLIST_FOREACH(bPoseChannel *, pchan, &object->pose->chanbase) { + BLI_LISTBASE_FOREACH(bPoseChannel *, pchan, &object->pose->chanbase) { if (BLI_findindex(&pchan->constraints, con) != -1) { /* bone transforms */ *type = DEG_NODE_TYPE_BONE; @@ -193,11 +204,7 @@ static bool pointer_to_component_node_criteria( } } else if (ptr->type == &RNA_ShapeKey) { - Key *key = (Key *)ptr->id.data; - /* ShapeKeys are currently handled as geometry on the geometry that - * owns it. - */ - *id = key->from; + *id = (ID *)ptr->id.data; *type = DEG_NODE_TYPE_GEOMETRY; return true; } @@ -263,7 +270,7 @@ DepsNode *Depsgraph::find_node_from_pointer(const PointerRNA *ptr, TimeSourceDepsNode *Depsgraph::add_time_source() { if (time_source == NULL) { - DepsNodeFactory *factory = deg_get_node_factory(DEG_NODE_TYPE_TIMESOURCE); + DepsNodeFactory *factory = deg_type_get_factory(DEG_NODE_TYPE_TIMESOURCE); time_source = (TimeSourceDepsNode *)factory->create_node(NULL, "", "Time Source"); } return time_source; @@ -284,7 +291,7 @@ IDDepsNode *Depsgraph::add_id_node(ID *id, bool do_tag, ID *id_cow_hint) BLI_assert((id->tag & LIB_TAG_COPY_ON_WRITE) == 0); IDDepsNode *id_node = find_id_node(id); if (!id_node) { - DepsNodeFactory *factory = deg_get_node_factory(DEG_NODE_TYPE_ID_REF); + DepsNodeFactory *factory = deg_type_get_factory(DEG_NODE_TYPE_ID_REF); id_node = (IDDepsNode *)factory->create_node(id, "", id->name); id_node->init_copy_on_write(id_cow_hint); if (do_tag) { @@ -354,7 +361,7 @@ DepsRelation *Depsgraph::add_new_relation(OperationDepsNode *from, if (comp_node->type == DEG_NODE_TYPE_GEOMETRY) { IDDepsNode *id_to = to->owner->owner; IDDepsNode *id_from = from->owner->owner; - if (id_to != id_from && (id_to->id_orig->tag & LIB_TAG_ID_RECALC_ALL)) { + if (id_to != id_from && (id_to->id_orig->recalc & ID_RECALC_ALL)) { if ((id_from->eval_flags & DAG_EVAL_NEED_CPU) == 0) { id_from->tag_update(this); id_from->eval_flags |= DAG_EVAL_NEED_CPU; @@ -431,7 +438,15 @@ DepsRelation::DepsRelation(DepsNode *from, DepsRelation::~DepsRelation() { /* Sanity check. */ - BLI_assert(this->from && this->to); + BLI_assert(from != NULL && to != NULL); +} + +void DepsRelation::unlink() +{ + /* Sanity check. */ + BLI_assert(from != NULL && to != NULL); + remove_from_vector(&from->outlinks, this); + remove_from_vector(&to->inlinks, this); } /* Low level tagging -------------------------------------- */ diff --git a/source/blender/depsgraph/intern/depsgraph.h b/source/blender/depsgraph/intern/depsgraph.h index 8a34be0c7a2..f18b93c9807 100644 --- a/source/blender/depsgraph/intern/depsgraph.h +++ b/source/blender/depsgraph/intern/depsgraph.h @@ -87,6 +87,8 @@ struct DepsRelation { const char *description); ~DepsRelation(); + + void unlink(); }; /* ********* */ diff --git a/source/blender/depsgraph/intern/depsgraph_build.cc b/source/blender/depsgraph/intern/depsgraph_build.cc index 57153279acb..902cbe039cd 100644 --- a/source/blender/depsgraph/intern/depsgraph_build.cc +++ b/source/blender/depsgraph/intern/depsgraph_build.cc @@ -68,6 +68,7 @@ extern "C" { #include "intern/nodes/deg_node.h" #include "intern/nodes/deg_node_component.h" +#include "intern/nodes/deg_node_id.h" #include "intern/nodes/deg_node_operation.h" #include "intern/depsgraph_types.h" @@ -293,8 +294,8 @@ void DEG_graph_relations_update(Depsgraph *graph, void DEG_relations_tag_update(Main *bmain) { DEG_DEBUG_PRINTF("%s: Tagging relations for update.\n", __func__); - LINKLIST_FOREACH(Scene *, scene, &bmain->scene) { - LINKLIST_FOREACH(ViewLayer *, view_layer, &scene->view_layers) { + BLI_LISTBASE_FOREACH (Scene *, scene, &bmain->scene) { + BLI_LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) { Depsgraph *depsgraph = (Depsgraph *)BKE_scene_get_depsgraph(scene, view_layer, diff --git a/source/blender/depsgraph/intern/depsgraph_debug.cc b/source/blender/depsgraph/intern/depsgraph_debug.cc index 42c1cf861eb..e8d166532ad 100644 --- a/source/blender/depsgraph/intern/depsgraph_debug.cc +++ b/source/blender/depsgraph/intern/depsgraph_debug.cc @@ -42,6 +42,9 @@ extern "C" { #include "DEG_depsgraph_build.h" #include "intern/depsgraph_intern.h" +#include "intern/nodes/deg_node_id.h" +#include "intern/nodes/deg_node_time.h" + #include "util/deg_util_foreach.h" bool DEG_debug_compare(const struct Depsgraph *graph1, diff --git a/source/blender/depsgraph/intern/depsgraph_eval.cc b/source/blender/depsgraph/intern/depsgraph_eval.cc index 1d389b902b8..ad1a850a807 100644 --- a/source/blender/depsgraph/intern/depsgraph_eval.cc +++ b/source/blender/depsgraph/intern/depsgraph_eval.cc @@ -48,12 +48,10 @@ extern "C" { #include "intern/nodes/deg_node.h" #include "intern/nodes/deg_node_operation.h" +#include "intern/nodes/deg_node_time.h" #include "intern/depsgraph.h" -/* Unfinished and unused, and takes quite some pre-processing time. */ -#undef USE_EVAL_PRIORITY - /* ****************** */ /* Evaluation Context */ @@ -85,11 +83,10 @@ void DEG_evaluation_context_init_from_scene(EvaluationContext *eval_ctx, eEvaluationMode mode) { DEG_evaluation_context_init(eval_ctx, mode); - eval_ctx->depsgraph = BKE_scene_get_depsgraph(scene, view_layer, false); + eval_ctx->depsgraph = BKE_scene_get_depsgraph(scene, view_layer, true); eval_ctx->view_layer = view_layer; eval_ctx->engine_type = engine_type; eval_ctx->ctime = BKE_scene_frame_get(scene); - BLI_assert(eval_ctx->depsgraph != NULL); } /* Free evaluation context. */ diff --git a/source/blender/depsgraph/intern/depsgraph_intern.h b/source/blender/depsgraph/intern/depsgraph_intern.h index e7e472ea5d6..df5e51a3910 100644 --- a/source/blender/depsgraph/intern/depsgraph_intern.h +++ b/source/blender/depsgraph/intern/depsgraph_intern.h @@ -60,8 +60,8 @@ namespace DEG { /* Typeinfo Struct (nti) */ struct DepsNodeFactory { virtual eDepsNode_Type type() const = 0; - virtual eDepsNode_Class tclass() const = 0; virtual const char *tname() const = 0; + virtual int id_recalc_tag() const = 0; virtual DepsNode *create_node(const ID *id, const char *subdata, @@ -71,8 +71,8 @@ struct DepsNodeFactory { template <class NodeType> struct DepsNodeFactoryImpl : public DepsNodeFactory { eDepsNode_Type type() const { return NodeType::typeinfo.type; } - eDepsNode_Class tclass() const { return NodeType::typeinfo.tclass; } const char *tname() const { return NodeType::typeinfo.tname; } + int id_recalc_tag() const { return NodeType::typeinfo.id_recalc_tag; } DepsNode *create_node(const ID *id, const char *subdata, const char *name) const { @@ -80,7 +80,6 @@ struct DepsNodeFactoryImpl : public DepsNodeFactory { /* populate base node settings */ node->type = type(); - node->tclass = tclass(); if (name[0] != '\0') { /* set name if provided ... */ @@ -103,10 +102,7 @@ struct DepsNodeFactoryImpl : public DepsNodeFactory { void deg_register_node_typeinfo(DepsNodeFactory *factory); /* Get typeinfo for specified type */ -DepsNodeFactory *deg_get_node_factory(const eDepsNode_Type type); - -/* Get typeinfo for provided node */ -DepsNodeFactory *deg_node_get_factory(const DepsNode *node); +DepsNodeFactory *deg_type_get_factory(const eDepsNode_Type type); /* Editors Integration -------------------------------------------------- */ @@ -116,11 +112,6 @@ void deg_editors_id_update(const DEGEditorUpdateContext *update_ctx, void deg_editors_scene_update(const DEGEditorUpdateContext *update_ctx, bool updated); -/* Tagging helpers ------------------------------------------------------ */ - -void lib_id_recalc_tag(struct Main *bmain, struct ID *id); -void lib_id_recalc_data_tag(struct Main *bmain, struct ID *id); - #define DEG_DEBUG_PRINTF(...) \ do { \ if (G.debug & G_DEBUG_DEPSGRAPH) { \ diff --git a/source/blender/depsgraph/intern/depsgraph_query.cc b/source/blender/depsgraph/intern/depsgraph_query.cc index 6892bdaa178..63c9aa1407a 100644 --- a/source/blender/depsgraph/intern/depsgraph_query.cc +++ b/source/blender/depsgraph/intern/depsgraph_query.cc @@ -46,13 +46,14 @@ extern "C" { #include "DEG_depsgraph_query.h" #include "intern/depsgraph_intern.h" +#include "intern/nodes/deg_node_id.h" bool DEG_id_type_tagged(Main *bmain, short id_type) { return bmain->id_tag_update[BKE_idcode_to_index(id_type)] != 0; } -short DEG_get_eval_flags_for_id(Depsgraph *graph, ID *id) +short DEG_get_eval_flags_for_id(const Depsgraph *graph, ID *id) { if (graph == NULL) { /* Happens when converting objects to mesh from a python script @@ -64,9 +65,8 @@ short DEG_get_eval_flags_for_id(Depsgraph *graph, ID *id) return 0; } - DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(graph); - - DEG::IDDepsNode *id_node = deg_graph->find_id_node(id); + const DEG::Depsgraph *deg_graph = reinterpret_cast<const DEG::Depsgraph *>(graph); + const DEG::IDDepsNode *id_node = deg_graph->find_id_node(id); if (id_node == NULL) { /* TODO(sergey): Does it mean we need to check set scene? */ return 0; @@ -75,16 +75,16 @@ short DEG_get_eval_flags_for_id(Depsgraph *graph, ID *id) return id_node->eval_flags; } -Scene *DEG_get_evaluated_scene(Depsgraph *graph) +Scene *DEG_get_evaluated_scene(const Depsgraph *graph) { - DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(graph); + const DEG::Depsgraph *deg_graph = reinterpret_cast<const DEG::Depsgraph *>(graph); Scene *scene_orig = deg_graph->scene; return reinterpret_cast<Scene *>(deg_graph->get_cow_id(&scene_orig->id)); } -ViewLayer *DEG_get_evaluated_view_layer(Depsgraph *graph) +ViewLayer *DEG_get_evaluated_view_layer(const Depsgraph *graph) { - DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(graph); + const DEG::Depsgraph *deg_graph = reinterpret_cast<const DEG::Depsgraph *>(graph); Scene *scene_cow = DEG_get_evaluated_scene(graph); ViewLayer *view_layer_orig = deg_graph->view_layer; ViewLayer *view_layer_cow = @@ -94,19 +94,19 @@ ViewLayer *DEG_get_evaluated_view_layer(Depsgraph *graph) return view_layer_cow; } -Object *DEG_get_evaluated_object(Depsgraph *depsgraph, Object *object) +Object *DEG_get_evaluated_object(const Depsgraph *depsgraph, Object *object) { return (Object *)DEG_get_evaluated_id(depsgraph, &object->id); } -ID *DEG_get_evaluated_id(struct Depsgraph *depsgraph, ID *id) +ID *DEG_get_evaluated_id(const Depsgraph *depsgraph, ID *id) { /* TODO(sergey): This is a duplicate of Depsgraph::get_cow_id(), * but here we never do assert, since we don't know nature of the * incoming ID datablock. */ - DEG::Depsgraph *deg_graph = (DEG::Depsgraph *)depsgraph; - DEG::IDDepsNode *id_node = deg_graph->find_id_node(id); + const DEG::Depsgraph *deg_graph = (const DEG::Depsgraph *)depsgraph; + const DEG::IDDepsNode *id_node = deg_graph->find_id_node(id); if (id_node == NULL) { return id; } diff --git a/source/blender/depsgraph/intern/depsgraph_query_foreach.cc b/source/blender/depsgraph/intern/depsgraph_query_foreach.cc index b1353f528bc..e6692cf49b3 100644 --- a/source/blender/depsgraph/intern/depsgraph_query_foreach.cc +++ b/source/blender/depsgraph/intern/depsgraph_query_foreach.cc @@ -50,6 +50,7 @@ extern "C" { #include "intern/nodes/deg_node.h" #include "intern/nodes/deg_node_component.h" +#include "intern/nodes/deg_node_id.h" #include "intern/nodes/deg_node_operation.h" #include "util/deg_util_foreach.h" diff --git a/source/blender/depsgraph/intern/depsgraph_query_iter.cc b/source/blender/depsgraph/intern/depsgraph_query_iter.cc index d8a54642a85..30c9d9f10be 100644 --- a/source/blender/depsgraph/intern/depsgraph_query_iter.cc +++ b/source/blender/depsgraph/intern/depsgraph_query_iter.cc @@ -38,6 +38,7 @@ extern "C" { #include "BKE_anim.h" #include "BKE_idprop.h" #include "BKE_layer.h" +#include "BKE_object.h" } /* extern "C" */ #include "DNA_object_types.h" @@ -49,15 +50,41 @@ extern "C" { #include "intern/depsgraph_intern.h" #include "util/deg_util_foreach.h" +#include "intern/nodes/deg_node_id.h" + #ifndef NDEBUG # include "intern/eval/deg_eval_copy_on_write.h" #endif /* ************************ DEG ITERATORS ********************* */ +static void verify_id_proeprties_freed(DEGObjectIterData *data) +{ + if (data->dupli_object_current == NULL) { + // We didn't enter duplication yet, so we can't have any dangling + // pointers. + return; + } + const Object *dupli_object = data->dupli_object_current->ob; + Object *temp_dupli_object = &data->temp_dupli_object; + if (temp_dupli_object->id.properties == NULL) { + // No ID proeprties in temp datablock -- no leak is possible. + return; + } + if (temp_dupli_object->id.properties == dupli_object->id.properties) { + // Temp copy of object did not modify ID properties. + return; + } + // Free memory which is owned by temporary storage which is about to + // get overwritten. + IDP_FreeProperty(temp_dupli_object->id.properties); + MEM_freeN(temp_dupli_object->id.properties); + temp_dupli_object->id.properties = NULL; +} + static bool deg_objects_dupli_iterator_next(BLI_Iterator *iter) { - DEGOIterObjectData *data = (DEGOIterObjectData *)iter->data; + DEGObjectIterData *data = (DEGObjectIterData *)iter->data; while (data->dupli_object_next != NULL) { DupliObject *dob = data->dupli_object_next; Object *obd = dob->ob; @@ -75,17 +102,29 @@ static bool deg_objects_dupli_iterator_next(BLI_Iterator *iter) continue; } + verify_id_proeprties_freed(data); + data->dupli_object_current = dob; /* Temporary object to evaluate. */ Object *dupli_parent = data->dupli_parent; Object *temp_dupli_object = &data->temp_dupli_object; *temp_dupli_object = *dob->ob; + temp_dupli_object->transflag &= ~OB_DUPLI; temp_dupli_object->select_color = dupli_parent->select_color; temp_dupli_object->base_flag = dupli_parent->base_flag | BASE_FROMDUPLI; - BLI_assert(dob->collection_properties != NULL); - temp_dupli_object->base_collection_properties = dob->collection_properties; - IDP_MergeGroup(temp_dupli_object->base_collection_properties, dupli_parent->base_collection_properties, false); + + if (dob->collection_properties != NULL) { + temp_dupli_object->base_collection_properties = dob->collection_properties; + IDP_MergeGroup(temp_dupli_object->base_collection_properties, + dupli_parent->base_collection_properties, + false); + } + else { + temp_dupli_object->base_collection_properties = + dupli_parent->base_collection_properties; + } + copy_m4_m4(data->temp_dupli_object.obmat, dob->mat); iter->current = &data->temp_dupli_object; BLI_assert( @@ -99,45 +138,63 @@ static bool deg_objects_dupli_iterator_next(BLI_Iterator *iter) static void DEG_iterator_objects_step(BLI_Iterator *iter, DEG::IDDepsNode *id_node) { - /* Reset the skip in case we are running from within a loop. */ - iter->skip = false; + /* Set it early in case we need to exit and we are running from within a loop. */ + iter->skip = true; - DEGOIterObjectData *data = (DEGOIterObjectData *)iter->data; + DEGObjectIterData *data = (DEGObjectIterData *)iter->data; const ID_Type id_type = GS(id_node->id_orig->name); if (id_type != ID_OB) { - iter->skip = true; return; } switch (id_node->linked_state) { case DEG::DEG_ID_LINKED_DIRECTLY: + if ((data->flag & DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY) == 0) { + return; + } break; case DEG::DEG_ID_LINKED_VIA_SET: - if (data->flag & DEG_ITER_OBJECT_FLAG_SET) { - break; - } - else { - ATTR_FALLTHROUGH; + if ((data->flag & DEG_ITER_OBJECT_FLAG_LINKED_VIA_SET) == 0) { + return; } + break; case DEG::DEG_ID_LINKED_INDIRECTLY: - iter->skip = true; - return; + if ((data->flag & DEG_ITER_OBJECT_FLAG_LINKED_INDIRECTLY) == 0) { + return; + } + break; } Object *object = (Object *)id_node->id_cow; BLI_assert(DEG::deg_validate_copy_on_write_datablock(&object->id)); - if ((data->flag & DEG_ITER_OBJECT_FLAG_DUPLI) && (object->transflag & OB_DUPLI)) { + if ((BKE_object_is_visible(object, OB_VISIBILITY_CHECK_UNKNOWN_RENDER_MODE) == false) && + ((data->flag & DEG_ITER_OBJECT_FLAG_VISIBLE) != 0)) + { + return; + } + + if ((data->flag & DEG_ITER_OBJECT_FLAG_DUPLI) && + (object->transflag & OB_DUPLI)) + { data->dupli_parent = object; data->dupli_list = object_duplilist(&data->eval_ctx, data->scene, object); data->dupli_object_next = (DupliObject *)data->dupli_list->first; + const eObjectVisibilityCheck mode = + (data->mode == DEG_ITER_OBJECT_MODE_RENDER) + ? OB_VISIBILITY_CHECK_FOR_RENDER + : OB_VISIBILITY_CHECK_FOR_VIEWPORT; + if (BKE_object_is_visible(object, mode) == false) { + return; + } } iter->current = object; + iter->skip = false; } -void DEG_iterator_objects_begin(BLI_Iterator *iter, DEGOIterObjectData *data) +void DEG_iterator_objects_begin(BLI_Iterator *iter, DEGObjectIterData *data) { Depsgraph *depsgraph = data->graph; DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(depsgraph); @@ -149,7 +206,10 @@ void DEG_iterator_objects_begin(BLI_Iterator *iter, DEGOIterObjectData *data) } /* TODO(sergey): What evaluation type we want here? */ - DEG_evaluation_context_init(&data->eval_ctx, DAG_EVAL_RENDER); + /* TODO(dfelinto): Get rid of evaluation context here, it's only used to do + * direct dupli-objects update in group.c. Which is terribly bad, and all + * objects are expected to be evaluated already. */ + DEG_evaluation_context_init(&data->eval_ctx, DAG_EVAL_VIEWPORT); data->eval_ctx.view_layer = DEG_get_evaluated_view_layer(depsgraph); iter->data = data; @@ -171,15 +231,17 @@ void DEG_iterator_objects_begin(BLI_Iterator *iter, DEGOIterObjectData *data) void DEG_iterator_objects_next(BLI_Iterator *iter) { - DEGOIterObjectData *data = (DEGOIterObjectData *)iter->data; + DEGObjectIterData *data = (DEGObjectIterData *)iter->data; Depsgraph *depsgraph = data->graph; DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(depsgraph); do { + iter->skip = false; if (data->dupli_list) { if (deg_objects_dupli_iterator_next(iter)) { return; } else { + verify_id_proeprties_freed(data); free_object_duplilist(data->dupli_list); data->dupli_parent = NULL; data->dupli_list = NULL; @@ -202,8 +264,10 @@ void DEG_iterator_objects_next(BLI_Iterator *iter) void DEG_iterator_objects_end(BLI_Iterator *iter) { #ifndef NDEBUG - DEGOIterObjectData *data = (DEGOIterObjectData *)iter->data; - /* Force crash in case the iterator data is referenced and accessed down the line. (T51718) */ + DEGObjectIterData *data = (DEGObjectIterData *)iter->data; + /* Force crash in case the iterator data is referenced and accessed down + * the line. (T51718) + */ memset(&data->temp_dupli_object, 0xff, sizeof(data->temp_dupli_object)); #else (void) iter; diff --git a/source/blender/depsgraph/intern/depsgraph_tag.cc b/source/blender/depsgraph/intern/depsgraph_tag.cc index e928da58e87..38f43f5720b 100644 --- a/source/blender/depsgraph/intern/depsgraph_tag.cc +++ b/source/blender/depsgraph/intern/depsgraph_tag.cc @@ -35,8 +35,9 @@ #include <queue> #include "BLI_utildefines.h" -#include "BLI_task.h" #include "BLI_listbase.h" +#include "BLI_math_bits.h" +#include "BLI_task.h" extern "C" { #include "DNA_object_types.h" @@ -63,225 +64,63 @@ extern "C" { #include "intern/eval/deg_eval_flush.h" #include "intern/nodes/deg_node.h" #include "intern/nodes/deg_node_component.h" +#include "intern/nodes/deg_node_id.h" #include "intern/nodes/deg_node_operation.h" #include "intern/depsgraph_intern.h" #include "util/deg_util_foreach.h" -/* Define this in order to have more strict sanitization of what tagging flags - * are used for ID databnlocks. Ideally, we would always want this, but there - * are cases in generic modules (like IR remapping) where we don't want to spent - * lots of time trying to guess which components are to be updated. - */ -// #define STRICT_COMPONENT_TAGGING - /* *********************** */ /* Update Tagging/Flushing */ namespace DEG { -/* Data-Based Tagging ------------------------------- */ - -void lib_id_recalc_tag(Main *bmain, ID *id) -{ - id->tag |= LIB_TAG_ID_RECALC; - DEG_id_type_tag(bmain, GS(id->name)); -} - -void lib_id_recalc_data_tag(Main *bmain, ID *id) -{ - id->tag |= LIB_TAG_ID_RECALC_DATA; - DEG_id_type_tag(bmain, GS(id->name)); -} - namespace { void deg_graph_id_tag_update(Main *bmain, Depsgraph *graph, ID *id, int flag); -void lib_id_recalc_tag_flag(Main *bmain, ID *id, int flag) -{ - /* This bit of code ensures legacy object->recalc flags are still filled in - * the same way as it was expected with the old dependency graph. - * - * This is because some areas like motion paths and likely some other - * physics baking process are doing manual scene update on all the frames, - * trying to minimize number of updates. - * - * But this flag will also let us to re-construct entry nodes for update - * after relations update and after layer visibility changes. - */ - if (flag) { - if (flag & OB_RECALC_OB) { - lib_id_recalc_tag(bmain, id); - } - if (flag & (OB_RECALC_DATA | PSYS_RECALC)) { - lib_id_recalc_data_tag(bmain, id); - } - } - else { - lib_id_recalc_tag(bmain, id); - } -} - -/* Special tagging */ -void id_tag_update_special_zero_flag(Depsgraph *graph, IDDepsNode *id_node) -{ - /* NOTE: Full ID node update for now, need to minimize that i9n the future. */ - id_node->tag_update(graph); -} - -/* Tag corresponding to OB_RECALC_OB. */ -void id_tag_update_object_transform(Depsgraph *graph, IDDepsNode *id_node) +void depsgraph_geometry_tag_to_component(const ID *id, + eDepsNode_Type *component_type) { - ComponentDepsNode *transform_comp = - id_node->find_component(DEG_NODE_TYPE_TRANSFORM); - if (transform_comp == NULL) { -#ifdef STRICT_COMPONENT_TAGGING - DEG_ERROR_PRINTF("ERROR: Unable to find transform component for %s\n", - id_node->id_orig->name); - BLI_assert(!"This is not supposed to happen!"); -#endif - return; - } - transform_comp->tag_update(graph); -} - -/* Tag corresponding to OB_RECALC_DATA. */ -void id_tag_update_object_data(Depsgraph *graph, IDDepsNode *id_node) -{ - const ID_Type id_type = GS(id_node->id_orig->name); - ComponentDepsNode *data_comp = NULL; + const ID_Type id_type = GS(id->name); switch (id_type) { case ID_OB: { - const Object *object = (Object *)id_node->id_orig; + const Object *object = (Object *)id; switch (object->type) { case OB_MESH: case OB_CURVE: case OB_SURF: case OB_FONT: case OB_MBALL: - data_comp = id_node->find_component(DEG_NODE_TYPE_GEOMETRY); + *component_type = DEG_NODE_TYPE_GEOMETRY; break; case OB_ARMATURE: - data_comp = id_node->find_component(DEG_NODE_TYPE_EVAL_POSE); + *component_type = DEG_NODE_TYPE_EVAL_POSE; break; - /* TODO(sergey): More cases here? */ + /* TODO(sergey): More cases here? */ } break; } case ID_ME: - data_comp = id_node->find_component(DEG_NODE_TYPE_GEOMETRY); + *component_type = DEG_NODE_TYPE_GEOMETRY; break; case ID_PA: return; case ID_LP: - data_comp = id_node->find_component(DEG_NODE_TYPE_PARAMETERS); + *component_type = DEG_NODE_TYPE_PARAMETERS; break; default: break; } - if (data_comp == NULL) { -#ifdef STRICT_COMPONENT_TAGGING - DEG_ERROR_PRINTF("ERROR: Unable to find data component for %s\n", - id_node->id_orig->name); - BLI_assert(!"This is not supposed to happen!"); -#endif - return; - } - data_comp->tag_update(graph); - /* Special legacy compatibility code, tag data ID for update when object - * is tagged for data update. - */ - if (id_type == ID_OB) { - Object *object = (Object *)id_node->id_orig; - ID *data_id = (ID *)object->data; - if (data_id != NULL) { - IDDepsNode *data_id_node = graph->find_id_node(data_id); - // BLI_assert(data_id_node != NULL); - /* TODO(sergey): Do we want more granular tags here? */ - /* TODO(sergey): Hrm, during some operations it's possible to have - * object node existing but not it's data. For example, when making - * objects local. This is valid situation, but how can we distinguish - * that from someone trying to do stupid things with dependency - * graph? - */ - if (data_id_node != NULL) { - data_id_node->tag_update(graph); - } - } - } -} - -/* Tag corresponding to OB_RECALC_TIME. */ -void id_tag_update_object_time(Depsgraph *graph, IDDepsNode *id_node) -{ - ComponentDepsNode *animation_comp = - id_node->find_component(DEG_NODE_TYPE_ANIMATION); - if (animation_comp == NULL) { - /* It's not necessarily we've got animation component in cases when - * we are tagging for time updates. - */ - return; - } - animation_comp->tag_update(graph); - /* TODO(sergey): More components to tag here? */ -} - -void id_tag_update_particle(Depsgraph *graph, IDDepsNode *id_node, int tag) -{ - ComponentDepsNode *particle_comp = - id_node->find_component(DEG_NODE_TYPE_PARAMETERS); - ParticleSettings *particle_settings = (ParticleSettings *)id_node->id_orig; - particle_settings->recalc |= (tag & PSYS_RECALC); - if (particle_comp == NULL) { -#ifdef STRICT_COMPONENT_TAGGING - DEG_ERROR_PRINTF("ERROR: Unable to find particle component for %s\n", - id_node->id_orig->name); - BLI_assert(!"This is not supposed to happen!"); -#endif - return; - } - particle_comp->tag_update(graph); -} - -void id_tag_update_shading(Depsgraph *graph, IDDepsNode *id_node) -{ - ComponentDepsNode *shading_comp; - if (GS(id_node->id_orig->name) == ID_NT) { - shading_comp = id_node->find_component(DEG_NODE_TYPE_SHADING_PARAMETERS); - } - else { - shading_comp = id_node->find_component(DEG_NODE_TYPE_SHADING); - } - if (shading_comp == NULL) { -#ifdef STRICT_COMPONENT_TAGGING - DEG_ERROR_PRINTF("ERROR: Unable to find shading component for %s\n", - id_node->id_orig->name); - BLI_assert(!"This is not supposed to happen!"); -#endif - return; - } - shading_comp->tag_update(graph); -} - -/* Tag corresponding to DEG_TAG_COPY_ON_WRITE. */ -void id_tag_update_copy_on_write(Depsgraph *graph, IDDepsNode *id_node) -{ - if (!DEG_depsgraph_use_copy_on_write()) { - return; - } - ComponentDepsNode *cow_comp = - id_node->find_component(DEG_NODE_TYPE_COPY_ON_WRITE); - OperationDepsNode *cow_node = cow_comp->get_entry_operation(); - cow_node->tag_update(graph); } -void id_tag_update_select_update(Depsgraph *graph, IDDepsNode *id_node) +void depsgraph_select_tag_to_component_opcode( + const ID *id, + eDepsNode_Type *component_type, + eDepsOperation_Code *operation_code) { - ComponentDepsNode *component; - OperationDepsNode *node = NULL; - const ID_Type id_type = GS(id_node->id_orig->name); + const ID_Type id_type = GS(id->name); if (id_type == ID_SCE) { /* We need to flush base flags to all objects in a scene since we * don't know which ones changed. However, we don't want to update @@ -292,62 +131,124 @@ void id_tag_update_select_update(Depsgraph *graph, IDDepsNode *id_node) * does nothing and which is only used to cascade flush down the * road. */ - component = id_node->find_component(DEG_NODE_TYPE_LAYER_COLLECTIONS); - BLI_assert(component != NULL); - if (component != NULL) { - node = component->find_operation(DEG_OPCODE_VIEW_LAYER_DONE); - } + *component_type = DEG_NODE_TYPE_LAYER_COLLECTIONS; + *operation_code = DEG_OPCODE_VIEW_LAYER_DONE; } else if (id_type == ID_OB) { - component = id_node->find_component(DEG_NODE_TYPE_LAYER_COLLECTIONS); - /* NOTE: This component might be missing for indirectly linked - * objects. - */ - if (component != NULL) { - node = component->find_operation(DEG_OPCODE_OBJECT_BASE_FLAGS); - } + *component_type = DEG_NODE_TYPE_LAYER_COLLECTIONS; + *operation_code = DEG_OPCODE_OBJECT_BASE_FLAGS; } else { - component = id_node->find_component(DEG_NODE_TYPE_BATCH_CACHE); - BLI_assert(component != NULL); - if (component != NULL) { - node = component->find_operation(DEG_OPCODE_GEOMETRY_SELECT_UPDATE, - "", -1); - } - } - if (node != NULL) { - node->tag_update(graph); + *component_type = DEG_NODE_TYPE_BATCH_CACHE; + *operation_code = DEG_OPCODE_GEOMETRY_SELECT_UPDATE; } } -void id_tag_update_base_flags(Depsgraph *graph, IDDepsNode *id_node) +void depsgraph_base_flags_tag_to_component_opcode( + const ID *id, + eDepsNode_Type *component_type, + eDepsOperation_Code *operation_code) { - ComponentDepsNode *component; - OperationDepsNode *node = NULL; - const ID_Type id_type = GS(id_node->id_orig->name); + const ID_Type id_type = GS(id->name); if (id_type == ID_SCE) { - component = id_node->find_component(DEG_NODE_TYPE_LAYER_COLLECTIONS); - if (component == NULL) { - return; - } - node = component->find_operation(DEG_OPCODE_VIEW_LAYER_INIT); + *component_type = DEG_NODE_TYPE_LAYER_COLLECTIONS; + *operation_code = DEG_OPCODE_VIEW_LAYER_INIT; } else if (id_type == ID_OB) { - component = id_node->find_component(DEG_NODE_TYPE_LAYER_COLLECTIONS); - if (component == NULL) { - return; - } - node = component->find_operation(DEG_OPCODE_OBJECT_BASE_FLAGS); - if (node == NULL) { - return; - } + *component_type = DEG_NODE_TYPE_LAYER_COLLECTIONS; + *operation_code = DEG_OPCODE_OBJECT_BASE_FLAGS; } - if (node != NULL) { - node->tag_update(graph); +} + +void depsgraph_tag_to_component_opcode(const ID *id, + eDepsgraph_Tag tag, + eDepsNode_Type *component_type, + eDepsOperation_Code *operation_code) +{ + const ID_Type id_type = GS(id->name); + *component_type = DEG_NODE_TYPE_UNDEFINED; + *operation_code = DEG_OPCODE_OPERATION; + /* Special case for now, in the future we should get rid of this. */ + if (tag == 0) { + *component_type = DEG_NODE_TYPE_ID_REF; + *operation_code = DEG_OPCODE_OPERATION; + return; + } + switch (tag) { + case DEG_TAG_TRANSFORM: + *component_type = DEG_NODE_TYPE_TRANSFORM; + break; + case DEG_TAG_GEOMETRY: + depsgraph_geometry_tag_to_component(id, component_type); + break; + case DEG_TAG_TIME: + *component_type = DEG_NODE_TYPE_ANIMATION; + break; + case DEG_TAG_PSYS_REDO: + case DEG_TAG_PSYS_RESET: + case DEG_TAG_PSYS_TYPE: + case DEG_TAG_PSYS_CHILD: + case DEG_TAG_PSYS_PHYS: + if (id_type == ID_PA) { + /* NOTES: + * - For particle settings node we need to use different + * component. Will be nice to get this unified with object, + * but we can survive for now with single exception here. + * Particles needs reconsideration anyway, + * - We do direct injection of particle settings recalc flag + * here. This is what we need to do for until particles + * are switched away from own recalc flag and are using + * ID->recalc flags instead. + */ + ParticleSettings *particle_settings = (ParticleSettings *)id; + particle_settings->recalc |= (tag & DEG_TAG_PSYS_ALL); + *component_type = DEG_NODE_TYPE_PARAMETERS; + } + else { + *component_type = DEG_NODE_TYPE_EVAL_PARTICLES; + } + break; + case DEG_TAG_COPY_ON_WRITE: + *component_type = DEG_NODE_TYPE_COPY_ON_WRITE; + break; + case DEG_TAG_SHADING_UPDATE: + if (id_type == ID_NT) { + *component_type = DEG_NODE_TYPE_SHADING_PARAMETERS; + } + else { + *component_type = DEG_NODE_TYPE_SHADING; + } + break; + case DEG_TAG_SELECT_UPDATE: + depsgraph_select_tag_to_component_opcode(id, + component_type, + operation_code); + break; + case DEG_TAG_BASE_FLAGS_UPDATE: + depsgraph_base_flags_tag_to_component_opcode(id, + component_type, + operation_code); + case DEG_TAG_EDITORS_UPDATE: + /* There is no such node in depsgraph, this tag is to be handled + * separately. + */ + break; + case DEG_TAG_PSYS_ALL: + BLI_assert(!"Should not happen"); + break; + } +} + +void id_tag_update_ntree_special(Main *bmain, Depsgraph *graph, ID *id, int flag) +{ + bNodeTree *ntree = ntreeFromID(id); + if (ntree == NULL) { + return; } + deg_graph_id_tag_update(bmain, graph, &ntree->id, flag); } -void id_tag_update_editors_update(Main *bmain, Depsgraph *graph, ID *id) +void depsgraph_update_editors_tag(Main *bmain, Depsgraph *graph, ID *id) { /* NOTE: We handle this immediately, without delaying anything, to be * sure we don't cause threading issues with OpenGL. @@ -355,96 +256,158 @@ void id_tag_update_editors_update(Main *bmain, Depsgraph *graph, ID *id) /* TODO(sergey): Make sure this works for CoW-ed datablocks as well. */ DEGEditorUpdateContext update_ctx = {NULL}; update_ctx.bmain = bmain; + update_ctx.depsgraph = (::Depsgraph *)graph; update_ctx.scene = graph->scene; update_ctx.view_layer = graph->view_layer; deg_editors_id_update(&update_ctx, id); } -void id_tag_update_ntree_special(Main *bmain, Depsgraph *graph, ID *id, int flag) +void depsgraph_tag_component(Depsgraph *graph, + IDDepsNode *id_node, + eDepsNode_Type component_type, + eDepsOperation_Code operation_code) { - bNodeTree *ntree = NULL; - switch (GS(id->name)) { - case ID_MA: - ntree = ((Material *)id)->nodetree; - break; - default: - break; - } - if (ntree == NULL) { + ComponentDepsNode *component_node = + id_node->find_component(component_type); + if (component_node == NULL) { return; } - IDDepsNode *id_node = graph->find_id_node(&ntree->id); - if (id_node != NULL) { - deg_graph_id_tag_update(bmain, graph, id_node->id_orig, flag); + if (operation_code == DEG_OPCODE_OPERATION) { + component_node->tag_update(graph); + } + else { + OperationDepsNode *operation_node = + component_node->find_operation(operation_code); + if (operation_node != NULL) { + operation_node->tag_update(graph); + } } } -void deg_graph_id_tag_update(Main *bmain, Depsgraph *graph, ID *id, int flag) +/* This is a tag compatibility with legacy code. + * + * Mainly, old code was tagging object with OB_RECALC_DATA tag to inform + * that object's data datablock changed. Now API expects that ID is given + * explicitly, but not all areas are aware of this yet. + */ +void deg_graph_id_tag_legacy_compat(Main *bmain, + ID *id, + eDepsgraph_Tag tag) { - Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(graph); - IDDepsNode *id_node = deg_graph->find_id_node(id); - /* Make sure legacy flags are all nicely update. */ - lib_id_recalc_tag_flag(bmain, id, flag); - if (id_node == NULL) { - /* Shouldn't happen, but better be sure here. */ - return; - } - /* Tag components based on flags. */ - if (flag == 0) { - id_tag_update_special_zero_flag(graph, id_node); - id_tag_update_ntree_special(bmain, graph, id, flag); - return; - } - if (flag & OB_RECALC_OB) { - id_tag_update_object_transform(graph, id_node); - } - if (flag & OB_RECALC_DATA) { - id_tag_update_object_data(graph, id_node); - if (DEG_depsgraph_use_copy_on_write()) { - if (flag & DEG_TAG_COPY_ON_WRITE) { - const ID_Type id_type = GS(id_node->id_orig->name); - if (id_type == ID_OB) { - Object *object = (Object *)id_node->id_orig; - ID *ob_data = (ID *)object->data; - DEG_id_tag_update_ex(bmain, ob_data, flag); - } - } + if (tag == DEG_TAG_GEOMETRY && GS(id->name) == ID_OB) { + Object *object = (Object *)id; + ID *data_id = (ID *)object->data; + if (data_id != NULL) { + DEG_id_tag_update_ex(bmain, data_id, 0); } } - if (flag & OB_RECALC_TIME) { - id_tag_update_object_time(graph, id_node); - } - if (flag & PSYS_RECALC) { - id_tag_update_particle(graph, id_node, flag); +} + +void deg_graph_id_tag_update_single_flag(Main *bmain, + Depsgraph *graph, + ID *id, + IDDepsNode *id_node, + eDepsgraph_Tag tag) +{ + if (tag == DEG_TAG_EDITORS_UPDATE) { + if (graph != NULL) { + depsgraph_update_editors_tag(bmain, graph, id); + } + return; } - if (flag & DEG_TAG_SHADING_UPDATE) { - id_tag_update_shading(graph, id_node); + /* Get description of what is to be tagged. */ + eDepsNode_Type component_type; + eDepsOperation_Code operation_code; + depsgraph_tag_to_component_opcode(id, + tag, + &component_type, + &operation_code); + /* Check whether we've got something to tag. */ + if (component_type == DEG_NODE_TYPE_UNDEFINED) { + /* Given ID does not support tag. */ + /* TODO(sergey): Shall we raise some panic here? */ + return; } - if (flag & DEG_TAG_COPY_ON_WRITE) { - id_tag_update_copy_on_write(graph, id_node); + /* Tag ID recalc flag. */ + DepsNodeFactory *factory = deg_type_get_factory(component_type); + BLI_assert(factory != NULL); + id->recalc |= factory->id_recalc_tag(); + /* Some sanity checks before moving forward. */ + if (id_node == NULL) { + /* Happens when object is tagged for update and not yet in the + * dependency graph (but will be after relations update). + */ + return; } - if (flag & DEG_TAG_SELECT_UPDATE) { - id_tag_update_select_update(graph, id_node); + /* Tag corresponding dependency graph operation for update. */ + if (component_type == DEG_NODE_TYPE_ID_REF) { + id_node->tag_update(graph); } - if (flag & DEG_TAG_BASE_FLAGS_UPDATE) { - id_tag_update_base_flags(graph, id_node); + else { + depsgraph_tag_component(graph, id_node, component_type, operation_code); } - if (flag & DEG_TAG_EDITORS_UPDATE) { - id_tag_update_editors_update(bmain, graph, id); + /* TODO(sergey): Get rid of this once all areas are using proper data ID + * for tagging. + */ + deg_graph_id_tag_legacy_compat(bmain, id, tag); + +} + +void deg_graph_id_tag_update(Main *bmain, Depsgraph *graph, ID *id, int flag) +{ + IDDepsNode *id_node = (graph != NULL) ? graph->find_id_node(id) + : NULL; + DEG_id_type_tag(bmain, GS(id->name)); + if (flag == 0) { + /* TODO(sergey): Which recalc flags to set here? */ + id->recalc |= ID_RECALC_ALL; + if (id_node != NULL) { + id_node->tag_update(graph); + } } + int current_flag = flag; + while (current_flag != 0) { + eDepsgraph_Tag tag = + (eDepsgraph_Tag)(1 << bitscan_forward_clear_i(¤t_flag)); + deg_graph_id_tag_update_single_flag(bmain, + graph, + id, + id_node, + tag); + } + /* Special case for nested node tree datablocks. */ id_tag_update_ntree_special(bmain, graph, id, flag); } +/* TODO(sergey): Consider storing scene and view layer at depsgraph allocation + * time. + */ +void deg_ensure_scene_view_layer(Depsgraph *graph, + Scene *scene, + ViewLayer *view_layer) +{ + if (!graph->need_update) { + return; + } + graph->scene = scene; + graph->view_layer = view_layer; +} + void deg_id_tag_update(Main *bmain, ID *id, int flag) { - lib_id_recalc_tag_flag(bmain, id, flag); - LINKLIST_FOREACH(Scene *, scene, &bmain->scene) { - LINKLIST_FOREACH(ViewLayer *, view_layer, &scene->view_layers) { + deg_graph_id_tag_update(bmain, NULL, id, flag); + BLI_LISTBASE_FOREACH (Scene *, scene, &bmain->scene) { + BLI_LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) { Depsgraph *depsgraph = (Depsgraph *)BKE_scene_get_depsgraph(scene, view_layer, false); if (depsgraph != NULL) { + /* Make sure depsgraph is pointing to a correct scene and + * view layer. This is mainly required in cases when depsgraph + * was not built yet. + */ + deg_ensure_scene_view_layer(depsgraph, scene, view_layer); deg_graph_id_tag_update(bmain, depsgraph, id, flag); } } @@ -469,7 +432,10 @@ void deg_graph_on_visible_update(Main *bmain, Depsgraph *graph) deg_graph_id_tag_update(bmain, graph, id_node->id_orig, flag); } /* Make sure collection properties are up to date. */ - for (Scene *scene_iter = graph->scene; scene_iter != NULL; scene_iter = scene_iter->set) { + for (Scene *scene_iter = graph->scene; + scene_iter != NULL; + scene_iter = scene_iter->set) + { IDDepsNode *scene_id_node = graph->find_id_node(&scene_iter->id); BLI_assert(scene_id_node != NULL); scene_id_node->tag_update(graph); @@ -480,6 +446,8 @@ void deg_graph_on_visible_update(Main *bmain, Depsgraph *graph) } // namespace DEG +/* Data-Based Tagging */ + /* Tag given ID for an update in all the dependency graphs. */ void DEG_id_tag_update(ID *id, int flag) { @@ -539,8 +507,8 @@ void DEG_graph_on_visible_update(Main *bmain, Depsgraph *depsgraph) void DEG_on_visible_update(Main *bmain, const bool UNUSED(do_time)) { - LINKLIST_FOREACH(Scene *, scene, &bmain->scene) { - LINKLIST_FOREACH(ViewLayer *, view_layer, &scene->view_layers) { + BLI_LISTBASE_FOREACH (Scene *, scene, &bmain->scene) { + BLI_LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) { Depsgraph *depsgraph = (Depsgraph *)BKE_scene_get_depsgraph(scene, view_layer, @@ -556,6 +524,7 @@ void DEG_on_visible_update(Main *bmain, const bool UNUSED(do_time)) * editors about this. */ void DEG_ids_check_recalc(Main *bmain, + Depsgraph *depsgraph, Scene *scene, ViewLayer *view_layer, bool time) @@ -578,6 +547,7 @@ void DEG_ids_check_recalc(Main *bmain, DEGEditorUpdateContext update_ctx = {NULL}; update_ctx.bmain = bmain; + update_ctx.depsgraph = depsgraph; update_ctx.scene = scene; update_ctx.view_layer = view_layer; DEG::deg_editors_scene_update(&update_ctx, (updated || time)); @@ -601,12 +571,12 @@ void DEG_ids_clear_recalc(Main *bmain) if (id && bmain->id_tag_update[BKE_idcode_to_index(GS(id->name))]) { for (; id; id = (ID *)id->next) { - id->tag &= ~(LIB_TAG_ID_RECALC | LIB_TAG_ID_RECALC_DATA); + id->recalc &= ~ID_RECALC_ALL; /* Some ID's contain semi-datablock nodetree */ ntree = ntreeFromID(id); if (ntree != NULL) { - ntree->id.tag &= ~(LIB_TAG_ID_RECALC | LIB_TAG_ID_RECALC_DATA); + ntree->id.recalc &= ~ID_RECALC_ALL; } } } diff --git a/source/blender/depsgraph/intern/depsgraph_type_defines.cc b/source/blender/depsgraph/intern/depsgraph_type_defines.cc index 24fbb8d6e6e..22df3161428 100644 --- a/source/blender/depsgraph/intern/depsgraph_type_defines.cc +++ b/source/blender/depsgraph/intern/depsgraph_type_defines.cc @@ -51,14 +51,7 @@ namespace DEG { /* Global type registry */ -/** - * \note For now, this is a hashtable not array, since the core node types - * currently do not have contiguous ID values. Using a hash here gives us - * more flexibility, albeit using more memory and also sacrificing a little - * speed. Later on, when things stabilise we may turn this back to an array - * since there are only just a few node types that an array would cope fine... - */ -static GHash *_depsnode_typeinfo_registry = NULL; +static DepsNodeFactory *depsnode_typeinfo_registry[NUM_DEG_NODE_TYPES] = {NULL}; /* Registration ------------------------------------------- */ @@ -66,28 +59,16 @@ static GHash *_depsnode_typeinfo_registry = NULL; void deg_register_node_typeinfo(DepsNodeFactory *factory) { BLI_assert(factory != NULL); - BLI_ghash_insert(_depsnode_typeinfo_registry, - SET_INT_IN_POINTER(factory->type()), - factory); + depsnode_typeinfo_registry[factory->type()] = factory; } /* Getters ------------------------------------------------- */ /* Get typeinfo for specified type */ -DepsNodeFactory *deg_get_node_factory(const eDepsNode_Type type) +DepsNodeFactory *deg_type_get_factory(const eDepsNode_Type type) { /* look up type - at worst, it doesn't exist in table yet, and we fail */ - return (DepsNodeFactory *)BLI_ghash_lookup(_depsnode_typeinfo_registry, - SET_INT_IN_POINTER(type)); -} - -/* Get typeinfo for provided node */ -DepsNodeFactory *deg_node_get_factory(const DepsNode *node) -{ - if (node != NULL) { - return NULL; - } - return deg_get_node_factory(node->type); + return depsnode_typeinfo_registry[type]; } /* Stringified opcodes ------------------------------------- */ @@ -183,9 +164,6 @@ const char *DepsOperationStringifier::operator[](eDepsOperation_Code opcode) /* Register all node types */ void DEG_register_node_types(void) { - /* initialise registry */ - DEG::_depsnode_typeinfo_registry = BLI_ghash_int_new("Depsgraph Node Type Registry"); - /* register node types */ DEG::deg_register_base_depsnodes(); DEG::deg_register_component_depsnodes(); @@ -195,5 +173,4 @@ void DEG_register_node_types(void) /* Free registry on exit */ void DEG_free_node_types(void) { - BLI_ghash_free(DEG::_depsnode_typeinfo_registry, NULL, NULL); } diff --git a/source/blender/depsgraph/intern/depsgraph_types.h b/source/blender/depsgraph/intern/depsgraph_types.h index b12becc5589..d091f42bf80 100644 --- a/source/blender/depsgraph/intern/depsgraph_types.h +++ b/source/blender/depsgraph/intern/depsgraph_types.h @@ -96,9 +96,9 @@ typedef enum eDepsNode_LinkedState_Type { /* Types of Nodes */ typedef enum eDepsNode_Type { /* Fallback type for invalid return value */ - DEG_NODE_TYPE_UNDEFINED = -1, + DEG_NODE_TYPE_UNDEFINED = 0, /* Inner Node (Operation) */ - DEG_NODE_TYPE_OPERATION = 0, + DEG_NODE_TYPE_OPERATION, /* **** Generic Types **** */ @@ -149,6 +149,9 @@ typedef enum eDepsNode_Type { DEG_NODE_TYPE_CACHE, /* Batch Cache Component */ DEG_NODE_TYPE_BATCH_CACHE, + + /* Total number of meaningful node types. */ + NUM_DEG_NODE_TYPES, } eDepsNode_Type; /* Identifiers for common operations (as an enum). */ diff --git a/source/blender/depsgraph/intern/eval/deg_eval.cc b/source/blender/depsgraph/intern/eval/deg_eval.cc index 5aebd6814a0..a6c6a16a528 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval.cc @@ -46,20 +46,16 @@ #include "atomic_ops.h" #include "intern/eval/deg_eval_flush.h" +#include "intern/eval/deg_eval_stats.h" #include "intern/nodes/deg_node.h" #include "intern/nodes/deg_node_component.h" +#include "intern/nodes/deg_node_id.h" #include "intern/nodes/deg_node_operation.h" +#include "intern/nodes/deg_node_time.h" #include "intern/depsgraph.h" #include "intern/depsgraph_intern.h" -#include "util/deg_util_foreach.h" - -/* Unfinished and unused, and takes quite some pre-processing time. */ -#undef USE_EVAL_PRIORITY -/* Use integrated debugger to keep track how much each of the nodes was - * evaluating. - */ -#undef USE_DEBUGGER +#include "util/deg_util_foreach.h" namespace DEG { @@ -75,52 +71,28 @@ static void schedule_children(TaskPool *pool, struct DepsgraphEvalState { EvaluationContext *eval_ctx; Depsgraph *graph; + bool do_stats; }; static void deg_task_run_func(TaskPool *pool, void *taskdata, int thread_id) { - DepsgraphEvalState *state = - reinterpret_cast<DepsgraphEvalState *>(BLI_task_pool_userdata(pool)); - OperationDepsNode *node = reinterpret_cast<OperationDepsNode *>(taskdata); - + void *userdata_v = BLI_task_pool_userdata(pool); + DepsgraphEvalState *state = (DepsgraphEvalState *)userdata_v; + OperationDepsNode *node = (OperationDepsNode *)taskdata; + /* Sanity checks. */ BLI_assert(!node->is_noop() && "NOOP nodes should not actually be scheduled"); - - /* Should only be the case for NOOPs, which never get to this point. */ - BLI_assert(node->evaluate); - - /* Get context. */ - /* TODO: Who initialises this? "Init" operations aren't able to - * initialise it!!! - */ - /* TODO(sergey): We don't use component contexts at this moment. */ - /* ComponentDepsNode *comp = node->owner; */ - BLI_assert(node->owner != NULL); - - /* Since we're not leaving the thread for until the graph branches it is - * possible to have NO-OP on the way. for which evaluate() will be NULL. - * but that's all fine, we'll just scheduler it's children. - */ - if (node->evaluate) { - /* Take note of current time. */ -#ifdef USE_DEBUGGER - double start_time = PIL_check_seconds_timer(); - DepsgraphDebug::task_started(state->graph, node); -#endif - - /* Perform operation. */ + /* Perform operation. */ + if (state->do_stats) { + const double start_time = PIL_check_seconds_timer(); node->evaluate(state->eval_ctx); - - /* Note how long this took. */ -#ifdef USE_DEBUGGER - double end_time = PIL_check_seconds_timer(); - DepsgraphDebug::task_completed(state->graph, - node, - end_time - start_time); -#endif + node->stats.current_time += PIL_check_seconds_timer() - start_time; } - + else { + node->evaluate(state->eval_ctx); + } + /* Schedule children. */ BLI_task_pool_delayed_push_begin(pool, thread_id); schedule_children(pool, state->graph, node, thread_id); BLI_task_pool_delayed_push_end(pool, thread_id); @@ -130,7 +102,10 @@ typedef struct CalculatePengindData { Depsgraph *graph; } CalculatePengindData; -static void calculate_pending_func(void *data_v, int i) +static void calculate_pending_func( + void *__restrict data_v, + const int i, + const ParallelRangeTLS *__restrict /*tls*/) { CalculatePengindData *data = (CalculatePengindData *)data_v; Depsgraph *graph = data->graph; @@ -157,42 +132,30 @@ static void calculate_pending_func(void *data_v, int i) static void calculate_pending_parents(Depsgraph *graph) { const int num_operations = graph->operations.size(); - const bool do_threads = num_operations > 256; CalculatePengindData data; data.graph = graph; + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.min_iter_per_thread = 1024; BLI_task_parallel_range(0, num_operations, &data, calculate_pending_func, - do_threads); + &settings); } -#ifdef USE_EVAL_PRIORITY -static void calculate_eval_priority(OperationDepsNode *node) +static void initialize_execution(DepsgraphEvalState *state, Depsgraph *graph) { - if (node->done) { - return; - } - node->done = 1; - - if (node->flag & DEPSOP_FLAG_NEEDS_UPDATE) { - /* XXX standard cost of a node, could be estimated somewhat later on */ - const float cost = 1.0f; - /* NOOP nodes have no cost */ - node->eval_priority = node->is_noop() ? cost : 0.0f; - - foreach (DepsRelation *rel, node->outlinks) { - OperationDepsNode *to = (OperationDepsNode *)rel->to; - BLI_assert(to->type == DEG_NODE_TYPE_OPERATION); - calculate_eval_priority(to); - node->eval_priority += to->eval_priority; + const bool do_stats = state->do_stats; + calculate_pending_parents(graph); + /* Clear tags and other things which needs to be clear. */ + foreach (OperationDepsNode *node, graph->operations) { + node->done = 0; + if (do_stats) { + node->stats.reset_current(); } } - else { - node->eval_priority = 0.0f; - } } -#endif /* Schedule a node if it needs evaluation. * dec_parents: Decrement pending parents count, true when child nodes are @@ -267,28 +230,23 @@ static void schedule_children(TaskPool *pool, void deg_evaluate_on_refresh(EvaluationContext *eval_ctx, Depsgraph *graph) { - /* Generate base evaluation context, upon which all the others are derived. */ - // TODO: this needs both main and scene access... - /* Nothing to update, early out. */ if (BLI_gset_size(graph->entry_tags) == 0) { return; } - /* Set time for the current graph evaluation context. */ TimeSourceDepsNode *time_src = graph->find_time_source(); eval_ctx->depsgraph = (::Depsgraph *)graph; eval_ctx->view_layer = DEG_get_evaluated_view_layer((::Depsgraph *)graph); eval_ctx->ctime = time_src->cfra; - - /* XXX could use a separate pool for each eval context */ + /* Set up evaluation context for depsgraph itself. */ DepsgraphEvalState state; state.eval_ctx = eval_ctx; state.graph = graph; - + state.do_stats = (G.debug_value != 0); + /* Set up task scheduler and pull for threaded evaluation. */ TaskScheduler *task_scheduler; bool need_free_scheduler; - if (G.debug & G_DEBUG_DEPSGRAPH_NO_THREADS) { task_scheduler = BLI_task_scheduler_create(1); need_free_scheduler = true; @@ -297,31 +255,22 @@ void deg_evaluate_on_refresh(EvaluationContext *eval_ctx, task_scheduler = BLI_task_scheduler_get(); need_free_scheduler = false; } - TaskPool *task_pool = BLI_task_pool_create_suspended(task_scheduler, &state); - - calculate_pending_parents(graph); - - /* Clear tags. */ - foreach (OperationDepsNode *node, graph->operations) { - node->done = 0; - } - - /* Calculate priority for operation nodes. */ -#ifdef USE_EVAL_PRIORITY - foreach (OperationDepsNode *node, graph->operations) { - calculate_eval_priority(node); - } -#endif - + /* Prepare all nodes for evaluation. */ + initialize_execution(&state, graph); + /* Do actual evaluation now. */ schedule_graph(task_pool, graph); - BLI_task_pool_work_and_wait(task_pool); BLI_task_pool_free(task_pool); - + /* Finalize statistics gathering. This is because we only gather single + * operation timing here, without aggregating anything to avoid any extra + * synchronization. + */ + if (state.do_stats) { + deg_eval_stats_aggregate(graph); + } /* Clear any uncleared tags - just in case. */ deg_graph_clear_tags(graph); - if (need_free_scheduler) { BLI_task_scheduler_free(task_scheduler); } diff --git a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc index 97e38af4367..a6668208574 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc @@ -46,6 +46,7 @@ #include "BLI_string.h" #include "BKE_global.h" +#include "BKE_idprop.h" #include "BKE_layer.h" #include "BKE_library.h" #include "BKE_main.h" @@ -80,6 +81,7 @@ extern "C" { #include "intern/depsgraph.h" #include "intern/builder/deg_builder_nodes.h" #include "intern/nodes/deg_node.h" +#include "intern/nodes/deg_node_id.h" namespace DEG { @@ -324,7 +326,6 @@ static bool check_datablocks_copy_on_writable(const ID *id_orig) return !ELEM(id_type, ID_BR, ID_LS, ID_AC, - ID_GR, ID_PAL); } @@ -467,6 +468,137 @@ void update_special_pointers(const Depsgraph *depsgraph, } } +void update_copy_on_write_layer_collections( + ListBase *layer_collections_cow, + const ListBase *layer_collections_orig); + +void update_copy_on_write_layer_collection( + LayerCollection *layer_collection_cow, + const LayerCollection *layer_collection_orig) +{ + // Make a local copy of original layer collection, so we can start + // modifying it. + LayerCollection local = *layer_collection_orig; + // Copy all pointer data from original CoW version of layer collection. + local.next = layer_collection_cow->next; + local.prev = layer_collection_cow->prev; + local.scene_collection = layer_collection_cow->scene_collection; + local.object_bases = layer_collection_cow->object_bases; + local.overrides = layer_collection_cow->overrides; + local.layer_collections = layer_collection_cow->layer_collections; + local.properties = layer_collection_cow->properties; + local.properties_evaluated = layer_collection_cow->properties_evaluated; + // Synchronize pointer-related data. + IDP_Reset(local.properties, layer_collection_orig->properties); + // Copy synchronized version back. + *layer_collection_cow = local; + // Recurs into nested layer collections. + update_copy_on_write_layer_collections( + &layer_collection_cow->layer_collections, + &layer_collection_orig->layer_collections); +} + +void update_copy_on_write_layer_collections( + ListBase *layer_collections_cow, + const ListBase *layer_collections_orig) +{ + const LayerCollection *layer_collection_orig = + (const LayerCollection *)layer_collections_orig->first; + LayerCollection *layer_collection_cow = + (LayerCollection *)layer_collections_cow->first; + while (layer_collection_orig != NULL) { + update_copy_on_write_layer_collection(layer_collection_cow, + layer_collection_orig); + layer_collection_orig = layer_collection_orig->next; + layer_collection_cow = layer_collection_cow->next; + } +} + +void update_copy_on_write_view_layer(const Depsgraph *depsgraph, + ViewLayer *view_layer_cow, + const ViewLayer *view_layer_orig) +{ + // Update pointers to active base. + if (view_layer_orig->basact == NULL) { + view_layer_cow->basact = NULL; + } + else { + const Object *obact_orig = view_layer_orig->basact->object; + Object *obact_cow = (Object *)depsgraph->get_cow_id(&obact_orig->id); + view_layer_cow->basact = BKE_view_layer_base_find(view_layer_cow, obact_cow); + } + // Update base flags. + // + // TODO(sergey): We should probably check visibled/selectabled. + // flag here? + const Base *base_orig = (Base *)view_layer_orig->object_bases.first; + Base *base_cow = (Base *)view_layer_cow->object_bases.first;; + while (base_orig != NULL) { + base_cow->flag = base_orig->flag; + base_orig = base_orig->next; + base_cow = base_cow->next; + } + // Synchronize settings. + view_layer_cow->active_collection = view_layer_orig->active_collection; + view_layer_cow->flag = view_layer_orig->flag; + view_layer_cow->layflag = view_layer_orig->layflag; + view_layer_cow->passflag = view_layer_orig->passflag; + view_layer_cow->pass_alpha_threshold = view_layer_orig->pass_alpha_threshold; + // Synchronize ID properties. + IDP_Reset(view_layer_cow->properties, view_layer_orig->properties); + IDP_Reset(view_layer_cow->id_properties, view_layer_orig->id_properties); + // Synchronize layer collections. + update_copy_on_write_layer_collections( + &view_layer_cow->layer_collections, + &view_layer_orig->layer_collections); +} + +void update_copy_on_write_view_layers(const Depsgraph *depsgraph, + Scene *scene_cow, + const Scene *scene_orig) +{ + const ViewLayer *view_layer_orig = (const ViewLayer *)scene_orig->view_layers.first; + ViewLayer *view_layer_cow = (ViewLayer *)scene_cow->view_layers.first; + while (view_layer_orig != NULL) { + update_copy_on_write_view_layer(depsgraph, + view_layer_cow, + view_layer_orig); + view_layer_orig = view_layer_orig->next; + view_layer_cow = view_layer_cow->next; + } +} + +void update_copy_on_write_scene_collections( + ListBase *collections_cow, + const ListBase *collections_orig); + +void update_copy_on_write_scene_collection( + SceneCollection *collection_cow, + const SceneCollection *collection_orig) +{ + collection_cow->active_object_index = collection_orig->active_object_index; + update_copy_on_write_scene_collections( + &collection_cow->scene_collections, + &collection_orig->scene_collections); +} + +void update_copy_on_write_scene_collections( + ListBase *collections_cow, + const ListBase *collections_orig) +{ + const SceneCollection *nested_collection_orig = + (const SceneCollection *)collections_orig->first; + SceneCollection *nested_collection_cow = + (SceneCollection *)collections_cow->first; + while (nested_collection_orig != NULL) { + update_copy_on_write_scene_collection( + nested_collection_cow, + nested_collection_orig); + nested_collection_orig = nested_collection_orig->next; + nested_collection_cow = nested_collection_cow->next; + } +} + /* Update copy-on-write version of scene from original scene. */ void update_copy_on_write_scene(const Depsgraph *depsgraph, Scene *scene_cow, @@ -476,33 +608,10 @@ void update_copy_on_write_scene(const Depsgraph *depsgraph, // TODO(sergey): Are we missing something here? scene_cow->r.cfra = scene_orig->r.cfra; scene_cow->r.subframe = scene_orig->r.subframe; - // Update bases. - const ViewLayer *view_layer_orig = (ViewLayer *)scene_orig->view_layers.first; - ViewLayer *view_layer_cow = (ViewLayer *)scene_cow->view_layers.first; - while (view_layer_orig != NULL) { - // Update pointers to active base. - if (view_layer_orig->basact == NULL) { - view_layer_cow->basact = NULL; - } - else { - const Object *obact_orig = view_layer_orig->basact->object; - Object *obact_cow = (Object *)depsgraph->get_cow_id(&obact_orig->id); - view_layer_cow->basact = BKE_view_layer_base_find(view_layer_cow, obact_cow); - } - // Update base flags. - // - // TODO(sergey): We should probably check visibled/selectabled - // flag here? - const Base *base_orig = (Base *)view_layer_orig->object_bases.first; - Base *base_cow = (Base *)view_layer_cow->object_bases.first;; - while (base_orig != NULL) { - base_cow->flag = base_orig->flag; - base_orig = base_orig->next; - base_cow = base_cow->next; - } - view_layer_orig = view_layer_orig->next; - view_layer_cow = view_layer_cow->next; - } + // Update view layers and collections. + update_copy_on_write_view_layers(depsgraph, scene_cow, scene_orig); + update_copy_on_write_scene_collection(scene_cow->collection, + scene_orig->collection); // Update edit object pointer. if (scene_orig->obedit != NULL) { scene_cow->obedit = (Object *)depsgraph->get_cow_id(&scene_orig->obedit->id); @@ -781,7 +890,7 @@ ID *deg_update_copy_on_write_datablock(const Depsgraph *depsgraph, */ if (mesh_evaluated != NULL) { if (object->data == mesh_evaluated) { - object->data = mesh_evaluated->id.newid; + object->data = mesh_evaluated->id.orig_id; } } /* Make a backup of base flags. */ @@ -817,7 +926,7 @@ ID *deg_update_copy_on_write_datablock(const Depsgraph *depsgraph, * pointers are left behind. */ mesh_evaluated->edit_btmesh = - ((Mesh *)mesh_evaluated->id.newid)->edit_btmesh; + ((Mesh *)mesh_evaluated->id.orig_id)->edit_btmesh; } } if (base_collection_properties != NULL) { @@ -921,8 +1030,7 @@ bool deg_validate_copy_on_write_datablock(ID *id_cow) void deg_tag_copy_on_write_id(ID *id_cow, const ID *id_orig) { id_cow->tag |= LIB_TAG_COPY_ON_WRITE; - /* TODO(sergey): Is it safe to re-use newid for original ID link? */ - id_cow->newid = (ID *)id_orig; + id_cow->orig_id = (ID *)id_orig; } bool deg_copy_on_write_is_expanded(const ID *id_cow) diff --git a/source/blender/depsgraph/intern/eval/deg_eval_flush.cc b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc index a30812c692f..c0d5e08b80f 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_flush.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc @@ -36,6 +36,7 @@ #include <deque> #include "BLI_utildefines.h" +#include "BLI_listbase.h" #include "BLI_task.h" #include "BLI_ghash.h" @@ -47,6 +48,7 @@ extern "C" { #include "intern/nodes/deg_node.h" #include "intern/nodes/deg_node_component.h" +#include "intern/nodes/deg_node_id.h" #include "intern/nodes/deg_node_operation.h" #include "intern/depsgraph_intern.h" @@ -70,14 +72,20 @@ typedef std::deque<OperationDepsNode *> FlushQueue; namespace { -void flush_init_operation_node_func(void *data_v, int i) +void flush_init_operation_node_func( + void *__restrict data_v, + const int i, + const ParallelRangeTLS *__restrict /*tls*/) { Depsgraph *graph = (Depsgraph *)data_v; OperationDepsNode *node = graph->operations[i]; node->scheduled = false; } -void flush_init_id_node_func(void *data_v, int i) +void flush_init_id_node_func( + void *__restrict data_v, + const int i, + const ParallelRangeTLS *__restrict /*tls*/) { Depsgraph *graph = (Depsgraph *)data_v; IDDepsNode *id_node = graph->id_nodes[i]; @@ -89,16 +97,26 @@ void flush_init_id_node_func(void *data_v, int i) BLI_INLINE void flush_prepare(Depsgraph *graph) { - const int num_operations = graph->operations.size(); - BLI_task_parallel_range(0, num_operations, - graph, - flush_init_operation_node_func, - (num_operations > 256)); - const int num_id_nodes = graph->id_nodes.size(); - BLI_task_parallel_range(0, num_id_nodes, - graph, - flush_init_id_node_func, - (num_id_nodes > 256)); + { + const int num_operations = graph->operations.size(); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.min_iter_per_thread = 1024; + BLI_task_parallel_range(0, num_operations, + graph, + flush_init_operation_node_func, + &settings); + } + { + const int num_id_nodes = graph->id_nodes.size(); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.min_iter_per_thread = 1024; + BLI_task_parallel_range(0, num_id_nodes, + graph, + flush_init_id_node_func, + &settings); + } } BLI_INLINE void flush_schedule_entrypoints(Depsgraph *graph, FlushQueue *queue) @@ -190,14 +208,27 @@ BLI_INLINE OperationDepsNode *flush_schedule_children( return result; } -BLI_INLINE void flush_editors_id_update(Main *bmain, - Depsgraph *graph, - const DEGEditorUpdateContext *update_ctx) +void flush_engine_data_update(ID *id) +{ + if (GS(id->name) != ID_OB) { + return; + } + Object *object = (Object *)id; + BLI_LISTBASE_FOREACH(ObjectEngineData *, engine_data, &object->drawdata) { + engine_data->recalc |= id->recalc; + } +} + +/* NOTE: It will also accumulate flags from changed components. */ +void flush_editors_id_update(Main *bmain, + Depsgraph *graph, + const DEGEditorUpdateContext *update_ctx) { foreach (IDDepsNode *id_node, graph->id_nodes) { if (id_node->done != ID_STATE_MODIFIED) { continue; } + DEG_id_type_tag(bmain, GS(id_node->id_orig->name)); /* TODO(sergey): Do we need to pass original or evaluated ID here? */ ID *id_orig = id_node->id_orig; ID *id_cow = id_node->id_cow; @@ -205,13 +236,26 @@ BLI_INLINE void flush_editors_id_update(Main *bmain, * This is because DEG_id_tag_update() sets tags on original * data. */ - id_cow->tag |= (id_orig->tag & LIB_TAG_ID_RECALC_ALL); + id_cow->recalc |= (id_orig->recalc & ID_RECALC_ALL); + /* Gather recalc flags from all changed components. */ + GHASH_FOREACH_BEGIN(ComponentDepsNode *, comp_node, id_node->components) + { + if (comp_node->done != COMPONENT_STATE_DONE) { + continue; + } + DepsNodeFactory *factory = deg_type_get_factory(comp_node->type); + BLI_assert(factory != NULL); + id_cow->recalc |= factory->id_recalc_tag(); + } + GHASH_FOREACH_END(); + DEG_DEBUG_PRINTF("Accumulated recalc bits for %s: %u\n", + id_orig->name, (unsigned int)id_cow->recalc); + /* Inform editors. */ if (deg_copy_on_write_is_expanded(id_cow)) { deg_editors_id_update(update_ctx, id_cow); + /* Inform draw engines that something was changed. */ + flush_engine_data_update(id_cow); } - lib_id_recalc_tag(bmain, id_orig); - /* TODO(sergey): For until we've got proper data nodes in the graph. */ - lib_id_recalc_data_tag(bmain, id_orig); } } @@ -236,11 +280,11 @@ void deg_graph_flush_updates(Main *bmain, Depsgraph *graph) FlushQueue queue; flush_schedule_entrypoints(graph, &queue); /* Prepare update context for editors. */ - DEGEditorUpdateContext update_ctx = { - bmain, - graph->scene, - graph->view_layer, - }; + DEGEditorUpdateContext update_ctx; + update_ctx.bmain = bmain; + update_ctx.depsgraph = (::Depsgraph *)graph; + update_ctx.scene = graph->scene; + update_ctx.view_layer = graph->view_layer; /* Do actual flush. */ while (!queue.empty()) { OperationDepsNode *op_node = queue.front(); @@ -265,7 +309,10 @@ void deg_graph_flush_updates(Main *bmain, Depsgraph *graph) flush_editors_id_update(bmain, graph, &update_ctx); } -static void graph_clear_func(void *data_v, int i) +static void graph_clear_func( + void *__restrict data_v, + const int i, + const ParallelRangeTLS *__restrict /*tls*/) { Depsgraph *graph = (Depsgraph *)data_v; OperationDepsNode *node = graph->operations[i]; @@ -278,8 +325,13 @@ void deg_graph_clear_tags(Depsgraph *graph) { /* Go over all operation nodes, clearing tags. */ const int num_operations = graph->operations.size(); - const bool do_threads = num_operations > 256; - BLI_task_parallel_range(0, num_operations, graph, graph_clear_func, do_threads); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.min_iter_per_thread = 1024; + BLI_task_parallel_range(0, num_operations, + graph, + graph_clear_func, + &settings); /* Clear any entry tags which haven't been flushed. */ BLI_gset_clear(graph->entry_tags, NULL); } diff --git a/source/blender/depsgraph/intern/eval/deg_eval_stats.cc b/source/blender/depsgraph/intern/eval/deg_eval_stats.cc new file mode 100644 index 00000000000..52ce744cc0a --- /dev/null +++ b/source/blender/depsgraph/intern/eval/deg_eval_stats.cc @@ -0,0 +1,70 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2017 Blender Foundation. + * All rights reserved. + * + * Original Author: Sergey Sharybin + * Contributor(s): None Yet + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/depsgraph/intern/eval/deg_eval_stats.cc + * \ingroup depsgraph + */ + +#include "intern/eval/deg_eval_stats.h" + +#include "BLI_utildefines.h" +#include "BLI_ghash.h" + +#include "intern/depsgraph.h" + +#include "intern/nodes/deg_node.h" +#include "intern/nodes/deg_node_component.h" +#include "intern/nodes/deg_node_id.h" +#include "intern/nodes/deg_node_operation.h" + +#include "util/deg_util_foreach.h" + +namespace DEG { + +void deg_eval_stats_aggregate(Depsgraph *graph) +{ + /* Reset current evaluation stats for ID and component nodes. + * Those are not filled in by the evaluation engine. + */ + foreach (DepsNode *node, graph->id_nodes) { + IDDepsNode *id_node = (IDDepsNode *)node; + GHASH_FOREACH_BEGIN(ComponentDepsNode *, comp_node, id_node->components) + { + comp_node->stats.reset_current(); + } + GHASH_FOREACH_END(); + id_node->stats.reset_current(); + } + /* Now accumulate operation timings to components and IDs. */ + foreach (OperationDepsNode *op_node, graph->operations) { + ComponentDepsNode *comp_node = op_node->owner; + IDDepsNode *id_node = comp_node->owner; + id_node->stats.current_time += op_node->stats.current_time; + comp_node->stats.current_time += op_node->stats.current_time; + } +} + +} // namespace DEG diff --git a/source/blender/depsgraph/intern/eval/deg_eval_stats.h b/source/blender/depsgraph/intern/eval/deg_eval_stats.h new file mode 100644 index 00000000000..8a7272ac89c --- /dev/null +++ b/source/blender/depsgraph/intern/eval/deg_eval_stats.h @@ -0,0 +1,40 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2017 Blender Foundation. + * All rights reserved. + * + * Original Author: Sergey Sharybin + * Contributor(s): None Yet + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/depsgraph/intern/eval/deg_eval_stats.h + * \ingroup depsgraph + */ + +#pragma once + +namespace DEG { + +struct Depsgraph; + +/* Aggregate operation timings to overall component and ID nodes timing. */ +void deg_eval_stats_aggregate(Depsgraph *graph); + +} // namespace DEG diff --git a/source/blender/depsgraph/intern/nodes/deg_node.cc b/source/blender/depsgraph/intern/nodes/deg_node.cc index 5f83d02082b..fdcfc129073 100644 --- a/source/blender/depsgraph/intern/nodes/deg_node.cc +++ b/source/blender/depsgraph/intern/nodes/deg_node.cc @@ -31,48 +31,57 @@ #include "intern/nodes/deg_node.h" #include <stdio.h> -#include <cstring> /* required for STREQ later on. */ #include "BLI_utildefines.h" -#include "BLI_ghash.h" - -extern "C" { -#include "DNA_ID.h" -#include "DNA_anim_types.h" -#include "DNA_object_types.h" - -#include "BKE_animsys.h" -#include "BKE_library.h" -} - -#include "DEG_depsgraph.h" #include "intern/eval/deg_eval_copy_on_write.h" #include "intern/nodes/deg_node_component.h" +#include "intern/nodes/deg_node_id.h" #include "intern/nodes/deg_node_operation.h" +#include "intern/nodes/deg_node_time.h" #include "intern/depsgraph_intern.h" + #include "util/deg_util_foreach.h" #include "util/deg_util_function.h" namespace DEG { -/* *************** */ -/* Node Management */ +/******************************************************************************* + * Type information. + */ -/* Add ------------------------------------------------ */ +DepsNode::TypeInfo::TypeInfo(eDepsNode_Type type, + const char *tname, + int id_recalc_tag) + : type(type), + tname(tname), + id_recalc_tag(id_recalc_tag) +{ +} -DepsNode::TypeInfo::TypeInfo(eDepsNode_Type type, const char *tname) +/******************************************************************************* + * Evaluation statistics. + */ + +DepsNode::Stats::Stats() { - this->type = type; - if (type == DEG_NODE_TYPE_OPERATION) - this->tclass = DEG_NODE_CLASS_OPERATION; - else if (type < DEG_NODE_TYPE_PARAMETERS) - this->tclass = DEG_NODE_CLASS_GENERIC; - else - this->tclass = DEG_NODE_CLASS_COMPONENT; - this->tname = tname; + reset(); } +void DepsNode::Stats::reset() +{ + current_time = 0.0; +} + +void DepsNode::Stats::reset_current() +{ + current_time = 0.0; +} + +/******************************************************************************* + * Node itself. + */ + DepsNode::DepsNode() { name = ""; @@ -100,216 +109,24 @@ string DepsNode::identifier() const return string(typebuf) + " : " + name; } -/* ************* */ -/* Generic Nodes */ - -/* Time Source Node ============================================== */ - -void TimeSourceDepsNode::tag_update(Depsgraph *graph) -{ - foreach (DepsRelation *rel, outlinks) { - DepsNode *node = rel->to; - node->tag_update(graph); - } -} - -/* Time Source Node ======================================= */ - -DEG_DEPSNODE_DEFINE(TimeSourceDepsNode, DEG_NODE_TYPE_TIMESOURCE, "Time Source"); -static DepsNodeFactoryImpl<TimeSourceDepsNode> DNTI_TIMESOURCE; - -/* ID Node ================================================ */ - -IDDepsNode::ComponentIDKey::ComponentIDKey(eDepsNode_Type type, - const char *name) - : type(type), name(name) -{ -} - -bool IDDepsNode::ComponentIDKey::operator== (const ComponentIDKey &other) const -{ - return type == other.type && - STREQ(name, other.name); -} - -static unsigned int id_deps_node_hash_key(const void *key_v) -{ - const IDDepsNode::ComponentIDKey *key = - reinterpret_cast<const IDDepsNode::ComponentIDKey *>(key_v); - return BLI_ghashutil_combine_hash(BLI_ghashutil_uinthash(key->type), - BLI_ghashutil_strhash_p(key->name)); -} - -static bool id_deps_node_hash_key_cmp(const void *a, const void *b) -{ - const IDDepsNode::ComponentIDKey *key_a = - reinterpret_cast<const IDDepsNode::ComponentIDKey *>(a); - const IDDepsNode::ComponentIDKey *key_b = - reinterpret_cast<const IDDepsNode::ComponentIDKey *>(b); - return !(*key_a == *key_b); -} - -static void id_deps_node_hash_key_free(void *key_v) -{ - typedef IDDepsNode::ComponentIDKey ComponentIDKey; - ComponentIDKey *key = reinterpret_cast<ComponentIDKey *>(key_v); - OBJECT_GUARDED_DELETE(key, ComponentIDKey); -} - -static void id_deps_node_hash_value_free(void *value_v) -{ - ComponentDepsNode *comp_node = reinterpret_cast<ComponentDepsNode *>(value_v); - OBJECT_GUARDED_DELETE(comp_node, ComponentDepsNode); -} - -/* Initialize 'id' node - from pointer data given. */ -void IDDepsNode::init(const ID *id, const char *UNUSED(subdata)) -{ - BLI_assert(id != NULL); - /* Store ID-pointer. */ - id_orig = (ID *)id; - eval_flags = 0; - linked_state = DEG_ID_LINKED_INDIRECTLY; - - components = BLI_ghash_new(id_deps_node_hash_key, - id_deps_node_hash_key_cmp, - "Depsgraph id components hash"); -} - -void IDDepsNode::init_copy_on_write(ID *id_cow_hint) -{ - /* Early output for non-copy-on-write case: we keep CoW pointer same as - * an original one. - */ - if (!DEG_depsgraph_use_copy_on_write()) { - UNUSED_VARS(id_cow_hint); - id_cow = id_orig; - return; +eDepsNode_Class DepsNode::get_class() const { + if (type == DEG_NODE_TYPE_OPERATION) { + return DEG_NODE_CLASS_OPERATION; } - /* Create pointer as early as possible, so we can use it for function - * bindings. Rest of data we'll be copying to the new datablock when - * it is actually needed. - */ - if (id_cow_hint != NULL) { - // BLI_assert(deg_copy_on_write_is_needed(id_orig)); - if (deg_copy_on_write_is_needed(id_orig)) { - id_cow = id_cow_hint; - } - else { - id_cow = id_orig; - } - } - else if (deg_copy_on_write_is_needed(id_orig)) { - id_cow = (ID *)BKE_libblock_alloc_notest(GS(id_orig->name)); - DEG_COW_PRINT("Create shallow copy for %s: id_orig=%p id_cow=%p\n", - id_orig->name, id_orig, id_cow); - deg_tag_copy_on_write_id(id_cow, id_orig); + else if (type < DEG_NODE_TYPE_PARAMETERS) { + return DEG_NODE_CLASS_GENERIC; } else { - id_cow = id_orig; - } -} - -/* Free 'id' node. */ -IDDepsNode::~IDDepsNode() -{ - destroy(); -} - -void IDDepsNode::destroy() -{ - if (id_orig == NULL) { - return; - } - - BLI_ghash_free(components, - id_deps_node_hash_key_free, - id_deps_node_hash_value_free); - - /* Free memory used by this CoW ID. */ - if (id_cow != id_orig && id_cow != NULL) { - deg_free_copy_on_write_datablock(id_cow); - MEM_freeN(id_cow); - DEG_COW_PRINT("Destroy CoW for %s: id_orig=%p id_cow=%p\n", - id_orig->name, id_orig, id_cow); - } - - /* Tag that the node is freed. */ - id_orig = NULL; -} - -ComponentDepsNode *IDDepsNode::find_component(eDepsNode_Type type, - const char *name) const -{ - ComponentIDKey key(type, name); - return reinterpret_cast<ComponentDepsNode *>(BLI_ghash_lookup(components, &key)); -} - -ComponentDepsNode *IDDepsNode::add_component(eDepsNode_Type type, - const char *name) -{ - ComponentDepsNode *comp_node = find_component(type, name); - if (!comp_node) { - DepsNodeFactory *factory = deg_get_node_factory(type); - comp_node = (ComponentDepsNode *)factory->create_node(this->id_orig, "", name); - - /* Register. */ - ComponentIDKey *key = OBJECT_GUARDED_NEW(ComponentIDKey, type, name); - BLI_ghash_insert(components, key, comp_node); - comp_node->owner = this; + return DEG_NODE_CLASS_COMPONENT; } - return comp_node; } -void IDDepsNode::tag_update(Depsgraph *graph) -{ - GHASH_FOREACH_BEGIN(ComponentDepsNode *, comp_node, components) - { - /* TODO(sergey): What about drivers? */ - bool do_component_tag = comp_node->type != DEG_NODE_TYPE_ANIMATION; - if (comp_node->type == DEG_NODE_TYPE_ANIMATION) { - AnimData *adt = BKE_animdata_from_id(id_orig); - /* Animation data might be null if relations are tagged for update. */ - if (adt != NULL && (adt->recalc & ADT_RECALC_ANIM)) { - do_component_tag = true; - } - } - else if (comp_node->type == DEG_NODE_TYPE_SHADING) { - /* TODO(sergey): For until we properly handle granular flags for DEG_id_tag_update() - * we skip flushing here to keep Luca happy. - */ - if (GS(id_orig->name) != ID_MA && - GS(id_orig->name) != ID_WO) - { - do_component_tag = false; - } - } - else if (comp_node->type == DEG_NODE_TYPE_SHADING_PARAMETERS) { - do_component_tag = false; - } - else if (comp_node->type == DEG_NODE_TYPE_EVAL_PARTICLES) { - /* Only do explicit particle settings tagging. */ - do_component_tag = false; - } - else if (comp_node->type == DEG_NODE_TYPE_BATCH_CACHE) { - do_component_tag = false; - } - if (do_component_tag) { - comp_node->tag_update(graph); - } - } - GHASH_FOREACH_END(); -} - -void IDDepsNode::finalize_build(Depsgraph *graph) -{ - /* Finalize build of all components. */ - GHASH_FOREACH_BEGIN(ComponentDepsNode *, comp_node, components) - { - comp_node->finalize_build(graph); - } - GHASH_FOREACH_END(); -} +/******************************************************************************* + * Generic nodes definition. + */ +\ +DEG_DEPSNODE_DEFINE(TimeSourceDepsNode, DEG_NODE_TYPE_TIMESOURCE, "Time Source"); +static DepsNodeFactoryImpl<TimeSourceDepsNode> DNTI_TIMESOURCE; DEG_DEPSNODE_DEFINE(IDDepsNode, DEG_NODE_TYPE_ID_REF, "ID Node"); static DepsNodeFactoryImpl<IDDepsNode> DNTI_ID_REF; diff --git a/source/blender/depsgraph/intern/nodes/deg_node.h b/source/blender/depsgraph/intern/nodes/deg_node.h index fd3ed694c9c..603a6be7ceb 100644 --- a/source/blender/depsgraph/intern/nodes/deg_node.h +++ b/source/blender/depsgraph/intern/nodes/deg_node.h @@ -51,22 +51,24 @@ struct OperationDepsNode; struct DepsNode { /* Helper class for static typeinfo in subclasses. */ struct TypeInfo { - TypeInfo(eDepsNode_Type type, const char *tname); - + TypeInfo(eDepsNode_Type type, const char *tname, int id_recalc_tag = 0); eDepsNode_Type type; - eDepsNode_Class tclass; const char *tname; + int id_recalc_tag; + }; + struct Stats { + Stats(); + /* Reset all the counters. Including all stats needed for average + * evaluation time calculation. + */ + void reset(); + /* Reset counters needed for the current graph evaluation, does not + * touch averaging accumulators. + */ + void reset_current(); + /* Time spend on this node during current graph evaluation. */ + double current_time; }; - - /* Identifier - mainly for debugging purposes. */ - const char *name; - - /* Structural type of node. */ - eDepsNode_Type type; - - /* Type of data/behaviour represented by node... */ - eDepsNode_Class tclass; - /* Relationships between nodes * The reason why all depsgraph nodes are descended from this type (apart * from basic serialization benefits - from the typeinfo) is that we can have @@ -74,23 +76,18 @@ struct DepsNode { */ typedef vector<DepsRelation *> Relations; - /* Nodes which this one depends on. */ - Relations inlinks; - - /* Nodes which depend on this one. */ - Relations outlinks; - - /* Generic tags for traversal algorithms. */ - int done; - int tag; + const char *name; /* Identifier - mainly for debugging purposes. */ + eDepsNode_Type type; /* Structural type of node. */ + Relations inlinks; /* Nodes which this one depends on. */ + Relations outlinks; /* Nodes which depend on this one. */ + int done; /* Generic tags for traversal algorithms. */ + Stats stats; /* Evaluation statistics. */ /* Methods. */ - DepsNode(); virtual ~DepsNode(); virtual string identifier() const; - string full_identifier() const; virtual void init(const ID * /*id*/, const char * /*subdata*/) {} @@ -99,6 +96,8 @@ struct DepsNode { virtual OperationDepsNode *get_entry_operation() { return NULL; } virtual OperationDepsNode *get_exit_operation() { return NULL; } + + virtual eDepsNode_Class get_class() const; }; /* Macros for common static typeinfo. */ @@ -107,68 +106,6 @@ struct DepsNode { #define DEG_DEPSNODE_DEFINE(NodeType, type_, tname_) \ const DepsNode::TypeInfo NodeType::typeinfo = DepsNode::TypeInfo(type_, tname_) -/* Generic Nodes ======================= */ - -struct ComponentDepsNode; -struct IDDepsNode; - -/* Time Source Node. */ -struct TimeSourceDepsNode : public DepsNode { - /* New "current time". */ - float cfra; - - /* time-offset relative to the "official" time source that this one has. */ - float offset; - - // TODO: evaluate() operation needed - - void tag_update(Depsgraph *graph); - - DEG_DEPSNODE_DECLARE; -}; - -/* ID-Block Reference */ -struct IDDepsNode : public DepsNode { - struct ComponentIDKey { - ComponentIDKey(eDepsNode_Type type, const char *name = ""); - bool operator==(const ComponentIDKey &other) const; - - eDepsNode_Type type; - const char *name; - }; - - void init(const ID *id, const char *subdata); - void init_copy_on_write(ID *id_cow_hint = NULL); - ~IDDepsNode(); - void destroy(); - - ComponentDepsNode *find_component(eDepsNode_Type type, - const char *name = "") const; - ComponentDepsNode *add_component(eDepsNode_Type type, - const char *name = ""); - - void tag_update(Depsgraph *graph); - - void finalize_build(Depsgraph *graph); - - /* ID Block referenced. */ - ID *id_orig; - ID *id_cow; - - /* Hash to make it faster to look up components. */ - GHash *components; - - /* Additional flags needed for scene evaluation. - * TODO(sergey): Only needed for until really granular updates - * of all the entities. - */ - int eval_flags; - - eDepsNode_LinkedState_Type linked_state; - - DEG_DEPSNODE_DECLARE; -}; - void deg_register_base_depsnodes(); } // namespace DEG diff --git a/source/blender/depsgraph/intern/nodes/deg_node_component.cc b/source/blender/depsgraph/intern/nodes/deg_node_component.cc index 01181453982..1f56edd1f87 100644 --- a/source/blender/depsgraph/intern/nodes/deg_node_component.cc +++ b/source/blender/depsgraph/intern/nodes/deg_node_component.cc @@ -42,6 +42,7 @@ extern "C" { #include "BKE_action.h" } /* extern "C" */ +#include "intern/nodes/deg_node_id.h" #include "intern/nodes/deg_node_operation.h" #include "intern/depsgraph_intern.h" #include "util/deg_util_foreach.h" @@ -227,7 +228,7 @@ OperationDepsNode *ComponentDepsNode::add_operation(const DepsEvalOperationCb& o { OperationDepsNode *op_node = find_operation(opcode, name, name_tag); if (!op_node) { - DepsNodeFactory *factory = deg_get_node_factory(DEG_NODE_TYPE_OPERATION); + DepsNodeFactory *factory = deg_type_get_factory(DEG_NODE_TYPE_OPERATION); op_node = (OperationDepsNode *)factory->create_node(this->owner->id_orig, "", name); /* register opnode in this component's operation set */ @@ -355,30 +356,6 @@ void ComponentDepsNode::finalize_build(Depsgraph * /*graph*/) operations_map = NULL; } -/* Register all components. =============================== */ - -#define DEG_COMPONENT_DEFINE(name, NAME) \ - DEG_DEPSNODE_DEFINE(name ## ComponentDepsNode, \ - DEG_NODE_TYPE_ ## NAME, \ - #name " Component"); \ -static DepsNodeFactoryImpl<name ## ComponentDepsNode> DNTI_ ## NAME - - -DEG_COMPONENT_DEFINE(Animation, ANIMATION); -DEG_COMPONENT_DEFINE(BatchCache, BATCH_CACHE); -DEG_COMPONENT_DEFINE(Cache, CACHE); -DEG_COMPONENT_DEFINE(CopyOnWrite, COPY_ON_WRITE); -DEG_COMPONENT_DEFINE(Geometry, GEOMETRY); -DEG_COMPONENT_DEFINE(LayerCollections, LAYER_COLLECTIONS); -DEG_COMPONENT_DEFINE(Parameters, PARAMETERS); -DEG_COMPONENT_DEFINE(Particles, EVAL_PARTICLES); -DEG_COMPONENT_DEFINE(Proxy, PROXY); -DEG_COMPONENT_DEFINE(Pose, EVAL_POSE); -DEG_COMPONENT_DEFINE(Sequencer, SEQUENCER); -DEG_COMPONENT_DEFINE(Shading, SHADING); -DEG_COMPONENT_DEFINE(ShadingParameters, SHADING_PARAMETERS); -DEG_COMPONENT_DEFINE(Transform, TRANSFORM); - /* Bone Component ========================================= */ /* Initialize 'bone component' node - from pointer data given */ @@ -398,7 +375,23 @@ void BoneComponentDepsNode::init(const ID *id, const char *subdata) this->pchan = BKE_pose_channel_find_name(object->pose, subdata); } -DEG_COMPONENT_DEFINE(Bone, BONE); +/* Register all components. =============================== */ + +DEG_COMPONENT_NODE_DEFINE(Animation, ANIMATION, ID_RECALC_ANIMATION); +DEG_COMPONENT_NODE_DEFINE(BatchCache, BATCH_CACHE, ID_RECALC_DRAW_CACHE); +DEG_COMPONENT_NODE_DEFINE(Bone, BONE, ID_RECALC_GEOMETRY); +DEG_COMPONENT_NODE_DEFINE(Cache, CACHE, ID_RECALC); +DEG_COMPONENT_NODE_DEFINE(CopyOnWrite, COPY_ON_WRITE, ID_RECALC); +DEG_COMPONENT_NODE_DEFINE(Geometry, GEOMETRY, ID_RECALC_GEOMETRY); +DEG_COMPONENT_NODE_DEFINE(LayerCollections, LAYER_COLLECTIONS, ID_RECALC_COLLECTIONS); +DEG_COMPONENT_NODE_DEFINE(Parameters, PARAMETERS, ID_RECALC); +DEG_COMPONENT_NODE_DEFINE(Particles, EVAL_PARTICLES, ID_RECALC_GEOMETRY); +DEG_COMPONENT_NODE_DEFINE(Proxy, PROXY, ID_RECALC_GEOMETRY); +DEG_COMPONENT_NODE_DEFINE(Pose, EVAL_POSE, ID_RECALC_GEOMETRY); +DEG_COMPONENT_NODE_DEFINE(Sequencer, SEQUENCER, ID_RECALC); +DEG_COMPONENT_NODE_DEFINE(Shading, SHADING, ID_RECALC_DRAW); +DEG_COMPONENT_NODE_DEFINE(ShadingParameters, SHADING_PARAMETERS, ID_RECALC_DRAW); +DEG_COMPONENT_NODE_DEFINE(Transform, TRANSFORM, ID_RECALC_TRANSFORM); /* Node Types Register =================================== */ diff --git a/source/blender/depsgraph/intern/nodes/deg_node_component.h b/source/blender/depsgraph/intern/nodes/deg_node_component.h index ba4f8551fea..b8009cc0a7f 100644 --- a/source/blender/depsgraph/intern/nodes/deg_node_component.h +++ b/source/blender/depsgraph/intern/nodes/deg_node_component.h @@ -46,6 +46,7 @@ namespace DEG { struct Depsgraph; struct OperationDepsNode; struct BoneComponentDepsNode; +struct IDDepsNode; /* ID Component - Base type for all components */ struct ComponentDepsNode : public DepsNode { @@ -123,19 +124,6 @@ struct ComponentDepsNode : public DepsNode { void tag_update(Depsgraph *graph); - /* Evaluation Context Management .................. */ - - /* Initialize component's evaluation context used for the specified - * purpose. - */ - virtual bool eval_context_init(EvaluationContext * /*eval_ctx*/) { return false; } - /* Free data in component's evaluation context which is used for - * the specified purpose - * - * NOTE: this does not free the actual context in question - */ - virtual void eval_context_free(EvaluationContext * /*eval_ctx*/) {} - OperationDepsNode *get_entry_operation(); OperationDepsNode *get_exit_operation(); @@ -164,25 +152,38 @@ struct ComponentDepsNode : public DepsNode { /* ---------------------------------------- */ -#define DEG_COMPONENT_DECLARE_GENERIC(name) \ +#define DEG_COMPONENT_NODE_DEFINE_TYPEINFO(NodeType, type_, tname_, id_recalc_tag) \ + const DepsNode::TypeInfo NodeType::typeinfo = \ + DepsNode::TypeInfo(type_, tname_, id_recalc_tag) + +#define DEG_COMPONENT_NODE_DECLARE DEG_DEPSNODE_DECLARE + +#define DEG_COMPONENT_NODE_DEFINE(name, NAME, id_recalc_tag) \ + DEG_COMPONENT_NODE_DEFINE_TYPEINFO(name ## ComponentDepsNode, \ + DEG_NODE_TYPE_ ## NAME, \ + #name " Component", \ + id_recalc_tag) ; \ + static DepsNodeFactoryImpl<name ## ComponentDepsNode> DNTI_ ## NAME + +#define DEG_COMPONENT_NODE_DECLARE_GENERIC(name) \ struct name ## ComponentDepsNode : public ComponentDepsNode { \ - DEG_DEPSNODE_DECLARE; \ + DEG_COMPONENT_NODE_DECLARE; \ } -DEG_COMPONENT_DECLARE_GENERIC(Animation); -DEG_COMPONENT_DECLARE_GENERIC(BatchCache); -DEG_COMPONENT_DECLARE_GENERIC(Cache); -DEG_COMPONENT_DECLARE_GENERIC(CopyOnWrite); -DEG_COMPONENT_DECLARE_GENERIC(Geometry); -DEG_COMPONENT_DECLARE_GENERIC(LayerCollections); -DEG_COMPONENT_DECLARE_GENERIC(Parameters); -DEG_COMPONENT_DECLARE_GENERIC(Particles); -DEG_COMPONENT_DECLARE_GENERIC(Proxy); -DEG_COMPONENT_DECLARE_GENERIC(Pose); -DEG_COMPONENT_DECLARE_GENERIC(Sequencer); -DEG_COMPONENT_DECLARE_GENERIC(Shading); -DEG_COMPONENT_DECLARE_GENERIC(ShadingParameters); -DEG_COMPONENT_DECLARE_GENERIC(Transform); +DEG_COMPONENT_NODE_DECLARE_GENERIC(Animation); +DEG_COMPONENT_NODE_DECLARE_GENERIC(BatchCache); +DEG_COMPONENT_NODE_DECLARE_GENERIC(Cache); +DEG_COMPONENT_NODE_DECLARE_GENERIC(CopyOnWrite); +DEG_COMPONENT_NODE_DECLARE_GENERIC(Geometry); +DEG_COMPONENT_NODE_DECLARE_GENERIC(LayerCollections); +DEG_COMPONENT_NODE_DECLARE_GENERIC(Parameters); +DEG_COMPONENT_NODE_DECLARE_GENERIC(Particles); +DEG_COMPONENT_NODE_DECLARE_GENERIC(Proxy); +DEG_COMPONENT_NODE_DECLARE_GENERIC(Pose); +DEG_COMPONENT_NODE_DECLARE_GENERIC(Sequencer); +DEG_COMPONENT_NODE_DECLARE_GENERIC(Shading); +DEG_COMPONENT_NODE_DECLARE_GENERIC(ShadingParameters); +DEG_COMPONENT_NODE_DECLARE_GENERIC(Transform); /* Bone Component */ struct BoneComponentDepsNode : public ComponentDepsNode { @@ -190,7 +191,7 @@ struct BoneComponentDepsNode : public ComponentDepsNode { struct bPoseChannel *pchan; /* the bone that this component represents */ - DEG_DEPSNODE_DECLARE; + DEG_COMPONENT_NODE_DECLARE; }; void deg_register_component_depsnodes(); diff --git a/source/blender/depsgraph/intern/nodes/deg_node_id.cc b/source/blender/depsgraph/intern/nodes/deg_node_id.cc new file mode 100644 index 00000000000..edc5c0114f9 --- /dev/null +++ b/source/blender/depsgraph/intern/nodes/deg_node_id.cc @@ -0,0 +1,217 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2013 Blender Foundation. + * All rights reserved. + * + * Original Author: Joshua Leung + * Contributor(s): None Yet + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/depsgraph/intern/nodes/deg_node_id.cc + * \ingroup depsgraph + */ + +#include "intern/nodes/deg_node_id.h" + +#include <stdio.h> +#include <cstring> /* required for STREQ later on. */ + +#include "BLI_utildefines.h" +#include "BLI_ghash.h" + +extern "C" { +#include "DNA_ID.h" +#include "DNA_anim_types.h" + +#include "BKE_animsys.h" +#include "BKE_library.h" +} + +#include "DEG_depsgraph.h" + +#include "intern/eval/deg_eval_copy_on_write.h" +#include "intern/nodes/deg_node_time.h" +#include "intern/depsgraph_intern.h" + +#include "util/deg_util_foreach.h" + +namespace DEG { + +IDDepsNode::ComponentIDKey::ComponentIDKey(eDepsNode_Type type, + const char *name) + : type(type), name(name) +{ +} + +bool IDDepsNode::ComponentIDKey::operator== (const ComponentIDKey &other) const +{ + return type == other.type && + STREQ(name, other.name); +} + +static unsigned int id_deps_node_hash_key(const void *key_v) +{ + const IDDepsNode::ComponentIDKey *key = + reinterpret_cast<const IDDepsNode::ComponentIDKey *>(key_v); + return BLI_ghashutil_combine_hash(BLI_ghashutil_uinthash(key->type), + BLI_ghashutil_strhash_p(key->name)); +} + +static bool id_deps_node_hash_key_cmp(const void *a, const void *b) +{ + const IDDepsNode::ComponentIDKey *key_a = + reinterpret_cast<const IDDepsNode::ComponentIDKey *>(a); + const IDDepsNode::ComponentIDKey *key_b = + reinterpret_cast<const IDDepsNode::ComponentIDKey *>(b); + return !(*key_a == *key_b); +} + +static void id_deps_node_hash_key_free(void *key_v) +{ + typedef IDDepsNode::ComponentIDKey ComponentIDKey; + ComponentIDKey *key = reinterpret_cast<ComponentIDKey *>(key_v); + OBJECT_GUARDED_DELETE(key, ComponentIDKey); +} + +static void id_deps_node_hash_value_free(void *value_v) +{ + ComponentDepsNode *comp_node = reinterpret_cast<ComponentDepsNode *>(value_v); + OBJECT_GUARDED_DELETE(comp_node, ComponentDepsNode); +} + +/* Initialize 'id' node - from pointer data given. */ +void IDDepsNode::init(const ID *id, const char *UNUSED(subdata)) +{ + BLI_assert(id != NULL); + /* Store ID-pointer. */ + id_orig = (ID *)id; + eval_flags = 0; + linked_state = DEG_ID_LINKED_INDIRECTLY; + + components = BLI_ghash_new(id_deps_node_hash_key, + id_deps_node_hash_key_cmp, + "Depsgraph id components hash"); +} + +void IDDepsNode::init_copy_on_write(ID *id_cow_hint) +{ + /* Early output for non-copy-on-write case: we keep CoW pointer same as + * an original one. + */ + if (!DEG_depsgraph_use_copy_on_write()) { + UNUSED_VARS(id_cow_hint); + id_cow = id_orig; + return; + } + /* Create pointer as early as possible, so we can use it for function + * bindings. Rest of data we'll be copying to the new datablock when + * it is actually needed. + */ + if (id_cow_hint != NULL) { + // BLI_assert(deg_copy_on_write_is_needed(id_orig)); + if (deg_copy_on_write_is_needed(id_orig)) { + id_cow = id_cow_hint; + } + else { + id_cow = id_orig; + } + } + else if (deg_copy_on_write_is_needed(id_orig)) { + id_cow = (ID *)BKE_libblock_alloc_notest(GS(id_orig->name)); + DEG_COW_PRINT("Create shallow copy for %s: id_orig=%p id_cow=%p\n", + id_orig->name, id_orig, id_cow); + deg_tag_copy_on_write_id(id_cow, id_orig); + } + else { + id_cow = id_orig; + } +} + +/* Free 'id' node. */ +IDDepsNode::~IDDepsNode() +{ + destroy(); +} + +void IDDepsNode::destroy() +{ + if (id_orig == NULL) { + return; + } + + BLI_ghash_free(components, + id_deps_node_hash_key_free, + id_deps_node_hash_value_free); + + /* Free memory used by this CoW ID. */ + if (id_cow != id_orig && id_cow != NULL) { + deg_free_copy_on_write_datablock(id_cow); + MEM_freeN(id_cow); + DEG_COW_PRINT("Destroy CoW for %s: id_orig=%p id_cow=%p\n", + id_orig->name, id_orig, id_cow); + } + + /* Tag that the node is freed. */ + id_orig = NULL; +} + +ComponentDepsNode *IDDepsNode::find_component(eDepsNode_Type type, + const char *name) const +{ + ComponentIDKey key(type, name); + return reinterpret_cast<ComponentDepsNode *>(BLI_ghash_lookup(components, &key)); +} + +ComponentDepsNode *IDDepsNode::add_component(eDepsNode_Type type, + const char *name) +{ + ComponentDepsNode *comp_node = find_component(type, name); + if (!comp_node) { + DepsNodeFactory *factory = deg_type_get_factory(type); + comp_node = (ComponentDepsNode *)factory->create_node(this->id_orig, "", name); + + /* Register. */ + ComponentIDKey *key = OBJECT_GUARDED_NEW(ComponentIDKey, type, name); + BLI_ghash_insert(components, key, comp_node); + comp_node->owner = this; + } + return comp_node; +} + +void IDDepsNode::tag_update(Depsgraph *graph) +{ + GHASH_FOREACH_BEGIN(ComponentDepsNode *, comp_node, components) + { + comp_node->tag_update(graph); + } + GHASH_FOREACH_END(); +} + +void IDDepsNode::finalize_build(Depsgraph *graph) +{ + /* Finalize build of all components. */ + GHASH_FOREACH_BEGIN(ComponentDepsNode *, comp_node, components) + { + comp_node->finalize_build(graph); + } + GHASH_FOREACH_END(); +} + +} // namespace DEG diff --git a/source/blender/depsgraph/intern/nodes/deg_node_id.h b/source/blender/depsgraph/intern/nodes/deg_node_id.h new file mode 100644 index 00000000000..505a1129192 --- /dev/null +++ b/source/blender/depsgraph/intern/nodes/deg_node_id.h @@ -0,0 +1,81 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2013 Blender Foundation. + * All rights reserved. + * + * Original Author: Joshua Leung + * Contributor(s): None Yet + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file depsgraph/intern/nodes/deg_node_id.h + * \ingroup depsgraph + */ + +#pragma once + +#include "intern/nodes/deg_node.h" + +namespace DEG { + +struct ComponentDepsNode; + +/* ID-Block Reference */ +struct IDDepsNode : public DepsNode { + struct ComponentIDKey { + ComponentIDKey(eDepsNode_Type type, const char *name = ""); + bool operator==(const ComponentIDKey &other) const; + + eDepsNode_Type type; + const char *name; + }; + + void init(const ID *id, const char *subdata); + void init_copy_on_write(ID *id_cow_hint = NULL); + ~IDDepsNode(); + void destroy(); + + ComponentDepsNode *find_component(eDepsNode_Type type, + const char *name = "") const; + ComponentDepsNode *add_component(eDepsNode_Type type, + const char *name = ""); + + void tag_update(Depsgraph *graph); + + void finalize_build(Depsgraph *graph); + + /* ID Block referenced. */ + ID *id_orig; + ID *id_cow; + + /* Hash to make it faster to look up components. */ + GHash *components; + + /* Additional flags needed for scene evaluation. + * TODO(sergey): Only needed for until really granular updates + * of all the entities. + */ + int eval_flags; + + eDepsNode_LinkedState_Type linked_state; + + DEG_DEPSNODE_DECLARE; +}; + +} // namespace DEG diff --git a/source/blender/depsgraph/intern/nodes/deg_node_operation.cc b/source/blender/depsgraph/intern/nodes/deg_node_operation.cc index 7467264f612..cbc0fbb4241 100644 --- a/source/blender/depsgraph/intern/nodes/deg_node_operation.cc +++ b/source/blender/depsgraph/intern/nodes/deg_node_operation.cc @@ -37,6 +37,7 @@ #include "intern/depsgraph.h" #include "intern/depsgraph_intern.h" +#include "intern/nodes/deg_node_id.h" namespace DEG { @@ -44,7 +45,6 @@ namespace DEG { /* Inner Nodes */ OperationDepsNode::OperationDepsNode() : - eval_priority(0.0f), flag(0), customdata_mask(0) { diff --git a/source/blender/depsgraph/intern/nodes/deg_node_operation.h b/source/blender/depsgraph/intern/nodes/deg_node_operation.h index d8203540fc5..c172f73be5f 100644 --- a/source/blender/depsgraph/intern/nodes/deg_node_operation.h +++ b/source/blender/depsgraph/intern/nodes/deg_node_operation.h @@ -38,6 +38,8 @@ struct Depsgraph; namespace DEG { +struct ComponentDepsNode; + /* Flags for Depsgraph Nodes */ typedef enum eDepsOperation_Flag { /* node needs to be updated */ @@ -74,7 +76,6 @@ struct OperationDepsNode : public DepsNode { /* How many inlinks are we still waiting on before we can be evaluated. */ uint32_t num_links_pending; - float eval_priority; bool scheduled; /* Identifier for the operation being performed. */ diff --git a/source/blender/depsgraph/intern/nodes/deg_node_time.cc b/source/blender/depsgraph/intern/nodes/deg_node_time.cc new file mode 100644 index 00000000000..230488b2328 --- /dev/null +++ b/source/blender/depsgraph/intern/nodes/deg_node_time.cc @@ -0,0 +1,46 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2013 Blender Foundation. + * All rights reserved. + * + * Original Author: Joshua Leung + * Contributor(s): None Yet + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/depsgraph/intern/nodes/deg_node_time.cc + * \ingroup depsgraph + */ + +#include "intern/nodes/deg_node_time.h" + +#include "intern/depsgraph_intern.h" +#include "util/deg_util_foreach.h" + +namespace DEG { + +void TimeSourceDepsNode::tag_update(Depsgraph *graph) +{ + foreach (DepsRelation *rel, outlinks) { + DepsNode *node = rel->to; + node->tag_update(graph); + } +} + +} // namespace DEG diff --git a/source/blender/depsgraph/intern/nodes/deg_node_time.h b/source/blender/depsgraph/intern/nodes/deg_node_time.h new file mode 100644 index 00000000000..93f3edef9cf --- /dev/null +++ b/source/blender/depsgraph/intern/nodes/deg_node_time.h @@ -0,0 +1,52 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2013 Blender Foundation. + * All rights reserved. + * + * Original Author: Joshua Leung + * Contributor(s): None Yet + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file depsgraph/intern/nodes/deg_node_time.h + * \ingroup depsgraph + */ + +#pragma once + +#include "intern/nodes/deg_node.h" + +namespace DEG { + +/* Time Source Node. */ +struct TimeSourceDepsNode : public DepsNode { + /* New "current time". */ + float cfra; + + /* time-offset relative to the "official" time source that this one has. */ + float offset; + + // TODO: evaluate() operation needed + + void tag_update(Depsgraph *graph); + + DEG_DEPSNODE_DECLARE; +}; + +} // namespace DEG diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index 8339b6b8720..1bff4b875ce 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -62,6 +62,7 @@ set(SRC intern/draw_cache_impl_metaball.c intern/draw_cache_impl_particles.c intern/draw_common.c + intern/draw_instance_data.c intern/draw_manager.c intern/draw_manager_text.c intern/draw_manager_profiling.c @@ -93,6 +94,7 @@ set(SRC engines/eevee/eevee_materials.c engines/eevee/eevee_motion_blur.c engines/eevee/eevee_occlusion.c + engines/eevee/eevee_render.c engines/eevee/eevee_screen_raytrace.c engines/eevee/eevee_subsurface.c engines/eevee/eevee_temporal_sampling.c @@ -104,6 +106,7 @@ set(SRC intern/draw_cache.h intern/draw_cache_impl.h intern/draw_common.h + intern/draw_instance_data.h intern/draw_manager_text.h intern/draw_manager_profiling.h intern/draw_view.h @@ -133,6 +136,7 @@ data_to_c_simple(engines/eevee/shaders/default_frag.glsl SRC) data_to_c_simple(engines/eevee/shaders/default_world_frag.glsl SRC) data_to_c_simple(engines/eevee/shaders/background_vert.glsl SRC) data_to_c_simple(engines/eevee/shaders/concentric_samples_lib.glsl SRC) +data_to_c_simple(engines/eevee/shaders/common_uniforms_lib.glsl SRC) data_to_c_simple(engines/eevee/shaders/lamps_lib.glsl SRC) data_to_c_simple(engines/eevee/shaders/lightprobe_lib.glsl SRC) data_to_c_simple(engines/eevee/shaders/lightprobe_filter_glossy_frag.glsl SRC) @@ -181,6 +185,7 @@ data_to_c_simple(engines/eevee/shaders/bsdf_sampling_lib.glsl SRC) data_to_c_simple(engines/eevee/shaders/raytrace_lib.glsl SRC) data_to_c_simple(engines/eevee/shaders/ltc_lib.glsl SRC) data_to_c_simple(engines/eevee/shaders/ssr_lib.glsl SRC) +data_to_c_simple(engines/eevee/shaders/update_noise_frag.glsl SRC) data_to_c_simple(engines/eevee/shaders/volumetric_lib.glsl SRC) data_to_c_simple(engines/eevee/shaders/volumetric_frag.glsl SRC) data_to_c_simple(engines/eevee/shaders/volumetric_geom.glsl SRC) @@ -202,6 +207,7 @@ data_to_c_simple(modes/shaders/edit_mesh_overlay_mix_frag.glsl SRC) data_to_c_simple(modes/shaders/edit_mesh_overlay_facefill_vert.glsl SRC) data_to_c_simple(modes/shaders/edit_mesh_overlay_facefill_frag.glsl SRC) data_to_c_simple(modes/shaders/edit_curve_overlay_frag.glsl SRC) +data_to_c_simple(modes/shaders/edit_curve_overlay_handle_geom.glsl SRC) data_to_c_simple(modes/shaders/edit_curve_overlay_loosevert_vert.glsl SRC) data_to_c_simple(modes/shaders/edit_lattice_overlay_frag.glsl SRC) data_to_c_simple(modes/shaders/edit_lattice_overlay_loosevert_vert.glsl SRC) @@ -216,7 +222,6 @@ data_to_c_simple(modes/shaders/object_grid_frag.glsl SRC) data_to_c_simple(modes/shaders/object_grid_vert.glsl SRC) data_to_c_simple(modes/shaders/object_lightprobe_grid_vert.glsl SRC) data_to_c_simple(modes/shaders/object_particle_prim_vert.glsl SRC) -data_to_c_simple(modes/shaders/object_particle_prim_frag.glsl SRC) data_to_c_simple(modes/shaders/object_particle_dot_vert.glsl SRC) data_to_c_simple(modes/shaders/object_particle_dot_frag.glsl SRC) data_to_c_simple(modes/shaders/paint_texture_frag.glsl SRC) diff --git a/source/blender/draw/DRW_engine.h b/source/blender/draw/DRW_engine.h index ba0f8681f10..c4946e2a4b8 100644 --- a/source/blender/draw/DRW_engine.h +++ b/source/blender/draw/DRW_engine.h @@ -30,6 +30,7 @@ struct ARegion; struct CollectionEngineSettings; struct Depsgraph; struct DRWPass; +struct DRWInstanceDataList; struct Main; struct Material; struct Scene; @@ -44,6 +45,8 @@ struct ViewportEngineData; struct View3D; struct rcti; struct GPUOffScreen; +struct GPUViewport; +struct RenderEngine; struct RenderEngineType; struct WorkSpace; @@ -65,6 +68,7 @@ typedef struct DefaultTextureList { void DRW_engines_register(void); void DRW_engines_free(void); +bool DRW_engine_render_support(struct DrawEngineType *draw_engine_type); void DRW_engine_register(struct DrawEngineType *draw_engine_type); void DRW_engine_viewport_data_size_get( const void *engine_type, @@ -72,6 +76,7 @@ void DRW_engine_viewport_data_size_get( typedef struct DRWUpdateContext { struct Main *bmain; + struct Depsgraph *depsgraph; struct Scene *scene; struct ViewLayer *view_layer; struct ARegion *ar; @@ -84,28 +89,32 @@ void DRW_notify_id_update(const DRWUpdateContext *update_ctx, struct ID *id); void DRW_draw_view(const struct bContext *C); void DRW_draw_render_loop_ex( - struct Depsgraph *graph, + struct Depsgraph *depsgraph, struct RenderEngineType *engine_type, struct ARegion *ar, struct View3D *v3d, const struct bContext *evil_C); void DRW_draw_render_loop( - struct Depsgraph *graph, + struct Depsgraph *depsgraph, struct ARegion *ar, struct View3D *v3d); void DRW_draw_render_loop_offscreen( - struct Depsgraph *graph, + struct Depsgraph *depsgraph, struct RenderEngineType *engine_type, struct ARegion *ar, struct View3D *v3d, - struct GPUOffScreen *ofs); + const bool draw_background, + struct GPUOffScreen *ofs, + struct GPUViewport *viewport); void DRW_draw_select_loop( - struct Depsgraph *graph, + struct Depsgraph *depsgraph, struct ARegion *ar, struct View3D *v3d, bool use_obedit_skip, bool use_nearest, const struct rcti *rect); void DRW_draw_depth_loop( - struct Depsgraph *graph, + struct Depsgraph *depsgraph, struct ARegion *ar, struct View3D *v3d); /* This is here because GPUViewport needs it */ void DRW_pass_free(struct DRWPass *pass); +struct DRWInstanceDataList *DRW_instance_data_list_create(void); +void DRW_instance_data_list_free(struct DRWInstanceDataList *idatalist); /* Mode engines initialization */ void OBJECT_collection_settings_create(struct IDProperty *properties); diff --git a/source/blender/draw/engines/basic/basic_engine.c b/source/blender/draw/engines/basic/basic_engine.c index 10dfe7b5996..31a431e3001 100644 --- a/source/blender/draw/engines/basic/basic_engine.c +++ b/source/blender/draw/engines/basic/basic_engine.c @@ -264,6 +264,7 @@ DrawEngineType draw_engine_basic_type = { &basic_draw_scene, NULL, NULL, + NULL, }; /* Note: currently unused, we may want to register so we can see this when debugging the view. */ diff --git a/source/blender/draw/engines/clay/clay_engine.c b/source/blender/draw/engines/clay/clay_engine.c index 01f89ae6b1c..d2bf164efdc 100644 --- a/source/blender/draw/engines/clay/clay_engine.c +++ b/source/blender/draw/engines/clay/clay_engine.c @@ -183,6 +183,7 @@ typedef struct CLAY_PrivateData { DRWShadingGroup *depth_shgrp_cull; DRWShadingGroup *depth_shgrp_cull_select; DRWShadingGroup *depth_shgrp_cull_active; + bool enable_ao; } CLAY_PrivateData; /* Transient data */ /* Functions */ @@ -317,7 +318,7 @@ static struct GPUTexture *create_jitter_texture(int num_samples) jitter[i][2] = bn * num_samples_inv; } - UNUSED_VARS(bsdf_split_sum_ggx, btdf_split_sum_ggx, ltc_mag_ggx, ltc_mat_ggx); + UNUSED_VARS(bsdf_split_sum_ggx, btdf_split_sum_ggx, ltc_mag_ggx, ltc_mat_ggx, ltc_disk_integral); return DRW_texture_create_2D(64, 64, DRW_TEX_RGB_16, DRW_TEX_FILTER | DRW_TEX_WRAP, &jitter[0][0]); } @@ -607,7 +608,7 @@ static int hair_mat_in_ubo(CLAY_Storage *storage, const CLAY_HAIR_UBO_Material * return id; } -static void ubo_mat_from_object(Object *ob, CLAY_UBO_Material *r_ubo) +static void ubo_mat_from_object(Object *ob, CLAY_UBO_Material *r_ubo, bool *r_needs_ao) { IDProperty *props = BKE_layer_collection_engine_evaluated_get(ob, COLLECTION_MODE_NONE, RE_engine_id_BLENDER_CLAY); @@ -622,6 +623,12 @@ static void ubo_mat_from_object(Object *ob, CLAY_UBO_Material *r_ubo) float ssao_attenuation = BKE_collection_engine_property_value_get_float(props, "ssao_attenuation"); int matcap_icon = BKE_collection_engine_property_value_get_int(props, "matcap_icon"); + if (((ssao_factor_cavity > 0.0) || (ssao_factor_edge > 0.0)) && + (ssao_distance > 0.0)) + { + *r_needs_ao = true; + } + memset(r_ubo, 0x0, sizeof(*r_ubo)); r_ubo->matcap_rot[0] = cosf(matcap_rot * 3.14159f * 2.0f); @@ -667,7 +674,7 @@ static DRWShadingGroup *CLAY_object_shgrp_get( DRWShadingGroup **shgrps = use_flat ? stl->storage->shgrps_flat : stl->storage->shgrps; CLAY_UBO_Material mat_ubo_test; - ubo_mat_from_object(ob, &mat_ubo_test); + ubo_mat_from_object(ob, &mat_ubo_test, &stl->g_data->enable_ao); int id = mat_in_ubo(stl->storage, &mat_ubo_test); @@ -712,6 +719,9 @@ static void clay_cache_init(void *vedata) stl->g_data = MEM_mallocN(sizeof(*stl->g_data), __func__); } + /* Disable AO unless a material needs it. */ + stl->g_data->enable_ao = false; + /* Depth Pass */ { psl->depth_pass = DRW_pass_create("Depth Pass", DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS); @@ -746,12 +756,45 @@ static void clay_cache_init(void *vedata) } } +static void clay_cache_populate_particles(void *vedata, Object *ob) +{ + CLAY_PassList *psl = ((CLAY_Data *)vedata)->psl; + CLAY_StorageList *stl = ((CLAY_Data *)vedata)->stl; + const DRWContextState *draw_ctx = DRW_context_state_get(); + + + Scene *scene = draw_ctx->scene; + Object *obedit = scene->obedit; + + if (ob != obedit) { + for (ParticleSystem *psys = ob->particlesystem.first; psys; psys = psys->next) { + if (psys_check_enabled(ob, psys, false)) { + ParticleSettings *part = psys->part; + int draw_as = (part->draw_as == PART_DRAW_REND) ? part->ren_as : part->draw_as; + + if (draw_as == PART_DRAW_PATH && !psys->pathcache && !psys->childcache) { + draw_as = PART_DRAW_DOT; + } + + static float mat[4][4]; + unit_m4(mat); + + if (draw_as == PART_DRAW_PATH) { + struct Gwn_Batch *geom = DRW_cache_particles_get_hair(psys, NULL); + DRWShadingGroup *hair_shgrp = CLAY_hair_shgrp_get(vedata, ob, stl, psl); + DRW_shgroup_call_add(hair_shgrp, geom, mat); + } + } + } + } +} + static void clay_cache_populate(void *vedata, Object *ob) { CLAY_PassList *psl = ((CLAY_Data *)vedata)->psl; CLAY_StorageList *stl = ((CLAY_Data *)vedata)->stl; - DRWShadingGroup *clay_shgrp, *hair_shgrp; + DRWShadingGroup *clay_shgrp; if (!DRW_object_is_renderable(ob)) return; @@ -764,6 +807,15 @@ static void clay_cache_populate(void *vedata, Object *ob) } } + /* Handle particles first in case the emitter itself shouldn't be rendered. */ + if (ob->type == OB_MESH) { + clay_cache_populate_particles(vedata, ob); + } + + if (DRW_check_object_visible_within_active_context(ob) == false) { + return; + } + struct Gwn_Batch *geom = DRW_cache_object_surface_get(ob); if (geom) { IDProperty *ces_mode_ob = BKE_layer_collection_engine_evaluated_get(ob, COLLECTION_MODE_OBJECT, ""); @@ -797,33 +849,6 @@ static void clay_cache_populate(void *vedata, Object *ob) DRW_shgroup_call_add(clay_shgrp, geom, ob->obmat); } } - - if (ob->type == OB_MESH) { - Scene *scene = draw_ctx->scene; - Object *obedit = scene->obedit; - - if (ob != obedit) { - for (ParticleSystem *psys = ob->particlesystem.first; psys; psys = psys->next) { - if (psys_check_enabled(ob, psys, false)) { - ParticleSettings *part = psys->part; - int draw_as = (part->draw_as == PART_DRAW_REND) ? part->ren_as : part->draw_as; - - if (draw_as == PART_DRAW_PATH && !psys->pathcache && !psys->childcache) { - draw_as = PART_DRAW_DOT; - } - - static float mat[4][4]; - unit_m4(mat); - - if (draw_as == PART_DRAW_PATH) { - geom = DRW_cache_particles_get_hair(psys, NULL); - hair_shgrp = CLAY_hair_shgrp_get(vedata, ob, stl, psl); - DRW_shgroup_call_add(hair_shgrp, geom, mat); - } - } - } - } - } } static void clay_cache_finish(void *vedata) @@ -836,18 +861,25 @@ static void clay_cache_finish(void *vedata) static void clay_draw_scene(void *vedata) { - + CLAY_StorageList *stl = ((CLAY_Data *)vedata)->stl; CLAY_PassList *psl = ((CLAY_Data *)vedata)->psl; CLAY_FramebufferList *fbl = ((CLAY_Data *)vedata)->fbl; DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get(); /* Pass 1 : Depth pre-pass */ - DRW_draw_pass(psl->depth_pass); - DRW_draw_pass(psl->depth_pass_cull); + if (stl->g_data->enable_ao) { + DRW_draw_pass(psl->depth_pass); + DRW_draw_pass(psl->depth_pass_cull); + } + else { + DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS; + DRW_pass_state_set(psl->clay_pass, state); + DRW_pass_state_set(psl->clay_pass_flat, state); + } /* Pass 2 : Duplicate depth */ /* Unless we go for deferred shading we need this to avoid manual depth test and artifacts */ - if (DRW_state_is_fbo()) { + if (DRW_state_is_fbo() && stl->g_data->enable_ao) { /* attach temp textures */ DRW_framebuffer_texture_attach(fbl->dupli_depth, e_data.depth_dup, 0, 0); @@ -917,6 +949,7 @@ DrawEngineType draw_engine_clay_type = { &clay_draw_scene, NULL, NULL, + NULL, }; RenderEngineType DRW_engine_viewport_clay_type = { diff --git a/source/blender/draw/engines/eevee/eevee_data.c b/source/blender/draw/engines/eevee/eevee_data.c index d5582a498a4..c6e5f645f10 100644 --- a/source/blender/draw/engines/eevee/eevee_data.c +++ b/source/blender/draw/engines/eevee/eevee_data.c @@ -45,13 +45,17 @@ static void eevee_view_layer_data_free(void *storage) DRW_TEXTURE_FREE_SAFE(sldata->shadow_cascade_target); DRW_TEXTURE_FREE_SAFE(sldata->shadow_cascade_blur); DRW_TEXTURE_FREE_SAFE(sldata->shadow_pool); - BLI_freelistN(&sldata->shadow_casters); + MEM_SAFE_FREE(sldata->shcasters_buffers[0].shadow_casters); + MEM_SAFE_FREE(sldata->shcasters_buffers[0].flags); + MEM_SAFE_FREE(sldata->shcasters_buffers[1].shadow_casters); + MEM_SAFE_FREE(sldata->shcasters_buffers[1].flags); /* Probes */ MEM_SAFE_FREE(sldata->probes); DRW_UBO_FREE_SAFE(sldata->probe_ubo); DRW_UBO_FREE_SAFE(sldata->grid_ubo); DRW_UBO_FREE_SAFE(sldata->planar_ubo); + DRW_UBO_FREE_SAFE(sldata->common_ubo); DRW_FRAMEBUFFER_FREE_SAFE(sldata->probe_fb); DRW_FRAMEBUFFER_FREE_SAFE(sldata->probe_filter_fb); DRW_TEXTURE_FREE_SAFE(sldata->probe_rt); @@ -59,24 +63,6 @@ static void eevee_view_layer_data_free(void *storage) DRW_TEXTURE_FREE_SAFE(sldata->probe_pool); DRW_TEXTURE_FREE_SAFE(sldata->irradiance_pool); DRW_TEXTURE_FREE_SAFE(sldata->irradiance_rt); - - /* Volumetrics */ - MEM_SAFE_FREE(sldata->volumetrics); -} - -static void eevee_lamp_data_free(void *storage) -{ - EEVEE_LampEngineData *led = (EEVEE_LampEngineData *)storage; - - MEM_SAFE_FREE(led->storage); - BLI_freelistN(&led->shadow_caster_list); -} - -static void eevee_lightprobe_data_free(void *storage) -{ - EEVEE_LightProbeEngineData *ped = (EEVEE_LightProbeEngineData *)storage; - - BLI_freelistN(&ped->captured_object_list); } EEVEE_ViewLayerData *EEVEE_view_layer_data_get(void) @@ -97,59 +83,95 @@ EEVEE_ViewLayerData *EEVEE_view_layer_data_ensure(void) return *sldata; } +/* Object data. */ + +static void eevee_object_data_init(ObjectEngineData *engine_data) +{ + EEVEE_ObjectEngineData *eevee_data = (EEVEE_ObjectEngineData *)engine_data; + eevee_data->shadow_caster_id = -1; +} + EEVEE_ObjectEngineData *EEVEE_object_data_get(Object *ob) { + if (ELEM(ob->type, OB_LIGHTPROBE, OB_LAMP)) { + return NULL; + } return (EEVEE_ObjectEngineData *)DRW_object_engine_data_get( ob, &draw_engine_eevee_type); } EEVEE_ObjectEngineData *EEVEE_object_data_ensure(Object *ob) { - EEVEE_ObjectEngineData **oedata = (EEVEE_ObjectEngineData **)DRW_object_engine_data_ensure( - ob, &draw_engine_eevee_type, NULL); + BLI_assert(!ELEM(ob->type, OB_LIGHTPROBE, OB_LAMP)); + return (EEVEE_ObjectEngineData *)DRW_object_engine_data_ensure( + ob, + &draw_engine_eevee_type, + sizeof(EEVEE_ObjectEngineData), + eevee_object_data_init, + NULL); +} - if (*oedata == NULL) { - *oedata = MEM_callocN(sizeof(**oedata), "EEVEE_ObjectEngineData"); - } +/* Light probe data. */ + +static void eevee_lightprobe_data_init(ObjectEngineData *engine_data) +{ + EEVEE_LightProbeEngineData *ped = (EEVEE_LightProbeEngineData *)engine_data; + ped->need_full_update = true; + ped->need_update = true; +} - return *oedata; +static void eevee_lightprobe_data_free(ObjectEngineData *engine_data) +{ + EEVEE_LightProbeEngineData *ped = (EEVEE_LightProbeEngineData *)engine_data; + + BLI_freelistN(&ped->captured_object_list); } EEVEE_LightProbeEngineData *EEVEE_lightprobe_data_get(Object *ob) { + if (ob->type != OB_LIGHTPROBE) { + return NULL; + } return (EEVEE_LightProbeEngineData *)DRW_object_engine_data_get( ob, &draw_engine_eevee_type); } EEVEE_LightProbeEngineData *EEVEE_lightprobe_data_ensure(Object *ob) { - EEVEE_LightProbeEngineData **pedata = (EEVEE_LightProbeEngineData **)DRW_object_engine_data_ensure( - ob, &draw_engine_eevee_type, &eevee_lightprobe_data_free); + BLI_assert(ob->type == OB_LIGHTPROBE); + return (EEVEE_LightProbeEngineData *)DRW_object_engine_data_ensure( + ob, + &draw_engine_eevee_type, + sizeof(EEVEE_LightProbeEngineData), + &eevee_lightprobe_data_init, + &eevee_lightprobe_data_free); +} - if (*pedata == NULL) { - *pedata = MEM_callocN(sizeof(**pedata), "EEVEE_LightProbeEngineData"); - (*pedata)->need_full_update = true; - (*pedata)->need_update = true; - } +/* Lamp data. */ - return *pedata; +static void eevee_lamp_data_init(ObjectEngineData *engine_data) +{ + EEVEE_LampEngineData *led = (EEVEE_LampEngineData *)engine_data; + led->need_update = true; + led->prev_cube_shadow_id = -1; } EEVEE_LampEngineData *EEVEE_lamp_data_get(Object *ob) { + if (ob->type != OB_LAMP) { + return NULL; + } return (EEVEE_LampEngineData *)DRW_object_engine_data_get( ob, &draw_engine_eevee_type); } EEVEE_LampEngineData *EEVEE_lamp_data_ensure(Object *ob) { - EEVEE_LampEngineData **ledata = (EEVEE_LampEngineData **)DRW_object_engine_data_ensure( - ob, &draw_engine_eevee_type, &eevee_lamp_data_free); - - if (*ledata == NULL) { - *ledata = MEM_callocN(sizeof(**ledata), "EEVEE_LampEngineData"); - (*ledata)->need_update = true; - } - - return *ledata; + BLI_assert(ob->type == OB_LAMP); + return (EEVEE_LampEngineData *)DRW_object_engine_data_ensure( + ob, + &draw_engine_eevee_type, + sizeof(EEVEE_LampEngineData), + eevee_lamp_data_init, + NULL); } diff --git a/source/blender/draw/engines/eevee/eevee_depth_of_field.c b/source/blender/draw/engines/eevee/eevee_depth_of_field.c index ef7e6412fc4..f5fc79aba4f 100644 --- a/source/blender/draw/engines/eevee/eevee_depth_of_field.c +++ b/source/blender/draw/engines/eevee/eevee_depth_of_field.c @@ -45,6 +45,7 @@ #include "BKE_screen.h" #include "DEG_depsgraph.h" +#include "DEG_depsgraph_query.h" #include "eevee_private.h" #include "GPU_extensions.h" @@ -74,7 +75,7 @@ static void eevee_create_shader_depth_of_field(void) datatoc_effect_dof_frag_glsl, "#define STEP_RESOLVE\n"); } -int EEVEE_depth_of_field_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata) +int EEVEE_depth_of_field_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata, Object *camera) { EEVEE_StorageList *stl = vedata->stl; EEVEE_FramebufferList *fbl = vedata->fbl; @@ -87,16 +88,15 @@ int EEVEE_depth_of_field_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *v if (BKE_collection_engine_property_value_get_bool(props, "dof_enable")) { Scene *scene = draw_ctx->scene; - View3D *v3d = draw_ctx->v3d; RegionView3D *rv3d = draw_ctx->rv3d; if (!e_data.dof_downsample_sh) { eevee_create_shader_depth_of_field(); } - if (rv3d->persp == RV3D_CAMOB && v3d->camera) { + if (camera) { const float *viewport_size = DRW_viewport_size_get(); - Camera *cam = (Camera *)v3d->camera->data; + Camera *cam = (Camera *)camera->data; /* Retreive Near and Far distance */ effects->dof_near_far[0] = -cam->clipsta; @@ -125,12 +125,15 @@ int EEVEE_depth_of_field_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *v &fbl->dof_down_fb, &draw_engine_eevee_type, buffer_size[0], buffer_size[1], tex_down, 3); - DRWFboTexture tex_scatter_far = {&txl->dof_far_blur, DRW_TEX_RGBA_16, DRW_TEX_FILTER}; + /* Go full 32bits for rendering and reduce the color artifacts. */ + DRWTextureFormat fb_format = DRW_state_is_image_render() ? DRW_TEX_RGBA_32 : DRW_TEX_RGBA_16; + + DRWFboTexture tex_scatter_far = {&txl->dof_far_blur, fb_format, DRW_TEX_FILTER}; DRW_framebuffer_init( &fbl->dof_scatter_far_fb, &draw_engine_eevee_type, buffer_size[0], buffer_size[1], &tex_scatter_far, 1); - DRWFboTexture tex_scatter_near = {&txl->dof_near_blur, DRW_TEX_RGBA_16, DRW_TEX_FILTER}; + DRWFboTexture tex_scatter_near = {&txl->dof_near_blur, fb_format, DRW_TEX_FILTER}; DRW_framebuffer_init( &fbl->dof_scatter_near_fb, &draw_engine_eevee_type, buffer_size[0], buffer_size[1], &tex_scatter_near, 1); @@ -142,7 +145,7 @@ int EEVEE_depth_of_field_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *v float rotation = cam->gpu_dof.rotation; float ratio = 1.0f / cam->gpu_dof.ratio; float sensor = BKE_camera_sensor_size(cam->sensor_fit, cam->sensor_x, cam->sensor_y); - float focus_dist = BKE_camera_object_dof_distance(v3d->camera); + float focus_dist = BKE_camera_object_dof_distance(camera); float focal_len = cam->lens; UNUSED_VARS(rotation, ratio); @@ -158,9 +161,13 @@ int EEVEE_depth_of_field_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *v float focal_len_scaled = scale_camera * focal_len; float sensor_scaled = scale_camera * sensor; + if (rv3d != NULL) { + sensor_scaled *= rv3d->viewcamtexcofac[0]; + } + effects->dof_params[0] = aperture * fabsf(focal_len_scaled / (focus_dist - focal_len_scaled)); effects->dof_params[1] = -focus_dist; - effects->dof_params[2] = viewport_size[0] / (rv3d->viewcamtexcofac[0] * sensor_scaled); + effects->dof_params[2] = viewport_size[0] / sensor_scaled; effects->dof_bokeh[0] = blades; effects->dof_bokeh[1] = rotation; effects->dof_bokeh[2] = ratio; @@ -213,7 +220,7 @@ void EEVEE_depth_of_field_cache_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_ DRW_shgroup_uniform_vec3(grp, "dofParams", effects->dof_params, 1); DRW_shgroup_call_add(grp, quad, NULL); - psl->dof_scatter = DRW_pass_create("DoF Scatter", DRW_STATE_WRITE_COLOR | DRW_STATE_ADDITIVE); + psl->dof_scatter = DRW_pass_create("DoF Scatter", DRW_STATE_WRITE_COLOR | DRW_STATE_ADDITIVE_FULL); /* This create an empty batch of N triangles to be positioned * by the vertex shader 0.4ms against 6ms with instancing */ diff --git a/source/blender/draw/engines/eevee/eevee_effects.c b/source/blender/draw/engines/eevee/eevee_effects.c index 703369a86ee..c1ac085230e 100644 --- a/source/blender/draw/engines/eevee/eevee_effects.c +++ b/source/blender/draw/engines/eevee/eevee_effects.c @@ -27,10 +27,9 @@ #include "DRW_render.h" -#include "BKE_global.h" /* for G.debug_value */ - #include "eevee_private.h" #include "GPU_texture.h" +#include "GPU_extensions.h" static struct { /* Downsample Depth */ @@ -77,36 +76,31 @@ static void eevee_create_shader_downsample(void) "#define MAX_PASS\n"); e_data.minz_downdepth_sh = DRW_shader_create_fullscreen( datatoc_effect_minmaxz_frag_glsl, - "#define MIN_PASS\n" - "#define INPUT_DEPTH\n"); + "#define MIN_PASS\n"); e_data.maxz_downdepth_sh = DRW_shader_create_fullscreen( datatoc_effect_minmaxz_frag_glsl, - "#define MAX_PASS\n" - "#define INPUT_DEPTH\n"); + "#define MAX_PASS\n"); e_data.minz_downdepth_layer_sh = DRW_shader_create_fullscreen( datatoc_effect_minmaxz_frag_glsl, "#define MIN_PASS\n" - "#define LAYERED\n" - "#define INPUT_DEPTH\n"); + "#define LAYERED\n"); e_data.maxz_downdepth_layer_sh = DRW_shader_create_fullscreen( datatoc_effect_minmaxz_frag_glsl, "#define MAX_PASS\n" - "#define LAYERED\n" - "#define INPUT_DEPTH\n"); + "#define LAYERED\n"); e_data.minz_copydepth_sh = DRW_shader_create_fullscreen( datatoc_effect_minmaxz_frag_glsl, "#define MIN_PASS\n" - "#define INPUT_DEPTH\n" "#define COPY_DEPTH\n"); e_data.maxz_copydepth_sh = DRW_shader_create_fullscreen( datatoc_effect_minmaxz_frag_glsl, "#define MAX_PASS\n" - "#define INPUT_DEPTH\n" "#define COPY_DEPTH\n"); } -void EEVEE_effects_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) +void EEVEE_effects_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, Object *camera) { + EEVEE_CommonUniformBuffer *common_data = &sldata->common_data; EEVEE_StorageList *stl = vedata->stl; EEVEE_FramebufferList *fbl = vedata->fbl; EEVEE_TextureList *txl = vedata->txl; @@ -126,9 +120,9 @@ void EEVEE_effects_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) effects = stl->effects; effects->enabled_effects = 0; - effects->enabled_effects |= EEVEE_motion_blur_init(sldata, vedata); + effects->enabled_effects |= EEVEE_motion_blur_init(sldata, vedata, camera); effects->enabled_effects |= EEVEE_bloom_init(sldata, vedata); - effects->enabled_effects |= EEVEE_depth_of_field_init(sldata, vedata); + effects->enabled_effects |= EEVEE_depth_of_field_init(sldata, vedata, camera); effects->enabled_effects |= EEVEE_temporal_sampling_init(sldata, vedata); effects->enabled_effects |= EEVEE_occlusion_init(sldata, vedata); effects->enabled_effects |= EEVEE_subsurface_init(sldata, vedata); @@ -154,10 +148,17 @@ void EEVEE_effects_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) * MinMax Pyramid */ DRWFboTexture texmax = {&txl->maxzbuffer, DRW_TEX_DEPTH_24, DRW_TEX_MIPMAP}; + + if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_ANY, GPU_DRIVER_ANY)) { + /* Intel gpu seems to have problem rendering to only depth format */ + texmax.format = DRW_TEX_R_32; + } + DRW_framebuffer_init(&fbl->downsample_fb, &draw_engine_eevee_type, - (int)viewport_size[0] / 2, (int)viewport_size[1] / 2, + max_ii((int)viewport_size[0] / 2, 1), max_ii((int)viewport_size[1] / 2, 1), &texmax, 1); + /** * Compute Mipmap texel alignement. */ @@ -167,8 +168,8 @@ void EEVEE_effects_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) mip_size[0] = floorf(fmaxf(1.0f, mip_size[0] / 2.0f)); mip_size[1] = floorf(fmaxf(1.0f, mip_size[1] / 2.0f)); } - stl->g_data->mip_ratio[i][0] = viewport_size[0] / (mip_size[0] * powf(2.0f, floorf(log2f(floorf(viewport_size[0] / mip_size[0]))))); - stl->g_data->mip_ratio[i][1] = viewport_size[1] / (mip_size[1] * powf(2.0f, floorf(log2f(floorf(viewport_size[1] / mip_size[1]))))); + common_data->mip_ratio[i][0] = viewport_size[0] / (mip_size[0] * powf(2.0f, floorf(log2f(floorf(viewport_size[0] / mip_size[0]))))); + common_data->mip_ratio[i][1] = viewport_size[1] / (mip_size[1] * powf(2.0f, floorf(log2f(floorf(viewport_size[1] / mip_size[1]))))); } @@ -207,12 +208,17 @@ void EEVEE_effects_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) } } -void EEVEE_effects_cache_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata) +void EEVEE_effects_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) { EEVEE_PassList *psl = vedata->psl; - EEVEE_StorageList *stl = vedata->stl; EEVEE_TextureList *txl = vedata->txl; - EEVEE_EffectsInfo *effects = stl->effects; + int downsample_write = DRW_STATE_WRITE_DEPTH; + + /* Intel gpu seems to have problem rendering to only depth format. + * Use color texture instead. */ + if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_ANY, GPU_DRIVER_ANY)) { + downsample_write = DRW_STATE_WRITE_COLOR; + } struct Gwn_Batch *quad = DRW_cache_fullscreen_quad_get(); @@ -220,7 +226,7 @@ void EEVEE_effects_cache_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *v psl->color_downsample_ps = DRW_pass_create("Downsample", DRW_STATE_WRITE_COLOR); DRWShadingGroup *grp = DRW_shgroup_create(e_data.downsample_sh, psl->color_downsample_ps); DRW_shgroup_uniform_buffer(grp, "source", &e_data.color_src); - DRW_shgroup_uniform_float(grp, "fireflyFactor", &effects->ssr_firefly_fac, 1); + DRW_shgroup_uniform_float(grp, "fireflyFactor", &sldata->common_data.ssr_firefly_fac, 1); DRW_shgroup_call_add(grp, quad, NULL); } @@ -239,39 +245,39 @@ void EEVEE_effects_cache_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *v DRWShadingGroup *grp; #if 0 /* Not used for now */ - psl->minz_downlevel_ps = DRW_pass_create("HiZ Min Down Level", DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS); + psl->minz_downlevel_ps = DRW_pass_create("HiZ Min Down Level", downsample_write | DRW_STATE_DEPTH_ALWAYS); grp = DRW_shgroup_create(e_data.minz_downlevel_sh, psl->minz_downlevel_ps); DRW_shgroup_uniform_buffer(grp, "depthBuffer", &stl->g_data->minzbuffer); DRW_shgroup_call_add(grp, quad, NULL); #endif - psl->maxz_downlevel_ps = DRW_pass_create("HiZ Max Down Level", DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS); + psl->maxz_downlevel_ps = DRW_pass_create("HiZ Max Down Level", downsample_write | DRW_STATE_DEPTH_ALWAYS); grp = DRW_shgroup_create(e_data.maxz_downlevel_sh, psl->maxz_downlevel_ps); DRW_shgroup_uniform_buffer(grp, "depthBuffer", &txl->maxzbuffer); DRW_shgroup_call_add(grp, quad, NULL); /* Copy depth buffer to halfres top level of HiZ */ #if 0 /* Not used for now */ - psl->minz_downdepth_ps = DRW_pass_create("HiZ Min Copy Depth Halfres", DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS); + psl->minz_downdepth_ps = DRW_pass_create("HiZ Min Copy Depth Halfres", downsample_write | DRW_STATE_DEPTH_ALWAYS); grp = DRW_shgroup_create(e_data.minz_downdepth_sh, psl->minz_downdepth_ps); DRW_shgroup_uniform_buffer(grp, "depthBuffer", &e_data.depth_src); DRW_shgroup_call_add(grp, quad, NULL); #endif - psl->maxz_downdepth_ps = DRW_pass_create("HiZ Max Copy Depth Halfres", DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS); + psl->maxz_downdepth_ps = DRW_pass_create("HiZ Max Copy Depth Halfres", downsample_write | DRW_STATE_DEPTH_ALWAYS); grp = DRW_shgroup_create(e_data.maxz_downdepth_sh, psl->maxz_downdepth_ps); DRW_shgroup_uniform_buffer(grp, "depthBuffer", &e_data.depth_src); DRW_shgroup_call_add(grp, quad, NULL); #if 0 /* Not used for now */ - psl->minz_downdepth_layer_ps = DRW_pass_create("HiZ Min Copy DepthLayer Halfres", DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS); + psl->minz_downdepth_layer_ps = DRW_pass_create("HiZ Min Copy DepthLayer Halfres", downsample_write | DRW_STATE_DEPTH_ALWAYS); grp = DRW_shgroup_create(e_data.minz_downdepth_layer_sh, psl->minz_downdepth_layer_ps); DRW_shgroup_uniform_buffer(grp, "depthBuffer", &e_data.depth_src); DRW_shgroup_uniform_int(grp, "depthLayer", &e_data.depth_src_layer, 1); DRW_shgroup_call_add(grp, quad, NULL); #endif - psl->maxz_downdepth_layer_ps = DRW_pass_create("HiZ Max Copy DepthLayer Halfres", DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS); + psl->maxz_downdepth_layer_ps = DRW_pass_create("HiZ Max Copy DepthLayer Halfres", downsample_write | DRW_STATE_DEPTH_ALWAYS); grp = DRW_shgroup_create(e_data.maxz_downdepth_layer_sh, psl->maxz_downdepth_layer_ps); DRW_shgroup_uniform_buffer(grp, "depthBuffer", &e_data.depth_src); DRW_shgroup_uniform_int(grp, "depthLayer", &e_data.depth_src_layer, 1); @@ -279,13 +285,13 @@ void EEVEE_effects_cache_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *v /* Copy depth buffer to halfres top level of HiZ */ #if 0 /* Not used for now */ - psl->minz_copydepth_ps = DRW_pass_create("HiZ Min Copy Depth Fullres", DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS); + psl->minz_copydepth_ps = DRW_pass_create("HiZ Min Copy Depth Fullres", downsample_write | DRW_STATE_DEPTH_ALWAYS); grp = DRW_shgroup_create(e_data.minz_copydepth_sh, psl->minz_copydepth_ps); DRW_shgroup_uniform_buffer(grp, "depthBuffer", &e_data.depth_src); DRW_shgroup_call_add(grp, quad, NULL); #endif - psl->maxz_copydepth_ps = DRW_pass_create("HiZ Max Copy Depth Fullres", DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS); + psl->maxz_copydepth_ps = DRW_pass_create("HiZ Max Copy Depth Fullres", downsample_write | DRW_STATE_DEPTH_ALWAYS); grp = DRW_shgroup_create(e_data.maxz_copydepth_sh, psl->maxz_copydepth_ps); DRW_shgroup_uniform_buffer(grp, "depthBuffer", &e_data.depth_src); DRW_shgroup_call_add(grp, quad, NULL); @@ -392,13 +398,12 @@ void EEVEE_downsample_cube_buffer(EEVEE_Data *vedata, struct GPUFrameBuffer *fb_ DRW_stats_group_end(); } -void EEVEE_draw_effects(EEVEE_Data *vedata) +void EEVEE_draw_effects(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) { EEVEE_TextureList *txl = vedata->txl; EEVEE_FramebufferList *fbl = vedata->fbl; EEVEE_StorageList *stl = vedata->stl; EEVEE_EffectsInfo *effects = stl->effects; - DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get(); DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); /* only once per frame after the first post process */ @@ -419,39 +424,9 @@ void EEVEE_draw_effects(EEVEE_Data *vedata) EEVEE_depth_of_field_draw(vedata); EEVEE_bloom_draw(vedata); - /* Restore default framebuffer */ - DRW_framebuffer_texture_attach(dfbl->default_fb, dtxl->depth, 0, 0); - DRW_framebuffer_bind(dfbl->default_fb); - - /* Tonemapping */ - DRW_transform_to_display(effects->source_buffer); - - /* Debug : Ouput buffer to view. */ - switch (G.debug_value) { - case 1: - if (txl->maxzbuffer) DRW_transform_to_display(txl->maxzbuffer); - break; - case 2: - if (stl->g_data->ssr_hit_output[0]) DRW_transform_to_display(stl->g_data->ssr_hit_output[0]); - break; - case 3: - if (txl->ssr_normal_input) DRW_transform_to_display(txl->ssr_normal_input); - break; - case 4: - if (txl->ssr_specrough_input) DRW_transform_to_display(txl->ssr_specrough_input); - break; - case 5: - if (txl->color_double_buffer) DRW_transform_to_display(txl->color_double_buffer); - break; - case 6: - if (stl->g_data->gtao_horizons_debug) DRW_transform_to_display(stl->g_data->gtao_horizons_debug); - break; - case 7: - if (txl->sss_data) DRW_transform_to_display(txl->sss_data); - break; - default: - break; - } + /* Save the final texture and framebuffer for final transformation or read. */ + effects->final_tx = effects->source_buffer; + effects->final_fb = (effects->target_buffer != fbl->main) ? fbl->main : fbl->effect_fb; /* If no post processes is enabled, buffers are still not swapped, do it now. */ SWAP_DOUBLE_BUFFERS(); @@ -466,7 +441,7 @@ void EEVEE_draw_effects(EEVEE_Data *vedata) } /* Record pers matrix for the next frame. */ - DRW_viewport_matrix_get(stl->g_data->prev_persmat, DRW_MAT_PERS); + DRW_viewport_matrix_get(sldata->common_data.prev_persmat, DRW_MAT_PERS); /* Update double buffer status if render mode. */ if (DRW_state_is_image_render()) { diff --git a/source/blender/draw/engines/eevee/eevee_engine.c b/source/blender/draw/engines/eevee/eevee_engine.c index a20b1afe3d4..8e74f3344dd 100644 --- a/source/blender/draw/engines/eevee/eevee_engine.c +++ b/source/blender/draw/engines/eevee/eevee_engine.c @@ -29,9 +29,13 @@ #include "BLI_rand.h" #include "BKE_object.h" +#include "BKE_global.h" /* for G.debug_value */ +#include "BKE_screen.h" #include "DNA_world_types.h" +#include "ED_screen.h" + #include "GPU_material.h" #include "GPU_glew.h" @@ -52,11 +56,16 @@ static void eevee_engine_init(void *ved) EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl; EEVEE_ViewLayerData *sldata = EEVEE_view_layer_data_ensure(); + const DRWContextState *draw_ctx = DRW_context_state_get(); + View3D *v3d = draw_ctx->v3d; + RegionView3D *rv3d = draw_ctx->rv3d; + Object *camera = (rv3d->persp == RV3D_CAMOB) ? v3d->camera : NULL; + if (!stl->g_data) { /* Alloc transient pointers */ stl->g_data = MEM_callocN(sizeof(*stl->g_data), __func__); } - stl->g_data->background_alpha = 1.0f; + stl->g_data->background_alpha = DRW_state_draw_background() ? 1.0f : 0.0f; stl->g_data->valid_double_buffer = (txl->color_double_buffer != NULL); DRWFboTexture tex = {&txl->color, DRW_TEX_RGBA_16, DRW_TEX_FILTER | DRW_TEX_MIPMAP}; @@ -66,14 +75,17 @@ static void eevee_engine_init(void *ved) (int)viewport_size[0], (int)viewport_size[1], &tex, 1); - /* EEVEE_effects_init needs to go first for TAA */ - EEVEE_effects_init(sldata, vedata); + if (sldata->common_ubo == NULL) { + sldata->common_ubo = DRW_uniformbuffer_create(sizeof(sldata->common_data), &sldata->common_data); + } - EEVEE_materials_init(stl); + /* EEVEE_effects_init needs to go first for TAA */ + EEVEE_effects_init(sldata, vedata, camera); + EEVEE_materials_init(sldata, stl, fbl); EEVEE_lights_init(sldata); EEVEE_lightprobes_init(sldata, vedata); - if (stl->effects->taa_current_sample > 1) { + if ((stl->effects->taa_current_sample > 1) && !DRW_state_is_image_render()) { /* XXX otherwise it would break the other engines. */ DRW_viewport_matrix_override_unset(DRW_MAT_PERS); DRW_viewport_matrix_override_unset(DRW_MAT_PERSINV); @@ -113,22 +125,17 @@ static void eevee_cache_populate(void *vedata, Object *ob) } } - if (ELEM(ob->type, OB_MESH)) { - if (!BKE_object_is_visible(ob)) { - return; - } + if (DRW_check_object_visible_within_active_context(ob) == false) { + return; + } + if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT)) { EEVEE_materials_cache_populate(vedata, sldata, ob); const bool cast_shadow = true; if (cast_shadow) { - if ((ob->base_flag & BASE_FROMDUPLI) != 0) { - /* TODO: Special case for dupli objects because we cannot save the object pointer. */ - } - else { - BLI_addtail(&sldata->shadow_casters, BLI_genericNodeN(ob)); - } + EEVEE_lights_cache_shcaster_object_add(sldata, ob); } } else if (ob->type == OB_LIGHTPROBE) { @@ -140,12 +147,7 @@ static void eevee_cache_populate(void *vedata, Object *ob) } } else if (ob->type == OB_LAMP) { - if ((ob->base_flag & BASE_FROMDUPLI) != 0) { - /* TODO: Special case for dupli objects because we cannot save the object pointer. */ - } - else { - EEVEE_lights_cache_add(sldata, ob); - } + EEVEE_lights_cache_add(sldata, ob); } } @@ -158,46 +160,47 @@ static void eevee_cache_finish(void *vedata) EEVEE_lightprobes_cache_finish(sldata, vedata); } -static void eevee_draw_scene(void *vedata) +/* As renders in an HDR offscreen buffer, we need draw everything once + * during the background pass. This way the other drawing callback between + * the background and the scene pass are visible. + * Note: we could break it up in two passes using some depth test + * to reduce the fillrate */ +static void eevee_draw_background(void *vedata) { EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl; + EEVEE_TextureList *txl = ((EEVEE_Data *)vedata)->txl; EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl; EEVEE_FramebufferList *fbl = ((EEVEE_Data *)vedata)->fbl; EEVEE_ViewLayerData *sldata = EEVEE_view_layer_data_ensure(); /* Default framebuffer and texture */ DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); + DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get(); /* Number of iteration: needed for all temporal effect (SSR, TAA) * when using opengl render. */ int loop_ct = DRW_state_is_image_render() ? 4 : 1; - static float rand = 0.0f; - - /* XXX temp for denoising render. TODO plug number of samples here */ - if (DRW_state_is_image_render()) { - rand += 1.0f / 16.0f; - rand = rand - floorf(rand); - - /* Set jitter offset */ - EEVEE_update_util_texture(rand); - } - else if (((stl->effects->enabled_effects & EFFECT_TAA) != 0) && (stl->effects->taa_current_sample > 1)) { - double r; - BLI_halton_1D(2, 0.0, stl->effects->taa_current_sample - 1, &r); - - /* Set jitter offset */ - /* PERF This is killing perf ! */ - EEVEE_update_util_texture((float)r); - } - while (loop_ct--) { + unsigned int primes[3] = {2, 3, 7}; + double offset[3] = {0.0, 0.0, 0.0}; + double r[3]; + + if (DRW_state_is_image_render() || + ((stl->effects->enabled_effects & EFFECT_TAA) != 0)) + { + BLI_halton_3D(primes, offset, stl->effects->taa_current_sample, r); + EEVEE_update_noise(psl, fbl, r); + } /* Refresh Probes */ DRW_stats_group_start("Probes Refresh"); EEVEE_lightprobes_refresh(sldata, vedata); DRW_stats_group_end(); + /* Update common buffer after probe rendering. */ + DRW_uniformbuffer_update(sldata->common_ubo, &sldata->common_data); + /* Refresh shadows */ DRW_stats_group_start("Shadows"); EEVEE_draw_shadows(sldata, psl); @@ -207,9 +210,19 @@ static void eevee_draw_scene(void *vedata) DRW_framebuffer_texture_detach(dtxl->depth); DRW_framebuffer_texture_attach(fbl->main, dtxl->depth, 0, 0); DRW_framebuffer_bind(fbl->main); - DRW_framebuffer_clear(false, true, true, NULL, 1.0f); + if (DRW_state_draw_background()) { + DRW_framebuffer_clear(false, true, true, NULL, 1.0f); + } + else { + /* We need to clear the alpha chanel in this case. */ + float clear_col[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + DRW_framebuffer_clear(true, true, true, clear_col, 1.0f); + } - if (((stl->effects->enabled_effects & EFFECT_TAA) != 0) && stl->effects->taa_current_sample > 1) { + if (((stl->effects->enabled_effects & EFFECT_TAA) != 0) && + (stl->effects->taa_current_sample > 1) && + !DRW_state_is_image_render()) + { DRW_viewport_matrix_override_set(stl->effects->overide_persmat, DRW_MAT_PERS); DRW_viewport_matrix_override_set(stl->effects->overide_persinv, DRW_MAT_PERSINV); DRW_viewport_matrix_override_set(stl->effects->overide_winmat, DRW_MAT_WIN); @@ -227,12 +240,14 @@ static void eevee_draw_scene(void *vedata) EEVEE_create_minmax_buffer(vedata, dtxl->depth, -1); DRW_stats_group_end(); - EEVEE_occlusion_compute(sldata, vedata); + EEVEE_occlusion_compute(sldata, vedata, dtxl->depth, -1); EEVEE_volumes_compute(sldata, vedata); /* Shading pass */ DRW_stats_group_start("Shading"); - DRW_draw_pass(psl->background_pass); + if (DRW_state_draw_background()) { + DRW_draw_pass(psl->background_pass); + } EEVEE_draw_default_passes(psl); DRW_draw_pass(psl->material_pass); EEVEE_subsurface_data_render(sldata, vedata); @@ -261,10 +276,10 @@ static void eevee_draw_scene(void *vedata) /* Post Process */ DRW_stats_group_start("Post FX"); - EEVEE_draw_effects(vedata); + EEVEE_draw_effects(sldata, vedata); DRW_stats_group_end(); - if (stl->effects->taa_current_sample > 1) { + if ((stl->effects->taa_current_sample > 1) && !DRW_state_is_image_render()) { DRW_viewport_matrix_override_unset(DRW_MAT_PERS); DRW_viewport_matrix_override_unset(DRW_MAT_PERSINV); DRW_viewport_matrix_override_unset(DRW_MAT_WIN); @@ -272,6 +287,43 @@ static void eevee_draw_scene(void *vedata) } } + /* Restore default framebuffer */ + DRW_framebuffer_texture_attach(dfbl->default_fb, dtxl->depth, 0, 0); + DRW_framebuffer_bind(dfbl->default_fb); + + /* Tonemapping */ + DRW_transform_to_display(stl->effects->final_tx); + + /* Debug : Ouput buffer to view. */ + switch (G.debug_value) { + case 1: + if (txl->maxzbuffer) DRW_transform_to_display(txl->maxzbuffer); + break; + case 2: + if (stl->g_data->ssr_pdf_output) DRW_transform_to_display(stl->g_data->ssr_pdf_output); + break; + case 3: + if (txl->ssr_normal_input) DRW_transform_to_display(txl->ssr_normal_input); + break; + case 4: + if (txl->ssr_specrough_input) DRW_transform_to_display(txl->ssr_specrough_input); + break; + case 5: + if (txl->color_double_buffer) DRW_transform_to_display(txl->color_double_buffer); + break; + case 6: + if (stl->g_data->gtao_horizons_debug) DRW_transform_to_display(stl->g_data->gtao_horizons_debug); + break; + case 7: + if (txl->gtao_horizons) DRW_transform_to_display(txl->gtao_horizons); + break; + case 8: + if (txl->sss_data) DRW_transform_to_display(txl->sss_data); + break; + default: + break; + } + EEVEE_volumes_free_smoke_textures(); stl->g_data->view_updated = false; @@ -285,24 +337,50 @@ static void eevee_view_update(void *vedata) } } -static void eevee_id_update(void *UNUSED(vedata), ID *id) +static void eevee_id_object_update(void *UNUSED(vedata), Object *object) { - const ID_Type id_type = GS(id->name); - if (id_type == ID_OB) { - Object *object = (Object *)id; - EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_get(object); - if (ped != NULL) { - ped->need_full_update = true; - } - EEVEE_LampEngineData *led = EEVEE_lamp_data_get(object); - if (led != NULL) { - led->need_update = true; - } - EEVEE_ObjectEngineData *oedata = EEVEE_object_data_get(object); - if (oedata != NULL) { - oedata->need_update = true; - } + /* This is a bit mask of components which update is to be ignored. */ + const int ignore_updates = ID_RECALC_COLLECTIONS; + const int allowed_updates = ~ignore_updates; + EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_get(object); + if (ped != NULL && (ped->engine_data.recalc & allowed_updates) != 0) { + ped->need_full_update = true; + ped->engine_data.recalc = 0; } + EEVEE_LampEngineData *led = EEVEE_lamp_data_get(object); + if (led != NULL && (led->engine_data.recalc & allowed_updates) != 0) { + led->need_update = true; + led->engine_data.recalc = 0; + } + EEVEE_ObjectEngineData *oedata = EEVEE_object_data_get(object); + if (oedata != NULL && (oedata->engine_data.recalc & allowed_updates) != 0) { + oedata->need_update = true; + oedata->engine_data.recalc = 0; + } +} + +static void eevee_id_update(void *vedata, ID *id) +{ + /* Handle updates based on ID type. */ + switch (GS(id->name)) { + case ID_OB: + eevee_id_object_update(vedata, (Object *)id); + break; + default: + /* pass */ + break; + } +} + +static void eevee_render_to_image(void *vedata, struct RenderEngine *engine, struct Depsgraph *depsgraph) +{ + EEVEE_render_init(vedata, engine, depsgraph); + + DRW_render_object_iter(vedata, engine, depsgraph, EEVEE_render_cache); + /* Actually do the rendering. */ + EEVEE_render_draw(vedata, engine, depsgraph); + /* Write outputs to RenderResult. */ + EEVEE_render_output(vedata, engine, depsgraph); } static void eevee_engine_free(void) @@ -340,7 +418,8 @@ static void eevee_view_layer_settings_create(RenderEngine *UNUSED(engine), IDPro BKE_collection_engine_property_add_int(props, "gi_cubemap_resolution", 512); BKE_collection_engine_property_add_int(props, "gi_visibility_resolution", 32); - BKE_collection_engine_property_add_int(props, "taa_samples", 8); + BKE_collection_engine_property_add_int(props, "taa_samples", 16); + BKE_collection_engine_property_add_int(props, "taa_render_samples", 64); BKE_collection_engine_property_add_bool(props, "sss_enable", false); BKE_collection_engine_property_add_int(props, "sss_samples", 7); @@ -350,7 +429,6 @@ static void eevee_view_layer_settings_create(RenderEngine *UNUSED(engine), IDPro BKE_collection_engine_property_add_bool(props, "ssr_enable", false); BKE_collection_engine_property_add_bool(props, "ssr_refraction", false); BKE_collection_engine_property_add_bool(props, "ssr_halfres", true); - BKE_collection_engine_property_add_int(props, "ssr_ray_count", 1); BKE_collection_engine_property_add_float(props, "ssr_quality", 0.25f); BKE_collection_engine_property_add_float(props, "ssr_max_roughness", 0.5f); BKE_collection_engine_property_add_float(props, "ssr_thickness", 0.2f); @@ -371,12 +449,10 @@ static void eevee_view_layer_settings_create(RenderEngine *UNUSED(engine), IDPro BKE_collection_engine_property_add_bool(props, "gtao_enable", false); BKE_collection_engine_property_add_bool(props, "gtao_use_bent_normals", true); - BKE_collection_engine_property_add_bool(props, "gtao_denoise", true); BKE_collection_engine_property_add_bool(props, "gtao_bounce", true); BKE_collection_engine_property_add_float(props, "gtao_distance", 0.2f); BKE_collection_engine_property_add_float(props, "gtao_factor", 1.0f); BKE_collection_engine_property_add_float(props, "gtao_quality", 0.25f); - BKE_collection_engine_property_add_int(props, "gtao_samples", 2); BKE_collection_engine_property_add_bool(props, "dof_enable", false); BKE_collection_engine_property_add_float(props, "bokeh_max_size", 100.0f); @@ -411,16 +487,17 @@ DrawEngineType draw_engine_eevee_type = { &eevee_cache_init, &eevee_cache_populate, &eevee_cache_finish, - &eevee_draw_scene, - NULL, //&EEVEE_draw_scene + &eevee_draw_background, + NULL, /* Everything is drawn in the background pass (see comment on function) */ &eevee_view_update, &eevee_id_update, + &eevee_render_to_image, }; RenderEngineType DRW_engine_viewport_eevee_type = { NULL, NULL, EEVEE_ENGINE, N_("Eevee"), RE_INTERNAL | RE_USE_SHADING_NODES, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, &DRW_render_to_image, NULL, NULL, NULL, NULL, NULL, &eevee_layer_collection_settings_create, &eevee_view_layer_settings_create, &draw_engine_eevee_type, diff --git a/source/blender/draw/engines/eevee/eevee_lightprobes.c b/source/blender/draw/engines/eevee/eevee_lightprobes.c index d7ccc1a5336..7403da737dd 100644 --- a/source/blender/draw/engines/eevee/eevee_lightprobes.c +++ b/source/blender/draw/engines/eevee/eevee_lightprobes.c @@ -26,7 +26,7 @@ #include "DRW_render.h" #include "BLI_utildefines.h" -#include "BLI_dynstr.h" +#include "BLI_string_utils.h" #include "BLI_rand.h" #include "DNA_world_types.h" @@ -83,7 +83,6 @@ static struct { struct GPUTexture *cube_face_minmaxz; int update_world; - bool world_ready_to_shade; } e_data = {NULL}; /* Engine data */ extern char datatoc_background_vert_glsl[]; @@ -107,6 +106,7 @@ extern char datatoc_irradiance_lib_glsl[]; extern char datatoc_lightprobe_lib_glsl[]; extern char datatoc_octahedron_lib_glsl[]; extern char datatoc_bsdf_common_lib_glsl[]; +extern char datatoc_common_uniforms_lib_glsl[]; extern char datatoc_bsdf_sampling_lib_glsl[]; extern GlobalsUboStorage ts; @@ -204,12 +204,11 @@ static void lightprobe_shaders_init(void) char *shader_str = NULL; - DynStr *ds_frag = BLI_dynstr_new(); - BLI_dynstr_append(ds_frag, datatoc_bsdf_common_lib_glsl); - BLI_dynstr_append(ds_frag, datatoc_bsdf_sampling_lib_glsl); - BLI_dynstr_append(ds_frag, datatoc_lightprobe_filter_glossy_frag_glsl); - shader_str = BLI_dynstr_get_cstring(ds_frag); - BLI_dynstr_free(ds_frag); + shader_str = BLI_string_joinN( + datatoc_common_uniforms_lib_glsl, + datatoc_bsdf_common_lib_glsl, + datatoc_bsdf_sampling_lib_glsl, + datatoc_lightprobe_filter_glossy_frag_glsl); e_data.probe_filter_glossy_sh = DRW_shader_create( datatoc_lightprobe_vert_glsl, datatoc_lightprobe_geom_glsl, shader_str, filter_defines); @@ -219,36 +218,33 @@ static void lightprobe_shaders_init(void) MEM_freeN(shader_str); - ds_frag = BLI_dynstr_new(); - BLI_dynstr_append(ds_frag, datatoc_bsdf_common_lib_glsl); - BLI_dynstr_append(ds_frag, datatoc_bsdf_sampling_lib_glsl); - BLI_dynstr_append(ds_frag, datatoc_lightprobe_filter_diffuse_frag_glsl); - shader_str = BLI_dynstr_get_cstring(ds_frag); - BLI_dynstr_free(ds_frag); + shader_str = BLI_string_joinN( + datatoc_common_uniforms_lib_glsl, + datatoc_bsdf_common_lib_glsl, + datatoc_bsdf_sampling_lib_glsl, + datatoc_lightprobe_filter_diffuse_frag_glsl); e_data.probe_filter_diffuse_sh = DRW_shader_create_fullscreen(shader_str, filter_defines); MEM_freeN(shader_str); - ds_frag = BLI_dynstr_new(); - BLI_dynstr_append(ds_frag, datatoc_bsdf_common_lib_glsl); - BLI_dynstr_append(ds_frag, datatoc_bsdf_sampling_lib_glsl); - BLI_dynstr_append(ds_frag, datatoc_lightprobe_filter_visibility_frag_glsl); - shader_str = BLI_dynstr_get_cstring(ds_frag); - BLI_dynstr_free(ds_frag); + shader_str = BLI_string_joinN( + datatoc_common_uniforms_lib_glsl, + datatoc_bsdf_common_lib_glsl, + datatoc_bsdf_sampling_lib_glsl, + datatoc_lightprobe_filter_visibility_frag_glsl); e_data.probe_filter_visibility_sh = DRW_shader_create_fullscreen(shader_str, filter_defines); MEM_freeN(shader_str); - ds_frag = BLI_dynstr_new(); - BLI_dynstr_append(ds_frag, datatoc_octahedron_lib_glsl); - BLI_dynstr_append(ds_frag, datatoc_bsdf_common_lib_glsl); - BLI_dynstr_append(ds_frag, datatoc_irradiance_lib_glsl); - BLI_dynstr_append(ds_frag, datatoc_lightprobe_lib_glsl); - BLI_dynstr_append(ds_frag, datatoc_lightprobe_grid_display_frag_glsl); - shader_str = BLI_dynstr_get_cstring(ds_frag); - BLI_dynstr_free(ds_frag); + shader_str = BLI_string_joinN( + datatoc_octahedron_lib_glsl, + datatoc_common_uniforms_lib_glsl, + datatoc_bsdf_common_lib_glsl, + datatoc_irradiance_lib_glsl, + datatoc_lightprobe_lib_glsl, + datatoc_lightprobe_grid_display_frag_glsl); e_data.probe_grid_display_sh = DRW_shader_create( datatoc_lightprobe_grid_display_vert_glsl, NULL, shader_str, filter_defines); @@ -258,13 +254,12 @@ static void lightprobe_shaders_init(void) e_data.probe_grid_fill_sh = DRW_shader_create_fullscreen( datatoc_lightprobe_grid_fill_frag_glsl, filter_defines); - ds_frag = BLI_dynstr_new(); - BLI_dynstr_append(ds_frag, datatoc_octahedron_lib_glsl); - BLI_dynstr_append(ds_frag, datatoc_bsdf_common_lib_glsl); - BLI_dynstr_append(ds_frag, datatoc_lightprobe_lib_glsl); - BLI_dynstr_append(ds_frag, datatoc_lightprobe_cube_display_frag_glsl); - shader_str = BLI_dynstr_get_cstring(ds_frag); - BLI_dynstr_free(ds_frag); + shader_str = BLI_string_joinN( + datatoc_octahedron_lib_glsl, + datatoc_common_uniforms_lib_glsl, + datatoc_bsdf_common_lib_glsl, + datatoc_lightprobe_lib_glsl, + datatoc_lightprobe_cube_display_frag_glsl); e_data.probe_cube_display_sh = DRW_shader_create( datatoc_lightprobe_cube_display_vert_glsl, NULL, shader_str, NULL); @@ -286,6 +281,7 @@ static void lightprobe_shaders_init(void) void EEVEE_lightprobes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *UNUSED(vedata)) { + EEVEE_CommonUniformBuffer *common_data = &sldata->common_data; bool update_all = false; const DRWContextState *draw_ctx = DRW_context_state_get(); ViewLayer *view_layer = draw_ctx->view_layer; @@ -298,15 +294,16 @@ void EEVEE_lightprobes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *UNUSED(veda if (!sldata->probes) { sldata->probes = MEM_callocN(sizeof(EEVEE_LightProbesInfo), "EEVEE_LightProbesInfo"); - sldata->probes->specular_toggle = true; - sldata->probes->ssr_toggle = true; - sldata->probes->sss_toggle = true; sldata->probes->grid_initialized = false; sldata->probe_ubo = DRW_uniformbuffer_create(sizeof(EEVEE_LightProbe) * MAX_PROBE, NULL); sldata->grid_ubo = DRW_uniformbuffer_create(sizeof(EEVEE_LightGrid) * MAX_GRID, NULL); sldata->planar_ubo = DRW_uniformbuffer_create(sizeof(EEVEE_PlanarReflection) * MAX_PLANAR, NULL); } + common_data->spec_toggle = true; + common_data->ssr_toggle = true; + common_data->sss_toggle = true; + int prop_bounce_num = BKE_collection_engine_property_value_get_int(props, "gi_diffuse_bounces"); if (sldata->probes->num_bounce != prop_bounce_num) { sldata->probes->num_bounce = prop_bounce_num; @@ -325,8 +322,8 @@ void EEVEE_lightprobes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *UNUSED(veda } int visibility_res = BKE_collection_engine_property_value_get_int(props, "gi_visibility_resolution"); - if (sldata->probes->irradiance_vis_size != visibility_res) { - sldata->probes->irradiance_vis_size = visibility_res; + if (common_data->prb_irradiance_vis_size != visibility_res) { + common_data->prb_irradiance_vis_size = visibility_res; update_all = true; } @@ -370,6 +367,7 @@ void EEVEE_lightprobes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedat EEVEE_StorageList *stl = vedata->stl; EEVEE_LightProbesInfo *pinfo = sldata->probes; + pinfo->do_cube_update = false; pinfo->num_cube = 1; /* at least one for the world */ pinfo->num_grid = 1; pinfo->num_planar = 0; @@ -391,7 +389,7 @@ void EEVEE_lightprobes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedat float *col = ts.colorBackground; if (wo) { col = &wo->horr; - if (wo->update_flag != 0) { + if (wo->update_flag != 0 || pinfo->prev_world != wo) { e_data.update_world |= PROBE_UPDATE_ALL; pinfo->updated_bounce = 0; pinfo->grid_initialized = false; @@ -413,6 +411,14 @@ void EEVEE_lightprobes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedat col = pink; } } + + pinfo->prev_world = wo; + } + else if (pinfo->prev_world) { + pinfo->prev_world = NULL; + e_data.update_world |= PROBE_UPDATE_ALL; + pinfo->updated_bounce = 0; + pinfo->grid_initialized = false; } /* Fallback if shader fails or if not using nodetree. */ @@ -430,14 +436,15 @@ void EEVEE_lightprobes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedat struct Gwn_Batch *geom = DRW_cache_fullscreen_quad_get(); DRWShadingGroup *grp = DRW_shgroup_instance_create(e_data.probe_filter_glossy_sh, psl->probe_glossy_compute, geom); - DRW_shgroup_uniform_float(grp, "sampleCount", &sldata->probes->samples_ct, 1); - DRW_shgroup_uniform_float(grp, "invSampleCount", &sldata->probes->invsamples_ct, 1); - DRW_shgroup_uniform_float(grp, "roughnessSquared", &sldata->probes->roughness, 1); - DRW_shgroup_uniform_float(grp, "lodFactor", &sldata->probes->lodfactor, 1); - DRW_shgroup_uniform_float(grp, "lodMax", &sldata->probes->lod_rt_max, 1); - DRW_shgroup_uniform_float(grp, "texelSize", &sldata->probes->texel_size, 1); - DRW_shgroup_uniform_float(grp, "paddingSize", &sldata->probes->padding_size, 1); - DRW_shgroup_uniform_int(grp, "Layer", &sldata->probes->layer, 1); + DRW_shgroup_uniform_float(grp, "intensityFac", &pinfo->intensity_fac, 1); + DRW_shgroup_uniform_float(grp, "sampleCount", &pinfo->samples_ct, 1); + DRW_shgroup_uniform_float(grp, "invSampleCount", &pinfo->invsamples_ct, 1); + DRW_shgroup_uniform_float(grp, "roughnessSquared", &pinfo->roughness, 1); + DRW_shgroup_uniform_float(grp, "lodFactor", &pinfo->lodfactor, 1); + DRW_shgroup_uniform_float(grp, "lodMax", &pinfo->lod_rt_max, 1); + DRW_shgroup_uniform_float(grp, "texelSize", &pinfo->texel_size, 1); + DRW_shgroup_uniform_float(grp, "paddingSize", &pinfo->padding_size, 1); + DRW_shgroup_uniform_int(grp, "Layer", &pinfo->layer, 1); DRW_shgroup_uniform_texture(grp, "texHammersley", e_data.hammersley); // DRW_shgroup_uniform_texture(grp, "texJitter", e_data.jitter); DRW_shgroup_uniform_texture(grp, "probeHdr", sldata->probe_rt); @@ -450,14 +457,15 @@ void EEVEE_lightprobes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedat DRWShadingGroup *grp = DRW_shgroup_create(e_data.probe_filter_diffuse_sh, psl->probe_diffuse_compute); #ifdef IRRADIANCE_SH_L2 - DRW_shgroup_uniform_int(grp, "probeSize", &sldata->probes->shres, 1); + DRW_shgroup_uniform_int(grp, "probeSize", &pinfo->shres, 1); #else - DRW_shgroup_uniform_float(grp, "sampleCount", &sldata->probes->samples_ct, 1); - DRW_shgroup_uniform_float(grp, "invSampleCount", &sldata->probes->invsamples_ct, 1); - DRW_shgroup_uniform_float(grp, "lodFactor", &sldata->probes->lodfactor, 1); - DRW_shgroup_uniform_float(grp, "lodMax", &sldata->probes->lod_rt_max, 1); + DRW_shgroup_uniform_float(grp, "sampleCount", &pinfo->samples_ct, 1); + DRW_shgroup_uniform_float(grp, "invSampleCount", &pinfo->invsamples_ct, 1); + DRW_shgroup_uniform_float(grp, "lodFactor", &pinfo->lodfactor, 1); + DRW_shgroup_uniform_float(grp, "lodMax", &pinfo->lod_rt_max, 1); DRW_shgroup_uniform_texture(grp, "texHammersley", e_data.hammersley); #endif + DRW_shgroup_uniform_float(grp, "intensityFac", &pinfo->intensity_fac, 1); DRW_shgroup_uniform_texture(grp, "probeHdr", sldata->probe_rt); struct Gwn_Batch *geom = DRW_cache_fullscreen_quad_get(); @@ -468,14 +476,14 @@ void EEVEE_lightprobes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedat psl->probe_visibility_compute = DRW_pass_create("LightProbe Visibility Compute", DRW_STATE_WRITE_COLOR); DRWShadingGroup *grp = DRW_shgroup_create(e_data.probe_filter_visibility_sh, psl->probe_visibility_compute); - DRW_shgroup_uniform_int(grp, "outputSize", &sldata->probes->shres, 1); - DRW_shgroup_uniform_float(grp, "visibilityRange", &sldata->probes->visibility_range, 1); - DRW_shgroup_uniform_float(grp, "visibilityBlur", &sldata->probes->visibility_blur, 1); - DRW_shgroup_uniform_float(grp, "sampleCount", &sldata->probes->samples_ct, 1); - DRW_shgroup_uniform_float(grp, "invSampleCount", &sldata->probes->invsamples_ct, 1); - DRW_shgroup_uniform_float(grp, "storedTexelSize", &sldata->probes->texel_size, 1); - DRW_shgroup_uniform_float(grp, "nearClip", &sldata->probes->near_clip, 1); - DRW_shgroup_uniform_float(grp, "farClip", &sldata->probes->far_clip, 1); + DRW_shgroup_uniform_int(grp, "outputSize", &pinfo->shres, 1); + DRW_shgroup_uniform_float(grp, "visibilityRange", &pinfo->visibility_range, 1); + DRW_shgroup_uniform_float(grp, "visibilityBlur", &pinfo->visibility_blur, 1); + DRW_shgroup_uniform_float(grp, "sampleCount", &pinfo->samples_ct, 1); + DRW_shgroup_uniform_float(grp, "invSampleCount", &pinfo->invsamples_ct, 1); + DRW_shgroup_uniform_float(grp, "storedTexelSize", &pinfo->texel_size, 1); + DRW_shgroup_uniform_float(grp, "nearClip", &pinfo->near_clip, 1); + DRW_shgroup_uniform_float(grp, "farClip", &pinfo->far_clip, 1); DRW_shgroup_uniform_texture(grp, "texHammersley", e_data.hammersley); DRW_shgroup_uniform_texture(grp, "probeDepth", sldata->probe_depth_rt); @@ -502,8 +510,8 @@ void EEVEE_lightprobes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedat DRW_shgroup_attrib_float(grp, "probe_id", 1); /* XXX this works because we are still uploading 4bytes and using the right stride */ DRW_shgroup_attrib_float(grp, "probe_location", 3); DRW_shgroup_attrib_float(grp, "sphere_size", 1); - DRW_shgroup_uniform_float(grp, "lodCubeMax", &sldata->probes->lod_cube_max, 1); DRW_shgroup_uniform_buffer(grp, "probeCubes", &sldata->probe_pool); + DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); geom = DRW_cache_quad_get(); grp = stl->g_data->planar_display_shgrp = DRW_shgroup_instance_create(e_data.probe_planar_display_sh, psl->probe_display, geom); @@ -518,7 +526,7 @@ void EEVEE_lightprobes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedat struct Gwn_Batch *geom = DRW_cache_fullscreen_quad_get(); DRWShadingGroup *grp = stl->g_data->planar_downsample = DRW_shgroup_instance_create(e_data.probe_planar_downsample_sh, psl->probe_planar_downsample_ps, geom); DRW_shgroup_uniform_buffer(grp, "source", &txl->planar_pool); - DRW_shgroup_uniform_float(grp, "fireflyFactor", &stl->effects->ssr_firefly_fac, 1); + DRW_shgroup_uniform_float(grp, "fireflyFactor", &sldata->common_data.ssr_firefly_fac, 1); } } @@ -551,7 +559,6 @@ void EEVEE_lightprobes_cache_add(EEVEE_ViewLayerData *sldata, Object *ob) ped->need_update = true; ped->probe_id = 0; - if (probe->type == LIGHTPROBE_TYPE_GRID) { ped->updated_cells = 0; ped->updated_lvl = 0; @@ -567,6 +574,8 @@ void EEVEE_lightprobes_cache_add(EEVEE_ViewLayerData *sldata, Object *ob) ped->probe_id = 0; } + pinfo->do_cube_update |= ped->need_update; + if (probe->type == LIGHTPROBE_TYPE_CUBE) { pinfo->probes_cube_ref[pinfo->num_cube] = ob; pinfo->num_cube++; @@ -685,8 +694,7 @@ static void EEVEE_planar_reflections_updates(EEVEE_ViewLayerData *sldata, EEVEE_ eplanar->attenuation_bias = max_dist * -eplanar->attenuation_scale; /* Debug Display */ - if (BKE_object_is_visible(ob) && - DRW_state_draw_support() && + if (DRW_state_draw_support() && (probe->flag & LIGHTPROBE_FLAG_SHOW_DATA)) { DRW_shgroup_call_dynamic_add(stl->g_data->planar_display_shgrp, &ped->probe_id, ob->obmat); @@ -734,8 +742,7 @@ static void EEVEE_lightprobes_updates(EEVEE_ViewLayerData *sldata, EEVEE_PassLis invert_m4(eprobe->parallaxmat); /* Debug Display */ - if (BKE_object_is_visible(ob) && - DRW_state_draw_support() && + if (DRW_state_draw_support() && (probe->flag & LIGHTPROBE_FLAG_SHOW_DATA)) { ped->probe_size = probe->data_draw_size * 0.1f; @@ -816,8 +823,7 @@ static void EEVEE_lightprobes_updates(EEVEE_ViewLayerData *sldata, EEVEE_PassLis len_v3(egrid->increment_z)) + 1.0f; /* Debug Display */ - if (BKE_object_is_visible(ob) && - DRW_state_draw_support() && + if (DRW_state_draw_support() && (probe->flag & LIGHTPROBE_FLAG_SHOW_DATA)) { struct Gwn_Batch *geom = DRW_cache_sphere_get(); @@ -837,6 +843,7 @@ static void EEVEE_lightprobes_updates(EEVEE_ViewLayerData *sldata, EEVEE_PassLis void EEVEE_lightprobes_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) { + EEVEE_CommonUniformBuffer *common_data = &sldata->common_data; EEVEE_StorageList *stl = vedata->stl; EEVEE_LightProbesInfo *pinfo = sldata->probes; Object *ob; @@ -854,7 +861,7 @@ void EEVEE_lightprobes_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *ved } int irr_size[3]; - irradiance_pool_size_get(pinfo->irradiance_vis_size, pinfo->total_irradiance_samples, irr_size); + irradiance_pool_size_get(common_data->prb_irradiance_vis_size, pinfo->total_irradiance_samples, irr_size); if ((irr_size[0] != pinfo->cache_irradiance_size[0]) || (irr_size[1] != pinfo->cache_irradiance_size[1]) || @@ -880,8 +887,7 @@ void EEVEE_lightprobes_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *ved /* Tag probes to refresh */ e_data.update_world |= PROBE_UPDATE_CUBE; - e_data.world_ready_to_shade = false; - pinfo->num_render_cube = 0; + common_data->prb_num_render_cube = 0; pinfo->cache_num_cube = pinfo->num_cube; for (int i = 1; (ob = pinfo->probes_cube_ref[i]) && (i < MAX_PROBE); i++) { @@ -913,7 +919,7 @@ void EEVEE_lightprobes_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *ved sldata->irradiance_rt = DRW_texture_create_2D_array(irr_size[0], irr_size[1], irr_size[2], irradiance_format, DRW_TEX_FILTER, NULL); } - pinfo->num_render_grid = 0; + common_data->prb_num_render_grid = 0; pinfo->updated_bounce = 0; pinfo->grid_initialized = false; e_data.update_world |= PROBE_UPDATE_GRID; @@ -925,9 +931,9 @@ void EEVEE_lightprobes_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *ved } } - if (pinfo->num_render_grid > pinfo->num_grid) { + if (common_data->prb_num_render_grid > pinfo->num_grid) { /* This can happen when deleting a probe. */ - pinfo->num_render_grid = pinfo->num_grid; + common_data->prb_num_render_grid = pinfo->num_grid; } EEVEE_lightprobes_updates(sldata, vedata->psl, vedata->stl); @@ -944,23 +950,26 @@ static void downsample_planar(void *vedata, int level) EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl; const float *size = DRW_viewport_size_get(); - copy_v2_v2(stl->g_data->texel_size, size); + copy_v2_v2(stl->g_data->planar_texel_size, size); for (int i = 0; i < level - 1; ++i) { - stl->g_data->texel_size[0] /= 2.0f; - stl->g_data->texel_size[1] /= 2.0f; - min_ff(floorf(stl->g_data->texel_size[0]), 1.0f); - min_ff(floorf(stl->g_data->texel_size[1]), 1.0f); + stl->g_data->planar_texel_size[0] /= 2.0f; + stl->g_data->planar_texel_size[1] /= 2.0f; + min_ff(floorf(stl->g_data->planar_texel_size[0]), 1.0f); + min_ff(floorf(stl->g_data->planar_texel_size[1]), 1.0f); } - invert_v2(stl->g_data->texel_size); + invert_v2(stl->g_data->planar_texel_size); DRW_draw_pass(psl->probe_planar_downsample_ps); } /* Glossy filter probe_rt to probe_pool at index probe_idx */ -static void glossy_filter_probe(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, EEVEE_PassList *psl, int probe_idx) +static void glossy_filter_probe( + EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, EEVEE_PassList *psl, int probe_idx, float intensity) { EEVEE_LightProbesInfo *pinfo = sldata->probes; + pinfo->intensity_fac = intensity; + /* Max lod used from the render target probe */ pinfo->lod_rt_max = floorf(log2f(pinfo->target_size)) - 2.0f; @@ -1023,7 +1032,7 @@ static void glossy_filter_probe(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, CLAMP_MIN(mipsize, 1); } /* For shading, save max level of the octahedron map */ - pinfo->lod_cube_max = (float)(maxlevel - min_lod_level) - 1.0f; + sldata->common_data.prb_lod_cube_max = (float)(maxlevel - min_lod_level) - 1.0f; /* reattach to have a valid framebuffer. */ DRW_framebuffer_texture_attach(sldata->probe_filter_fb, sldata->probe_pool, 0, 0); @@ -1032,12 +1041,15 @@ static void glossy_filter_probe(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, /* Diffuse filter probe_rt to irradiance_pool at index probe_idx */ static void diffuse_filter_probe( EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, EEVEE_PassList *psl, int offset, - float clipsta, float clipend, float vis_range, float vis_blur) + float clipsta, float clipend, float vis_range, float vis_blur, float intensity) { + EEVEE_CommonUniformBuffer *common_data = &sldata->common_data; EEVEE_LightProbesInfo *pinfo = sldata->probes; + pinfo->intensity_fac = intensity; + int pool_size[3]; - irradiance_pool_size_get(pinfo->irradiance_vis_size, pinfo->total_irradiance_samples, pool_size); + irradiance_pool_size_get(common_data->prb_irradiance_vis_size, pinfo->total_irradiance_samples, pool_size); /* find cell position on the virtual 3D texture */ /* NOTE : Keep in sync with load_irradiance_cell() */ @@ -1081,23 +1093,24 @@ static void diffuse_filter_probe( /* Compute visibility */ pinfo->samples_ct = 512.0f; /* TODO refine */ pinfo->invsamples_ct = 1.0f / pinfo->samples_ct; - pinfo->shres = pinfo->irradiance_vis_size; + pinfo->shres = common_data->prb_irradiance_vis_size; pinfo->visibility_range = vis_range; pinfo->visibility_blur = vis_blur; pinfo->near_clip = -clipsta; pinfo->far_clip = -clipend; - pinfo->texel_size = 1.0f / (float)pinfo->irradiance_vis_size; + pinfo->texel_size = 1.0f / (float)common_data->prb_irradiance_vis_size; - int cell_per_col = pool_size[1] / pinfo->irradiance_vis_size; - cell_per_row = pool_size[0] / pinfo->irradiance_vis_size; - x = pinfo->irradiance_vis_size * (offset % cell_per_row); - y = pinfo->irradiance_vis_size * ((offset / cell_per_row) % cell_per_col); + int cell_per_col = pool_size[1] / common_data->prb_irradiance_vis_size; + cell_per_row = pool_size[0] / common_data->prb_irradiance_vis_size; + x = common_data->prb_irradiance_vis_size * (offset % cell_per_row); + y = common_data->prb_irradiance_vis_size * ((offset / cell_per_row) % cell_per_col); int layer = 1 + ((offset / cell_per_row) / cell_per_col); DRW_framebuffer_texture_detach(sldata->irradiance_rt); DRW_framebuffer_texture_layer_attach(sldata->probe_filter_fb, sldata->irradiance_rt, 0, layer, 0); - DRW_framebuffer_viewport_size(sldata->probe_filter_fb, x, y, pinfo->irradiance_vis_size, sldata->probes->irradiance_vis_size); + DRW_framebuffer_viewport_size(sldata->probe_filter_fb, x, y, common_data->prb_irradiance_vis_size, + common_data->prb_irradiance_vis_size); DRW_draw_pass(psl->probe_visibility_compute); } @@ -1116,24 +1129,13 @@ static void render_scene_to_probe( EEVEE_StorageList *stl = vedata->stl; EEVEE_LightProbesInfo *pinfo = sldata->probes; - float winmat[4][4], wininv[4][4], posmat[4][4], tmp_ao_dist, tmp_ao_samples, tmp_ao_settings; + float winmat[4][4], wininv[4][4], posmat[4][4]; unit_m4(posmat); /* Move to capture position */ negate_v3_v3(posmat[3], pos); - /* Disable specular lighting when rendering probes to avoid feedback loops (looks bad). */ - sldata->probes->specular_toggle = false; - sldata->probes->ssr_toggle = false; - sldata->probes->sss_toggle = false; - - /* Disable AO until we find a way to hide really bad discontinuities between cubefaces. */ - tmp_ao_dist = stl->effects->ao_dist; - tmp_ao_samples = stl->effects->ao_samples; - tmp_ao_settings = stl->effects->ao_settings; - stl->effects->ao_settings = 0.0f; /* Disable AO */ - /* 1 - Render to each cubeface individually. * We do this instead of using geometry shader because a) it's faster, * b) it's easier than fixing the nodetree shaders (for view dependant effects). */ @@ -1149,6 +1151,9 @@ static void render_scene_to_probe( stl->g_data->minzbuffer = e_data.depth_placeholder; txl->maxzbuffer = e_data.depth_placeholder; + /* Update common uniforms */ + DRW_uniformbuffer_update(sldata->common_ubo, &sldata->common_data); + /* Detach to rebind the right cubeface. */ DRW_framebuffer_bind(sldata->probe_fb); DRW_framebuffer_texture_detach(sldata->probe_rt); @@ -1210,15 +1215,9 @@ static void render_scene_to_probe( DRW_viewport_matrix_override_unset(DRW_MAT_WININV); /* Restore */ - pinfo->specular_toggle = true; - pinfo->ssr_toggle = true; - pinfo->sss_toggle = true; txl->planar_pool = tmp_planar_pool; stl->g_data->minzbuffer = tmp_minz; txl->maxzbuffer = tmp_maxz; - stl->effects->ao_dist = tmp_ao_dist; - stl->effects->ao_samples = tmp_ao_samples; - stl->effects->ao_settings = tmp_ao_settings; } static void render_scene_to_planar( @@ -1257,11 +1256,6 @@ static void render_scene_to_planar( DRW_framebuffer_clear(false, true, false, NULL, 1.0); - /* Turn off ssr to avoid black specular */ - /* TODO : Enable SSR in planar reflections? (Would be very heavy) */ - sldata->probes->ssr_toggle = false; - sldata->probes->sss_toggle = false; - /* Avoid using the texture attached to framebuffer when rendering. */ /* XXX */ GPUTexture *tmp_planar_pool = txl->planar_pool; @@ -1279,7 +1273,7 @@ static void render_scene_to_planar( EEVEE_create_minmax_buffer(vedata, tmp_planar_depth, layer); /* Compute GTAO Horizons */ - EEVEE_occlusion_compute(sldata, vedata); + EEVEE_occlusion_compute(sldata, vedata, tmp_planar_depth, layer); /* Rebind Planar FB */ DRW_framebuffer_bind(fbl->planarref_fb); @@ -1293,8 +1287,6 @@ static void render_scene_to_planar( DRW_state_clip_planes_reset(); /* Restore */ - sldata->probes->ssr_toggle = true; - sldata->probes->sss_toggle = true; txl->planar_pool = tmp_planar_pool; txl->planar_depth = tmp_planar_depth; DRW_viewport_matrix_override_unset(DRW_MAT_PERS); @@ -1380,27 +1372,25 @@ static void lightprobe_cell_world_location_get(EEVEE_LightGrid *egrid, float loc static void lightprobes_refresh_world(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) { + EEVEE_CommonUniformBuffer *common_data = &sldata->common_data; EEVEE_PassList *psl = vedata->psl; - EEVEE_LightProbesInfo *pinfo = sldata->probes; + render_world_to_probe(sldata, psl); if (e_data.update_world & PROBE_UPDATE_CUBE) { - glossy_filter_probe(sldata, vedata, psl, 0); + glossy_filter_probe(sldata, vedata, psl, 0, 1.0); + common_data->prb_num_render_cube = 1; } if (e_data.update_world & PROBE_UPDATE_GRID) { - diffuse_filter_probe(sldata, vedata, psl, 0, 0.0, 0.0, 0.0, 0.0); + diffuse_filter_probe(sldata, vedata, psl, 0, 0.0, 0.0, 0.0, 0.0, 1.0); SWAP(GPUTexture *, sldata->irradiance_pool, sldata->irradiance_rt); DRW_framebuffer_texture_detach(sldata->probe_pool); DRW_framebuffer_texture_attach(sldata->probe_filter_fb, sldata->irradiance_rt, 0, 0); DRW_draw_pass(psl->probe_grid_fill); DRW_framebuffer_texture_detach(sldata->irradiance_rt); DRW_framebuffer_texture_attach(sldata->probe_filter_fb, sldata->probe_pool, 0, 0); + common_data->prb_num_render_grid = 1; } e_data.update_world = 0; - if (!e_data.world_ready_to_shade) { - e_data.world_ready_to_shade = true; - pinfo->num_render_cube = 1; - pinfo->num_render_grid = 1; - } DRW_viewport_request_redraw(); } @@ -1432,36 +1422,53 @@ static void lightprobes_refresh_initialize_grid(EEVEE_ViewLayerData *sldata, EEV static void lightprobes_refresh_planar(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) { + EEVEE_CommonUniformBuffer *common_data = &sldata->common_data; EEVEE_TextureList *txl = vedata->txl; Object *ob; EEVEE_LightProbesInfo *pinfo = sldata->probes; + + if (pinfo->num_planar == 0) { + return; + } + + /* Temporary Remove all planar reflections (avoid lag effect). */ + common_data->prb_num_planar = 0; + /* Turn off ssr to avoid black specular */ + /* TODO : Enable SSR in planar reflections? (Would be very heavy) */ + common_data->ssr_toggle = false; + common_data->sss_toggle = false; + + DRW_uniformbuffer_update(sldata->common_ubo, &sldata->common_data); + for (int i = 0; (ob = pinfo->probes_planar_ref[i]) && (i < MAX_PLANAR); i++) { EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_ensure(ob); if (!ped->need_update) { continue; } - /* Temporary Remove all planar reflections (avoid lag effect). */ - int tmp_num_planar = pinfo->num_planar; - pinfo->num_planar = 0; render_scene_to_planar(sldata, vedata, i, ped->viewmat, ped->persmat, ped->planer_eq_offset); - /* Restore */ - pinfo->num_planar = tmp_num_planar; ped->need_update = false; ped->probe_id = i; } + + /* Restore */ + common_data->prb_num_planar = pinfo->num_planar; + common_data->ssr_toggle = true; + common_data->sss_toggle = true; + /* If there is at least one planar probe */ if (pinfo->num_planar > 0 && (vedata->stl->effects->enabled_effects & EFFECT_SSR) != 0) { const int max_lod = 9; DRW_stats_group_start("Planar Probe Downsample"); DRW_framebuffer_recursive_downsample(vedata->fbl->downsample_fb, txl->planar_pool, max_lod, &downsample_planar, vedata); /* For shading, save max level of the planar map */ - pinfo->lod_planar_max = (float)(max_lod); + common_data->prb_lod_planar_max = (float)(max_lod); DRW_stats_group_end(); } } static void lightprobes_refresh_cube(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) { + EEVEE_CommonUniformBuffer *common_data = &sldata->common_data; EEVEE_PassList *psl = vedata->psl; EEVEE_StorageList *stl = vedata->stl; EEVEE_LightProbesInfo *pinfo = sldata->probes; @@ -1473,11 +1480,11 @@ static void lightprobes_refresh_cube(EEVEE_ViewLayerData *sldata, EEVEE_Data *ve } LightProbe *prb = (LightProbe *)ob->data; render_scene_to_probe(sldata, vedata, ob->obmat[3], prb->clipsta, prb->clipend); - glossy_filter_probe(sldata, vedata, psl, i); + glossy_filter_probe(sldata, vedata, psl, i, prb->intensity); ped->need_update = false; ped->probe_id = i; if (!ped->ready_to_shade) { - pinfo->num_render_cube++; + common_data->prb_num_render_cube++; ped->ready_to_shade = true; } #if 0 @@ -1488,13 +1495,13 @@ static void lightprobes_refresh_cube(EEVEE_ViewLayerData *sldata, EEVEE_Data *ve stl->effects->taa_current_sample = 1; /* Only do one probe per frame */ - lightprobes_refresh_planar(sldata, vedata); return; } } static void lightprobes_refresh_all_no_world(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) { + EEVEE_CommonUniformBuffer *common_data = &sldata->common_data; EEVEE_PassList *psl = vedata->psl; EEVEE_StorageList *stl = vedata->stl; EEVEE_LightProbesInfo *pinfo = sldata->probes; @@ -1506,7 +1513,6 @@ static void lightprobes_refresh_all_no_world(EEVEE_ViewLayerData *sldata, EEVEE_ /* Only compute probes if not navigating or in playback */ struct wmWindowManager *wm = CTX_wm_manager(draw_ctx->evil_C); if (((rv3d->rflag & RV3D_NAVIGATING) != 0) || ED_screen_animation_no_scrub(wm) != NULL) { - lightprobes_refresh_planar(sldata, vedata); return; } } @@ -1515,7 +1521,7 @@ static void lightprobes_refresh_all_no_world(EEVEE_ViewLayerData *sldata, EEVEE_ /* Reflection probes depend on diffuse lighting thus on irradiance grid, * so update them first. */ while (pinfo->updated_bounce < pinfo->num_bounce) { - pinfo->num_render_grid = pinfo->num_grid; + common_data->prb_num_render_grid = pinfo->num_grid; /* TODO(sergey): This logic can be split into smaller functions. */ for (int i = 1; (ob = pinfo->probes_grid_ref[i]) && (i < MAX_GRID); i++) { EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_ensure(ob); @@ -1559,16 +1565,16 @@ static void lightprobes_refresh_all_no_world(EEVEE_ViewLayerData *sldata, EEVEE_ lightprobe_cell_world_location_get(egrid, grid_loc, pos); SWAP(GPUTexture *, sldata->irradiance_pool, sldata->irradiance_rt); /* Temporary Remove all probes. */ - int tmp_num_render_grid = pinfo->num_render_grid; - int tmp_num_render_cube = pinfo->num_render_cube; - int tmp_num_planar = pinfo->num_planar; + int tmp_num_render_grid = common_data->prb_num_render_grid; + int tmp_num_render_cube = common_data->prb_num_render_cube; + int tmp_num_planar = common_data->prb_num_planar; float tmp_level_bias = egrid->level_bias; - pinfo->num_render_cube = 0; - pinfo->num_planar = 0; + common_data->prb_num_render_cube = 0; + common_data->prb_num_planar = 0; /* Use light from previous bounce when capturing radiance. */ if (pinfo->updated_bounce == 0) { /* But not on first bounce. */ - pinfo->num_render_grid = 0; + common_data->prb_num_render_grid = 0; } else { /* Remove bias */ @@ -1577,14 +1583,15 @@ static void lightprobes_refresh_all_no_world(EEVEE_ViewLayerData *sldata, EEVEE_ } render_scene_to_probe(sldata, vedata, pos, prb->clipsta, prb->clipend); diffuse_filter_probe(sldata, vedata, psl, egrid->offset + cell_id, - prb->clipsta, prb->clipend, egrid->visibility_range, prb->vis_blur); + prb->clipsta, prb->clipend, egrid->visibility_range, prb->vis_blur, + prb->intensity); /* To see what is going on. */ SWAP(GPUTexture *, sldata->irradiance_pool, sldata->irradiance_rt); /* Restore */ - pinfo->num_render_cube = tmp_num_render_cube; + common_data->prb_num_render_cube = tmp_num_render_cube; pinfo->num_planar = tmp_num_planar; if (pinfo->updated_bounce == 0) { - pinfo->num_render_grid = tmp_num_render_grid; + common_data->prb_num_render_grid = tmp_num_render_grid; } else { egrid->level_bias = tmp_level_bias; @@ -1608,12 +1615,11 @@ static void lightprobes_refresh_all_no_world(EEVEE_ViewLayerData *sldata, EEVEE_ DRW_viewport_request_redraw(); /* Do not let this frame accumulate. */ stl->effects->taa_current_sample = 1; - lightprobes_refresh_planar(sldata, vedata); return; } pinfo->updated_bounce++; - pinfo->num_render_grid = pinfo->num_grid; + common_data->prb_num_render_grid = pinfo->num_grid; if (pinfo->updated_bounce < pinfo->num_bounce) { /* Retag all grids to update for next bounce */ @@ -1641,13 +1647,39 @@ static void lightprobes_refresh_all_no_world(EEVEE_ViewLayerData *sldata, EEVEE_ void EEVEE_lightprobes_refresh(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) { + EEVEE_LightProbesInfo *pinfo = sldata->probes; + EEVEE_CommonUniformBuffer *common_data = &sldata->common_data; + + /* Disable specular lighting when rendering probes to avoid feedback loops (looks bad). */ + common_data->spec_toggle = false; + common_data->ssr_toggle = false; + common_data->sss_toggle = false; + + /* Disable AO until we find a way to hide really bad discontinuities between cubefaces. */ + float tmp_ao_dist = common_data->ao_dist; + float tmp_ao_settings = common_data->ao_settings; + common_data->ao_settings = 0.0f; + common_data->ao_dist = 0.0f; + /* Render world in priority */ if (e_data.update_world) { lightprobes_refresh_world(sldata, vedata); } - else if (true) { /* TODO if at least one probe needs refresh */ + else if (pinfo->do_cube_update || (pinfo->updated_bounce < pinfo->num_bounce)) { lightprobes_refresh_all_no_world(sldata, vedata); } + + /* Restore */ + common_data->spec_toggle = true; + common_data->ssr_toggle = true; + common_data->sss_toggle = true; + common_data->ao_dist = tmp_ao_dist; + common_data->ao_settings = tmp_ao_settings; + + lightprobes_refresh_planar(sldata, vedata); + + /* Disable SSR if we cannot read previous frame */ + common_data->ssr_toggle = vedata->stl->g_data->valid_double_buffer; } void EEVEE_lightprobes_free(void) diff --git a/source/blender/draw/engines/eevee/eevee_lights.c b/source/blender/draw/engines/eevee/eevee_lights.c index 22465c04cfa..69b58bf9670 100644 --- a/source/blender/draw/engines/eevee/eevee_lights.c +++ b/source/blender/draw/engines/eevee/eevee_lights.c @@ -32,28 +32,7 @@ #include "eevee_engine.h" #include "eevee_private.h" -/* Theses are the structs stored inside Objects. - * It works with even if the object is in multiple layers - * because we don't get the same "Object *" for each layer. */ -typedef struct EEVEE_LightData { - short light_id, shadow_id; -} EEVEE_LightData; - -typedef struct EEVEE_ShadowCubeData { - short light_id, shadow_id, cube_id, layer_id; -} EEVEE_ShadowCubeData; - -typedef struct EEVEE_ShadowCascadeData { - short light_id, shadow_id, cascade_id, layer_id; - float viewprojmat[MAX_CASCADE_NUM][4][4]; /* World->Lamp->NDC : used for rendering the shadow map. */ - float radius[MAX_CASCADE_NUM]; -} EEVEE_ShadowCascadeData; - -typedef struct ShadowCaster { - struct ShadowCaster *next, *prev; - void *ob; - bool prune; -} ShadowCaster; +#define SHADOW_CASTER_ALLOC_CHUNK 16 static struct { struct GPUShader *shadow_sh; @@ -70,6 +49,48 @@ extern char datatoc_shadow_store_frag_glsl[]; extern char datatoc_shadow_copy_frag_glsl[]; extern char datatoc_concentric_samples_lib_glsl[]; +/* Prototype */ +static void eevee_light_setup(Object *ob, EEVEE_Light *evli); + +/* *********** LIGHT BITS *********** */ +static void lightbits_set_single(EEVEE_LightBits *bitf, unsigned int idx, bool val) +{ + if (val) { + bitf->fields[idx / 8] |= (1 << (idx % 8)); + } + else { + bitf->fields[idx / 8] &= ~(1 << (idx % 8)); + } +} + +static void lightbits_set_all(EEVEE_LightBits *bitf, bool val) +{ + memset(bitf, (val) ? 0xFF : 0x00, sizeof(EEVEE_LightBits)); +} + +static void lightbits_or(EEVEE_LightBits *r, const EEVEE_LightBits *v) +{ + for (int i = 0; i < MAX_LIGHTBITS_FIELDS; ++i) { + r->fields[i] |= v->fields[i]; + } +} + +static bool lightbits_get(const EEVEE_LightBits *r, unsigned int idx) +{ + return r->fields[idx / 8] & (1 << (idx % 8)); +} + +static void lightbits_convert(EEVEE_LightBits *r, const EEVEE_LightBits *bitf, const int *light_bit_conv_table, unsigned int table_length) +{ + for (int i = 0; i < table_length; ++i) { + if (lightbits_get(bitf, i) != 0) { + if (light_bit_conv_table[i] >= 0) { + r->fields[i / 8] |= (1 << (i % 8)); + } + } + } +} + /* *********** FUNCTIONS *********** */ void EEVEE_lights_init(EEVEE_ViewLayerData *sldata) @@ -96,7 +117,8 @@ void EEVEE_lights_init(EEVEE_ViewLayerData *sldata) store_shadow_shader_str, "#define ESM\n"); e_data.shadow_store_cascade_sh[SHADOW_ESM] = DRW_shader_create_fullscreen( - store_shadow_shader_str, "#define ESM\n" + store_shadow_shader_str, + "#define ESM\n" "#define CSM\n"); e_data.shadow_store_cube_sh[SHADOW_VSM] = DRW_shader_create_fullscreen( @@ -114,7 +136,8 @@ void EEVEE_lights_init(EEVEE_ViewLayerData *sldata) "#define ESM\n" "#define COPY\n"); e_data.shadow_copy_cascade_sh[SHADOW_ESM] = DRW_shader_create_fullscreen( - datatoc_shadow_copy_frag_glsl, "#define ESM\n" + datatoc_shadow_copy_frag_glsl, + "#define ESM\n" "#define COPY\n" "#define CSM\n"); @@ -134,8 +157,21 @@ void EEVEE_lights_init(EEVEE_ViewLayerData *sldata) sldata->light_ubo = DRW_uniformbuffer_create(sizeof(EEVEE_Light) * MAX_LIGHT, NULL); sldata->shadow_ubo = DRW_uniformbuffer_create(shadow_ubo_size, NULL); sldata->shadow_render_ubo = DRW_uniformbuffer_create(sizeof(EEVEE_ShadowRender), NULL); + + for (int i = 0; i < 2; ++i) { + sldata->shcasters_buffers[i].shadow_casters = MEM_callocN(sizeof(EEVEE_ShadowCaster) * SHADOW_CASTER_ALLOC_CHUNK, "EEVEE_ShadowCaster buf"); + sldata->shcasters_buffers[i].flags = MEM_callocN(sizeof(sldata->shcasters_buffers[0].flags) * SHADOW_CASTER_ALLOC_CHUNK, "EEVEE_shcast_buffer flags buf"); + sldata->shcasters_buffers[i].alloc_count = SHADOW_CASTER_ALLOC_CHUNK; + sldata->shcasters_buffers[i].count = 0; + } + + sldata->lamps->shcaster_frontbuffer = &sldata->shcasters_buffers[0]; + sldata->lamps->shcaster_backbuffer = &sldata->shcasters_buffers[1]; } + /* Flip buffers */ + SWAP(EEVEE_ShadowCasterBuffer *, sldata->lamps->shcaster_frontbuffer, sldata->lamps->shcaster_backbuffer); + int sh_method = BKE_collection_engine_property_value_get_int(props, "shadow_method"); int sh_size = BKE_collection_engine_property_value_get_int(props, "shadow_size"); int sh_high_bitdepth = BKE_collection_engine_property_value_get_int(props, "shadow_high_bitdepth"); @@ -173,6 +209,7 @@ void EEVEE_lights_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_PassList *psl) { EEVEE_LampsInfo *linfo = sldata->lamps; + linfo->shcaster_frontbuffer->count = 0; linfo->num_light = 0; linfo->num_layer = 0; linfo->gpu_cube_ct = linfo->gpu_cascade_ct = linfo->gpu_shadow_ct = 0; @@ -180,6 +217,11 @@ void EEVEE_lights_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_PassList *psl) memset(linfo->light_ref, 0, sizeof(linfo->light_ref)); memset(linfo->shadow_cube_ref, 0, sizeof(linfo->shadow_cube_ref)); memset(linfo->shadow_cascade_ref, 0, sizeof(linfo->shadow_cascade_ref)); + memset(linfo->new_shadow_id, -1, sizeof(linfo->new_shadow_id)); + + /* Shadow Casters: Reset flags. */ + memset(linfo->shcaster_backbuffer->flags, (char)SHADOW_CASTER_PRUNED, linfo->shcaster_backbuffer->alloc_count); + memset(linfo->shcaster_frontbuffer->flags, 0x00, linfo->shcaster_frontbuffer->alloc_count); { psl->shadow_cube_store_pass = DRW_pass_create("Shadow Storage Pass", DRW_STATE_WRITE_COLOR); @@ -239,9 +281,6 @@ void EEVEE_lights_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_PassList *psl) "Shadow Cascade Pass", DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS); } - - /* Reset shadow casters list */ - BLI_freelistN(&sldata->shadow_casters); } void EEVEE_lights_cache_add(EEVEE_ViewLayerData *sldata, Object *ob) @@ -250,14 +289,27 @@ void EEVEE_lights_cache_add(EEVEE_ViewLayerData *sldata, Object *ob) /* Step 1 find all lamps in the scene and setup them */ if (linfo->num_light >= MAX_LIGHT) { - printf("Too much lamps in the scene !!!\n"); - linfo->num_light = MAX_LIGHT - 1; + printf("Too many lamps in the scene !!!\n"); } else { Lamp *la = (Lamp *)ob->data; + EEVEE_Light *evli = linfo->light_data + linfo->num_light; + eevee_light_setup(ob, evli); + + /* We do not support shadowmaps for dupli lamps. */ + if ((ob->base_flag & BASE_FROMDUPLI) != 0) { + linfo->num_light++; + return; + } + EEVEE_LampEngineData *led = EEVEE_lamp_data_ensure(ob); - MEM_SAFE_FREE(led->storage); + /* Save previous shadow id. */ + int prev_cube_sh_id = led->prev_cube_shadow_id; + + /* Default light without shadows */ + led->data.ld.shadow_id = -1; + led->prev_cube_shadow_id = -1; if (la->mode & (LA_SHAD_BUF | LA_SHAD_RAY)) { if (la->type == LA_SUN) { @@ -268,13 +320,11 @@ void EEVEE_lights_cache_add(EEVEE_ViewLayerData *sldata, Object *ob) /* Save Light object. */ linfo->shadow_cascade_ref[linfo->cpu_cascade_ct] = ob; - /* Create storage and store indices. */ - EEVEE_ShadowCascadeData *data = MEM_mallocN( - sizeof(EEVEE_ShadowCascadeData), "EEVEE_ShadowCascadeData"); + /* Store indices. */ + EEVEE_ShadowCascadeData *data = &led->data.scad; data->shadow_id = linfo->gpu_shadow_ct; data->cascade_id = linfo->gpu_cascade_ct; data->layer_id = linfo->num_layer; - led->storage = data; /* Increment indices. */ linfo->gpu_shadow_ct += 1; @@ -291,13 +341,24 @@ void EEVEE_lights_cache_add(EEVEE_ViewLayerData *sldata, Object *ob) /* Save Light object. */ linfo->shadow_cube_ref[linfo->cpu_cube_ct] = ob; - /* Create storage and store indices. */ - EEVEE_ShadowCubeData *data = MEM_mallocN( - sizeof(EEVEE_ShadowCubeData), "EEVEE_ShadowCubeData"); + /* For light update tracking. */ + if ((prev_cube_sh_id >= 0) && + (prev_cube_sh_id < linfo->shcaster_backbuffer->count)) + { + linfo->new_shadow_id[prev_cube_sh_id] = linfo->cpu_cube_ct; + } + led->prev_cube_shadow_id = linfo->cpu_cube_ct; + + /* Saving lamp bounds for later. */ + BLI_assert(linfo->cpu_cube_ct >= 0 && linfo->cpu_cube_ct < MAX_LIGHT); + copy_v3_v3(linfo->shadow_bounds[linfo->cpu_cube_ct].center, ob->obmat[3]); + linfo->shadow_bounds[linfo->cpu_cube_ct].radius = la->clipend; + + EEVEE_ShadowCubeData *data = &led->data.scd; + /* Store indices. */ data->shadow_id = linfo->gpu_shadow_ct; data->cube_id = linfo->gpu_cube_ct; data->layer_id = linfo->num_layer; - led->storage = data; /* Increment indices. */ linfo->gpu_shadow_ct += 1; @@ -309,13 +370,7 @@ void EEVEE_lights_cache_add(EEVEE_ViewLayerData *sldata, Object *ob) } } - /* Default light without shadows */ - if (!led->storage) { - led->storage = MEM_mallocN(sizeof(EEVEE_LightData), "EEVEE_LightData"); - ((EEVEE_LightData *)led->storage)->shadow_id = -1; - } - - ((EEVEE_LightData *)led->storage)->light_id = linfo->num_light; + led->data.ld.light_id = linfo->num_light; linfo->light_ref[linfo->num_light] = ob; linfo->num_light++; } @@ -362,11 +417,75 @@ void EEVEE_lights_cache_shcaster_material_add( DRW_shgroup_set_instance_count(grp, MAX_CASCADE_NUM); } +/* Make that object update shadow casting lamps inside its influence bounding box. */ +void EEVEE_lights_cache_shcaster_object_add(EEVEE_ViewLayerData *sldata, Object *ob) +{ + if ((ob->base_flag & BASE_FROMDUPLI) != 0) { + /* TODO: Special case for dupli objects because we cannot save the object pointer. */ + return; + } + + EEVEE_ObjectEngineData *oedata = EEVEE_object_data_ensure(ob); + EEVEE_LampsInfo *linfo = sldata->lamps; + EEVEE_ShadowCasterBuffer *backbuffer = linfo->shcaster_backbuffer; + EEVEE_ShadowCasterBuffer *frontbuffer = linfo->shcaster_frontbuffer; + int past_id = oedata->shadow_caster_id; + + /* Update flags in backbuffer. */ + if (past_id > -1 && past_id < backbuffer->count) { + backbuffer->flags[past_id] &= ~SHADOW_CASTER_PRUNED; + + if (oedata->need_update) { + backbuffer->flags[past_id] |= SHADOW_CASTER_UPDATED; + } + } + + /* Update id. */ + oedata->shadow_caster_id = frontbuffer->count++; + + /* Make sure shadow_casters is big enough. */ + if (oedata->shadow_caster_id >= frontbuffer->alloc_count) { + frontbuffer->alloc_count += SHADOW_CASTER_ALLOC_CHUNK; + frontbuffer->shadow_casters = MEM_reallocN(frontbuffer->shadow_casters, sizeof(EEVEE_ShadowCaster) * frontbuffer->alloc_count); + frontbuffer->flags = MEM_reallocN(frontbuffer->flags, sizeof(EEVEE_ShadowCaster) * frontbuffer->alloc_count); + } + + EEVEE_ShadowCaster *shcaster = frontbuffer->shadow_casters + oedata->shadow_caster_id; + + if (oedata->need_update) { + frontbuffer->flags[oedata->shadow_caster_id] = SHADOW_CASTER_UPDATED; + } + + /* Update World AABB in frontbuffer. */ + BoundBox *bb = BKE_object_boundbox_get(ob); + float min[3], max[3]; + INIT_MINMAX(min, max); + for (int i = 0; i < 8; ++i) { + float vec[3]; + copy_v3_v3(vec, bb->vec[i]); + mul_m4_v3(ob->obmat, vec); + minmax_v3v3_v3(min, max, vec); + } + + EEVEE_BoundBox *aabb = &shcaster->bbox; + add_v3_v3v3(aabb->center, min, max); + mul_v3_fl(aabb->center, 0.5f); + sub_v3_v3v3(aabb->halfdim, aabb->center, max); + + aabb->halfdim[0] = fabsf(aabb->halfdim[0]); + aabb->halfdim[1] = fabsf(aabb->halfdim[1]); + aabb->halfdim[2] = fabsf(aabb->halfdim[2]); + + oedata->need_update = false; +} + void EEVEE_lights_cache_finish(EEVEE_ViewLayerData *sldata) { EEVEE_LampsInfo *linfo = sldata->lamps; DRWTextureFormat shadow_pool_format = DRW_TEX_R_32; + sldata->common_data.la_num_light = linfo->num_light; + /* Setup enough layers. */ /* Free textures if number mismatch. */ if (linfo->num_layer != linfo->cache_num_layer) { @@ -428,11 +547,8 @@ void EEVEE_lights_cache_finish(EEVEE_ViewLayerData *sldata) } /* Update buffer with lamp data */ -static void eevee_light_setup(Object *ob, EEVEE_LampsInfo *linfo, EEVEE_LampEngineData *led) +static void eevee_light_setup(Object *ob, EEVEE_Light *evli) { - /* TODO only update if data changes */ - EEVEE_LightData *evld = led->storage; - EEVEE_Light *evli = linfo->light_data + evld->light_id; Lamp *la = (Lamp *)ob->data; float mat[4][4], scale[3], power; @@ -485,13 +601,14 @@ static void eevee_light_setup(Object *ob, EEVEE_LampsInfo *linfo, EEVEE_LampEngi } else if (la->type == LA_SPOT || la->type == LA_LOCAL) { power = 1.0f / (4.0f * evli->radius * evli->radius * M_PI * M_PI) * /* 1/(4*r²*Pi²) */ - M_PI * M_PI * M_PI * 10.0; /* XXX : Empirical, Fit cycles power */ + M_PI * M_PI * 10.0; /* XXX : Empirical, Fit cycles power */ /* for point lights (a.k.a radius == 0.0) */ // power = M_PI * M_PI * 0.78; /* XXX : Empirical, Fit cycles power */ } else { - power = 1.0f; + power = 1.0f / (4.0f * evli->radius * evli->radius * M_PI * M_PI) * /* 1/(r²*Pi) */ + 12.5f; /* XXX : Empirical, Fit cycles power */ } mul_v3_fl(evli->color, power * la->energy); @@ -504,7 +621,7 @@ static void eevee_light_setup(Object *ob, EEVEE_LampsInfo *linfo, EEVEE_LampEngi static void eevee_shadow_cube_setup(Object *ob, EEVEE_LampsInfo *linfo, EEVEE_LampEngineData *led) { - EEVEE_ShadowCubeData *sh_data = (EEVEE_ShadowCubeData *)led->storage; + EEVEE_ShadowCubeData *sh_data = &led->data.scd; EEVEE_Light *evli = linfo->light_data + sh_data->light_id; EEVEE_Shadow *ubo_data = linfo->shadow_data + sh_data->shadow_id; EEVEE_ShadowCube *cube_data = linfo->shadow_cube_data + sh_data->cube_id; @@ -598,7 +715,7 @@ static void eevee_shadow_cascade_setup(Object *ob, EEVEE_LampsInfo *linfo, EEVEE int sh_nbr = 1; /* TODO : MSM */ int cascade_nbr = la->cascade_count; - EEVEE_ShadowCascadeData *sh_data = (EEVEE_ShadowCascadeData *)led->storage; + EEVEE_ShadowCascadeData *sh_data = &led->data.scad; EEVEE_Light *evli = linfo->light_data + sh_data->light_id; EEVEE_Shadow *ubo_data = linfo->shadow_data + sh_data->shadow_id; EEVEE_ShadowCascade *cascade_data = linfo->shadow_cascade_data + sh_data->cascade_id; @@ -783,128 +900,86 @@ static void eevee_shadow_cascade_setup(Object *ob, EEVEE_LampsInfo *linfo, EEVEE } /* Used for checking if object is inside the shadow volume. */ -static bool cube_bbox_intersect(const float cube_center[3], float cube_half_dim, const BoundBox *bb, float (*obmat)[4]) +static bool sphere_bbox_intersect(const EEVEE_BoundSphere *bs, const EEVEE_BoundBox *bb) { - float min[3], max[4], tmp[4][4]; - unit_m4(tmp); - translate_m4(tmp, -cube_center[0], -cube_center[1], -cube_center[2]); - mul_m4_m4m4(tmp, tmp, obmat); - - /* Just simple AABB intersection test in world space. */ - INIT_MINMAX(min, max); - for (int i = 0; i < 8; ++i) { - float vec[3]; - copy_v3_v3(vec, bb->vec[i]); - mul_m4_v3(tmp, vec); - minmax_v3v3_v3(min, max, vec); - } + /* We are testing using a rougher AABB vs AABB test instead of full AABB vs Sphere. */ + /* TODO test speed with AABB vs Sphere. */ + bool x = fabsf(bb->center[0] - bs->center[0]) <= (bb->halfdim[0] + bs->radius); + bool y = fabsf(bb->center[1] - bs->center[1]) <= (bb->halfdim[1] + bs->radius); + bool z = fabsf(bb->center[2] - bs->center[2]) <= (bb->halfdim[2] + bs->radius); - if (MAX3(max[0], max[1], max[2]) < -cube_half_dim) return false; - if (MIN3(min[0], min[1], min[2]) > cube_half_dim) return false; - - return true; + return x && y && z; } -static ShadowCaster *search_object_in_list(ListBase *list, Object *ob) +void EEVEE_lights_update(EEVEE_ViewLayerData *sldata) { - for (ShadowCaster *ldata = list->first; ldata; ldata = ldata->next) { - if (ldata->ob == ob) - return ldata; + EEVEE_LampsInfo *linfo = sldata->lamps; + Object *ob; + int i; + char *flag; + EEVEE_ShadowCaster *shcaster; + EEVEE_BoundSphere *bsphere; + EEVEE_ShadowCasterBuffer *frontbuffer = linfo->shcaster_frontbuffer; + EEVEE_ShadowCasterBuffer *backbuffer = linfo->shcaster_backbuffer; + + EEVEE_LightBits update_bits = {{0}}; + if ((linfo->update_flag & LIGHT_UPDATE_SHADOW_CUBE) != 0) { + /* Update all lights. */ + lightbits_set_all(&update_bits, true); } - - return NULL; -} - -static void delete_pruned_shadowcaster(EEVEE_LampEngineData *led) -{ - ShadowCaster *next; - for (ShadowCaster *ldata = led->shadow_caster_list.first; ldata; ldata = next) { - next = ldata->next; - if (ldata->prune == true) { - led->need_update = true; - BLI_freelinkN(&led->shadow_caster_list, ldata); + else { + /* Search for deleted shadow casters and if shcaster WAS in shadow radius. */ + /* No need to run this if we already update all lamps. */ + EEVEE_LightBits past_bits = {{0}}; + EEVEE_LightBits curr_bits = {{0}}; + shcaster = backbuffer->shadow_casters; + flag = backbuffer->flags; + for (i = 0; i < backbuffer->count; ++i, ++flag, ++shcaster) { + /* If the shadowcaster has been deleted or updated. */ + if (*flag != 0) { + /* Add the lamps that were intersecting with its BBox. */ + lightbits_or(&past_bits, &shcaster->bits); + } } + /* Convert old bits to new bits and add result to final update bits. */ + /* NOTE: This might be overkill since all lights are tagged to refresh if + * the light count changes. */ + lightbits_convert(&curr_bits, &past_bits, linfo->new_shadow_id, MAX_LIGHT); + lightbits_or(&update_bits, &curr_bits); } -} -static void light_tag_shadow_update(Object *lamp, Object *ob) -{ - Lamp *la = lamp->data; - EEVEE_LampEngineData *led = EEVEE_lamp_data_ensure(lamp); - - bool is_inside_range = cube_bbox_intersect(lamp->obmat[3], la->clipend, BKE_object_boundbox_get(ob), ob->obmat); - ShadowCaster *ldata = search_object_in_list(&led->shadow_caster_list, ob); - - if (is_inside_range) { - if (ldata == NULL) { - /* Object was not a shadow caster previously but is now. Add it. */ - ldata = MEM_callocN(sizeof(ShadowCaster), "ShadowCaster"); - ldata->ob = ob; - BLI_addtail(&led->shadow_caster_list, ldata); - led->need_update = true; + /* Search for updates in current shadow casters. */ + shcaster = frontbuffer->shadow_casters; + flag = frontbuffer->flags; + for (i = 0; i < frontbuffer->count; i++, flag++, shcaster++) { + /* Run intersection checks to fill the bitfields. */ + bsphere = linfo->shadow_bounds; + for (int j = 0; j < linfo->cpu_cube_ct; j++, bsphere++) { + bool iter = sphere_bbox_intersect(bsphere, &shcaster->bbox); + lightbits_set_single(&shcaster->bits, j, iter); } - else { - EEVEE_ObjectEngineData *oedata = EEVEE_object_data_ensure(ob); - if (oedata->need_update) { - led->need_update = true; - } + /* Only add to final bits if objects has been updated. */ + if (*flag != 0) { + lightbits_or(&update_bits, &shcaster->bits); } - ldata->prune = false; } - else if (ldata != NULL) { - /* Object was a shadow caster previously and is not anymore. Remove it. */ - led->need_update = true; - BLI_freelinkN(&led->shadow_caster_list, ldata); - } -} - -static void eevee_lights_shcaster_updated(EEVEE_ViewLayerData *sldata, Object *ob) -{ - Object *lamp; - EEVEE_LampsInfo *linfo = sldata->lamps; - - /* Iterate over all shadow casting lamps to see if - * each of them needs update because of this object */ - for (int i = 0; (lamp = linfo->shadow_cube_ref[i]) && (i < MAX_SHADOW_CUBE); i++) { - light_tag_shadow_update(lamp, ob); - } - EEVEE_ObjectEngineData *oedata = EEVEE_object_data_ensure(ob); - oedata->need_update = false; -} - -void EEVEE_lights_update(EEVEE_ViewLayerData *sldata) -{ - EEVEE_LampsInfo *linfo = sldata->lamps; - Object *ob; - int i; - /* Prune shadow casters to remove if object does not exists anymore (unprune them if object exists) */ - Object *lamp; - for (i = 0; (lamp = linfo->shadow_cube_ref[i]) && (i < MAX_SHADOW_CUBE); i++) { - EEVEE_LampEngineData *led = EEVEE_lamp_data_ensure(lamp); + /* Setup shadow cube in UBO and tag for update if necessary. */ + for (i = 0; (i < MAX_SHADOW_CUBE) && (ob = linfo->shadow_cube_ref[i]); i++) { + EEVEE_LampEngineData *led = EEVEE_lamp_data_ensure(ob); - if ((linfo->update_flag & LIGHT_UPDATE_SHADOW_CUBE) != 0) { + eevee_shadow_cube_setup(ob, linfo, led); + if (lightbits_get(&update_bits, i) != 0) { led->need_update = true; } - - for (ShadowCaster *ldata = led->shadow_caster_list.first; ldata; ldata = ldata->next) { - ldata->prune = true; - } } - for (LinkData *ldata = sldata->shadow_casters.first; ldata; ldata = ldata->next) { - eevee_lights_shcaster_updated(sldata, ldata->data); - } - - for (i = 0; (ob = linfo->light_ref[i]) && (i < MAX_LIGHT); i++) { - EEVEE_LampEngineData *led = EEVEE_lamp_data_ensure(ob); - eevee_light_setup(ob, linfo, led); - } - - for (i = 0; (ob = linfo->shadow_cube_ref[i]) && (i < MAX_SHADOW_CUBE); i++) { - EEVEE_LampEngineData *led = EEVEE_lamp_data_ensure(ob); - eevee_shadow_cube_setup(ob, linfo, led); - delete_pruned_shadowcaster(led); + /* Resize shcasters buffers if too big. */ + if (frontbuffer->alloc_count - frontbuffer->count > SHADOW_CASTER_ALLOC_CHUNK) { + frontbuffer->alloc_count = (frontbuffer->count / SHADOW_CASTER_ALLOC_CHUNK) * SHADOW_CASTER_ALLOC_CHUNK; + frontbuffer->alloc_count += (frontbuffer->count % SHADOW_CASTER_ALLOC_CHUNK != 0) ? SHADOW_CASTER_ALLOC_CHUNK : 0; + frontbuffer->shadow_casters = MEM_reallocN(frontbuffer->shadow_casters, sizeof(EEVEE_ShadowCaster) * frontbuffer->alloc_count); + frontbuffer->flags = MEM_reallocN(frontbuffer->flags, sizeof(EEVEE_ShadowCaster) * frontbuffer->alloc_count); } } @@ -932,7 +1007,7 @@ void EEVEE_draw_shadows(EEVEE_ViewLayerData *sldata, EEVEE_PassList *psl) } EEVEE_ShadowRender *srd = &linfo->shadow_render_data; - EEVEE_ShadowCubeData *evscd = (EEVEE_ShadowCubeData *)led->storage; + EEVEE_ShadowCubeData *evscd = &led->data.scd; srd->clip_near = la->clipsta; srd->clip_far = la->clipend; @@ -1010,7 +1085,7 @@ void EEVEE_draw_shadows(EEVEE_ViewLayerData *sldata, EEVEE_PassList *psl) EEVEE_LampEngineData *led = EEVEE_lamp_data_ensure(ob); Lamp *la = (Lamp *)ob->data; - EEVEE_ShadowCascadeData *evscd = (EEVEE_ShadowCascadeData *)led->storage; + EEVEE_ShadowCascadeData *evscd = &led->data.scad; EEVEE_ShadowRender *srd = &linfo->shadow_render_data; eevee_shadow_cascade_setup(ob, linfo, led); diff --git a/source/blender/draw/engines/eevee/eevee_lut.h b/source/blender/draw/engines/eevee/eevee_lut.h index d706110351e..3c2ffeb11a7 100644 --- a/source/blender/draw/engines/eevee/eevee_lut.h +++ b/source/blender/draw/engines/eevee/eevee_lut.h @@ -3345,6 +3345,521 @@ static float bsdf_split_sum_ggx[64 * 64 * 2] = { 0.626953f, 0.023544f, 0.616699f, 0.022186f, 0.605957f, 0.020920f, 0.594727f, 0.019730f }; +static float ltc_disk_integral[64 * 64] = { + 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, + 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, + 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, + 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, + 0.015873f, 0.047619f, 0.079365f, 0.111111f, 0.142857f, 0.174603f, 0.206349f, 0.238095f, + 0.269841f, 0.301587f, 0.333333f, 0.365079f, 0.396825f, 0.428571f, 0.460317f, 0.492064f, + 0.523810f, 0.555556f, 0.587302f, 0.619048f, 0.650794f, 0.682540f, 0.714286f, 0.746032f, + 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f, + 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, + 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, + 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, + 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000148f, 0.002454f, 0.008675f, 0.019560f, + 0.035433f, 0.056294f, 0.081819f, 0.111259f, 0.142857f, 0.174603f, 0.206349f, 0.238095f, + 0.269841f, 0.301587f, 0.333333f, 0.365079f, 0.396825f, 0.428571f, 0.460317f, 0.492064f, + 0.523810f, 0.555556f, 0.587302f, 0.619048f, 0.650794f, 0.682540f, 0.714286f, 0.746032f, + 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f, + 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, + 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, + 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, + 0.000000f, 0.000000f, 0.000002f, 0.000761f, 0.003673f, 0.009403f, 0.018333f, 0.030683f, + 0.046556f, 0.065952f, 0.088768f, 0.114784f, 0.143618f, 0.174606f, 0.206349f, 0.238095f, + 0.269841f, 0.301587f, 0.333333f, 0.365079f, 0.396825f, 0.428571f, 0.460318f, 0.492064f, + 0.523810f, 0.555556f, 0.587302f, 0.619048f, 0.650794f, 0.682540f, 0.714286f, 0.746032f, + 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f, + 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, + 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, + 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, + 0.000000f, 0.000039f, 0.000969f, 0.003703f, 0.008684f, 0.016189f, 0.026395f, 0.039409f, + 0.055282f, 0.074014f, 0.095554f, 0.119795f, 0.146560f, 0.175573f, 0.206388f, 0.238095f, + 0.269841f, 0.301587f, 0.333333f, 0.365079f, 0.396825f, 0.428571f, 0.460317f, 0.492064f, + 0.523810f, 0.555556f, 0.587302f, 0.619048f, 0.650794f, 0.682540f, 0.714286f, 0.746032f, + 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f, + 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, + 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, + 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, + 0.000047f, 0.000895f, 0.003265f, 0.007514f, 0.013873f, 0.022495f, 0.033483f, 0.046897f, + 0.062770f, 0.081102f, 0.101860f, 0.124985f, 0.150372f, 0.177868f, 0.207245f, 0.238143f, + 0.269841f, 0.301587f, 0.333333f, 0.365079f, 0.396825f, 0.428571f, 0.460317f, 0.492064f, + 0.523810f, 0.555556f, 0.587302f, 0.619048f, 0.650794f, 0.682540f, 0.714286f, 0.746032f, + 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f, + 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, + 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, + 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000028f, + 0.000695f, 0.002655f, 0.006230f, 0.011623f, 0.018976f, 0.028384f, 0.039915f, 0.053606f, + 0.069479f, 0.087534f, 0.107749f, 0.130087f, 0.154481f, 0.180833f, 0.209005f, 0.238791f, + 0.269869f, 0.301587f, 0.333333f, 0.365079f, 0.396825f, 0.428571f, 0.460317f, 0.492064f, + 0.523810f, 0.555556f, 0.587302f, 0.619048f, 0.650794f, 0.682540f, 0.714286f, 0.746032f, + 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f, + 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, + 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, + 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000007f, 0.000465f, + 0.002017f, 0.004975f, 0.009533f, 0.015821f, 0.023934f, 0.033937f, 0.045874f, 0.059772f, + 0.075645f, 0.093493f, 0.113302f, 0.135045f, 0.158678f, 0.184136f, 0.211325f, 0.240113f, + 0.270306f, 0.301594f, 0.333333f, 0.365079f, 0.396825f, 0.428571f, 0.460317f, 0.492064f, + 0.523810f, 0.555556f, 0.587302f, 0.619048f, 0.650794f, 0.682540f, 0.714286f, 0.746032f, + 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f, + 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, + 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, + 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000260f, 0.001426f, + 0.003823f, 0.007642f, 0.013012f, 0.020025f, 0.028745f, 0.039218f, 0.051475f, 0.065535f, + 0.081408f, 0.099094f, 0.118583f, 0.139856f, 0.162882f, 0.187615f, 0.213991f, 0.241918f, + 0.271267f, 0.301847f, 0.333333f, 0.365079f, 0.396826f, 0.428572f, 0.460318f, 0.492064f, + 0.523810f, 0.555556f, 0.587302f, 0.619048f, 0.650794f, 0.682540f, 0.714286f, 0.746032f, + 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f, + 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, + 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, + 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000109f, 0.000921f, 0.002807f, + 0.005966f, 0.010528f, 0.016585f, 0.024200f, 0.033420f, 0.044278f, 0.056796f, 0.070988f, + 0.086861f, 0.104415f, 0.123643f, 0.144531f, 0.167057f, 0.191188f, 0.216878f, 0.244062f, + 0.272649f, 0.302509f, 0.333442f, 0.365079f, 0.396826f, 0.428572f, 0.460318f, 0.492064f, + 0.523810f, 0.555556f, 0.587302f, 0.619048f, 0.650794f, 0.682540f, 0.714286f, 0.746032f, + 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f, + 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, + 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, + 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000024f, 0.000524f, 0.001947f, 0.004511f, + 0.008351f, 0.013561f, 0.020206f, 0.028332f, 0.037974f, 0.049155f, 0.061892f, 0.076194f, + 0.092067f, 0.109511f, 0.128520f, 0.149085f, 0.171189f, 0.194809f, 0.219910f, 0.246447f, + 0.274352f, 0.303535f, 0.333857f, 0.365104f, 0.396826f, 0.428572f, 0.460318f, 0.492064f, + 0.523810f, 0.555556f, 0.587302f, 0.619048f, 0.650794f, 0.682540f, 0.714286f, 0.746032f, + 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f, + 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, + 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, + 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000242f, 0.001250f, 0.003275f, 0.006463f, + 0.010913f, 0.016693f, 0.023849f, 0.032418f, 0.042423f, 0.053881f, 0.066805f, 0.081201f, + 0.097074f, 0.114424f, 0.133246f, 0.153534f, 0.175275f, 0.198453f, 0.223042f, 0.249009f, + 0.276304f, 0.304862f, 0.334584f, 0.365322f, 0.396826f, 0.428571f, 0.460318f, 0.492064f, + 0.523810f, 0.555556f, 0.587302f, 0.619048f, 0.650794f, 0.682540f, 0.714286f, 0.746032f, + 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f, + 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, + 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, + 0.000000f, 0.000000f, 0.000000f, 0.000074f, 0.000716f, 0.002252f, 0.004848f, 0.008610f, + 0.013608f, 0.019894f, 0.027502f, 0.036458f, 0.046780f, 0.058480f, 0.071567f, 0.086045f, + 0.101918f, 0.119186f, 0.137845f, 0.157891f, 0.179316f, 0.202106f, 0.226243f, 0.251704f, + 0.278451f, 0.306436f, 0.335586f, 0.365796f, 0.396900f, 0.428571f, 0.460318f, 0.492064f, + 0.523810f, 0.555556f, 0.587302f, 0.619048f, 0.650794f, 0.682540f, 0.714286f, 0.746032f, + 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f, + 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, + 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, + 0.000000f, 0.000000f, 0.000006f, 0.000342f, 0.001437f, 0.003492f, 0.006624f, 0.010911f, + 0.016406f, 0.023146f, 0.031157f, 0.040457f, 0.051059f, 0.062972f, 0.076203f, 0.090753f, + 0.106626f, 0.123822f, 0.142337f, 0.162170f, 0.183314f, 0.205760f, 0.229496f, 0.254502f, + 0.280753f, 0.308212f, 0.336825f, 0.366517f, 0.397167f, 0.428578f, 0.460318f, 0.492064f, + 0.523810f, 0.555556f, 0.587302f, 0.619048f, 0.650794f, 0.682540f, 0.714286f, 0.746032f, + 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f, + 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, + 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, + 0.000000f, 0.000000f, 0.000114f, 0.000820f, 0.002381f, 0.004935f, 0.008569f, 0.013339f, + 0.019286f, 0.026437f, 0.034810f, 0.044418f, 0.055271f, 0.067375f, 0.080733f, 0.095348f, + 0.111221f, 0.128352f, 0.146740f, 0.166382f, 0.187276f, 0.209413f, 0.232786f, 0.257382f, + 0.283181f, 0.310156f, 0.338269f, 0.367461f, 0.397646f, 0.428685f, 0.460318f, 0.492064f, + 0.523810f, 0.555556f, 0.587302f, 0.619048f, 0.650794f, 0.682540f, 0.714286f, 0.746032f, + 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f, + 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, + 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, + 0.000000f, 0.000014f, 0.000390f, 0.001503f, 0.003525f, 0.006554f, 0.010655f, 0.015872f, + 0.022233f, 0.029758f, 0.038460f, 0.048347f, 0.059427f, 0.071702f, 0.085175f, 0.099848f, + 0.115721f, 0.132794f, 0.151067f, 0.170538f, 0.191204f, 0.213063f, 0.236107f, 0.260329f, + 0.285714f, 0.312243f, 0.339887f, 0.368604f, 0.398329f, 0.428961f, 0.460331f, 0.492064f, + 0.523810f, 0.555556f, 0.587302f, 0.619048f, 0.650794f, 0.682540f, 0.714286f, 0.746032f, + 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f, + 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, + 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, + 0.000000f, 0.000130f, 0.000845f, 0.002376f, 0.004845f, 0.008325f, 0.012864f, 0.018495f, + 0.025237f, 0.033105f, 0.042107f, 0.052249f, 0.063534f, 0.075965f, 0.089543f, 0.104269f, + 0.120142f, 0.137163f, 0.155330f, 0.174645f, 0.195106f, 0.216710f, 0.239454f, 0.263332f, + 0.288336f, 0.314451f, 0.341658f, 0.369924f, 0.399202f, 0.429416f, 0.460447f, 0.492064f, + 0.523809f, 0.555555f, 0.587301f, 0.619048f, 0.650794f, 0.682540f, 0.714286f, 0.746032f, + 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f, + 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, + 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, + 0.000016f, 0.000391f, 0.001475f, 0.003423f, 0.006322f, 0.010230f, 0.015179f, 0.021195f, + 0.028290f, 0.036474f, 0.045752f, 0.056128f, 0.067602f, 0.080176f, 0.093850f, 0.108623f, + 0.124496f, 0.141469f, 0.159541f, 0.178713f, 0.198985f, 0.220355f, 0.242823f, 0.266385f, + 0.291036f, 0.316767f, 0.343563f, 0.371402f, 0.400248f, 0.430047f, 0.460709f, 0.492079f, + 0.523810f, 0.555556f, 0.587302f, 0.619048f, 0.650794f, 0.682540f, 0.714286f, 0.746032f, + 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f, + 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, + 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, + 0.000123f, 0.000807f, 0.002272f, 0.004628f, 0.007942f, 0.012253f, 0.017589f, 0.023963f, + 0.031387f, 0.039864f, 0.049398f, 0.059990f, 0.071638f, 0.084344f, 0.098106f, 0.112923f, + 0.128796f, 0.145725f, 0.163709f, 0.182749f, 0.202847f, 0.224001f, 0.246214f, 0.269482f, + 0.293805f, 0.319176f, 0.345587f, 0.373021f, 0.401454f, 0.430844f, 0.461125f, 0.492187f, + 0.523810f, 0.555556f, 0.587302f, 0.619048f, 0.650794f, 0.682540f, 0.714286f, 0.746032f, + 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f, + 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, + 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000012f, + 0.000356f, 0.001378f, 0.003225f, 0.005979f, 0.009689f, 0.014384f, 0.020083f, 0.026795f, + 0.034525f, 0.043276f, 0.053047f, 0.063839f, 0.075649f, 0.088476f, 0.102320f, 0.117178f, + 0.133051f, 0.149939f, 0.167841f, 0.186760f, 0.206696f, 0.227650f, 0.249625f, 0.272620f, + 0.296636f, 0.321671f, 0.347718f, 0.374768f, 0.402804f, 0.431796f, 0.461695f, 0.492420f, + 0.523822f, 0.555556f, 0.587302f, 0.619048f, 0.650794f, 0.682540f, 0.714286f, 0.746032f, + 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f, + 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, + 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000100f, + 0.000725f, 0.002097f, 0.004323f, 0.007463f, 0.011553f, 0.016613f, 0.022655f, 0.029684f, + 0.037702f, 0.046708f, 0.056701f, 0.067680f, 0.079640f, 0.092581f, 0.106501f, 0.121397f, + 0.137270f, 0.154120f, 0.171946f, 0.190751f, 0.210537f, 0.231305f, 0.253057f, 0.275797f, + 0.299525f, 0.324242f, 0.349947f, 0.376633f, 0.404289f, 0.432895f, 0.462415f, 0.492788f, + 0.523909f, 0.555556f, 0.587302f, 0.619048f, 0.650794f, 0.682540f, 0.714286f, 0.746032f, + 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f, + 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, + 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000005f, 0.000296f, + 0.001231f, 0.002960f, 0.005558f, 0.009072f, 0.013526f, 0.018933f, 0.025299f, 0.032627f, + 0.040916f, 0.050162f, 0.060364f, 0.071517f, 0.083619f, 0.096666f, 0.110656f, 0.125588f, + 0.141461f, 0.158275f, 0.176031f, 0.194730f, 0.214374f, 0.234967f, 0.256512f, 0.279011f, + 0.302468f, 0.326887f, 0.352266f, 0.378605f, 0.405897f, 0.434130f, 0.463277f, 0.493295f, + 0.524106f, 0.555561f, 0.587302f, 0.619048f, 0.650794f, 0.682540f, 0.714286f, 0.746032f, + 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f, + 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, + 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000068f, 0.000613f, + 0.001874f, 0.003958f, 0.006921f, 0.010796f, 0.015599f, 0.021336f, 0.028011f, 0.035623f, + 0.044167f, 0.053640f, 0.064038f, 0.075355f, 0.087589f, 0.100736f, 0.114793f, 0.129759f, + 0.145632f, 0.162412f, 0.180101f, 0.198700f, 0.218213f, 0.238641f, 0.259989f, 0.282262f, + 0.305464f, 0.329599f, 0.354670f, 0.380678f, 0.407622f, 0.435493f, 0.464275f, 0.493938f, + 0.524422f, 0.555624f, 0.587302f, 0.619048f, 0.650794f, 0.682540f, 0.714286f, 0.746032f, + 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f, + 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, + 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000001f, 0.000223f, 0.001054f, + 0.002649f, 0.005086f, 0.008406f, 0.012629f, 0.017766f, 0.023820f, 0.030789f, 0.038669f, + 0.047455f, 0.057143f, 0.067726f, 0.079199f, 0.091558f, 0.104798f, 0.118918f, 0.133915f, + 0.149788f, 0.166537f, 0.184164f, 0.202669f, 0.222056f, 0.242329f, 0.263492f, 0.285551f, + 0.308510f, 0.332376f, 0.357153f, 0.382845f, 0.409454f, 0.436977f, 0.465404f, 0.494713f, + 0.524864f, 0.555779f, 0.587302f, 0.619048f, 0.650794f, 0.682540f, 0.714286f, 0.746032f, + 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f, + 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, + 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000037f, 0.000486f, 0.001621f, + 0.003553f, 0.006338f, 0.010004f, 0.014565f, 0.020024f, 0.026380f, 0.033629f, 0.041765f, + 0.050782f, 0.060673f, 0.071431f, 0.083052f, 0.095529f, 0.108859f, 0.123038f, 0.138065f, + 0.153938f, 0.170657f, 0.188224f, 0.206640f, 0.225909f, 0.246035f, 0.267022f, 0.288878f, + 0.311607f, 0.335216f, 0.359713f, 0.385103f, 0.411390f, 0.438576f, 0.466656f, 0.495617f, + 0.525431f, 0.556041f, 0.587338f, 0.619048f, 0.650794f, 0.682540f, 0.714286f, 0.746032f, + 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f, + 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, + 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000149f, 0.000861f, 0.002312f, + 0.004581f, 0.007709f, 0.011713f, 0.016599f, 0.022367f, 0.029014f, 0.036531f, 0.044912f, + 0.054148f, 0.064233f, 0.075158f, 0.086918f, 0.099507f, 0.112922f, 0.127157f, 0.142212f, + 0.158085f, 0.174776f, 0.192287f, 0.210619f, 0.229775f, 0.249761f, 0.270582f, 0.292243f, + 0.314753f, 0.338118f, 0.362347f, 0.387447f, 0.413424f, 0.440284f, 0.468027f, 0.496645f, + 0.526122f, 0.556417f, 0.587451f, 0.619048f, 0.650794f, 0.682540f, 0.714286f, 0.746032f, + 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f, + 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, + 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000012f, 0.000355f, 0.001353f, 0.003126f, + 0.005730f, 0.009194f, 0.013526f, 0.018728f, 0.024795f, 0.031720f, 0.039494f, 0.048109f, + 0.057555f, 0.067824f, 0.078909f, 0.090802f, 0.103499f, 0.116993f, 0.131282f, 0.146364f, + 0.162237f, 0.178902f, 0.196358f, 0.214610f, 0.233660f, 0.253512f, 0.274174f, 0.295650f, + 0.317950f, 0.341081f, 0.365053f, 0.389874f, 0.415553f, 0.442098f, 0.469512f, 0.497794f, + 0.526935f, 0.556908f, 0.587657f, 0.619060f, 0.650794f, 0.682540f, 0.714286f, 0.746032f, + 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f, + 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, + 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000083f, 0.000665f, 0.001962f, 0.004059f, + 0.006997f, 0.010790f, 0.015442f, 0.020949f, 0.027304f, 0.034497f, 0.042518f, 0.051358f, + 0.061005f, 0.071451f, 0.082688f, 0.094709f, 0.107507f, 0.121078f, 0.135419f, 0.150526f, + 0.166399f, 0.183038f, 0.200443f, 0.218618f, 0.237566f, 0.257291f, 0.277800f, 0.299100f, + 0.321199f, 0.344106f, 0.367830f, 0.392383f, 0.417774f, 0.444013f, 0.471107f, 0.499060f, + 0.527869f, 0.557517f, 0.587966f, 0.619130f, 0.650794f, 0.682540f, 0.714286f, 0.746032f, + 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f, + 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, + 0.000000f, 0.000000f, 0.000000f, 0.000001f, 0.000233f, 0.001082f, 0.002688f, 0.005111f, + 0.008377f, 0.012493f, 0.017456f, 0.023260f, 0.029893f, 0.037345f, 0.045604f, 0.054659f, + 0.064499f, 0.075115f, 0.086498f, 0.098641f, 0.111537f, 0.125182f, 0.139571f, 0.154703f, + 0.170576f, 0.187190f, 0.204547f, 0.222648f, 0.241498f, 0.261101f, 0.281465f, 0.302595f, + 0.324501f, 0.347192f, 0.370679f, 0.394973f, 0.420085f, 0.446027f, 0.472810f, 0.500441f, + 0.528921f, 0.558244f, 0.588384f, 0.619281f, 0.650795f, 0.682540f, 0.714286f, 0.746032f, + 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f, + 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, + 0.000000f, 0.000000f, 0.000000f, 0.000033f, 0.000477f, 0.001611f, 0.003532f, 0.006280f, + 0.009869f, 0.014301f, 0.019568f, 0.025659f, 0.032563f, 0.040265f, 0.048753f, 0.058016f, + 0.068042f, 0.078821f, 0.090344f, 0.102604f, 0.115594f, 0.129309f, 0.143745f, 0.158901f, + 0.174774f, 0.191365f, 0.208674f, 0.226705f, 0.245461f, 0.264947f, 0.285170f, 0.306137f, + 0.327857f, 0.350341f, 0.373598f, 0.397642f, 0.422485f, 0.448139f, 0.474619f, 0.501933f, + 0.530089f, 0.559087f, 0.588913f, 0.619525f, 0.650826f, 0.682540f, 0.714286f, 0.746032f, + 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f, + 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, + 0.000000f, 0.000000f, 0.000000f, 0.000130f, 0.000821f, 0.002252f, 0.004491f, 0.007562f, + 0.011472f, 0.016213f, 0.021776f, 0.028147f, 0.035312f, 0.043256f, 0.051966f, 0.061430f, + 0.071635f, 0.082571f, 0.094229f, 0.106602f, 0.119682f, 0.133465f, 0.147947f, 0.163125f, + 0.178998f, 0.195566f, 0.212830f, 0.230793f, 0.249459f, 0.268832f, 0.288920f, 0.309730f, + 0.331271f, 0.353554f, 0.376590f, 0.400391f, 0.424973f, 0.450347f, 0.476531f, 0.503535f, + 0.531372f, 0.560047f, 0.589554f, 0.619869f, 0.650923f, 0.682540f, 0.714286f, 0.746032f, + 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f, + 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, + 0.000000f, 0.000000f, 0.000005f, 0.000309f, 0.001270f, 0.003008f, 0.005566f, 0.008959f, + 0.013183f, 0.018228f, 0.024080f, 0.030723f, 0.038142f, 0.046321f, 0.055246f, 0.064903f, + 0.075281f, 0.086369f, 0.098158f, 0.110639f, 0.123806f, 0.137655f, 0.152180f, 0.167380f, + 0.183253f, 0.199799f, 0.217020f, 0.234918f, 0.253496f, 0.272761f, 0.292719f, 0.313377f, + 0.334745f, 0.356833f, 0.379654f, 0.403221f, 0.427548f, 0.452651f, 0.478545f, 0.505246f, + 0.532768f, 0.561122f, 0.590309f, 0.620318f, 0.651102f, 0.682545f, 0.714286f, 0.746032f, + 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f, + 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, + 0.000000f, 0.000000f, 0.000053f, 0.000579f, 0.001828f, 0.003878f, 0.006757f, 0.010468f, + 0.015002f, 0.020344f, 0.026479f, 0.033388f, 0.041054f, 0.049461f, 0.058594f, 0.068440f, + 0.078985f, 0.090220f, 0.102134f, 0.114721f, 0.127972f, 0.141884f, 0.156451f, 0.171672f, + 0.187545f, 0.204070f, 0.221249f, 0.239083f, 0.257578f, 0.276738f, 0.296569f, 0.317080f, + 0.338281f, 0.360181f, 0.382794f, 0.406133f, 0.430213f, 0.455050f, 0.480662f, 0.507065f, + 0.534278f, 0.562313f, 0.591180f, 0.620875f, 0.651373f, 0.682593f, 0.714286f, 0.746032f, + 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f, + 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, + 0.000000f, 0.000000f, 0.000169f, 0.000949f, 0.002497f, 0.004864f, 0.008063f, 0.012089f, + 0.016929f, 0.022563f, 0.028974f, 0.036142f, 0.044049f, 0.052678f, 0.062014f, 0.072042f, + 0.082750f, 0.094127f, 0.106164f, 0.118852f, 0.132185f, 0.146157f, 0.160766f, 0.176007f, + 0.191880f, 0.208385f, 0.225523f, 0.243296f, 0.261709f, 0.280767f, 0.300476f, 0.320845f, + 0.341883f, 0.363601f, 0.386011f, 0.409128f, 0.432967f, 0.457545f, 0.482881f, 0.508992f, + 0.535899f, 0.563619f, 0.592165f, 0.621544f, 0.651743f, 0.682709f, 0.714286f, 0.746032f, + 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f, + 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, + 0.000000f, 0.000010f, 0.000368f, 0.001423f, 0.003279f, 0.005966f, 0.009485f, 0.013824f, + 0.018964f, 0.024886f, 0.031567f, 0.038988f, 0.047130f, 0.055975f, 0.065508f, 0.075714f, + 0.086580f, 0.098095f, 0.110251f, 0.123038f, 0.136450f, 0.150482f, 0.165129f, 0.180390f, + 0.196263f, 0.212748f, 0.229847f, 0.247561f, 0.265895f, 0.284854f, 0.304445f, 0.324675f, + 0.345555f, 0.367095f, 0.389309f, 0.412210f, 0.435814f, 0.460138f, 0.485203f, 0.511028f, + 0.537634f, 0.565041f, 0.593268f, 0.622327f, 0.652217f, 0.682907f, 0.714296f, 0.746032f, + 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f, + 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, + 0.000000f, 0.000068f, 0.000658f, 0.002006f, 0.004178f, 0.007186f, 0.011024f, 0.015672f, + 0.021109f, 0.027312f, 0.034259f, 0.041928f, 0.050300f, 0.059356f, 0.069081f, 0.079460f, + 0.090480f, 0.102130f, 0.114400f, 0.127284f, 0.140772f, 0.154862f, 0.169548f, 0.184828f, + 0.200701f, 0.217167f, 0.234227f, 0.251884f, 0.270141f, 0.289004f, 0.308479f, 0.328575f, + 0.349301f, 0.370668f, 0.392689f, 0.415379f, 0.438754f, 0.462830f, 0.487630f, 0.513173f, + 0.539482f, 0.566579f, 0.594488f, 0.623226f, 0.652800f, 0.683198f, 0.714354f, 0.746032f, + 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f, + 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, + 0.000000f, 0.000196f, 0.001048f, 0.002702f, 0.005194f, 0.008526f, 0.012680f, 0.017635f, + 0.023365f, 0.029846f, 0.037053f, 0.044965f, 0.053561f, 0.062824f, 0.072737f, 0.083284f, + 0.094454f, 0.106236f, 0.118619f, 0.131595f, 0.145159f, 0.159305f, 0.174028f, 0.189327f, + 0.205200f, 0.221647f, 0.238670f, 0.256270f, 0.274453f, 0.293222f, 0.312585f, 0.332550f, + 0.353126f, 0.374324f, 0.396158f, 0.418641f, 0.441790f, 0.465624f, 0.490163f, 0.515429f, + 0.541445f, 0.568236f, 0.595828f, 0.624242f, 0.653496f, 0.683588f, 0.714482f, 0.746032f, + 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f, + 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, + 0.000012f, 0.000407f, 0.001545f, 0.003514f, 0.006332f, 0.009987f, 0.014457f, 0.019715f, + 0.025734f, 0.032488f, 0.039952f, 0.048102f, 0.056919f, 0.066384f, 0.076480f, 0.087193f, + 0.098509f, 0.110419f, 0.122912f, 0.135980f, 0.149617f, 0.163817f, 0.178577f, 0.193894f, + 0.209767f, 0.226196f, 0.243182f, 0.260728f, 0.278837f, 0.297515f, 0.316768f, 0.336605f, + 0.357034f, 0.378067f, 0.399717f, 0.421998f, 0.444928f, 0.468523f, 0.492806f, 0.517798f, + 0.543525f, 0.570012f, 0.597288f, 0.625379f, 0.654307f, 0.684084f, 0.714693f, 0.746044f, + 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f, + 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, + 0.000074f, 0.000713f, 0.002152f, 0.004446f, 0.007592f, 0.011571f, 0.016356f, 0.021915f, + 0.028220f, 0.035243f, 0.042959f, 0.051344f, 0.060377f, 0.070040f, 0.080316f, 0.091191f, + 0.102651f, 0.114686f, 0.127286f, 0.140443f, 0.154151f, 0.168405f, 0.183201f, 0.198536f, + 0.214409f, 0.230820f, 0.247770f, 0.265263f, 0.283301f, 0.301889f, 0.321035f, 0.340746f, + 0.361032f, 0.381904f, 0.403374f, 0.425457f, 0.448169f, 0.471530f, 0.495561f, 0.520284f, + 0.545725f, 0.571911f, 0.598873f, 0.626640f, 0.655239f, 0.684692f, 0.714999f, 0.746106f, + 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f, + 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, + 0.000208f, 0.001121f, 0.002877f, 0.005501f, 0.008979f, 0.013283f, 0.018380f, 0.024238f, + 0.030826f, 0.038115f, 0.046079f, 0.054695f, 0.063941f, 0.073799f, 0.084252f, 0.095285f, + 0.106886f, 0.119044f, 0.131749f, 0.144994f, 0.158772f, 0.173078f, 0.187908f, 0.203261f, + 0.219134f, 0.235527f, 0.252443f, 0.269883f, 0.287851f, 0.306352f, 0.325393f, 0.344981f, + 0.365126f, 0.385839f, 0.407132f, 0.429020f, 0.451520f, 0.474651f, 0.498433f, 0.522890f, + 0.548048f, 0.573936f, 0.600584f, 0.628027f, 0.656295f, 0.685417f, 0.715406f, 0.746240f, + 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f, + 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000011f, + 0.000427f, 0.001638f, 0.003724f, 0.006685f, 0.010497f, 0.015125f, 0.020534f, 0.026688f, + 0.033557f, 0.041109f, 0.049318f, 0.058161f, 0.067617f, 0.077666f, 0.088293f, 0.099482f, + 0.111221f, 0.123499f, 0.136308f, 0.149639f, 0.163485f, 0.177843f, 0.192707f, 0.208077f, + 0.223950f, 0.240326f, 0.257208f, 0.274596f, 0.292496f, 0.310911f, 0.329849f, 0.349316f, + 0.369323f, 0.389880f, 0.410999f, 0.432696f, 0.454987f, 0.477890f, 0.501426f, 0.525620f, + 0.550498f, 0.576089f, 0.602427f, 0.629544f, 0.657479f, 0.686264f, 0.715924f, 0.746459f, + 0.777789f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f, + 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000071f, + 0.000744f, 0.002274f, 0.004698f, 0.008002f, 0.012149f, 0.017102f, 0.022822f, 0.029271f, + 0.036417f, 0.044229f, 0.052681f, 0.061749f, 0.071411f, 0.081649f, 0.092447f, 0.103790f, + 0.115665f, 0.128062f, 0.140972f, 0.154387f, 0.168301f, 0.182709f, 0.197608f, 0.212994f, + 0.228867f, 0.245227f, 0.262074f, 0.279412f, 0.297244f, 0.315575f, 0.334412f, 0.353760f, + 0.373631f, 0.394034f, 0.414983f, 0.436491f, 0.458575f, 0.481253f, 0.504547f, 0.528481f, + 0.553081f, 0.578377f, 0.604404f, 0.631197f, 0.658795f, 0.687238f, 0.716559f, 0.746776f, + 0.777849f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f, + 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000205f, + 0.001168f, 0.003033f, 0.005806f, 0.009456f, 0.013942f, 0.019220f, 0.025250f, 0.031992f, + 0.039414f, 0.047484f, 0.056176f, 0.065466f, 0.075333f, 0.085757f, 0.096724f, 0.108218f, + 0.120227f, 0.132741f, 0.145751f, 0.159249f, 0.173230f, 0.187687f, 0.202619f, 0.218021f, + 0.233894f, 0.250238f, 0.267052f, 0.284341f, 0.302106f, 0.320354f, 0.339090f, 0.358322f, + 0.378059f, 0.398311f, 0.419090f, 0.440412f, 0.462292f, 0.484748f, 0.507802f, 0.531477f, + 0.555802f, 0.580805f, 0.606522f, 0.632990f, 0.660250f, 0.688346f, 0.717319f, 0.747200f, + 0.777982f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f, + 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000007f, 0.000427f, + 0.001710f, 0.003925f, 0.007054f, 0.011055f, 0.015881f, 0.021485f, 0.027824f, 0.034859f, + 0.042554f, 0.050881f, 0.059811f, 0.069321f, 0.079390f, 0.089998f, 0.101132f, 0.112775f, + 0.124917f, 0.137547f, 0.150655f, 0.164236f, 0.178281f, 0.192788f, 0.207752f, 0.223171f, + 0.239044f, 0.255371f, 0.272153f, 0.289393f, 0.307093f, 0.325259f, 0.343896f, 0.363012f, + 0.382617f, 0.402719f, 0.423332f, 0.444469f, 0.466146f, 0.488383f, 0.511199f, 0.534618f, + 0.558668f, 0.583380f, 0.608787f, 0.634929f, 0.661849f, 0.689594f, 0.718211f, 0.747742f, + 0.778205f, 0.809530f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f, + 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000059f, 0.000754f, + 0.002379f, 0.004956f, 0.008449f, 0.012806f, 0.017974f, 0.023905f, 0.030553f, 0.037879f, + 0.045847f, 0.054429f, 0.063595f, 0.073323f, 0.083592f, 0.094384f, 0.105682f, 0.117474f, + 0.129747f, 0.142491f, 0.155697f, 0.169358f, 0.183469f, 0.198024f, 0.213020f, 0.228455f, + 0.244329f, 0.260639f, 0.277389f, 0.294580f, 0.312216f, 0.330300f, 0.348840f, 0.367842f, + 0.387315f, 0.407270f, 0.427717f, 0.448671f, 0.470149f, 0.492167f, 0.514746f, 0.537911f, + 0.561688f, 0.586108f, 0.611206f, 0.637022f, 0.663599f, 0.690989f, 0.719242f, 0.748411f, + 0.778531f, 0.809583f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f, + 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000187f, 0.001196f, + 0.003184f, 0.006136f, 0.010000f, 0.014716f, 0.020230f, 0.026488f, 0.033445f, 0.041062f, + 0.049303f, 0.058138f, 0.067540f, 0.077485f, 0.087953f, 0.098926f, 0.110388f, 0.122327f, + 0.134729f, 0.147587f, 0.160889f, 0.174631f, 0.188806f, 0.203409f, 0.218437f, 0.233888f, + 0.249761f, 0.266056f, 0.282774f, 0.299917f, 0.317488f, 0.335493f, 0.353936f, 0.372825f, + 0.392168f, 0.411976f, 0.432259f, 0.453032f, 0.474310f, 0.496111f, 0.518456f, 0.541367f, + 0.564872f, 0.589001f, 0.613789f, 0.639277f, 0.665510f, 0.692539f, 0.720422f, 0.749216f, + 0.778974f, 0.809711f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f, + 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000002f, 0.000409f, 0.001767f, + 0.004137f, 0.007474f, 0.011716f, 0.016797f, 0.022657f, 0.029244f, 0.036512f, 0.044420f, + 0.052933f, 0.062021f, 0.071657f, 0.081819f, 0.092485f, 0.103638f, 0.115263f, 0.127348f, + 0.139880f, 0.152849f, 0.166248f, 0.180070f, 0.194308f, 0.208958f, 0.224018f, 0.239485f, + 0.255359f, 0.271638f, 0.288324f, 0.305419f, 0.322927f, 0.340851f, 0.359199f, 0.377975f, + 0.397189f, 0.416851f, 0.436971f, 0.457564f, 0.478644f, 0.500229f, 0.522339f, 0.544997f, + 0.568230f, 0.592068f, 0.616546f, 0.641705f, 0.667590f, 0.694255f, 0.721760f, 0.750168f, + 0.779545f, 0.809933f, 0.841272f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f, + 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000041f, 0.000744f, 0.002481f, + 0.005248f, 0.008982f, 0.013608f, 0.019058f, 0.025269f, 0.032188f, 0.039767f, 0.047967f, + 0.056752f, 0.066093f, 0.075963f, 0.086340f, 0.097203f, 0.108537f, 0.120325f, 0.132554f, + 0.145215f, 0.158296f, 0.171790f, 0.185691f, 0.199993f, 0.214691f, 0.229782f, 0.245265f, + 0.261138f, 0.277401f, 0.294056f, 0.311104f, 0.328548f, 0.346394f, 0.364645f, 0.383310f, + 0.402396f, 0.421912f, 0.441870f, 0.462283f, 0.483165f, 0.504535f, 0.526410f, 0.548816f, + 0.571776f, 0.595323f, 0.619489f, 0.644317f, 0.669852f, 0.696148f, 0.723267f, 0.751280f, + 0.780258f, 0.810268f, 0.841311f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f, + 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000156f, 0.001209f, 0.003349f, + 0.006531f, 0.010672f, 0.015691f, 0.021515f, 0.028080f, 0.035332f, 0.043225f, 0.051717f, + 0.060775f, 0.070370f, 0.080474f, 0.091067f, 0.102128f, 0.113641f, 0.125591f, 0.137965f, + 0.150754f, 0.163947f, 0.177537f, 0.191516f, 0.205881f, 0.220626f, 0.235749f, 0.251248f, + 0.267121f, 0.283368f, 0.299992f, 0.316992f, 0.334374f, 0.352140f, 0.370296f, 0.388849f, + 0.407807f, 0.427178f, 0.446974f, 0.467207f, 0.487892f, 0.509046f, 0.530687f, 0.552839f, + 0.575527f, 0.598780f, 0.622634f, 0.647128f, 0.672308f, 0.698231f, 0.724958f, 0.752563f, + 0.781127f, 0.810733f, 0.841426f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f, + 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000374f, 0.001821f, 0.004389f, + 0.008001f, 0.012559f, 0.017979f, 0.024182f, 0.031106f, 0.038695f, 0.046903f, 0.055690f, + 0.065023f, 0.074872f, 0.085211f, 0.096020f, 0.107279f, 0.118971f, 0.131084f, 0.143604f, + 0.156521f, 0.169825f, 0.183510f, 0.197569f, 0.211997f, 0.226789f, 0.241944f, 0.257458f, + 0.273331f, 0.289563f, 0.306154f, 0.323108f, 0.340426f, 0.358113f, 0.376175f, 0.394616f, + 0.413445f, 0.432671f, 0.452305f, 0.472358f, 0.492845f, 0.513783f, 0.535189f, 0.557087f, + 0.579500f, 0.602459f, 0.625997f, 0.650154f, 0.674976f, 0.700518f, 0.726845f, 0.754032f, + 0.782167f, 0.811344f, 0.841644f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f, + 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000020f, 0.000719f, 0.002598f, 0.005618f, + 0.009675f, 0.014663f, 0.020490f, 0.027080f, 0.034367f, 0.042297f, 0.050824f, 0.059909f, + 0.069517f, 0.079622f, 0.090198f, 0.101224f, 0.112682f, 0.124555f, 0.136831f, 0.149496f, + 0.162542f, 0.175958f, 0.189739f, 0.203877f, 0.218368f, 0.233208f, 0.248393f, 0.263923f, + 0.279796f, 0.296012f, 0.312573f, 0.329479f, 0.346734f, 0.364342f, 0.382307f, 0.400637f, + 0.419337f, 0.438418f, 0.457889f, 0.477761f, 0.498050f, 0.518770f, 0.539940f, 0.561581f, + 0.583718f, 0.606380f, 0.629599f, 0.653415f, 0.677874f, 0.703030f, 0.728948f, 0.755706f, + 0.783396f, 0.812121f, 0.841989f, 0.873035f, 0.904762f, 0.936508f, 0.968254f, 1.000000f, + 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000114f, 0.001215f, 0.003561f, 0.007056f, + 0.011574f, 0.017003f, 0.023248f, 0.030232f, 0.037888f, 0.046164f, 0.055014f, 0.064399f, + 0.074287f, 0.084650f, 0.095464f, 0.106709f, 0.118367f, 0.130423f, 0.142862f, 0.155674f, + 0.168849f, 0.182378f, 0.196255f, 0.210473f, 0.225027f, 0.239915f, 0.255132f, 0.270678f, + 0.286551f, 0.302751f, 0.319280f, 0.336138f, 0.353330f, 0.370858f, 0.388728f, 0.406944f, + 0.425515f, 0.444449f, 0.463756f, 0.483447f, 0.503535f, 0.524036f, 0.544968f, 0.566350f, + 0.588208f, 0.610569f, 0.633466f, 0.656936f, 0.681025f, 0.705788f, 0.731289f, 0.757606f, + 0.784834f, 0.813085f, 0.842485f, 0.873130f, 0.904762f, 0.936508f, 0.968254f, 1.000000f, + 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000324f, 0.001887f, 0.004735f, 0.008727f, + 0.013724f, 0.019607f, 0.026280f, 0.033666f, 0.041699f, 0.050326f, 0.059504f, 0.069194f, + 0.079365f, 0.089989f, 0.101045f, 0.112512f, 0.124372f, 0.136611f, 0.149216f, 0.162176f, + 0.175482f, 0.189125f, 0.203098f, 0.217396f, 0.232015f, 0.246950f, 0.262200f, 0.277761f, + 0.293634f, 0.309819f, 0.326315f, 0.343126f, 0.360254f, 0.377701f, 0.395474f, 0.413577f, + 0.432018f, 0.450804f, 0.469944f, 0.489451f, 0.509337f, 0.529617f, 0.550307f, 0.571428f, + 0.593003f, 0.615059f, 0.637628f, 0.660746f, 0.684460f, 0.708820f, 0.733893f, 0.759756f, + 0.786505f, 0.814259f, 0.843157f, 0.873340f, 0.904762f, 0.936508f, 0.968254f, 1.000000f, + 0.000000f, 0.000000f, 0.000000f, 0.000003f, 0.000683f, 0.002764f, 0.006148f, 0.010661f, + 0.016155f, 0.022506f, 0.029620f, 0.037417f, 0.045835f, 0.054821f, 0.064333f, 0.074333f, + 0.084792f, 0.095683f, 0.106984f, 0.118675f, 0.130741f, 0.143166f, 0.155939f, 0.169049f, + 0.182487f, 0.196245f, 0.210317f, 0.224697f, 0.239380f, 0.254364f, 0.269646f, 0.285223f, + 0.301096f, 0.317265f, 0.333729f, 0.350491f, 0.367554f, 0.384920f, 0.402594f, 0.420582f, + 0.438891f, 0.457527f, 0.476499f, 0.495820f, 0.515500f, 0.535555f, 0.556000f, 0.576855f, + 0.598143f, 0.619888f, 0.642123f, 0.664883f, 0.688211f, 0.712160f, 0.736792f, 0.762186f, + 0.788439f, 0.815672f, 0.844034f, 0.873699f, 0.904765f, 0.936508f, 0.968254f, 1.000000f, + 0.000000f, 0.000000f, 0.000000f, 0.000066f, 0.001228f, 0.003880f, 0.007835f, 0.012895f, + 0.018905f, 0.025742f, 0.033309f, 0.041530f, 0.050342f, 0.059696f, 0.069550f, 0.079868f, + 0.090620f, 0.101783f, 0.113333f, 0.125254f, 0.137529f, 0.150144f, 0.163088f, 0.176351f, + 0.189924f, 0.203799f, 0.217970f, 0.232433f, 0.247182f, 0.262216f, 0.277530f, 0.293124f, + 0.308997f, 0.325149f, 0.341581f, 0.358294f, 0.375290f, 0.392573f, 0.410148f, 0.428019f, + 0.446192f, 0.464676f, 0.483478f, 0.502608f, 0.522079f, 0.541905f, 0.562100f, 0.582684f, + 0.603677f, 0.625106f, 0.646998f, 0.669390f, 0.692324f, 0.715849f, 0.740028f, 0.764937f, + 0.790673f, 0.817358f, 0.845150f, 0.874244f, 0.904828f, 0.936508f, 0.968254f, 1.000000f, + 0.000000f, 0.000000f, 0.000000f, 0.000260f, 0.002001f, 0.005278f, 0.009840f, 0.015475f, + 0.022025f, 0.029365f, 0.037402f, 0.046060f, 0.055280f, 0.065013f, 0.075218f, 0.085861f, + 0.096916f, 0.108356f, 0.120163f, 0.132319f, 0.144808f, 0.157618f, 0.170737f, 0.184155f, + 0.197866f, 0.211861f, 0.226134f, 0.240682f, 0.255499f, 0.270583f, 0.285931f, 0.301542f, + 0.317415f, 0.333550f, 0.349948f, 0.366610f, 0.383539f, 0.400738f, 0.418210f, 0.435961f, + 0.453997f, 0.472324f, 0.490951f, 0.509887f, 0.529144f, 0.548735f, 0.568674f, 0.588979f, + 0.609671f, 0.630773f, 0.652314f, 0.674328f, 0.696854f, 0.719942f, 0.743651f, 0.768057f, + 0.793253f, 0.819363f, 0.846547f, 0.875017f, 0.905021f, 0.936508f, 0.968254f, 1.000000f, + 0.000000f, 0.000000f, 0.000000f, 0.000642f, 0.003053f, 0.007010f, 0.012219f, 0.018462f, + 0.025577f, 0.033444f, 0.041970f, 0.051082f, 0.060724f, 0.070849f, 0.081417f, 0.092397f, + 0.103763f, 0.115491f, 0.127562f, 0.139960f, 0.152670f, 0.165679f, 0.178979f, 0.192558f, + 0.206410f, 0.220529f, 0.234907f, 0.249542f, 0.264428f, 0.279564f, 0.294947f, 0.310575f, + 0.326448f, 0.342566f, 0.358929f, 0.375540f, 0.392399f, 0.409511f, 0.426878f, 0.444506f, + 0.462400f, 0.480566f, 0.499013f, 0.517749f, 0.536785f, 0.556134f, 0.575809f, 0.595827f, + 0.616207f, 0.636973f, 0.658150f, 0.679772f, 0.701876f, 0.724509f, 0.747730f, 0.771609f, + 0.796240f, 0.821743f, 0.848280f, 0.876069f, 0.905404f, 0.936508f, 0.968254f, 1.000000f, + 0.000000f, 0.000000f, 0.000020f, 0.001278f, 0.004450f, 0.009147f, 0.015050f, 0.021937f, + 0.029649f, 0.038068f, 0.047106f, 0.056694f, 0.066777f, 0.077310f, 0.088257f, 0.099588f, + 0.111277f, 0.123304f, 0.135650f, 0.148299f, 0.161237f, 0.174455f, 0.187941f, 0.201687f, + 0.215687f, 0.229933f, 0.244420f, 0.259145f, 0.274103f, 0.289293f, 0.304711f, 0.320357f, + 0.336230f, 0.352330f, 0.368658f, 0.385214f, 0.402002f, 0.419023f, 0.436282f, 0.453782f, + 0.471529f, 0.489528f, 0.507788f, 0.526317f, 0.545124f, 0.564221f, 0.583621f, 0.603341f, + 0.623397f, 0.643812f, 0.664611f, 0.685824f, 0.707488f, 0.729646f, 0.752354f, 0.775680f, + 0.799715f, 0.824574f, 0.850417f, 0.877466f, 0.906040f, 0.936528f, 0.968254f, 1.000000f, + 0.000000f, 0.000000f, 0.000183f, 0.002253f, 0.006282f, 0.011786f, 0.018436f, 0.026011f, + 0.034358f, 0.043364f, 0.052944f, 0.063033f, 0.073580f, 0.084544f, 0.095889f, 0.107588f, + 0.119617f, 0.131957f, 0.144591f, 0.157503f, 0.170682f, 0.184117f, 0.197799f, 0.211720f, + 0.225873f, 0.240253f, 0.254854f, 0.269673f, 0.284707f, 0.299953f, 0.315408f, 0.331073f, + 0.346946f, 0.363028f, 0.379318f, 0.395818f, 0.412530f, 0.429457f, 0.446602f, 0.463968f, + 0.481561f, 0.499386f, 0.517450f, 0.535761f, 0.554328f, 0.573162f, 0.592275f, 0.611681f, + 0.631398f, 0.651445f, 0.671845f, 0.692628f, 0.713827f, 0.735484f, 0.757650f, 0.780390f, + 0.803789f, 0.827960f, 0.853056f, 0.879298f, 0.907014f, 0.936691f, 0.968254f, 1.000000f, + 0.000000f, 0.000000f, 0.000617f, 0.003679f, 0.008674f, 0.015068f, 0.022531f, 0.030851f, + 0.039880f, 0.049515f, 0.059675f, 0.070300f, 0.081343f, 0.092764f, 0.104533f, 0.116624f, + 0.129015f, 0.141687f, 0.154626f, 0.167818f, 0.181252f, 0.194918f, 0.208807f, 0.222913f, + 0.237229f, 0.251750f, 0.266473f, 0.281392f, 0.296505f, 0.311811f, 0.327306f, 0.342991f, + 0.358864f, 0.374925f, 0.391176f, 0.407616f, 0.424249f, 0.441076f, 0.458100f, 0.475324f, + 0.492754f, 0.510394f, 0.528251f, 0.546331f, 0.564644f, 0.583198f, 0.602005f, 0.621078f, + 0.640434f, 0.660089f, 0.680066f, 0.700390f, 0.721094f, 0.742215f, 0.763800f, 0.785912f, + 0.808628f, 0.832055f, 0.856338f, 0.881690f, 0.908441f, 0.937125f, 0.968254f, 1.000000f, + 0.000000f, 0.000000f, 0.001477f, 0.005732f, 0.011826f, 0.019212f, 0.027573f, 0.036710f, + 0.046487f, 0.056807f, 0.067598f, 0.078806f, 0.090386f, 0.102304f, 0.114532f, 0.127047f, + 0.139828f, 0.152861f, 0.166130f, 0.179624f, 0.193332f, 0.207247f, 0.221360f, 0.235666f, + 0.250158f, 0.264832f, 0.279684f, 0.294711f, 0.309911f, 0.325280f, 0.340819f, 0.356524f, + 0.372397f, 0.388438f, 0.404645f, 0.421022f, 0.437569f, 0.454287f, 0.471181f, 0.488253f, + 0.505507f, 0.522947f, 0.540580f, 0.558412f, 0.576449f, 0.594701f, 0.613178f, 0.631892f, + 0.650856f, 0.670088f, 0.689606f, 0.709434f, 0.729600f, 0.750138f, 0.771093f, 0.792519f, + 0.814488f, 0.837097f, 0.860481f, 0.884842f, 0.910494f, 0.937985f, 0.968254f, 1.000000f, + 0.000000f, 0.000096f, 0.003012f, 0.008704f, 0.016071f, 0.024590f, 0.033968f, 0.044025f, + 0.054641f, 0.065728f, 0.077225f, 0.089081f, 0.101260f, 0.113731f, 0.126469f, 0.139454f, + 0.152670f, 0.166101f, 0.179736f, 0.193565f, 0.207578f, 0.221769f, 0.236130f, 0.250656f, + 0.265343f, 0.280187f, 0.295183f, 0.310330f, 0.325624f, 0.341065f, 0.356650f, 0.372380f, + 0.388253f, 0.404269f, 0.420430f, 0.436735f, 0.453187f, 0.469786f, 0.486536f, 0.503439f, + 0.520498f, 0.537717f, 0.555102f, 0.572657f, 0.590390f, 0.608307f, 0.626419f, 0.644733f, + 0.663264f, 0.682025f, 0.701032f, 0.720308f, 0.739875f, 0.759764f, 0.780014f, 0.800673f, + 0.821803f, 0.843492f, 0.865860f, 0.889087f, 0.913466f, 0.939520f, 0.968350f, 1.000000f, + 0.000000f, 0.000727f, 0.005696f, 0.013170f, 0.022074f, 0.031940f, 0.042520f, 0.053660f, + 0.065258f, 0.077243f, 0.089562f, 0.102175f, 0.115050f, 0.128164f, 0.141495f, 0.155026f, + 0.168745f, 0.182639f, 0.196699f, 0.210915f, 0.225282f, 0.239792f, 0.254440f, 0.269223f, + 0.284135f, 0.299174f, 0.314337f, 0.329622f, 0.345026f, 0.360549f, 0.376189f, 0.391946f, + 0.407819f, 0.423808f, 0.439914f, 0.456137f, 0.472479f, 0.488940f, 0.505523f, 0.522230f, + 0.539064f, 0.556028f, 0.573125f, 0.590361f, 0.607741f, 0.625270f, 0.642957f, 0.660809f, + 0.678836f, 0.697050f, 0.715465f, 0.734098f, 0.752968f, 0.772101f, 0.791529f, 0.811290f, + 0.831438f, 0.852044f, 0.873210f, 0.895090f, 0.917932f, 0.942204f, 0.968981f, 1.000000f, + 0.000000f, 0.002796f, 0.010764f, 0.020645f, 0.031576f, 0.043202f, 0.055340f, 0.067877f, + 0.080740f, 0.093877f, 0.107250f, 0.120832f, 0.134598f, 0.148533f, 0.162620f, 0.176849f, + 0.191210f, 0.205694f, 0.220294f, 0.235005f, 0.249820f, 0.264737f, 0.279751f, 0.294859f, + 0.310058f, 0.325346f, 0.340721f, 0.356181f, 0.371725f, 0.387353f, 0.403063f, 0.418854f, + 0.434727f, 0.450682f, 0.466718f, 0.482837f, 0.499038f, 0.515324f, 0.531695f, 0.548153f, + 0.564700f, 0.581338f, 0.598070f, 0.614900f, 0.631830f, 0.648865f, 0.666011f, 0.683273f, + 0.700659f, 0.718176f, 0.735834f, 0.753646f, 0.771625f, 0.789790f, 0.808162f, 0.826771f, + 0.845654f, 0.864863f, 0.884472f, 0.904592f, 0.925407f, 0.947271f, 0.971050f, 1.000000f, + 0.000000f, 0.015873f, 0.031746f, 0.047619f, 0.063492f, 0.079365f, 0.095238f, 0.111111f, + 0.126984f, 0.142857f, 0.158730f, 0.174603f, 0.190476f, 0.206349f, 0.222222f, 0.238095f, + 0.253968f, 0.269841f, 0.285714f, 0.301587f, 0.317460f, 0.333333f, 0.349206f, 0.365079f, + 0.380952f, 0.396825f, 0.412698f, 0.428571f, 0.444444f, 0.460317f, 0.476190f, 0.492063f, + 0.507937f, 0.523810f, 0.539683f, 0.555556f, 0.571429f, 0.587302f, 0.603175f, 0.619048f, + 0.634921f, 0.650794f, 0.666667f, 0.682540f, 0.698413f, 0.714286f, 0.730159f, 0.746032f, + 0.761905f, 0.777778f, 0.793651f, 0.809524f, 0.825397f, 0.841270f, 0.857143f, 0.873016f, + 0.888889f, 0.904762f, 0.920635f, 0.936508f, 0.952381f, 0.968254f, 0.984127f, 1.000000f +}; + static float btdf_split_sum_ggx[32][64 * 64] = { { 0.000000f, 1.000000f, 0.999512f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.999512f, 1.000000f, diff --git a/source/blender/draw/engines/eevee/eevee_materials.c b/source/blender/draw/engines/eevee/eevee_materials.c index c25ab1e7859..84627e03137 100644 --- a/source/blender/draw/engines/eevee/eevee_materials.c +++ b/source/blender/draw/engines/eevee/eevee_materials.c @@ -28,6 +28,8 @@ #include "BLI_dynstr.h" #include "BLI_ghash.h" #include "BLI_alloca.h" +#include "BLI_rand.h" +#include "BLI_string_utils.h" #include "BKE_particle.h" #include "BKE_paint.h" @@ -51,16 +53,18 @@ static struct { struct GPUShader *default_prepass_sh; struct GPUShader *default_prepass_clip_sh; struct GPUShader *default_lit[VAR_MAT_MAX]; - struct GPUShader *default_background; + struct GPUShader *update_noise_sh; /* 64*64 array texture containing all LUTs and other utilitarian arrays. * Packing enables us to same precious textures slots. */ struct GPUTexture *util_tex; + struct GPUTexture *noise_tex; unsigned int sss_count; - float viewvecs[2][4]; + float alpha_hash_offset; + float noise_offsets[3]; } e_data = {NULL}; /* Engine data */ extern char datatoc_lamps_lib_glsl[]; @@ -76,6 +80,7 @@ extern char datatoc_btdf_lut_frag_glsl[]; extern char datatoc_bsdf_common_lib_glsl[]; extern char datatoc_bsdf_direct_lib_glsl[]; extern char datatoc_bsdf_sampling_lib_glsl[]; +extern char datatoc_common_uniforms_lib_glsl[]; extern char datatoc_irradiance_lib_glsl[]; extern char datatoc_octahedron_lib_glsl[]; extern char datatoc_lit_surface_frag_glsl[]; @@ -87,6 +92,7 @@ extern char datatoc_shadow_geom_glsl[]; extern char datatoc_lightprobe_geom_glsl[]; extern char datatoc_lightprobe_vert_glsl[]; extern char datatoc_background_vert_glsl[]; +extern char datatoc_update_noise_frag_glsl[]; extern char datatoc_volumetric_vert_glsl[]; extern char datatoc_volumetric_geom_glsl[]; extern char datatoc_volumetric_frag_glsl[]; @@ -105,13 +111,9 @@ static struct GPUTexture *create_ggx_lut_texture(int UNUSED(w), int UNUSED(h)) static float samples_ct = 8192.0f; static float inv_samples_ct = 1.0f / 8192.0f; - char *lib_str = NULL; - - DynStr *ds_vert = BLI_dynstr_new(); - BLI_dynstr_append(ds_vert, datatoc_bsdf_common_lib_glsl); - BLI_dynstr_append(ds_vert, datatoc_bsdf_sampling_lib_glsl); - lib_str = BLI_dynstr_get_cstring(ds_vert); - BLI_dynstr_free(ds_vert); + char *lib_str = BLI_string_joinN( + datatoc_bsdf_common_lib_glsl, + datatoc_bsdf_sampling_lib_glsl); struct GPUShader *sh = DRW_shader_create_with_lib( datatoc_lightprobe_vert_glsl, datatoc_lightprobe_geom_glsl, datatoc_bsdf_lut_frag_glsl, lib_str, @@ -167,14 +169,10 @@ static struct GPUTexture *create_ggx_refraction_lut_texture(int w, int h) static float a2 = 0.0f; static float inv_samples_ct = 1.0f / 8192.0f; - char *frag_str = NULL; - - DynStr *ds_vert = BLI_dynstr_new(); - BLI_dynstr_append(ds_vert, datatoc_bsdf_common_lib_glsl); - BLI_dynstr_append(ds_vert, datatoc_bsdf_sampling_lib_glsl); - BLI_dynstr_append(ds_vert, datatoc_btdf_lut_frag_glsl); - frag_str = BLI_dynstr_get_cstring(ds_vert); - BLI_dynstr_free(ds_vert); + char *frag_str = BLI_string_joinN( + datatoc_bsdf_common_lib_glsl, + datatoc_bsdf_sampling_lib_glsl, + datatoc_btdf_lut_frag_glsl); struct GPUShader *sh = DRW_shader_create_fullscreen(frag_str, "#define HAMMERSLEY_SIZE 8192\n" @@ -352,77 +350,67 @@ static char *eevee_get_volume_defines(int options) **/ static void add_standard_uniforms( DRWShadingGroup *shgrp, EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, - int *ssr_id, float *refract_depth, bool use_ssrefraction, bool use_alpha_blend, bool use_sss) + int *ssr_id, float *refract_depth, bool use_ssrefraction, bool use_alpha_blend) { - if (ssr_id == NULL || !vedata->stl->g_data->valid_double_buffer) { + if (ssr_id == NULL) { static int no_ssr = -1.0f; ssr_id = &no_ssr; } + DRW_shgroup_uniform_block(shgrp, "probe_block", sldata->probe_ubo); DRW_shgroup_uniform_block(shgrp, "grid_block", sldata->grid_ubo); DRW_shgroup_uniform_block(shgrp, "planar_block", sldata->planar_ubo); DRW_shgroup_uniform_block(shgrp, "light_block", sldata->light_ubo); DRW_shgroup_uniform_block(shgrp, "shadow_block", sldata->shadow_ubo); - DRW_shgroup_uniform_int(shgrp, "light_count", &sldata->lamps->num_light, 1); - DRW_shgroup_uniform_int(shgrp, "probe_count", &sldata->probes->num_render_cube, 1); - DRW_shgroup_uniform_int(shgrp, "grid_count", &sldata->probes->num_render_grid, 1); - DRW_shgroup_uniform_int(shgrp, "planar_count", &sldata->probes->num_planar, 1); - DRW_shgroup_uniform_bool(shgrp, "specToggle", &sldata->probes->specular_toggle, 1); - DRW_shgroup_uniform_bool(shgrp, "ssrToggle", &sldata->probes->ssr_toggle, 1); - DRW_shgroup_uniform_float(shgrp, "lodCubeMax", &sldata->probes->lod_cube_max, 1); - DRW_shgroup_uniform_texture(shgrp, "utilTex", e_data.util_tex); - DRW_shgroup_uniform_buffer(shgrp, "probeCubes", &sldata->probe_pool); - DRW_shgroup_uniform_buffer(shgrp, "probePlanars", &vedata->txl->planar_pool); - DRW_shgroup_uniform_buffer(shgrp, "irradianceGrid", &sldata->irradiance_pool); - DRW_shgroup_uniform_int(shgrp, "irradianceVisibilitySize", &sldata->probes->irradiance_vis_size, 1); - DRW_shgroup_uniform_buffer(shgrp, "shadowTexture", &sldata->shadow_pool); - DRW_shgroup_uniform_int(shgrp, "outputSsrId", ssr_id, 1); - DRW_shgroup_uniform_vec4(shgrp, "aoParameters[0]", &vedata->stl->effects->ao_dist, 2); - DRW_shgroup_uniform_vec4(shgrp, "viewvecs[0]", (float *)vedata->stl->g_data->viewvecs, 2); - DRW_shgroup_uniform_buffer(shgrp, "maxzBuffer", &vedata->txl->maxzbuffer); - DRW_shgroup_uniform_vec2(shgrp, "mipRatio[0]", (float *)vedata->stl->g_data->mip_ratio, 10); - DRW_shgroup_uniform_vec4(shgrp, "ssrParameters", &vedata->stl->effects->ssr_quality, 1); - - if (refract_depth != NULL) { - DRW_shgroup_uniform_float(shgrp, "refractionDepth", refract_depth, 1); + DRW_shgroup_uniform_block(shgrp, "common_block", sldata->common_ubo); + + /* TODO if glossy or diffuse bsdf */ + if (true) { + DRW_shgroup_uniform_texture(shgrp, "utilTex", e_data.util_tex); + DRW_shgroup_uniform_buffer(shgrp, "shadowTexture", &sldata->shadow_pool); + DRW_shgroup_uniform_buffer(shgrp, "maxzBuffer", &vedata->txl->maxzbuffer); + + if ((vedata->stl->effects->enabled_effects & EFFECT_GTAO) != 0) { + DRW_shgroup_uniform_buffer(shgrp, "horizonBuffer", &vedata->txl->gtao_horizons); + } + else { + /* Use maxzbuffer as fallback to avoid sampling problem on certain platform, see: T52593 */ + DRW_shgroup_uniform_buffer(shgrp, "horizonBuffer", &vedata->txl->maxzbuffer); + } } - if (use_ssrefraction) { - DRW_shgroup_uniform_buffer(shgrp, "colorBuffer", &vedata->txl->refract_color); - DRW_shgroup_uniform_float(shgrp, "borderFadeFactor", &vedata->stl->effects->ssr_border_fac, 1); - DRW_shgroup_uniform_float(shgrp, "maxRoughness", &vedata->stl->effects->ssr_max_roughness, 1); - DRW_shgroup_uniform_int(shgrp, "rayCount", &vedata->stl->effects->ssr_ray_count, 1); + /* TODO if diffuse bsdf */ + if (true) { + DRW_shgroup_uniform_buffer(shgrp, "irradianceGrid", &sldata->irradiance_pool); } - if (vedata->stl->effects->use_ao) { - DRW_shgroup_uniform_buffer(shgrp, "horizonBuffer", &vedata->txl->gtao_horizons); - DRW_shgroup_uniform_ivec2(shgrp, "aoHorizonTexSize", (int *)vedata->stl->effects->ao_texsize, 1); + /* TODO if glossy bsdf */ + if (true) { + DRW_shgroup_uniform_buffer(shgrp, "probeCubes", &sldata->probe_pool); + DRW_shgroup_uniform_buffer(shgrp, "probePlanars", &vedata->txl->planar_pool); + DRW_shgroup_uniform_int(shgrp, "outputSsrId", ssr_id, 1); } - else { - /* Use shadow_pool as fallback to avoid sampling problem on certain platform, see: T52593 */ - DRW_shgroup_uniform_buffer(shgrp, "horizonBuffer", &sldata->shadow_pool); + + if (use_ssrefraction) { + BLI_assert(refract_depth != NULL); + DRW_shgroup_uniform_float(shgrp, "refractionDepth", refract_depth, 1); + DRW_shgroup_uniform_buffer(shgrp, "colorBuffer", &vedata->txl->refract_color); } - if (vedata->stl->effects->use_volumetrics && use_alpha_blend) { + if ((vedata->stl->effects->enabled_effects & EFFECT_VOLUMETRIC) != 0 && + use_alpha_blend) + { /* Do not use history buffers as they already have been swapped */ DRW_shgroup_uniform_buffer(shgrp, "inScattering", &vedata->txl->volume_scatter); DRW_shgroup_uniform_buffer(shgrp, "inTransmittance", &vedata->txl->volume_transmittance); - DRW_shgroup_uniform_vec2(shgrp, "volume_uv_ratio", (float *)sldata->volumetrics->volume_coord_scale, 1); - DRW_shgroup_uniform_vec3(shgrp, "volume_param", (float *)sldata->volumetrics->depth_param, 1); - } - - if (use_sss) { - DRW_shgroup_uniform_bool(shgrp, "sssToggle", &sldata->probes->sss_toggle, 1); } } static void create_default_shader(int options) { - DynStr *ds_frag = BLI_dynstr_new(); - BLI_dynstr_append(ds_frag, e_data.frag_shader_lib); - BLI_dynstr_append(ds_frag, datatoc_default_frag_glsl); - char *frag_str = BLI_dynstr_get_cstring(ds_frag); - BLI_dynstr_free(ds_frag); + char *frag_str = BLI_string_joinN( + e_data.frag_shader_lib, + datatoc_default_frag_glsl); char *defines = eevee_get_defines(options); @@ -432,11 +420,13 @@ static void create_default_shader(int options) MEM_freeN(frag_str); } -void EEVEE_update_util_texture(float offset) +static void eevee_init_noise_texture(void) { + e_data.noise_tex = DRW_texture_create_2D(64, 64, DRW_TEX_RGBA_16, 0, (float *)blue_noise); +} - /* TODO: split this into 2 functions : one for init, - * and the other one that updates the noise with the offset. */ +static void eevee_init_util_texture(void) +{ const int layers = 3 + 16; float (*texels)[4] = MEM_mallocN(sizeof(float[4]) * 64 * 64 * layers, "utils texels"); float (*texels_layer)[4] = texels; @@ -451,19 +441,16 @@ void EEVEE_update_util_texture(float offset) texels_layer[i][0] = bsdf_split_sum_ggx[i * 2 + 0]; texels_layer[i][1] = bsdf_split_sum_ggx[i * 2 + 1]; texels_layer[i][2] = ltc_mag_ggx[i]; + texels_layer[i][3] = ltc_disk_integral[i]; } texels_layer += 64 * 64; /* Copy blue noise in 3rd layer */ for (int i = 0; i < 64 * 64; i++) { - float noise; - noise = fmod(blue_noise[i][0] + offset, 1.0f); - texels_layer[i][0] = noise; - - noise = fmod(blue_noise[i][1] + offset, 1.0f); - texels_layer[i][1] = noise * 0.5f + 0.5f; - texels_layer[i][2] = cosf(noise * 2.0f * M_PI); - texels_layer[i][3] = sinf(noise * 2.0f * M_PI); + texels_layer[i][0] = blue_noise[i][0]; + texels_layer[i][1] = blue_noise[i][1]; + texels_layer[i][2] = cosf(blue_noise[i][1] * 2.0f * M_PI); + texels_layer[i][3] = sinf(blue_noise[i][1] * 2.0f * M_PI); } texels_layer += 64 * 64; @@ -478,62 +465,72 @@ void EEVEE_update_util_texture(float offset) texels_layer += 64 * 64; } - if (e_data.util_tex == NULL) { - e_data.util_tex = DRW_texture_create_2D_array( - 64, 64, layers, DRW_TEX_RGBA_16, DRW_TEX_FILTER | DRW_TEX_WRAP, (float *)texels); - } - else { - DRW_texture_update(e_data.util_tex, (float *)texels); - } + e_data.util_tex = DRW_texture_create_2D_array( + 64, 64, layers, DRW_TEX_RGBA_16, DRW_TEX_FILTER | DRW_TEX_WRAP, (float *)texels); MEM_freeN(texels); } -void EEVEE_materials_init(EEVEE_StorageList *stl) +void EEVEE_update_noise(EEVEE_PassList *psl, EEVEE_FramebufferList *fbl, double offsets[3]) +{ + e_data.noise_offsets[0] = offsets[0]; + e_data.noise_offsets[1] = offsets[1]; + e_data.noise_offsets[2] = offsets[2]; + + /* Attach & detach because we don't currently support multiple FB per texture, + * and this would be the case for multiple viewport. */ + DRW_framebuffer_texture_layer_attach(fbl->update_noise_fb, e_data.util_tex, 0, 2, 0); + DRW_framebuffer_bind(fbl->update_noise_fb); + DRW_draw_pass(psl->update_noise_pass); + DRW_framebuffer_texture_detach(e_data.util_tex); +} + +void EEVEE_materials_init(EEVEE_ViewLayerData *sldata, EEVEE_StorageList *stl, EEVEE_FramebufferList *fbl) { if (!e_data.frag_shader_lib) { char *frag_str = NULL; /* Shaders */ - DynStr *ds_frag = BLI_dynstr_new(); - BLI_dynstr_append(ds_frag, datatoc_bsdf_common_lib_glsl); - BLI_dynstr_append(ds_frag, datatoc_bsdf_sampling_lib_glsl); - BLI_dynstr_append(ds_frag, datatoc_ambient_occlusion_lib_glsl); - BLI_dynstr_append(ds_frag, datatoc_raytrace_lib_glsl); - BLI_dynstr_append(ds_frag, datatoc_ssr_lib_glsl); - BLI_dynstr_append(ds_frag, datatoc_octahedron_lib_glsl); - BLI_dynstr_append(ds_frag, datatoc_irradiance_lib_glsl); - BLI_dynstr_append(ds_frag, datatoc_lightprobe_lib_glsl); - BLI_dynstr_append(ds_frag, datatoc_ltc_lib_glsl); - BLI_dynstr_append(ds_frag, datatoc_bsdf_direct_lib_glsl); - BLI_dynstr_append(ds_frag, datatoc_lamps_lib_glsl); - for (int i = 0; i < 7; ++i) { - /* Add one for each Closure */ - BLI_dynstr_append(ds_frag, datatoc_lit_surface_frag_glsl); - } - BLI_dynstr_append(ds_frag, datatoc_volumetric_lib_glsl); - e_data.frag_shader_lib = BLI_dynstr_get_cstring(ds_frag); - BLI_dynstr_free(ds_frag); - - ds_frag = BLI_dynstr_new(); - BLI_dynstr_append(ds_frag, datatoc_bsdf_common_lib_glsl); - BLI_dynstr_append(ds_frag, datatoc_ambient_occlusion_lib_glsl); - BLI_dynstr_append(ds_frag, datatoc_octahedron_lib_glsl); - BLI_dynstr_append(ds_frag, datatoc_irradiance_lib_glsl); - BLI_dynstr_append(ds_frag, datatoc_lightprobe_lib_glsl); - BLI_dynstr_append(ds_frag, datatoc_ltc_lib_glsl); - BLI_dynstr_append(ds_frag, datatoc_bsdf_direct_lib_glsl); - BLI_dynstr_append(ds_frag, datatoc_lamps_lib_glsl); - BLI_dynstr_append(ds_frag, datatoc_volumetric_lib_glsl); - BLI_dynstr_append(ds_frag, datatoc_volumetric_frag_glsl); - e_data.volume_shader_lib = BLI_dynstr_get_cstring(ds_frag); - BLI_dynstr_free(ds_frag); - - ds_frag = BLI_dynstr_new(); - BLI_dynstr_append(ds_frag, e_data.frag_shader_lib); - BLI_dynstr_append(ds_frag, datatoc_default_frag_glsl); - frag_str = BLI_dynstr_get_cstring(ds_frag); - BLI_dynstr_free(ds_frag); + e_data.frag_shader_lib = BLI_string_joinN( + datatoc_common_uniforms_lib_glsl, + datatoc_bsdf_common_lib_glsl, + datatoc_bsdf_sampling_lib_glsl, + datatoc_ambient_occlusion_lib_glsl, + datatoc_raytrace_lib_glsl, + datatoc_ssr_lib_glsl, + datatoc_octahedron_lib_glsl, + datatoc_irradiance_lib_glsl, + datatoc_lightprobe_lib_glsl, + datatoc_ltc_lib_glsl, + datatoc_bsdf_direct_lib_glsl, + datatoc_lamps_lib_glsl, + /* Add one for each Closure */ + datatoc_lit_surface_frag_glsl, + datatoc_lit_surface_frag_glsl, + datatoc_lit_surface_frag_glsl, + datatoc_lit_surface_frag_glsl, + datatoc_lit_surface_frag_glsl, + datatoc_lit_surface_frag_glsl, + datatoc_lit_surface_frag_glsl, + datatoc_lit_surface_frag_glsl, + datatoc_volumetric_lib_glsl); + + e_data.volume_shader_lib = BLI_string_joinN( + datatoc_common_uniforms_lib_glsl, + datatoc_bsdf_common_lib_glsl, + datatoc_ambient_occlusion_lib_glsl, + datatoc_octahedron_lib_glsl, + datatoc_irradiance_lib_glsl, + datatoc_lightprobe_lib_glsl, + datatoc_ltc_lib_glsl, + datatoc_bsdf_direct_lib_glsl, + datatoc_lamps_lib_glsl, + datatoc_volumetric_lib_glsl, + datatoc_volumetric_frag_glsl); + + frag_str = BLI_string_joinN( + e_data.frag_shader_lib, + datatoc_default_frag_glsl); e_data.default_background = DRW_shader_create( datatoc_background_vert_glsl, NULL, datatoc_default_world_frag_glsl, @@ -549,16 +546,32 @@ void EEVEE_materials_init(EEVEE_StorageList *stl) MEM_freeN(frag_str); - EEVEE_update_util_texture(0.0f); + e_data.update_noise_sh = DRW_shader_create_fullscreen( + datatoc_update_noise_frag_glsl, NULL); + + eevee_init_util_texture(); + eevee_init_noise_texture(); } + /* Alpha hash scale: Non-flickering size if we are not refining the render. */ + if (!DRW_state_is_image_render() && + (((stl->effects->enabled_effects & EFFECT_TAA) == 0) || + (stl->effects->taa_current_sample == 1))) { - /* Update viewvecs */ - const bool is_persp = DRW_viewport_is_persp_get(); + e_data.alpha_hash_offset = 0.0f; + } + else { + double r; + BLI_halton_1D(5, 0.0, stl->effects->taa_current_sample, &r); + e_data.alpha_hash_offset = (float)r; + } + + { + /* Update view_vecs */ float invproj[4][4], winmat[4][4]; /* view vectors for the corners of the view frustum. * Can be used to recreate the world space position easily */ - float viewvecs[3][4] = { + float view_vecs[3][4] = { {-1.0f, -1.0f, -1.0f, 1.0f}, {1.0f, -1.0f, -1.0f, 1.0f}, {-1.0f, 1.0f, -1.0f, 1.0f} @@ -567,31 +580,39 @@ void EEVEE_materials_init(EEVEE_StorageList *stl) /* invert the view matrix */ DRW_viewport_matrix_get(winmat, DRW_MAT_WIN); invert_m4_m4(invproj, winmat); + const bool is_persp = (winmat[3][3] == 0.0f); /* convert the view vectors to view space */ for (int i = 0; i < 3; i++) { - mul_m4_v4(invproj, viewvecs[i]); + mul_m4_v4(invproj, view_vecs[i]); /* normalized trick see: * http://www.derschmale.com/2014/01/26/reconstructing-positions-from-the-depth-buffer */ - mul_v3_fl(viewvecs[i], 1.0f / viewvecs[i][3]); + mul_v3_fl(view_vecs[i], 1.0f / view_vecs[i][3]); if (is_persp) - mul_v3_fl(viewvecs[i], 1.0f / viewvecs[i][2]); - viewvecs[i][3] = 1.0; + mul_v3_fl(view_vecs[i], 1.0f / view_vecs[i][2]); + view_vecs[i][3] = 1.0; } - copy_v4_v4(stl->g_data->viewvecs[0], viewvecs[0]); - copy_v4_v4(stl->g_data->viewvecs[1], viewvecs[1]); + copy_v4_v4(sldata->common_data.view_vecs[0], view_vecs[0]); + copy_v4_v4(sldata->common_data.view_vecs[1], view_vecs[1]); /* we need to store the differences */ - stl->g_data->viewvecs[1][0] -= viewvecs[0][0]; - stl->g_data->viewvecs[1][1] = viewvecs[2][1] - viewvecs[0][1]; + sldata->common_data.view_vecs[1][0] -= view_vecs[0][0]; + sldata->common_data.view_vecs[1][1] = view_vecs[2][1] - view_vecs[0][1]; /* calculate a depth offset as well */ if (!is_persp) { float vec_far[] = {-1.0f, -1.0f, 1.0f, 1.0f}; mul_m4_v4(invproj, vec_far); mul_v3_fl(vec_far, 1.0f / vec_far[3]); - stl->g_data->viewvecs[1][2] = vec_far[2] - viewvecs[0][2]; + sldata->common_data.view_vecs[1][2] = vec_far[2] - view_vecs[0][2]; + } + } + + { + /* Update noise Framebuffer. */ + if (fbl->update_noise_fb == NULL) { + fbl->update_noise_fb = DRW_framebuffer_create(); } } } @@ -652,6 +673,7 @@ struct GPUMaterial *EEVEE_material_mesh_get( struct Scene *scene, Material *ma, EEVEE_Data *vedata, bool use_blend, bool use_multiply, bool use_refract, bool use_sss, bool use_translucency, int shadow_method) { + EEVEE_EffectsInfo *effects = vedata->stl->effects; const void *engine = &DRW_engine_viewport_eevee_type; int options = VAR_MAT_MESH; @@ -659,9 +681,9 @@ struct GPUMaterial *EEVEE_material_mesh_get( if (use_multiply) options |= VAR_MAT_MULT; if (use_refract) options |= VAR_MAT_REFRACT; if (use_sss) options |= VAR_MAT_SSS; - if (use_sss && vedata->stl->effects->sss_separate_albedo) options |= VAR_MAT_SSSALBED; + if (use_sss && effects->sss_separate_albedo) options |= VAR_MAT_SSSALBED; if (use_translucency) options |= VAR_MAT_TRANSLUC; - if (vedata->stl->effects->use_volumetrics && use_blend) options |= VAR_MAT_VOLUME; + if (((effects->enabled_effects & EFFECT_VOLUMETRIC) != 0) && use_blend) options |= VAR_MAT_VOLUME; options |= eevee_material_shadow_option(shadow_method); @@ -728,11 +750,9 @@ struct GPUMaterial *EEVEE_material_mesh_depth_get( char *defines = eevee_get_defines(options); - DynStr *ds_frag = BLI_dynstr_new(); - BLI_dynstr_append(ds_frag, e_data.frag_shader_lib); - BLI_dynstr_append(ds_frag, datatoc_prepass_frag_glsl); - char *frag_str = BLI_dynstr_get_cstring(ds_frag); - BLI_dynstr_free(ds_frag); + char *frag_str = BLI_string_joinN( + e_data.frag_shader_lib, + datatoc_prepass_frag_glsl); mat = GPU_material_from_nodetree( scene, ma->nodetree, &ma->gpumaterial, engine, options, @@ -779,6 +799,7 @@ static struct DRWShadingGroup *EEVEE_default_shading_group_create( EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, DRWPass *pass, bool is_hair, bool is_flat_normal, bool use_blend, bool use_ssr, int shadow_method) { + EEVEE_EffectsInfo *effects = vedata->stl->effects; static int ssr_id; ssr_id = (use_ssr) ? 1 : -1; int options = VAR_MAT_MESH; @@ -786,7 +807,7 @@ static struct DRWShadingGroup *EEVEE_default_shading_group_create( if (is_hair) options |= VAR_MAT_HAIR; if (is_flat_normal) options |= VAR_MAT_FLAT; if (use_blend) options |= VAR_MAT_BLEND; - if (vedata->stl->effects->use_volumetrics && use_blend) options |= VAR_MAT_VOLUME; + if (((effects->enabled_effects & EFFECT_VOLUMETRIC) != 0) && use_blend) options |= VAR_MAT_VOLUME; options |= eevee_material_shadow_option(shadow_method); @@ -795,7 +816,7 @@ static struct DRWShadingGroup *EEVEE_default_shading_group_create( } DRWShadingGroup *shgrp = DRW_shgroup_create(e_data.default_lit[options], pass); - add_standard_uniforms(shgrp, sldata, vedata, &ssr_id, NULL, false, use_blend, false); + add_standard_uniforms(shgrp, sldata, vedata, &ssr_id, NULL, false, use_blend); return shgrp; } @@ -825,7 +846,7 @@ static struct DRWShadingGroup *EEVEE_default_shading_group_get( vedata->psl->default_pass[options] = DRW_pass_create("Default Lit Pass", state); DRWShadingGroup *shgrp = DRW_shgroup_create(e_data.default_lit[options], vedata->psl->default_pass[options]); - add_standard_uniforms(shgrp, sldata, vedata, &ssr_id, NULL, false, false, false); + add_standard_uniforms(shgrp, sldata, vedata, &ssr_id, NULL, false, false); } return DRW_shgroup_create(e_data.default_lit[options], vedata->psl->default_pass[options]); @@ -836,19 +857,6 @@ void EEVEE_materials_cache_init(EEVEE_Data *vedata) EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl; EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl; - { - const DRWContextState *draw_ctx = DRW_context_state_get(); - ViewLayer *view_layer = draw_ctx->view_layer; - IDProperty *props = BKE_view_layer_engine_evaluated_get(view_layer, COLLECTION_MODE_NONE, RE_engine_id_BLENDER_EEVEE); - /* Global AO Switch*/ - stl->effects->use_ao = BKE_collection_engine_property_value_get_bool(props, "gtao_enable"); - stl->effects->use_bent_normals = BKE_collection_engine_property_value_get_bool(props, "gtao_use_bent_normals"); - /* SSR switch */ - stl->effects->use_ssr = BKE_collection_engine_property_value_get_bool(props, "ssr_enable"); - /* Volumetrics */ - stl->effects->use_volumetrics = BKE_collection_engine_property_value_get_bool(props, "volumetric_enable"); - } - /* Create Material Ghash */ { stl->g_data->material_hash = BLI_ghash_ptr_new("Eevee_material ghash"); @@ -951,6 +959,15 @@ void EEVEE_materials_cache_init(EEVEE_Data *vedata) DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS | DRW_STATE_CLIP_PLANES | DRW_STATE_WIRE; psl->transparent_pass = DRW_pass_create("Material Transparent Pass", state); } + + { + psl->update_noise_pass = DRW_pass_create("Update Noise Pass", DRW_STATE_WRITE_COLOR); + DRWShadingGroup *grp = DRW_shgroup_create(e_data.update_noise_sh, psl->update_noise_pass); + DRW_shgroup_uniform_texture(grp, "blueNoise", e_data.noise_tex); + DRW_shgroup_uniform_vec3(grp, "offsets", e_data.noise_offsets, 1); + DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL); + } + } #define ADD_SHGROUP_CALL(shgrp, ob, geom) do { \ @@ -979,6 +996,7 @@ static void material_opaque( bool do_cull, bool use_flat_nor, struct GPUMaterial **gpumat, struct GPUMaterial **gpumat_depth, struct DRWShadingGroup **shgrp, struct DRWShadingGroup **shgrp_depth, struct DRWShadingGroup **shgrp_depth_clip) { + EEVEE_EffectsInfo *effects = vedata->stl->effects; const DRWContextState *draw_ctx = DRW_context_state_get(); Scene *scene = draw_ctx->scene; EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl; @@ -991,9 +1009,11 @@ static void material_opaque( float *rough_p = &ma->gloss_mir; const bool use_gpumat = (ma->use_nodes && ma->nodetree); - const bool use_refract = ((ma->blend_flag & MA_BL_SS_REFRACTION) != 0) && ((stl->effects->enabled_effects & EFFECT_REFRACT) != 0); - const bool use_sss = ((ma->blend_flag & MA_BL_SS_SUBSURFACE) != 0) && ((stl->effects->enabled_effects & EFFECT_SSS) != 0); - const bool use_translucency = ((ma->blend_flag & MA_BL_TRANSLUCENCY) != 0) && ((stl->effects->enabled_effects & EFFECT_SSS) != 0); + const bool use_refract = ((ma->blend_flag & MA_BL_SS_REFRACTION) != 0) && + ((effects->enabled_effects & EFFECT_REFRACT) != 0); + const bool use_sss = ((ma->blend_flag & MA_BL_SS_SUBSURFACE) != 0) && + ((effects->enabled_effects & EFFECT_SSS) != 0); + const bool use_translucency = use_sss && ((ma->blend_flag & MA_BL_TRANSLUCENCY) != 0); EeveeMaterialShadingGroups *emsg = BLI_ghash_lookup(material_hash, (const void *)ma); @@ -1021,8 +1041,8 @@ static void material_opaque( if (*shgrp) { static int no_ssr = -1; static int first_ssr = 1; - int *ssr_id = (stl->effects->use_ssr && !use_refract) ? &first_ssr : &no_ssr; - add_standard_uniforms(*shgrp, sldata, vedata, ssr_id, &ma->refract_depth, use_refract, false, use_sss); + int *ssr_id = (((effects->enabled_effects & EFFECT_SSR) != 0) && !use_refract) ? &first_ssr : &no_ssr; + add_standard_uniforms(*shgrp, sldata, vedata, ssr_id, &ma->refract_depth, use_refract, false); if (use_sss) { struct GPUTexture *sss_tex_profile = NULL; @@ -1037,7 +1057,7 @@ static void material_opaque( } DRW_shgroup_stencil_mask(*shgrp, e_data.sss_count + 1); - EEVEE_subsurface_add_pass(vedata, e_data.sss_count + 1, sss_profile); + EEVEE_subsurface_add_pass(sldata, vedata, e_data.sss_count + 1, sss_profile); e_data.sss_count++; } } @@ -1067,19 +1087,24 @@ static void material_opaque( } if (*shgrp_depth != NULL) { - add_standard_uniforms(*shgrp_depth, sldata, vedata, NULL, NULL, false, false, false); + add_standard_uniforms(*shgrp_depth, sldata, vedata, NULL, NULL, false, false); if (ma->blend_method == MA_BM_CLIP) { DRW_shgroup_uniform_float(*shgrp_depth, "alphaThreshold", &ma->alpha_threshold, 1); DRW_shgroup_uniform_float(*shgrp_depth_clip, "alphaThreshold", &ma->alpha_threshold, 1); } + else if (ma->blend_method == MA_BM_HASHED) { + DRW_shgroup_uniform_float(*shgrp_depth, "hashAlphaOffset", &e_data.alpha_hash_offset, 1); + DRW_shgroup_uniform_float(*shgrp_depth_clip, "hashAlphaOffset", &e_data.alpha_hash_offset, 1); + } } } } /* Fallback to default shader */ if (*shgrp == NULL) { - *shgrp = EEVEE_default_shading_group_get(sldata, vedata, false, use_flat_nor, stl->effects->use_ssr, linfo->shadow_method); + bool use_ssr = ((effects->enabled_effects & EFFECT_SSR) != 0); + *shgrp = EEVEE_default_shading_group_get(sldata, vedata, false, use_flat_nor, use_ssr, linfo->shadow_method); DRW_shgroup_uniform_vec3(*shgrp, "basecol", color_p, 1); DRW_shgroup_uniform_float(*shgrp, "metallic", metal_p, 1); DRW_shgroup_uniform_float(*shgrp, "specular", spec_p, 1); @@ -1131,7 +1156,7 @@ static void material_transparent( if (*shgrp) { static int ssr_id = -1; /* TODO transparent SSR */ bool use_blend = (ma->blend_method & MA_BM_BLEND) != 0; - add_standard_uniforms(*shgrp, sldata, vedata, &ssr_id, &ma->refract_depth, use_refract, use_blend, false); + add_standard_uniforms(*shgrp, sldata, vedata, &ssr_id, &ma->refract_depth, use_refract, use_blend); } else { /* Shader failed : pink color */ @@ -1217,7 +1242,7 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata, EEVEE_ViewLayerData *sld const bool is_default_mode_shader = is_sculpt_mode; /* First get materials for this mesh. */ - if (ELEM(ob->type, OB_MESH)) { + if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT)) { const int materials_len = MAX2(1, (is_sculpt_mode_draw ? 1 : ob->totcol)); struct DRWShadingGroup **shgrp_array = BLI_array_alloca(shgrp_array, materials_len); @@ -1335,7 +1360,7 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata, EEVEE_ViewLayerData *sld } /* Volumetrics */ - if (vedata->stl->effects->use_volumetrics && use_volume_material) { + if (((stl->effects->enabled_effects & EFFECT_VOLUMETRIC) != 0) && use_volume_material) { EEVEE_volumes_cache_object_add(sldata, vedata, scene, ob); } } @@ -1383,7 +1408,7 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata, EEVEE_ViewLayerData *sld shgrp = DRW_shgroup_material_create(gpumat, psl->material_pass); if (shgrp) { - add_standard_uniforms(shgrp, sldata, vedata, NULL, NULL, false, false, false); + add_standard_uniforms(shgrp, sldata, vedata, NULL, NULL, false, false); BLI_ghash_insert(material_hash, ma, shgrp); @@ -1401,7 +1426,9 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata, EEVEE_ViewLayerData *sld /* Fallback to default shader */ if (shgrp == NULL) { - shgrp = EEVEE_default_shading_group_get(sldata, vedata, true, false, stl->effects->use_ssr, sldata->lamps->shadow_method); + bool use_ssr = ((stl->effects->enabled_effects & EFFECT_SSR) != 0); + shgrp = EEVEE_default_shading_group_get(sldata, vedata, true, false, use_ssr, + sldata->lamps->shadow_method); DRW_shgroup_uniform_vec3(shgrp, "basecol", color_p, 1); DRW_shgroup_uniform_float(shgrp, "metallic", metal_p, 1); DRW_shgroup_uniform_float(shgrp, "specular", spec_p, 1); @@ -1438,7 +1465,9 @@ void EEVEE_materials_free(void) DRW_SHADER_FREE_SAFE(e_data.default_prepass_sh); DRW_SHADER_FREE_SAFE(e_data.default_prepass_clip_sh); DRW_SHADER_FREE_SAFE(e_data.default_background); + DRW_SHADER_FREE_SAFE(e_data.update_noise_sh); DRW_TEXTURE_FREE_SAFE(e_data.util_tex); + DRW_TEXTURE_FREE_SAFE(e_data.noise_tex); } void EEVEE_draw_default_passes(EEVEE_PassList *psl) diff --git a/source/blender/draw/engines/eevee/eevee_motion_blur.c b/source/blender/draw/engines/eevee/eevee_motion_blur.c index d5e0a05f9ed..037bbe3b6c9 100644 --- a/source/blender/draw/engines/eevee/eevee_motion_blur.c +++ b/source/blender/draw/engines/eevee/eevee_motion_blur.c @@ -40,6 +40,7 @@ #include "ED_screen.h" #include "DEG_depsgraph.h" +#include "DEG_depsgraph_query.h" #include "eevee_private.h" #include "GPU_texture.h" @@ -52,7 +53,11 @@ static struct { extern char datatoc_effect_motion_blur_frag_glsl[]; static void eevee_motion_blur_camera_get_matrix_at_time( - const bContext *C, Scene *scene, ARegion *ar, RegionView3D *rv3d, View3D *v3d, Object *camera, float time, float r_mat[4][4]) + Scene *scene, + ARegion *ar, RegionView3D *rv3d, View3D *v3d, + Object *camera, + float time, + float r_mat[4][4]) { EvaluationContext eval_ctx; float obmat[4][4]; @@ -63,7 +68,19 @@ static void eevee_motion_blur_camera_get_matrix_at_time( memcpy(&camdata_cpy, camera->data, sizeof(camdata_cpy)); cam_cpy.data = &camdata_cpy; - CTX_data_eval_ctx(C, &eval_ctx); + /* NOTE: Mode corresponds to old usage of eval_ctx from viewport (which was + * actually coming from bmain). It was always DAG_EVAL_VIEWPORT. For F12 + * render this should be DAG_EVAL_RENDER, but the whole hack is to be + * reconsidered first anyway. + */ + const DRWContextState *draw_ctx = DRW_context_state_get(); + DEG_evaluation_context_init_from_scene( + &eval_ctx, + scene, + draw_ctx->view_layer, + draw_ctx->engine_type, + DAG_EVAL_VIEWPORT); + eval_ctx.ctime = time; /* Past matrix */ /* FIXME : This is a temporal solution that does not take care of parent animations */ @@ -76,27 +93,15 @@ static void eevee_motion_blur_camera_get_matrix_at_time( CameraParams params; BKE_camera_params_init(¶ms); - /* copy of BKE_camera_params_from_view3d */ - { - params.lens = v3d->lens; - params.clipsta = v3d->near; - params.clipend = v3d->far; - - /* camera view */ + if (v3d != NULL) { + BKE_camera_params_from_view3d(¶ms, draw_ctx->depsgraph, v3d, rv3d); + BKE_camera_params_compute_viewplane(¶ms, ar->winx, ar->winy, 1.0f, 1.0f); + } + else { BKE_camera_params_from_object(¶ms, &cam_cpy); - - params.zoom = BKE_screen_view3d_zoom_to_fac(rv3d->camzoom); - - params.offsetx = 2.0f * rv3d->camdx * params.zoom; - params.offsety = 2.0f * rv3d->camdy * params.zoom; - - params.shiftx *= params.zoom; - params.shifty *= params.zoom; - - params.zoom = CAMERA_PARAM_ZOOM_INIT_CAMOB / params.zoom; + BKE_camera_params_compute_viewplane(¶ms, scene->r.xsch, scene->r.ysch, scene->r.xasp, scene->r.yasp); } - BKE_camera_params_compute_viewplane(¶ms, ar->winx, ar->winy, 1.0f, 1.0f); BKE_camera_params_compute_matrix(¶ms); /* FIXME Should be done per view (MULTIVIEW) */ @@ -110,7 +115,7 @@ static void eevee_create_shader_motion_blur(void) e_data.motion_blur_sh = DRW_shader_create_fullscreen(datatoc_effect_motion_blur_frag_glsl, NULL); } -int EEVEE_motion_blur_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata) +int EEVEE_motion_blur_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata, Object *camera) { EEVEE_StorageList *stl = vedata->stl; EEVEE_EffectsInfo *effects = stl->effects; @@ -121,34 +126,51 @@ int EEVEE_motion_blur_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *veda View3D *v3d = draw_ctx->v3d; RegionView3D *rv3d = draw_ctx->rv3d; ARegion *ar = draw_ctx->ar; - IDProperty *props = BKE_view_layer_engine_evaluated_get(view_layer, COLLECTION_MODE_NONE, RE_engine_id_BLENDER_EEVEE); + IDProperty *props = BKE_view_layer_engine_evaluated_get(view_layer, + COLLECTION_MODE_NONE, + RE_engine_id_BLENDER_EEVEE); - if (BKE_collection_engine_property_value_get_bool(props, "motion_blur_enable") && (draw_ctx->evil_C != NULL)) { + if (BKE_collection_engine_property_value_get_bool(props, "motion_blur_enable")) { /* Update Motion Blur Matrices */ - if (rv3d->persp == RV3D_CAMOB && v3d->camera) { + if (camera) { float persmat[4][4]; float ctime = BKE_scene_frame_get(scene); float delta = BKE_collection_engine_property_value_get_float(props, "motion_blur_shutter"); + Object *camera_object = DEG_get_evaluated_object(draw_ctx->depsgraph, camera); /* Current matrix */ - eevee_motion_blur_camera_get_matrix_at_time(draw_ctx->evil_C, scene, ar, rv3d, v3d, v3d->camera, ctime, effects->current_ndc_to_world); + eevee_motion_blur_camera_get_matrix_at_time(scene, + ar, rv3d, v3d, + camera_object, + ctime, + effects->current_ndc_to_world); /* Viewport Matrix */ DRW_viewport_matrix_get(persmat, DRW_MAT_PERS); /* Only continue if camera is not being keyed */ - if (compare_m4m4(persmat, effects->current_ndc_to_world, 0.0001f)) { - + if (DRW_state_is_image_render() || + compare_m4m4(persmat, effects->current_ndc_to_world, 0.0001f)) + { /* Past matrix */ - eevee_motion_blur_camera_get_matrix_at_time(draw_ctx->evil_C, scene, ar, rv3d, v3d, v3d->camera, ctime - delta, effects->past_world_to_ndc); + eevee_motion_blur_camera_get_matrix_at_time(scene, + ar, rv3d, v3d, + camera_object, + ctime - delta, + effects->past_world_to_ndc); #if 0 /* for future high quality blur */ /* Future matrix */ - eevee_motion_blur_camera_get_matrix_at_time(scene, ar, rv3d, v3d, v3d->camera, ctime + delta, effects->future_world_to_ndc); + eevee_motion_blur_camera_get_matrix_at_time(scene, + ar, rv3d, v3d, + camera_object, + ctime + delta, + effects->future_world_to_ndc); #endif invert_m4(effects->current_ndc_to_world); - effects->motion_blur_samples = BKE_collection_engine_property_value_get_int(props, "motion_blur_samples"); + effects->motion_blur_samples = BKE_collection_engine_property_value_get_int(props, + "motion_blur_samples"); if (!e_data.motion_blur_sh) { eevee_create_shader_motion_blur(); diff --git a/source/blender/draw/engines/eevee/eevee_occlusion.c b/source/blender/draw/engines/eevee/eevee_occlusion.c index c1dde385284..9da438e825f 100644 --- a/source/blender/draw/engines/eevee/eevee_occlusion.c +++ b/source/blender/draw/engines/eevee/eevee_occlusion.c @@ -27,7 +27,7 @@ #include "DRW_render.h" -#include "BLI_dynstr.h" +#include "BLI_string_utils.h" #include "DNA_anim_types.h" @@ -38,38 +38,43 @@ static struct { /* Ground Truth Ambient Occlusion */ struct GPUShader *gtao_sh; + struct GPUShader *gtao_layer_sh; struct GPUShader *gtao_debug_sh; + struct GPUTexture *src_depth; } e_data = {NULL}; /* Engine data */ extern char datatoc_ambient_occlusion_lib_glsl[]; +extern char datatoc_common_uniforms_lib_glsl[]; extern char datatoc_bsdf_common_lib_glsl[]; extern char datatoc_effect_gtao_frag_glsl[]; static void eevee_create_shader_occlusion(void) { - DynStr *ds_frag = BLI_dynstr_new(); - BLI_dynstr_append(ds_frag, datatoc_bsdf_common_lib_glsl); - BLI_dynstr_append(ds_frag, datatoc_ambient_occlusion_lib_glsl); - BLI_dynstr_append(ds_frag, datatoc_effect_gtao_frag_glsl); - char *frag_str = BLI_dynstr_get_cstring(ds_frag); - BLI_dynstr_free(ds_frag); + char *frag_str = BLI_string_joinN( + datatoc_common_uniforms_lib_glsl, + datatoc_bsdf_common_lib_glsl, + datatoc_ambient_occlusion_lib_glsl, + datatoc_effect_gtao_frag_glsl); e_data.gtao_sh = DRW_shader_create_fullscreen(frag_str, NULL); + e_data.gtao_layer_sh = DRW_shader_create_fullscreen(frag_str, "#define LAYERED_DEPTH\n"); e_data.gtao_debug_sh = DRW_shader_create_fullscreen(frag_str, "#define DEBUG_AO\n"); MEM_freeN(frag_str); } -int EEVEE_occlusion_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata) +int EEVEE_occlusion_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) { + EEVEE_CommonUniformBuffer *common_data = &sldata->common_data; EEVEE_StorageList *stl = vedata->stl; EEVEE_FramebufferList *fbl = vedata->fbl; EEVEE_TextureList *txl = vedata->txl; - EEVEE_EffectsInfo *effects = stl->effects; const DRWContextState *draw_ctx = DRW_context_state_get(); ViewLayer *view_layer = draw_ctx->view_layer; - IDProperty *props = BKE_view_layer_engine_evaluated_get(view_layer, COLLECTION_MODE_NONE, RE_engine_id_BLENDER_EEVEE); + IDProperty *props = BKE_view_layer_engine_evaluated_get(view_layer, + COLLECTION_MODE_NONE, + RE_engine_id_BLENDER_EEVEE); if (BKE_collection_engine_property_value_get_bool(props, "gtao_enable")) { const float *viewport_size = DRW_viewport_size_get(); @@ -79,48 +84,24 @@ int EEVEE_occlusion_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata eevee_create_shader_occlusion(); } - effects->ao_dist = BKE_collection_engine_property_value_get_float(props, "gtao_distance"); - effects->ao_factor = BKE_collection_engine_property_value_get_float(props, "gtao_factor"); - effects->ao_quality = 1.0f - BKE_collection_engine_property_value_get_float(props, "gtao_quality"); - effects->ao_samples = BKE_collection_engine_property_value_get_int(props, "gtao_samples"); - effects->ao_samples_inv = 1.0f / effects->ao_samples; + common_data->ao_dist = BKE_collection_engine_property_value_get_float(props, "gtao_distance"); + common_data->ao_factor = BKE_collection_engine_property_value_get_float(props, "gtao_factor"); + common_data->ao_quality = 1.0f - BKE_collection_engine_property_value_get_float(props, "gtao_quality"); - effects->ao_settings = 1.0; /* USE_AO */ + common_data->ao_settings = 1.0; /* USE_AO */ if (BKE_collection_engine_property_value_get_bool(props, "gtao_use_bent_normals")) { - effects->ao_settings += 2.0; /* USE_BENT_NORMAL */ + common_data->ao_settings += 2.0; /* USE_BENT_NORMAL */ } if (BKE_collection_engine_property_value_get_bool(props, "gtao_denoise")) { - effects->ao_settings += 4.0; /* USE_DENOISE */ - } - - effects->ao_bounce_fac = (float)BKE_collection_engine_property_value_get_bool(props, "gtao_bounce"); - - effects->ao_texsize[0] = ((int)viewport_size[0]); - effects->ao_texsize[1] = ((int)viewport_size[1]); - - /* Round up to multiple of 2 */ - if ((effects->ao_texsize[0] & 0x1) != 0) { - effects->ao_texsize[0] += 1; + common_data->ao_settings += 4.0; /* USE_DENOISE */ } - if ((effects->ao_texsize[1] & 0x1) != 0) { - effects->ao_texsize[1] += 1; - } - - CLAMP(effects->ao_samples, 1, 32); - if (effects->hori_tex_layers != effects->ao_samples) { - DRW_TEXTURE_FREE_SAFE(txl->gtao_horizons); - } - - if (txl->gtao_horizons == NULL) { - effects->hori_tex_layers = effects->ao_samples; - txl->gtao_horizons = DRW_texture_create_2D_array((int)viewport_size[0], (int)viewport_size[1], effects->hori_tex_layers, DRW_TEX_RG_8, 0, NULL); - } + common_data->ao_bounce_fac = (float)BKE_collection_engine_property_value_get_bool(props, "gtao_bounce"); - DRWFboTexture tex = {&txl->gtao_horizons, DRW_TEX_RG_8, 0}; + DRWFboTexture tex = {&txl->gtao_horizons, DRW_TEX_RGBA_8, 0}; DRW_framebuffer_init(&fbl->gtao_fb, &draw_engine_eevee_type, - effects->ao_texsize[0], effects->ao_texsize[1], + (int)viewport_size[0], (int)viewport_size[1], &tex, 1); if (G.debug_value == 6) { @@ -137,12 +118,12 @@ int EEVEE_occlusion_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata /* Cleanup */ DRW_TEXTURE_FREE_SAFE(txl->gtao_horizons); DRW_FRAMEBUFFER_FREE_SAFE(fbl->gtao_fb); - effects->ao_settings = 0.0f; + common_data->ao_settings = 0.0f; return 0; } -void EEVEE_occlusion_cache_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata) +void EEVEE_occlusion_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) { EEVEE_PassList *psl = vedata->psl; EEVEE_StorageList *stl = vedata->stl; @@ -166,51 +147,54 @@ void EEVEE_occlusion_cache_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data **/ psl->ao_horizon_search = DRW_pass_create("GTAO Horizon Search", DRW_STATE_WRITE_COLOR); DRWShadingGroup *grp = DRW_shgroup_create(e_data.gtao_sh, psl->ao_horizon_search); + DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex()); DRW_shgroup_uniform_buffer(grp, "maxzBuffer", &txl->maxzbuffer); - DRW_shgroup_uniform_buffer(grp, "depthBuffer", &dtxl->depth); - DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)stl->g_data->viewvecs, 2); - DRW_shgroup_uniform_vec2(grp, "mipRatio[0]", (float *)stl->g_data->mip_ratio, 10); - DRW_shgroup_uniform_vec4(grp, "aoParameters[0]", &stl->effects->ao_dist, 2); - DRW_shgroup_uniform_float(grp, "sampleNbr", &stl->effects->ao_sample_nbr, 1); - DRW_shgroup_uniform_ivec2(grp, "aoHorizonTexSize", (int *)stl->effects->ao_texsize, 1); + DRW_shgroup_uniform_buffer(grp, "depthBuffer", &effects->ao_src_depth); + DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); + DRW_shgroup_call_add(grp, quad, NULL); + + psl->ao_horizon_search_layer = DRW_pass_create("GTAO Horizon Search Layer", DRW_STATE_WRITE_COLOR); + grp = DRW_shgroup_create(e_data.gtao_layer_sh, psl->ao_horizon_search_layer); DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex()); + DRW_shgroup_uniform_buffer(grp, "maxzBuffer", &txl->maxzbuffer); + DRW_shgroup_uniform_buffer(grp, "depthBufferLayered", &effects->ao_src_depth); + DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); + DRW_shgroup_uniform_int(grp, "layer", &stl->effects->ao_depth_layer, 1); DRW_shgroup_call_add(grp, quad, NULL); if (G.debug_value == 6) { psl->ao_horizon_debug = DRW_pass_create("GTAO Horizon Debug", DRW_STATE_WRITE_COLOR); grp = DRW_shgroup_create(e_data.gtao_debug_sh, psl->ao_horizon_debug); + DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex()); DRW_shgroup_uniform_buffer(grp, "maxzBuffer", &txl->maxzbuffer); DRW_shgroup_uniform_buffer(grp, "depthBuffer", &dtxl->depth); DRW_shgroup_uniform_buffer(grp, "normalBuffer", &txl->ssr_normal_input); DRW_shgroup_uniform_buffer(grp, "horizonBuffer", &txl->gtao_horizons); - DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)stl->g_data->viewvecs, 2); - DRW_shgroup_uniform_vec2(grp, "mipRatio[0]", (float *)stl->g_data->mip_ratio, 10); - DRW_shgroup_uniform_vec4(grp, "aoParameters[0]", &stl->effects->ao_dist, 2); - DRW_shgroup_uniform_ivec2(grp, "aoHorizonTexSize", (int *)stl->effects->ao_texsize, 1); - DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex()); + DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); DRW_shgroup_call_add(grp, quad, NULL); } } } -void EEVEE_occlusion_compute(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata) +void EEVEE_occlusion_compute( + EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata, struct GPUTexture *depth_src, int layer) { EEVEE_PassList *psl = vedata->psl; - EEVEE_TextureList *txl = vedata->txl; EEVEE_FramebufferList *fbl = vedata->fbl; EEVEE_StorageList *stl = vedata->stl; EEVEE_EffectsInfo *effects = stl->effects; if ((effects->enabled_effects & EFFECT_GTAO) != 0) { DRW_stats_group_start("GTAO Horizon Scan"); - for (effects->ao_sample_nbr = 0.0; - effects->ao_sample_nbr < effects->ao_samples; - ++effects->ao_sample_nbr) - { - DRW_framebuffer_texture_detach(txl->gtao_horizons); - DRW_framebuffer_texture_layer_attach(fbl->gtao_fb, txl->gtao_horizons, 0, (int)effects->ao_sample_nbr, 0); - DRW_framebuffer_bind(fbl->gtao_fb); + effects->ao_src_depth = depth_src; + effects->ao_depth_layer = layer; + DRW_framebuffer_bind(fbl->gtao_fb); + + if (layer >= 0) { + DRW_draw_pass(psl->ao_horizon_search_layer); + } + else { DRW_draw_pass(psl->ao_horizon_search); } @@ -247,5 +231,6 @@ void EEVEE_occlusion_draw_debug(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data void EEVEE_occlusion_free(void) { DRW_SHADER_FREE_SAFE(e_data.gtao_sh); + DRW_SHADER_FREE_SAFE(e_data.gtao_layer_sh); DRW_SHADER_FREE_SAFE(e_data.gtao_debug_sh); } diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h index 98fc6d6a6e4..218de6ddd88 100644 --- a/source/blender/draw/engines/eevee/eevee_private.h +++ b/source/blender/draw/engines/eevee/eevee_private.h @@ -27,6 +27,8 @@ #define __EEVEE_PRIVATE_H__ struct Object; +struct EEVEE_BoundSphere; +struct EEVEE_ShadowCasterBuffer; extern struct DrawEngineType draw_engine_eevee_type; @@ -127,6 +129,14 @@ enum { SHADOW_METHOD_MAX = 3, }; +typedef struct EEVEE_BoundSphere { + float center[3], radius; +} EEVEE_BoundSphere; + +typedef struct EEVEE_BoundBox { + float center[3], halfdim[3]; +} EEVEE_BoundBox; + typedef struct EEVEE_PassList { /* Shadows */ struct DRWPass *shadow_pass; @@ -148,6 +158,7 @@ typedef struct EEVEE_PassList { /* Effects */ struct DRWPass *ao_horizon_search; + struct DRWPass *ao_horizon_search_layer; struct DRWPass *ao_horizon_debug; struct DRWPass *motion_blur; struct DRWPass *bloom_blit; @@ -195,6 +206,7 @@ typedef struct EEVEE_PassList { struct DRWPass *refract_pass; struct DRWPass *transparent_pass; struct DRWPass *background_pass; + struct DRWPass *update_noise_pass; } EEVEE_PassList; typedef struct EEVEE_FramebufferList { @@ -217,6 +229,8 @@ typedef struct EEVEE_FramebufferList { struct GPUFrameBuffer *screen_tracing_fb; struct GPUFrameBuffer *refract_fb; + struct GPUFrameBuffer *update_noise_fb; + struct GPUFrameBuffer *planarref_fb; struct GPUFrameBuffer *main; @@ -237,6 +251,7 @@ typedef struct EEVEE_TextureList { struct GPUTexture *bloom_upsample[MAX_BLOOM_STEP - 1]; /* R16_G16_B16 */ struct GPUTexture *ssr_normal_input; struct GPUTexture *ssr_specrough_input; + struct GPUTexture *ssr_hit_output; struct GPUTexture *refract_color; struct GPUTexture *volume_prop_scattering; @@ -310,17 +325,23 @@ typedef struct EEVEE_ShadowRender { float shadow_inv_samples_ct; } EEVEE_ShadowRender; -/* ************ VOLUME DATA ************ */ -typedef struct EEVEE_VolumetricsInfo { - float integration_step_count, shadow_step_count, sample_distribution, light_clamp; - float integration_start, integration_end; - float depth_param[3], history_alpha; - bool use_lights, use_volume_shadows; - int froxel_tex_size[3]; - float inv_tex_size[3]; - float volume_coord_scale[2]; - float jitter[3]; -} EEVEE_VolumetricsInfo; +/* This is just a really long bitflag with special function to access it. */ +#define MAX_LIGHTBITS_FIELDS (MAX_LIGHT / 8) +typedef struct EEVEE_LightBits { + unsigned char fields[MAX_LIGHTBITS_FIELDS]; +} EEVEE_LightBits; + +typedef struct EEVEE_ShadowCaster { + struct EEVEE_LightBits bits; + struct EEVEE_BoundBox bbox; +} EEVEE_ShadowCaster; + +typedef struct EEVEE_ShadowCasterBuffer { + struct EEVEE_ShadowCaster *shadow_casters; + char *flags; + unsigned int alloc_count; + unsigned int count; +} EEVEE_ShadowCasterBuffer; /* ************ LIGHT DATA ************* */ typedef struct EEVEE_LampsInfo { @@ -346,8 +367,20 @@ typedef struct EEVEE_LampsInfo { struct EEVEE_Shadow shadow_data[MAX_SHADOW]; struct EEVEE_ShadowCube shadow_cube_data[MAX_SHADOW_CUBE]; struct EEVEE_ShadowCascade shadow_cascade_data[MAX_SHADOW_CASCADE]; + /* Lights tracking */ + int new_shadow_id[MAX_LIGHT]; /* To be able to convert old bitfield to new bitfield */ + struct EEVEE_BoundSphere shadow_bounds[MAX_LIGHT]; /* Tighly packed light bounds */ + /* Pointers only. */ + struct EEVEE_ShadowCasterBuffer *shcaster_frontbuffer; + struct EEVEE_ShadowCasterBuffer *shcaster_backbuffer; } EEVEE_LampsInfo; +/* EEVEE_LampsInfo->shadow_casters_flag */ +enum { + SHADOW_CASTER_PRUNED = (1 << 0), + SHADOW_CASTER_UPDATED = (1 << 1), +}; + /* EEVEE_LampsInfo->update_flag */ enum { LIGHT_UPDATE_SHADOW_CUBE = (1 << 0), @@ -395,11 +428,9 @@ typedef struct EEVEE_LightProbesInfo { int num_bounce; int cubemap_res; int target_size; - int irradiance_vis_size; int grid_initialized; - /* Actual number of probes that have datas. */ - int num_render_cube; - int num_render_grid; + struct World *prev_world; + bool do_cube_update; /* For rendering probes */ float probemat[6][4][4]; int layer; @@ -414,11 +445,8 @@ typedef struct EEVEE_LightProbesInfo { float lod_rt_max, lod_cube_max, lod_planar_max; float visibility_range; float visibility_blur; + float intensity_fac; int shres; - int shnbr; - bool specular_toggle; - bool ssr_toggle; - bool sss_toggle; /* List of probes in the scene. */ /* XXX This is fragile, can get out of sync quickly. */ struct Object *probes_cube_ref[MAX_PROBE]; @@ -441,30 +469,18 @@ enum { typedef struct EEVEE_EffectsInfo { int enabled_effects; bool swap_double_buffer; - /* SSSS */ int sss_sample_count; - float sss_jitter_threshold; bool sss_separate_albedo; - /* Volumetrics */ - bool use_volumetrics; int volume_current_sample; - /* SSR */ - bool use_ssr; bool reflection_trace_full; - bool ssr_use_normalization; - int ssr_ray_count; - float ssr_firefly_fac; - float ssr_border_fac; - float ssr_max_roughness; - float ssr_quality; - float ssr_thickness; - float ssr_pixelsize[2]; - + int ssr_neighbor_ofs; + int ssr_halfres_ofs[2]; /* Temporal Anti Aliasing */ int taa_current_sample; + int taa_render_sample; int taa_total_sample; float taa_alpha; bool prev_drw_support; @@ -473,27 +489,19 @@ typedef struct EEVEE_EffectsInfo { float overide_persinv[4][4]; float overide_winmat[4][4]; float overide_wininv[4][4]; - /* Ambient Occlusion */ - bool use_ao, use_bent_normals; - float ao_dist, ao_samples, ao_factor, ao_samples_inv; - float ao_offset, ao_bounce_fac, ao_quality, ao_settings; - float ao_sample_nbr; - int ao_texsize[2], hori_tex_layers; - + int ao_depth_layer; + struct GPUTexture *ao_src_depth; /* pointer copy */ /* Motion Blur */ float current_ndc_to_world[4][4]; float past_world_to_ndc[4][4]; - float tmp_mat[4][4]; int motion_blur_samples; - /* Depth Of Field */ float dof_near_far[2]; float dof_params[3]; float dof_bokeh[4]; float dof_layer_select[2]; int dof_target_size[2]; - /* Bloom */ int bloom_iteration_ct; float source_texel_size[2]; @@ -506,10 +514,11 @@ typedef struct EEVEE_EffectsInfo { float unf_source_texel_size[2]; struct GPUTexture *unf_source_buffer; /* pointer copy */ struct GPUTexture *unf_base_buffer; /* pointer copy */ - /* Not alloced, just a copy of a *GPUtexture in EEVEE_TextureList. */ struct GPUTexture *source_buffer; /* latest updated texture */ struct GPUFrameBuffer *target_buffer; /* next target to render to */ + struct GPUTexture *final_tx; /* Final color to transform to display color space. */ + struct GPUFrameBuffer *final_fb; /* Framebuffer with final_tx as attachement. */ } EEVEE_EffectsInfo; enum { @@ -527,6 +536,58 @@ enum { EFFECT_SSS = (1 << 11), }; +/* ***************** COMMON DATA **************** */ + +/* Common uniform buffer containing all "constant" data over the whole drawing pipeline. */ +/* !! CAUTION !! + * - [i]vec3 need to be paded to [i]vec4 (even in ubo declaration). + * - Make sure that [i]vec4 start at a multiple of 16 bytes. + * - Arrays of vec2/vec3 are padded as arrays of vec4. + * - sizeof(bool) == sizeof(int) in GLSL so use int in C */ +typedef struct EEVEE_CommonUniformBuffer { + float prev_persmat[4][4]; /* mat4 */ + float view_vecs[2][4]; /* vec4[2] */ + float mip_ratio[10][4]; /* vec2[10] */ + /* Ambient Occlusion */ + /* -- 16 byte aligned -- */ + float ao_dist, pad1, ao_factor, pad2; /* vec4 */ + float ao_offset, ao_bounce_fac, ao_quality, ao_settings; /* vec4 */ + /* Volumetric */ + /* -- 16 byte aligned -- */ + int vol_tex_size[3], pad3; /* ivec3 */ + float vol_depth_param[3], pad4; /* vec3 */ + float vol_inv_tex_size[3], pad5; /* vec3 */ + float vol_jitter[3], pad6; /* vec3 */ + float vol_coord_scale[2], pad7[2]; /* vec2 */ + /* -- 16 byte aligned -- */ + float vol_history_alpha; /* float */ + float vol_light_clamp; /* float */ + float vol_shadow_steps; /* float */ + int vol_use_lights; /* bool */ + /* Screen Space Reflections */ + /* -- 16 byte aligned -- */ + float ssr_quality, ssr_thickness, ssr_pixelsize[2]; /* vec4 */ + float ssr_border_fac; /* float */ + float ssr_max_roughness; /* float */ + float ssr_firefly_fac; /* float */ + float ssr_brdf_bias; /* float */ + int ssr_toggle; /* bool */ + /* SubSurface Scattering */ + float sss_jitter_threshold; /* float */ + int sss_toggle; /* bool */ + /* Specular */ + int spec_toggle; /* bool */ + /* Lamps */ + int la_num_light; /* int */ + /* Probes */ + int prb_num_planar; /* int */ + int prb_num_render_cube; /* int */ + int prb_num_render_grid; /* int */ + int prb_irradiance_vis_size; /* int */ + float prb_lod_cube_max; /* float */ + float prb_lod_planar_max; /* float */ +} EEVEE_CommonUniformBuffer; + /* ************** SCENE LAYER DATA ************** */ typedef struct EEVEE_ViewLayerData { /* Lamps */ @@ -546,7 +607,7 @@ typedef struct EEVEE_ViewLayerData { struct GPUTexture *shadow_cascade_blur; struct GPUTexture *shadow_pool; - struct ListBase shadow_casters; /* Shadow casters gathered during cache iteration */ + struct EEVEE_ShadowCasterBuffer shcasters_buffers[2]; /* Probes */ struct EEVEE_LightProbesInfo *probes; @@ -564,20 +625,45 @@ typedef struct EEVEE_ViewLayerData { struct GPUTexture *irradiance_pool; struct GPUTexture *irradiance_rt; - struct ListBase probe_queue; /* List of probes to update */ - - /* Volumetrics */ - struct EEVEE_VolumetricsInfo *volumetrics; + /* Common Uniform Buffer */ + struct EEVEE_CommonUniformBuffer common_data; + struct GPUUniformBuffer *common_ubo; } EEVEE_ViewLayerData; /* ************ OBJECT DATA ************ */ +typedef struct EEVEE_LightData { + short light_id, shadow_id; +} EEVEE_LightData; + +typedef struct EEVEE_ShadowCubeData { + short light_id, shadow_id, cube_id, layer_id; +} EEVEE_ShadowCubeData; + +typedef struct EEVEE_ShadowCascadeData { + short light_id, shadow_id, cascade_id, layer_id; + float viewprojmat[MAX_CASCADE_NUM][4][4]; /* World->Lamp->NDC : used for rendering the shadow map. */ + float radius[MAX_CASCADE_NUM]; +} EEVEE_ShadowCascadeData; + +/* Theses are the structs stored inside Objects. + * It works with even if the object is in multiple layers + * because we don't get the same "Object *" for each layer. */ typedef struct EEVEE_LampEngineData { + ObjectEngineData engine_data; + bool need_update; - struct ListBase shadow_caster_list; - void *storage; /* either EEVEE_LightData, EEVEE_ShadowCubeData, EEVEE_ShadowCascadeData */ + /* This needs to be out of the union to avoid undefined behaviour. */ + short prev_cube_shadow_id; + union { + struct EEVEE_LightData ld; + struct EEVEE_ShadowCubeData scd; + struct EEVEE_ShadowCascadeData scad; + } data; } EEVEE_LampEngineData; typedef struct EEVEE_LightProbeEngineData { + ObjectEngineData engine_data; + /* NOTE: need_full_update is set by dependency graph when the probe or it's * object is updated. This triggers full probe update, including it's * "progressive" GI refresh. @@ -606,7 +692,10 @@ typedef struct EEVEE_LightProbeEngineData { } EEVEE_LightProbeEngineData; typedef struct EEVEE_ObjectEngineData { + ObjectEngineData engine_data; + bool need_update; + unsigned int shadow_caster_id; } EEVEE_ObjectEngineData; /* *********************************** */ @@ -635,18 +724,18 @@ typedef struct EEVEE_PrivateData { struct GHash *material_hash; struct GHash *hair_material_hash; struct GPUTexture *minzbuffer; - struct GPUTexture *ssr_hit_output[4]; + struct GPUTexture *ssr_pdf_output; struct GPUTexture *gtao_horizons_debug; float background_alpha; /* TODO find a better place for this. */ - float viewvecs[2][4]; /* For planar probes */ - float texel_size[2]; - /* To correct mip level texel mis-alignement */ - float mip_ratio[10][2]; /* TODO put in a UBO */ + float planar_texel_size[2]; /* For double buffering */ bool view_updated; bool valid_double_buffer; - float prev_persmat[4][4]; + /* Render Matrices */ + float persmat[4][4], persinv[4][4]; + float viewmat[4][4], viewinv[4][4]; + float winmat[4][4], wininv[4][4]; } EEVEE_PrivateData; /* Transient data */ /* eevee_data.c */ @@ -661,7 +750,7 @@ EEVEE_LampEngineData *EEVEE_lamp_data_ensure(Object *ob); /* eevee_materials.c */ struct GPUTexture *EEVEE_materials_get_util_tex(void); /* XXX */ -void EEVEE_materials_init(EEVEE_StorageList *stl); +void EEVEE_materials_init(EEVEE_ViewLayerData *sldata, EEVEE_StorageList *stl, EEVEE_FramebufferList *fbl); void EEVEE_materials_cache_init(EEVEE_Data *vedata); void EEVEE_materials_cache_populate(EEVEE_Data *vedata, EEVEE_ViewLayerData *sldata, Object *ob); void EEVEE_materials_cache_finish(EEVEE_Data *vedata); @@ -676,7 +765,7 @@ struct GPUMaterial *EEVEE_material_mesh_depth_get(struct Scene *scene, Material struct GPUMaterial *EEVEE_material_hair_get(struct Scene *scene, Material *ma, int shadow_method); void EEVEE_materials_free(void); void EEVEE_draw_default_passes(EEVEE_PassList *psl); -void EEVEE_update_util_texture(float offset); +void EEVEE_update_noise(EEVEE_PassList *psl, EEVEE_FramebufferList *fbl, double offsets[3]); /* eevee_lights.c */ void EEVEE_lights_init(EEVEE_ViewLayerData *sldata); @@ -688,6 +777,7 @@ void EEVEE_lights_cache_shcaster_material_add( EEVEE_ViewLayerData *sldata, EEVEE_PassList *psl, struct GPUMaterial *gpumat, struct Gwn_Batch *geom, struct Object *ob, float (*obmat)[4], float *alpha_threshold); +void EEVEE_lights_cache_shcaster_object_add(EEVEE_ViewLayerData *sldata, struct Object *ob); void EEVEE_lights_cache_finish(EEVEE_ViewLayerData *sldata); void EEVEE_lights_update(EEVEE_ViewLayerData *sldata); void EEVEE_draw_shadows(EEVEE_ViewLayerData *sldata, EEVEE_PassList *psl); @@ -702,7 +792,7 @@ void EEVEE_lightprobes_refresh(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); void EEVEE_lightprobes_free(void); /* eevee_depth_of_field.c */ -int EEVEE_depth_of_field_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); +int EEVEE_depth_of_field_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, Object *camera); void EEVEE_depth_of_field_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); void EEVEE_depth_of_field_draw(EEVEE_Data *vedata); void EEVEE_depth_of_field_free(void); @@ -716,7 +806,7 @@ void EEVEE_bloom_free(void); /* eevee_occlusion.c */ int EEVEE_occlusion_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); void EEVEE_occlusion_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); -void EEVEE_occlusion_compute(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); +void EEVEE_occlusion_compute(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, struct GPUTexture *depth_src, int layer); void EEVEE_occlusion_draw_debug(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); void EEVEE_occlusion_free(void); @@ -730,19 +820,22 @@ void EEVEE_screen_raytrace_free(void); /* eevee_subsurface.c */ int EEVEE_subsurface_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); void EEVEE_subsurface_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); -void EEVEE_subsurface_add_pass(EEVEE_Data *vedata, unsigned int sss_id, struct GPUUniformBuffer *sss_profile); +void EEVEE_subsurface_add_pass( + EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, unsigned int sss_id, struct GPUUniformBuffer *sss_profile); void EEVEE_subsurface_data_render(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); void EEVEE_subsurface_compute(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); void EEVEE_subsurface_free(void); /* eevee_motion_blur.c */ -int EEVEE_motion_blur_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); +int EEVEE_motion_blur_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, Object *camera); void EEVEE_motion_blur_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); void EEVEE_motion_blur_draw(EEVEE_Data *vedata); void EEVEE_motion_blur_free(void); /* eevee_temporal_sampling.c */ int EEVEE_temporal_sampling_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); +void EEVEE_temporal_sampling_matrices_calc( + EEVEE_EffectsInfo *effects, float viewmat[4][4], float persmat[4][4], double ht_point[2]); void EEVEE_temporal_sampling_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); void EEVEE_temporal_sampling_draw(EEVEE_Data *vedata); void EEVEE_temporal_sampling_free(void); @@ -757,15 +850,21 @@ void EEVEE_volumes_free_smoke_textures(void); void EEVEE_volumes_free(void); /* eevee_effects.c */ -void EEVEE_effects_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); +void EEVEE_effects_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, Object *camera); void EEVEE_effects_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); void EEVEE_create_minmax_buffer(EEVEE_Data *vedata, struct GPUTexture *depth_src, int layer); void EEVEE_downsample_buffer(EEVEE_Data *vedata, struct GPUFrameBuffer *fb_src, struct GPUTexture *texture_src, int level); void EEVEE_downsample_cube_buffer(EEVEE_Data *vedata, struct GPUFrameBuffer *fb_src, struct GPUTexture *texture_src, int level); void EEVEE_effects_do_gtao(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); -void EEVEE_draw_effects(EEVEE_Data *vedata); +void EEVEE_draw_effects(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); void EEVEE_effects_free(void); +/* eevee_ */ +void EEVEE_render_init(EEVEE_Data *vedata, struct RenderEngine *engine, struct Depsgraph *depsgraph); +void EEVEE_render_cache(void *vedata, struct Object *ob, struct RenderEngine *engine, struct Depsgraph *depsgraph); +void EEVEE_render_draw(EEVEE_Data *vedata, struct RenderEngine *engine, struct Depsgraph *depsgraph); +void EEVEE_render_output(EEVEE_Data *vedata, struct RenderEngine *engine, struct Depsgraph *depsgraph); + /* Shadow Matrix */ static const float texcomat[4][4] = { /* From NDC to TexCo */ {0.5f, 0.0f, 0.0f, 0.0f}, diff --git a/source/blender/draw/engines/eevee/eevee_render.c b/source/blender/draw/engines/eevee/eevee_render.c new file mode 100644 index 00000000000..a020887e420 --- /dev/null +++ b/source/blender/draw/engines/eevee/eevee_render.c @@ -0,0 +1,278 @@ +/* + * Copyright 2016, Blender Foundation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Blender Institute + * + */ + +/** \file eevee_render.c + * \ingroup draw_engine + */ + +/** + * Render functions for final render outputs. + */ + +#include "DRW_engine.h" +#include "DRW_render.h" + +#include "BLI_rand.h" + +#include "DEG_depsgraph_query.h" + +#include "GPU_framebuffer.h" +#include "GPU_glew.h" + +#include "RE_pipeline.h" + +#include "eevee_private.h" + +void EEVEE_render_init(EEVEE_Data *ved, RenderEngine *engine, struct Depsgraph *depsgraph) +{ + EEVEE_Data *vedata = (EEVEE_Data *)ved; + EEVEE_PassList *psl = vedata->psl; + EEVEE_StorageList *stl = vedata->stl; + EEVEE_TextureList *txl = vedata->txl; + EEVEE_FramebufferList *fbl = vedata->fbl; + EEVEE_ViewLayerData *sldata = EEVEE_view_layer_data_ensure(); + Scene *scene = DEG_get_evaluated_scene(depsgraph); + const float *viewport_size = DRW_viewport_size_get(); + + /* Init default FB and render targets: + * In render mode the default framebuffer is not generated + * because there is no viewport. So we need to manually create it or + * not use it. For code clarity we just allocate it make use of it. */ + DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get(); + DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); + + /* NOTE : use 32 bit format for precision in render mode. */ + DRWFboTexture dtex = {&dtxl->depth, DRW_TEX_DEPTH_24_STENCIL_8, 0}; + DRW_framebuffer_init(&dfbl->default_fb, &draw_engine_eevee_type, + (int)viewport_size[0], (int)viewport_size[1], + &dtex, 1); + + DRWFboTexture tex = {&txl->color, DRW_TEX_RGBA_32, DRW_TEX_FILTER | DRW_TEX_MIPMAP}; + DRW_framebuffer_init(&fbl->main, &draw_engine_eevee_type, + (int)viewport_size[0], (int)viewport_size[1], + &tex, 1); + + /* Alloc transient data. */ + if (!stl->g_data) { + stl->g_data = MEM_callocN(sizeof(*stl->g_data), __func__); + } + EEVEE_PrivateData *g_data = stl->g_data; + g_data->background_alpha = 1.0f; /* TODO option */ + g_data->valid_double_buffer = 0; + + /* Alloc common ubo data. */ + if (sldata->common_ubo == NULL) { + sldata->common_ubo = DRW_uniformbuffer_create(sizeof(sldata->common_data), &sldata->common_data); + } + + /* Set the pers & view matrix. */ + struct Object *camera = RE_GetCamera(engine->re); + float frame = BKE_scene_frame_get(scene); + RE_GetCameraWindow(engine->re, camera, frame, g_data->winmat); + RE_GetCameraModelMatrix(engine->re, camera, g_data->viewinv); + + invert_m4_m4(g_data->viewmat, g_data->viewinv); + mul_m4_m4m4(g_data->persmat, g_data->winmat, g_data->viewmat); + invert_m4_m4(g_data->persinv, g_data->persmat); + invert_m4_m4(g_data->wininv, g_data->winmat); + + DRW_viewport_matrix_override_set(g_data->persmat, DRW_MAT_PERS); + DRW_viewport_matrix_override_set(g_data->persinv, DRW_MAT_PERSINV); + DRW_viewport_matrix_override_set(g_data->winmat, DRW_MAT_WIN); + DRW_viewport_matrix_override_set(g_data->wininv, DRW_MAT_WININV); + DRW_viewport_matrix_override_set(g_data->viewmat, DRW_MAT_VIEW); + DRW_viewport_matrix_override_set(g_data->viewinv, DRW_MAT_VIEWINV); + + /* EEVEE_effects_init needs to go first for TAA */ + EEVEE_effects_init(sldata, vedata, camera); + EEVEE_materials_init(sldata, stl, fbl); + EEVEE_lights_init(sldata); + EEVEE_lightprobes_init(sldata, vedata); + + /* INIT CACHE */ + EEVEE_bloom_cache_init(sldata, vedata); + EEVEE_depth_of_field_cache_init(sldata, vedata); + EEVEE_effects_cache_init(sldata, vedata); + EEVEE_lightprobes_cache_init(sldata, vedata); + EEVEE_lights_cache_init(sldata, psl); + EEVEE_materials_cache_init(vedata); + EEVEE_motion_blur_cache_init(sldata, vedata); + EEVEE_occlusion_cache_init(sldata, vedata); + EEVEE_screen_raytrace_cache_init(sldata, vedata); + EEVEE_subsurface_cache_init(sldata, vedata); + EEVEE_temporal_sampling_cache_init(sldata, vedata); + EEVEE_volumes_cache_init(sldata, vedata); +} + +void EEVEE_render_cache( + void *vedata, struct Object *ob, + struct RenderEngine *UNUSED(engine), struct Depsgraph *UNUSED(depsgraph)) +{ + EEVEE_ViewLayerData *sldata = EEVEE_view_layer_data_ensure(); + + if (DRW_check_object_visible_within_active_context(ob) == false) { + return; + } + + if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT)) { + EEVEE_materials_cache_populate(vedata, sldata, ob); + + const bool cast_shadow = true; + + if (cast_shadow) { + EEVEE_lights_cache_shcaster_object_add(sldata, ob); + } + } + else if (ob->type == OB_LIGHTPROBE) { + EEVEE_lightprobes_cache_add(sldata, ob); + } + else if (ob->type == OB_LAMP) { + EEVEE_lights_cache_add(sldata, ob); + } +} + +void EEVEE_render_draw(EEVEE_Data *vedata, struct RenderEngine *UNUSED(engine), struct Depsgraph *UNUSED(depsgraph)) +{ + EEVEE_PassList *psl = vedata->psl; + EEVEE_StorageList *stl = vedata->stl; + EEVEE_FramebufferList *fbl = vedata->fbl; + DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); + EEVEE_ViewLayerData *sldata = EEVEE_view_layer_data_ensure(); + EEVEE_PrivateData *g_data = stl->g_data; + + /* FINISH CACHE */ + EEVEE_materials_cache_finish(vedata); + EEVEE_lights_cache_finish(sldata); + EEVEE_lightprobes_cache_finish(sldata, vedata); + + const DRWContextState *draw_ctx = DRW_context_state_get(); + ViewLayer *view_layer = draw_ctx->view_layer; + IDProperty *props = BKE_view_layer_engine_evaluated_get(view_layer, COLLECTION_MODE_NONE, RE_engine_id_BLENDER_EEVEE); + unsigned int render_samples = BKE_collection_engine_property_value_get_int(props, "taa_render_samples"); + + while (render_samples-- > 0) { + float clear_col[4] = {0.0f, 0.0f, 0.0f, 0.6f}; + unsigned int primes[3] = {2, 3, 7}; + double offset[3] = {0.0, 0.0, 0.0}; + double r[3]; + + BLI_halton_3D(primes, offset, stl->effects->taa_current_sample, r); + EEVEE_update_noise(psl, fbl, r); + EEVEE_temporal_sampling_matrices_calc(stl->effects, g_data->viewmat, g_data->persmat, r); + + /* Refresh Probes & shadows */ + EEVEE_lightprobes_refresh(sldata, vedata); + DRW_uniformbuffer_update(sldata->common_ubo, &sldata->common_data); + EEVEE_draw_shadows(sldata, psl); + + DRW_viewport_matrix_override_set(stl->effects->overide_persmat, DRW_MAT_PERS); + DRW_viewport_matrix_override_set(stl->effects->overide_persinv, DRW_MAT_PERSINV); + DRW_viewport_matrix_override_set(stl->effects->overide_winmat, DRW_MAT_WIN); + DRW_viewport_matrix_override_set(stl->effects->overide_wininv, DRW_MAT_WININV); + DRW_viewport_matrix_override_set(g_data->viewmat, DRW_MAT_VIEW); + DRW_viewport_matrix_override_set(g_data->viewinv, DRW_MAT_VIEWINV); + + DRW_framebuffer_texture_detach(dtxl->depth); + DRW_framebuffer_texture_attach(fbl->main, dtxl->depth, 0, 0); + DRW_framebuffer_bind(fbl->main); + DRW_framebuffer_clear(true, true, true, clear_col, 1.0f); + /* Depth prepass */ + DRW_draw_pass(psl->depth_pass); + DRW_draw_pass(psl->depth_pass_cull); + /* Create minmax texture */ + EEVEE_create_minmax_buffer(vedata, dtxl->depth, -1); + EEVEE_occlusion_compute(sldata, vedata, dtxl->depth, -1); + EEVEE_volumes_compute(sldata, vedata); + /* Shading pass */ + DRW_draw_pass(psl->background_pass); + EEVEE_draw_default_passes(psl); + DRW_draw_pass(psl->material_pass); + EEVEE_subsurface_data_render(sldata, vedata); + /* Effects pre-transparency */ + EEVEE_subsurface_compute(sldata, vedata); + EEVEE_reflection_compute(sldata, vedata); + EEVEE_occlusion_draw_debug(sldata, vedata); + DRW_draw_pass(psl->probe_display); + EEVEE_refraction_compute(sldata, vedata); + /* Opaque refraction */ + DRW_draw_pass(psl->refract_depth_pass); + DRW_draw_pass(psl->refract_depth_pass_cull); + DRW_draw_pass(psl->refract_pass); + /* Volumetrics Resolve Opaque */ + EEVEE_volumes_resolve(sldata, vedata); + /* Transparent */ + DRW_pass_sort_shgroup_z(psl->transparent_pass); + DRW_draw_pass(psl->transparent_pass); + /* Post Process */ + EEVEE_draw_effects(sldata, vedata); + } +} + +void EEVEE_render_output(EEVEE_Data *vedata, RenderEngine *engine, struct Depsgraph *UNUSED(depsgraph)) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + ViewLayer *view_layer = draw_ctx->view_layer; + DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); + EEVEE_ViewLayerData *sldata = EEVEE_view_layer_data_ensure(); + EEVEE_FramebufferList *fbl = vedata->fbl; + EEVEE_StorageList *stl = vedata->stl; + EEVEE_PrivateData *g_data = stl->g_data; + EEVEE_CommonUniformBuffer *common_data = &sldata->common_data; + + const char *viewname = NULL; + const float *render_size = DRW_viewport_size_get(); + + /* Combined */ + RenderResult *rr = RE_engine_begin_result(engine, 0, 0, (int)render_size[0], (int)render_size[1], NULL, viewname); + RenderLayer *rl = rr->layers.first; + RenderPass *rp = RE_pass_find_by_name(rl, RE_PASSNAME_COMBINED, viewname); + + DRW_framebuffer_bind(stl->effects->final_fb); + DRW_framebuffer_read_data(0, 0, (int)render_size[0], (int)render_size[1], 4, 0, rp->rect); + + if (view_layer->passflag & SCE_PASS_Z) { + rp = RE_pass_find_by_name(rl, RE_PASSNAME_Z, viewname); + + DRW_framebuffer_texture_attach(fbl->main, dtxl->depth, 0, 0); + DRW_framebuffer_bind(fbl->main); + DRW_framebuffer_read_depth(0, 0, (int)render_size[0], (int)render_size[1], rp->rect); + + bool is_persp = DRW_viewport_is_persp_get(); + + /* Convert ogl depth [0..1] to view Z [near..far] */ + for (int i = 0; i < (int)render_size[0] * (int)render_size[1]; ++i) { + if (rp->rect[i] == 1.0f ) { + rp->rect[i] = 1e10f; /* Background */ + } + else { + if (is_persp) { + rp->rect[i] = rp->rect[i] * 2.0f - 1.0f; + rp->rect[i] = g_data->winmat[3][2] / (rp->rect[i] + g_data->winmat[2][2]); + } + else { + rp->rect[i] = -common_data->view_vecs[0][2] + rp->rect[i] * -common_data->view_vecs[1][2]; + } + } + } + } + + RE_engine_end_result(engine, rr, false, false, false); +}
\ No newline at end of file diff --git a/source/blender/draw/engines/eevee/eevee_screen_raytrace.c b/source/blender/draw/engines/eevee/eevee_screen_raytrace.c index 35669968337..2917bfd1236 100644 --- a/source/blender/draw/engines/eevee/eevee_screen_raytrace.c +++ b/source/blender/draw/engines/eevee/eevee_screen_raytrace.c @@ -28,15 +28,16 @@ #include "DRW_render.h" #include "BLI_dynstr.h" +#include "BLI_string_utils.h" #include "eevee_private.h" #include "GPU_texture.h" /* SSR shader variations */ enum { - SSR_SAMPLES = (1 << 0) | (1 << 1), - SSR_RESOLVE = (1 << 2), - SSR_FULL_TRACE = (1 << 3), + SSR_RESOLVE = (1 << 0), + SSR_FULL_TRACE = (1 << 1), + SSR_AO = (1 << 3), SSR_MAX_SHADER = (1 << 4), }; @@ -50,6 +51,7 @@ static struct { } e_data = {NULL}; /* Engine data */ extern char datatoc_ambient_occlusion_lib_glsl[]; +extern char datatoc_common_uniforms_lib_glsl[]; extern char datatoc_bsdf_common_lib_glsl[]; extern char datatoc_bsdf_sampling_lib_glsl[]; extern char datatoc_octahedron_lib_glsl[]; @@ -60,22 +62,18 @@ extern char datatoc_raytrace_lib_glsl[]; static struct GPUShader *eevee_effects_screen_raytrace_shader_get(int options) { if (e_data.ssr_sh[options] == NULL) { - DynStr *ds_frag = BLI_dynstr_new(); - BLI_dynstr_append(ds_frag, datatoc_bsdf_common_lib_glsl); - BLI_dynstr_append(ds_frag, datatoc_bsdf_sampling_lib_glsl); - BLI_dynstr_append(ds_frag, datatoc_octahedron_lib_glsl); - BLI_dynstr_append(ds_frag, datatoc_lightprobe_lib_glsl); - BLI_dynstr_append(ds_frag, datatoc_ambient_occlusion_lib_glsl); - BLI_dynstr_append(ds_frag, datatoc_raytrace_lib_glsl); - BLI_dynstr_append(ds_frag, datatoc_effect_ssr_frag_glsl); - char *ssr_shader_str = BLI_dynstr_get_cstring(ds_frag); - BLI_dynstr_free(ds_frag); - - int samples = (SSR_SAMPLES & options) + 1; + char *ssr_shader_str = BLI_string_joinN( + datatoc_common_uniforms_lib_glsl, + datatoc_bsdf_common_lib_glsl, + datatoc_bsdf_sampling_lib_glsl, + datatoc_octahedron_lib_glsl, + datatoc_lightprobe_lib_glsl, + datatoc_ambient_occlusion_lib_glsl, + datatoc_raytrace_lib_glsl, + datatoc_effect_ssr_frag_glsl); DynStr *ds_defines = BLI_dynstr_new(); BLI_dynstr_appendf(ds_defines, SHADER_DEFINES); - BLI_dynstr_appendf(ds_defines, "#define RAY_COUNT %d\n", samples); if (options & SSR_RESOLVE) { BLI_dynstr_appendf(ds_defines, "#define STEP_RESOLVE\n"); } @@ -86,6 +84,9 @@ static struct GPUShader *eevee_effects_screen_raytrace_shader_get(int options) if (options & SSR_FULL_TRACE) { BLI_dynstr_appendf(ds_defines, "#define FULLRES\n"); } + if (options & SSR_AO) { + BLI_dynstr_appendf(ds_defines, "#define SSR_AO\n"); + } char *ssr_define_str = BLI_dynstr_get_cstring(ds_defines); BLI_dynstr_free(ds_defines); @@ -98,8 +99,9 @@ static struct GPUShader *eevee_effects_screen_raytrace_shader_get(int options) return e_data.ssr_sh[options]; } -int EEVEE_screen_raytrace_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata) +int EEVEE_screen_raytrace_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) { + EEVEE_CommonUniformBuffer *common_data = &sldata->common_data; EEVEE_StorageList *stl = vedata->stl; EEVEE_FramebufferList *fbl = vedata->fbl; EEVEE_TextureList *txl = vedata->txl; @@ -108,11 +110,13 @@ int EEVEE_screen_raytrace_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data * const DRWContextState *draw_ctx = DRW_context_state_get(); ViewLayer *view_layer = draw_ctx->view_layer; - IDProperty *props = BKE_view_layer_engine_evaluated_get(view_layer, COLLECTION_MODE_NONE, RE_engine_id_BLENDER_EEVEE); + IDProperty *props = BKE_view_layer_engine_evaluated_get(view_layer, + COLLECTION_MODE_NONE, + RE_engine_id_BLENDER_EEVEE); /* Compute pixel size, (shared with contact shadows) */ - copy_v2_v2(effects->ssr_pixelsize, viewport_size); - invert_v2(effects->ssr_pixelsize); + copy_v2_v2(common_data->ssr_pixelsize, viewport_size); + invert_v2(common_data->ssr_pixelsize); if (BKE_collection_engine_property_value_get_bool(props, "ssr_enable")) { const bool use_refraction = BKE_collection_engine_property_value_get_bool(props, "ssr_refraction"); @@ -120,24 +124,27 @@ int EEVEE_screen_raytrace_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data * if (use_refraction) { DRWFboTexture tex = {&txl->refract_color, DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER | DRW_TEX_MIPMAP}; - DRW_framebuffer_init(&fbl->refract_fb, &draw_engine_eevee_type, (int)viewport_size[0], (int)viewport_size[1], &tex, 1); + DRW_framebuffer_init(&fbl->refract_fb, &draw_engine_eevee_type, + (int)viewport_size[0], (int)viewport_size[1], + &tex, 1); } - effects->ssr_ray_count = BKE_collection_engine_property_value_get_int(props, "ssr_ray_count"); + bool prev_trace_full = effects->reflection_trace_full; effects->reflection_trace_full = !BKE_collection_engine_property_value_get_bool(props, "ssr_halfres"); - effects->ssr_use_normalization = BKE_collection_engine_property_value_get_bool(props, "ssr_normalize_weight"); - effects->ssr_quality = 1.0f - BKE_collection_engine_property_value_get_float(props, "ssr_quality"); - effects->ssr_thickness = BKE_collection_engine_property_value_get_float(props, "ssr_thickness"); - effects->ssr_border_fac = BKE_collection_engine_property_value_get_float(props, "ssr_border_fade"); - effects->ssr_firefly_fac = BKE_collection_engine_property_value_get_float(props, "ssr_firefly_fac"); - effects->ssr_max_roughness = BKE_collection_engine_property_value_get_float(props, "ssr_max_roughness"); - - if (effects->ssr_firefly_fac < 1e-8f) { - effects->ssr_firefly_fac = FLT_MAX; + common_data->ssr_thickness = BKE_collection_engine_property_value_get_float(props, "ssr_thickness"); + common_data->ssr_border_fac = BKE_collection_engine_property_value_get_float(props, "ssr_border_fade"); + common_data->ssr_firefly_fac = BKE_collection_engine_property_value_get_float(props, "ssr_firefly_fac"); + common_data->ssr_max_roughness = BKE_collection_engine_property_value_get_float(props, "ssr_max_roughness"); + common_data->ssr_quality = 1.0f - 0.95f * BKE_collection_engine_property_value_get_float(props, "ssr_quality"); + common_data->ssr_brdf_bias = 0.1f + common_data->ssr_quality * 0.6f; /* Range [0.1, 0.7]. */ + + if (common_data->ssr_firefly_fac < 1e-8f) { + common_data->ssr_firefly_fac = FLT_MAX; } - /* Important, can lead to breakage otherwise. */ - CLAMP(effects->ssr_ray_count, 1, 4); + if (prev_trace_full != effects->reflection_trace_full) { + DRW_TEXTURE_FREE_SAFE(txl->ssr_hit_output); + } const int divisor = (effects->reflection_trace_full) ? 1 : 2; int tracing_res[2] = {(int)viewport_size[0] / divisor, (int)viewport_size[1] / divisor}; @@ -147,7 +154,8 @@ int EEVEE_screen_raytrace_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data * /* TODO create one texture layer per lobe */ if (txl->ssr_specrough_input == NULL) { DRWTextureFormat specrough_format = (high_qual_input) ? DRW_TEX_RGBA_16 : DRW_TEX_RGBA_8; - txl->ssr_specrough_input = DRW_texture_create_2D((int)viewport_size[0], (int)viewport_size[1], specrough_format, 0, NULL); + txl->ssr_specrough_input = DRW_texture_create_2D((int)viewport_size[0], (int)viewport_size[1], + specrough_format, 0, NULL); } /* Reattach textures to the right buffer (because we are alternating between buffers) */ @@ -156,15 +164,15 @@ int EEVEE_screen_raytrace_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data * DRW_framebuffer_texture_attach(fbl->main, txl->ssr_specrough_input, 2, 0); /* Raytracing output */ - /* TODO try integer format for hit coord to increase precision */ - DRWFboTexture tex_output[4] = { - {&stl->g_data->ssr_hit_output[0], DRW_TEX_RGBA_16, DRW_TEX_TEMP}, - {&stl->g_data->ssr_hit_output[1], DRW_TEX_RGBA_16, DRW_TEX_TEMP}, - {&stl->g_data->ssr_hit_output[2], DRW_TEX_RGBA_16, DRW_TEX_TEMP}, - {&stl->g_data->ssr_hit_output[3], DRW_TEX_RGBA_16, DRW_TEX_TEMP}, - }; + /* (AMD or Intel) For some reason DRW_TEX_TEMP with DRW_TEX_RG_16I + * creates problems when toggling ssr_halfres. Texture is not read correctly (black output). + * So using a persistent buffer instead. */ + DRWFboTexture tex_output[2] = {{&txl->ssr_hit_output, DRW_TEX_RG_16I, 0}, + {&stl->g_data->ssr_pdf_output, DRW_TEX_R_16, DRW_TEX_TEMP}}; - DRW_framebuffer_init(&fbl->screen_tracing_fb, &draw_engine_eevee_type, tracing_res[0], tracing_res[1], tex_output, effects->ssr_ray_count); + DRW_framebuffer_init(&fbl->screen_tracing_fb, &draw_engine_eevee_type, + tracing_res[0], tracing_res[1], + tex_output, 2); /* Enable double buffering to be able to read previous frame color */ return EFFECT_SSR | EFFECT_NORMAL_BUFFER | EFFECT_DOUBLE_BUFFER | ((use_refraction) ? EFFECT_REFRACT : 0); @@ -172,10 +180,9 @@ int EEVEE_screen_raytrace_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data * /* Cleanup to release memory */ DRW_TEXTURE_FREE_SAFE(txl->ssr_specrough_input); + DRW_TEXTURE_FREE_SAFE(txl->ssr_hit_output); DRW_FRAMEBUFFER_FREE_SAFE(fbl->screen_tracing_fb); - for (int i = 0; i < 4; ++i) { - stl->g_data->ssr_hit_output[i] = NULL; - } + stl->g_data->ssr_pdf_output = NULL; return 0; } @@ -191,7 +198,7 @@ void EEVEE_screen_raytrace_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *v if ((effects->enabled_effects & EFFECT_SSR) != 0) { int options = (effects->reflection_trace_full) ? SSR_FULL_TRACE : 0; - options |= (effects->ssr_ray_count - 1); + options |= ((effects->enabled_effects & EFFECT_GTAO) != 0) ? SSR_AO : 0; struct GPUShader *trace_shader = eevee_effects_screen_raytrace_shader_get(options); struct GPUShader *resolve_shader = eevee_effects_screen_raytrace_shader_get(SSR_RESOLVE | options); @@ -214,15 +221,14 @@ void EEVEE_screen_raytrace_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *v DRW_shgroup_uniform_buffer(grp, "depthBuffer", &e_data.depth_src); DRW_shgroup_uniform_buffer(grp, "normalBuffer", &txl->ssr_normal_input); DRW_shgroup_uniform_buffer(grp, "specroughBuffer", &txl->ssr_specrough_input); - DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex()); DRW_shgroup_uniform_buffer(grp, "maxzBuffer", &txl->maxzbuffer); - DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)stl->g_data->viewvecs, 2); - DRW_shgroup_uniform_vec2(grp, "mipRatio[0]", (float *)stl->g_data->mip_ratio, 10); - DRW_shgroup_uniform_vec4(grp, "ssrParameters", &effects->ssr_quality, 1); - DRW_shgroup_uniform_int(grp, "planar_count", &sldata->probes->num_planar, 1); - DRW_shgroup_uniform_float(grp, "maxRoughness", &effects->ssr_max_roughness, 1); DRW_shgroup_uniform_buffer(grp, "planarDepth", &vedata->txl->planar_depth); + DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex()); DRW_shgroup_uniform_block(grp, "planar_block", sldata->planar_ubo); + DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); + if (!effects->reflection_trace_full) { + DRW_shgroup_uniform_ivec2(grp, "halfresOffset", effects->ssr_halfres_ofs, 1); + } DRW_shgroup_call_add(grp, quad, NULL); psl->ssr_resolve = DRW_pass_create("SSR Resolve", DRW_STATE_WRITE_COLOR | DRW_STATE_ADDITIVE); @@ -230,41 +236,19 @@ void EEVEE_screen_raytrace_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *v DRW_shgroup_uniform_buffer(grp, "depthBuffer", &e_data.depth_src); DRW_shgroup_uniform_buffer(grp, "normalBuffer", &txl->ssr_normal_input); DRW_shgroup_uniform_buffer(grp, "specroughBuffer", &txl->ssr_specrough_input); - DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex()); + DRW_shgroup_uniform_buffer(grp, "probeCubes", &sldata->probe_pool); + DRW_shgroup_uniform_buffer(grp, "probePlanars", &vedata->txl->planar_pool); + DRW_shgroup_uniform_buffer(grp, "planarDepth", &vedata->txl->planar_depth); + DRW_shgroup_uniform_buffer(grp, "hitBuffer", &vedata->txl->ssr_hit_output); + DRW_shgroup_uniform_buffer(grp, "pdfBuffer", &stl->g_data->ssr_pdf_output); DRW_shgroup_uniform_buffer(grp, "prevColorBuffer", &txl->color_double_buffer); - DRW_shgroup_uniform_mat4(grp, "PastViewProjectionMatrix", (float *)stl->g_data->prev_persmat); - DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)stl->g_data->viewvecs, 2); - DRW_shgroup_uniform_int(grp, "planar_count", &sldata->probes->num_planar, 1); - DRW_shgroup_uniform_int(grp, "probe_count", &sldata->probes->num_render_cube, 1); - DRW_shgroup_uniform_vec2(grp, "mipRatio[0]", (float *)stl->g_data->mip_ratio, 10); - DRW_shgroup_uniform_float(grp, "borderFadeFactor", &effects->ssr_border_fac, 1); - DRW_shgroup_uniform_float(grp, "maxRoughness", &effects->ssr_max_roughness, 1); - DRW_shgroup_uniform_float(grp, "lodCubeMax", &sldata->probes->lod_cube_max, 1); - DRW_shgroup_uniform_float(grp, "lodPlanarMax", &sldata->probes->lod_planar_max, 1); - DRW_shgroup_uniform_float(grp, "fireflyFactor", &effects->ssr_firefly_fac, 1); DRW_shgroup_uniform_block(grp, "probe_block", sldata->probe_ubo); DRW_shgroup_uniform_block(grp, "planar_block", sldata->planar_ubo); - DRW_shgroup_uniform_buffer(grp, "probeCubes", &sldata->probe_pool); - DRW_shgroup_uniform_buffer(grp, "probePlanars", &vedata->txl->planar_pool); - DRW_shgroup_uniform_buffer(grp, "hitBuffer0", &stl->g_data->ssr_hit_output[0]); - if (effects->ssr_ray_count > 1) { - DRW_shgroup_uniform_buffer(grp, "hitBuffer1", &stl->g_data->ssr_hit_output[1]); - } - if (effects->ssr_ray_count > 2) { - DRW_shgroup_uniform_buffer(grp, "hitBuffer2", &stl->g_data->ssr_hit_output[2]); - } - if (effects->ssr_ray_count > 3) { - DRW_shgroup_uniform_buffer(grp, "hitBuffer3", &stl->g_data->ssr_hit_output[3]); - } - - DRW_shgroup_uniform_vec4(grp, "aoParameters[0]", &effects->ao_dist, 2); - if (effects->use_ao) { + DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); + DRW_shgroup_uniform_int(grp, "neighborOffset", &effects->ssr_neighbor_ofs, 1); + if ((effects->enabled_effects & EFFECT_GTAO) != 0) { + DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex()); DRW_shgroup_uniform_buffer(grp, "horizonBuffer", &vedata->txl->gtao_horizons); - DRW_shgroup_uniform_ivec2(grp, "aoHorizonTexSize", (int *)vedata->stl->effects->ao_texsize, 1); - } - else { - /* Use shadow_pool as fallback to avoid sampling problem on certain platform, see: T52593 */ - DRW_shgroup_uniform_buffer(grp, "horizonBuffer", &sldata->shadow_pool); } DRW_shgroup_call_add(grp, quad, NULL); @@ -301,22 +285,39 @@ void EEVEE_reflection_compute(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *v e_data.depth_src = dtxl->depth; DRW_stats_group_start("SSR"); - - for (int i = 0; i < effects->ssr_ray_count; ++i) { - DRW_framebuffer_texture_attach(fbl->screen_tracing_fb, stl->g_data->ssr_hit_output[i], i, 0); - } + DRW_framebuffer_texture_attach(fbl->screen_tracing_fb, stl->g_data->ssr_pdf_output, 1, 0); DRW_framebuffer_bind(fbl->screen_tracing_fb); /* Raytrace. */ DRW_draw_pass(psl->ssr_raytrace); - for (int i = 0; i < effects->ssr_ray_count; ++i) { - DRW_framebuffer_texture_detach(stl->g_data->ssr_hit_output[i]); - } + DRW_framebuffer_texture_detach(stl->g_data->ssr_pdf_output); EEVEE_downsample_buffer(vedata, fbl->downsample_fb, txl->color_double_buffer, 9); /* Resolve at fullres */ + int sample = (DRW_state_is_image_render()) ? effects->taa_render_sample : effects->taa_current_sample; + /* Doing a neighbor shift only after a few iteration. We wait for a prime number of cycles to avoid + * noise correlation. This reduces variance faster. */ + effects->ssr_neighbor_ofs = ((sample / 5) % 8) * 4; + switch ((sample / 11) % 4) { + case 0: + effects->ssr_halfres_ofs[0] = 0; + effects->ssr_halfres_ofs[1] = 0; + break; + case 1: + effects->ssr_halfres_ofs[0] = 0; + effects->ssr_halfres_ofs[1] = 1; + break; + case 2: + effects->ssr_halfres_ofs[0] = 1; + effects->ssr_halfres_ofs[1] = 0; + break; + case 4: + effects->ssr_halfres_ofs[0] = 1; + effects->ssr_halfres_ofs[1] = 1; + break; + } DRW_framebuffer_texture_detach(dtxl->depth); DRW_framebuffer_texture_detach(txl->ssr_normal_input); DRW_framebuffer_texture_detach(txl->ssr_specrough_input); diff --git a/source/blender/draw/engines/eevee/eevee_subsurface.c b/source/blender/draw/engines/eevee/eevee_subsurface.c index 4efdfb0fb84..17da4a18b78 100644 --- a/source/blender/draw/engines/eevee/eevee_subsurface.c +++ b/source/blender/draw/engines/eevee/eevee_subsurface.c @@ -27,7 +27,7 @@ #include "DRW_render.h" -#include "BLI_dynstr.h" +#include "BLI_string_utils.h" #include "eevee_private.h" #include "GPU_texture.h" @@ -36,18 +36,26 @@ static struct { struct GPUShader *sss_sh[3]; } e_data = {NULL}; /* Engine data */ +extern char datatoc_common_uniforms_lib_glsl[]; extern char datatoc_effect_subsurface_frag_glsl[]; static void eevee_create_shader_subsurface(void) { - e_data.sss_sh[0] = DRW_shader_create_fullscreen(datatoc_effect_subsurface_frag_glsl, "#define FIRST_PASS\n"); - e_data.sss_sh[1] = DRW_shader_create_fullscreen(datatoc_effect_subsurface_frag_glsl, "#define SECOND_PASS\n"); - e_data.sss_sh[2] = DRW_shader_create_fullscreen(datatoc_effect_subsurface_frag_glsl, "#define SECOND_PASS\n" - "#define USE_SEP_ALBEDO\n"); + char *frag_str = BLI_string_joinN( + datatoc_common_uniforms_lib_glsl, + datatoc_effect_subsurface_frag_glsl); + + e_data.sss_sh[0] = DRW_shader_create_fullscreen(frag_str, "#define FIRST_PASS\n"); + e_data.sss_sh[1] = DRW_shader_create_fullscreen(frag_str, "#define SECOND_PASS\n"); + e_data.sss_sh[2] = DRW_shader_create_fullscreen(frag_str, "#define SECOND_PASS\n" + "#define USE_SEP_ALBEDO\n"); + + MEM_freeN(frag_str); } -int EEVEE_subsurface_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata) +int EEVEE_subsurface_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) { + EEVEE_CommonUniformBuffer *common_data = &sldata->common_data; EEVEE_StorageList *stl = vedata->stl; EEVEE_EffectsInfo *effects = stl->effects; EEVEE_FramebufferList *fbl = vedata->fbl; @@ -60,8 +68,8 @@ int EEVEE_subsurface_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedat if (BKE_collection_engine_property_value_get_bool(props, "sss_enable")) { effects->sss_sample_count = 1 + BKE_collection_engine_property_value_get_int(props, "sss_samples") * 2; - effects->sss_jitter_threshold = BKE_collection_engine_property_value_get_float(props, "sss_jitter_threshold"); effects->sss_separate_albedo = BKE_collection_engine_property_value_get_bool(props, "sss_separate_albedo"); + common_data->sss_jitter_threshold = BKE_collection_engine_property_value_get_float(props, "sss_jitter_threshold"); /* Shaders */ if (!e_data.sss_sh[0]) { @@ -117,7 +125,8 @@ void EEVEE_subsurface_cache_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data } } -void EEVEE_subsurface_add_pass(EEVEE_Data *vedata, unsigned int sss_id, struct GPUUniformBuffer *sss_profile) +void EEVEE_subsurface_add_pass( + EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, unsigned int sss_id, struct GPUUniformBuffer *sss_profile) { DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); EEVEE_TextureList *txl = vedata->txl; @@ -127,23 +136,21 @@ void EEVEE_subsurface_add_pass(EEVEE_Data *vedata, unsigned int sss_id, struct G struct Gwn_Batch *quad = DRW_cache_fullscreen_quad_get(); DRWShadingGroup *grp = DRW_shgroup_create(e_data.sss_sh[0], psl->sss_blur_ps); - DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)vedata->stl->g_data->viewvecs, 2); DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex()); DRW_shgroup_uniform_buffer(grp, "depthBuffer", &dtxl->depth); DRW_shgroup_uniform_buffer(grp, "sssData", &txl->sss_data); DRW_shgroup_uniform_block(grp, "sssProfile", sss_profile); - DRW_shgroup_uniform_float(grp, "jitterThreshold", &effects->sss_jitter_threshold, 1); + DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); DRW_shgroup_stencil_mask(grp, sss_id); DRW_shgroup_call_add(grp, quad, NULL); struct GPUShader *sh = (effects->sss_separate_albedo) ? e_data.sss_sh[2] : e_data.sss_sh[1]; grp = DRW_shgroup_create(sh, psl->sss_resolve_ps); - DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)vedata->stl->g_data->viewvecs, 2); DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex()); DRW_shgroup_uniform_buffer(grp, "depthBuffer", &dtxl->depth); DRW_shgroup_uniform_buffer(grp, "sssData", &txl->sss_blur); DRW_shgroup_uniform_block(grp, "sssProfile", sss_profile); - DRW_shgroup_uniform_float(grp, "jitterThreshold", &effects->sss_jitter_threshold, 1); + DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); DRW_shgroup_stencil_mask(grp, sss_id); DRW_shgroup_call_add(grp, quad, NULL); diff --git a/source/blender/draw/engines/eevee/eevee_temporal_sampling.c b/source/blender/draw/engines/eevee/eevee_temporal_sampling.c index 5faac4c42cc..24b8117b6f5 100644 --- a/source/blender/draw/engines/eevee/eevee_temporal_sampling.c +++ b/source/blender/draw/engines/eevee/eevee_temporal_sampling.c @@ -44,6 +44,23 @@ static void eevee_create_shader_temporal_sampling(void) e_data.taa_resolve_sh = DRW_shader_create_fullscreen(datatoc_effect_temporal_aa_glsl, NULL); } +void EEVEE_temporal_sampling_matrices_calc( + EEVEE_EffectsInfo *effects, float viewmat[4][4], float persmat[4][4], double ht_point[2]) +{ + const float *viewport_size = DRW_viewport_size_get(); + + /* TODO Blackman-Harris filter */ + + window_translate_m4( + effects->overide_winmat, persmat, + ((float)(ht_point[0]) * 2.0f - 1.0f) / viewport_size[0], + ((float)(ht_point[1]) * 2.0f - 1.0f) / viewport_size[1]); + + mul_m4_m4m4(effects->overide_persmat, effects->overide_winmat, viewmat); + invert_m4_m4(effects->overide_persinv, effects->overide_persmat); + invert_m4_m4(effects->overide_wininv, effects->overide_winmat); +} + int EEVEE_temporal_sampling_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata) { EEVEE_StorageList *stl = vedata->stl; @@ -51,14 +68,21 @@ int EEVEE_temporal_sampling_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data EEVEE_TextureList *txl = vedata->txl; EEVEE_EffectsInfo *effects = stl->effects; + /* Reset for each "redraw". When rendering using ogl render, + * we accumulate the redraw inside the drawing loop in eevee_draw_background(). + * But we do NOT accumulate between "redraw" (as in full draw manager drawloop) + * because the opengl render already does that. */ + effects->taa_render_sample = 1; + const DRWContextState *draw_ctx = DRW_context_state_get(); ViewLayer *view_layer = draw_ctx->view_layer; IDProperty *props = BKE_view_layer_engine_evaluated_get(view_layer, COLLECTION_MODE_NONE, RE_engine_id_BLENDER_EEVEE); - if (BKE_collection_engine_property_value_get_int(props, "taa_samples") != 1 && + if ((BKE_collection_engine_property_value_get_int(props, "taa_samples") != 1 && /* FIXME the motion blur camera evaluation is tagging view_updated * thus making the TAA always reset and never stopping rendering. */ - (effects->enabled_effects & EFFECT_MOTION_BLUR) == 0) + (effects->enabled_effects & EFFECT_MOTION_BLUR) == 0) || + DRW_state_is_image_render()) { const float *viewport_size = DRW_viewport_size_get(); float persmat[4][4], viewmat[4][4]; @@ -79,40 +103,41 @@ int EEVEE_temporal_sampling_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data DRW_viewport_matrix_get(persmat, DRW_MAT_PERS); DRW_viewport_matrix_get(viewmat, DRW_MAT_VIEW); DRW_viewport_matrix_get(effects->overide_winmat, DRW_MAT_WIN); - view_is_valid = view_is_valid && compare_m4m4(persmat, effects->prev_drw_persmat, FLT_MIN); - copy_m4_m4(effects->prev_drw_persmat, persmat); + /* The view is jittered by the oglrenderer. So avoid testing in this case. */ + if (!DRW_state_is_image_render()) { + view_is_valid = view_is_valid && compare_m4m4(persmat, effects->prev_drw_persmat, FLT_MIN); + copy_m4_m4(effects->prev_drw_persmat, persmat); + } /* Prevent ghosting from probe data. */ view_is_valid = view_is_valid && (effects->prev_drw_support == DRW_state_draw_support()); effects->prev_drw_support = DRW_state_draw_support(); - if (view_is_valid && - ((effects->taa_total_sample == 0) || - (effects->taa_current_sample < effects->taa_total_sample))) + if (((effects->taa_total_sample == 0) || (effects->taa_current_sample < effects->taa_total_sample)) || + DRW_state_is_image_render()) { - effects->taa_current_sample += 1; - - effects->taa_alpha = 1.0f / (float)(effects->taa_current_sample); - - double ht_point[2]; - double ht_offset[2] = {0.0, 0.0}; - unsigned int ht_primes[2] = {2, 3}; - - BLI_halton_2D(ht_primes, ht_offset, effects->taa_current_sample - 1, ht_point); - - window_translate_m4( - effects->overide_winmat, persmat, - ((float)(ht_point[0]) * 2.0f - 1.0f) / viewport_size[0], - ((float)(ht_point[1]) * 2.0f - 1.0f) / viewport_size[1]); - - mul_m4_m4m4(effects->overide_persmat, effects->overide_winmat, viewmat); - invert_m4_m4(effects->overide_persinv, effects->overide_persmat); - invert_m4_m4(effects->overide_wininv, effects->overide_winmat); - - DRW_viewport_matrix_override_set(effects->overide_persmat, DRW_MAT_PERS); - DRW_viewport_matrix_override_set(effects->overide_persinv, DRW_MAT_PERSINV); - DRW_viewport_matrix_override_set(effects->overide_winmat, DRW_MAT_WIN); - DRW_viewport_matrix_override_set(effects->overide_wininv, DRW_MAT_WININV); + if (view_is_valid) { + /* OGL render already jitter the camera. */ + if (!DRW_state_is_image_render()) { + effects->taa_current_sample += 1; + + double ht_point[2]; + double ht_offset[2] = {0.0, 0.0}; + unsigned int ht_primes[2] = {2, 3}; + + BLI_halton_2D(ht_primes, ht_offset, effects->taa_current_sample - 1, ht_point); + + EEVEE_temporal_sampling_matrices_calc(effects, viewmat, persmat, ht_point); + + DRW_viewport_matrix_override_set(effects->overide_persmat, DRW_MAT_PERS); + DRW_viewport_matrix_override_set(effects->overide_persinv, DRW_MAT_PERSINV); + DRW_viewport_matrix_override_set(effects->overide_winmat, DRW_MAT_WIN); + DRW_viewport_matrix_override_set(effects->overide_wininv, DRW_MAT_WININV); + } + } + else { + effects->taa_current_sample = 1; + } } else { effects->taa_current_sample = 1; @@ -127,6 +152,8 @@ int EEVEE_temporal_sampling_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data return EFFECT_TAA | EFFECT_DOUBLE_BUFFER | EFFECT_POST_BUFFER; } + effects->taa_current_sample = 1; + /* Cleanup to release memory */ DRW_TEXTURE_FREE_SAFE(txl->depth_double_buffer); DRW_FRAMEBUFFER_FREE_SAFE(fbl->depth_double_buffer_fb); @@ -162,11 +189,21 @@ void EEVEE_temporal_sampling_draw(EEVEE_Data *vedata) if ((effects->enabled_effects & EFFECT_TAA) != 0) { if (effects->taa_current_sample != 1) { + if (DRW_state_is_image_render()) { + /* See EEVEE_temporal_sampling_init() for more details. */ + effects->taa_alpha = 1.0f / (float)(effects->taa_render_sample); + } + else { + effects->taa_alpha = 1.0f / (float)(effects->taa_current_sample); + } + DRW_framebuffer_bind(fbl->effect_fb); DRW_draw_pass(psl->taa_resolve); /* Restore the depth from sample 1. */ - DRW_framebuffer_blit(fbl->depth_double_buffer_fb, fbl->main, true, false); + if (!DRW_state_is_image_render()) { + DRW_framebuffer_blit(fbl->depth_double_buffer_fb, fbl->main, true, false); + } /* Special Swap */ SWAP(struct GPUFrameBuffer *, fbl->effect_fb, fbl->double_buffer); @@ -179,15 +216,25 @@ void EEVEE_temporal_sampling_draw(EEVEE_Data *vedata) /* Save the depth buffer for the next frame. * This saves us from doing anything special * in the other mode engines. */ - DRW_framebuffer_blit(fbl->main, fbl->depth_double_buffer_fb, true, false); + if (!DRW_state_is_image_render()) { + DRW_framebuffer_blit(fbl->main, fbl->depth_double_buffer_fb, true, false); + } } - if ((effects->taa_total_sample == 0) || - (effects->taa_current_sample < effects->taa_total_sample)) - { - DRW_viewport_request_redraw(); + /* Make each loop count when doing a render. */ + if (DRW_state_is_image_render()) { + effects->taa_render_sample += 1; + effects->taa_current_sample += 1; + } + else { + if ((effects->taa_total_sample == 0) || + (effects->taa_current_sample < effects->taa_total_sample)) + { + DRW_viewport_request_redraw(); + } } } + } void EEVEE_temporal_sampling_free(void) diff --git a/source/blender/draw/engines/eevee/eevee_volumes.c b/source/blender/draw/engines/eevee/eevee_volumes.c index dae4503dc32..a960682e8c9 100644 --- a/source/blender/draw/engines/eevee/eevee_volumes.c +++ b/source/blender/draw/engines/eevee/eevee_volumes.c @@ -27,8 +27,8 @@ #include "DRW_render.h" -#include "BLI_dynstr.h" #include "BLI_rand.h" +#include "BLI_string_utils.h" #include "DNA_object_force.h" #include "DNA_smoke_types.h" @@ -51,6 +51,7 @@ static struct { struct GPUShader *volumetric_clear_sh; struct GPUShader *volumetric_scatter_sh; + struct GPUShader *volumetric_scatter_with_lamps_sh; struct GPUShader *volumetric_integration_sh; struct GPUShader *volumetric_resolve_sh; @@ -63,6 +64,7 @@ static struct { extern char datatoc_bsdf_common_lib_glsl[]; extern char datatoc_bsdf_direct_lib_glsl[]; +extern char datatoc_common_uniforms_lib_glsl[]; extern char datatoc_octahedron_lib_glsl[]; extern char datatoc_irradiance_lib_glsl[]; extern char datatoc_lamps_lib_glsl[]; @@ -77,21 +79,19 @@ extern char datatoc_gpu_shader_fullscreen_vert_glsl[]; static void eevee_create_shader_volumes(void) { - DynStr *ds_frag = BLI_dynstr_new(); - BLI_dynstr_append(ds_frag, datatoc_bsdf_common_lib_glsl); - BLI_dynstr_append(ds_frag, datatoc_volumetric_lib_glsl); - e_data.volumetric_common_lib = BLI_dynstr_get_cstring(ds_frag); - BLI_dynstr_free(ds_frag); - - ds_frag = BLI_dynstr_new(); - BLI_dynstr_append(ds_frag, datatoc_bsdf_common_lib_glsl); - BLI_dynstr_append(ds_frag, datatoc_bsdf_direct_lib_glsl); - BLI_dynstr_append(ds_frag, datatoc_octahedron_lib_glsl); - BLI_dynstr_append(ds_frag, datatoc_irradiance_lib_glsl); - BLI_dynstr_append(ds_frag, datatoc_lamps_lib_glsl); - BLI_dynstr_append(ds_frag, datatoc_volumetric_lib_glsl); - e_data.volumetric_common_lamps_lib = BLI_dynstr_get_cstring(ds_frag); - BLI_dynstr_free(ds_frag); + e_data.volumetric_common_lib = BLI_string_joinN( + datatoc_common_uniforms_lib_glsl, + datatoc_bsdf_common_lib_glsl, + datatoc_volumetric_lib_glsl); + + e_data.volumetric_common_lamps_lib = BLI_string_joinN( + datatoc_common_uniforms_lib_glsl, + datatoc_bsdf_common_lib_glsl, + datatoc_bsdf_direct_lib_glsl, + datatoc_octahedron_lib_glsl, + datatoc_irradiance_lib_glsl, + datatoc_lamps_lib_glsl, + datatoc_volumetric_lib_glsl); e_data.volumetric_clear_sh = DRW_shader_create_with_lib( datatoc_volumetric_vert_glsl, @@ -108,6 +108,15 @@ static void eevee_create_shader_volumes(void) SHADER_DEFINES "#define VOLUMETRICS\n" "#define VOLUME_SHADOW\n"); + e_data.volumetric_scatter_with_lamps_sh = DRW_shader_create_with_lib( + datatoc_volumetric_vert_glsl, + datatoc_volumetric_geom_glsl, + datatoc_volumetric_scatter_frag_glsl, + e_data.volumetric_common_lamps_lib, + SHADER_DEFINES + "#define VOLUMETRICS\n" + "#define VOLUME_LIGHTING\n" + "#define VOLUME_SHADOW\n"); e_data.volumetric_integration_sh = DRW_shader_create_with_lib( datatoc_volumetric_vert_glsl, datatoc_volumetric_geom_glsl, @@ -125,6 +134,7 @@ int EEVEE_volumes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) EEVEE_FramebufferList *fbl = vedata->fbl; EEVEE_TextureList *txl = vedata->txl; EEVEE_EffectsInfo *effects = stl->effects; + EEVEE_CommonUniformBuffer *common_data = &sldata->common_data; const DRWContextState *draw_ctx = DRW_context_state_get(); ViewLayer *view_layer = draw_ctx->view_layer; @@ -141,29 +151,23 @@ int EEVEE_volumes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) eevee_create_shader_volumes(); } - if (sldata->volumetrics == NULL) { - sldata->volumetrics = MEM_callocN(sizeof(EEVEE_VolumetricsInfo), "EEVEE_VolumetricsInfo"); - } - - EEVEE_VolumetricsInfo *volumetrics = sldata->volumetrics; - int tile_size = BKE_collection_engine_property_value_get_int(props, "volumetric_tile_size"); /* Find Froxel Texture resolution. */ - int froxel_tex_size[3]; + int tex_size[3]; - froxel_tex_size[0] = (int)ceilf(fmaxf(1.0f, viewport_size[0] / (float)tile_size)); - froxel_tex_size[1] = (int)ceilf(fmaxf(1.0f, viewport_size[1] / (float)tile_size)); - froxel_tex_size[2] = max_ii(BKE_collection_engine_property_value_get_int(props, "volumetric_samples"), 1); + tex_size[0] = (int)ceilf(fmaxf(1.0f, viewport_size[0] / (float)tile_size)); + tex_size[1] = (int)ceilf(fmaxf(1.0f, viewport_size[1] / (float)tile_size)); + tex_size[2] = max_ii(BKE_collection_engine_property_value_get_int(props, "volumetric_samples"), 1); - volumetrics->volume_coord_scale[0] = viewport_size[0] / (float)(tile_size * froxel_tex_size[0]); - volumetrics->volume_coord_scale[1] = viewport_size[1] / (float)(tile_size * froxel_tex_size[1]); + common_data->vol_coord_scale[0] = viewport_size[0] / (float)(tile_size * tex_size[0]); + common_data->vol_coord_scale[1] = viewport_size[1] / (float)(tile_size * tex_size[1]); /* TODO compute snap to maxZBuffer for clustered rendering */ - if ((volumetrics->froxel_tex_size[0] != froxel_tex_size[0]) || - (volumetrics->froxel_tex_size[1] != froxel_tex_size[1]) || - (volumetrics->froxel_tex_size[2] != froxel_tex_size[2])) + if ((common_data->vol_tex_size[0] != tex_size[0]) || + (common_data->vol_tex_size[1] != tex_size[1]) || + (common_data->vol_tex_size[2] != tex_size[2])) { DRW_TEXTURE_FREE_SAFE(txl->volume_prop_scattering); DRW_TEXTURE_FREE_SAFE(txl->volume_prop_extinction); @@ -176,38 +180,46 @@ int EEVEE_volumes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) DRW_FRAMEBUFFER_FREE_SAFE(fbl->volumetric_fb); DRW_FRAMEBUFFER_FREE_SAFE(fbl->volumetric_scat_fb); DRW_FRAMEBUFFER_FREE_SAFE(fbl->volumetric_integ_fb); - volumetrics->froxel_tex_size[0] = froxel_tex_size[0]; - volumetrics->froxel_tex_size[1] = froxel_tex_size[1]; - volumetrics->froxel_tex_size[2] = froxel_tex_size[2]; + common_data->vol_tex_size[0] = tex_size[0]; + common_data->vol_tex_size[1] = tex_size[1]; + common_data->vol_tex_size[2] = tex_size[2]; - volumetrics->inv_tex_size[0] = 1.0f / (float)(volumetrics->froxel_tex_size[0]); - volumetrics->inv_tex_size[1] = 1.0f / (float)(volumetrics->froxel_tex_size[1]); - volumetrics->inv_tex_size[2] = 1.0f / (float)(volumetrics->froxel_tex_size[2]); + common_data->vol_inv_tex_size[0] = 1.0f / (float)(tex_size[0]); + common_data->vol_inv_tex_size[1] = 1.0f / (float)(tex_size[1]); + common_data->vol_inv_tex_size[2] = 1.0f / (float)(tex_size[2]); } /* Like frostbite's paper, 5% blend of the new frame. */ - volumetrics->history_alpha = (txl->volume_prop_scattering == NULL) ? 0.0f : 0.95f; + common_data->vol_history_alpha = (txl->volume_prop_scattering == NULL) ? 0.0f : 0.95f; if (txl->volume_prop_scattering == NULL) { /* Volume properties: We evaluate all volumetric objects * and store their final properties into each froxel */ - txl->volume_prop_scattering = DRW_texture_create_3D(froxel_tex_size[0], froxel_tex_size[1], froxel_tex_size[2], DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER, NULL); - txl->volume_prop_extinction = DRW_texture_create_3D(froxel_tex_size[0], froxel_tex_size[1], froxel_tex_size[2], DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER, NULL); - txl->volume_prop_emission = DRW_texture_create_3D(froxel_tex_size[0], froxel_tex_size[1], froxel_tex_size[2], DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER, NULL); - txl->volume_prop_phase = DRW_texture_create_3D(froxel_tex_size[0], froxel_tex_size[1], froxel_tex_size[2], DRW_TEX_RG_16, DRW_TEX_FILTER, NULL); + txl->volume_prop_scattering = DRW_texture_create_3D(tex_size[0], tex_size[1], tex_size[2], + DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER, NULL); + txl->volume_prop_extinction = DRW_texture_create_3D(tex_size[0], tex_size[1], tex_size[2], + DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER, NULL); + txl->volume_prop_emission = DRW_texture_create_3D(tex_size[0], tex_size[1], tex_size[2], + DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER, NULL); + txl->volume_prop_phase = DRW_texture_create_3D(tex_size[0], tex_size[1], tex_size[2], + DRW_TEX_RG_16, DRW_TEX_FILTER, NULL); /* Volume scattering: We compute for each froxel the * Scattered light towards the view. We also resolve temporal * super sampling during this stage. */ - txl->volume_scatter = DRW_texture_create_3D(froxel_tex_size[0], froxel_tex_size[1], froxel_tex_size[2], DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER, NULL); - txl->volume_transmittance = DRW_texture_create_3D(froxel_tex_size[0], froxel_tex_size[1], froxel_tex_size[2], DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER, NULL); + txl->volume_scatter = DRW_texture_create_3D(tex_size[0], tex_size[1], tex_size[2], + DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER, NULL); + txl->volume_transmittance = DRW_texture_create_3D(tex_size[0], tex_size[1], tex_size[2], + DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER, NULL); /* Final integration: We compute for each froxel the * amount of scattered light and extinction coef at this * given depth. We use theses textures as double buffer * for the volumetric history. */ - txl->volume_scatter_history = DRW_texture_create_3D(froxel_tex_size[0], froxel_tex_size[1], froxel_tex_size[2], DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER, NULL); - txl->volume_transmittance_history = DRW_texture_create_3D(froxel_tex_size[0], froxel_tex_size[1], froxel_tex_size[2], DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER, NULL); + txl->volume_scatter_history = DRW_texture_create_3D(tex_size[0], tex_size[1], tex_size[2], + DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER, NULL); + txl->volume_transmittance_history = DRW_texture_create_3D(tex_size[0], tex_size[1], tex_size[2], + DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER, NULL); } /* Temporal Super sampling jitter */ @@ -225,7 +237,7 @@ int EEVEE_volumes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) } if (do_taa) { - volumetrics->history_alpha = 0.0f; + common_data->vol_history_alpha = 0.0f; current_sample = effects->taa_current_sample - 1; effects->volume_current_sample = -1; } @@ -238,9 +250,9 @@ int EEVEE_volumes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) } BLI_halton_3D(ht_primes, ht_offset, current_sample, ht_point); - volumetrics->jitter[0] = (float)ht_point[0]; - volumetrics->jitter[1] = (float)ht_point[1]; - volumetrics->jitter[2] = (float)ht_point[2]; + common_data->vol_jitter[0] = (float)ht_point[0]; + common_data->vol_jitter[1] = (float)ht_point[1]; + common_data->vol_jitter[2] = (float)ht_point[2]; /* Framebuffer setup */ DRWFboTexture tex_vol[4] = {{&txl->volume_prop_scattering, DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER}, @@ -249,63 +261,64 @@ int EEVEE_volumes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) {&txl->volume_prop_phase, DRW_TEX_RG_16, DRW_TEX_FILTER}}; DRW_framebuffer_init(&fbl->volumetric_fb, &draw_engine_eevee_type, - (int)froxel_tex_size[0], (int)froxel_tex_size[1], + (int)tex_size[0], (int)tex_size[1], tex_vol, 4); DRWFboTexture tex_vol_scat[2] = {{&txl->volume_scatter, DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER}, {&txl->volume_transmittance, DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER}}; DRW_framebuffer_init(&fbl->volumetric_scat_fb, &draw_engine_eevee_type, - (int)froxel_tex_size[0], (int)froxel_tex_size[1], + (int)tex_size[0], (int)tex_size[1], tex_vol_scat, 2); DRWFboTexture tex_vol_integ[2] = {{&txl->volume_scatter_history, DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER}, {&txl->volume_transmittance_history, DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER}}; DRW_framebuffer_init(&fbl->volumetric_integ_fb, &draw_engine_eevee_type, - (int)froxel_tex_size[0], (int)froxel_tex_size[1], + (int)tex_size[0], (int)tex_size[1], tex_vol_integ, 2); - volumetrics->integration_start = BKE_collection_engine_property_value_get_float(props, "volumetric_start"); - volumetrics->integration_end = BKE_collection_engine_property_value_get_float(props, "volumetric_end"); - volumetrics->sample_distribution = 4.0f * (1.00001f - BKE_collection_engine_property_value_get_float(props, "volumetric_sample_distribution")); - volumetrics->use_volume_shadows = BKE_collection_engine_property_value_get_bool(props, "volumetric_shadows"); - volumetrics->light_clamp = BKE_collection_engine_property_value_get_float(props, "volumetric_light_clamp"); + float integration_start = BKE_collection_engine_property_value_get_float(props, "volumetric_start"); + float integration_end = BKE_collection_engine_property_value_get_float(props, "volumetric_end"); + common_data->vol_light_clamp = BKE_collection_engine_property_value_get_float(props, "volumetric_light_clamp"); - if (volumetrics->use_volume_shadows) { - volumetrics->shadow_step_count = (float)BKE_collection_engine_property_value_get_int(props, "volumetric_shadow_samples"); + common_data->vol_shadow_steps = (float)BKE_collection_engine_property_value_get_int(props, "volumetric_shadow_samples"); + if (BKE_collection_engine_property_value_get_bool(props, "volumetric_shadows")) { } else { - volumetrics->shadow_step_count = 0; + common_data->vol_shadow_steps = 0; } if (DRW_viewport_is_persp_get()) { - const float clip_start = stl->g_data->viewvecs[0][2]; + float sample_distribution = BKE_collection_engine_property_value_get_float(props, "volumetric_sample_distribution"); + sample_distribution = 4.0f * (1.00001f - sample_distribution); + + const float clip_start = common_data->view_vecs[0][2]; /* Negate */ - float near = volumetrics->integration_start = min_ff(-volumetrics->integration_start, clip_start - 1e-4f); - float far = volumetrics->integration_end = min_ff(-volumetrics->integration_end, near - 1e-4f); + float near = integration_start = min_ff(-integration_start, clip_start - 1e-4f); + float far = integration_end = min_ff(-integration_end, near - 1e-4f); - volumetrics->depth_param[0] = (far - near * exp2(1.0f / volumetrics->sample_distribution)) / (far - near); - volumetrics->depth_param[1] = (1.0f - volumetrics->depth_param[0]) / near; - volumetrics->depth_param[2] = volumetrics->sample_distribution; + common_data->vol_depth_param[0] = (far - near * exp2(1.0f / sample_distribution)) / (far - near); + common_data->vol_depth_param[1] = (1.0f - common_data->vol_depth_param[0]) / near; + common_data->vol_depth_param[2] = sample_distribution; } else { - const float clip_start = stl->g_data->viewvecs[0][2]; - const float clip_end = stl->g_data->viewvecs[1][2]; - volumetrics->integration_start = min_ff(volumetrics->integration_end, clip_start); - volumetrics->integration_end = max_ff(-volumetrics->integration_end, clip_end); - - volumetrics->depth_param[0] = volumetrics->integration_start; - volumetrics->depth_param[1] = volumetrics->integration_end; - volumetrics->depth_param[2] = 1.0f / (volumetrics->integration_end - volumetrics->integration_start); + const float clip_start = common_data->view_vecs[0][2]; + const float clip_end = common_data->view_vecs[1][2]; + integration_start = min_ff(integration_end, clip_start); + integration_end = max_ff(-integration_end, clip_end); + + common_data->vol_depth_param[0] = integration_start; + common_data->vol_depth_param[1] = integration_end; + common_data->vol_depth_param[2] = 1.0f / (integration_end - integration_start); } /* Disable clamp if equal to 0. */ - if (volumetrics->light_clamp == 0.0) { - volumetrics->light_clamp = FLT_MAX; + if (common_data->vol_light_clamp == 0.0) { + common_data->vol_light_clamp = FLT_MAX; } - volumetrics->use_lights = BKE_collection_engine_property_value_get_bool(props, "volumetric_lights"); + common_data->vol_use_lights = BKE_collection_engine_property_value_get_bool(props, "volumetric_lights"); return EFFECT_VOLUMETRIC | EFFECT_POST_BUFFER; } @@ -332,12 +345,11 @@ void EEVEE_volumes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) EEVEE_StorageList *stl = vedata->stl; EEVEE_TextureList *txl = vedata->txl; EEVEE_EffectsInfo *effects = stl->effects; + EEVEE_CommonUniformBuffer *common_data = &sldata->common_data; if ((effects->enabled_effects & EFFECT_VOLUMETRIC) != 0) { const DRWContextState *draw_ctx = DRW_context_state_get(); Scene *scene = draw_ctx->scene; - EEVEE_VolumetricsInfo *volumetrics = sldata->volumetrics; - static int zero = 0; DRWShadingGroup *grp; /* Quick breakdown of the Volumetric rendering: @@ -374,65 +386,59 @@ void EEVEE_volumes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) if (wo != NULL && wo->use_nodes && wo->nodetree) { struct GPUMaterial *mat = EEVEE_material_world_volume_get(scene, wo); - grp = DRW_shgroup_material_empty_tri_batch_create(mat, psl->volumetric_world_ps, volumetrics->froxel_tex_size[2]); + grp = DRW_shgroup_material_empty_tri_batch_create(mat, + psl->volumetric_world_ps, + common_data->vol_tex_size[2]); if (grp) { - DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)stl->g_data->viewvecs, 2); - DRW_shgroup_uniform_ivec3(grp, "volumeTextureSize", (int *)volumetrics->froxel_tex_size, 1); - DRW_shgroup_uniform_vec2(grp, "volume_uv_ratio", (float *)volumetrics->volume_coord_scale, 1); - DRW_shgroup_uniform_vec3(grp, "volume_param", (float *)volumetrics->depth_param, 1); - DRW_shgroup_uniform_vec3(grp, "volume_jitter", (float *)volumetrics->jitter, 1); + DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); } } else { /* If no world or volume material is present just clear the buffer with this drawcall */ - grp = DRW_shgroup_empty_tri_batch_create(e_data.volumetric_clear_sh, psl->volumetric_world_ps, volumetrics->froxel_tex_size[2]); + grp = DRW_shgroup_empty_tri_batch_create(e_data.volumetric_clear_sh, + psl->volumetric_world_ps, + common_data->vol_tex_size[2]); - DRW_shgroup_uniform_ivec3(grp, "volumeTextureSize", (int *)volumetrics->froxel_tex_size, 1); + DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); } /* Volumetric Objects */ - psl->volumetric_objects_ps = DRW_pass_create("Volumetric Properties", DRW_STATE_WRITE_COLOR | DRW_STATE_ADDITIVE); + psl->volumetric_objects_ps = DRW_pass_create("Volumetric Properties", DRW_STATE_WRITE_COLOR | + DRW_STATE_ADDITIVE); + struct GPUShader *scatter_sh = (common_data->vol_use_lights) ? e_data.volumetric_scatter_with_lamps_sh + : e_data.volumetric_scatter_sh; psl->volumetric_scatter_ps = DRW_pass_create("Volumetric Scattering", DRW_STATE_WRITE_COLOR); - grp = DRW_shgroup_empty_tri_batch_create(e_data.volumetric_scatter_sh, psl->volumetric_scatter_ps, volumetrics->froxel_tex_size[2]); - DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)stl->g_data->viewvecs, 2); - DRW_shgroup_uniform_vec2(grp, "volume_uv_ratio", (float *)volumetrics->volume_coord_scale, 1); - DRW_shgroup_uniform_vec3(grp, "volume_param", (float *)volumetrics->depth_param, 1); - DRW_shgroup_uniform_vec3(grp, "volume_jitter", (float *)volumetrics->jitter, 1); - DRW_shgroup_uniform_mat4(grp, "PastViewProjectionMatrix", (float *)stl->g_data->prev_persmat); - DRW_shgroup_uniform_block(grp, "light_block", sldata->light_ubo); - DRW_shgroup_uniform_block(grp, "shadow_block", sldata->shadow_ubo); - DRW_shgroup_uniform_int(grp, "light_count", (volumetrics->use_lights) ? &sldata->lamps->num_light : &zero, 1); + grp = DRW_shgroup_empty_tri_batch_create(scatter_sh, psl->volumetric_scatter_ps, + common_data->vol_tex_size[2]); DRW_shgroup_uniform_buffer(grp, "irradianceGrid", &sldata->irradiance_pool); DRW_shgroup_uniform_buffer(grp, "shadowTexture", &sldata->shadow_pool); - DRW_shgroup_uniform_float(grp, "volume_light_clamp", &volumetrics->light_clamp, 1); - DRW_shgroup_uniform_float(grp, "volume_shadows_steps", &volumetrics->shadow_step_count, 1); - DRW_shgroup_uniform_float(grp, "volume_history_alpha", &volumetrics->history_alpha, 1); DRW_shgroup_uniform_buffer(grp, "volumeScattering", &txl->volume_prop_scattering); DRW_shgroup_uniform_buffer(grp, "volumeExtinction", &txl->volume_prop_extinction); DRW_shgroup_uniform_buffer(grp, "volumeEmission", &txl->volume_prop_emission); DRW_shgroup_uniform_buffer(grp, "volumePhase", &txl->volume_prop_phase); DRW_shgroup_uniform_buffer(grp, "historyScattering", &txl->volume_scatter_history); DRW_shgroup_uniform_buffer(grp, "historyTransmittance", &txl->volume_transmittance_history); + DRW_shgroup_uniform_block(grp, "light_block", sldata->light_ubo); + DRW_shgroup_uniform_block(grp, "shadow_block", sldata->shadow_ubo); + DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); psl->volumetric_integration_ps = DRW_pass_create("Volumetric Integration", DRW_STATE_WRITE_COLOR); - grp = DRW_shgroup_empty_tri_batch_create(e_data.volumetric_integration_sh, psl->volumetric_integration_ps, volumetrics->froxel_tex_size[2]); - DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)stl->g_data->viewvecs, 2); - DRW_shgroup_uniform_vec2(grp, "volume_uv_ratio", (float *)volumetrics->volume_coord_scale, 1); - DRW_shgroup_uniform_vec3(grp, "volume_param", (float *)volumetrics->depth_param, 1); + grp = DRW_shgroup_empty_tri_batch_create(e_data.volumetric_integration_sh, + psl->volumetric_integration_ps, + common_data->vol_tex_size[2]); DRW_shgroup_uniform_buffer(grp, "volumeScattering", &txl->volume_scatter); DRW_shgroup_uniform_buffer(grp, "volumeExtinction", &txl->volume_transmittance); + DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); psl->volumetric_resolve_ps = DRW_pass_create("Volumetric Resolve", DRW_STATE_WRITE_COLOR); grp = DRW_shgroup_create(e_data.volumetric_resolve_sh, psl->volumetric_resolve_ps); - DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)stl->g_data->viewvecs, 2); - DRW_shgroup_uniform_vec2(grp, "volume_uv_ratio", (float *)volumetrics->volume_coord_scale, 1); - DRW_shgroup_uniform_vec3(grp, "volume_param", (float *)volumetrics->depth_param, 1); DRW_shgroup_uniform_buffer(grp, "inScattering", &txl->volume_scatter); DRW_shgroup_uniform_buffer(grp, "inTransmittance", &txl->volume_transmittance); DRW_shgroup_uniform_buffer(grp, "inSceneColor", &e_data.color_src); DRW_shgroup_uniform_buffer(grp, "inSceneDepth", &e_data.depth_src); + DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL); } } @@ -442,7 +448,6 @@ void EEVEE_volumes_cache_object_add(EEVEE_ViewLayerData *sldata, EEVEE_Data *ved float *texcoloc = NULL; float *texcosize = NULL; struct ModifierData *md = NULL; - EEVEE_VolumetricsInfo *volumetrics = sldata->volumetrics; Material *ma = give_current_material(ob, 1); if (ma == NULL) { @@ -451,7 +456,7 @@ void EEVEE_volumes_cache_object_add(EEVEE_ViewLayerData *sldata, EEVEE_Data *ved struct GPUMaterial *mat = EEVEE_material_mesh_volume_get(scene, ma); - DRWShadingGroup *grp = DRW_shgroup_material_empty_tri_batch_create(mat, vedata->psl->volumetric_objects_ps, volumetrics->froxel_tex_size[2]); + DRWShadingGroup *grp = DRW_shgroup_material_empty_tri_batch_create(mat, vedata->psl->volumetric_objects_ps, sldata->common_data.vol_tex_size[2]); /* Making sure it's updated. */ invert_m4_m4(ob->imat, ob->obmat); @@ -459,14 +464,10 @@ void EEVEE_volumes_cache_object_add(EEVEE_ViewLayerData *sldata, EEVEE_Data *ved BKE_mesh_texspace_get_reference((struct Mesh *)ob->data, NULL, &texcoloc, NULL, &texcosize); if (grp) { + DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); DRW_shgroup_uniform_mat4(grp, "volumeObjectMatrix", (float *)ob->imat); DRW_shgroup_uniform_vec3(grp, "volumeOrcoLoc", texcoloc, 1); DRW_shgroup_uniform_vec3(grp, "volumeOrcoSize", texcosize, 1); - DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)vedata->stl->g_data->viewvecs, 2); - DRW_shgroup_uniform_ivec3(grp, "volumeTextureSize", (int *)volumetrics->froxel_tex_size, 1); - DRW_shgroup_uniform_vec2(grp, "volume_uv_ratio", (float *)volumetrics->volume_coord_scale, 1); - DRW_shgroup_uniform_vec3(grp, "volume_param", (float *)volumetrics->depth_param, 1); - DRW_shgroup_uniform_vec3(grp, "volume_jitter", (float *)volumetrics->jitter, 1); } /* Smoke Simulation */ @@ -576,6 +577,7 @@ void EEVEE_volumes_free(void) DRW_SHADER_FREE_SAFE(e_data.volumetric_clear_sh); DRW_SHADER_FREE_SAFE(e_data.volumetric_scatter_sh); + DRW_SHADER_FREE_SAFE(e_data.volumetric_scatter_with_lamps_sh); DRW_SHADER_FREE_SAFE(e_data.volumetric_integration_sh); DRW_SHADER_FREE_SAFE(e_data.volumetric_resolve_sh); } diff --git a/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl b/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl index 5ec72833379..55f66f5500a 100644 --- a/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl @@ -30,87 +30,18 @@ #ifndef UTIL_TEX #define UTIL_TEX uniform sampler2DArray utilTex; +#define texelfetch_noise_tex(coord) texelFetch(utilTex, ivec3(ivec2(coord) % LUT_SIZE, 2.0), 0) #endif /* UTIL_TEX */ -uniform vec4 aoParameters[2]; -uniform sampler2DArray horizonBuffer; - -/* Cannot use textureSize(horizonBuffer) when rendering to it */ -uniform ivec2 aoHorizonTexSize; - -#define aoDistance aoParameters[0].x -#define aoSamples aoParameters[0].y -#define aoFactor aoParameters[0].z -#define aoInvSamples aoParameters[0].w - -#define aoOffset aoParameters[1].x /* UNUSED */ -#define aoBounceFac aoParameters[1].y -#define aoQuality aoParameters[1].z -#define aoSettings aoParameters[1].w +uniform sampler2D horizonBuffer; +/* aoSettings flags */ #define USE_AO 1 #define USE_BENT_NORMAL 2 #define USE_DENOISE 4 -vec2 pack_horizons(vec2 v) { return v * 0.5 + 0.5; } -vec2 unpack_horizons(vec2 v) { return v * 2.0 - 1.0; } - -/* Returns the texel coordinate in horizonBuffer - * for a given fullscreen coord */ -ivec2 get_hr_co(ivec2 fs_co) -{ - bvec2 quarter = notEqual(fs_co & ivec2(1), ivec2(0)); - - ivec2 hr_co = fs_co / 2; - hr_co += ivec2(quarter) * (aoHorizonTexSize / 2); - - return hr_co; -} - -/* Returns the texel coordinate in fullscreen (depthBuffer) - * for a given horizonBuffer coord */ -ivec2 get_fs_co(ivec2 hr_co) -{ - hr_co *= 2; - bvec2 quarter = greaterThanEqual(hr_co, aoHorizonTexSize); - - hr_co -= ivec2(quarter) * (aoHorizonTexSize - 1); - - return hr_co; -} - -/* Returns the phi angle in horizonBuffer - * for a given horizonBuffer coord */ -float get_phi(ivec2 hr_co, ivec2 fs_co, float sample) -{ - bvec2 quarter = greaterThanEqual(hr_co, aoHorizonTexSize / 2); - ivec2 tex_co = ((int(aoSettings) & USE_DENOISE) != 0) ? hr_co - ivec2(quarter) * (aoHorizonTexSize / 2) : fs_co; - float blue_noise = texture(utilTex, vec3((vec2(tex_co) + 0.5) / LUT_SIZE, 2.0)).r; - - float phi = sample * aoInvSamples; - - if ((int(aoSettings) & USE_DENOISE) != 0) { - /* Interleaved jitter for spatial 2x2 denoising */ - phi += 0.25 * aoInvSamples * (float(quarter.x) + 2.0 * float(quarter.y)); - blue_noise *= 0.25; - } - /* Blue noise is scaled to cover the rest of the range. */ - phi += aoInvSamples * blue_noise; - phi *= M_PI; - - return phi; -} - -/* Returns direction jittered offset for a given fullscreen coord */ -float get_offset(ivec2 fs_co, float sample) -{ - float offset = sample * aoInvSamples; - - /* Interleaved jitter for spatial 2x2 denoising */ - offset += 0.25 * dot(vec2(1.0), vec2(fs_co & 1)); - offset += texture(utilTex, vec3((vec2(fs_co / 2) + 0.5 + 16.0) / LUT_SIZE, 2.0)).r; - return offset; -} +vec4 pack_horizons(vec4 v) { return v * 0.5 + 0.5; } +vec4 unpack_horizons(vec4 v) { return v * 2.0 - 1.0; } /* Returns maximum screen distance an AO ray can travel for a given view depth */ vec2 get_max_dir(float view_depth) @@ -120,6 +51,13 @@ vec2 get_max_dir(float view_depth) return vec2(ProjectionMatrix[0][0], ProjectionMatrix[1][1]) * max_dist; } +vec2 get_ao_dir(float jitter) +{ + /* Only half a turn because we integrate in slices. */ + jitter *= M_PI; + return vec2(cos(jitter), sin(jitter)); +} + void get_max_horizon_grouped(vec4 co1, vec4 co2, vec3 x, float lod, inout float h) { co1 *= mipRatio[int(lod + 1.0)].xyxy; /* +1 because we are using half res top level */ @@ -161,10 +99,8 @@ void get_max_horizon_grouped(vec4 co1, vec4 co2, vec3 x, float lod, inout float h = mix(h, max(h, s_h.w), blend.w); } -vec2 search_horizon_sweep(float phi, vec3 pos, vec2 uvs, float jitter, vec2 max_dir) +vec2 search_horizon_sweep(vec2 t_phi, vec3 pos, vec2 uvs, float jitter, vec2 max_dir) { - vec2 t_phi = vec2(cos(phi), sin(phi)); /* Screen space direction */ - max_dir *= max_v2(abs(t_phi)); /* Convert to pixel space. */ @@ -214,11 +150,8 @@ vec2 search_horizon_sweep(float phi, vec3 pos, vec2 uvs, float jitter, vec2 max_ return h; } -void integrate_slice(vec3 normal, float phi, vec2 horizons, inout float visibility, inout vec3 bent_normal) +void integrate_slice(vec3 normal, vec2 t_phi, vec2 horizons, inout float visibility, inout vec3 bent_normal) { - /* TODO OPTI Could be precomputed. */ - vec2 t_phi = vec2(cos(phi), sin(phi)); /* Screen space direction */ - /* Projecting Normal to Plane P defined by t_phi and omega_o */ vec3 np = vec3(t_phi.y, -t_phi.x, 0.0); /* Normal vector to Integration plane */ vec3 t = vec3(-t_phi, 0.0); @@ -251,71 +184,43 @@ void integrate_slice(vec3 normal, float phi, vec2 horizons, inout float visibili bent_normal += vec3(sin(b_angle) * -t_phi, cos(b_angle) * 0.5); } -void denoise_ao(vec3 normal, float frag_depth, inout float visibility, inout vec3 bent_normal) +void gtao_deferred(vec3 normal, vec3 position, vec4 noise, float frag_depth, out float visibility, out vec3 bent_normal) { - vec2 d_sign = vec2(ivec2(gl_FragCoord.xy) & 1) - 0.5; - - if ((int(aoSettings) & USE_DENOISE) == 0) { - d_sign *= 0.0; - } - - /* 2x2 Bilateral Filter using derivatives. */ - vec2 n_step = step(-0.2, -abs(vec2(length(dFdx(normal)), length(dFdy(normal))))); - vec2 z_step = step(-0.1, -abs(vec2(dFdx(frag_depth), dFdy(frag_depth)))); - - visibility -= dFdx(visibility) * d_sign.x * z_step.x * n_step.x; - visibility -= dFdy(visibility) * d_sign.y * z_step.y * n_step.y; + /* Fetch early, hide latency! */ + vec4 horizons = texelFetch(horizonBuffer, ivec2(gl_FragCoord.xy), 0); - bent_normal -= dFdx(bent_normal) * d_sign.x * z_step.x * n_step.x; - bent_normal -= dFdy(bent_normal) * d_sign.y * z_step.y * n_step.y; -} - -void gtao_deferred(vec3 normal, vec3 position, float frag_depth, out float visibility, out vec3 bent_normal) -{ + vec4 dirs; + dirs.xy = get_ao_dir(noise.x * 0.5); + dirs.zw = get_ao_dir(noise.x * 0.5 + 0.5); vec2 uvs = get_uvs_from_view(position); - vec4 texel_size = vec4(-1.0, -1.0, 1.0, 1.0) / vec2(textureSize(depthBuffer, 0)).xyxy; - - ivec2 fs_co = ivec2(gl_FragCoord.xy); - ivec2 hr_co = get_hr_co(fs_co); - bent_normal = vec3(0.0); visibility = 0.0; - for (float i = 0.0; i < MAX_PHI_STEP; i++) { - if (i >= aoSamples) break; + horizons = unpack_horizons(horizons); - vec2 horiz = unpack_horizons(texelFetch(horizonBuffer, ivec3(hr_co, int(i)), 0).rg); - float phi = get_phi(hr_co, fs_co, i); + integrate_slice(normal, dirs.xy, horizons.xy, visibility, bent_normal); + integrate_slice(normal, dirs.zw, horizons.zw, visibility, bent_normal); - integrate_slice(normal, phi, horiz.xy, visibility, bent_normal); - } + visibility *= 0.5; /* We integrated 2 slices. */ - visibility *= aoInvSamples; bent_normal = normalize(bent_normal); } -void gtao(vec3 normal, vec3 position, vec2 noise, out float visibility, out vec3 bent_normal) +void gtao(vec3 normal, vec3 position, vec4 noise, out float visibility, out vec3 bent_normal) { vec2 uvs = get_uvs_from_view(position); - - float homcco = ProjectionMatrix[2][3] * position.z + ProjectionMatrix[3][3]; - float max_dist = aoDistance / homcco; /* Search distance */ - vec2 max_dir = max_dist * vec2(ProjectionMatrix[0][0], ProjectionMatrix[1][1]); + vec2 max_dir = get_max_dir(position.z); + vec2 dir = get_ao_dir(noise.x); bent_normal = vec3(0.0); visibility = 0.0; - for (float i = 0.0; i < MAX_PHI_STEP; i++) { - if (i >= aoSamples) break; - - float phi = M_PI * (i + noise.x) * aoInvSamples; - vec2 horizons = search_horizon_sweep(phi, position, uvs, noise.g, max_dir); - - integrate_slice(normal, phi, horizons, visibility, bent_normal); - } + /* Only trace in 2 directions. May lead to a darker result but since it's mostly for + * alpha blended objects that will have overdraw, we limit the performance impact. */ + vec2 horizons = search_horizon_sweep(dir, position, uvs, noise.y, max_dir); + integrate_slice(normal, dir, horizons, visibility, bent_normal); - visibility *= aoInvSamples; bent_normal = normalize(bent_normal); } @@ -337,7 +242,7 @@ float gtao_multibounce(float visibility, vec3 albedo) } /* Use the right occlusion */ -float occlusion_compute(vec3 N, vec3 vpos, float user_occlusion, vec2 randuv, out vec3 bent_normal) +float occlusion_compute(vec3 N, vec3 vpos, float user_occlusion, vec4 rand, out vec3 bent_normal) { #ifndef USE_REFRACTION if ((int(aoSettings) & USE_AO) > 0) { @@ -345,11 +250,10 @@ float occlusion_compute(vec3 N, vec3 vpos, float user_occlusion, vec2 randuv, ou vec3 vnor = mat3(ViewMatrix) * N; #ifdef ENABLE_DEFERED_AO - gtao_deferred(vnor, vpos, gl_FragCoord.z, visibility, bent_normal); + gtao_deferred(vnor, vpos, rand, gl_FragCoord.z, visibility, bent_normal); #else - gtao(vnor, vpos, randuv, visibility, bent_normal); + gtao(vnor, vpos, rand, visibility, bent_normal); #endif - denoise_ao(vnor, gl_FragCoord.z, visibility, bent_normal); /* Prevent some problems down the road. */ visibility = max(1e-3, visibility); diff --git a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl index 37ed2235c6f..68299fe7546 100644 --- a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl @@ -11,7 +11,6 @@ uniform mat4 ProjectionMatrix; uniform mat4 ViewProjectionMatrix; uniform mat4 ViewMatrixInverse; -uniform vec4 viewvecs[2]; #ifndef SHADOW_SHADER uniform mat4 ViewMatrix; #else @@ -31,8 +30,6 @@ flat in int shFace; /* Shadow layer we are rendering to. */ #define ViewMatrix FaceViewMatrix[shFace] #endif -uniform vec2 mipRatio[10]; - /* Buffers */ uniform sampler2D colorBuffer; uniform sampler2D depthBuffer; @@ -125,6 +122,10 @@ float min_v3(vec3 v) { return min(v.x, min(v.y, v.z)); } float max_v2(vec2 v) { return max(v.x, v.y); } float max_v3(vec3 v) { return max(v.x, max(v.y, v.z)); } +float sum(vec2 v) { return dot(vec2(1.0), v); } +float sum(vec3 v) { return dot(vec3(1.0), v); } +float sum(vec4 v) { return dot(vec4(1.0), v); } + float saturate(float a) { return clamp(a, 0.0, 1.0); } vec2 saturate(vec2 a) { return clamp(a, 0.0, 1.0); } vec3 saturate(vec3 a) { return clamp(a, 0.0, 1.0); } @@ -300,7 +301,7 @@ float get_view_z_from_depth(float depth) return -ProjectionMatrix[3][2] / (d + ProjectionMatrix[2][2]); } else { - return viewvecs[0].z + depth * viewvecs[1].z; + return viewVecs[0].z + depth * viewVecs[1].z; } } @@ -311,7 +312,7 @@ float get_depth_from_view_z(float z) return d * 0.5 + 0.5; } else { - return (z - viewvecs[0].z) / viewvecs[1].z; + return (z - viewVecs[0].z) / viewVecs[1].z; } } @@ -324,10 +325,10 @@ vec2 get_uvs_from_view(vec3 view) vec3 get_view_space_from_depth(vec2 uvcoords, float depth) { if (ProjectionMatrix[3][3] == 0.0) { - return (viewvecs[0].xyz + vec3(uvcoords, 0.0) * viewvecs[1].xyz) * get_view_z_from_depth(depth); + return (viewVecs[0].xyz + vec3(uvcoords, 0.0) * viewVecs[1].xyz) * get_view_z_from_depth(depth); } else { - return viewvecs[0].xyz + vec3(uvcoords, depth) * viewvecs[1].xyz; + return viewVecs[0].xyz + vec3(uvcoords, depth) * viewVecs[1].xyz; } } @@ -545,7 +546,7 @@ vec3 F_schlick(vec3 f0, float cos_theta) /* Fresnel approximation for LTC area lights (not MRP) */ vec3 F_area(vec3 f0, vec2 lut) { - vec2 fac = normalize(lut.xy); + vec2 fac = normalize(lut.xy); /* XXX FIXME this does not work!!! */ /* Unreal specular matching : if specular color is below 2% intensity, * treat as shadowning */ @@ -691,7 +692,6 @@ Closure closure_mix(Closure cl1, Closure cl2, float fac) } else { cl.ssr_data = mix(vec4(vec3(0.0), cl2.ssr_data.w), cl2.ssr_data.xyzw, fac); /* do not blend roughness */ - cl.ssr_data = mix(vec4(vec3(0.0), cl2.ssr_data.w), cl2.ssr_data.xyzw, fac); /* do not blend roughness */ cl.ssr_normal = cl2.ssr_normal; cl.ssr_id = cl2.ssr_id; } @@ -739,12 +739,10 @@ Closure closure_add(Closure cl1, Closure cl2) #endif #endif cl.radiance = cl1.radiance + cl2.radiance; - cl.opacity = cl1.opacity + cl2.opacity; + cl.opacity = saturate(cl1.opacity + cl2.opacity); return cl; } -uniform bool sssToggle; - #if defined(MESH_SHADER) && !defined(USE_ALPHA_HASH) && !defined(USE_ALPHA_CLIP) && !defined(SHADOW_SHADER) && !defined(USE_MULTIPLY) layout(location = 0) out vec4 fragColor; #ifdef USE_SSS @@ -774,6 +772,10 @@ vec4 volumetric_resolve(vec4 scene_color, vec2 frag_uvs, float frag_depth); void main() { Closure cl = nodetree_exec(); +#ifndef USE_ALPHA_BLEND + /* Prevent alpha hash material writing into alpha channel. */ + cl.opacity = 1.0; +#endif #if defined(USE_ALPHA_BLEND_VOLUMETRICS) /* XXX fragile, better use real viewport resolution */ diff --git a/source/blender/draw/engines/eevee/shaders/bsdf_direct_lib.glsl b/source/blender/draw/engines/eevee/shaders/bsdf_direct_lib.glsl index ae03f22ac14..ddc7327334c 100644 --- a/source/blender/draw/engines/eevee/shaders/bsdf_direct_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/bsdf_direct_lib.glsl @@ -28,56 +28,30 @@ float direct_diffuse_sun(LightData ld, vec3 N) return bsdf; } -/* From Frostbite PBR Course - * Analytical irradiance from a sphere with correct horizon handling - * http://www.frostbite.com/wp-content/uploads/2014/11/course_notes_moving_frostbite_to_pbr.pdf */ +#ifdef USE_LTC float direct_diffuse_sphere(LightData ld, vec3 N, vec4 l_vector) { - float dist = l_vector.w; - vec3 L = l_vector.xyz / dist; - float radius = max(ld.l_sizex, 0.0001); - float costheta = clamp(dot(N, L), -0.999, 0.999); - float h = min(ld.l_radius / dist , 0.9999); - float h2 = h*h; - float costheta2 = costheta * costheta; - float bsdf; - - if (costheta2 > h2) { - bsdf = M_PI * h2 * clamp(costheta, 0.0, 1.0); - } - else { - float sintheta = sqrt(1.0 - costheta2); - float x = sqrt(1.0 / h2 - 1.0); - float y = -x * (costheta / sintheta); - float sinthetasqrty = sintheta * sqrt(1.0 - y * y); - bsdf = (costheta * acos(y) - x * sinthetasqrty) * h2 + atan(sinthetasqrty / x); - } - - bsdf = max(bsdf, 0.0); - bsdf *= M_1_PI2; + float NL = dot(N, l_vector.xyz / l_vector.w); - return bsdf; + return ltc_evaluate_disk_simple(ld.l_radius / l_vector.w, NL); } -#ifdef USE_LTC float direct_diffuse_rectangle(LightData ld, vec3 N, vec3 V, vec4 l_vector) { vec3 corners[4]; - corners[0] = l_vector.xyz + ld.l_right * -ld.l_sizex + ld.l_up * ld.l_sizey; - corners[1] = l_vector.xyz + ld.l_right * -ld.l_sizex + ld.l_up * -ld.l_sizey; - corners[2] = l_vector.xyz + ld.l_right * ld.l_sizex + ld.l_up * -ld.l_sizey; - corners[3] = l_vector.xyz + ld.l_right * ld.l_sizex + ld.l_up * ld.l_sizey; + corners[0] = normalize(l_vector.xyz + ld.l_right * -ld.l_sizex + ld.l_up * ld.l_sizey); + corners[1] = normalize(l_vector.xyz + ld.l_right * -ld.l_sizex + ld.l_up * -ld.l_sizey); + corners[2] = normalize(l_vector.xyz + ld.l_right * ld.l_sizex + ld.l_up * -ld.l_sizey); + corners[3] = normalize(l_vector.xyz + ld.l_right * ld.l_sizex + ld.l_up * ld.l_sizey); - float bsdf = ltc_evaluate(N, V, mat3(1.0), corners); - bsdf *= M_1_2PI; - return bsdf; + return ltc_evaluate_quad(corners, N); } -#endif -#if 0 -float direct_diffuse_unit_disc(vec3 N, vec3 L) +float direct_diffuse_unit_disc(LightData ld, vec3 N, vec3 V) { + float NL = dot(N, -ld.l_forward); + return ltc_evaluate_disk_simple(ld.l_radius, NL); } #endif @@ -106,47 +80,27 @@ vec3 direct_ggx_sun(LightData ld, vec3 N, vec3 V, float roughness, vec3 f0) #ifdef USE_LTC vec3 direct_ggx_sphere(LightData ld, vec3 N, vec3 V, vec4 l_vector, float roughness, vec3 f0) { - vec3 L = l_vector.xyz / l_vector.w; - vec3 spec_dir = get_specular_reflection_dominant_dir(N, V, roughness); - vec3 P = line_aligned_plane_intersect(vec3(0.0), spec_dir, l_vector.xyz); - - vec3 Px = normalize(P - l_vector.xyz) * ld.l_radius; - vec3 Py = cross(Px, L); + roughness = clamp(roughness, 0.0008, 0.999); /* Fix low roughness artifacts. */ vec2 uv = lut_coords(dot(N, V), sqrt(roughness)); vec3 brdf_lut = texture(utilTex, vec3(uv, 1.0)).rgb; vec4 ltc_lut = texture(utilTex, vec3(uv, 0.0)).rgba; mat3 ltc_mat = ltc_matrix(ltc_lut); -// #define HIGHEST_QUALITY -#ifdef HIGHEST_QUALITY - vec3 Pxy1 = normalize( Px + Py) * ld.l_radius; - vec3 Pxy2 = normalize(-Px + Py) * ld.l_radius; - - /* counter clockwise */ - vec3 points[8]; - points[0] = l_vector.xyz + Px; - points[1] = l_vector.xyz - Pxy2; - points[2] = l_vector.xyz - Py; - points[3] = l_vector.xyz - Pxy1; - points[4] = l_vector.xyz - Px; - points[5] = l_vector.xyz + Pxy2; - points[6] = l_vector.xyz + Py; - points[7] = l_vector.xyz + Pxy1; - float bsdf = ltc_evaluate_circle(N, V, ltc_mat, points); -#else - vec3 points[4]; - points[0] = l_vector.xyz + Px; - points[1] = l_vector.xyz - Py; - points[2] = l_vector.xyz - Px; - points[3] = l_vector.xyz + Py; - float bsdf = ltc_evaluate(N, V, ltc_mat, points); - /* sqrt(pi/2) difference between square and disk area */ - bsdf *= 1.25331413731; -#endif + /* Make orthonormal basis. */ + vec3 L = l_vector.xyz / l_vector.w; + vec3 Px, Py; + make_orthonormal_basis(L, Px, Py); + Px *= ld.l_radius; + Py *= ld.l_radius; + vec3 points[3]; + points[0] = l_vector.xyz - Px - Py; + points[1] = l_vector.xyz + Px - Py; + points[2] = l_vector.xyz + Px + Py; + + float bsdf = ltc_evaluate_disk(N, V, ltc_mat, points); bsdf *= brdf_lut.b; /* Bsdf intensity */ - bsdf *= M_1_2PI * M_1_PI; vec3 spec = F_area(f0, brdf_lut.xy) * bsdf; @@ -165,19 +119,38 @@ vec3 direct_ggx_rectangle(LightData ld, vec3 N, vec3 V, vec4 l_vector, float rou vec3 brdf_lut = texture(utilTex, vec3(uv, 1.0)).rgb; vec4 ltc_lut = texture(utilTex, vec3(uv, 0.0)).rgba; mat3 ltc_mat = ltc_matrix(ltc_lut); - float bsdf = ltc_evaluate(N, V, ltc_mat, corners); + + ltc_transform_quad(N, V, ltc_mat, corners); + float bsdf = ltc_evaluate_quad(corners, vec3(0.0, 0.0, 1.0)); bsdf *= brdf_lut.b; /* Bsdf intensity */ - bsdf *= M_1_2PI; vec3 spec = F_area(f0, brdf_lut.xy) * bsdf; return spec; } -#endif -#if 0 -float direct_ggx_disc(vec3 N, vec3 L) +vec3 direct_ggx_unit_disc(LightData ld, vec3 N, vec3 V, float roughness, vec3 f0) { + roughness = clamp(roughness, 0.0004, 0.999); /* Fix low roughness artifacts. */ + + vec2 uv = lut_coords(dot(N, V), sqrt(roughness)); + vec3 brdf_lut = texture(utilTex, vec3(uv, 1.0)).rgb; + vec4 ltc_lut = texture(utilTex, vec3(uv, 0.0)).rgba; + mat3 ltc_mat = ltc_matrix(ltc_lut); + vec3 Px = ld.l_right * ld.l_radius; + vec3 Py = ld.l_up * ld.l_radius; + + vec3 points[3]; + points[0] = -ld.l_forward - Px - Py; + points[1] = -ld.l_forward + Px - Py; + points[2] = -ld.l_forward + Px + Py; + + float bsdf = ltc_evaluate_disk(N, V, ltc_mat, points); + bsdf *= brdf_lut.b; /* Bsdf intensity */ + + vec3 spec = F_area(f0, brdf_lut.xy) * bsdf; + + return spec; } #endif
\ No newline at end of file diff --git a/source/blender/draw/engines/eevee/shaders/bsdf_sampling_lib.glsl b/source/blender/draw/engines/eevee/shaders/bsdf_sampling_lib.glsl index 13586619fe9..e5c0cb9c9c9 100644 --- a/source/blender/draw/engines/eevee/shaders/bsdf_sampling_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/bsdf_sampling_lib.glsl @@ -9,12 +9,12 @@ vec2 jitternoise = vec2(0.0); #ifndef UTIL_TEX #define UTIL_TEX uniform sampler2DArray utilTex; +#define texelfetch_noise_tex(coord) texelFetch(utilTex, ivec3(ivec2(coord) % LUT_SIZE, 2.0), 0) #endif /* UTIL_TEX */ void setup_noise(void) { - jitternoise = texture(utilTex, vec3(gl_FragCoord.xy / LUT_SIZE, 2.0)).rg; /* Global variable */ - jitternoise.g = (jitternoise.g - 0.5) * 2.0; + jitternoise = texelfetch_noise_tex(gl_FragCoord.xy).rg; /* Global variable */ } #ifdef HAMMERSLEY_SIZE diff --git a/source/blender/draw/engines/eevee/shaders/common_uniforms_lib.glsl b/source/blender/draw/engines/eevee/shaders/common_uniforms_lib.glsl new file mode 100644 index 00000000000..37106fc32bd --- /dev/null +++ b/source/blender/draw/engines/eevee/shaders/common_uniforms_lib.glsl @@ -0,0 +1,55 @@ + +layout(std140) uniform common_block { + mat4 pastViewProjectionMatrix; + vec4 viewVecs[2]; + vec2 mipRatio[10]; /* To correct mip level texel mis-alignement */ + /* Ambient Occlusion */ + vec4 aoParameters[2]; + /* Volumetric */ + ivec4 volTexSize; + vec4 volDepthParameters; /* Parameters to the volume Z equation */ + vec4 volInvTexSize; + vec4 volJitter; + vec4 volCoordScale; /* To convert volume uvs to screen uvs */ + float volHistoryAlpha; + float volLightClamp; + float volShadowSteps; + bool volUseLights; + /* Screen Space Reflections */ + vec4 ssrParameters; + float ssrBorderFac; + float ssrMaxRoughness; + float ssrFireflyFac; + float ssrBrdfBias; + bool ssrToggle; + /* SubSurface Scattering */ + float sssJitterThreshold; + bool sssToggle; + /* Specular */ + bool specToggle; + /* Lamps */ + int laNumLight; + /* Probes */ + int prbNumPlanar; + int prbNumRenderCube; + int prbNumRenderGrid; + int prbIrradianceVisSize; + float prbLodCubeMax; + float prbLodPlanarMax; +}; + +/* aoParameters */ +#define aoDistance aoParameters[0].x +#define aoSamples aoParameters[0].y /* UNUSED */ +#define aoFactor aoParameters[0].z +#define aoInvSamples aoParameters[0].w /* UNUSED */ + +#define aoOffset aoParameters[1].x /* UNUSED */ +#define aoBounceFac aoParameters[1].y +#define aoQuality aoParameters[1].z +#define aoSettings aoParameters[1].w + +/* ssrParameters */ +#define ssrQuality ssrParameters.x +#define ssrThickness ssrParameters.y +#define ssrPixelSize ssrParameters.zw
\ No newline at end of file diff --git a/source/blender/draw/engines/eevee/shaders/default_frag.glsl b/source/blender/draw/engines/eevee/shaders/default_frag.glsl index 45c5c88e763..6d941ae6ec3 100644 --- a/source/blender/draw/engines/eevee/shaders/default_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/default_frag.glsl @@ -11,7 +11,7 @@ Closure nodetree_exec(void) vec3 f0 = mix(dielectric, basecol, metallic); vec3 N = (gl_FrontFacing) ? worldNormal : -worldNormal; vec3 out_diff, out_spec, ssr_spec; - eevee_closure_default(N, albedo, f0, 0, roughness, 1.0, out_diff, out_spec, ssr_spec); + eevee_closure_default(N, albedo, f0, 1, roughness, 1.0, out_diff, out_spec, ssr_spec); Closure result = Closure(out_spec + out_diff * albedo, 1.0, vec4(ssr_spec, roughness), normal_encode(normalize(viewNormal), viewCameraVec), 0); diff --git a/source/blender/draw/engines/eevee/shaders/effect_gtao_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_gtao_frag.glsl index 1c63051c65b..32edf709d88 100644 --- a/source/blender/draw/engines/eevee/shaders/effect_gtao_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/effect_gtao_frag.glsl @@ -12,8 +12,8 @@ uniform sampler2D normalBuffer; void main() { - vec4 texel_size = 1.0 / vec2(textureSize(depthBuffer, 0)).xyxy; - vec2 uvs = saturate(gl_FragCoord.xy * texel_size.xy); + vec2 texel_size = 1.0 / vec2(textureSize(depthBuffer, 0)).xy; + vec2 uvs = saturate(gl_FragCoord.xy * texel_size); float depth = textureLod(depthBuffer, uvs, 0.0).r; @@ -23,28 +23,32 @@ void main() vec3 bent_normal; float visibility; -#if 1 - gtao_deferred(normal, viewPosition, depth, visibility, bent_normal); -#else - vec2 rand = vec2((1.0 / 4.0) * float((int(gl_FragCoord.y) & 0x1) * 2 + (int(gl_FragCoord.x) & 0x1)), 0.5); - rand = fract(rand.x + texture(utilTex, vec3(floor(gl_FragCoord.xy * 0.5) / LUT_SIZE, 2.0)).rg); - gtao(normal, viewPosition, rand, visibility, bent_normal); -#endif - denoise_ao(normal, depth, visibility, bent_normal); + + vec4 noise = texelfetch_noise_tex(gl_FragCoord.xy); + + gtao_deferred(normal, viewPosition, noise, depth, visibility, bent_normal); FragColor = vec4(visibility); } #else -uniform float sampleNbr; + +#ifdef LAYERED_DEPTH +uniform sampler2DArray depthBufferLayered; +uniform int layer; +# define gtao_depthBuffer depthBufferLayered +# define gtao_textureLod(a, b, c) textureLod(a, vec3(b, layer), c) + +#else +# define gtao_depthBuffer depthBuffer +# define gtao_textureLod(a, b, c) textureLod(a, b, c) + +#endif void main() { - ivec2 hr_co = ivec2(gl_FragCoord.xy); - ivec2 fs_co = get_fs_co(hr_co); - - vec2 uvs = saturate((vec2(fs_co) + 0.5) / vec2(textureSize(depthBuffer, 0))); - float depth = textureLod(depthBuffer, uvs, 0.0).r; + vec2 uvs = saturate(gl_FragCoord.xy / vec2(textureSize(gtao_depthBuffer, 0).xy)); + float depth = gtao_textureLod(gtao_depthBuffer, uvs, 0.0).r; if (depth == 1.0) { /* Do not trace for background */ @@ -56,14 +60,17 @@ void main() depth = saturate(depth - 3e-6); /* Tweaked for 24bit depth buffer. */ vec3 viewPosition = get_view_space_from_depth(uvs, depth); - - float phi = get_phi(hr_co, fs_co, sampleNbr); - float offset = get_offset(fs_co, sampleNbr); + vec4 noise = texelfetch_noise_tex(gl_FragCoord.xy); vec2 max_dir = get_max_dir(viewPosition.z); + vec4 dirs; + dirs.xy = get_ao_dir(noise.x * 0.5); + dirs.zw = get_ao_dir(noise.x * 0.5 + 0.5); - FragColor.xy = search_horizon_sweep(phi, viewPosition, uvs, offset, max_dir); + /* Search in 4 directions. */ + FragColor.xy = search_horizon_sweep(dirs.xy, viewPosition, uvs, noise.y, max_dir); + FragColor.zw = search_horizon_sweep(dirs.zw, viewPosition, uvs, noise.y, max_dir); /* Resize output for integer texture. */ - FragColor = pack_horizons(FragColor.xy).xyxy; + FragColor = pack_horizons(FragColor); } #endif diff --git a/source/blender/draw/engines/eevee/shaders/effect_minmaxz_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_minmaxz_frag.glsl index ce6f3568cdf..65d3970a82a 100644 --- a/source/blender/draw/engines/eevee/shaders/effect_minmaxz_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/effect_minmaxz_frag.glsl @@ -23,6 +23,10 @@ uniform sampler2D depthBuffer; #define minmax(a, b) max(a, b) #endif +#ifdef GPU_INTEL +out vec4 fragColor; +#endif + void main() { ivec2 texelPos = ivec2(gl_FragCoord.xy); @@ -61,5 +65,10 @@ void main() } #endif +#ifdef GPU_INTEL + /* Use color format instead of 24bit depth texture */ + fragColor = vec4(val); +#else gl_FragDepth = val; +#endif }
\ No newline at end of file diff --git a/source/blender/draw/engines/eevee/shaders/effect_motion_blur_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_motion_blur_frag.glsl index 1a01db3a1a3..73e284570cd 100644 --- a/source/blender/draw/engines/eevee/shaders/effect_motion_blur_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/effect_motion_blur_frag.glsl @@ -57,7 +57,7 @@ void main() float inc = 2.0 * inv_samples; float i = -1.0 + noise; - FragColor = vec4(0.0, 0.0, 0.0, 1.0); + FragColor = vec4(0.0); for (int j = 0; j < samples && j < MAX_SAMPLE; j++) { FragColor += textureLod(colorBuffer, uvcoordsvar.xy + motion * i, 0.0) * inv_samples; i += inc; diff --git a/source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl index 2dc8dfa0d1c..aa88e365d93 100644 --- a/source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl @@ -5,80 +5,78 @@ #ifndef UTIL_TEX #define UTIL_TEX uniform sampler2DArray utilTex; +#define texelfetch_noise_tex(coord) texelFetch(utilTex, ivec3(ivec2(coord) % LUT_SIZE, 2.0), 0) #endif /* UTIL_TEX */ -#define BRDF_BIAS 0.7 #define MAX_MIP 9.0 -uniform float fireflyFactor; -uniform float maxRoughness; +uniform ivec2 halfresOffset; + +ivec2 encode_hit_data(vec2 hit_pos, bool has_hit, bool is_planar) +{ + ivec2 hit_data = ivec2(saturate(hit_pos) * 32767.0); /* 16bit signed int limit */ + hit_data.x *= (is_planar) ? -1 : 1; + hit_data.y *= (has_hit) ? 1 : -1; + return hit_data; +} + +vec2 decode_hit_data(vec2 hit_data, out bool has_hit, out bool is_planar) +{ + is_planar = (hit_data.x < 0); + has_hit = (hit_data.y > 0); + return vec2(abs(hit_data)) / 32767.0; /* 16bit signed int limit */ +} #ifdef STEP_RAYTRACE uniform sampler2D normalBuffer; uniform sampler2D specroughBuffer; -uniform int planar_count; -uniform float noiseOffset; - -layout(location = 0) out vec4 hitData0; -layout(location = 1) out vec4 hitData1; -layout(location = 2) out vec4 hitData2; -layout(location = 3) out vec4 hitData3; +layout(location = 0) out ivec2 hitData; +layout(location = 1) out float pdfData; -vec4 do_planar_ssr(int index, vec3 V, vec3 N, vec3 T, vec3 B, vec3 planeNormal, vec3 viewPosition, float a2, vec3 rand, float ofs) +void do_planar_ssr(int index, vec3 V, vec3 N, vec3 T, vec3 B, vec3 planeNormal, vec3 viewPosition, float a2, vec4 rand) { - float pdf, NH; - float jitter = fract(rand.x + ofs); - - /* Importance sampling bias */ - rand.x = mix(rand.x, 0.0, BRDF_BIAS); - - vec3 H = sample_ggx(rand, a2, N, T, B, NH); /* Microfacet normal */ - pdf = pdf_ggx_reflect(NH, a2); + float NH; + vec3 H = sample_ggx(rand.xzw, a2, N, T, B, NH); /* Microfacet normal */ + float pdf = pdf_ggx_reflect(NH, a2); vec3 R = reflect(-V, H); R = reflect(R, planeNormal); /* If ray is bad (i.e. going below the plane) regenerate. */ if (dot(R, planeNormal) > 0.0) { - vec3 H = sample_ggx(rand * vec3(1.0, -1.0, -1.0), a2, N, T, B, NH); /* Microfacet normal */ + vec3 H = sample_ggx(rand.xzw * vec3(1.0, -1.0, -1.0), a2, N, T, B, NH); /* Microfacet normal */ pdf = pdf_ggx_reflect(NH, a2); R = reflect(-V, H); R = reflect(R, planeNormal); } - pdf = min(1024e32, pdf); /* Theoretical limit of 16bit float */ - pdf *= -1.0; /* Tag as planar ray. */ + pdfData = min(1024e32, pdf); /* Theoretical limit of 16bit float */ /* Since viewspace hit position can land behind the camera in this case, * we save the reflected view position (visualize it as the hit position * below the reflection plane). This way it's garanted that the hit will * be in front of the camera. That let us tag the bad rays with a negative * sign in the Z component. */ - vec3 hit_pos = raycast(index, viewPosition, R * 1e16, 1e16, jitter, ssrQuality, a2, false); + vec3 hit_pos = raycast(index, viewPosition, R * 1e16, 1e16, rand.y, ssrQuality, a2, false); - return vec4(hit_pos, pdf); + hitData = encode_hit_data(hit_pos.xy, (hit_pos.z > 0.0), true); } -vec4 do_ssr(vec3 V, vec3 N, vec3 T, vec3 B, vec3 viewPosition, float a2, vec3 rand, float ofs) +void do_ssr(vec3 V, vec3 N, vec3 T, vec3 B, vec3 viewPosition, float a2, vec4 rand) { - float pdf, NH; - float jitter = fract(rand.x + ofs); - - /* Importance sampling bias */ - rand.x = mix(rand.x, 0.0, BRDF_BIAS); - - vec3 H = sample_ggx(rand, a2, N, T, B, NH); /* Microfacet normal */ - pdf = pdf_ggx_reflect(NH, a2); + float NH; + vec3 H = sample_ggx(rand.xzw, a2, N, T, B, NH); /* Microfacet normal */ + float pdf = pdf_ggx_reflect(NH, a2); vec3 R = reflect(-V, H); - pdf = min(1024e32, pdf); /* Theoretical limit of 16bit float */ + pdfData = min(1024e32, pdf); /* Theoretical limit of 16bit float */ - vec3 hit_pos = raycast(-1, viewPosition, R * 1e16, ssrThickness, jitter, ssrQuality, a2, true); + vec3 hit_pos = raycast(-1, viewPosition, R * 1e16, ssrThickness, rand.y, ssrQuality, a2, true); - return vec4(hit_pos, pdf); + hitData = encode_hit_data(hit_pos.xy, (hit_pos.z > 0.0), false); } void main() @@ -87,20 +85,22 @@ void main() ivec2 fullres_texel = ivec2(gl_FragCoord.xy); ivec2 halfres_texel = fullres_texel; #else - ivec2 fullres_texel = ivec2(gl_FragCoord.xy) * 2; + ivec2 fullres_texel = ivec2(gl_FragCoord.xy) * 2 + halfresOffset; ivec2 halfres_texel = ivec2(gl_FragCoord.xy); #endif float depth = texelFetch(depthBuffer, fullres_texel, 0).r; + /* Default: not hits. */ + hitData = encode_hit_data(vec2(0.5), false, false); + pdfData = 0.0; + /* Early out */ + /* We can't do discard because we don't clear the render target. */ if (depth == 1.0) - discard; + return; - vec2 uvs = gl_FragCoord.xy / vec2(textureSize(depthBuffer, 0)); -#ifndef FULLRES - uvs *= 2.0; -#endif + vec2 uvs = vec2(fullres_texel) / vec2(textureSize(depthBuffer, 0)); /* Using view space */ vec3 viewPosition = get_view_space_from_depth(uvs, depth); @@ -112,18 +112,24 @@ void main() /* Early out */ if (dot(speccol_roughness.rgb, vec3(1.0)) == 0.0) - discard; + return; float roughness = speccol_roughness.a; float roughnessSquared = max(1e-3, roughness * roughness); float a2 = roughnessSquared * roughnessSquared; - if (roughness > maxRoughness + 0.2) { - hitData0 = hitData1 = hitData2 = hitData3 = vec4(0.0); + /* Early out */ + if (roughness > ssrMaxRoughness + 0.2) return; - } - vec3 rand = texelFetch(utilTex, ivec3(halfres_texel % LUT_SIZE, 2), 0).rba; + vec4 rand = texelFetch(utilTex, ivec3(halfres_texel % LUT_SIZE, 2), 0); + + /* Gives *perfect* reflection for very small roughness */ + if (roughness < 0.04) { + rand.xzw *= 0.0; + } + /* Importance sampling bias */ + rand.x = mix(rand.x, 0.0, ssrBrdfBias); vec3 worldPosition = transform_point(ViewMatrixInverse, viewPosition); vec3 wN = transform_direction(ViewMatrixInverse, N); @@ -132,7 +138,7 @@ void main() make_orthonormal_basis(N, T, B); /* Generate tangent space */ /* Planar Reflections */ - for (int i = 0; i < MAX_PLANAR && i < planar_count; ++i) { + for (int i = 0; i < MAX_PLANAR && i < prbNumPlanar; ++i) { PlanarData pd = planars_data[i]; float fade = probe_attenuation_planar(pd, worldPosition, wN, 0.0); @@ -144,31 +150,12 @@ void main() tracePosition = transform_point(ViewMatrix, tracePosition); vec3 planeNormal = transform_direction(ViewMatrix, pd.pl_normal); - hitData0 = do_planar_ssr(i, V, N, T, B, planeNormal, tracePosition, a2, rand, 0.0); -#if (RAY_COUNT > 1) - hitData1 = do_planar_ssr(i, V, N, T, B, planeNormal, tracePosition, a2, rand.xyz * vec3(1.0, -1.0, -1.0), 1.0 / float(RAY_COUNT)); -#endif -#if (RAY_COUNT > 2) - hitData2 = do_planar_ssr(i, V, N, T, B, planeNormal, tracePosition, a2, rand.xzy * vec3(1.0, 1.0, -1.0), 2.0 / float(RAY_COUNT)); -#endif -#if (RAY_COUNT > 3) - hitData3 = do_planar_ssr(i, V, N, T, B, planeNormal, tracePosition, a2, rand.xzy * vec3(1.0, -1.0, 1.0), 3.0 / float(RAY_COUNT)); -#endif + do_planar_ssr(i, V, N, T, B, planeNormal, tracePosition, a2, rand); return; } } - /* TODO : Raytrace together if textureGather is supported. */ - hitData0 = do_ssr(V, N, T, B, viewPosition, a2, rand, 0.0); -#if (RAY_COUNT > 1) - hitData1 = do_ssr(V, N, T, B, viewPosition, a2, rand.xyz * vec3(1.0, -1.0, -1.0), 1.0 / float(RAY_COUNT)); -#endif -#if (RAY_COUNT > 2) - hitData2 = do_ssr(V, N, T, B, viewPosition, a2, rand.xzy * vec3(1.0, 1.0, -1.0), 2.0 / float(RAY_COUNT)); -#endif -#if (RAY_COUNT > 3) - hitData3 = do_ssr(V, N, T, B, viewPosition, a2, rand.xzy * vec3(1.0, -1.0, 1.0), 3.0 / float(RAY_COUNT)); -#endif + do_ssr(V, N, T, B, viewPosition, a2, rand); } #else /* STEP_RESOLVE */ @@ -177,30 +164,42 @@ uniform sampler2D prevColorBuffer; /* previous frame */ uniform sampler2D normalBuffer; uniform sampler2D specroughBuffer; -uniform sampler2D hitBuffer0; -uniform sampler2D hitBuffer1; -uniform sampler2D hitBuffer2; -uniform sampler2D hitBuffer3; +uniform isampler2D hitBuffer; +uniform sampler2D pdfBuffer; + +uniform int neighborOffset; -uniform int probe_count; -uniform int planar_count; +const ivec2 neighbors[32] = ivec2[32]( + ivec2( 0, 0), ivec2( 1, 1), ivec2(-2, 0), ivec2( 0, -2), + ivec2( 0, 0), ivec2( 1, -1), ivec2(-2, 0), ivec2( 0, 2), + ivec2( 0, 0), ivec2(-1, -1), ivec2( 2, 0), ivec2( 0, 2), + ivec2( 0, 0), ivec2(-1, 1), ivec2( 2, 0), ivec2( 0, -2), -uniform mat4 PastViewProjectionMatrix; + ivec2( 0, 0), ivec2( 2, 2), ivec2(-2, 2), ivec2( 0, -1), + ivec2( 0, 0), ivec2( 2, -2), ivec2(-2, -2), ivec2( 0, 1), + ivec2( 0, 0), ivec2(-2, -2), ivec2(-2, 2), ivec2( 1, 0), + ivec2( 0, 0), ivec2( 2, 2), ivec2( 2, -2), ivec2(-1, 0) +); out vec4 fragColor; -void fallback_cubemap(vec3 N, vec3 V, vec3 W, vec3 viewPosition, float roughness, float roughnessSquared, inout vec4 spec_accum) +void fallback_cubemap( + vec3 N, vec3 V, vec3 W, vec3 viewPosition, float roughness, float roughnessSquared, inout vec4 spec_accum) { /* Specular probes */ vec3 spec_dir = get_specular_reflection_dominant_dir(N, V, roughnessSquared); - vec4 rand = texture(utilTex, vec3(gl_FragCoord.xy / LUT_SIZE, 2.0)); + vec4 rand = texelfetch_noise_tex(gl_FragCoord.xy); vec3 bent_normal; - float final_ao = occlusion_compute(N, viewPosition, 1.0, rand.rg, bent_normal); +#ifdef SSR_AO + float final_ao = occlusion_compute(N, viewPosition, 1.0, rand, bent_normal); final_ao = specular_occlusion(dot(N, V), final_ao, roughness); +#else + const float final_ao = 1.0; +#endif /* Starts at 1 because 0 is world probe */ - for (int i = 1; i < MAX_PROBE && i < probe_count && spec_accum.a < 0.999; ++i) { + for (int i = 1; i < MAX_PROBE && i < prbNumRenderCube && spec_accum.a < 0.999; ++i) { CubeData cd = probes_data[i]; float fade = probe_attenuation_cube(cd, W); @@ -251,90 +250,177 @@ float brightness(vec3 c) vec2 get_reprojected_reflection(vec3 hit, vec3 pos, vec3 N) { /* TODO real reprojection with motion vectors, etc... */ - return project_point(PastViewProjectionMatrix, hit).xy * 0.5 + 0.5; + return project_point(pastViewProjectionMatrix, hit).xy * 0.5 + 0.5; } -vec4 get_ssr_sample( - sampler2D hitBuffer, PlanarData pd, float planar_index, vec3 worldPosition, vec3 N, vec3 V, float roughnessSquared, - float cone_tan, vec2 source_uvs, vec2 texture_size, ivec2 target_texel, - inout float weight_acc) +float get_sample_depth(vec2 hit_co, bool is_planar, float planar_index) { - vec4 hit_co_pdf = texelFetch(hitBuffer, target_texel, 0).rgba; - bool has_hit = (hit_co_pdf.z > 0.0); - bool is_planar = (hit_co_pdf.w < 0.0); - hit_co_pdf.z = abs(hit_co_pdf.z); - hit_co_pdf.w = abs(hit_co_pdf.w); - - /* Hit position in world space. */ - hit_co_pdf.xyz = get_view_space_from_depth(hit_co_pdf.xy, hit_co_pdf.z); - vec3 hit_pos = transform_point(ViewMatrixInverse, hit_co_pdf.xyz); + if (is_planar) { + return textureLod(planarDepth, vec3(hit_co, planar_index), 0.0).r; + } + else { + return textureLod(depthBuffer, hit_co, 0.0).r; + } +} - vec2 ref_uvs; +vec3 get_hit_vector( + vec3 hit_pos, PlanarData pd, vec3 worldPosition, vec3 N, vec3 V, bool is_planar, + inout vec2 hit_co, inout float mask) +{ vec3 hit_vec; - float mask = 1.0; + if (is_planar) { /* Reflect back the hit position to have it in non-reflected world space */ vec3 trace_pos = line_plane_intersect(worldPosition, V, pd.pl_plane_eq); hit_vec = hit_pos - trace_pos; hit_vec = reflect(hit_vec, pd.pl_normal); - ref_uvs = project_point(ProjectionMatrix, hit_co_pdf.xyz).xy * 0.5 + 0.5; } else { /* Find hit position in previous frame. */ - ref_uvs = get_reprojected_reflection(hit_pos, worldPosition, N); + mask = screen_border_mask(gl_FragCoord.xy / vec2(textureSize(depthBuffer, 0))); + hit_co = get_reprojected_reflection(hit_pos, worldPosition, N); hit_vec = hit_pos - worldPosition; - mask = screen_border_mask(gl_FragCoord.xy / texture_size); } - mask = min(mask, screen_border_mask(ref_uvs)); - mask *= float(has_hit); - float hit_dist = max(1e-8, length(hit_vec)); - vec3 L = hit_vec / hit_dist; + mask = min(mask, screen_border_mask(hit_co)); + return hit_vec; +} - float cone_footprint = hit_dist * cone_tan; +vec3 get_scene_color(vec2 ref_uvs, float mip, float planar_index, bool is_planar) +{ + if (is_planar) { + return textureLod(probePlanars, vec3(ref_uvs, planar_index), min(mip, prbLodPlanarMax)).rgb; + } + else { + return textureLod(prevColorBuffer, ref_uvs, mip).rgb; + } +} + +vec4 get_ssr_samples( + vec4 hit_pdf, ivec4 hit_data[2], + PlanarData pd, float planar_index, vec3 worldPosition, vec3 N, vec3 V, + float roughnessSquared, float cone_tan, vec2 source_uvs, + inout float weight_acc) +{ + bvec4 is_planar, has_hit; + vec4 hit_co[2]; + hit_co[0].xy = decode_hit_data(hit_data[0].xy, has_hit.x, is_planar.x); + hit_co[0].zw = decode_hit_data(hit_data[0].zw, has_hit.y, is_planar.y); + hit_co[1].xy = decode_hit_data(hit_data[1].xy, has_hit.z, is_planar.z); + hit_co[1].zw = decode_hit_data(hit_data[1].zw, has_hit.w, is_planar.w); + + vec4 hit_depth; + hit_depth.x = get_sample_depth(hit_co[0].xy, is_planar.x, planar_index); + hit_depth.y = get_sample_depth(hit_co[0].zw, is_planar.y, planar_index); + hit_depth.z = get_sample_depth(hit_co[1].xy, is_planar.z, planar_index); + hit_depth.w = get_sample_depth(hit_co[1].zw, is_planar.w, planar_index); + + /* Hit position in view space. */ + vec3 hit_view[4]; + hit_view[0] = get_view_space_from_depth(hit_co[0].xy, hit_depth.x); + hit_view[1] = get_view_space_from_depth(hit_co[0].zw, hit_depth.y); + hit_view[2] = get_view_space_from_depth(hit_co[1].xy, hit_depth.z); + hit_view[3] = get_view_space_from_depth(hit_co[1].zw, hit_depth.w); + + vec4 homcoord = vec4(hit_view[0].z, hit_view[1].z, hit_view[2].z, hit_view[3].z); + homcoord = ProjectionMatrix[2][3] * homcoord + ProjectionMatrix[3][3]; + + /* Hit position in world space. */ + vec3 hit_pos[4]; + hit_pos[0] = transform_point(ViewMatrixInverse, hit_view[0]); + hit_pos[1] = transform_point(ViewMatrixInverse, hit_view[1]); + hit_pos[2] = transform_point(ViewMatrixInverse, hit_view[2]); + hit_pos[3] = transform_point(ViewMatrixInverse, hit_view[3]); + + /* Get actual hit vector and hit coordinate (from last frame). */ + vec4 mask = vec4(1.0); + hit_pos[0] = get_hit_vector(hit_pos[0], pd, worldPosition, N, V, is_planar.x, hit_co[0].xy, mask.x); + hit_pos[1] = get_hit_vector(hit_pos[1], pd, worldPosition, N, V, is_planar.y, hit_co[0].zw, mask.y); + hit_pos[2] = get_hit_vector(hit_pos[2], pd, worldPosition, N, V, is_planar.z, hit_co[1].xy, mask.z); + hit_pos[3] = get_hit_vector(hit_pos[3], pd, worldPosition, N, V, is_planar.w, hit_co[1].zw, mask.w); + + vec4 hit_dist; + hit_dist.x = length(hit_pos[0]); + hit_dist.y = length(hit_pos[1]); + hit_dist.z = length(hit_pos[2]); + hit_dist.w = length(hit_pos[3]); + hit_dist = max(vec4(1e-8), hit_dist); + + /* Normalize */ + hit_pos[0] /= hit_dist.x; + hit_pos[1] /= hit_dist.y; + hit_pos[2] /= hit_dist.z; + hit_pos[3] /= hit_dist.w; /* Compute cone footprint in screen space. */ - float homcoord = ProjectionMatrix[2][3] * hit_co_pdf.z + ProjectionMatrix[3][3]; - cone_footprint = BRDF_BIAS * 0.5 * cone_footprint * max(ProjectionMatrix[0][0], ProjectionMatrix[1][1]) / homcoord; + vec4 cone_footprint = hit_dist * cone_tan; + cone_footprint = ssrBrdfBias * 0.5 * cone_footprint * max(ProjectionMatrix[0][0], ProjectionMatrix[1][1]) / homcoord; /* Estimate a cone footprint to sample a corresponding mipmap level. */ - float mip = clamp(log2(cone_footprint * max(texture_size.x, texture_size.y)), 0.0, MAX_MIP); + vec4 mip = log2(cone_footprint * max_v2(vec2(textureSize(depthBuffer, 0)))); + mip = clamp(mip, 0.0, MAX_MIP); /* Correct UVs for mipmaping mis-alignment */ - ref_uvs *= mip_ratio_interp(mip); + hit_co[0].xy *= mip_ratio_interp(mip.x); + hit_co[0].zw *= mip_ratio_interp(mip.y); + hit_co[1].xy *= mip_ratio_interp(mip.z); + hit_co[1].zw *= mip_ratio_interp(mip.w); /* Slide 54 */ - float bsdf = bsdf_ggx(N, L, V, roughnessSquared); - float weight = step(1e-8, hit_co_pdf.w) * bsdf / max(1e-8, hit_co_pdf.w); - weight_acc += weight; + vec4 bsdf; + bsdf.x = bsdf_ggx(N, hit_pos[0], V, roughnessSquared); + bsdf.y = bsdf_ggx(N, hit_pos[1], V, roughnessSquared); + bsdf.z = bsdf_ggx(N, hit_pos[2], V, roughnessSquared); + bsdf.w = bsdf_ggx(N, hit_pos[3], V, roughnessSquared); - vec3 sample; - if (is_planar) { - sample = textureLod(probePlanars, vec3(ref_uvs, planar_index), min(mip, lodPlanarMax)).rgb; - } - else { - sample = textureLod(prevColorBuffer, ref_uvs, mip).rgb; - } + vec4 weight = step(1e-8, hit_pdf) * bsdf / max(vec4(1e-8), hit_pdf); - /* Clamped brightness. */ - float luma = max(1e-8, brightness(sample)); - sample *= 1.0 - max(0.0, luma - fireflyFactor) / luma; + vec3 sample[4]; + sample[0] = get_scene_color(hit_co[0].xy, mip.x, planar_index, is_planar.x); + sample[1] = get_scene_color(hit_co[0].zw, mip.y, planar_index, is_planar.y); + sample[2] = get_scene_color(hit_co[1].xy, mip.z, planar_index, is_planar.z); + sample[3] = get_scene_color(hit_co[1].zw, mip.w, planar_index, is_planar.w); - /* Do not add light if ray has failed. */ - sample *= float(has_hit); + /* Clamped brightness. */ + vec4 luma; + luma.x = brightness(sample[0]); + luma.y = brightness(sample[1]); + luma.z = brightness(sample[2]); + luma.w = brightness(sample[3]); + luma = max(vec4(1e-8), luma); + luma = 1.0 - max(vec4(0.0), luma - ssrFireflyFac) / luma; + + sample[0] *= luma.x; + sample[1] *= luma.y; + sample[2] *= luma.z; + sample[3] *= luma.w; /* Protection against NaNs in the history buffer. * This could be removed if some previous pass has already * sanitized the input. */ - if (any(isnan(sample))) { - sample = vec3(0.0); - weight = 0.0; + if (any(isnan(sample[0]))) { + sample[0] = vec3(0.0); weight.x = 0.0; + } + if (any(isnan(sample[1]))) { + sample[1] = vec3(0.0); weight.y = 0.0; + } + if (any(isnan(sample[2]))) { + sample[2] = vec3(0.0); weight.z = 0.0; + } + if (any(isnan(sample[3]))) { + sample[3] = vec3(0.0); weight.w = 0.0; } - return vec4(sample, mask) * weight; -} + weight_acc += sum(weight); -#define NUM_NEIGHBORS 4 + /* Do not add light if ray has failed. */ + vec4 accum; + accum = vec4(sample[0], mask.x) * weight.x * float(has_hit.x); + accum += vec4(sample[1], mask.y) * weight.y * float(has_hit.y); + accum += vec4(sample[2], mask.z) * weight.z * float(has_hit.z); + accum += vec4(sample[3], mask.w) * weight.w * float(has_hit.w); + return accum; +} void main() { @@ -344,9 +430,7 @@ void main() #else ivec2 halfres_texel = ivec2(gl_FragCoord.xy / 2.0); #endif - vec2 texture_size = vec2(textureSize(depthBuffer, 0)); - vec2 uvs = gl_FragCoord.xy / texture_size; - vec3 rand = texelFetch(utilTex, ivec3(fullres_texel % LUT_SIZE, 2), 0).rba; + vec2 uvs = gl_FragCoord.xy / vec2(textureSize(depthBuffer, 0)); float depth = textureLod(depthBuffer, uvs, 0.0).r; @@ -366,10 +450,24 @@ void main() if (dot(speccol_roughness.rgb, vec3(1.0)) == 0.0) discard; + /* TODO optimize with textureGather */ + /* Doing these fetches early to hide latency. */ + vec4 hit_pdf; + hit_pdf.x = texelFetch(pdfBuffer, halfres_texel + neighbors[0 + neighborOffset], 0).r; + hit_pdf.y = texelFetch(pdfBuffer, halfres_texel + neighbors[1 + neighborOffset], 0).r; + hit_pdf.z = texelFetch(pdfBuffer, halfres_texel + neighbors[2 + neighborOffset], 0).r; + hit_pdf.w = texelFetch(pdfBuffer, halfres_texel + neighbors[3 + neighborOffset], 0).r; + + ivec4 hit_data[2]; + hit_data[0].xy = texelFetch(hitBuffer, halfres_texel + neighbors[0 + neighborOffset], 0).rg; + hit_data[0].zw = texelFetch(hitBuffer, halfres_texel + neighbors[1 + neighborOffset], 0).rg; + hit_data[1].xy = texelFetch(hitBuffer, halfres_texel + neighbors[2 + neighborOffset], 0).rg; + hit_data[1].zw = texelFetch(hitBuffer, halfres_texel + neighbors[3 + neighborOffset], 0).rg; + /* Find Planar Reflections affecting this pixel */ PlanarData pd; float planar_index; - for (int i = 0; i < MAX_PLANAR && i < planar_count; ++i) { + for (int i = 0; i < MAX_PLANAR && i < prbNumPlanar; ++i) { pd = planars_data[i]; float fade = probe_attenuation_planar(pd, worldPosition, N, 0.0); @@ -390,55 +488,21 @@ void main() float cone_tan = sqrt(1 - cone_cos * cone_cos) / cone_cos; cone_tan *= mix(saturate(dot(N, -V) * 2.0), 1.0, roughness); /* Elongation fit */ - vec2 source_uvs = project_point(PastViewProjectionMatrix, worldPosition).xy * 0.5 + 0.5; + vec2 source_uvs = project_point(pastViewProjectionMatrix, worldPosition).xy * 0.5 + 0.5; vec4 ssr_accum = vec4(0.0); float weight_acc = 0.0; - const ivec2 neighbors[9] = ivec2[9]( - ivec2(0, 0), - - ivec2(0, 1), - ivec2(-1, -1), ivec2(1, -1), - - ivec2(-1, 1), ivec2(1, 1), - ivec2(0, -1), - - ivec2(-1, 0), ivec2(1, 0) - ); - ivec2 invert_neighbor; - invert_neighbor.x = ((fullres_texel.x & 0x1) == 0) ? 1 : -1; - invert_neighbor.y = ((fullres_texel.y & 0x1) == 0) ? 1 : -1; - - if (roughness < maxRoughness + 0.2) { - for (int i = 0; i < NUM_NEIGHBORS; i++) { - ivec2 target_texel = halfres_texel + neighbors[i] * invert_neighbor; - - ssr_accum += get_ssr_sample(hitBuffer0, pd, planar_index, worldPosition, N, V, - roughnessSquared, cone_tan, source_uvs, - texture_size, target_texel, weight_acc); -#if (RAY_COUNT > 1) - ssr_accum += get_ssr_sample(hitBuffer1, pd, planar_index, worldPosition, N, V, - roughnessSquared, cone_tan, source_uvs, - texture_size, target_texel, weight_acc); -#endif -#if (RAY_COUNT > 2) - ssr_accum += get_ssr_sample(hitBuffer2, pd, planar_index, worldPosition, N, V, - roughnessSquared, cone_tan, source_uvs, - texture_size, target_texel, weight_acc); -#endif -#if (RAY_COUNT > 3) - ssr_accum += get_ssr_sample(hitBuffer3, pd, planar_index, worldPosition, N, V, - roughnessSquared, cone_tan, source_uvs, - texture_size, target_texel, weight_acc); -#endif - } + + if (roughness < ssrMaxRoughness + 0.2) { + ssr_accum += get_ssr_samples(hit_pdf, hit_data, pd, planar_index, worldPosition, N, V, + roughnessSquared, cone_tan, source_uvs, weight_acc); } /* Compute SSR contribution */ if (weight_acc > 0.0) { ssr_accum /= weight_acc; /* fade between 0.5 and 1.0 roughness */ - ssr_accum.a *= smoothstep(maxRoughness + 0.2, maxRoughness, roughness); + ssr_accum.a *= smoothstep(ssrMaxRoughness + 0.2, ssrMaxRoughness, roughness); accumulate_light(ssr_accum.rgb, ssr_accum.a, spec_accum); } diff --git a/source/blender/draw/engines/eevee/shaders/effect_subsurface_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_subsurface_frag.glsl index 88e71a060c5..184eac54c26 100644 --- a/source/blender/draw/engines/eevee/shaders/effect_subsurface_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/effect_subsurface_frag.glsl @@ -8,16 +8,19 @@ layout(std140) uniform sssProfile { int sss_samples; }; -uniform float jitterThreshold; uniform sampler2D depthBuffer; uniform sampler2D sssData; uniform sampler2D sssAlbedo; + +#ifndef UTIL_TEX +#define UTIL_TEX uniform sampler2DArray utilTex; +#define texelfetch_noise_tex(coord) texelFetch(utilTex, ivec3(ivec2(coord) % LUT_SIZE, 2.0), 0) +#endif /* UTIL_TEX */ out vec4 FragColor; uniform mat4 ProjectionMatrix; -uniform vec4 viewvecs[2]; float get_view_z_from_depth(float depth) { @@ -26,7 +29,7 @@ float get_view_z_from_depth(float depth) return -ProjectionMatrix[3][2] / (d + ProjectionMatrix[2][2]); } else { - return viewvecs[0].z + depth * viewvecs[1].z; + return viewVecs[0].z + depth * viewVecs[1].z; } } @@ -41,7 +44,7 @@ void main(void) vec4 sss_data = texture(sssData, uvs).rgba; float depth_view = get_view_z_from_depth(texture(depthBuffer, uvs).r); - float rand = texelFetch(utilTex, ivec3(ivec2(gl_FragCoord.xy) % LUT_SIZE, 2), 0).r; + float rand = texelfetch_noise_tex(gl_FragCoord.xy).r; #ifdef FIRST_PASS float angle = M_2PI * rand + M_PI_2; vec2 dir = vec2(1.0, 0.0); @@ -61,7 +64,7 @@ void main(void) vec3 accum = sss_data.rgb * kernel[0].rgb; for (int i = 1; i < sss_samples && i < MAX_SSS_SAMPLES; i++) { - vec2 sample_uv = uvs + kernel[i].a * finalStep * ((abs(kernel[i].a) > jitterThreshold) ? dir : dir_rand); + vec2 sample_uv = uvs + kernel[i].a * finalStep * ((abs(kernel[i].a) > sssJitterThreshold) ? dir : dir_rand); vec3 color = texture(sssData, sample_uv).rgb; float sample_depth = texture(depthBuffer, sample_uv).r; sample_depth = get_view_z_from_depth(sample_depth); diff --git a/source/blender/draw/engines/eevee/shaders/irradiance_lib.glsl b/source/blender/draw/engines/eevee/shaders/irradiance_lib.glsl index 76d20486d3d..132cc16fcbd 100644 --- a/source/blender/draw/engines/eevee/shaders/irradiance_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/irradiance_lib.glsl @@ -1,6 +1,5 @@ uniform sampler2DArray irradianceGrid; -uniform int irradianceVisibilitySize; #define IRRADIANCE_LIB @@ -81,8 +80,8 @@ IrradianceData load_irradiance_cell(int cell, vec3 N) float load_visibility_cell(int cell, vec3 L, float dist, float bias, float bleed_bias, float range) { /* Keep in sync with diffuse_filter_probe() */ - ivec2 cell_co = ivec2(irradianceVisibilitySize); - ivec2 cell_per_row_col = textureSize(irradianceGrid, 0).xy / irradianceVisibilitySize; + ivec2 cell_co = ivec2(prbIrradianceVisSize); + ivec2 cell_per_row_col = textureSize(irradianceGrid, 0).xy / prbIrradianceVisSize; cell_co.x *= (cell % cell_per_row_col.x); cell_co.y *= (cell / cell_per_row_col.x) % cell_per_row_col.y; float layer = 1.0 + float((cell / cell_per_row_col.x) / cell_per_row_col.y); @@ -90,8 +89,8 @@ float load_visibility_cell(int cell, vec3 L, float dist, float bias, float bleed vec2 texel_size = 1.0 / vec2(textureSize(irradianceGrid, 0).xy); vec2 co = vec2(cell_co) * texel_size; - vec2 uv = mapping_octahedron(-L, vec2(1.0 / float(irradianceVisibilitySize))); - uv *= vec2(irradianceVisibilitySize) * texel_size; + vec2 uv = mapping_octahedron(-L, vec2(1.0 / float(prbIrradianceVisSize))); + uv *= vec2(prbIrradianceVisSize) * texel_size; vec4 data = texture(irradianceGrid, vec3(co + uv, layer)); diff --git a/source/blender/draw/engines/eevee/shaders/lamps_lib.glsl b/source/blender/draw/engines/eevee/shaders/lamps_lib.glsl index 933f056c401..1c7956bb807 100644 --- a/source/blender/draw/engines/eevee/shaders/lamps_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/lamps_lib.glsl @@ -161,7 +161,7 @@ float light_visibility(LightData ld, vec3 W, float x = dot(ld.l_right, lL) / ld.l_sizex; float y = dot(ld.l_up, lL) / ld.l_sizey; - float ellipse = 1.0 / sqrt(1.0 + x * x + y * y); + float ellipse = inversesqrt(1.0 + x * x + y * y); float spotmask = smoothstep(0.0, 1.0, (ellipse - ld.l_spot_size) / ld.l_spot_blend); @@ -203,14 +203,13 @@ float light_visibility(LightData ld, vec3 W, vec3 T, B; make_orthonormal_basis(L.xyz / L.w, T, B); - vec3 rand = texture(utilTex, vec3(gl_FragCoord.xy / LUT_SIZE, 2.0)).xzw; - /* XXX This is a hack to not have noise correlation artifacts. - * A better solution to have better noise is welcome. */ - rand.yz *= fast_sqrt(fract(rand.x * 7919.0)) * data.sh_contact_spread; + vec4 rand = texelfetch_noise_tex(gl_FragCoord.xy); + /* WATCH THIS : This still seems to have correlation artifacts for low samples. */ + rand.zw *= fast_sqrt(rand.y) * data.sh_contact_spread; /* We use the full l_vector.xyz so that the spread is minimize * if the shading point is further away from the light source */ - vec3 ray_dir = L.xyz + T * rand.y + B * rand.z; + vec3 ray_dir = L.xyz + T * rand.z + B * rand.w; ray_dir = transform_direction(ViewMatrix, ray_dir); ray_dir = normalize(ray_dir); vec3 ray_origin = viewPosition + viewNormal * data.sh_contact_offset; @@ -235,8 +234,7 @@ float light_diffuse(LightData ld, vec3 N, vec3 V, vec4 l_vector) { #ifdef USE_LTC if (ld.l_type == SUN) { - /* TODO disk area light */ - return direct_diffuse_sun(ld, N); + return direct_diffuse_unit_disc(ld, N, V); } else if (ld.l_type == AREA) { return direct_diffuse_rectangle(ld, N, V, l_vector); @@ -258,8 +256,7 @@ vec3 light_specular(LightData ld, vec3 N, vec3 V, vec4 l_vector, float roughness { #ifdef USE_LTC if (ld.l_type == SUN) { - /* TODO disk area light */ - return direct_ggx_sun(ld, N, V, roughness, f0); + return direct_ggx_unit_disc(ld, N, V, roughness, f0); } else if (ld.l_type == AREA) { return direct_ggx_rectangle(ld, N, V, l_vector, roughness, f0); @@ -298,9 +295,7 @@ vec3 light_translucent(LightData ld, vec3 W, vec3 N, vec4 l_vector, float scale) { #if !defined(USE_TRANSLUCENCY) || defined(VOLUMETRICS) return vec3(0.0); -#endif - -#ifndef VOLUMETRICS +#else vec3 vis = vec3(1.0); /* Only shadowed light can produce translucency */ @@ -313,14 +308,13 @@ vec3 light_translucent(LightData ld, vec3 W, vec3 N, vec4 l_vector, float scale) vec3 T, B; make_orthonormal_basis(L.xyz / L.w, T, B); - vec3 rand = texture(utilTex, vec3(gl_FragCoord.xy / LUT_SIZE, 2.0)).xzw; - /* XXX This is a hack to not have noise correlation artifacts. - * A better solution to have better noise is welcome. */ - rand.yz *= fast_sqrt(fract(rand.x * 7919.0)) * data.sh_blur; + vec4 rand = texelfetch_noise_tex(gl_FragCoord.xy); + /* WATCH THIS : This still seems to have correlation artifacts for low samples. */ + rand.zw *= fast_sqrt(rand.y) * data.sh_blur; /* We use the full l_vector.xyz so that the spread is minimize * if the shading point is further away from the light source */ - W = W + T * rand.y + B * rand.z; + W = W + T * rand.z + B * rand.w; if (ld.l_type == SUN) { ShadowCascadeData scd = shadows_cascade_data[int(data.sh_data_start)]; @@ -374,19 +368,24 @@ vec3 light_translucent(LightData ld, vec3 W, vec3 N, vec4 l_vector, float scale) /* TODO : put this out of the shader. */ float falloff; if (ld.l_type == AREA) { - vis *= 0.0962 * (ld.l_sizex * ld.l_sizey * 4.0 * M_PI); + vis *= (ld.l_sizex * ld.l_sizey * 4.0 * M_PI) * (1.0 / 80.0); + vis *= 0.3 * 20.0 * max(0.0, dot(-ld.l_forward, l_vector.xyz / l_vector.w)); /* XXX ad hoc, empirical */ vis /= (l_vector.w * l_vector.w); falloff = dot(N, l_vector.xyz / l_vector.w); } else if (ld.l_type == SUN) { + vis *= (4.0f * ld.l_radius * ld.l_radius * M_2PI) * (1.0 / 12.5); /* Removing area light power*/ + vis *= M_2PI * 0.78; /* Matching cycles with point light. */ + vis *= 0.082; /* XXX ad hoc, empirical */ falloff = dot(N, -ld.l_forward); } else { - vis *= 0.0248 * (4.0 * ld.l_radius * ld.l_radius * M_PI * M_PI); + vis *= (4.0 * ld.l_radius * ld.l_radius) * (1.0 /10.0); + vis *= 1.5; /* XXX ad hoc, empirical */ vis /= (l_vector.w * l_vector.w); falloff = dot(N, l_vector.xyz / l_vector.w); } - vis *= M_1_PI; /* Normalize */ + // vis *= M_1_PI; /* Normalize */ /* Applying profile */ vis *= sss_profile(abs(delta) / scale); @@ -400,7 +399,7 @@ vec3 light_translucent(LightData ld, vec3 W, vec3 N, vec4 l_vector, float scale) float x = dot(ld.l_right, lL) / ld.l_sizex; float y = dot(ld.l_up, lL) / ld.l_sizey; - float ellipse = 1.0 / sqrt(1.0 + x * x + y * y); + float ellipse = inversesqrt(1.0 + x * x + y * y); float spotmask = smoothstep(0.0, 1.0, (ellipse - ld.l_spot_size) / ld.l_spot_blend); diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_cube_display_frag.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_cube_display_frag.glsl index fc0b5b9548b..d10f4bc0d42 100644 --- a/source/blender/draw/engines/eevee/shaders/lightprobe_cube_display_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/lightprobe_cube_display_frag.glsl @@ -11,5 +11,5 @@ void main() ? normalize(cameraPos - worldPosition) : cameraForward; vec3 N = normalize(worldNormal); - FragColor = vec4(textureLod_octahedron(probeCubes, vec4(reflect(-V, N), pid), 0.0, lodCubeMax).rgb, 1.0); + FragColor = vec4(textureLod_octahedron(probeCubes, vec4(reflect(-V, N), pid), 0.0, prbLodCubeMax).rgb, 1.0); } diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_filter_diffuse_frag.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_filter_diffuse_frag.glsl index eb4315c93a3..b19ee7a9ea3 100644 --- a/source/blender/draw/engines/eevee/shaders/lightprobe_filter_diffuse_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/lightprobe_filter_diffuse_frag.glsl @@ -3,6 +3,7 @@ uniform samplerCube probeHdr; uniform int probeSize; uniform float lodFactor; uniform float lodMax; +uniform float intensityFac; in vec3 worldPosition; @@ -192,6 +193,6 @@ void main() } } - FragColor = irradiance_encode(out_radiance / weight); + FragColor = irradiance_encode(intensityFac * out_radiance / weight); #endif }
\ No newline at end of file diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_filter_glossy_frag.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_filter_glossy_frag.glsl index 33714c5293c..3aec3ce4642 100644 --- a/source/blender/draw/engines/eevee/shaders/lightprobe_filter_glossy_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/lightprobe_filter_glossy_frag.glsl @@ -5,6 +5,7 @@ uniform float texelSize; uniform float lodFactor; uniform float lodMax; uniform float paddingSize; +uniform float intensityFac; in vec3 worldPosition; @@ -82,5 +83,5 @@ void main() { } } - FragColor = vec4(out_radiance / weight, 1.0); + FragColor = vec4(intensityFac * out_radiance / weight, 1.0); }
\ No newline at end of file diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl index e914228aded..429f6ea92e4 100644 --- a/source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl @@ -1,10 +1,7 @@ /* ----------- Uniforms --------- */ uniform sampler2DArray probePlanars; -uniform float lodPlanarMax; - uniform sampler2DArray probeCubes; -uniform float lodCubeMax; /* ----------- Structures --------- */ @@ -162,12 +159,12 @@ vec3 probe_evaluate_cube(float id, CubeData cd, vec3 W, vec3 R, float roughness) float fac = saturate(original_roughness * 2.0 - 1.0); R = mix(intersection, R, fac * fac); - return textureLod_octahedron(probeCubes, vec4(R, id), roughness * lodCubeMax, lodCubeMax).rgb; + return textureLod_octahedron(probeCubes, vec4(R, id), roughness * prbLodCubeMax, prbLodCubeMax).rgb; } vec3 probe_evaluate_world_spec(vec3 R, float roughness) { - return textureLod_octahedron(probeCubes, vec4(R, 0.0), roughness * lodCubeMax, lodCubeMax).rgb; + return textureLod_octahedron(probeCubes, vec4(R, 0.0), roughness * prbLodCubeMax, prbLodCubeMax).rgb; } vec3 probe_evaluate_planar( diff --git a/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl b/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl index 6ecaf0a627b..cc66b477da0 100644 --- a/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl @@ -2,19 +2,12 @@ #ifndef LIT_SURFACE_UNIFORM #define LIT_SURFACE_UNIFORM -uniform int light_count; -uniform int probe_count; -uniform int grid_count; -uniform int planar_count; - -uniform bool specToggle; -uniform bool ssrToggle; - uniform float refractionDepth; #ifndef UTIL_TEX #define UTIL_TEX uniform sampler2DArray utilTex; +#define texelfetch_noise_tex(coord) texelFetch(utilTex, ivec3(ivec2(coord) % LUT_SIZE, 2.0), 0) #endif /* UTIL_TEX */ in vec3 worldPosition; @@ -28,9 +21,6 @@ in vec3 worldNormal; in vec3 viewNormal; #endif -uniform float maxRoughness; -uniform int rayCount; - #endif /* LIT_SURFACE_UNIFORM */ /** AUTO CONFIG @@ -176,7 +166,7 @@ void CLOSURE_NAME( vec3 V = cameraVec; - vec4 rand = texture(utilTex, vec3(gl_FragCoord.xy / LUT_SIZE, 2.0)); + vec4 rand = texelFetch(utilTex, ivec3(ivec2(gl_FragCoord.xy) % LUT_SIZE, 2.0), 0); /* ---------------------------------------------------------------- */ /* -------------------- SCENE LAMPS LIGHTING ---------------------- */ @@ -187,7 +177,7 @@ void CLOSURE_NAME( norm_view = normalize(cross(norm_view, N)); /* Normal facing view */ #endif - for (int i = 0; i < MAX_LIGHT && i < light_count; ++i) { + for (int i = 0; i < MAX_LIGHT && i < laNumLight; ++i) { LightData ld = lights_data[i]; vec4 l_vector; /* Non-Normalized Light Vector with length in last component. */ @@ -266,7 +256,7 @@ void CLOSURE_NAME( /* Planar Reflections */ /* ---------------------------- */ - for (int i = 0; i < MAX_PLANAR && i < planar_count && spec_accum.a < 0.999; ++i) { + for (int i = 0; i < MAX_PLANAR && i < prbNumPlanar && spec_accum.a < 0.999; ++i) { PlanarData pd = planars_data[i]; /* Fade on geometric normal. */ @@ -312,17 +302,11 @@ void CLOSURE_NAME( /* Screen Space Refraction */ /* ---------------------------- */ #ifdef USE_REFRACTION - if (ssrToggle && roughness < maxRoughness + 0.2) { + if (ssrToggle && roughness < ssrMaxRoughness + 0.2) { /* Find approximated position of the 2nd refraction event. */ vec3 refr_vpos = (refractionDepth > 0.0) ? transform_point(ViewMatrix, refr_pos) : viewPosition; - - float ray_ofs = 1.0 / float(rayCount); - vec4 trans = screen_space_refraction(refr_vpos, N, refr_V, final_ior, roughnessSquared, rand.xzw, 0.0); - if (rayCount > 1) trans += screen_space_refraction(refr_vpos, N, refr_V, final_ior, roughnessSquared, rand.xzw * vec3(1.0, -1.0, -1.0), 1.0 * ray_ofs); - if (rayCount > 2) trans += screen_space_refraction(refr_vpos, N, refr_V, final_ior, roughnessSquared, rand.xwz * vec3(1.0, 1.0, -1.0), 2.0 * ray_ofs); - if (rayCount > 3) trans += screen_space_refraction(refr_vpos, N, refr_V, final_ior, roughnessSquared, rand.xwz * vec3(1.0, -1.0, 1.0), 3.0 * ray_ofs); - trans /= float(rayCount); - trans.a *= smoothstep(maxRoughness + 0.2, maxRoughness, roughness); + vec4 trans = screen_space_refraction(refr_vpos, N, refr_V, final_ior, roughnessSquared, rand); + trans.a *= smoothstep(ssrMaxRoughness + 0.2, ssrMaxRoughness, roughness); accumulate_light(trans.rgb, trans.a, refr_accum); } #endif @@ -342,7 +326,7 @@ void CLOSURE_NAME( #endif /* Starts at 1 because 0 is world probe */ - for (int i = 1; ACCUM.a < 0.999 && i < probe_count && i < MAX_PROBE; ++i) { + for (int i = 1; ACCUM.a < 0.999 && i < prbNumRenderCube && i < MAX_PROBE; ++i) { CubeData cd = probes_data[i]; float fade = probe_attenuation_cube(cd, worldPosition); @@ -402,7 +386,7 @@ void CLOSURE_NAME( /* ---------------------------- */ #if defined(CLOSURE_GLOSSY) || defined(CLOSURE_DIFFUSE) vec3 bent_normal; - float final_ao = occlusion_compute(N, viewPosition, ao, rand.rg, bent_normal); + float final_ao = occlusion_compute(N, viewPosition, ao, rand, bent_normal); #endif @@ -417,12 +401,14 @@ void CLOSURE_NAME( /* This factor is outputed to be used by SSR in order * to match the intensity of the regular reflections. */ ssr_spec = F_ibl(f0, brdf_lut); - if (!(ssrToggle && ssr_id == outputSsrId)) { - /* The SSR pass recompute the occlusion to not apply it to the SSR */ - ssr_spec *= specular_occlusion(NV, final_ao, roughness); + float spec_occlu = specular_occlusion(NV, final_ao, roughness); + + /* The SSR pass recompute the occlusion to not apply it to the SSR */ + if (ssrToggle && ssr_id == outputSsrId) { + spec_occlu = 1.0; } - out_spec += spec_accum.rgb * ssr_spec * float(specToggle); + out_spec += spec_accum.rgb * ssr_spec * spec_occlu * float(specToggle); #endif #ifdef CLOSURE_REFRACTION @@ -452,7 +438,7 @@ void CLOSURE_NAME( /* Irradiance Grids */ /* ---------------------------- */ /* Start at 1 because 0 is world irradiance */ - for (int i = 1; i < MAX_GRID && i < grid_count && diff_accum.a < 0.999; ++i) { + for (int i = 1; i < MAX_GRID && i < prbNumRenderGrid && diff_accum.a < 0.999; ++i) { GridData gd = grids_data[i]; vec3 localpos; @@ -467,7 +453,7 @@ void CLOSURE_NAME( /* ---------------------------- */ /* World Diffuse */ /* ---------------------------- */ - if (diff_accum.a < 0.999 && grid_count > 0) { + if (diff_accum.a < 0.999 && prbNumRenderGrid > 0) { vec3 diff = probe_evaluate_world_diff(bent_normal); accumulate_light(diff, 1.0, diff_accum); } diff --git a/source/blender/draw/engines/eevee/shaders/ltc_lib.glsl b/source/blender/draw/engines/eevee/shaders/ltc_lib.glsl index ffaa81c3638..5c62cb19152 100644 --- a/source/blender/draw/engines/eevee/shaders/ltc_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/ltc_lib.glsl @@ -1,150 +1,140 @@ -/* Mainly From https://eheitzresearch.wordpress.com/415-2/ */ +/** + * Adapted from : + * Real-Time Polygonal-Light Shading with Linearly Transformed Cosines. + * Eric Heitz, Jonathan Dupuy, Stephen Hill and David Neubelt. + * ACM Transactions on Graphics (Proceedings of ACM SIGGRAPH 2016) 35(4), 2016. + * Project page: https://eheitzresearch.wordpress.com/415-2/ + **/ #define USE_LTC #ifndef UTIL_TEX #define UTIL_TEX uniform sampler2DArray utilTex; +#define texelfetch_noise_tex(coord) texelFetch(utilTex, ivec3(ivec2(coord) % LUT_SIZE, 2.0), 0) #endif /* UTIL_TEX */ -/* from Real-Time Area Lighting: a Journey from Research to Production - * Stephen Hill and Eric Heitz */ -float edge_integral(vec3 p1, vec3 p2) +/* Diffuse *clipped* sphere integral. */ +float diffuse_sphere_integral_lut(float avg_dir_z, float form_factor) { -#if 0 - /* more accurate replacement of acos */ - float x = dot(p1, p2); - float y = abs(x); + vec2 uv = vec2(avg_dir_z * 0.5 + 0.5, form_factor); + uv = uv * (LUT_SIZE - 1.0) / LUT_SIZE + 0.5 / LUT_SIZE; - float a = 5.42031 + (3.12829 + 0.0902326 * y) * y; - float b = 3.45068 + (4.18814 + y) * y; - float theta_sintheta = a / b; - - if (x < 0.0) { - theta_sintheta = (M_PI / sqrt(1.0 - x * x)) - theta_sintheta; - } - vec3 u = cross(p1, p2); - return theta_sintheta * dot(u, N); -#endif - float cos_theta = dot(p1, p2); - cos_theta = clamp(cos_theta, -0.9999, 0.9999); + return texture(utilTex, vec3(uv, 1.0)).w; +} - float theta = acos(cos_theta); - vec3 u = normalize(cross(p1, p2)); - return theta * cross(p1, p2).z / sin(theta); +float diffuse_sphere_integral_cheap(float avg_dir_z, float form_factor) +{ + return max((form_factor * form_factor + avg_dir_z) / (form_factor + 1.0), 0.0); } -int clip_quad_to_horizon(inout vec3 L[5]) +/** + * An extended version of the implementation from + * "How to solve a cubic equation, revisited" + * http://momentsingraphics.de/?p=105 + **/ +vec3 solve_cubic(vec4 coefs) { - /* detect clipping config */ - int config = 0; - if (L[0].z > 0.0) config += 1; - if (L[1].z > 0.0) config += 2; - if (L[2].z > 0.0) config += 4; - if (L[3].z > 0.0) config += 8; + /* Normalize the polynomial */ + coefs.xyz /= coefs.w; + /* Divide middle coefficients by three */ + coefs.yz /= 3.0; - /* clip */ - int n = 0; + float A = coefs.w; + float B = coefs.z; + float C = coefs.y; + float D = coefs.x; - if (config == 0) - { - /* clip all */ - } - else if (config == 1) /* V1 clip V2 V3 V4 */ - { - n = 3; - L[1] = -L[1].z * L[0] + L[0].z * L[1]; - L[2] = -L[3].z * L[0] + L[0].z * L[3]; - } - else if (config == 2) /* V2 clip V1 V3 V4 */ - { - n = 3; - L[0] = -L[0].z * L[1] + L[1].z * L[0]; - L[2] = -L[2].z * L[1] + L[1].z * L[2]; - } - else if (config == 3) /* V1 V2 clip V3 V4 */ - { - n = 4; - L[2] = -L[2].z * L[1] + L[1].z * L[2]; - L[3] = -L[3].z * L[0] + L[0].z * L[3]; - } - else if (config == 4) /* V3 clip V1 V2 V4 */ - { - n = 3; - L[0] = -L[3].z * L[2] + L[2].z * L[3]; - L[1] = -L[1].z * L[2] + L[2].z * L[1]; - } - else if (config == 5) /* V1 V3 clip V2 V4) impossible */ - { - n = 0; - } - else if (config == 6) /* V2 V3 clip V1 V4 */ - { - n = 4; - L[0] = -L[0].z * L[1] + L[1].z * L[0]; - L[3] = -L[3].z * L[2] + L[2].z * L[3]; - } - else if (config == 7) /* V1 V2 V3 clip V4 */ - { - n = 5; - L[4] = -L[3].z * L[0] + L[0].z * L[3]; - L[3] = -L[3].z * L[2] + L[2].z * L[3]; - } - else if (config == 8) /* V4 clip V1 V2 V3 */ - { - n = 3; - L[0] = -L[0].z * L[3] + L[3].z * L[0]; - L[1] = -L[2].z * L[3] + L[3].z * L[2]; - L[2] = L[3]; - } - else if (config == 9) /* V1 V4 clip V2 V3 */ - { - n = 4; - L[1] = -L[1].z * L[0] + L[0].z * L[1]; - L[2] = -L[2].z * L[3] + L[3].z * L[2]; - } - else if (config == 10) /* V2 V4 clip V1 V3) impossible */ - { - n = 0; - } - else if (config == 11) /* V1 V2 V4 clip V3 */ - { - n = 5; - L[4] = L[3]; - L[3] = -L[2].z * L[3] + L[3].z * L[2]; - L[2] = -L[2].z * L[1] + L[1].z * L[2]; - } - else if (config == 12) /* V3 V4 clip V1 V2 */ + /* Compute the Hessian and the discriminant */ + vec3 delta = vec3( + -coefs.z*coefs.z + coefs.y, + -coefs.y*coefs.z + coefs.x, + dot(vec2(coefs.z, -coefs.y), coefs.xy) + ); + + /* Discriminant */ + float discr = dot(vec2(4.0 * delta.x, -delta.y), delta.zy); + + vec2 xlc, xsc; + + /* Algorithm A */ { - n = 4; - L[1] = -L[1].z * L[2] + L[2].z * L[1]; - L[0] = -L[0].z * L[3] + L[3].z * L[0]; + float A_a = 1.0; + float C_a = delta.x; + float D_a = -2.0 * B * delta.x + delta.y; + + /* Take the cubic root of a normalized complex number */ + float theta = atan(sqrt(discr), -D_a) / 3.0; + + float x_1a = 2.0 * sqrt(-C_a) * cos(theta); + float x_3a = 2.0 * sqrt(-C_a) * cos(theta + (2.0 / 3.0) * M_PI); + + float xl; + if ((x_1a + x_3a) > 2.0 * B) { + xl = x_1a; + } + else { + xl = x_3a; + } + + xlc = vec2(xl - B, A); } - else if (config == 13) /* V1 V3 V4 clip V2 */ + + /* Algorithm D */ { - n = 5; - L[4] = L[3]; - L[3] = L[2]; - L[2] = -L[1].z * L[2] + L[2].z * L[1]; - L[1] = -L[1].z * L[0] + L[0].z * L[1]; + float A_d = D; + float C_d = delta.z; + float D_d = -D * delta.y + 2.0 * C * delta.z; + + /* Take the cubic root of a normalized complex number */ + float theta = atan(D * sqrt(discr), -D_d) / 3.0; + + float x_1d = 2.0 * sqrt(-C_d) * cos(theta); + float x_3d = 2.0 * sqrt(-C_d) * cos(theta + (2.0 / 3.0) * M_PI); + + float xs; + if (x_1d + x_3d < 2.0 * C) + xs = x_1d; + else + xs = x_3d; + + xsc = vec2(-D, xs + C); } - else if (config == 14) /* V2 V3 V4 clip V1 */ - { - n = 5; - L[4] = -L[0].z * L[3] + L[3].z * L[0]; - L[0] = -L[0].z * L[1] + L[1].z * L[0]; + + float E = xlc.y * xsc.y; + float F = -xlc.x * xsc.y - xlc.y * xsc.x; + float G = xlc.x * xsc.x; + + vec2 xmc = vec2(C * F - B * G, -B * F + C * E); + + vec3 root = vec3(xsc.x / xsc.y, + xmc.x / xmc.y, + xlc.x / xlc.y); + + if (root.x < root.y && root.x < root.z) { + root.xyz = root.yxz; } - else if (config == 15) /* V1 V2 V3 V4 */ - { - n = 4; + else if (root.z < root.x && root.z < root.y) { + root.xyz = root.xzy; } - if (n == 3) - L[3] = L[0]; - if (n == 4) - L[4] = L[0]; + return root; +} + +/* from Real-Time Area Lighting: a Journey from Research to Production + * Stephen Hill and Eric Heitz */ +vec3 edge_integral_vec(vec3 v1, vec3 v2) +{ + float x = dot(v1, v2); + float y = abs(x); + + float a = 0.8543985 + (0.4965155 + 0.0145206 * y) * y; + float b = 3.4175940 + (4.1616724 + y) * y; + float v = a / b; - return n; + float theta_sintheta = (x > 0.0) ? v : 0.5 * inversesqrt(max(1.0 - x * x, 1e-7)) - v; + + return cross(v1, v2) * theta_sintheta; } mat3 ltc_matrix(vec4 lut) @@ -159,7 +149,7 @@ mat3 ltc_matrix(vec4 lut) return Minv; } -float ltc_evaluate(vec3 N, vec3 V, mat3 Minv, vec3 corners[4]) +void ltc_transform_quad(vec3 N, vec3 V, mat3 Minv, inout vec3 corners[4]) { /* Avoid dot(N, V) == 1 in ortho mode, leading T1 normalize to fail. */ V = normalize(V + 1e-8); @@ -172,42 +162,51 @@ float ltc_evaluate(vec3 N, vec3 V, mat3 Minv, vec3 corners[4]) /* rotate area light in (T1, T2, R) basis */ Minv = Minv * transpose(mat3(T1, T2, N)); - /* polygon (allocate 5 vertices for clipping) */ - vec3 L[5]; - L[0] = Minv * corners[0]; - L[1] = Minv * corners[1]; - L[2] = Minv * corners[2]; - L[3] = Minv * corners[3]; - - int n = clip_quad_to_horizon(L); - - if (n == 0) - return 0.0; - - /* project onto sphere */ - L[0] = normalize(L[0]); - L[1] = normalize(L[1]); - L[2] = normalize(L[2]); - L[3] = normalize(L[3]); - L[4] = normalize(L[4]); - - /* integrate */ - float sum = 0.0; - - sum += edge_integral(L[0], L[1]); - sum += edge_integral(L[1], L[2]); - sum += edge_integral(L[2], L[3]); - if (n >= 4) - sum += edge_integral(L[3], L[4]); - if (n == 5) - sum += edge_integral(L[4], L[0]); - - return abs(sum); + /* Apply LTC inverse matrix. */ + corners[0] = normalize(Minv * corners[0]); + corners[1] = normalize(Minv * corners[1]); + corners[2] = normalize(Minv * corners[2]); + corners[3] = normalize(Minv * corners[3]); } -/* Aproximate circle with an octogone */ -#define LTC_CIRCLE_RES 8 -float ltc_evaluate_circle(vec3 N, vec3 V, mat3 Minv, vec3 p[LTC_CIRCLE_RES]) +/* If corners have already pass through ltc_transform_quad(), then N **MUST** be vec3(0.0, 0.0, 1.0), + * corresponding to the Up axis of the shading basis. */ +float ltc_evaluate_quad(vec3 corners[4], vec3 N) +{ + /* Approximation using a sphere of the same solid angle than the quad. + * Finding the clipped sphere diffuse integral is easier than clipping the quad. */ + vec3 avg_dir; + avg_dir = edge_integral_vec(corners[0], corners[1]); + avg_dir += edge_integral_vec(corners[1], corners[2]); + avg_dir += edge_integral_vec(corners[2], corners[3]); + avg_dir += edge_integral_vec(corners[3], corners[0]); + + float form_factor = length(avg_dir); + float avg_dir_z = dot(N, avg_dir / form_factor); + +#if 1 /* use tabulated horizon-clipped sphere */ + return form_factor * diffuse_sphere_integral_lut(avg_dir_z, form_factor); +#else /* Less accurate version, a bit cheaper. */ + return form_factor * diffuse_sphere_integral_cheap(avg_dir_z, form_factor); +#endif +} + +/* If disk does not need to be transformed and is already front facing. */ +float ltc_evaluate_disk_simple(float disk_radius, float NL) +{ + float r_sqr = disk_radius * disk_radius; + float one_r_sqr = 1.0 + r_sqr; + float form_factor = r_sqr * inversesqrt(one_r_sqr * one_r_sqr); + +#if 1 /* use tabulated horizon-clipped sphere */ + return form_factor * diffuse_sphere_integral_lut(NL, form_factor); +#else /* Less accurate version, a bit cheaper. */ + return form_factor * diffuse_sphere_integral_cheap(NL, form_factor); +#endif +} + +/* disk_points are WS vectors from the shading point to the disk "bounding domain" */ +float ltc_evaluate_disk(vec3 N, vec3 V, mat3 Minv, vec3 disk_points[3]) { /* Avoid dot(N, V) == 1 in ortho mode, leading T1 normalize to fail. */ V = normalize(V + 1e-8); @@ -218,23 +217,106 @@ float ltc_evaluate_circle(vec3 N, vec3 V, mat3 Minv, vec3 p[LTC_CIRCLE_RES]) T2 = cross(N, T1); /* rotate area light in (T1, T2, R) basis */ - Minv = Minv * transpose(mat3(T1, T2, N)); + mat3 R = transpose(mat3(T1, T2, N)); - for (int i = 0; i < LTC_CIRCLE_RES; ++i) { - p[i] = Minv * p[i]; - /* clip to horizon */ - p[i].z = max(0.0, p[i].z); - /* project onto sphere */ - p[i] = normalize(p[i]); - } + /* Intermediate step: init ellipse. */ + vec3 L_[3]; + L_[0] = mul(R, disk_points[0]); + L_[1] = mul(R, disk_points[1]); + L_[2] = mul(R, disk_points[2]); + + vec3 C = 0.5 * (L_[0] + L_[2]); + vec3 V1 = 0.5 * (L_[1] - L_[2]); + vec3 V2 = 0.5 * (L_[1] - L_[0]); + + /* Transform ellipse by Minv. */ + C = Minv * C; + V1 = Minv * V1; + V2 = Minv * V2; + + /* Compute eigenvectors of new ellipse. */ - /* integrate */ - float sum = 0.0; - for (int i = 0; i < LTC_CIRCLE_RES - 1; ++i) { - sum += edge_integral(p[i], p[i + 1]); + float d11 = dot(V1, V1); + float d22 = dot(V2, V2); + float d12 = dot(V1, V2); + float a, b; /* Eigenvalues */ + const float threshold = 0.0007; /* Can be adjusted. Fix artifacts. */ + if (abs(d12) / sqrt(d11 * d22) > threshold) { + float tr = d11 + d22; + float det = -d12 * d12 + d11 * d22; + + /* use sqrt matrix to solve for eigenvalues */ + det = sqrt(det); + float u = 0.5 * sqrt(tr - 2.0 * det); + float v = 0.5 * sqrt(tr + 2.0 * det); + float e_max = (u + v); + float e_min = (u - v); + e_max *= e_max; + e_min *= e_min; + + vec3 V1_, V2_; + if (d11 > d22) { + V1_ = d12 * V1 + (e_max - d11) * V2; + V2_ = d12 * V1 + (e_min - d11) * V2; + } + else { + V1_ = d12 * V2 + (e_max - d22) * V1; + V2_ = d12 * V2 + (e_min - d22) * V1; + } + + a = 1.0 / e_max; + b = 1.0 / e_min; + V1 = normalize(V1_); + V2 = normalize(V2_); } - sum += edge_integral(p[LTC_CIRCLE_RES - 1], p[0]); + else { + a = 1.0 / d11; + b = 1.0 / d22; + V1 *= sqrt(a); + V2 *= sqrt(b); + } + + /* Now find front facing ellipse with same solid angle. */ - return max(0.0, sum); + vec3 V3 = normalize(cross(V1, V2)); + if (dot(C, V3) < 0.0) + V3 *= -1.0; + + float L = dot(V3, C); + float x0 = dot(V1, C) / L; + float y0 = dot(V2, C) / L; + + a *= L*L; + b *= L*L; + + float c0 = a * b; + float c1 = a * b * (1.0 + x0 * x0 + y0 * y0) - a - b; + float c2 = 1.0 - a * (1.0 + x0 * x0) - b * (1.0 + y0 * y0); + float c3 = 1.0; + + vec3 roots = solve_cubic(vec4(c0, c1, c2, c3)); + float e1 = roots.x; + float e2 = roots.y; + float e3 = roots.z; + + vec3 avg_dir = vec3(a * x0 / (a - e2), b * y0 / (b - e2), 1.0); + + mat3 rotate = mat3(V1, V2, V3); + + avg_dir = rotate * avg_dir; + avg_dir = normalize(avg_dir); + + /* L1, L2 are the extends of the front facing ellipse. */ + float L1 = sqrt(-e2/e3); + float L2 = sqrt(-e2/e1); + + /* Find the sphere and compute lighting. */ + float form_factor = max(0.0, L1 * L2 * inversesqrt((1.0 + L1 * L1) * (1.0 + L2 * L2))); + +#if 1 /* use tabulated horizon-clipped sphere */ + return form_factor * diffuse_sphere_integral_lut(avg_dir.z, form_factor); +#else /* Less accurate version, a bit cheaper. */ + return form_factor * diffuse_sphere_integral_cheap(avg_dir.z, form_factor); +#endif } diff --git a/source/blender/draw/engines/eevee/shaders/prepass_frag.glsl b/source/blender/draw/engines/eevee/shaders/prepass_frag.glsl index f921d56e3bc..1c0e65f0613 100644 --- a/source/blender/draw/engines/eevee/shaders/prepass_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/prepass_frag.glsl @@ -10,14 +10,15 @@ float hash3d(vec3 a) { return hash(vec2(hash(a.xy), a.z)); } -//uniform float hashScale; -float hashScale = 0.001; +uniform float hashAlphaOffset; float hashed_alpha_threshold(vec3 co) { + const float hash_scale = 1.0; /* Roughly in pixel */ + /* Find the discretized derivatives of our coordinates. */ float max_deriv = max(length(dFdx(co)), length(dFdy(co))); - float pix_scale = 1.0 / (hashScale * max_deriv); + float pix_scale = 1.0 / (hash_scale * max_deriv); /* Find two nearest log-discretized noise scales. */ float pix_scale_log = log2(pix_scale); @@ -53,7 +54,8 @@ float hashed_alpha_threshold(vec3 co) /* Avoids threshold == 0. */ threshold = clamp(threshold, 1.0e-6, 1.0); - return threshold; + /* Jitter the threshold for TAA accumulation. */ + return fract(threshold + hashAlphaOffset); } #endif diff --git a/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl b/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl index c593081ce91..cb75731b7da 100644 --- a/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl @@ -1,13 +1,5 @@ #define MAX_STEP 256 -uniform vec4 ssrParameters; - -#define ssrQuality ssrParameters.x -#define ssrThickness ssrParameters.y -#define ssrPixelSize ssrParameters.zw - -uniform float borderFadeFactor; - float sample_depth(vec2 uv, int index, float lod) { #ifdef PLANAR_PROBE_RAYTRACE @@ -233,7 +225,7 @@ vec3 raycast( float screen_border_mask(vec2 hit_co) { const float margin = 0.003; - float atten = borderFadeFactor + margin; /* Screen percentage */ + float atten = ssrBorderFac + margin; /* Screen percentage */ hit_co = smoothstep(margin, atten, hit_co) * (1 - smoothstep(1.0 - atten, 1.0 - margin, hit_co)); float screenfade = hit_co.x * hit_co.y; diff --git a/source/blender/draw/engines/eevee/shaders/ssr_lib.glsl b/source/blender/draw/engines/eevee/shaders/ssr_lib.glsl index 92287d2ecbc..6c7bfeb6b82 100644 --- a/source/blender/draw/engines/eevee/shaders/ssr_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/ssr_lib.glsl @@ -2,10 +2,9 @@ #define BTDF_BIAS 0.85 -vec4 screen_space_refraction(vec3 viewPosition, vec3 N, vec3 V, float ior, float roughnessSquared, vec3 rand, float ofs) +vec4 screen_space_refraction(vec3 viewPosition, vec3 N, vec3 V, float ior, float roughnessSquared, vec4 rand) { float a2 = max(5e-6, roughnessSquared * roughnessSquared); - float jitter = fract(rand.x + ofs); /* Importance sampling bias */ rand.x = mix(rand.x, 0.0, BTDF_BIAS); @@ -13,12 +12,12 @@ vec4 screen_space_refraction(vec3 viewPosition, vec3 N, vec3 V, float ior, float vec3 T, B; float NH; make_orthonormal_basis(N, T, B); - vec3 H = sample_ggx(rand, a2, N, T, B, NH); /* Microfacet normal */ + vec3 H = sample_ggx(rand.xzw, a2, N, T, B, NH); /* Microfacet normal */ float pdf = pdf_ggx_reflect(NH, a2); /* If ray is bad (i.e. going below the plane) regenerate. */ if (F_eta(ior, dot(H, V)) < 1.0) { - H = sample_ggx(rand * vec3(1.0, -1.0, -1.0), a2, N, T, B, NH); /* Microfacet normal */ + H = sample_ggx(rand.xzw * vec3(1.0, -1.0, -1.0), a2, N, T, B, NH); /* Microfacet normal */ pdf = pdf_ggx_reflect(NH, a2); } @@ -33,7 +32,7 @@ vec4 screen_space_refraction(vec3 viewPosition, vec3 N, vec3 V, float ior, float R = transform_direction(ViewMatrix, R); - vec3 hit_pos = raycast(-1, viewPosition, R * 1e16, ssrThickness, jitter, ssrQuality, roughnessSquared, false); + vec3 hit_pos = raycast(-1, viewPosition, R * 1e16, ssrThickness, rand.y, ssrQuality, roughnessSquared, false); if ((hit_pos.z > 0.0) && (F_eta(ior, dot(H, V)) < 1.0)) { hit_pos = get_view_space_from_depth(hit_pos.xy, hit_pos.z); diff --git a/source/blender/draw/engines/eevee/shaders/update_noise_frag.glsl b/source/blender/draw/engines/eevee/shaders/update_noise_frag.glsl new file mode 100644 index 00000000000..13ffe02eb0d --- /dev/null +++ b/source/blender/draw/engines/eevee/shaders/update_noise_frag.glsl @@ -0,0 +1,18 @@ + +uniform sampler2D blueNoise; +uniform vec3 offsets; + +out vec4 FragColor; + +#define M_2PI 6.28318530717958647692 + +void main(void) +{ + vec2 blue_noise = texelFetch(blueNoise, ivec2(gl_FragCoord.xy), 0).xy; + + float noise = fract(blue_noise.y + offsets.z); + FragColor.x = fract(blue_noise.x + offsets.x); + FragColor.y = fract(blue_noise.y + offsets.y); + FragColor.z = cos(noise * M_2PI); + FragColor.w = sin(noise * M_2PI); +} diff --git a/source/blender/draw/engines/eevee/shaders/volumetric_frag.glsl b/source/blender/draw/engines/eevee/shaders/volumetric_frag.glsl index 00e01e753f9..3a293647f84 100644 --- a/source/blender/draw/engines/eevee/shaders/volumetric_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/volumetric_frag.glsl @@ -4,9 +4,6 @@ #define NODETREE_EXEC -uniform ivec3 volumeTextureSize; -uniform vec3 volume_jitter; - #ifdef MESH_SHADER uniform mat4 volumeObjectMatrix; uniform vec3 volumeOrcoLoc; @@ -33,7 +30,7 @@ layout(location = 3) out vec4 volumePhase; void main() { ivec3 volume_cell = ivec3(gl_FragCoord.xy, slice); - vec3 ndc_cell = volume_to_ndc((vec3(volume_cell) + volume_jitter) / volumeTextureSize); + vec3 ndc_cell = volume_to_ndc((vec3(volume_cell) + volJitter.xyz) * volInvTexSize.xyz); viewPosition = get_view_space_from_depth(ndc_cell.xy, ndc_cell.z); worldPosition = transform_point(ViewMatrixInverse, viewPosition); diff --git a/source/blender/draw/engines/eevee/shaders/volumetric_lib.glsl b/source/blender/draw/engines/eevee/shaders/volumetric_lib.glsl index 1376c53d633..1a8167c2830 100644 --- a/source/blender/draw/engines/eevee/shaders/volumetric_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/volumetric_lib.glsl @@ -2,22 +2,16 @@ /* Based on Frosbite Unified Volumetric. * https://www.ea.com/frostbite/news/physically-based-unified-volumetric-rendering-in-frostbite */ -uniform float volume_light_clamp; - -uniform vec3 volume_param; /* Parameters to the volume Z equation */ - -uniform vec2 volume_uv_ratio; /* To convert volume uvs to screen uvs */ - /* Volume slice to view space depth. */ float volume_z_to_view_z(float z) { if (ProjectionMatrix[3][3] == 0.0) { /* Exponential distribution */ - return (exp2(z / volume_param.z) - volume_param.x) / volume_param.y; + return (exp2(z / volDepthParameters.z) - volDepthParameters.x) / volDepthParameters.y; } else { /* Linear distribution */ - return mix(volume_param.x, volume_param.y, z); + return mix(volDepthParameters.x, volDepthParameters.y, z); } } @@ -25,11 +19,11 @@ float view_z_to_volume_z(float depth) { if (ProjectionMatrix[3][3] == 0.0) { /* Exponential distribution */ - return volume_param.z * log2(depth * volume_param.y + volume_param.x); + return volDepthParameters.z * log2(depth * volDepthParameters.y + volDepthParameters.x); } else { /* Linear distribution */ - return (depth - volume_param.x) * volume_param.z; + return (depth - volDepthParameters.x) * volDepthParameters.z; } } @@ -38,7 +32,7 @@ vec3 volume_to_ndc(vec3 cos) { cos.z = volume_z_to_view_z(cos.z); cos.z = get_depth_from_view_z(cos.z); - cos.xy /= volume_uv_ratio; + cos.xy /= volCoordScale.xy; return cos; } @@ -46,7 +40,7 @@ vec3 ndc_to_volume(vec3 cos) { cos.z = get_view_z_from_depth(cos.z); cos.z = view_z_to_volume_z(cos.z); - cos.xy *= volume_uv_ratio; + cos.xy *= volCoordScale.xy; return cos; } @@ -71,14 +65,17 @@ vec3 light_volume(LightData ld, vec4 l_vector) /* TODO : Area lighting ? */ /* XXX : Removing Area Power. */ /* TODO : put this out of the shader. */ + /* See eevee_light_setup(). */ if (ld.l_type == AREA) { - power = 0.0962 * (ld.l_sizex * ld.l_sizey * 4.0 * M_PI); + power = (ld.l_sizex * ld.l_sizey * 4.0 * M_PI) * (1.0 / 80.0); + power *= 20.0 * max(0.0, dot(-ld.l_forward, l_vector.xyz / l_vector.w)); /* XXX ad hoc, empirical */ } else if (ld.l_type == SUN) { - power = 1.0; + power = (4.0f * ld.l_radius * ld.l_radius * M_2PI) * (1.0 / 12.5); /* Removing area light power*/ + power *= M_2PI * 0.78; /* Matching cycles with point light. */ } else { - power = 0.0248 * (4.0 * ld.l_radius * ld.l_radius * M_PI * M_PI); + power = (4.0 * ld.l_radius * ld.l_radius) * (1.0 /10.0); } /* OPTI: find a better way than calculating this on the fly */ @@ -87,15 +84,13 @@ vec3 light_volume(LightData ld, vec4 l_vector) power /= (l_vector.w * l_vector.w); - lum = min(lum * power, volume_light_clamp); + lum = min(lum * power, volLightClamp); return tint * lum; } #define VOLUMETRIC_SHADOW_MAX_STEP 32.0 -uniform float volume_shadows_steps; - vec3 participating_media_extinction(vec3 wpos, sampler3D volume_extinction) { /* Waiting for proper volume shadowmaps and out of frustum shadow map. */ @@ -110,11 +105,11 @@ vec3 light_volume_shadow(LightData ld, vec3 ray_wpos, vec4 l_vector, sampler3D v { #if defined(VOLUME_SHADOW) /* Heterogeneous volume shadows */ - float dd = l_vector.w / volume_shadows_steps; + float dd = l_vector.w / volShadowSteps; vec3 L = l_vector.xyz * l_vector.w; vec3 shadow = vec3(1.0); - for (float s = 0.5; s < VOLUMETRIC_SHADOW_MAX_STEP && s < (volume_shadows_steps - 0.1); s += 1.0) { - vec3 pos = ray_wpos + L * (s / volume_shadows_steps); + for (float s = 0.5; s < VOLUMETRIC_SHADOW_MAX_STEP && s < (volShadowSteps - 0.1); s += 1.0) { + vec3 pos = ray_wpos + L * (s / volShadowSteps); vec3 s_extinction = participating_media_extinction(pos, volume_extinction); shadow *= exp(-s_extinction * dd); } diff --git a/source/blender/draw/engines/eevee/shaders/volumetric_scatter_frag.glsl b/source/blender/draw/engines/eevee/shaders/volumetric_scatter_frag.glsl index ea402ff3d99..fcbb6661b14 100644 --- a/source/blender/draw/engines/eevee/shaders/volumetric_scatter_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/volumetric_scatter_frag.glsl @@ -13,28 +13,20 @@ uniform sampler3D volumePhase; uniform sampler3D historyScattering; uniform sampler3D historyTransmittance; -uniform vec3 volume_jitter; -uniform float volume_history_alpha; -uniform int light_count; -uniform mat4 PastViewProjectionMatrix; - flat in int slice; layout(location = 0) out vec4 outScattering; layout(location = 1) out vec4 outTransmittance; -#define VOLUME_LIGHTING - void main() { - vec3 volume_tex_size = vec3(textureSize(volumeScattering, 0)); ivec3 volume_cell = ivec3(gl_FragCoord.xy, slice); /* Emission */ outScattering = texelFetch(volumeEmission, volume_cell, 0); outTransmittance = texelFetch(volumeExtinction, volume_cell, 0); vec3 s_scattering = texelFetch(volumeScattering, volume_cell, 0).rgb; - vec3 volume_ndc = volume_to_ndc((vec3(volume_cell) + volume_jitter) / volume_tex_size); + vec3 volume_ndc = volume_to_ndc((vec3(volume_cell) + volJitter.xyz) * volInvTexSize.xyz); vec3 worldPosition = get_world_space_from_depth(volume_ndc.xy, volume_ndc.z); vec3 wdir = cameraVec; @@ -45,7 +37,7 @@ void main() outScattering.rgb += irradiance_volumetric(worldPosition) * s_scattering * phase_function_isotropic(); #ifdef VOLUME_LIGHTING /* Lights */ - for (int i = 0; i < MAX_LIGHT && i < light_count; ++i) { + for (int i = 0; i < MAX_LIGHT && i < laNumLight; ++i) { LightData ld = lights_data[i]; @@ -63,16 +55,16 @@ void main() /* Temporal supersampling */ /* Note : this uses the cell non-jittered position (texel center). */ - vec3 curr_ndc = volume_to_ndc(vec3(gl_FragCoord.xy, float(slice) + 0.5) / volume_tex_size); + vec3 curr_ndc = volume_to_ndc(vec3(gl_FragCoord.xy, float(slice) + 0.5) * volInvTexSize.xyz); vec3 wpos = get_world_space_from_depth(curr_ndc.xy, curr_ndc.z); - vec3 prev_ndc = project_point(PastViewProjectionMatrix, wpos); + vec3 prev_ndc = project_point(pastViewProjectionMatrix, wpos); vec3 prev_volume = ndc_to_volume(prev_ndc * 0.5 + 0.5); - if ((volume_history_alpha > 0.0) && all(greaterThan(prev_volume, vec3(0.0))) && all(lessThan(prev_volume, vec3(1.0)))) { + if ((volHistoryAlpha > 0.0) && all(greaterThan(prev_volume, vec3(0.0))) && all(lessThan(prev_volume, vec3(1.0)))) { vec4 h_Scattering = texture(historyScattering, prev_volume); vec4 h_Transmittance = texture(historyTransmittance, prev_volume); - outScattering = mix(outScattering, h_Scattering, volume_history_alpha); - outTransmittance = mix(outTransmittance, h_Transmittance, volume_history_alpha); + outScattering = mix(outScattering, h_Scattering, volHistoryAlpha); + outTransmittance = mix(outTransmittance, h_Transmittance, volHistoryAlpha); } /* Catch NaNs */ diff --git a/source/blender/draw/engines/external/external_engine.c b/source/blender/draw/engines/external/external_engine.c index 851d0ef9eb7..ec0141953fe 100644 --- a/source/blender/draw/engines/external/external_engine.c +++ b/source/blender/draw/engines/external/external_engine.c @@ -218,6 +218,7 @@ DrawEngineType draw_engine_external_type = { &external_draw_scene, NULL, NULL, + NULL, }; /* Note: currently unused, we should not register unless we want to see this when debugging the view. */ diff --git a/source/blender/draw/intern/DRW_render.h b/source/blender/draw/intern/DRW_render.h index 0753dbc7a1a..528495b8710 100644 --- a/source/blender/draw/intern/DRW_render.h +++ b/source/blender/draw/intern/DRW_render.h @@ -139,6 +139,8 @@ typedef struct DrawEngineType { void (*view_update)(void *vedata); void (*id_update)(void *vedata, struct ID *id); + + void (*render_to_image)(void *vedata, struct RenderEngine *engine, struct Depsgraph *graph); } DrawEngineType; #ifndef __DRW_ENGINE_H__ @@ -157,7 +159,9 @@ typedef struct DefaultTextureList { #endif /* Textures */ - +/* NOTE naming in this struct is broken. + * There should either be suffixes for Normalized int formats or float formats. + * Right now every 8bit texture is Normalized int and others are Floating point. */ typedef enum { DRW_TEX_RGBA_8, DRW_TEX_RGBA_16, @@ -168,6 +172,7 @@ typedef enum { DRW_TEX_RGB_32, DRW_TEX_RG_8, DRW_TEX_RG_16, + DRW_TEX_RG_16I, DRW_TEX_RG_32, DRW_TEX_R_8, DRW_TEX_R_16, @@ -226,12 +231,14 @@ typedef struct DRWFboTexture { DRWTextureFlag flag; } DRWFboTexture; +struct GPUFrameBuffer *DRW_framebuffer_create(void); void DRW_framebuffer_init( struct GPUFrameBuffer **fb, void *engine_type, int width, int height, DRWFboTexture textures[MAX_FBO_TEX], int textures_len); void DRW_framebuffer_bind(struct GPUFrameBuffer *fb); void DRW_framebuffer_clear(bool color, bool depth, bool stencil, float clear_col[4], float clear_depth); void DRW_framebuffer_read_data(int x, int y, int w, int h, int channels, int slot, float *data); +void DRW_framebuffer_read_depth(int x, int y, int w, int h, float *data); void DRW_framebuffer_texture_attach(struct GPUFrameBuffer *fb, struct GPUTexture *tex, int slot, int mip); void DRW_framebuffer_texture_layer_attach(struct GPUFrameBuffer *fb, struct GPUTexture *tex, int slot, int layer, int mip); void DRW_framebuffer_cubeface_attach(struct GPUFrameBuffer *fb, struct GPUTexture *tex, int slot, int face, int mip); @@ -290,6 +297,7 @@ typedef enum { DRW_STATE_MULTIPLY = (1 << 16), DRW_STATE_TRANSMISSION = (1 << 17), DRW_STATE_CLIP_PLANES = (1 << 18), + DRW_STATE_ADDITIVE_FULL = (1 << 19), /* Same as DRW_STATE_ADDITIVE but let alpha accumulate without premult. */ DRW_STATE_WRITE_STENCIL = (1 << 27), DRW_STATE_STENCIL_EQUAL = (1 << 28), @@ -326,10 +334,6 @@ void DRW_shgroup_call_dynamic_add_array(DRWShadingGroup *shgroup, const void *at const void *array[] = {__VA_ARGS__}; \ DRW_shgroup_call_dynamic_add_array(shgroup, array, (sizeof(array) / sizeof(*array))); \ } while (0) -/* Use this only to make your instances selectable. */ -#define DRW_shgroup_call_dynamic_add_empty(shgroup) do { \ - DRW_shgroup_call_dynamic_add_array(shgroup, NULL, 0); \ -} while (0) /* Use this to set a high number of instances. */ void DRW_shgroup_set_instance_count(DRWShadingGroup *shgroup, int count); @@ -341,13 +345,14 @@ void DRW_shgroup_attrib_float(DRWShadingGroup *shgroup, const char *name, int si void DRW_shgroup_uniform_texture(DRWShadingGroup *shgroup, const char *name, const struct GPUTexture *tex); void DRW_shgroup_uniform_block(DRWShadingGroup *shgroup, const char *name, const struct GPUUniformBuffer *ubo); void DRW_shgroup_uniform_buffer(DRWShadingGroup *shgroup, const char *name, struct GPUTexture **tex); -void DRW_shgroup_uniform_bool(DRWShadingGroup *shgroup, const char *name, const bool *value, int arraysize); void DRW_shgroup_uniform_float(DRWShadingGroup *shgroup, const char *name, const float *value, int arraysize); void DRW_shgroup_uniform_vec2(DRWShadingGroup *shgroup, const char *name, const float *value, int arraysize); void DRW_shgroup_uniform_vec3(DRWShadingGroup *shgroup, const char *name, const float *value, int arraysize); void DRW_shgroup_uniform_vec4(DRWShadingGroup *shgroup, const char *name, const float *value, int arraysize); void DRW_shgroup_uniform_short_to_int(DRWShadingGroup *shgroup, const char *name, const short *value, int arraysize); void DRW_shgroup_uniform_short_to_float(DRWShadingGroup *shgroup, const char *name, const short *value, int arraysize); +/* Boolean are expected to be 4bytes longs for opengl! */ +void DRW_shgroup_uniform_bool(DRWShadingGroup *shgroup, const char *name, const int *value, int arraysize); void DRW_shgroup_uniform_int(DRWShadingGroup *shgroup, const char *name, const int *value, int arraysize); void DRW_shgroup_uniform_ivec2(DRWShadingGroup *shgroup, const char *name, const int *value, int arraysize); void DRW_shgroup_uniform_ivec3(DRWShadingGroup *shgroup, const char *name, const int *value, int arraysize); @@ -356,6 +361,7 @@ void DRW_shgroup_uniform_mat4(DRWShadingGroup *shgroup, const char *name, const /* Passes */ DRWPass *DRW_pass_create(const char *name, DRWState state); +void DRW_pass_state_set(DRWPass *pass, DRWState state); void DRW_pass_foreach_shgroup(DRWPass *pass, void (*callback)(void *userData, DRWShadingGroup *shgrp), void *userData); void DRW_pass_sort_shgroup_z(DRWPass *pass); @@ -383,19 +389,29 @@ struct DefaultTextureList *DRW_viewport_texture_list_get(void); void DRW_viewport_request_redraw(void); +void DRW_render_to_image(struct RenderEngine *re, struct Depsgraph *depsgraph); +void DRW_render_object_iter( + void *vedata, struct RenderEngine *engine, struct Depsgraph *graph, + void (*callback)(void *vedata, struct Object *ob, struct RenderEngine *engine, struct Depsgraph *graph)); + /* ViewLayers */ void *DRW_view_layer_engine_data_get(DrawEngineType *engine_type); void **DRW_view_layer_engine_data_ensure(DrawEngineType *engine_type, void (*callback)(void *storage)); /* Objects */ -void *DRW_object_engine_data_get(Object *ob, DrawEngineType *engine_type); -void **DRW_object_engine_data_ensure( - Object *ob, DrawEngineType *engine_type, void (*callback)(void *storage)); +ObjectEngineData *DRW_object_engine_data_get(Object *ob, DrawEngineType *engine_type); +ObjectEngineData *DRW_object_engine_data_ensure( + Object *ob, + DrawEngineType *engine_type, + size_t size, + ObjectEngineDataInitCb init_cb, + ObjectEngineDataFreeCb free_cb); struct LampEngineData *DRW_lamp_engine_data_ensure(Object *ob, struct RenderEngineType *engine_type); void DRW_lamp_engine_data_free(struct LampEngineData *led); /* Settings */ bool DRW_object_is_renderable(struct Object *ob); +bool DRW_check_object_visible_within_active_context(struct Object *ob); bool DRW_object_is_flat_normal(const struct Object *ob); int DRW_object_is_mode_shade(const struct Object *ob); @@ -431,6 +447,9 @@ bool DRW_state_is_image_render(void); bool DRW_state_is_scene_render(void); bool DRW_state_show_text(void); bool DRW_state_draw_support(void); +bool DRW_state_draw_background(void); + +enum eDepsObjectIteratorMode DRW_iterator_mode_get(void); struct DRWTextStore *DRW_state_text_cache_get(void); @@ -448,6 +467,8 @@ typedef struct DRWContextState { struct RenderEngineType *engine_type; + struct Depsgraph *depsgraph; + /* Last resort (some functions take this as an arg so we can't easily avoid). * May be NULL when used for selection or depth buffer. */ const struct bContext *evil_C; diff --git a/source/blender/draw/intern/draw_armature.c b/source/blender/draw/intern/draw_armature.c index c7a88f7689e..09fe3d68651 100644 --- a/source/blender/draw/intern/draw_armature.c +++ b/source/blender/draw/intern/draw_armature.c @@ -102,20 +102,22 @@ static void drw_shgroup_bone_octahedral_solid(const float (*bone_mat)[4], const { if (g_data.bone_octahedral_solid == NULL) { struct Gwn_Batch *geom = DRW_cache_bone_octahedral_get(); - g_data.bone_octahedral_solid = shgroup_instance_objspace_solid(g_data.pass_bone_solid, geom, g_data.ob->obmat); + g_data.bone_octahedral_solid = shgroup_instance_solid(g_data.pass_bone_solid, geom); } - - DRW_shgroup_call_dynamic_add(g_data.bone_octahedral_solid, bone_mat, color); + float final_bonemat[4][4]; + mul_m4_m4m4(final_bonemat, g_data.ob->obmat, bone_mat); + DRW_shgroup_call_dynamic_add(g_data.bone_octahedral_solid, final_bonemat, color); } static void drw_shgroup_bone_octahedral_wire(const float (*bone_mat)[4], const float color[4]) { if (g_data.bone_octahedral_wire == NULL) { struct Gwn_Batch *geom = DRW_cache_bone_octahedral_wire_outline_get(); - g_data.bone_octahedral_wire = shgroup_instance_objspace_wire(g_data.pass_bone_wire, geom, g_data.ob->obmat); + g_data.bone_octahedral_wire = shgroup_instance_wire(g_data.pass_bone_wire, geom); } - - DRW_shgroup_call_dynamic_add(g_data.bone_octahedral_wire, bone_mat, color); + float final_bonemat[4][4]; + mul_m4_m4m4(final_bonemat, g_data.ob->obmat, bone_mat); + DRW_shgroup_call_dynamic_add(g_data.bone_octahedral_wire, final_bonemat, color); } /* Box / B-Bone */ @@ -123,20 +125,22 @@ static void drw_shgroup_bone_box_solid(const float (*bone_mat)[4], const float c { if (g_data.bone_box_solid == NULL) { struct Gwn_Batch *geom = DRW_cache_bone_box_get(); - g_data.bone_box_solid = shgroup_instance_objspace_solid(g_data.pass_bone_solid, geom, g_data.ob->obmat); + g_data.bone_box_solid = shgroup_instance_solid(g_data.pass_bone_solid, geom); } - - DRW_shgroup_call_dynamic_add(g_data.bone_box_solid, bone_mat, color); + float final_bonemat[4][4]; + mul_m4_m4m4(final_bonemat, g_data.ob->obmat, bone_mat); + DRW_shgroup_call_dynamic_add(g_data.bone_box_solid, final_bonemat, color); } static void drw_shgroup_bone_box_wire(const float (*bone_mat)[4], const float color[4]) { if (g_data.bone_box_wire == NULL) { struct Gwn_Batch *geom = DRW_cache_bone_box_wire_outline_get(); - g_data.bone_box_wire = shgroup_instance_objspace_wire(g_data.pass_bone_wire, geom, g_data.ob->obmat); + g_data.bone_box_wire = shgroup_instance_wire(g_data.pass_bone_wire, geom); } - - DRW_shgroup_call_dynamic_add(g_data.bone_box_wire, bone_mat, color); + float final_bonemat[4][4]; + mul_m4_m4m4(final_bonemat, g_data.ob->obmat, bone_mat); + DRW_shgroup_call_dynamic_add(g_data.bone_box_wire, final_bonemat, color); } /* Wire */ @@ -144,10 +148,11 @@ static void drw_shgroup_bone_wire_wire(const float (*bone_mat)[4], const float c { if (g_data.bone_wire_wire == NULL) { struct Gwn_Batch *geom = DRW_cache_bone_wire_wire_outline_get(); - g_data.bone_wire_wire = shgroup_instance_objspace_wire(g_data.pass_bone_wire, geom, g_data.ob->obmat); + g_data.bone_wire_wire = shgroup_instance_wire(g_data.pass_bone_wire, geom); } - - DRW_shgroup_call_dynamic_add(g_data.bone_wire_wire, bone_mat, color); + float final_bonemat[4][4]; + mul_m4_m4m4(final_bonemat, g_data.ob->obmat, bone_mat); + DRW_shgroup_call_dynamic_add(g_data.bone_wire_wire, final_bonemat, color); } /* Envelope */ @@ -159,10 +164,11 @@ static void drw_shgroup_bone_envelope_distance( if (g_data.bone_envelope_distance == NULL) { struct Gwn_Batch *geom = DRW_cache_bone_envelope_distance_outline_get(); /* Note: bone_wire draw pass is not really working, think we need another one here? */ - g_data.bone_envelope_distance = shgroup_instance_bone_envelope_wire(g_data.pass_bone_envelope, geom, g_data.ob->obmat); + g_data.bone_envelope_distance = shgroup_instance_bone_envelope_wire(g_data.pass_bone_envelope, geom); } - - DRW_shgroup_call_dynamic_add(g_data.bone_envelope_distance, bone_mat, color, radius_head, radius_tail, distance); + float final_bonemat[4][4]; + mul_m4_m4m4(final_bonemat, g_data.ob->obmat, bone_mat); + DRW_shgroup_call_dynamic_add(g_data.bone_envelope_distance, final_bonemat, color, radius_head, radius_tail, distance); } } @@ -172,10 +178,11 @@ static void drw_shgroup_bone_envelope_solid( { if (g_data.bone_envelope_solid == NULL) { struct Gwn_Batch *geom = DRW_cache_bone_envelope_solid_get(); - g_data.bone_envelope_solid = shgroup_instance_bone_envelope_solid(g_data.pass_bone_solid, geom, g_data.ob->obmat); + g_data.bone_envelope_solid = shgroup_instance_bone_envelope_solid(g_data.pass_bone_solid, geom); } - - DRW_shgroup_call_dynamic_add(g_data.bone_envelope_solid, bone_mat, color, radius_head, radius_tail); + float final_bonemat[4][4]; + mul_m4_m4m4(final_bonemat, g_data.ob->obmat, bone_mat); + DRW_shgroup_call_dynamic_add(g_data.bone_envelope_solid, final_bonemat, color, radius_head, radius_tail); } static void drw_shgroup_bone_envelope_wire( @@ -184,10 +191,11 @@ static void drw_shgroup_bone_envelope_wire( { if (g_data.bone_envelope_wire == NULL) { struct Gwn_Batch *geom = DRW_cache_bone_envelope_wire_outline_get(); - g_data.bone_envelope_wire = shgroup_instance_bone_envelope_wire(g_data.pass_bone_wire, geom, g_data.ob->obmat); + g_data.bone_envelope_wire = shgroup_instance_bone_envelope_wire(g_data.pass_bone_wire, geom); } - - DRW_shgroup_call_dynamic_add(g_data.bone_envelope_wire, bone_mat, color, radius_head, radius_tail, distance); + float final_bonemat[4][4]; + mul_m4_m4m4(final_bonemat, g_data.ob->obmat, bone_mat); + DRW_shgroup_call_dynamic_add(g_data.bone_envelope_wire, final_bonemat, color, radius_head, radius_tail, distance); } static void drw_shgroup_bone_envelope_head_wire( @@ -196,10 +204,11 @@ static void drw_shgroup_bone_envelope_head_wire( { if (g_data.bone_envelope_head_wire == NULL) { struct Gwn_Batch *geom = DRW_cache_bone_envelope_head_wire_outline_get(); - g_data.bone_envelope_head_wire = shgroup_instance_bone_envelope_wire(g_data.pass_bone_wire, geom, g_data.ob->obmat); + g_data.bone_envelope_head_wire = shgroup_instance_bone_envelope_wire(g_data.pass_bone_wire, geom); } - - DRW_shgroup_call_dynamic_add(g_data.bone_envelope_head_wire, bone_mat, color, radius_head, radius_tail, distance); + float final_bonemat[4][4]; + mul_m4_m4m4(final_bonemat, g_data.ob->obmat, bone_mat); + DRW_shgroup_call_dynamic_add(g_data.bone_envelope_head_wire, final_bonemat, color, radius_head, radius_tail, distance); } /* Custom (geometry) */ @@ -209,8 +218,10 @@ static void drw_shgroup_bone_custom_solid(const float (*bone_mat)[4], const floa /* grr, not re-using instances! */ struct Gwn_Batch *geom = DRW_cache_object_surface_get(custom); if (geom) { - DRWShadingGroup *shgrp_geom_solid = shgroup_instance_objspace_solid(g_data.pass_bone_solid, geom, g_data.ob->obmat); - DRW_shgroup_call_dynamic_add(shgrp_geom_solid, bone_mat, color); + DRWShadingGroup *shgrp_geom_solid = shgroup_instance_solid(g_data.pass_bone_solid, geom); + float final_bonemat[4][4]; + mul_m4_m4m4(final_bonemat, g_data.ob->obmat, bone_mat); + DRW_shgroup_call_dynamic_add(shgrp_geom_solid, final_bonemat, color); } } @@ -219,8 +230,10 @@ static void drw_shgroup_bone_custom_wire(const float (*bone_mat)[4], const float /* grr, not re-using instances! */ struct Gwn_Batch *geom = DRW_cache_object_wire_outline_get(custom); if (geom) { - DRWShadingGroup *shgrp_geom_wire = shgroup_instance_objspace_wire(g_data.pass_bone_wire, geom, g_data.ob->obmat); - DRW_shgroup_call_dynamic_add(shgrp_geom_wire, bone_mat, color); + DRWShadingGroup *shgrp_geom_wire = shgroup_instance_wire(g_data.pass_bone_wire, geom); + float final_bonemat[4][4]; + mul_m4_m4m4(final_bonemat, g_data.ob->obmat, bone_mat); + DRW_shgroup_call_dynamic_add(shgrp_geom_wire, final_bonemat, color); } } @@ -229,20 +242,22 @@ static void drw_shgroup_bone_point_solid(const float (*bone_mat)[4], const float { if (g_data.bone_point_solid == NULL) { struct Gwn_Batch *geom = DRW_cache_bone_point_get(); - g_data.bone_point_solid = shgroup_instance_objspace_solid(g_data.pass_bone_solid, geom, g_data.ob->obmat); + g_data.bone_point_solid = shgroup_instance_solid(g_data.pass_bone_solid, geom); } - - DRW_shgroup_call_dynamic_add(g_data.bone_point_solid, bone_mat, color); + float final_bonemat[4][4]; + mul_m4_m4m4(final_bonemat, g_data.ob->obmat, bone_mat); + DRW_shgroup_call_dynamic_add(g_data.bone_point_solid, final_bonemat, color); } static void drw_shgroup_bone_point_wire(const float (*bone_mat)[4], const float color[4]) { if (g_data.bone_point_wire == NULL) { struct Gwn_Batch *geom = DRW_cache_bone_point_wire_outline_get(); - g_data.bone_point_wire = shgroup_instance_objspace_wire(g_data.pass_bone_wire, geom, g_data.ob->obmat); + g_data.bone_point_wire = shgroup_instance_wire(g_data.pass_bone_wire, geom); } - - DRW_shgroup_call_dynamic_add(g_data.bone_point_wire, bone_mat, color); + float final_bonemat[4][4]; + mul_m4_m4m4(final_bonemat, g_data.ob->obmat, bone_mat); + DRW_shgroup_call_dynamic_add(g_data.bone_point_wire, final_bonemat, color); } /* Axes */ @@ -250,10 +265,11 @@ static void drw_shgroup_bone_axes(const float (*bone_mat)[4], const float color[ { if (g_data.bone_axes == NULL) { struct Gwn_Batch *geom = DRW_cache_bone_arrows_get(); - g_data.bone_axes = shgroup_instance_objspace_wire(g_data.pass_bone_wire, geom, g_data.ob->obmat); + g_data.bone_axes = shgroup_instance_wire(g_data.pass_bone_wire, geom); } - - DRW_shgroup_call_dynamic_add(g_data.bone_axes, bone_mat, color); + float final_bonemat[4][4]; + mul_m4_m4m4(final_bonemat, g_data.ob->obmat, bone_mat); + DRW_shgroup_call_dynamic_add(g_data.bone_axes, final_bonemat, color); } /* Relationship lines */ diff --git a/source/blender/draw/intern/draw_cache.c b/source/blender/draw/intern/draw_cache.c index 8010a232f89..3b4180c0375 100644 --- a/source/blender/draw/intern/draw_cache.c +++ b/source/blender/draw/intern/draw_cache.c @@ -65,6 +65,7 @@ static struct DRWShapeCache { Gwn_Batch *drw_field_tube_limit; Gwn_Batch *drw_field_cone_limit; Gwn_Batch *drw_lamp; + Gwn_Batch *drw_lamp_shadows; Gwn_Batch *drw_lamp_sunrays; Gwn_Batch *drw_lamp_area; Gwn_Batch *drw_lamp_hemi; @@ -87,6 +88,7 @@ static struct DRWShapeCache { Gwn_Batch *drw_bone_point_wire; Gwn_Batch *drw_bone_arrows; Gwn_Batch *drw_camera; + Gwn_Batch *drw_camera_frame; Gwn_Batch *drw_camera_tria; Gwn_Batch *drw_camera_focus; Gwn_Batch *drw_particle_cross; @@ -520,6 +522,12 @@ Gwn_Batch **DRW_cache_object_surface_material_get( switch (ob->type) { case OB_MESH: return DRW_cache_mesh_surface_shaded_get(ob, gpumat_array, gpumat_array_len); + case OB_CURVE: + return DRW_cache_curve_surface_shaded_get(ob, gpumat_array, gpumat_array_len); + case OB_SURF: + return DRW_cache_surf_surface_shaded_get(ob, gpumat_array, gpumat_array_len); + case OB_FONT: + return DRW_cache_text_surface_shaded_get(ob, gpumat_array, gpumat_array_len); default: return NULL; } @@ -1007,14 +1015,14 @@ Gwn_Batch *DRW_cache_lamp_get(void) Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format); GWN_vertbuf_data_alloc(vbo, NSEGMENTS * 2); - for (int a = 0; a < NSEGMENTS; a++) { - v[0] = sinf((2.0f * M_PI * a) / ((float)NSEGMENTS)); - v[1] = cosf((2.0f * M_PI * a) / ((float)NSEGMENTS)); - GWN_vertbuf_attr_set(vbo, attr_id.pos, a * 2, v); + for (int a = 0; a < NSEGMENTS * 2; a += 2) { + v[0] = sinf((2.0f * M_PI * a) / ((float)NSEGMENTS * 2)); + v[1] = cosf((2.0f * M_PI * a) / ((float)NSEGMENTS * 2)); + GWN_vertbuf_attr_set(vbo, attr_id.pos, a, v); - v[0] = sinf((2.0f * M_PI * (a + 1)) / ((float)NSEGMENTS)); - v[1] = cosf((2.0f * M_PI * (a + 1)) / ((float)NSEGMENTS)); - GWN_vertbuf_attr_set(vbo, attr_id.pos, a * 2 + 1, v); + v[0] = sinf((2.0f * M_PI * (a + 1)) / ((float)NSEGMENTS * 2)); + v[1] = cosf((2.0f * M_PI * (a + 1)) / ((float)NSEGMENTS * 2)); + GWN_vertbuf_attr_set(vbo, attr_id.pos, a + 1, v); } SHC.drw_lamp = GWN_batch_create_ex(GWN_PRIM_LINES, vbo, NULL, GWN_BATCH_OWNS_VBO); @@ -1023,12 +1031,44 @@ Gwn_Batch *DRW_cache_lamp_get(void) #undef NSEGMENTS } +Gwn_Batch *DRW_cache_lamp_shadows_get(void) +{ +#define NSEGMENTS 10 + if (!SHC.drw_lamp_shadows) { + float v[2]; + + /* Position Only 3D format */ + static Gwn_VertFormat format = { 0 }; + static struct { uint pos; } attr_id; + if (format.attrib_ct == 0) { + attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); + } + + Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format); + GWN_vertbuf_data_alloc(vbo, NSEGMENTS * 2); + + for (int a = 0; a < NSEGMENTS * 2; a += 2) { + v[0] = sinf((2.0f * M_PI * a) / ((float)NSEGMENTS * 2)); + v[1] = cosf((2.0f * M_PI * a) / ((float)NSEGMENTS * 2)); + GWN_vertbuf_attr_set(vbo, attr_id.pos, a, v); + + v[0] = sinf((2.0f * M_PI * (a + 1)) / ((float)NSEGMENTS * 2)); + v[1] = cosf((2.0f * M_PI * (a + 1)) / ((float)NSEGMENTS * 2)); + GWN_vertbuf_attr_set(vbo, attr_id.pos, a + 1, v); + } + + SHC.drw_lamp_shadows = GWN_batch_create_ex(GWN_PRIM_LINES, vbo, NULL, GWN_BATCH_OWNS_VBO); + } + return SHC.drw_lamp_shadows; +#undef NSEGMENTS +} + Gwn_Batch *DRW_cache_lamp_sunrays_get(void) { if (!SHC.drw_lamp_sunrays) { float v[2], v1[2], v2[2]; - /* Position Only 3D format */ + /* Position Only 2D format */ static Gwn_VertFormat format = { 0 }; static struct { uint pos; } attr_id; if (format.attrib_ct == 0) { @@ -1036,17 +1076,21 @@ Gwn_Batch *DRW_cache_lamp_sunrays_get(void) } Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format); - GWN_vertbuf_data_alloc(vbo, 16); + GWN_vertbuf_data_alloc(vbo, 32); for (int a = 0; a < 8; a++) { v[0] = sinf((2.0f * M_PI * a) / 8.0f); v[1] = cosf((2.0f * M_PI * a) / 8.0f); - mul_v2_v2fl(v1, v, 1.2f); - mul_v2_v2fl(v2, v, 2.5f); + mul_v2_v2fl(v1, v, 1.6f); + mul_v2_v2fl(v2, v, 1.9f); + GWN_vertbuf_attr_set(vbo, attr_id.pos, a * 4, v1); + GWN_vertbuf_attr_set(vbo, attr_id.pos, a * 4 + 1, v2); - GWN_vertbuf_attr_set(vbo, attr_id.pos, a * 2, v1); - GWN_vertbuf_attr_set(vbo, attr_id.pos, a * 2 + 1, v2); + mul_v2_v2fl(v1, v, 2.2f); + mul_v2_v2fl(v2, v, 2.5f); + GWN_vertbuf_attr_set(vbo, attr_id.pos, a * 4 + 2, v1); + GWN_vertbuf_attr_set(vbo, attr_id.pos, a * 4 + 3, v2); } SHC.drw_lamp_sunrays = GWN_batch_create_ex(GWN_PRIM_LINES, vbo, NULL, GWN_BATCH_OWNS_VBO); @@ -1846,7 +1890,7 @@ Gwn_Batch *DRW_cache_bone_envelope_distance_outline_get(void) const float x = cosf(alpha); const float y = -sinf(alpha); - /* { X, Y, head/tail, inner/outer border } */ + /* { X, Y, head/tail, inner/outer border } */ GWN_vertbuf_attr_set(vbo, pos_id, v_idx++, (const float[4]){x, y, head_tail, 0.0f}); GWN_vertbuf_attr_set(vbo, pos_id, v_idx++, (const float[4]){x, y, head_tail, 1.0f}); if (is_headtail_transition) { @@ -1880,7 +1924,7 @@ Gwn_Batch *DRW_cache_bone_envelope_wire_outline_get(void) /* Two lines between head and tail circles. */ /* Encoded lines, vertex shader gives them final correct value. */ - /* { X, Y, head/tail, inner/outer border } */ + /* { X, Y, head/tail, inner/outer border } */ GWN_vertbuf_attr_set(vbo, pos_id, v_idx++, (const float[4]){ 1.0f, 0.0f, 0.0f, 0.0f}); GWN_vertbuf_attr_set(vbo, pos_id, v_idx++, (const float[4]){ 1.0f, 0.0f, 1.0f, 0.0f}); GWN_vertbuf_attr_set(vbo, pos_id, v_idx++, (const float[4]){-1.0f, 0.0f, 0.0f, 0.0f}); @@ -1916,7 +1960,7 @@ Gwn_Batch *DRW_cache_bone_envelope_head_wire_outline_get(void) const float x = cosf(alpha); const float y = -sinf(alpha); - /* { X, Y, head/tail, inner/outer border } */ + /* { X, Y, head/tail, inner/outer border } */ GWN_vertbuf_attr_set(vbo, pos_id, v_idx++, (const float[4]){ x, y, 0.0f, 0.0f}); } @@ -1996,97 +2040,139 @@ Gwn_Batch *DRW_cache_bone_arrows_get(void) /** \name Camera * \{ */ +/** + * We could make these more generic functions. + * although filling 1d lines is not common. + * + * \note Use x coordinate to identify the vertex the vertex shader take care to place it appropriately. + */ + +static const float camera_coords_frame_bounds[5] = { + 0.0f, /* center point */ + 1.0f, /* + X + Y */ + 2.0f, /* + X - Y */ + 3.0f, /* - X - Y */ + 4.0f, /* - X + Y */ +}; + +static const float camera_coords_frame_tri[3] = { + 5.0f, /* tria + X */ + 6.0f, /* tria - X */ + 7.0f, /* tria + Y */ +}; + +/** Draw a loop of lines. */ +static void camera_fill_lines_loop_fl_v1( + Gwn_VertBufRaw *pos_step, + const float *coords, const uint coords_len) +{ + for (uint i = 0, i_prev = coords_len - 1; i < coords_len; i_prev = i++) { + *((float *)GWN_vertbuf_raw_step(pos_step)) = coords[i_prev]; + *((float *)GWN_vertbuf_raw_step(pos_step)) = coords[i]; + } +} + +/** Fan lines out from the first vertex. */ +static void camera_fill_lines_fan_fl_v1( + Gwn_VertBufRaw *pos_step, + const float *coords, const uint coords_len) +{ + for (uint i = 1; i < coords_len; i++) { + *((float *)GWN_vertbuf_raw_step(pos_step)) = coords[0]; + *((float *)GWN_vertbuf_raw_step(pos_step)) = coords[i]; + } +} + +/** Simply fill the array. */ +static void camera_fill_array_fl_v1( + Gwn_VertBufRaw *pos_step, + const float *coords, const uint coords_len) +{ + for (uint i = 0; i < coords_len; i++) { + *((float *)GWN_vertbuf_raw_step(pos_step)) = coords[i]; + } +} + + Gwn_Batch *DRW_cache_camera_get(void) { if (!SHC.drw_camera) { - float v0 = 0.0f; /* Center point */ - float v1 = 1.0f; /* + X + Y */ - float v2 = 2.0f; /* + X - Y */ - float v3 = 3.0f; /* - X - Y */ - float v4 = 4.0f; /* - X + Y */ - float v5 = 5.0f; /* tria + X */ - float v6 = 6.0f; /* tria - X */ - float v7 = 7.0f; /* tria + Y */ - int v_idx = 0; - static Gwn_VertFormat format = { 0 }; static struct { uint pos; } attr_id; if (format.attrib_ct == 0) { - /* use x coordinate to identify the vertex - * the vertex shader take care to place it - * appropriatelly */ attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 1, GWN_FETCH_FLOAT); } /* Vertices */ Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format); - GWN_vertbuf_data_alloc(vbo, 22); - - GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, &v0); - GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, &v1); + const int vbo_len_capacity = 22; + GWN_vertbuf_data_alloc(vbo, vbo_len_capacity); + Gwn_VertBufRaw pos_step; + GWN_vertbuf_attr_get_raw_data(vbo, attr_id.pos, &pos_step); - GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, &v0); - GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, &v2); + /* camera cone (from center to frame) */ + camera_fill_lines_fan_fl_v1(&pos_step, camera_coords_frame_bounds, ARRAY_SIZE(camera_coords_frame_bounds)); - GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, &v0); - GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, &v3); + /* camera frame (skip center) */ + camera_fill_lines_loop_fl_v1(&pos_step, &camera_coords_frame_bounds[1], ARRAY_SIZE(camera_coords_frame_bounds) - 1); - GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, &v0); - GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, &v4); + /* camera triangle (above the frame) */ + camera_fill_lines_loop_fl_v1(&pos_step, camera_coords_frame_tri, ARRAY_SIZE(camera_coords_frame_tri)); - /* camera frame */ - GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, &v1); - GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, &v2); + BLI_assert(vbo_len_capacity == GWN_vertbuf_raw_used(&pos_step)); - GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, &v2); - GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, &v3); + SHC.drw_camera = GWN_batch_create_ex(GWN_PRIM_LINES, vbo, NULL, GWN_BATCH_OWNS_VBO); + } + return SHC.drw_camera; +} - GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, &v3); - GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, &v4); +Gwn_Batch *DRW_cache_camera_frame_get(void) +{ + if (!SHC.drw_camera_frame) { - GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, &v4); - GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, &v1); + static Gwn_VertFormat format = { 0 }; + static struct { uint pos; } attr_id; + if (format.attrib_ct == 0) { + attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 1, GWN_FETCH_FLOAT); + } - /* tria */ - GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, &v5); - GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, &v6); + /* Vertices */ + Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format); + const int vbo_len_capacity = 8; + GWN_vertbuf_data_alloc(vbo, vbo_len_capacity); + Gwn_VertBufRaw pos_step; + GWN_vertbuf_attr_get_raw_data(vbo, attr_id.pos, &pos_step); - GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, &v6); - GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, &v7); + /* camera frame (skip center) */ + camera_fill_lines_loop_fl_v1(&pos_step, &camera_coords_frame_bounds[1], ARRAY_SIZE(camera_coords_frame_bounds) - 1); - GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, &v7); - GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, &v5); + BLI_assert(vbo_len_capacity == GWN_vertbuf_raw_used(&pos_step)); - SHC.drw_camera = GWN_batch_create_ex(GWN_PRIM_LINES, vbo, NULL, GWN_BATCH_OWNS_VBO); + SHC.drw_camera_frame = GWN_batch_create_ex(GWN_PRIM_LINES, vbo, NULL, GWN_BATCH_OWNS_VBO); } - return SHC.drw_camera; + return SHC.drw_camera_frame; } Gwn_Batch *DRW_cache_camera_tria_get(void) { if (!SHC.drw_camera_tria) { - float v5 = 5.0f; /* tria + X */ - float v6 = 6.0f; /* tria - X */ - float v7 = 7.0f; /* tria + Y */ - int v_idx = 0; - static Gwn_VertFormat format = { 0 }; static struct { uint pos; } attr_id; if (format.attrib_ct == 0) { - /* use x coordinate to identify the vertex - * the vertex shader take care to place it - * appropriatelly */ attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 1, GWN_FETCH_FLOAT); } /* Vertices */ Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format); - GWN_vertbuf_data_alloc(vbo, 6); + const int vbo_len_capacity = 3; + GWN_vertbuf_data_alloc(vbo, vbo_len_capacity); + Gwn_VertBufRaw pos_step; + GWN_vertbuf_attr_get_raw_data(vbo, attr_id.pos, &pos_step); + + /* camera triangle (above the frame) */ + camera_fill_array_fl_v1(&pos_step, camera_coords_frame_tri, ARRAY_SIZE(camera_coords_frame_tri)); - /* tria */ - GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, &v5); - GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, &v6); - GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, &v7); + BLI_assert(vbo_len_capacity == GWN_vertbuf_raw_used(&pos_step)); SHC.drw_camera_tria = GWN_batch_create_ex(GWN_PRIM_TRIS, vbo, NULL, GWN_BATCH_OWNS_VBO); } @@ -2334,6 +2420,16 @@ Gwn_Batch *DRW_cache_curve_surface_get(Object *ob) return DRW_curve_batch_cache_get_triangles_with_normals(cu, ob->curve_cache); } +/* Return list of batches */ +Gwn_Batch **DRW_cache_curve_surface_shaded_get( + Object *ob, struct GPUMaterial **gpumat_array, uint gpumat_array_len) +{ + BLI_assert(ob->type == OB_CURVE); + + struct Curve *cu = ob->data; + return DRW_curve_batch_cache_get_surface_shaded(cu, ob->curve_cache, gpumat_array, gpumat_array_len); +} + /** \} */ /* -------------------------------------------------------------------- */ @@ -2372,6 +2468,17 @@ Gwn_Batch *DRW_cache_text_surface_get(Object *ob) return DRW_curve_batch_cache_get_triangles_with_normals(cu, ob->curve_cache); } +Gwn_Batch **DRW_cache_text_surface_shaded_get( + Object *ob, struct GPUMaterial **gpumat_array, uint gpumat_array_len) +{ + BLI_assert(ob->type == OB_FONT); + struct Curve *cu = ob->data; + if (cu->editfont && (cu->flag & CU_FAST)) { + return NULL; + } + return DRW_curve_batch_cache_get_surface_shaded(cu, ob->curve_cache, gpumat_array, gpumat_array_len); +} + Gwn_Batch *DRW_cache_text_cursor_overlay_get(Object *ob) { BLI_assert(ob->type == OB_FONT); @@ -2401,6 +2508,16 @@ Gwn_Batch *DRW_cache_surf_surface_get(Object *ob) return DRW_curve_batch_cache_get_triangles_with_normals(cu, ob->curve_cache); } +/* Return list of batches */ +Gwn_Batch **DRW_cache_surf_surface_shaded_get( + Object *ob, struct GPUMaterial **gpumat_array, uint gpumat_array_len) +{ + BLI_assert(ob->type == OB_SURF); + + struct Curve *cu = ob->data; + return DRW_curve_batch_cache_get_surface_shaded(cu, ob->curve_cache, gpumat_array, gpumat_array_len); +} + /** \} */ /* -------------------------------------------------------------------- */ diff --git a/source/blender/draw/intern/draw_cache.h b/source/blender/draw/intern/draw_cache.h index 35ac8f4a35d..c039bb8883d 100644 --- a/source/blender/draw/intern/draw_cache.h +++ b/source/blender/draw/intern/draw_cache.h @@ -70,6 +70,7 @@ struct Gwn_Batch *DRW_cache_field_cone_limit_get(void); /* Lamps */ struct Gwn_Batch *DRW_cache_lamp_get(void); +struct Gwn_Batch *DRW_cache_lamp_shadows_get(void); struct Gwn_Batch *DRW_cache_lamp_sunrays_get(void); struct Gwn_Batch *DRW_cache_lamp_area_get(void); struct Gwn_Batch *DRW_cache_lamp_hemi_get(void); @@ -78,6 +79,7 @@ struct Gwn_Batch *DRW_cache_lamp_spot_square_get(void); /* Camera */ struct Gwn_Batch *DRW_cache_camera_get(void); +struct Gwn_Batch *DRW_cache_camera_frame_get(void); struct Gwn_Batch *DRW_cache_camera_tria_get(void); /* Speaker */ @@ -130,6 +132,8 @@ void DRW_cache_mesh_sculpt_coords_ensure(struct Object *ob); /* Curve */ struct Gwn_Batch *DRW_cache_curve_surface_get(struct Object *ob); +struct Gwn_Batch **DRW_cache_curve_surface_shaded_get( + struct Object *ob, struct GPUMaterial **gpumat_array, uint gpumat_array_len); struct Gwn_Batch *DRW_cache_curve_surface_verts_get(struct Object *ob); struct Gwn_Batch *DRW_cache_curve_edge_wire_get(struct Object *ob); /* edit-mode */ @@ -140,12 +144,16 @@ struct Gwn_Batch *DRW_cache_curve_vert_overlay_get(struct Object *ob); /* Font */ struct Gwn_Batch *DRW_cache_text_edge_wire_get(struct Object *ob); struct Gwn_Batch *DRW_cache_text_surface_get(struct Object *ob); +struct Gwn_Batch **DRW_cache_text_surface_shaded_get( + struct Object *ob, struct GPUMaterial **gpumat_array, uint gpumat_array_len); /* edit-mode */ struct Gwn_Batch *DRW_cache_text_cursor_overlay_get(struct Object *ob); struct Gwn_Batch *DRW_cache_text_select_overlay_get(struct Object *ob); /* Surface */ struct Gwn_Batch *DRW_cache_surf_surface_get(struct Object *ob); +struct Gwn_Batch **DRW_cache_surf_surface_shaded_get( + struct Object *ob, struct GPUMaterial **gpumat_array, uint gpumat_array_len); /* Lattice */ struct Gwn_Batch *DRW_cache_lattice_verts_get(struct Object *ob); diff --git a/source/blender/draw/intern/draw_cache_impl.h b/source/blender/draw/intern/draw_cache_impl.h index c998282ae1f..0b18f3a257f 100644 --- a/source/blender/draw/intern/draw_cache_impl.h +++ b/source/blender/draw/intern/draw_cache_impl.h @@ -29,14 +29,16 @@ struct CurveCache; struct GPUMaterial; struct Gwn_Batch; +struct Gwn_IndexBuf; +struct Gwn_VertBuf; struct ListBase; -struct MetaBall; struct ModifierData; struct ParticleSystem; struct Curve; struct Lattice; struct Mesh; +struct MetaBall; /* Expose via BKE callbacks */ void DRW_mball_batch_cache_dirty(struct MetaBall *mb, int mode); @@ -62,6 +64,9 @@ struct Gwn_Batch *DRW_curve_batch_cache_get_overlay_edges(struct Curve *cu); struct Gwn_Batch *DRW_curve_batch_cache_get_overlay_verts(struct Curve *cu); struct Gwn_Batch *DRW_curve_batch_cache_get_triangles_with_normals(struct Curve *cu, struct CurveCache *ob_curve_cache); +struct Gwn_Batch **DRW_curve_batch_cache_get_surface_shaded( + struct Curve *cu, struct CurveCache *ob_curve_cache, + struct GPUMaterial **gpumat_array, uint gpumat_array_len); /* Metaball */ struct Gwn_Batch *DRW_metaball_batch_cache_get_triangles_with_normals(struct Object *ob); @@ -71,7 +76,12 @@ struct Gwn_Batch *DRW_curve_batch_cache_get_overlay_cursor(struct Curve *cu); struct Gwn_Batch *DRW_curve_batch_cache_get_overlay_select(struct Curve *cu); /* DispList */ -struct Gwn_Batch *BLI_displist_batch_calc_surface(struct ListBase *lb); +struct Gwn_VertBuf *DRW_displist_vertbuf_calc_pos_with_normals(struct ListBase *lb); +struct Gwn_IndexBuf *DRW_displist_indexbuf_calc_triangles_in_order(struct ListBase *lb); +struct Gwn_IndexBuf **DRW_displist_indexbuf_calc_triangles_in_order_split_by_material( + struct ListBase *lb, uint gpumat_array_len); +struct Gwn_Batch **DRW_displist_batch_calc_tri_pos_normals_and_uv_split_by_material( + struct ListBase *lb, uint gpumat_array_len); /* Lattice */ struct Gwn_Batch *DRW_lattice_batch_cache_get_all_edges(struct Lattice *lt, bool use_weight, const int actdef); diff --git a/source/blender/draw/intern/draw_cache_impl_curve.c b/source/blender/draw/intern/draw_cache_impl_curve.c index e6e52fe4579..3939ea062e9 100644 --- a/source/blender/draw/intern/draw_cache_impl_curve.c +++ b/source/blender/draw/intern/draw_cache_impl_curve.c @@ -40,9 +40,22 @@ #include "GPU_batch.h" +#include "UI_resources.h" + #include "draw_cache_impl.h" /* own include */ -#define SELECT 1 +#define SELECT 1 +#define ACTIVE_NURB 1 << 7 /* last char bite */ +#define HANDLE_SEL_OFFSET (TH_HANDLE_SEL_FREE - TH_HANDLE_FREE) + +/* Used as values of `color_id` in `edit_curve_overlay_handle_geom.glsl` */ +enum { + COLOR_NURB_ULINE_ID = TH_HANDLE_SEL_AUTOCLAMP - TH_HANDLE_FREE + 1, + COLOR_NURB_SEL_ULINE_ID, + COLOR_ACTIVE_SPLINE, + + TOT_HANDLE_COL, +}; /** * TODO @@ -126,7 +139,8 @@ static int curve_render_normal_len_get(const ListBase *lb, const CurveCache *ob_ nr -= skip; } #else - normal_len += max_ii((nr + max_ii(skip - 1, 0)) / (skip + 1), 0); + /* Same as loop above */ + normal_len += (nr / (skip + 1)) + ((nr % (skip + 1)) != 0); #endif } return normal_len; @@ -310,7 +324,11 @@ typedef struct CurveBatchCache { } overlay; struct { + Gwn_VertBuf *verts; + Gwn_IndexBuf *triangles_in_order; + Gwn_Batch **shaded_triangles; Gwn_Batch *batch; + int mat_len; } surface; /* 3d text */ @@ -340,6 +358,10 @@ static bool curve_batch_cache_valid(Curve *cu) return false; } + if (cache->is_dirty) { + return false; + } + if (cache->is_editmode != ((cu->editnurb != NULL) || (cu->editfont != NULL))) { return false; } @@ -358,16 +380,6 @@ static bool curve_batch_cache_valid(Curve *cu) } } - if (cache->is_dirty == false) { - return true; - } - else { - /* TODO: check number of vertices/edges? */ - if (cache->is_editmode) { - return false; - } - } - return true; } @@ -444,6 +456,14 @@ static void curve_batch_cache_clear(Curve *cu) GWN_BATCH_DISCARD_SAFE(cache->overlay.verts); GWN_BATCH_DISCARD_SAFE(cache->overlay.edges); + GWN_VERTBUF_DISCARD_SAFE(cache->surface.verts); + GWN_INDEXBUF_DISCARD_SAFE(cache->surface.triangles_in_order); + if (cache->surface.shaded_triangles) { + for (int i = 0; i < cache->surface.mat_len; ++i) { + GWN_BATCH_DISCARD_SAFE(cache->surface.shaded_triangles[i]); + } + } + MEM_SAFE_FREE(cache->surface.shaded_triangles); GWN_BATCH_DISCARD_SAFE(cache->surface.batch); /* don't own vbo & elems */ @@ -735,47 +755,50 @@ static void curve_batch_cache_create_overlay_batches(Curve *cu) int vbo_len_used = 0; GWN_vertbuf_data_alloc(vbo, vbo_len_capacity); int i = 0; - for (Nurb *nu = rdata->nurbs->first; nu; nu = nu->next) { + for (Nurb *nu = rdata->nurbs->first; nu; nu = nu->next, i++) { + const bool is_active_nurb = (i == cu->actnu); + if (nu->bezt) { int a = 0; for (const BezTriple *bezt = nu->bezt; a < nu->pntsu; a++, bezt++) { if (bezt->hide == false) { - const bool is_active = (i == rdata->actvert); - char vflag; - - vflag = (bezt->f1 & SELECT) ? (is_active ? VFLAG_VERTEX_ACTIVE : VFLAG_VERTEX_SELECTED) : 0; - GWN_vertbuf_attr_set(vbo, attr_id.pos, vbo_len_used, bezt->vec[0]); - GWN_vertbuf_attr_set(vbo, attr_id.data, vbo_len_used, &vflag); - vbo_len_used += 1; + char col_id; - /* same vertex twice, only check different selection */ - for (int j = 0; j < 2; j++) { - vflag = ((j ? bezt->f3 : bezt->f1) & SELECT) ? - (is_active ? VFLAG_VERTEX_ACTIVE : VFLAG_VERTEX_SELECTED) : 0; + for (int j = 0; j < 2; j += 1) { + /* same vertex twice, only check different selection */ GWN_vertbuf_attr_set(vbo, attr_id.pos, vbo_len_used, bezt->vec[1]); - GWN_vertbuf_attr_set(vbo, attr_id.data, vbo_len_used, &vflag); vbo_len_used += 1; - } - vflag = (bezt->f3 & SELECT) ? (is_active ? VFLAG_VERTEX_ACTIVE : VFLAG_VERTEX_SELECTED) : 0; - GWN_vertbuf_attr_set(vbo, attr_id.pos, vbo_len_used, bezt->vec[2]); - GWN_vertbuf_attr_set(vbo, attr_id.data, vbo_len_used, &vflag); - vbo_len_used += 1; + col_id = (&bezt->h1)[j]; + if ((&bezt->f1)[j * 2] & SELECT) { + col_id += HANDLE_SEL_OFFSET; + } + if (is_active_nurb) { + col_id |= ACTIVE_NURB; + } + + GWN_vertbuf_attr_set(vbo, attr_id.pos, vbo_len_used, bezt->vec[j * 2]); + GWN_vertbuf_attr_set(vbo, attr_id.data, vbo_len_used, &col_id); + vbo_len_used += 1; + } } - i += 1; } } else if (nu->bp) { int a = 1; for (const BPoint *bp_prev = nu->bp, *bp_curr = &nu->bp[1]; a < nu->pntsu; a++, bp_prev = bp_curr++) { if ((bp_prev->hide == false) && (bp_curr->hide == false)) { - char vflag; - vflag = ((bp_prev->f1 & SELECT) && (bp_curr->f1 & SELECT)) ? VFLAG_VERTEX_SELECTED : 0; + char col_id = ((bp_prev->f1 & SELECT) && (bp_curr->f1 & SELECT)) ? COLOR_NURB_SEL_ULINE_ID : COLOR_NURB_ULINE_ID; + + if (is_active_nurb) { + col_id |= ACTIVE_NURB; + } + GWN_vertbuf_attr_set(vbo, attr_id.pos, vbo_len_used, bp_prev->vec); - GWN_vertbuf_attr_set(vbo, attr_id.data, vbo_len_used, &vflag); vbo_len_used += 1; + GWN_vertbuf_attr_set(vbo, attr_id.pos, vbo_len_used, bp_curr->vec); - GWN_vertbuf_attr_set(vbo, attr_id.data, vbo_len_used, &vflag); + GWN_vertbuf_attr_set(vbo, attr_id.data, vbo_len_used, &col_id); vbo_len_used += 1; } @@ -796,8 +819,18 @@ static Gwn_Batch *curve_batch_cache_get_pos_and_normals(CurveRenderData *rdata, { BLI_assert(rdata->types & CU_DATATYPE_SURFACE); if (cache->surface.batch == NULL) { - cache->surface.batch = BLI_displist_batch_calc_surface(&rdata->ob_curve_cache->disp); + ListBase *lb = &rdata->ob_curve_cache->disp; + + if (cache->surface.verts == NULL) { + cache->surface.verts = DRW_displist_vertbuf_calc_pos_with_normals(lb); + } + if (cache->surface.triangles_in_order == NULL) { + cache->surface.triangles_in_order = DRW_displist_indexbuf_calc_triangles_in_order(lb); + } + cache->surface.batch = GWN_batch_create( + GWN_PRIM_TRIS, cache->surface.verts, cache->surface.triangles_in_order); } + return cache->surface.batch; } @@ -997,6 +1030,55 @@ Gwn_Batch *DRW_curve_batch_cache_get_triangles_with_normals( return cache->surface.batch; } +Gwn_Batch **DRW_curve_batch_cache_get_surface_shaded( + struct Curve *cu, struct CurveCache *ob_curve_cache, + struct GPUMaterial **UNUSED(gpumat_array), uint gpumat_array_len) +{ + CurveBatchCache *cache = curve_batch_cache_get(cu); + + if (cache->surface.mat_len != gpumat_array_len) { + /* TODO: deduplicate code */ + if (cache->surface.shaded_triangles) { + for (int i = 0; i < cache->surface.mat_len; ++i) { + GWN_BATCH_DISCARD_SAFE(cache->surface.shaded_triangles[i]); + } + } + MEM_SAFE_FREE(cache->surface.shaded_triangles); + } + + if (cache->surface.shaded_triangles == NULL) { + CurveRenderData *rdata = curve_render_data_create(cu, ob_curve_cache, CU_DATATYPE_SURFACE); + ListBase *lb = &rdata->ob_curve_cache->disp; + + cache->surface.mat_len = gpumat_array_len; + if (cu->flag & CU_UV_ORCO) { + cache->surface.shaded_triangles = DRW_displist_batch_calc_tri_pos_normals_and_uv_split_by_material( + lb, gpumat_array_len); + } + else { + cache->surface.shaded_triangles = MEM_mallocN( + sizeof(*cache->surface.shaded_triangles) * gpumat_array_len, __func__); + Gwn_IndexBuf **el = DRW_displist_indexbuf_calc_triangles_in_order_split_by_material( + lb, gpumat_array_len); + + if (cache->surface.verts == NULL) { + cache->surface.verts = DRW_displist_vertbuf_calc_pos_with_normals(lb); + } + + for (int i = 0; i < gpumat_array_len; ++i) { + cache->surface.shaded_triangles[i] = GWN_batch_create_ex( + GWN_PRIM_TRIS, cache->surface.verts, el[i], GWN_BATCH_OWNS_INDEX); + } + + MEM_freeN(el); /* Save `el` in cache? */ + } + + curve_render_data_free(rdata); + } + + return cache->surface.shaded_triangles; +} + /* -------------------------------------------------------------------- */ @@ -1033,4 +1115,4 @@ Gwn_Batch *DRW_curve_batch_cache_get_overlay_cursor(Curve *cu) return cache->text.cursor; } -/** \} */
\ No newline at end of file +/** \} */ diff --git a/source/blender/draw/intern/draw_cache_impl_displist.c b/source/blender/draw/intern/draw_cache_impl_displist.c index 96386f82faf..627fb38d9d6 100644 --- a/source/blender/draw/intern/draw_cache_impl_displist.c +++ b/source/blender/draw/intern/draw_cache_impl_displist.c @@ -31,6 +31,7 @@ #include "MEM_guardedalloc.h" +#include "BLI_alloca.h" #include "BLI_utildefines.h" #include "BLI_math_vector.h" @@ -86,13 +87,39 @@ static int curve_render_surface_tri_len_get(const ListBase *lb) return tri_len; } -Gwn_Batch *BLI_displist_batch_calc_surface(ListBase *lb) +static void displist_indexbufbuilder_set(Gwn_IndexBufBuilder *elb, const DispList *dl, const int ofs) { - const int tri_len = curve_render_surface_tri_len_get(lb); - if (tri_len == 0) { - return NULL; + if (ELEM(dl->type, DL_INDEX3, DL_INDEX4, DL_SURF)) { + const int *idx = dl->index; + if (dl->type == DL_INDEX3) { + const int i_end = dl->parts; + for (int i = 0; i < i_end; i++, idx += 3) { + GWN_indexbuf_add_tri_verts(elb, idx[0] + ofs, idx[2] + ofs, idx[1] + ofs); + } + } + else if (dl->type == DL_SURF) { + const int i_end = dl->totindex; + for (int i = 0; i < i_end; i++, idx += 4) { + GWN_indexbuf_add_tri_verts(elb, idx[0] + ofs, idx[2] + ofs, idx[1] + ofs); + GWN_indexbuf_add_tri_verts(elb, idx[0] + ofs, idx[3] + ofs, idx[2] + ofs); + } + } + else { + BLI_assert(dl->type == DL_INDEX4); + const int i_end = dl->parts; + for (int i = 0; i < i_end; i++, idx += 4) { + GWN_indexbuf_add_tri_verts(elb, idx[0] + ofs, idx[1] + ofs, idx[2] + ofs); + + if (idx[2] != idx[3]) { + GWN_indexbuf_add_tri_verts(elb, idx[0] + ofs, idx[2] + ofs, idx[3] + ofs); + } + } + } } +} +Gwn_VertBuf *DRW_displist_vertbuf_calc_pos_with_normals(ListBase *lb) +{ static Gwn_VertFormat format = { 0 }; static struct { uint pos, nor; } attr_id; if (format.attrib_ct == 0) { @@ -101,74 +128,271 @@ Gwn_Batch *BLI_displist_batch_calc_surface(ListBase *lb) attr_id.nor = GWN_vertformat_attr_add(&format, "nor", GWN_COMP_F32, 3, GWN_FETCH_FLOAT); } - const int vert_len = curve_render_surface_vert_len_get(lb); Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format); - { - const int vbo_len_capacity = vert_len; - int vbo_len_used = 0; - GWN_vertbuf_data_alloc(vbo, vbo_len_capacity); - - BKE_displist_normals_add(lb); - - for (const DispList *dl = lb->first; dl; dl = dl->next) { - const bool ndata_is_single = dl->type == DL_INDEX3; - if (ELEM(dl->type, DL_INDEX3, DL_INDEX4, DL_SURF)) { - const float *fp_co = dl->verts; - const float *fp_no = dl->nors; - const int vbo_end = vbo_len_used + dl_vert_len(dl); - while (vbo_len_used < vbo_end) { - GWN_vertbuf_attr_set(vbo, attr_id.pos, vbo_len_used, fp_co); - if (fp_no) { - GWN_vertbuf_attr_set(vbo, attr_id.nor, vbo_len_used, fp_no); - if (ndata_is_single == false) { - fp_no += 3; - } + GWN_vertbuf_data_alloc(vbo, curve_render_surface_vert_len_get(lb)); + + BKE_displist_normals_add(lb); + + int vbo_len_used = 0; + for (const DispList *dl = lb->first; dl; dl = dl->next) { + const bool ndata_is_single = dl->type == DL_INDEX3; + if (ELEM(dl->type, DL_INDEX3, DL_INDEX4, DL_SURF)) { + const float *fp_co = dl->verts; + const float *fp_no = dl->nors; + const int vbo_end = vbo_len_used + dl_vert_len(dl); + while (vbo_len_used < vbo_end) { + GWN_vertbuf_attr_set(vbo, attr_id.pos, vbo_len_used, fp_co); + if (fp_no) { + GWN_vertbuf_attr_set(vbo, attr_id.nor, vbo_len_used, fp_no); + if (ndata_is_single == false) { + fp_no += 3; } - fp_co += 3; - vbo_len_used += 1; } + fp_co += 3; + vbo_len_used += 1; } } } - { - Gwn_IndexBufBuilder elb; - GWN_indexbuf_init(&elb, GWN_PRIM_TRIS, tri_len, vert_len); + return vbo; +} - int ofs = 0; - for (const DispList *dl = lb->first; dl; dl = dl->next) { - if (ELEM(dl->type, DL_INDEX3, DL_INDEX4, DL_SURF)) { - const int *idx = dl->index; - if (dl->type == DL_INDEX3) { - const int i_end = dl->parts; - for (int i = 0; i < i_end; i++, idx += 3) { - GWN_indexbuf_add_tri_verts(&elb, idx[0] + ofs, idx[1] + ofs, idx[2] + ofs); - } +Gwn_IndexBuf *DRW_displist_indexbuf_calc_triangles_in_order(ListBase *lb) +{ + const int tri_len = curve_render_surface_tri_len_get(lb); + const int vert_len = curve_render_surface_vert_len_get(lb); + + Gwn_IndexBufBuilder elb; + GWN_indexbuf_init(&elb, GWN_PRIM_TRIS, tri_len, vert_len); + + int ofs = 0; + for (const DispList *dl = lb->first; dl; dl = dl->next) { + displist_indexbufbuilder_set(&elb, dl, ofs); + ofs += dl_vert_len(dl); + } + + return GWN_indexbuf_build(&elb); +} + +Gwn_IndexBuf **DRW_displist_indexbuf_calc_triangles_in_order_split_by_material(ListBase *lb, uint gpumat_array_len) +{ + Gwn_IndexBuf **shaded_triangles_in_order = MEM_callocN(sizeof(*shaded_triangles_in_order) * gpumat_array_len, __func__); + Gwn_IndexBufBuilder *elb = BLI_array_alloca(elb, gpumat_array_len); + + const int tri_len = curve_render_surface_tri_len_get(lb); + const int vert_len = curve_render_surface_vert_len_get(lb); + int i; + + /* Init each index buffer builder */ + for (i = 0; i < gpumat_array_len; i++) { + GWN_indexbuf_init(&elb[i], GWN_PRIM_TRIS, tri_len, vert_len); + } + + /* calc each index buffer builder */ + int ofs = 0; + for (const DispList *dl = lb->first; dl; dl = dl->next) { + displist_indexbufbuilder_set(&elb[dl->col], dl, ofs); + ofs += dl_vert_len(dl); + } + + /* build each indexbuf */ + for (i = 0; i < gpumat_array_len; i++) { + shaded_triangles_in_order[i] = GWN_indexbuf_build(&elb[i]); + } + + return shaded_triangles_in_order; +} + +static void displist_vertbuf_attr_set_tri_pos_normals_and_uv( + Gwn_VertBufRaw *pos_step, Gwn_VertBufRaw *nor_step, Gwn_VertBufRaw *uv_step, + const float v1[3], const float v2[3], const float v3[3], + const float n1[3], const float n2[3], const float n3[3], + const float uv1[2], const float uv2[2], const float uv3[2]) +{ + copy_v3_v3(GWN_vertbuf_raw_step(pos_step), v1); + copy_v3_v3(GWN_vertbuf_raw_step(nor_step), n1); + copy_v2_v2(GWN_vertbuf_raw_step(uv_step), uv1); + + copy_v3_v3(GWN_vertbuf_raw_step(pos_step), v2); + copy_v3_v3(GWN_vertbuf_raw_step(nor_step), n2); + copy_v2_v2(GWN_vertbuf_raw_step(uv_step), uv2); + + copy_v3_v3(GWN_vertbuf_raw_step(pos_step), v3); + copy_v3_v3(GWN_vertbuf_raw_step(nor_step), n3); + copy_v2_v2(GWN_vertbuf_raw_step(uv_step), uv3); +} + +Gwn_Batch **DRW_displist_batch_calc_tri_pos_normals_and_uv_split_by_material(ListBase *lb, uint gpumat_array_len) +{ + static Gwn_VertFormat shaded_triangles_format = { 0 }; + static struct { uint pos, nor, uv; } attr_id; + + if (shaded_triangles_format.attrib_ct == 0) { + /* initialize vertex format */ + attr_id.pos = GWN_vertformat_attr_add(&shaded_triangles_format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT); + attr_id.nor = GWN_vertformat_attr_add(&shaded_triangles_format, "nor", GWN_COMP_F32, 3, GWN_FETCH_FLOAT); + attr_id.uv = GWN_vertformat_attr_add(&shaded_triangles_format, "u", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); + } + + Gwn_Batch **shaded_triangles = MEM_mallocN(sizeof(*shaded_triangles) * gpumat_array_len, __func__); + + Gwn_VertBuf **vbo = BLI_array_alloca(vbo, gpumat_array_len); + uint *vbo_len_capacity = BLI_array_alloca(vbo_len_capacity, gpumat_array_len); + + Gwn_VertBufRaw *pos_step, *nor_step, *uv_step; + pos_step = BLI_array_alloca(pos_step, gpumat_array_len); + nor_step = BLI_array_alloca(nor_step, gpumat_array_len); + uv_step = BLI_array_alloca(uv_step, gpumat_array_len); + + /* Create each vertex buffer */ + for (int i = 0; i < gpumat_array_len; i++) { + vbo[i] = GWN_vertbuf_create_with_format(&shaded_triangles_format); + vbo_len_capacity[i] = 0; + } + + /* Calc `vbo_len_capacity` */ + for (const DispList *dl = lb->first; dl; dl = dl->next) { + vbo_len_capacity[dl->col] += dl_tri_len(dl) * 3; + } + + /* Alloc each vertex buffer and get each raw data */ + for (int i = 0; i < gpumat_array_len; i++) { + GWN_vertbuf_data_alloc(vbo[i], vbo_len_capacity[i]); + GWN_vertbuf_attr_get_raw_data(vbo[i], attr_id.pos, &pos_step[i]); + GWN_vertbuf_attr_get_raw_data(vbo[i], attr_id.nor, &nor_step[i]); + GWN_vertbuf_attr_get_raw_data(vbo[i], attr_id.uv, &uv_step[i]); + } + + BKE_displist_normals_add(lb); + + for (const DispList *dl = lb->first; dl; dl = dl->next) { + if (ELEM(dl->type, DL_INDEX3, DL_INDEX4, DL_SURF)) { + const int col = dl->col; + const float(*verts)[3] = (float(*)[3])dl->verts; + const float(*nors)[3] = (float(*)[3])dl->nors; + const int *idx = dl->index; + float uv[4][2]; + + if (dl->type == DL_INDEX3) { + const float x_max = (float)(dl->nr - 1); + uv[0][1] = uv[1][1] = uv[2][1] = 0.0f; + const int i_end = dl->parts; + for (int i = 0; i < i_end; i++, idx += 3) { + uv[0][0] = idx[0] / x_max; + uv[1][0] = idx[2] / x_max; + uv[2][0] = idx[1] / x_max; + + displist_vertbuf_attr_set_tri_pos_normals_and_uv( + &pos_step[col], &nor_step[col], &uv_step[col], + verts[idx[0]], verts[idx[2]], verts[idx[1]], + nors[idx[0]], nors[idx[2]], nors[idx[1]], + uv[0], uv[1], uv[2]); } - else if (dl->type == DL_SURF) { - const int i_end = dl->totindex; - for (int i = 0; i < i_end; i++, idx += 4) { - GWN_indexbuf_add_tri_verts(&elb, idx[0] + ofs, idx[1] + ofs, idx[2] + ofs); - GWN_indexbuf_add_tri_verts(&elb, idx[0] + ofs, idx[2] + ofs, idx[3] + ofs); + } + else if (dl->type == DL_SURF) { + uint quad[4]; + for (int a = 0; a < dl->parts; a++) { + if ((dl->flag & DL_CYCL_V) == 0 && a == dl->parts - 1) { + break; } - } - else { - BLI_assert(dl->type == DL_INDEX4); - const int i_end = dl->parts; - for (int i = 0; i < i_end; i++, idx += 4) { - GWN_indexbuf_add_tri_verts(&elb, idx[0] + ofs, idx[1] + ofs, idx[2] + ofs); - - if (idx[2] != idx[3]) { - GWN_indexbuf_add_tri_verts(&elb, idx[0] + ofs, idx[2] + ofs, idx[3] + ofs); + + int b; + if (dl->flag & DL_CYCL_U) { + quad[0] = dl->nr * a; + quad[3] = quad[0] + dl->nr - 1; + quad[1] = quad[0] + dl->nr; + quad[2] = quad[3] + dl->nr; + b = 0; + } + else { + quad[3] = dl->nr * a; + quad[0] = quad[3] + 1; + quad[2] = quad[3] + dl->nr; + quad[1] = quad[0] + dl->nr; + b = 1; + } + if ((dl->flag & DL_CYCL_V) && a == dl->parts - 1) { + quad[1] -= dl->parts * dl->nr; + quad[2] -= dl->parts * dl->nr; + } + + for (; b < dl->nr; b++) { + int orco_sizeu = dl->nr - 1; + int orco_sizev = dl->parts - 1; + + /* exception as handled in convertblender.c too */ + if (dl->flag & DL_CYCL_U) { + orco_sizeu++; + } + if (dl->flag & DL_CYCL_V) { + orco_sizev++; + } + + for (int i = 0; i < 4; i++) { + /* find uv based on vertex index into grid array */ + uv[i][0] = (quad[i] / dl->nr) / (float)orco_sizev; + uv[i][1] = (quad[i] % dl->nr) / (float)orco_sizeu; + + /* cyclic correction */ + if ((i == 1 || i == 2) && uv[i][0] == 0.0f) { + uv[i][0] = 1.0f; + } + if ((i == 0 || i == 1) && uv[i][1] == 0.0f) { + uv[i][1] = 1.0f; + } } + + displist_vertbuf_attr_set_tri_pos_normals_and_uv( + &pos_step[col], &nor_step[col], &uv_step[col], + verts[quad[0]], verts[quad[1]], verts[quad[2]], + nors[quad[0]], nors[quad[1]], nors[quad[2]], + uv[0], uv[1], uv[2]); + + displist_vertbuf_attr_set_tri_pos_normals_and_uv( + &pos_step[col], &nor_step[col], &uv_step[col], + verts[quad[0]], verts[quad[2]], verts[quad[3]], + nors[quad[0]], nors[quad[2]], nors[quad[3]], + uv[0], uv[2], uv[3]); + + quad[2] = quad[1]; + quad[1]++; + quad[3] = quad[0]; + quad[0]++; + } + } + } + else { + BLI_assert(dl->type == DL_INDEX4); + uv[0][0] = uv[0][1] = uv[1][0] = uv[3][1] = 0.0f; + uv[1][1] = uv[2][0] = uv[2][1] = uv[3][0] = 1.0f; + + const int i_end = dl->parts; + for (int i = 0; i < i_end; i++, idx += 4) { + displist_vertbuf_attr_set_tri_pos_normals_and_uv( + &pos_step[col], &nor_step[col], &uv_step[col], + verts[idx[0]], verts[idx[1]], verts[idx[2]], + nors[idx[0]], nors[idx[1]], nors[idx[2]], + uv[0], uv[1], uv[2]); + + if (idx[2] != idx[3]) { + displist_vertbuf_attr_set_tri_pos_normals_and_uv( + &pos_step[col], &nor_step[col], &uv_step[col], + verts[idx[0]], verts[idx[2]], verts[idx[3]], + nors[idx[0]], nors[idx[2]], nors[idx[3]], + uv[0], uv[2], uv[3]); } } - ofs += dl_vert_len(dl); } } + } - return GWN_batch_create_ex( - GWN_PRIM_TRIS, vbo, GWN_indexbuf_build(&elb), - GWN_BATCH_OWNS_VBO | GWN_BATCH_OWNS_INDEX); + for (int i = 0; i < gpumat_array_len; i++) { + uint vbo_len_used = GWN_vertbuf_raw_used(&pos_step[i]); + if (vbo_len_capacity[i] != vbo_len_used) { + GWN_vertbuf_data_resize(vbo[i], vbo_len_used); + } + shaded_triangles[i] = GWN_batch_create_ex(GWN_PRIM_TRIS, vbo[i], NULL, GWN_BATCH_OWNS_VBO); } + + return shaded_triangles; } diff --git a/source/blender/draw/intern/draw_cache_impl_lattice.c b/source/blender/draw/intern/draw_cache_impl_lattice.c index 20698fe6592..eed408de3cd 100644 --- a/source/blender/draw/intern/draw_cache_impl_lattice.c +++ b/source/blender/draw/intern/draw_cache_impl_lattice.c @@ -41,7 +41,7 @@ #include "BKE_lattice.h" #include "BKE_deform.h" -#include "BKE_texture.h" +#include "BKE_colorband.h" #include "GPU_batch.h" @@ -260,7 +260,7 @@ static void lattice_render_data_weight_col_get(const LatticeRenderData *rdata, c float weight = defvert_find_weight(rdata->dvert + vert_idx, actdef); if (U.flag & USER_CUSTOM_RANGE) { - do_colorband(&U.coba_weight, weight, r_col); + BKE_colorband_evaluate(&U.coba_weight, weight, r_col); } else { rgb_from_weight(r_col, weight); diff --git a/source/blender/draw/intern/draw_cache_impl_mesh.c b/source/blender/draw/intern/draw_cache_impl_mesh.c index 8cd0c13faec..b44c5b8a20b 100644 --- a/source/blender/draw/intern/draw_cache_impl_mesh.c +++ b/source/blender/draw/intern/draw_cache_impl_mesh.c @@ -48,7 +48,7 @@ #include "BKE_editmesh_tangent.h" #include "BKE_mesh.h" #include "BKE_mesh_tangent.h" -#include "BKE_texture.h" +#include "BKE_colorband.h" #include "bmesh.h" @@ -1097,7 +1097,7 @@ static void mesh_render_data_ensure_vert_weight_color(MeshRenderData *rdata, con const MDeformVert *dvert = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset); float weight = defvert_find_weight(dvert, defgroup); if (U.flag & USER_CUSTOM_RANGE) { - do_colorband(&U.coba_weight, weight, vweight[i]); + BKE_colorband_evaluate(&U.coba_weight, weight, vweight[i]); } else { rgb_from_weight(vweight[i], weight); @@ -1113,7 +1113,7 @@ static void mesh_render_data_ensure_vert_weight_color(MeshRenderData *rdata, con for (int i = 0; i < rdata->vert_len; i++) { float weight = defvert_find_weight(&rdata->dvert[i], defgroup); if (U.flag & USER_CUSTOM_RANGE) { - do_colorband(&U.coba_weight, weight, vweight[i]); + BKE_colorband_evaluate(&U.coba_weight, weight, vweight[i]); } else { rgb_from_weight(vweight[i], weight); @@ -2167,11 +2167,10 @@ static Gwn_VertBuf *mesh_batch_cache_get_facedot_pos_with_normals_and_flag( } } const int vbo_len_used = vidx; + BLI_assert(vbo_len_used <= vbo_len_capacity); if (vbo_len_used != vbo_len_capacity) { GWN_vertbuf_data_resize(vbo, vbo_len_used); } - BLI_assert(vbo_len_capacity == vbo_len_used); - UNUSED_VARS_NDEBUG(vbo_len_used); } return cache->ed_fcenter_pos_with_nor_and_sel; diff --git a/source/blender/draw/intern/draw_cache_impl_metaball.c b/source/blender/draw/intern/draw_cache_impl_metaball.c index e2dba8e626e..f01e7b929f8 100644 --- a/source/blender/draw/intern/draw_cache_impl_metaball.c +++ b/source/blender/draw/intern/draw_cache_impl_metaball.c @@ -132,7 +132,12 @@ Gwn_Batch *DRW_metaball_batch_cache_get_triangles_with_normals(Object *ob) MetaBallBatchCache *cache = metaball_batch_cache_get(mb); if (cache->batch == NULL) { - cache->batch = BLI_displist_batch_calc_surface(&ob->curve_cache->disp); + ListBase *lb = &ob->curve_cache->disp; + cache->batch = GWN_batch_create_ex( + GWN_PRIM_TRIS, + DRW_displist_vertbuf_calc_pos_with_normals(lb), + DRW_displist_indexbuf_calc_triangles_in_order(lb), + GWN_BATCH_OWNS_VBO | GWN_BATCH_OWNS_INDEX); } return cache->batch; diff --git a/source/blender/draw/intern/draw_common.c b/source/blender/draw/intern/draw_common.c index b52c8e280b3..0eb97a54ba5 100644 --- a/source/blender/draw/intern/draw_common.c +++ b/source/blender/draw/intern/draw_common.c @@ -31,7 +31,7 @@ #include "UI_resources.h" #include "BKE_global.h" -#include "BKE_texture.h" +#include "BKE_colorband.h" #include "draw_common.h" @@ -81,6 +81,21 @@ void DRW_globals_update(void) UI_GetThemeColor4fv(TH_FACE_DOT, ts.colorFaceDot); UI_GetThemeColor4fv(TH_BACK, ts.colorBackground); + /* Curve */ + UI_GetThemeColor4fv(TH_HANDLE_FREE, ts.colorHandleFree); + UI_GetThemeColor4fv(TH_HANDLE_AUTO, ts.colorHandleAuto); + UI_GetThemeColor4fv(TH_HANDLE_VECT, ts.colorHandleVect); + UI_GetThemeColor4fv(TH_HANDLE_ALIGN, ts.colorHandleAlign); + UI_GetThemeColor4fv(TH_HANDLE_AUTOCLAMP, ts.colorHandleAutoclamp); + UI_GetThemeColor4fv(TH_HANDLE_SEL_FREE, ts.colorHandleSelFree); + UI_GetThemeColor4fv(TH_HANDLE_SEL_AUTO, ts.colorHandleSelAuto); + UI_GetThemeColor4fv(TH_HANDLE_SEL_VECT, ts.colorHandleSelVect); + UI_GetThemeColor4fv(TH_HANDLE_SEL_ALIGN, ts.colorHandleSelAlign); + UI_GetThemeColor4fv(TH_HANDLE_SEL_AUTOCLAMP, ts.colorHandleSelAutoclamp); + UI_GetThemeColor4fv(TH_NURB_ULINE, ts.colorNurbUline); + UI_GetThemeColor4fv(TH_NURB_SEL_ULINE, ts.colorNurbSelUline); + UI_GetThemeColor4fv(TH_ACTIVE_SPLINE, ts.colorActiveSpline); + /* Grid */ UI_GetThemeColorShade4fv(TH_GRID, 10, ts.colorGrid); /* emphasise division lines lighter instead of darker, if background is darker than grid */ @@ -130,7 +145,7 @@ void DRW_globals_update(void) ramp.data[2].r = 1.0f; ramp.data[2].pos = 1.0f; - colorband_table_RGBA(&ramp, &colors, &col_size); + BKE_colorband_evaluate_table_rgba(&ramp, &colors, &col_size); if (globals_ramp) { GPU_texture_free(globals_ramp); @@ -200,7 +215,7 @@ DRWShadingGroup *shgroup_instance_screenspace(DRWPass *pass, struct Gwn_Batch *g return grp; } -DRWShadingGroup *shgroup_instance_objspace_solid(DRWPass *pass, struct Gwn_Batch *geom, float (*obmat)[4]) +DRWShadingGroup *shgroup_instance_solid(DRWPass *pass, struct Gwn_Batch *geom) { static float light[3] = {0.0f, 0.0f, 1.0f}; GPUShader *sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_OBJECTSPACE_SIMPLE_LIGHTING_VARIYING_COLOR); @@ -208,20 +223,18 @@ DRWShadingGroup *shgroup_instance_objspace_solid(DRWPass *pass, struct Gwn_Batch DRWShadingGroup *grp = DRW_shgroup_instance_create(sh, pass, geom); DRW_shgroup_attrib_float(grp, "InstanceModelMatrix", 16); DRW_shgroup_attrib_float(grp, "color", 4); - DRW_shgroup_uniform_mat4(grp, "ObjectModelMatrix", (float *)obmat); DRW_shgroup_uniform_vec3(grp, "light", light, 1); return grp; } -DRWShadingGroup *shgroup_instance_objspace_wire(DRWPass *pass, struct Gwn_Batch *geom, float (*obmat)[4]) +DRWShadingGroup *shgroup_instance_wire(DRWPass *pass, struct Gwn_Batch *geom) { GPUShader *sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_OBJECTSPACE_VARIYING_COLOR); DRWShadingGroup *grp = DRW_shgroup_instance_create(sh, pass, geom); DRW_shgroup_attrib_float(grp, "InstanceModelMatrix", 16); DRW_shgroup_attrib_float(grp, "color", 4); - DRW_shgroup_uniform_mat4(grp, "ObjectModelMatrix", (float *)obmat); return grp; } @@ -308,8 +321,8 @@ DRWShadingGroup *shgroup_distance_lines_instance(DRWPass *pass, struct Gwn_Batch DRWShadingGroup *shgroup_spot_instance(DRWPass *pass, struct Gwn_Batch *geom) { GPUShader *sh_inst = GPU_shader_get_builtin_shader(GPU_SHADER_INSTANCE_EDGES_VARIYING_COLOR); - static bool True = true; - static bool False = false; + static const int True = true; + static const int False = false; DRWShadingGroup *grp = DRW_shgroup_instance_create(sh_inst, pass, geom); DRW_shgroup_attrib_float(grp, "color", 3); @@ -321,7 +334,7 @@ DRWShadingGroup *shgroup_spot_instance(DRWPass *pass, struct Gwn_Batch *geom) return grp; } -DRWShadingGroup *shgroup_instance_bone_envelope_wire(DRWPass *pass, struct Gwn_Batch *geom, float (*obmat)[4]) +DRWShadingGroup *shgroup_instance_bone_envelope_wire(DRWPass *pass, struct Gwn_Batch *geom) { GPUShader *sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_INSTANCE_BONE_ENVELOPE_WIRE); @@ -331,12 +344,11 @@ DRWShadingGroup *shgroup_instance_bone_envelope_wire(DRWPass *pass, struct Gwn_B DRW_shgroup_attrib_float(grp, "radius_head", 1); DRW_shgroup_attrib_float(grp, "radius_tail", 1); DRW_shgroup_attrib_float(grp, "distance", 1); - DRW_shgroup_uniform_mat4(grp, "ObjectModelMatrix", (float *)obmat); return grp; } -DRWShadingGroup *shgroup_instance_bone_envelope_solid(DRWPass *pass, struct Gwn_Batch *geom, float (*obmat)[4]) +DRWShadingGroup *shgroup_instance_bone_envelope_solid(DRWPass *pass, struct Gwn_Batch *geom) { static float light[3] = {0.0f, 0.0f, 1.0f}; GPUShader *sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_INSTANCE_BONE_ENVELOPE_SOLID); @@ -346,7 +358,6 @@ DRWShadingGroup *shgroup_instance_bone_envelope_solid(DRWPass *pass, struct Gwn_ DRW_shgroup_attrib_float(grp, "color", 4); DRW_shgroup_attrib_float(grp, "radius_head", 1); DRW_shgroup_attrib_float(grp, "radius_tail", 1); - DRW_shgroup_uniform_mat4(grp, "ObjectModelMatrix", (float *)obmat); DRW_shgroup_uniform_vec3(grp, "light", light, 1); return grp; diff --git a/source/blender/draw/intern/draw_common.h b/source/blender/draw/intern/draw_common.h index 0bdb79b3a40..cfd88effd15 100644 --- a/source/blender/draw/intern/draw_common.h +++ b/source/blender/draw/intern/draw_common.h @@ -72,6 +72,20 @@ typedef struct GlobalsUboStorage { float colorBackground[4]; + float colorHandleFree[4]; + float colorHandleAuto[4]; + float colorHandleVect[4]; + float colorHandleAlign[4]; + float colorHandleAutoclamp[4]; + float colorHandleSelFree[4]; + float colorHandleSelAuto[4]; + float colorHandleSelVect[4]; + float colorHandleSelAlign[4]; + float colorHandleSelAutoclamp[4]; + float colorNurbUline[4]; + float colorNurbSelUline[4]; + float colorActiveSpline[4]; + float colorGrid[4]; float colorGridEmphasise[4]; float colorGridAxisX[4]; @@ -92,8 +106,8 @@ struct DRWShadingGroup *shgroup_dynpoints_uniform_color(struct DRWPass *pass, fl struct DRWShadingGroup *shgroup_groundlines_uniform_color(struct DRWPass *pass, float color[4]); struct DRWShadingGroup *shgroup_groundpoints_uniform_color(struct DRWPass *pass, float color[4]); struct DRWShadingGroup *shgroup_instance_screenspace(struct DRWPass *pass, struct Gwn_Batch *geom, float *size); -struct DRWShadingGroup *shgroup_instance_objspace_solid(struct DRWPass *pass, struct Gwn_Batch *geom, float (*obmat)[4]); -struct DRWShadingGroup *shgroup_instance_objspace_wire(struct DRWPass *pass, struct Gwn_Batch *geom, float (*obmat)[4]); +struct DRWShadingGroup *shgroup_instance_solid(struct DRWPass *pass, struct Gwn_Batch *geom); +struct DRWShadingGroup *shgroup_instance_wire(struct DRWPass *pass, struct Gwn_Batch *geom); struct DRWShadingGroup *shgroup_instance_screen_aligned(struct DRWPass *pass, struct Gwn_Batch *geom); struct DRWShadingGroup *shgroup_instance_axis_names(struct DRWPass *pass, struct Gwn_Batch *geom); struct DRWShadingGroup *shgroup_instance_image_plane(struct DRWPass *pass, struct Gwn_Batch *geom); @@ -102,8 +116,8 @@ struct DRWShadingGroup *shgroup_instance(struct DRWPass *pass, struct Gwn_Batch struct DRWShadingGroup *shgroup_camera_instance(struct DRWPass *pass, struct Gwn_Batch *geom); struct DRWShadingGroup *shgroup_distance_lines_instance(struct DRWPass *pass, struct Gwn_Batch *geom); struct DRWShadingGroup *shgroup_spot_instance(struct DRWPass *pass, struct Gwn_Batch *geom); -struct DRWShadingGroup *shgroup_instance_bone_envelope_wire(struct DRWPass *pass, struct Gwn_Batch *geom, float (*obmat)[4]); -struct DRWShadingGroup *shgroup_instance_bone_envelope_solid(struct DRWPass *pass, struct Gwn_Batch *geom, float (*obmat)[4]); +struct DRWShadingGroup *shgroup_instance_bone_envelope_wire(struct DRWPass *pass, struct Gwn_Batch *geom); +struct DRWShadingGroup *shgroup_instance_bone_envelope_solid(struct DRWPass *pass, struct Gwn_Batch *geom); struct DRWShadingGroup *shgroup_instance_mball_helpers(struct DRWPass *pass, struct Gwn_Batch *geom); int DRW_object_wire_theme_get(struct Object *ob, struct ViewLayer *view_layer, float **r_color); diff --git a/source/blender/draw/intern/draw_instance_data.c b/source/blender/draw/intern/draw_instance_data.c new file mode 100644 index 00000000000..e7ce4374d1c --- /dev/null +++ b/source/blender/draw/intern/draw_instance_data.c @@ -0,0 +1,226 @@ +/* + * Copyright 2016, Blender Foundation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Blender Institute + * + */ + +/** \file blender/draw/intern/draw_instance_data.c + * \ingroup draw + */ + +/** + * DRW Instance Data Manager + * This is a special memory manager that keeps memory blocks ready to send as vbo data in one continuous allocation. + * This way we avoid feeding gawain each instance data one by one and unecessary memcpy. + * Since we loose which memory block was used each DRWShadingGroup we need to redistribute them in the same order/size + * to avoid to realloc each frame. + * This is why DRWInstanceDatas are sorted in a list for each different data size. + **/ + +#include "draw_instance_data.h" +#include "DRW_engine.h" + +#include "MEM_guardedalloc.h" +#include "BLI_utildefines.h" + +#define MAX_INSTANCE_DATA_SIZE 32 /* Can be adjusted for more */ + +struct DRWInstanceData { + struct DRWInstanceData *next; + bool used; /* If this data is used or not. */ + size_t chunk_size; /* Current size of the whole chunk. */ + size_t data_size; /* Size of one instance data. */ + size_t instance_group; /* How many instance to allocate at a time. */ + size_t offset; /* Offset to the next instance data. */ + float *memchunk; /* Should be float no matter what. */ +}; + +struct DRWInstanceDataList { + /* Linked lists for all possible data pool size */ + /* Not entirely sure if we should separate them in the first place. + * This is done to minimize the reattribution misses. */ + DRWInstanceData *idata_head[MAX_INSTANCE_DATA_SIZE]; + DRWInstanceData *idata_tail[MAX_INSTANCE_DATA_SIZE]; +}; + +/* -------------------------------------------------------------------- */ + +/** \name Instance Data (DRWInstanceData) + * \{ */ + +static DRWInstanceData *drw_instance_data_create( + DRWInstanceDataList *idatalist, unsigned int attrib_size, unsigned int instance_group) +{ + DRWInstanceData *idata = MEM_mallocN(sizeof(DRWInstanceData), "DRWInstanceData"); + idata->next = NULL; + idata->used = true; + idata->data_size = attrib_size; + idata->instance_group = instance_group; + idata->chunk_size = idata->data_size * instance_group; + idata->offset = 0; + idata->memchunk = MEM_mallocN(idata->chunk_size * sizeof(float), "DRWInstanceData memchunk"); + + BLI_assert(attrib_size > 0); + + /* Push to linked list. */ + if (idatalist->idata_head[attrib_size-1] == NULL) { + idatalist->idata_head[attrib_size-1] = idata; + } + else { + idatalist->idata_tail[attrib_size-1]->next = idata; + } + idatalist->idata_tail[attrib_size-1] = idata; + + return idata; +} + +static void DRW_instance_data_free(DRWInstanceData *idata) +{ + MEM_freeN(idata->memchunk); +} + +/** + * Return a pointer to the next instance data space. + * DO NOT SAVE/REUSE THIS POINTER after the next call + * to this function since the chunk may have been + * reallocated. + **/ +void *DRW_instance_data_next(DRWInstanceData *idata) +{ + idata->offset += idata->data_size; + + /* Check if chunk is large enough. realloc otherwise. */ + if (idata->offset > idata->chunk_size) { + idata->chunk_size += idata->data_size * idata->instance_group; + idata->memchunk = MEM_reallocN(idata->memchunk, idata->chunk_size * sizeof(float)); + } + + return idata->memchunk + (idata->offset - idata->data_size); +} + +void *DRW_instance_data_get(DRWInstanceData *idata) +{ + return (void *)idata->memchunk; +} + +DRWInstanceData *DRW_instance_data_request( + DRWInstanceDataList *idatalist, unsigned int attrib_size, unsigned int instance_group) +{ + BLI_assert(attrib_size > 0 && attrib_size <= MAX_INSTANCE_DATA_SIZE); + + DRWInstanceData *idata = idatalist->idata_head[attrib_size - 1]; + + /* Search for an unused data chunk. */ + for (; idata; idata = idata->next) { + if (idata->used == false) { + idata->used = true; + return idata; + } + } + + return drw_instance_data_create(idatalist, attrib_size, instance_group); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ + +/** \name Instance Data List (DRWInstanceDataList) + * \{ */ + +DRWInstanceDataList *DRW_instance_data_list_create(void) +{ + return MEM_callocN(sizeof(DRWInstanceDataList), "DRWInstanceDataList"); +} + +void DRW_instance_data_list_free(DRWInstanceDataList *idatalist) +{ + DRWInstanceData *idata, *next_idata; + + for (int i = 0; i < MAX_INSTANCE_DATA_SIZE; ++i) { + for (idata = idatalist->idata_head[i]; idata; idata = next_idata) { + next_idata = idata->next; + DRW_instance_data_free(idata); + MEM_freeN(idata); + } + idatalist->idata_head[i] = NULL; + idatalist->idata_tail[i] = NULL; + } +} + +void DRW_instance_data_list_reset(DRWInstanceDataList *idatalist) +{ + DRWInstanceData *idata; + + for (int i = 0; i < MAX_INSTANCE_DATA_SIZE; ++i) { + for (idata = idatalist->idata_head[i]; idata; idata = idata->next) { + idata->used = false; + idata->offset = 0; + } + } +} + +void DRW_instance_data_list_free_unused(DRWInstanceDataList *idatalist) +{ + DRWInstanceData *idata, *next_idata; + + /* Remove unused data blocks and sanitize each list. */ + for (int i = 0; i < MAX_INSTANCE_DATA_SIZE; ++i) { + idatalist->idata_tail[i] = NULL; + for (idata = idatalist->idata_head[i]; idata; idata = next_idata) { + next_idata = idata->next; + if (idata->used == false) { + if (idatalist->idata_head[i] == idata) { + idatalist->idata_head[i] = next_idata; + } + else { + /* idatalist->idata_tail[i] is garanteed not to be null in this case. */ + idatalist->idata_tail[i]->next = next_idata; + } + DRW_instance_data_free(idata); + MEM_freeN(idata); + } + else { + if (idatalist->idata_tail[i] != NULL) { + idatalist->idata_tail[i]->next = idata; + } + idatalist->idata_tail[i] = idata; + } + } + } +} + +void DRW_instance_data_list_resize(DRWInstanceDataList *idatalist) +{ + DRWInstanceData *idata; + + for (int i = 0; i < MAX_INSTANCE_DATA_SIZE; ++i) { + for (idata = idatalist->idata_head[i]; idata; idata = idata->next) { + /* Rounding up to nearest chunk size to compare. */ + size_t fac = idata->data_size * idata->instance_group; + size_t tmp = idata->offset + fac - 1; + size_t rounded_offset = tmp - tmp % fac; + if (rounded_offset < idata->chunk_size) { + idata->chunk_size = rounded_offset; + idata->memchunk = MEM_reallocN(idata->memchunk, idata->chunk_size * sizeof(float)); + } + } + } +} + +/** \} */ diff --git a/source/blender/draw/intern/draw_instance_data.h b/source/blender/draw/intern/draw_instance_data.h new file mode 100644 index 00000000000..637c0e3cc24 --- /dev/null +++ b/source/blender/draw/intern/draw_instance_data.h @@ -0,0 +1,41 @@ +/* + * Copyright 2016, Blender Foundation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Blender Institute + * + */ + +/** \file draw_instance_data.h + * \ingroup draw + */ + +#ifndef __DRAW_INSTANCE_DATA_H__ +#define __DRAW_INSTANCE_DATA_H__ + +typedef struct DRWInstanceData DRWInstanceData; +typedef struct DRWInstanceDataList DRWInstanceDataList; + +void *DRW_instance_data_next(DRWInstanceData *idata); +void *DRW_instance_data_get(DRWInstanceData *idata); +DRWInstanceData *DRW_instance_data_request( + DRWInstanceDataList *idatalist, unsigned int attrib_size, unsigned int instance_group); + +void DRW_instance_data_list_reset(DRWInstanceDataList *idatalist); +void DRW_instance_data_list_free_unused(DRWInstanceDataList *idatalist); +void DRW_instance_data_list_resize(DRWInstanceDataList *idatalist); + +#endif /* __DRAW_INSTANCE_DATA_H__ */ diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c index 264fc079e42..55195b88c05 100644 --- a/source/blender/draw/intern/draw_manager.c +++ b/source/blender/draw/intern/draw_manager.c @@ -25,14 +25,15 @@ #include <stdio.h> -#include "BLI_dynstr.h" #include "BLI_listbase.h" #include "BLI_mempool.h" #include "BLI_rect.h" #include "BLI_string.h" +#include "BLI_string_utils.h" #include "BIF_glutil.h" +#include "BKE_curve.h" #include "BKE_global.h" #include "BKE_mesh.h" #include "BKE_object.h" @@ -47,10 +48,12 @@ #include "DRW_render.h" #include "DNA_camera_types.h" +#include "DNA_curve_types.h" #include "DNA_view3d_types.h" #include "DNA_screen_types.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" +#include "DNA_meta_types.h" #include "ED_space_api.h" #include "ED_screen.h" @@ -85,6 +88,8 @@ /* only for callbacks */ #include "draw_cache_impl.h" +#include "draw_instance_data.h" + #include "draw_mode_engines.h" #include "engines/clay/clay_engine.h" #include "engines/eevee/eevee_engine.h" @@ -180,19 +185,8 @@ struct DRWUniform { const void *value; }; -typedef struct DRWAttrib { - struct DRWAttrib *prev; - char name[MAX_ATTRIB_NAME]; - int location; - int format_id; - int size; /* number of component */ - int type; -} DRWAttrib; - struct DRWInterface { DRWUniform *uniforms; /* DRWUniform, single-linked list */ - DRWAttrib *attribs; /* DRWAttrib, single-linked list */ - DRWAttrib *attribs_first; /* First added attrib to traverse in the right order */ int attribs_count; int attribs_stride; int attribs_size[16]; @@ -218,6 +212,12 @@ struct DRWInterface { /* Dynamic batch */ Gwn_Batch *instance_batch; /* contains instances attributes */ GLuint instance_vbo; /* same as instance_batch but generated from DRWCalls */ + struct DRWInstanceData *inst_data; +#ifdef USE_GPU_SELECT + struct DRWInstanceData *inst_selectid; + /* Override for single object instances. */ + int override_selectid; +#endif int instance_count; Gwn_VertFormat vbo_format; }; @@ -259,12 +259,6 @@ typedef struct DRWCallGenerate { void *user_data; } DRWCallGenerate; -typedef struct DRWCallDynamic { - DRWCallHeader head; - - const void *data[MAX_ATTRIB_COUNT]; -} DRWCallDynamic; - struct DRWShadingGroup { struct DRWShadingGroup *next; @@ -309,22 +303,15 @@ enum { DRW_CALL_DYNAMIC, }; -/* only 16 bits long */ -enum { - STENCIL_SELECT = (1 << 0), - STENCIL_ACTIVE = (1 << 1), -}; - /** Render State: No persistent data between draw calls. */ static struct DRWGlobalState { /* Cache generation */ ViewportMemoryPool *vmempool; DRWUniform *last_uniform; - DRWAttrib *last_attrib; DRWCall *last_call; DRWCallGenerate *last_callgenerate; - DRWCallDynamic *last_calldynamic; DRWShadingGroup *last_shgroup; + DRWInstanceDataList *idatalist; /* Rendering state */ GPUShader *shader; @@ -351,6 +338,7 @@ static struct DRWGlobalState { unsigned int is_depth : 1; unsigned int is_image_render : 1; unsigned int is_scene_render : 1; + unsigned int draw_background : 1; } options; /* Current rendering context */ @@ -409,6 +397,7 @@ static void drw_texture_get_format( case DRW_TEX_RGB_11_11_10: *r_data_type = GPU_R11F_G11F_B10F; break; case DRW_TEX_RG_8: *r_data_type = GPU_RG8; break; case DRW_TEX_RG_16: *r_data_type = GPU_RG16F; break; + case DRW_TEX_RG_16I: *r_data_type = GPU_RG16I; break; case DRW_TEX_RG_32: *r_data_type = GPU_RG32F; break; case DRW_TEX_R_8: *r_data_type = GPU_R8; break; case DRW_TEX_R_16: *r_data_type = GPU_R16F; break; @@ -442,6 +431,7 @@ static void drw_texture_get_format( break; case DRW_TEX_RG_8: case DRW_TEX_RG_16: + case DRW_TEX_RG_16I: case DRW_TEX_RG_32: *r_channels = 2; break; @@ -594,24 +584,11 @@ GPUShader *DRW_shader_create_with_lib( char *frag_with_lib = NULL; char *geom_with_lib = NULL; - DynStr *ds_vert = BLI_dynstr_new(); - BLI_dynstr_append(ds_vert, lib); - BLI_dynstr_append(ds_vert, vert); - vert_with_lib = BLI_dynstr_get_cstring(ds_vert); - BLI_dynstr_free(ds_vert); - - DynStr *ds_frag = BLI_dynstr_new(); - BLI_dynstr_append(ds_frag, lib); - BLI_dynstr_append(ds_frag, frag); - frag_with_lib = BLI_dynstr_get_cstring(ds_frag); - BLI_dynstr_free(ds_frag); + vert_with_lib = BLI_string_joinN(lib, vert); + frag_with_lib = BLI_string_joinN(lib, frag); if (geom) { - DynStr *ds_geom = BLI_dynstr_new(); - BLI_dynstr_append(ds_geom, lib); - BLI_dynstr_append(ds_geom, geom); - geom_with_lib = BLI_dynstr_get_cstring(ds_geom); - BLI_dynstr_free(ds_geom); + geom_with_lib = BLI_string_joinN(lib, geom); } sh = GPU_shader_create(vert_with_lib, frag_with_lib, geom_with_lib, NULL, defines); @@ -682,12 +659,14 @@ static void drw_interface_create(DRWInterface *interface, GPUShader *shader) interface->attribs_stride = 0; interface->instance_vbo = 0; interface->instance_batch = NULL; + interface->inst_data = NULL; + interface->uniforms = NULL; +#ifdef USE_GPU_SELECT + interface->inst_selectid = NULL; + interface->override_selectid = -1; +#endif memset(&interface->vbo_format, 0, sizeof(Gwn_VertFormat)); - - interface->uniforms = NULL; - interface->attribs = NULL; - interface->attribs_first = NULL; } @@ -725,14 +704,22 @@ static void drw_interface_uniform(DRWShadingGroup *shgroup, const char *name, shgroup->interface.uniforms = uni; } -static void drw_interface_attrib(DRWShadingGroup *shgroup, const char *name, DRWAttribType type, int size, bool dummy) +static void drw_interface_attrib(DRWShadingGroup *shgroup, const char *name, DRWAttribType UNUSED(type), int size, bool dummy) { - DRWAttrib *attrib = BLI_mempool_alloc(DST.vmempool->attribs); + unsigned int attrib_id = shgroup->interface.attribs_count; GLuint program = GPU_shader_get_program(shgroup->shader); - attrib->location = glGetAttribLocation(program, name); - attrib->type = type; - attrib->size = size; + shgroup->interface.attribs_loc[attrib_id] = glGetAttribLocation(program, name); + shgroup->interface.attribs_size[attrib_id] = size; + shgroup->interface.attribs_stride += size; + shgroup->interface.attribs_count += 1; + + if (shgroup->type != DRW_SHG_INSTANCE) { + BLI_assert(size <= 4); /* Matrices are not supported by Gawain. */ + GWN_vertformat_attr_add(&shgroup->interface.vbo_format, name, GWN_COMP_F32, size, GWN_FETCH_FLOAT); + } + + BLI_assert(shgroup->interface.attribs_count < MAX_ATTRIB_COUNT); /* Adding attribute even if not found for now (to keep memory alignment). * Should ideally take vertex format automatically from batch eventually */ @@ -747,23 +734,6 @@ static void drw_interface_attrib(DRWShadingGroup *shgroup, const char *name, DRW #else UNUSED_VARS(dummy); #endif - - BLI_assert(BLI_strnlen(name, 32) < 32); - BLI_strncpy(attrib->name, name, 32); - - shgroup->interface.attribs_count += 1; - BLI_assert(shgroup->interface.attribs_count < MAX_ATTRIB_COUNT); - - /* Prepend */ - if (shgroup->interface.attribs == NULL) { - shgroup->interface.attribs = attrib; - shgroup->interface.attribs_first = attrib; - } - else { - shgroup->interface.attribs->prev = attrib; - shgroup->interface.attribs = attrib; - } - attrib->prev = NULL; } /** \} */ @@ -847,16 +817,10 @@ DRWShadingGroup *DRW_shgroup_material_create(struct GPUMaterial *material, DRWPa else { switch (input->type) { case GPU_FLOAT: - DRW_shgroup_uniform_float(grp, input->shadername, (float *)input->dynamicvec, 1); - break; case GPU_VEC2: - DRW_shgroup_uniform_vec2(grp, input->shadername, (float *)input->dynamicvec, 1); - break; case GPU_VEC3: - DRW_shgroup_uniform_vec3(grp, input->shadername, (float *)input->dynamicvec, 1); - break; case GPU_VEC4: - DRW_shgroup_uniform_vec4(grp, input->shadername, (float *)input->dynamicvec, 1); + /* Should already be in the material ubo. */ break; case GPU_MAT3: DRW_shgroup_uniform_mat3(grp, input->shadername, (float *)input->dynamicvec); @@ -961,14 +925,6 @@ void DRW_shgroup_free(struct DRWShadingGroup *shgroup) GWN_BATCH_DISCARD_SAFE(shgroup->batch_geom); } -void DRW_shgroup_instance_batch(DRWShadingGroup *shgroup, struct Gwn_Batch *instances) -{ - BLI_assert(shgroup->type == DRW_SHG_INSTANCE); - BLI_assert(shgroup->interface.instance_batch == NULL); - - shgroup->interface.instance_batch = instances; -} - #define CALL_PREPEND(shgroup, call) { \ if (shgroup->calls == NULL) { \ shgroup->calls = call; \ @@ -981,10 +937,25 @@ void DRW_shgroup_instance_batch(DRWShadingGroup *shgroup, struct Gwn_Batch *inst call->head.prev = NULL; \ } ((void)0) +void DRW_shgroup_instance_batch(DRWShadingGroup *shgroup, struct Gwn_Batch *instances) +{ + BLI_assert(shgroup->type == DRW_SHG_INSTANCE); + BLI_assert(shgroup->interface.instance_batch == NULL); + + shgroup->interface.instance_batch = instances; + +#ifdef USE_GPU_SELECT + DRWCall *call = BLI_mempool_alloc(DST.vmempool->calls); + call->head.select_id = g_DRW_select_id; + + CALL_PREPEND(shgroup, call); +#endif +} void DRW_shgroup_call_add(DRWShadingGroup *shgroup, Gwn_Batch *geom, float (*obmat)[4]) { BLI_assert(geom != NULL); + BLI_assert(shgroup->type == DRW_SHG_NORMAL); DRWCall *call = BLI_mempool_alloc(DST.vmempool->calls); @@ -1006,6 +977,7 @@ void DRW_shgroup_call_add(DRWShadingGroup *shgroup, Gwn_Batch *geom, float (*obm void DRW_shgroup_call_object_add(DRWShadingGroup *shgroup, Gwn_Batch *geom, Object *ob) { BLI_assert(geom != NULL); + BLI_assert(shgroup->type == DRW_SHG_NORMAL); DRWCall *call = BLI_mempool_alloc(DST.vmempool->calls); @@ -1027,6 +999,7 @@ void DRW_shgroup_call_generate_add( float (*obmat)[4]) { BLI_assert(geometry_fn != NULL); + BLI_assert(shgroup->type == DRW_SHG_NORMAL); DRWCallGenerate *call = BLI_mempool_alloc(DST.vmempool->calls_generate); @@ -1070,43 +1043,30 @@ void DRW_shgroup_call_dynamic_add_array(DRWShadingGroup *shgroup, const void *at DRWInterface *interface = &shgroup->interface; #ifdef USE_GPU_SELECT - if ((G.f & G_PICKSEL) && (interface->instance_count > 0)) { - DRWShadingGroup *original_shgroup = shgroup; - shgroup = BLI_mempool_alloc(DST.vmempool->shgroups); - memcpy(shgroup, original_shgroup, sizeof(DRWShadingGroup)); - - shgroup->calls = NULL; - shgroup->calls_first = NULL; - - interface = &shgroup->interface; - interface->instance_count = 0; - - /* Append */ - if (shgroup->pass_parent->shgroups != NULL) { - shgroup->pass_parent->shgroups_last->next = shgroup; - } - else { - shgroup->pass_parent->shgroups = shgroup; + if (G.f & G_PICKSEL) { + if (interface->inst_selectid == NULL) { + interface->inst_selectid = DRW_instance_data_request(DST.idatalist, 1, 128); } - shgroup->pass_parent->shgroups_last = shgroup; - shgroup->next = NULL; + + int *select_id = DRW_instance_data_next(interface->inst_selectid); + *select_id = g_DRW_select_id; } #endif - DRWCallDynamic *call = BLI_mempool_alloc(DST.vmempool->calls_dynamic); - - CALL_PREPEND(shgroup, call); - BLI_assert(attr_len == interface->attribs_count); UNUSED_VARS_NDEBUG(attr_len); - call->head.type = DRW_CALL_DYNAMIC; -#ifdef USE_GPU_SELECT - call->head.select_id = g_DRW_select_id; -#endif + if (interface->attribs_stride > 0) { + if (interface->inst_data == NULL) { + interface->inst_data = DRW_instance_data_request(DST.idatalist, interface->attribs_stride, 16); + } + + float *data = DRW_instance_data_next(interface->inst_data); - if (interface->attribs_count != 0) { - memcpy((void *)call->data, attr, sizeof(void *) * interface->attribs_count); + for (int i = 0; i < interface->attribs_count; ++i) { + memcpy(data, attr[i], sizeof(float) * interface->attribs_size[i]); + data = data + interface->attribs_size[i]; + } } interface->instance_count += 1; @@ -1117,8 +1077,15 @@ void DRW_shgroup_set_instance_count(DRWShadingGroup *shgroup, int count) { DRWInterface *interface = &shgroup->interface; + BLI_assert(interface->instance_count == 0); BLI_assert(interface->attribs_count == 0); +#ifdef USE_GPU_SELECT + if (G.f & G_PICKSEL) { + interface->override_selectid = g_DRW_select_id; + } +#endif + interface->instance_count = count; } @@ -1161,7 +1128,7 @@ void DRW_shgroup_uniform_buffer(DRWShadingGroup *shgroup, const char *name, GPUT drw_interface_uniform(shgroup, name, DRW_UNIFORM_BUFFER, tex, 0, 1); } -void DRW_shgroup_uniform_bool(DRWShadingGroup *shgroup, const char *name, const bool *value, int arraysize) +void DRW_shgroup_uniform_bool(DRWShadingGroup *shgroup, const char *name, const int *value, int arraysize) { drw_interface_uniform(shgroup, name, DRW_UNIFORM_BOOL, value, 1, arraysize); } @@ -1234,32 +1201,13 @@ static void shgroup_dynamic_batch(DRWShadingGroup *shgroup) return; /* Upload Data */ - if (interface->vbo_format.attrib_ct == 0) { - for (DRWAttrib *attrib = interface->attribs_first; attrib; attrib = attrib->prev) { - BLI_assert(attrib->size <= 4); /* matrices have no place here for now */ - if (attrib->type == DRW_ATTRIB_FLOAT) { - attrib->format_id = GWN_vertformat_attr_add( - &interface->vbo_format, attrib->name, GWN_COMP_F32, attrib->size, GWN_FETCH_FLOAT); - } - else if (attrib->type == DRW_ATTRIB_INT) { - attrib->format_id = GWN_vertformat_attr_add( - &interface->vbo_format, attrib->name, GWN_COMP_I8, attrib->size, GWN_FETCH_INT); - } - else { - BLI_assert(false); - } - } - } - Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&interface->vbo_format); - GWN_vertbuf_data_alloc(vbo, nbr); - - int j = 0; - for (DRWCallDynamic *call = shgroup->calls_first; call; call = call->head.prev, j++) { - int i = 0; - for (DRWAttrib *attrib = interface->attribs_first; attrib; attrib = attrib->prev, i++) { - GWN_vertbuf_attr_set(vbo, attrib->format_id, j, call->data[i]); - } + if (interface->inst_data) { + GWN_vertbuf_data_set(vbo, nbr, DRW_instance_data_get(interface->inst_data), false); + } else { + /* Use unitialized memory. This is for dummy vertex buffers. */ + /* XXX TODO do not alloc at all. */ + GWN_vertbuf_data_alloc(vbo, nbr); } /* TODO make the batch dynamic instead of freeing it every times */ @@ -1271,10 +1219,9 @@ static void shgroup_dynamic_batch(DRWShadingGroup *shgroup) static void shgroup_dynamic_instance(DRWShadingGroup *shgroup) { - int i = 0; - int offset = 0; DRWInterface *interface = &shgroup->interface; int buffer_size = 0; + void *data = NULL; if (interface->instance_batch != NULL) { return; @@ -1289,26 +1236,8 @@ static void shgroup_dynamic_instance(DRWShadingGroup *shgroup) return; } - /* only once */ - if (interface->attribs_stride == 0) { - for (DRWAttrib *attrib = interface->attribs_first; attrib; attrib = attrib->prev, i++) { - BLI_assert(attrib->type == DRW_ATTRIB_FLOAT); /* Only float for now */ - interface->attribs_stride += attrib->size; - interface->attribs_size[i] = attrib->size; - interface->attribs_loc[i] = attrib->location; - } - } - /* Gather Data */ buffer_size = sizeof(float) * interface->attribs_stride * interface->instance_count; - float *data = MEM_mallocN(buffer_size, "Instance VBO data"); - - for (DRWCallDynamic *call = shgroup->calls_first; call; call = call->head.prev) { - for (int j = 0; j < interface->attribs_count; ++j) { - memcpy(data + offset, call->data[j], sizeof(float) * interface->attribs_size[j]); - offset += interface->attribs_size[j]; - } - } /* TODO poke mike to add this to gawain */ if (interface->instance_vbo) { @@ -1316,11 +1245,13 @@ static void shgroup_dynamic_instance(DRWShadingGroup *shgroup) interface->instance_vbo = 0; } + if (interface->inst_data) { + data = DRW_instance_data_get(interface->inst_data); + } + glGenBuffers(1, &interface->instance_vbo); glBindBuffer(GL_ARRAY_BUFFER, interface->instance_vbo); glBufferData(GL_ARRAY_BUFFER, buffer_size, data, GL_STATIC_DRAW); - - MEM_freeN(data); } static void shgroup_dynamic_batch_from_calls(DRWShadingGroup *shgroup) @@ -1359,6 +1290,11 @@ DRWPass *DRW_pass_create(const char *name, DRWState state) return pass; } +void DRW_pass_state_set(DRWPass *pass, DRWState state) +{ + pass->state = state; +} + void DRW_pass_free(DRWPass *pass) { for (DRWShadingGroup *shgroup = pass->shgroups; shgroup; shgroup = shgroup->next) { @@ -1597,14 +1533,16 @@ static void drw_state_set(DRWState state) { int test; if (CHANGED_ANY_STORE_VAR( - DRW_STATE_BLEND | DRW_STATE_ADDITIVE | DRW_STATE_MULTIPLY | DRW_STATE_TRANSMISSION, + DRW_STATE_BLEND | DRW_STATE_ADDITIVE | DRW_STATE_MULTIPLY | DRW_STATE_TRANSMISSION | + DRW_STATE_ADDITIVE_FULL, test)) { if (test) { glEnable(GL_BLEND); if ((state & DRW_STATE_BLEND) != 0) { - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, /* RGB */ + GL_ONE, GL_ONE_MINUS_SRC_ALPHA); /* Alpha */ } else if ((state & DRW_STATE_MULTIPLY) != 0) { glBlendFunc(GL_DST_COLOR, GL_ZERO); @@ -1613,7 +1551,13 @@ static void drw_state_set(DRWState state) glBlendFunc(GL_ONE, GL_SRC_ALPHA); } else if ((state & DRW_STATE_ADDITIVE) != 0) { - glBlendFunc(GL_SRC_ALPHA, GL_ONE); + /* Do not let alpha accumulate but premult the source RGB by it. */ + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE, /* RGB */ + GL_ZERO, GL_ONE); /* Alpha */ + } + else if ((state & DRW_STATE_ADDITIVE_FULL) != 0) { + /* Let alpha accumulate. */ + glBlendFunc(GL_ONE, GL_ONE); } else { BLI_assert(0); @@ -1839,28 +1783,37 @@ static void draw_geometry_prepare( GPU_shader_uniform_vector(shgroup->shader, interface->clipplanes, 4, DST.num_clip_planes, (float *)DST.clip_planes_eq); } -static void draw_geometry_execute(DRWShadingGroup *shgroup, Gwn_Batch *geom) +static void draw_geometry_execute_ex( + DRWShadingGroup *shgroup, Gwn_Batch *geom, unsigned int start, unsigned int count) { DRWInterface *interface = &shgroup->interface; /* step 2 : bind vertex array & draw */ GWN_batch_program_set(geom, GPU_shader_get_program(shgroup->shader), GPU_shader_get_interface(shgroup->shader)); if (interface->instance_batch) { + /* Used for Particles. Cannot do partial drawing. */ GWN_batch_draw_stupid_instanced_with_batch(geom, interface->instance_batch); } else if (interface->instance_vbo) { GWN_batch_draw_stupid_instanced( - geom, interface->instance_vbo, interface->instance_count, interface->attribs_count, + geom, interface->instance_vbo, start, count, interface->attribs_count, interface->attribs_stride, interface->attribs_size, interface->attribs_loc); } else { - GWN_batch_draw_stupid(geom); + GWN_batch_draw_stupid(geom, start, count); } /* XXX this just tells gawain we are done with the shader. * This does not unbind the shader. */ GWN_batch_program_unset(geom); } -static void draw_geometry(DRWShadingGroup *shgroup, Gwn_Batch *geom, const float (*obmat)[4], ID *ob_data) +static void draw_geometry_execute(DRWShadingGroup *shgroup, Gwn_Batch *geom) +{ + draw_geometry_execute_ex(shgroup, geom, 0, 0); +} + +static void draw_geometry( + DRWShadingGroup *shgroup, Gwn_Batch *geom, const float (*obmat)[4], ID *ob_data, + unsigned int start, unsigned int count) { float *texcoloc = NULL; float *texcosize = NULL; @@ -1870,15 +1823,31 @@ static void draw_geometry(DRWShadingGroup *shgroup, Gwn_Batch *geom, const float case ID_ME: BKE_mesh_texspace_get_reference((Mesh *)ob_data, NULL, &texcoloc, NULL, &texcosize); break; + case ID_CU: + { + Curve *cu = (Curve *)ob_data; + if (cu->bb == NULL || (cu->bb->flag & BOUNDBOX_DIRTY)) { + BKE_curve_texspace_calc(cu); + } + texcoloc = cu->loc; + texcosize = cu->size; + break; + } + case ID_MB: + { + MetaBall *mb = (MetaBall *)ob_data; + texcoloc = mb->loc; + texcosize = mb->size; + break; + } default: - /* TODO, curve, metaball? */ break; } } draw_geometry_prepare(shgroup, obmat, texcoloc, texcosize); - draw_geometry_execute(shgroup, geom); + draw_geometry_execute_ex(shgroup, geom, start, count); } static void bind_texture(GPUTexture *tex) @@ -2012,15 +1981,39 @@ static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state) GPU_select_load_id((_call)->head.select_id); \ } ((void)0) -# define GPU_SELECT_LOAD_IF_PICKSEL_LIST(_call_last, _call_first) \ - if ((G.f & G_PICKSEL) && _call_first) { \ - BLI_assert(_call_first && (_call_first == _call_last)); \ - GPU_select_load_id(((DRWCall *)_call_first)->head.select_id); \ - } ((void)0) +# define GPU_SELECT_LOAD_IF_PICKSEL_LIST(_shgroup, _start, _count) \ + _start = 0; \ + _count = _shgroup->interface.instance_count; \ + int *select_id = NULL; \ + if (G.f & G_PICKSEL) { \ + if (_shgroup->interface.override_selectid == -1) { \ + select_id = DRW_instance_data_get(_shgroup->interface.inst_selectid); \ + switch (_shgroup->type) { \ + case DRW_SHG_TRIANGLE_BATCH: _count = 3; break; \ + case DRW_SHG_LINE_BATCH: _count = 2; break; \ + default: _count = 1; break; \ + } \ + } \ + else { \ + GPU_select_load_id(_shgroup->interface.override_selectid); \ + } \ + } \ + while (_start < _shgroup->interface.instance_count) { \ + if (select_id) { \ + GPU_select_load_id(select_id[_start]); \ + } + +# define GPU_SELECT_LOAD_IF_PICKSEL_LIST_END(_start, _count) \ + _start += _count; \ + } #else # define GPU_SELECT_LOAD_IF_PICKSEL(call) -# define GPU_SELECT_LOAD_IF_PICKSEL_LIST(call, _call_first) +# define GPU_SELECT_LOAD_IF_PICKSEL_LIST_END(start, count) +# define GPU_SELECT_LOAD_IF_PICKSEL_LIST(_shgroup, _start, _count) \ + _start = 0; \ + _count = _shgroup->interface.instance_count; + #endif /* Rendering Calls */ @@ -2032,14 +2025,28 @@ static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state) if (shgroup->type == DRW_SHG_INSTANCE && (interface->instance_count > 0 || interface->instance_batch != NULL)) { - GPU_SELECT_LOAD_IF_PICKSEL_LIST(shgroup->calls, shgroup->calls_first); - draw_geometry(shgroup, shgroup->instance_geom, obmat, shgroup->instance_data); + if (interface->instance_batch != NULL) { + GPU_SELECT_LOAD_IF_PICKSEL((DRWCall *)shgroup->calls_first); + draw_geometry(shgroup, shgroup->instance_geom, obmat, shgroup->instance_data, 0, 0); + } + else { + unsigned int count, start; + GPU_SELECT_LOAD_IF_PICKSEL_LIST(shgroup, start, count) + { + draw_geometry(shgroup, shgroup->instance_geom, obmat, shgroup->instance_data, start, count); + } + GPU_SELECT_LOAD_IF_PICKSEL_LIST_END(start, count) + } } else { /* Some dynamic batch can have no geom (no call to aggregate) */ if (shgroup->batch_geom) { - GPU_SELECT_LOAD_IF_PICKSEL_LIST(shgroup->calls, shgroup->calls_first); - draw_geometry(shgroup, shgroup->batch_geom, obmat, NULL); + unsigned int count, start; + GPU_SELECT_LOAD_IF_PICKSEL_LIST(shgroup, start, count) + { + draw_geometry(shgroup, shgroup->batch_geom, obmat, NULL, start, count); + } + GPU_SELECT_LOAD_IF_PICKSEL_LIST_END(start, count) } } } @@ -2055,7 +2062,7 @@ static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state) GPU_SELECT_LOAD_IF_PICKSEL(call); if (call->head.type == DRW_CALL_SINGLE) { - draw_geometry(shgroup, call->geometry, call->obmat, call->ob_data); + draw_geometry(shgroup, call->geometry, call->obmat, call->ob_data, 0, 0); } else { BLI_assert(call->head.type == DRW_CALL_GENERATE); @@ -2195,9 +2202,7 @@ bool DRW_object_is_renderable(Object *ob) Scene *scene = DST.draw_ctx.scene; Object *obedit = scene->obedit; - if (!BKE_object_is_visible(ob)) { - return false; - } + BLI_assert(BKE_object_is_visible(ob, OB_VISIBILITY_CHECK_UNKNOWN_RENDER_MODE)); if (ob->type == OB_MESH) { if (ob == obedit) { @@ -2216,6 +2221,18 @@ bool DRW_object_is_renderable(Object *ob) return true; } +/** + * Return whether this object is visible depending if + * we are rendering or drawing in the viewport. + */ +bool DRW_check_object_visible_within_active_context(Object *ob) +{ + const eObjectVisibilityCheck mode = DRW_state_is_scene_render() ? + OB_VISIBILITY_CHECK_FOR_RENDER : + OB_VISIBILITY_CHECK_FOR_VIEWPORT; + return BKE_object_is_visible(ob, mode); +} + bool DRW_object_is_flat_normal(const Object *ob) { if (ob->type == OB_MESH) { @@ -2227,7 +2244,6 @@ bool DRW_object_is_flat_normal(const Object *ob) return true; } - /** * Return true if the object has its own draw mode. * Caller must check this is active */ @@ -2266,6 +2282,7 @@ static GPUTextureFormat convert_tex_format( case DRW_TEX_R_32: *r_channels = 1; return GPU_R32F; case DRW_TEX_RG_8: *r_channels = 2; return GPU_RG8; case DRW_TEX_RG_16: *r_channels = 2; return GPU_RG16F; + case DRW_TEX_RG_16I: *r_channels = 2; return GPU_RG16I; case DRW_TEX_RG_32: *r_channels = 2; return GPU_RG32F; case DRW_TEX_RGBA_8: *r_channels = 4; return GPU_RGBA8; case DRW_TEX_RGBA_16: *r_channels = 4; return GPU_RGBA16F; @@ -2281,11 +2298,17 @@ static GPUTextureFormat convert_tex_format( } } +struct GPUFrameBuffer *DRW_framebuffer_create(void) +{ + return GPU_framebuffer_create(); +} + void DRW_framebuffer_init( struct GPUFrameBuffer **fb, void *engine_type, int width, int height, DRWFboTexture textures[MAX_FBO_TEX], int textures_len) { BLI_assert(textures_len <= MAX_FBO_TEX); + BLI_assert(width > 0 && height > 0); bool create_fb = false; int color_attachment = -1; @@ -2298,6 +2321,7 @@ void DRW_framebuffer_init( for (int i = 0; i < textures_len; ++i) { int channels; bool is_depth; + bool create_tex = false; DRWFboTexture fbotex = textures[i]; bool is_temp = (fbotex.flag & DRW_TEX_TEMP) != 0; @@ -2310,16 +2334,18 @@ void DRW_framebuffer_init( *fbotex.tex = GPU_viewport_texture_pool_query( DST.viewport, engine_type, width, height, channels, gpu_format); } - else if (create_fb) { + else { *fbotex.tex = GPU_texture_create_2D_custom( width, height, channels, gpu_format, NULL, NULL); + create_tex = true; } } - if (create_fb) { - if (!is_depth) { - ++color_attachment; - } + if (!is_depth) { + ++color_attachment; + } + + if (create_fb || create_tex) { drw_texture_set_parameters(*fbotex.tex, fbotex.flag); GPU_framebuffer_texture_attach(*fb, *fbotex.tex, color_attachment, 0); } @@ -2339,7 +2365,9 @@ void DRW_framebuffer_init( } } - GPU_framebuffer_bind(DST.default_framebuffer); + if (DST.default_framebuffer != NULL) { + GPU_framebuffer_bind(DST.default_framebuffer); + } } } @@ -2387,6 +2415,14 @@ void DRW_framebuffer_read_data(int x, int y, int w, int h, int channels, int slo glReadPixels(x, y, w, h, type, GL_FLOAT, data); } +void DRW_framebuffer_read_depth(int x, int y, int w, int h, float *data) +{ + GLenum type = GL_DEPTH_COMPONENT; + + glReadBuffer(GL_COLOR_ATTACHMENT0); /* This is OK! */ + glReadPixels(x, y, w, h, type, GL_FLOAT, data); +} + void DRW_framebuffer_texture_attach(struct GPUFrameBuffer *fb, GPUTexture *tex, int slot, int mip) { GPU_framebuffer_texture_attach(fb, tex, slot, mip); @@ -2437,18 +2473,22 @@ void DRW_transform_to_display(GPUTexture *tex) bool use_ocio = false; - { + /* View transform is already applied for offscreen, don't apply again, see: T52046 */ + if (!(DST.options.is_image_render && !DST.options.is_scene_render)) { Scene *scene = DST.draw_ctx.scene; - /* View transform is already applied for offscreen, don't apply again, see: T52046 */ - ColorManagedViewSettings *view_settings = - (DST.options.is_image_render && !DST.options.is_scene_render) ? - NULL : &scene->view_settings; use_ocio = IMB_colormanagement_setup_glsl_draw_from_space( - view_settings, &scene->display_settings, NULL, dither, false); + &scene->view_settings, &scene->display_settings, NULL, dither, false); } if (!use_ocio) { - immBindBuiltinProgram(GPU_SHADER_2D_IMAGE_LINEAR_TO_SRGB); + /* View transform is already applied for offscreen, don't apply again, see: T52046 */ + if (DST.options.is_image_render && !DST.options.is_scene_render) { + immBindBuiltinProgram(GPU_SHADER_2D_IMAGE_COLOR); + immUniformColor4f(1.0f, 1.0f, 1.0f, 1.0f); + } + else { + immBindBuiltinProgram(GPU_SHADER_2D_IMAGE_LINEAR_TO_SRGB); + } immUniform1i("image", 0); } @@ -2541,12 +2581,13 @@ static void drw_viewport_cache_resize(void) if (DST.vmempool != NULL) { BLI_mempool_clear_ex(DST.vmempool->calls, BLI_mempool_count(DST.vmempool->calls)); BLI_mempool_clear_ex(DST.vmempool->calls_generate, BLI_mempool_count(DST.vmempool->calls_generate)); - BLI_mempool_clear_ex(DST.vmempool->calls_dynamic, BLI_mempool_count(DST.vmempool->calls_dynamic)); BLI_mempool_clear_ex(DST.vmempool->shgroups, BLI_mempool_count(DST.vmempool->shgroups)); BLI_mempool_clear_ex(DST.vmempool->uniforms, BLI_mempool_count(DST.vmempool->uniforms)); - BLI_mempool_clear_ex(DST.vmempool->attribs, BLI_mempool_count(DST.vmempool->attribs)); BLI_mempool_clear_ex(DST.vmempool->passes, BLI_mempool_count(DST.vmempool->passes)); } + + DRW_instance_data_list_free_unused(DST.idatalist); + DRW_instance_data_list_resize(DST.idatalist); } /* It also stores viewport variable to an immutable place: DST @@ -2575,21 +2616,18 @@ static void drw_viewport_var_init(void) if (DST.vmempool->calls_generate == NULL) { DST.vmempool->calls_generate = BLI_mempool_create(sizeof(DRWCallGenerate), 0, 512, 0); } - if (DST.vmempool->calls_dynamic == NULL) { - DST.vmempool->calls_dynamic = BLI_mempool_create(sizeof(DRWCallDynamic), 0, 512, 0); - } if (DST.vmempool->shgroups == NULL) { DST.vmempool->shgroups = BLI_mempool_create(sizeof(DRWShadingGroup), 0, 256, 0); } if (DST.vmempool->uniforms == NULL) { DST.vmempool->uniforms = BLI_mempool_create(sizeof(DRWUniform), 0, 512, 0); } - if (DST.vmempool->attribs == NULL) { - DST.vmempool->attribs = BLI_mempool_create(sizeof(DRWAttrib), 0, 256, 0); - } if (DST.vmempool->passes == NULL) { DST.vmempool->passes = BLI_mempool_create(sizeof(DRWPass), 0, 64, 0); } + + DST.idatalist = GPU_viewport_instance_data_list_get(DST.viewport); + DRW_instance_data_list_reset(DST.idatalist); } else { DST.size[0] = 0; @@ -2598,14 +2636,17 @@ static void drw_viewport_var_init(void) DST.default_framebuffer = NULL; DST.vmempool = NULL; } - /* Refresh DST.screenvecs */ - copy_v3_v3(DST.screenvecs[0], rv3d->viewinv[0]); - copy_v3_v3(DST.screenvecs[1], rv3d->viewinv[1]); - normalize_v3(DST.screenvecs[0]); - normalize_v3(DST.screenvecs[1]); - /* Refresh DST.pixelsize */ - DST.pixsize = rv3d->pixsize; + if (rv3d != NULL) { + /* Refresh DST.screenvecs */ + copy_v3_v3(DST.screenvecs[0], rv3d->viewinv[0]); + copy_v3_v3(DST.screenvecs[1], rv3d->viewinv[1]); + normalize_v3(DST.screenvecs[0]); + normalize_v3(DST.screenvecs[1]); + + /* Refresh DST.pixelsize */ + DST.pixsize = rv3d->pixsize; + } /* Reset facing */ DST.frontface = GL_CCW; @@ -2636,6 +2677,7 @@ void DRW_viewport_matrix_get(float mat[4][4], DRWViewportMatrixType type) copy_m4_m4(mat, viewport_matrix_override.mat[type]); } else { + BLI_assert(rv3d != NULL); /* Can't use this in render mode. */ switch (type) { case DRW_MAT_PERS: copy_m4_m4(mat, rv3d->persmat); @@ -2676,7 +2718,16 @@ void DRW_viewport_matrix_override_unset(DRWViewportMatrixType type) bool DRW_viewport_is_persp_get(void) { RegionView3D *rv3d = DST.draw_ctx.rv3d; - return rv3d->is_persp; + if (rv3d) { + return rv3d->is_persp; + } + else { + if (viewport_matrix_override.override[DRW_MAT_WIN]) { + return viewport_matrix_override.mat[DRW_MAT_WIN][3][3] == 0.0f; + } + } + BLI_assert(0); + return false; } DefaultFramebufferList *DRW_viewport_framebuffer_list_get(void) @@ -2737,33 +2788,40 @@ void **DRW_view_layer_engine_data_ensure(DrawEngineType *engine_type, void (*cal /** \name Objects (DRW_object) * \{ */ -void *DRW_object_engine_data_get(Object *ob, DrawEngineType *engine_type) +ObjectEngineData *DRW_object_engine_data_get(Object *ob, DrawEngineType *engine_type) { for (ObjectEngineData *oed = ob->drawdata.first; oed; oed = oed->next) { if (oed->engine_type == engine_type) { - return oed->storage; + return oed; } } return NULL; } -void **DRW_object_engine_data_ensure( - Object *ob, DrawEngineType *engine_type, void (*callback)(void *storage)) +ObjectEngineData *DRW_object_engine_data_ensure( + Object *ob, + DrawEngineType *engine_type, + size_t size, + ObjectEngineDataInitCb init_cb, + ObjectEngineDataFreeCb free_cb) { - ObjectEngineData *oed; - - for (oed = ob->drawdata.first; oed; oed = oed->next) { - if (oed->engine_type == engine_type) { - return &oed->storage; - } + BLI_assert(size >= sizeof(ObjectEngineData)); + /* Try to re-use existing data. */ + ObjectEngineData *oed = DRW_object_engine_data_get(ob, engine_type); + if (oed != NULL) { + return oed; } - - oed = MEM_callocN(sizeof(ObjectEngineData), "ObjectEngineData"); + /* Allocate new data. */ + oed = MEM_callocN(size, "ObjectEngineData"); oed->engine_type = engine_type; - oed->free = callback; + oed->free = free_cb; + /* Perform user-side initialization, if needed. */ + if (init_cb != NULL) { + init_cb(oed); + } + /* Register in the list. */ BLI_addtail(&ob->drawdata, oed); - - return &oed->storage; + return oed; } /* XXX There is definitly some overlap between this and DRW_object_engine_data_ensure. @@ -2833,6 +2891,10 @@ static void drw_engines_cache_populate(Object *ob) DrawEngineType *engine = link->data; ViewportEngineData *data = DRW_viewport_engine_data_ensure(engine); + if (engine->id_update) { + engine->id_update(data, &ob->id); + } + if (engine->cache_populate) { engine->cache_populate(data, ob); } @@ -2870,7 +2932,9 @@ static void drw_engines_draw_background(void) } /* No draw_background found, doing default background */ - DRW_draw_background(); + if (DRW_state_draw_background()) { + DRW_draw_background(); + } } static void drw_engines_draw_scene(void) @@ -3244,6 +3308,7 @@ void DRW_notify_view_update(const DRWUpdateContext *update_ctx) ARegion *ar = update_ctx->ar; View3D *v3d = update_ctx->v3d; RegionView3D *rv3d = ar->regiondata; + Depsgraph *depsgraph = update_ctx->depsgraph; Scene *scene = update_ctx->scene; ViewLayer *view_layer = update_ctx->view_layer; @@ -3257,7 +3322,8 @@ void DRW_notify_view_update(const DRWUpdateContext *update_ctx) DST.viewport = rv3d->viewport; DST.draw_ctx = (DRWContextState){ - ar, rv3d, v3d, scene, view_layer, OBACT(view_layer), engine_type, NULL, + ar, rv3d, v3d, scene, view_layer, OBACT(view_layer), engine_type, depsgraph, + NULL, }; drw_engines_enable(scene, view_layer, engine_type); @@ -3293,6 +3359,7 @@ void DRW_notify_id_update(const DRWUpdateContext *update_ctx, ID *id) ARegion *ar = update_ctx->ar; View3D *v3d = update_ctx->v3d; RegionView3D *rv3d = ar->regiondata; + Depsgraph *depsgraph = update_ctx->depsgraph; Scene *scene = update_ctx->scene; ViewLayer *view_layer = update_ctx->view_layer; if (rv3d->viewport == NULL) { @@ -3302,7 +3369,7 @@ void DRW_notify_id_update(const DRWUpdateContext *update_ctx, ID *id) memset(&DST, 0x0, sizeof(DST)); DST.viewport = rv3d->viewport; DST.draw_ctx = (DRWContextState){ - ar, rv3d, v3d, scene, view_layer, OBACT(view_layer), engine_type, NULL, + ar, rv3d, v3d, scene, view_layer, OBACT(view_layer), engine_type, depsgraph, NULL, }; drw_engines_enable(scene, view_layer, engine_type); for (LinkData *link = DST.enabled_engines.first; link; link = link->next) { @@ -3328,14 +3395,14 @@ void DRW_notify_id_update(const DRWUpdateContext *update_ctx, ID *id) * for each relevant engine / mode engine. */ void DRW_draw_view(const bContext *C) { - struct Depsgraph *graph = CTX_data_depsgraph(C); + struct Depsgraph *depsgraph = CTX_data_depsgraph(C); RenderEngineType *engine_type = CTX_data_engine_type(C); ARegion *ar = CTX_wm_region(C); View3D *v3d = CTX_wm_view3d(C); /* Reset before using it. */ memset(&DST, 0x0, sizeof(DST)); - DRW_draw_render_loop_ex(graph, engine_type, ar, v3d, C); + DRW_draw_render_loop_ex(depsgraph, engine_type, ar, v3d, C); } /** @@ -3343,13 +3410,13 @@ void DRW_draw_view(const bContext *C) * Need to reset DST before calling this function */ void DRW_draw_render_loop_ex( - struct Depsgraph *graph, + struct Depsgraph *depsgraph, RenderEngineType *engine_type, ARegion *ar, View3D *v3d, const bContext *evil_C) { - Scene *scene = DEG_get_evaluated_scene(graph); - ViewLayer *view_layer = DEG_get_evaluated_view_layer(graph); + Scene *scene = DEG_get_evaluated_scene(depsgraph); + ViewLayer *view_layer = DEG_get_evaluated_view_layer(depsgraph); RegionView3D *rv3d = ar->regiondata; DST.draw_ctx.evil_C = evil_C; @@ -3361,7 +3428,7 @@ void DRW_draw_render_loop_ex( GPU_viewport_engines_data_validate(DST.viewport, DRW_engines_get_hash()); DST.draw_ctx = (DRWContextState){ - ar, rv3d, v3d, scene, view_layer, OBACT(view_layer), engine_type, + ar, rv3d, v3d, scene, view_layer, OBACT(view_layer), engine_type, depsgraph, /* reuse if caller sets */ DST.draw_ctx.evil_C, @@ -3378,18 +3445,16 @@ void DRW_draw_render_loop_ex( /* Init engines */ drw_engines_init(); - /* TODO : tag to refresh by the deps graph */ - /* ideally only refresh when objects are added/removed */ - /* or render properties / materials change */ + /* Cache filling */ { PROFILE_START(stime); drw_engines_cache_init(); - DEG_OBJECT_ITER(graph, ob, DEG_ITER_OBJECT_FLAG_ALL); + DEG_OBJECT_ITER_FOR_RENDER_ENGINE(depsgraph, ob, DRW_iterator_mode_get()) { drw_engines_cache_populate(ob); } - DEG_OBJECT_ITER_END + DEG_OBJECT_ITER_FOR_RENDER_ENGINE_END drw_engines_cache_finish(); PROFILE_END_ACCUM(DST.cache_time, stime); @@ -3399,6 +3464,7 @@ void DRW_draw_render_loop_ex( /* Start Drawing */ DRW_state_reset(); + drw_engines_draw_background(); /* WIP, single image drawn over the camera view (replace) */ @@ -3413,10 +3479,8 @@ void DRW_draw_render_loop_ex( } } - extern void view3d_draw_bgpic_test(Scene *scene, ARegion *ar, View3D *v3d, - const bool do_foreground, const bool do_camera_frame); if (do_bg_image) { - view3d_draw_bgpic_test(scene, ar, v3d, false, true); + ED_view3d_draw_bgpic_test(scene, depsgraph, ar, v3d, false, true); } @@ -3439,16 +3503,20 @@ void DRW_draw_render_loop_ex( if (DST.draw_ctx.evil_C) { /* needed so manipulator isn't obscured */ glDisable(GL_DEPTH_TEST); - DRW_draw_manipulator(); - glEnable(GL_DEPTH_TEST); + DRW_draw_manipulator_3d(); DRW_draw_region_info(); + + /* Draw 2D after region info so we can draw on top of the camera passepartout overlay. + * 'DRW_draw_region_info' sets the projection in pixel-space. */ + DRW_draw_manipulator_2d(); + glEnable(GL_DEPTH_TEST); } DRW_stats_reset(); if (do_bg_image) { - view3d_draw_bgpic_test(scene, ar, v3d, true, true); + ED_view3d_draw_bgpic_test(scene, depsgraph, ar, v3d, true, true); } if (G.debug_value > 20) { @@ -3468,21 +3536,23 @@ void DRW_draw_render_loop_ex( } void DRW_draw_render_loop( - struct Depsgraph *graph, + struct Depsgraph *depsgraph, ARegion *ar, View3D *v3d) { /* Reset before using it. */ memset(&DST, 0x0, sizeof(DST)); - Scene *scene = DEG_get_evaluated_scene(graph); + Scene *scene = DEG_get_evaluated_scene(depsgraph); RenderEngineType *engine_type = RE_engines_find(scene->view_render.engine_id); - DRW_draw_render_loop_ex(graph, engine_type, ar, v3d, NULL); + DRW_draw_render_loop_ex(depsgraph, engine_type, ar, v3d, NULL); } +/* @viewport CAN be NULL, in this case we create one. */ void DRW_draw_render_loop_offscreen( - struct Depsgraph *graph, RenderEngineType *engine_type, - ARegion *ar, View3D *v3d, GPUOffScreen *ofs) + struct Depsgraph *depsgraph, RenderEngineType *engine_type, + ARegion *ar, View3D *v3d, const bool draw_background, GPUOffScreen *ofs, + GPUViewport *viewport) { RegionView3D *rv3d = ar->regiondata; @@ -3490,20 +3560,28 @@ void DRW_draw_render_loop_offscreen( void *backup_viewport = rv3d->viewport; { /* backup (_never_ use rv3d->viewport) */ - rv3d->viewport = GPU_viewport_create_from_offscreen(ofs); + if (viewport == NULL) { + rv3d->viewport = GPU_viewport_create_from_offscreen(ofs); + } + else { + rv3d->viewport = viewport; + } } /* Reset before using it. */ memset(&DST, 0x0, sizeof(DST)); DST.options.is_image_render = true; - DRW_draw_render_loop_ex(graph, engine_type, ar, v3d, NULL); + DST.options.draw_background = draw_background; + DRW_draw_render_loop_ex(depsgraph, engine_type, ar, v3d, NULL); /* restore */ { - /* don't free data owned by 'ofs' */ - GPU_viewport_clear_from_offscreen(rv3d->viewport); - GPU_viewport_free(rv3d->viewport); - MEM_freeN(rv3d->viewport); + if (viewport == NULL) { + /* don't free data owned by 'ofs' */ + GPU_viewport_clear_from_offscreen(rv3d->viewport); + GPU_viewport_free(rv3d->viewport); + MEM_freeN(rv3d->viewport); + } rv3d->viewport = backup_viewport; } @@ -3512,17 +3590,81 @@ void DRW_draw_render_loop_offscreen( GPU_offscreen_bind(ofs, false); } +void DRW_render_to_image(RenderEngine *re, struct Depsgraph *depsgraph) +{ + Scene *scene = DEG_get_evaluated_scene(depsgraph); + ViewLayer *view_layer = DEG_get_evaluated_view_layer(depsgraph); + RenderEngineType *engine_type = re->type; + DrawEngineType *draw_engine_type = engine_type->draw_engine; + RenderData *r = &scene->r; + + /* Reset before using it. */ + memset(&DST, 0x0, sizeof(DST)); + DST.options.is_image_render = true; + + DST.draw_ctx = (DRWContextState){ + NULL, NULL, NULL, scene, view_layer, OBACT(view_layer), engine_type, depsgraph, NULL + }; + + DST.viewport = GPU_viewport_create(); + const int size[2] = {(r->size * r->xsch) / 100, (r->size * r->ysch) / 100}; + GPU_viewport_size_set(DST.viewport, size); + + drw_viewport_var_init(); + + ViewportEngineData *data = DRW_viewport_engine_data_ensure(draw_engine_type); + + /* set default viewport */ + gpuPushAttrib(GPU_ENABLE_BIT | GPU_VIEWPORT_BIT); + glDisable(GL_SCISSOR_TEST); + glViewport(0, 0, size[0], size[1]); + + engine_type->draw_engine->render_to_image(data, re, depsgraph); + + /* TODO grease pencil */ + + GPU_viewport_free(DST.viewport); + MEM_freeN(DST.viewport); + + DRW_state_reset(); + /* FIXME GL_DEPTH_TEST is enabled by default but it seems + * to trigger some bad behaviour / artifacts if it's turned + * on at this point. */ + glDisable(GL_DEPTH_TEST); + + /* Restore Drawing area. */ + gpuPopAttrib(); + glEnable(GL_SCISSOR_TEST); + GPU_framebuffer_restore(); + +#ifdef DEBUG + /* Avoid accidental reuse. */ + memset(&DST, 0xFF, sizeof(DST)); +#endif +} + +void DRW_render_object_iter( + void *vedata, RenderEngine *engine, struct Depsgraph *depsgraph, + void (*callback)(void *vedata, Object *ob, RenderEngine *engine, struct Depsgraph *depsgraph)) +{ + DEG_OBJECT_ITER_FOR_RENDER_ENGINE(depsgraph, ob, DRW_iterator_mode_get()) + { + callback(vedata, ob, engine, depsgraph); + } + DEG_OBJECT_ITER_FOR_RENDER_ENGINE_END +} + /** * object mode select-loop, see: ED_view3d_draw_select_loop (legacy drawing). */ void DRW_draw_select_loop( - struct Depsgraph *graph, + struct Depsgraph *depsgraph, ARegion *ar, View3D *v3d, bool UNUSED(use_obedit_skip), bool UNUSED(use_nearest), const rcti *rect) { - Scene *scene = DEG_get_evaluated_scene(graph); + Scene *scene = DEG_get_evaluated_scene(depsgraph); RenderEngineType *engine_type = RE_engines_find(scene->view_render.engine_id); - ViewLayer *view_layer = DEG_get_evaluated_view_layer(graph); + ViewLayer *view_layer = DEG_get_evaluated_view_layer(depsgraph); #ifndef USE_GPU_SELECT UNUSED_VARS(vc, scene, view_layer, v3d, ar, rect); #else @@ -3573,7 +3715,7 @@ void DRW_draw_select_loop( /* Instead of 'DRW_context_state_init(C, &DST.draw_ctx)', assign from args */ DST.draw_ctx = (DRWContextState){ - ar, rv3d, v3d, scene, view_layer, OBACT(view_layer), engine_type, (bContext *)NULL, + ar, rv3d, v3d, scene, view_layer, OBACT(view_layer), engine_type, depsgraph, (bContext *)NULL, }; drw_viewport_var_init(); @@ -3584,7 +3726,7 @@ void DRW_draw_select_loop( /* Init engines */ drw_engines_init(); - /* TODO : tag to refresh by the deps graph */ + /* TODO : tag to refresh by the dependency graph */ /* ideally only refresh when objects are added/removed */ /* or render properties / materials change */ if (cache_is_dirty) { @@ -3594,7 +3736,10 @@ void DRW_draw_select_loop( drw_engines_cache_populate(scene->obedit); } else { - DEG_OBJECT_ITER(graph, ob, DEG_ITER_OBJECT_FLAG_DUPLI) + DEG_OBJECT_ITER(depsgraph, ob, DRW_iterator_mode_get(), + DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY | + DEG_ITER_OBJECT_FLAG_VISIBLE | + DEG_ITER_OBJECT_FLAG_DUPLI) { if ((ob->base_flag & BASE_SELECTABLED) != 0) { DRW_select_load_id(ob->select_color); @@ -3634,12 +3779,12 @@ void DRW_draw_select_loop( * object mode select-loop, see: ED_view3d_draw_depth_loop (legacy drawing). */ void DRW_draw_depth_loop( - Depsgraph *graph, + Depsgraph *depsgraph, ARegion *ar, View3D *v3d) { - Scene *scene = DEG_get_evaluated_scene(graph); + Scene *scene = DEG_get_evaluated_scene(depsgraph); RenderEngineType *engine_type = RE_engines_find(scene->view_render.engine_id); - ViewLayer *view_layer = DEG_get_evaluated_view_layer(graph); + ViewLayer *view_layer = DEG_get_evaluated_view_layer(depsgraph); RegionView3D *rv3d = ar->regiondata; /* backup (_never_ use rv3d->viewport) */ @@ -3669,7 +3814,7 @@ void DRW_draw_depth_loop( /* Instead of 'DRW_context_state_init(C, &DST.draw_ctx)', assign from args */ DST.draw_ctx = (DRWContextState){ - ar, rv3d, v3d, scene, view_layer, OBACT(view_layer), engine_type, (bContext *)NULL, + ar, rv3d, v3d, scene, view_layer, OBACT(view_layer), engine_type, depsgraph, (bContext *)NULL, }; drw_viewport_var_init(); @@ -3680,17 +3825,17 @@ void DRW_draw_depth_loop( /* Init engines */ drw_engines_init(); - /* TODO : tag to refresh by the deps graph */ + /* TODO : tag to refresh by the dependency graph */ /* ideally only refresh when objects are added/removed */ /* or render properties / materials change */ if (cache_is_dirty) { drw_engines_cache_init(); - DEG_OBJECT_ITER(graph, ob, DEG_ITER_OBJECT_FLAG_ALL) + DEG_OBJECT_ITER_FOR_RENDER_ENGINE(depsgraph, ob, DRW_iterator_mode_get()) { drw_engines_cache_populate(ob); } - DEG_OBJECT_ITER_END + DEG_OBJECT_ITER_FOR_RENDER_ENGINE_END drw_engines_cache_finish(); } @@ -3736,7 +3881,7 @@ void DRW_state_dfdy_factors_get(float dfdyfac[2]) */ bool DRW_state_is_fbo(void) { - return (DST.default_framebuffer != NULL); + return ((DST.default_framebuffer != NULL) || DST.options.is_image_render); } /** @@ -3772,6 +3917,15 @@ bool DRW_state_is_scene_render(void) } /** + * Gives you the iterator mode to use for depsgraph. + */ +eDepsObjectIteratorMode DRW_iterator_mode_get(void) +{ + return DRW_state_is_scene_render() ? DEG_ITER_OBJECT_MODE_RENDER : + DEG_ITER_OBJECT_MODE_VIEWPORT; +} + +/** * Should text draw in this mode? */ bool DRW_state_show_text(void) @@ -3793,6 +3947,17 @@ bool DRW_state_draw_support(void) ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0); } +/** + * Whether we should render the background + */ +bool DRW_state_draw_background(void) +{ + if (DRW_state_is_image_render() == false) { + return true; + } + return DST.options.draw_background; +} + /** \} */ @@ -3814,6 +3979,11 @@ const DRWContextState *DRW_context_state_get(void) /** \name Init/Exit (DRW_engines) * \{ */ +bool DRW_engine_render_support(DrawEngineType *draw_engine_type) +{ + return draw_engine_type->render_to_image; +} + void DRW_engine_register(DrawEngineType *draw_engine_type) { BLI_addtail(&DRW_engines, draw_engine_type); diff --git a/source/blender/draw/intern/draw_view.c b/source/blender/draw/intern/draw_view.c index 474d6ac8769..391c29e511f 100644 --- a/source/blender/draw/intern/draw_view.c +++ b/source/blender/draw/intern/draw_view.c @@ -715,16 +715,13 @@ void DRW_draw_cursor(void) /* **************************** 3D Manipulator ******************************** */ -void DRW_draw_manipulator(void) +void DRW_draw_manipulator_3d(void) { const DRWContextState *draw_ctx = DRW_context_state_get(); View3D *v3d = draw_ctx->v3d; v3d->zbuf = false; ARegion *ar = draw_ctx->ar; - - /* TODO, only draws 3D manipulators right now, need to see how 2D drawing will work in new viewport */ - /* draw depth culled manipulators - manipulators need to be updated *after* view matrix was set up */ /* TODO depth culling manipulators is not yet supported, just drawing _3D here, should * later become _IN_SCENE (and draw _3D separate) */ @@ -732,25 +729,18 @@ void DRW_draw_manipulator(void) ar->manipulator_map, draw_ctx->evil_C, WM_MANIPULATORMAP_DRAWSTEP_3D); - /* We may want to split this into a separate pass. - * or maintain a stage in the draw manager where all pixel-space drawing happens. */ - { - float original_proj[4][4]; - gpuGetProjectionMatrix(original_proj); - wmOrtho2_region_pixelspace(ar); - - gpuPushMatrix(); - gpuLoadIdentity(); - - glDepthMask(GL_FALSE); +} - WM_manipulatormap_draw( - ar->manipulator_map, draw_ctx->evil_C, - WM_MANIPULATORMAP_DRAWSTEP_2D); +void DRW_draw_manipulator_2d(void) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + View3D *v3d = draw_ctx->v3d; + v3d->zbuf = false; + ARegion *ar = draw_ctx->ar; - glDepthMask(GL_TRUE); + WM_manipulatormap_draw( + ar->manipulator_map, draw_ctx->evil_C, + WM_MANIPULATORMAP_DRAWSTEP_2D); - gpuPopMatrix(); - gpuLoadProjectionMatrix(original_proj); - } + glDepthMask(GL_TRUE); } diff --git a/source/blender/draw/intern/draw_view.h b/source/blender/draw/intern/draw_view.h index b400ceeffa2..203420483a7 100644 --- a/source/blender/draw/intern/draw_view.h +++ b/source/blender/draw/intern/draw_view.h @@ -30,6 +30,7 @@ void DRW_draw_grid(void); void DRW_draw_region_info(void); void DRW_draw_background(void); void DRW_draw_cursor(void); -void DRW_draw_manipulator(void); +void DRW_draw_manipulator_3d(void); +void DRW_draw_manipulator_2d(void); -#endif /* __DRAW_VIEW_H__ */
\ No newline at end of file +#endif /* __DRAW_VIEW_H__ */ diff --git a/source/blender/draw/modes/edit_armature_mode.c b/source/blender/draw/modes/edit_armature_mode.c index 4deb4f86692..3c0c33b1daa 100644 --- a/source/blender/draw/modes/edit_armature_mode.c +++ b/source/blender/draw/modes/edit_armature_mode.c @@ -154,4 +154,5 @@ DrawEngineType draw_engine_edit_armature_type = { NULL, &EDIT_ARMATURE_draw_scene, NULL, + NULL, }; diff --git a/source/blender/draw/modes/edit_curve_mode.c b/source/blender/draw/modes/edit_curve_mode.c index 1ecf1a60a35..54a1bd79572 100644 --- a/source/blender/draw/modes/edit_curve_mode.c +++ b/source/blender/draw/modes/edit_curve_mode.c @@ -45,10 +45,12 @@ extern struct GlobalsUboStorage ts; /* draw_common.c */ extern char datatoc_common_globals_lib_glsl[]; extern char datatoc_edit_curve_overlay_loosevert_vert_glsl[]; extern char datatoc_edit_curve_overlay_frag_glsl[]; +extern char datatoc_edit_curve_overlay_handle_geom_glsl[]; extern char datatoc_gpu_shader_3D_vert_glsl[]; extern char datatoc_gpu_shader_uniform_color_frag_glsl[]; extern char datatoc_gpu_shader_point_uniform_color_frag_glsl[]; +extern char datatoc_gpu_shader_flat_color_frag_glsl[]; /* *********** LISTS *********** */ /* All lists are per viewport specific datas. @@ -158,7 +160,11 @@ static void EDIT_CURVE_engine_init(void *vedata) } if (!e_data.overlay_edge_sh) { - e_data.overlay_edge_sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_UNIFORM_COLOR); + e_data.overlay_edge_sh = DRW_shader_create_with_lib( + datatoc_edit_curve_overlay_loosevert_vert_glsl, + datatoc_edit_curve_overlay_handle_geom_glsl, + datatoc_gpu_shader_flat_color_frag_glsl, + datatoc_common_globals_lib_glsl, NULL); } if (!e_data.overlay_vert_sh) { @@ -182,27 +188,36 @@ static void EDIT_CURVE_cache_init(void *vedata) } { + DRWShadingGroup *grp; + /* Center-Line (wire) */ psl->wire_pass = DRW_pass_create( "Curve Wire", DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS | DRW_STATE_WIRE); - stl->g_data->wire_shgrp = DRW_shgroup_create(e_data.wire_sh, psl->wire_pass); + + grp = DRW_shgroup_create(e_data.wire_sh, psl->wire_pass); + DRW_shgroup_uniform_vec4(grp, "color", ts.colorWireEdit, 1); + stl->g_data->wire_shgrp = grp; - /* TODO: following handle theme colors, - * For now use overlay vert shader for handles (we want them colored): - * TH_NURB_ULINE, TH_NURB_SEL_ULINE, TH_HANDLE_* */ psl->overlay_edge_pass = DRW_pass_create( "Curve Handle Overlay", DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_WIRE); - /* TODO: following handle theme colors, - * For now use overlay vert shader for handles (we want them colored) */ - stl->g_data->overlay_edge_shgrp = DRW_shgroup_create(e_data.overlay_vert_sh, psl->overlay_edge_pass); + + grp = DRW_shgroup_create(e_data.overlay_edge_sh, psl->overlay_edge_pass); + DRW_shgroup_uniform_block(grp, "globalsBlock", globals_ubo); + DRW_shgroup_uniform_vec2(grp, "viewportSize", DRW_viewport_size_get(), 1); + stl->g_data->overlay_edge_shgrp = grp; + psl->overlay_vert_pass = DRW_pass_create( "Curve Vert Overlay", DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_POINT); - stl->g_data->overlay_vert_shgrp = DRW_shgroup_create(e_data.overlay_vert_sh, psl->overlay_vert_pass); + + grp = DRW_shgroup_create(e_data.overlay_vert_sh, psl->overlay_vert_pass); + DRW_shgroup_uniform_block(grp, "globalsBlock", globals_ubo); + DRW_shgroup_uniform_vec2(grp, "viewportSize", DRW_viewport_size_get(), 1); + stl->g_data->overlay_vert_shgrp = grp; } } @@ -293,7 +308,8 @@ static void EDIT_CURVE_draw_scene(void *vedata) * Mostly used for freeing shaders */ static void EDIT_CURVE_engine_free(void) { - // DRW_SHADER_FREE_SAFE(custom_shader); + DRW_SHADER_FREE_SAFE(e_data.overlay_edge_sh); + DRW_SHADER_FREE_SAFE(e_data.overlay_vert_sh); } /* Create collection settings here. @@ -331,4 +347,5 @@ DrawEngineType draw_engine_edit_curve_type = { NULL, /* draw_background but not needed by mode engines */ &EDIT_CURVE_draw_scene, NULL, + NULL, }; diff --git a/source/blender/draw/modes/edit_lattice_mode.c b/source/blender/draw/modes/edit_lattice_mode.c index ff4c557326e..e676677ff97 100644 --- a/source/blender/draw/modes/edit_lattice_mode.c +++ b/source/blender/draw/modes/edit_lattice_mode.c @@ -294,4 +294,5 @@ DrawEngineType draw_engine_edit_lattice_type = { NULL, /* draw_background but not needed by mode engines */ &EDIT_LATTICE_draw_scene, NULL, + NULL, }; diff --git a/source/blender/draw/modes/edit_mesh_mode.c b/source/blender/draw/modes/edit_mesh_mode.c index 1a8c03e3933..29ba658f79d 100644 --- a/source/blender/draw/modes/edit_mesh_mode.c +++ b/source/blender/draw/modes/edit_mesh_mode.c @@ -610,4 +610,5 @@ DrawEngineType draw_engine_edit_mesh_type = { NULL, &EDIT_MESH_draw_scene, NULL, + NULL, }; diff --git a/source/blender/draw/modes/edit_metaball_mode.c b/source/blender/draw/modes/edit_metaball_mode.c index a83f5ae33bc..78ceaf8b6f1 100644 --- a/source/blender/draw/modes/edit_metaball_mode.c +++ b/source/blender/draw/modes/edit_metaball_mode.c @@ -248,4 +248,5 @@ DrawEngineType draw_engine_edit_metaball_type = { NULL, /* draw_background but not needed by mode engines */ &EDIT_METABALL_draw_scene, NULL, + NULL, }; diff --git a/source/blender/draw/modes/edit_surface_mode.c b/source/blender/draw/modes/edit_surface_mode.c index 4e60c4abff5..8f0371925db 100644 --- a/source/blender/draw/modes/edit_surface_mode.c +++ b/source/blender/draw/modes/edit_surface_mode.c @@ -266,4 +266,5 @@ DrawEngineType draw_engine_edit_surface_type = { NULL, /* draw_background but not needed by mode engines */ &EDIT_SURFACE_draw_scene, NULL, + NULL, }; diff --git a/source/blender/draw/modes/edit_text_mode.c b/source/blender/draw/modes/edit_text_mode.c index b375bad84b5..60f28d89f4b 100644 --- a/source/blender/draw/modes/edit_text_mode.c +++ b/source/blender/draw/modes/edit_text_mode.c @@ -309,4 +309,5 @@ DrawEngineType draw_engine_edit_text_type = { NULL, /* draw_background but not needed by mode engines */ &EDIT_TEXT_draw_scene, NULL, + NULL, }; diff --git a/source/blender/draw/modes/object_mode.c b/source/blender/draw/modes/object_mode.c index 91b64818eff..f27f41c3d2a 100644 --- a/source/blender/draw/modes/object_mode.c +++ b/source/blender/draw/modes/object_mode.c @@ -61,6 +61,8 @@ #include "draw_manager_text.h" #include "draw_common.h" +#include "DEG_depsgraph_query.h" + extern struct GPUUniformBuffer *globals_ubo; /* draw_common.c */ extern struct GPUTexture *globals_ramp; /* draw_common.c */ extern GlobalsUboStorage ts; @@ -74,11 +76,11 @@ extern char datatoc_object_empty_image_frag_glsl[]; extern char datatoc_object_empty_image_vert_glsl[]; extern char datatoc_object_lightprobe_grid_vert_glsl[]; extern char datatoc_object_particle_prim_vert_glsl[]; -extern char datatoc_object_particle_prim_frag_glsl[]; extern char datatoc_object_particle_dot_vert_glsl[]; extern char datatoc_object_particle_dot_frag_glsl[]; extern char datatoc_common_globals_lib_glsl[]; extern char datatoc_common_fxaa_lib_glsl[]; +extern char datatoc_gpu_shader_flat_color_frag_glsl[]; extern char datatoc_gpu_shader_fullscreen_vert_glsl[]; extern char datatoc_gpu_shader_uniform_color_frag_glsl[]; @@ -184,6 +186,7 @@ typedef struct OBJECT_PrivateData { /* Camera */ DRWShadingGroup *camera; + DRWShadingGroup *camera_frame; DRWShadingGroup *camera_tria; DRWShadingGroup *camera_focus; DRWShadingGroup *camera_clip; @@ -328,12 +331,12 @@ static void OBJECT_engine_init(void *vedata) if (!e_data.part_prim_sh) { e_data.part_prim_sh = DRW_shader_create( - datatoc_object_particle_prim_vert_glsl, NULL, datatoc_object_particle_prim_frag_glsl, NULL); + datatoc_object_particle_prim_vert_glsl, NULL, datatoc_gpu_shader_flat_color_frag_glsl, NULL); } if (!e_data.part_axis_sh) { e_data.part_axis_sh = DRW_shader_create( - datatoc_object_particle_prim_vert_glsl, NULL, datatoc_object_particle_prim_frag_glsl, + datatoc_object_particle_prim_vert_glsl, NULL, datatoc_gpu_shader_flat_color_frag_glsl, "#define USE_AXIS\n"); } @@ -506,8 +509,14 @@ static void OBJECT_engine_init(void *vedata) e_data.zneg_flag = e_data.zpos_flag = CLIP_ZNEG | CLIP_ZPOS; } - float dist = (rv3d->persp == RV3D_CAMOB && v3d->camera) - ? ((Camera *)v3d->camera)->clipend : v3d->far; + float dist; + if (rv3d->persp == RV3D_CAMOB && v3d->camera) { + Object *camera_object = DEG_get_evaluated_object(draw_ctx->depsgraph, v3d->camera); + dist = ((Camera *)camera_object)->clipend; + } + else { + dist = v3d->far; + } e_data.grid_settings[0] = dist / 2.0f; /* gridDistance */ e_data.grid_settings[1] = grid_res; /* gridResolution */ @@ -749,8 +758,9 @@ static void OBJECT_cache_init(void *vedata) DRWState state = DRW_STATE_WRITE_COLOR; struct Gwn_Batch *quad = DRW_cache_fullscreen_quad_get(); static float alphaOcclu = 0.35f; - static bool bTrue = true; - static bool bFalse = false; + /* Reminder : bool uniforms need to be 4 bytes. */ + static const int bTrue = true; + static const int bFalse = false; psl->outlines_search = DRW_pass_create("Outlines Detect Pass", state); @@ -920,6 +930,9 @@ static void OBJECT_cache_init(void *vedata) geom = DRW_cache_camera_get(); stl->g_data->camera = shgroup_camera_instance(psl->non_meshes, geom); + geom = DRW_cache_camera_frame_get(); + stl->g_data->camera_frame = shgroup_camera_instance(psl->non_meshes, geom); + geom = DRW_cache_camera_tria_get(); stl->g_data->camera_tria = shgroup_camera_instance(psl->non_meshes, geom); @@ -977,6 +990,7 @@ static void OBJECT_cache_init(void *vedata) geom = DRW_cache_lamp_get(); stl->g_data->lamp_circle = shgroup_instance_screenspace(psl->non_meshes, geom, &ts.sizeLampCircle); + geom = DRW_cache_lamp_shadows_get(); stl->g_data->lamp_circle_shadow = shgroup_instance_screenspace(psl->non_meshes, geom, &ts.sizeLampCircleShadow); geom = DRW_cache_lamp_sunrays_get(); @@ -1110,15 +1124,22 @@ static void DRW_shgroup_lamp(OBJECT_StorageList *stl, Object *ob, ViewLayer *vie int theme_id = DRW_object_wire_theme_get(ob, view_layer, &color); static float zero = 0.0f; - float **la_mats = (float **)DRW_object_engine_data_ensure(ob, &draw_engine_object_type, NULL); - if (*la_mats == NULL) { - /* we need 2 matrices */ - *la_mats = MEM_mallocN(sizeof(float) * 16 * 2, "Lamp Object Mode Matrices"); - } + typedef struct LampEngineData { + ObjectEngineData engine_data; + float shape_mat[4][4]; + float spot_blend_mat[4][4]; + } LampEngineData; + + LampEngineData *lamp_engine_data = + (LampEngineData *)DRW_object_engine_data_ensure( + ob, + &draw_engine_object_type, + sizeof(LampEngineData), + NULL, + NULL); - float (*shapemat)[4], (*spotblendmat)[4]; - shapemat = (float (*)[4])(*la_mats); - spotblendmat = (float (*)[4])(*la_mats + 16); + float (*shapemat)[4] = lamp_engine_data->shape_mat; + float (*spotblendmat)[4] = lamp_engine_data->spot_blend_mat; /* Don't draw the center if it's selected or active */ if (theme_id == TH_GROUP) @@ -1213,9 +1234,11 @@ static void DRW_shgroup_camera(OBJECT_StorageList *stl, Object *ob, ViewLayer *v const DRWContextState *draw_ctx = DRW_context_state_get(); View3D *v3d = draw_ctx->v3d; Scene *scene = draw_ctx->scene; + RegionView3D *rv3d = draw_ctx->rv3d; Camera *cam = ob->data; const bool is_active = (ob == v3d->camera); + const bool look_through = (is_active && (rv3d->persp == RV3D_CAMOB)); float *color; DRW_object_wire_theme_get(ob, view_layer, &color); @@ -1228,7 +1251,7 @@ static void DRW_shgroup_camera(OBJECT_StorageList *stl, Object *ob, ViewLayer *v BKE_camera_view_frame_ex(scene, cam, cam->drawsize, false, scale, asp, shift, &drawsize, vec); - // /* Frame coords */ + /* Frame coords */ copy_v2_v2(cam->drwcorners[0], vec[0]); copy_v2_v2(cam->drwcorners[1], vec[1]); copy_v2_v2(cam->drwcorners[2], vec[2]); @@ -1243,13 +1266,23 @@ static void DRW_shgroup_camera(OBJECT_StorageList *stl, Object *ob, ViewLayer *v cam->drwtria[1][0] = shift[0]; cam->drwtria[1][1] = shift[1] + ((1.1f * drawsize * (asp[1] + 0.7f)) * scale[1]); - DRW_shgroup_call_dynamic_add(stl->g_data->camera, color, cam->drwcorners, &cam->drwdepth, cam->drwtria, ob->obmat); - - /* Active cam */ - if (is_active) { + if (look_through) { + /* Only draw the frame. */ + DRW_shgroup_call_dynamic_add( + stl->g_data->camera_frame, color, cam->drwcorners, + &cam->drwdepth, cam->drwtria, ob->obmat); + } + else { DRW_shgroup_call_dynamic_add( - stl->g_data->camera_tria, color, - cam->drwcorners, &cam->drwdepth, cam->drwtria, ob->obmat); + stl->g_data->camera, color, cam->drwcorners, + &cam->drwdepth, cam->drwtria, ob->obmat); + + /* Active cam */ + if (is_active) { + DRW_shgroup_call_dynamic_add( + stl->g_data->camera_tria, color, + cam->drwcorners, &cam->drwdepth, cam->drwtria, ob->obmat); + } } /* draw the rest in normalize object space */ @@ -1455,13 +1488,13 @@ static void DRW_shgroup_lightprobe(OBJECT_StorageList *stl, OBJECT_PassList *psl bool do_outlines = ((ob->base_flag & BASE_SELECTED) != 0); DRW_object_wire_theme_get(ob, view_layer, &color); - OBJECT_LightProbeEngineData *prb_data; - OBJECT_LightProbeEngineData **prb_data_pt = (OBJECT_LightProbeEngineData **)DRW_object_engine_data_ensure(ob, &draw_engine_object_type, NULL); - if (*prb_data_pt == NULL) { - *prb_data_pt = MEM_mallocN(sizeof(OBJECT_LightProbeEngineData), "Probe Clip distances Matrices"); - } - - prb_data = *prb_data_pt; + OBJECT_LightProbeEngineData *prb_data = + (OBJECT_LightProbeEngineData *)DRW_object_engine_data_ensure( + ob, + &draw_engine_object_type, + sizeof(OBJECT_LightProbeEngineData), + NULL, + NULL); if ((DRW_state_is_select() || do_outlines) && ((prb->flag & LIGHTPROBE_FLAG_SHOW_DATA) != 0)) { @@ -1499,9 +1532,6 @@ static void DRW_shgroup_lightprobe(OBJECT_StorageList *stl, OBJECT_PassList *psl sub_v3_v3(prb_data->increment_z, prb_data->corner); DRWShadingGroup *grp = DRW_shgroup_instance_create(e_data.lightprobe_grid_sh, psl->lightprobes, DRW_cache_sphere_get()); - /* Dummy call just to save select ID */ - DRW_shgroup_call_dynamic_add_empty(grp); - /* Then overide the instance count */ DRW_shgroup_set_instance_count(grp, prb->grid_resolution_x * prb->grid_resolution_y * prb->grid_resolution_z); DRW_shgroup_uniform_vec4(grp, "color", color, 1); DRW_shgroup_uniform_vec3(grp, "corner", prb_data->corner, 1); @@ -1648,7 +1678,7 @@ static void DRW_shgroup_lightprobe(OBJECT_StorageList *stl, OBJECT_PassList *psl static void DRW_shgroup_relationship_lines(OBJECT_StorageList *stl, Object *ob) { - if (ob->parent && BKE_object_is_visible(ob->parent)) { + if (ob->parent && DRW_check_object_visible_within_active_context(ob->parent)) { DRW_shgroup_call_dynamic_add(stl->g_data->relationship_lines, ob->obmat[3]); DRW_shgroup_call_dynamic_add(stl->g_data->relationship_lines, ob->parent->obmat[3]); } @@ -1763,7 +1793,12 @@ static void OBJECT_cache_populate(void *vedata, Object *ob) View3D *v3d = draw_ctx->v3d; int theme_id = TH_UNDEFINED; - if (!BKE_object_is_visible(ob)) { + /* Handle particles first in case the emitter itself shouldn't be rendered. */ + if (ob->type == OB_MESH) { + OBJECT_cache_populate_particles(ob, psl); + } + + if (DRW_check_object_visible_within_active_context(ob) == false) { return; } @@ -1804,8 +1839,6 @@ static void OBJECT_cache_populate(void *vedata, Object *ob) } } } - - OBJECT_cache_populate_particles(ob, psl); break; } case OB_SURF: @@ -2011,4 +2044,5 @@ DrawEngineType draw_engine_object_type = { NULL, &OBJECT_draw_scene, NULL, + NULL, }; diff --git a/source/blender/draw/modes/paint_texture_mode.c b/source/blender/draw/modes/paint_texture_mode.c index b49da0cba2f..2a5eabd08fa 100644 --- a/source/blender/draw/modes/paint_texture_mode.c +++ b/source/blender/draw/modes/paint_texture_mode.c @@ -414,4 +414,5 @@ DrawEngineType draw_engine_paint_texture_type = { NULL, /* draw_background but not needed by mode engines */ &PAINT_TEXTURE_draw_scene, NULL, + NULL, }; diff --git a/source/blender/draw/modes/paint_vertex_mode.c b/source/blender/draw/modes/paint_vertex_mode.c index e430fca5742..835fefdee26 100644 --- a/source/blender/draw/modes/paint_vertex_mode.c +++ b/source/blender/draw/modes/paint_vertex_mode.c @@ -213,4 +213,5 @@ DrawEngineType draw_engine_paint_vertex_type = { NULL, &PAINT_VERTEX_draw_scene, NULL, + NULL, }; diff --git a/source/blender/draw/modes/paint_weight_mode.c b/source/blender/draw/modes/paint_weight_mode.c index e139b4af97f..3cc2ad63ed4 100644 --- a/source/blender/draw/modes/paint_weight_mode.c +++ b/source/blender/draw/modes/paint_weight_mode.c @@ -251,4 +251,5 @@ DrawEngineType draw_engine_paint_weight_type = { NULL, &PAINT_WEIGHT_draw_scene, NULL, + NULL, }; diff --git a/source/blender/draw/modes/particle_mode.c b/source/blender/draw/modes/particle_mode.c index 6a3e53a72c2..0d0758971d5 100644 --- a/source/blender/draw/modes/particle_mode.c +++ b/source/blender/draw/modes/particle_mode.c @@ -261,4 +261,5 @@ DrawEngineType draw_engine_particle_type = { NULL, /* draw_background but not needed by mode engines */ &PARTICLE_draw_scene, NULL, + NULL, }; diff --git a/source/blender/draw/modes/pose_mode.c b/source/blender/draw/modes/pose_mode.c index 1c2acd56085..560773f2d05 100644 --- a/source/blender/draw/modes/pose_mode.c +++ b/source/blender/draw/modes/pose_mode.c @@ -195,4 +195,5 @@ DrawEngineType draw_engine_pose_type = { NULL, &POSE_draw_scene, NULL, + NULL, }; diff --git a/source/blender/draw/modes/sculpt_mode.c b/source/blender/draw/modes/sculpt_mode.c index d9f1f5ebe91..d8c5bae522b 100644 --- a/source/blender/draw/modes/sculpt_mode.c +++ b/source/blender/draw/modes/sculpt_mode.c @@ -302,4 +302,5 @@ DrawEngineType draw_engine_sculpt_type = { NULL, /* draw_background but not needed by mode engines */ &SCULPT_draw_scene, NULL, + NULL, }; diff --git a/source/blender/draw/modes/shaders/common_globals_lib.glsl b/source/blender/draw/modes/shaders/common_globals_lib.glsl index dc36d252926..0c14c1e7db0 100644 --- a/source/blender/draw/modes/shaders/common_globals_lib.glsl +++ b/source/blender/draw/modes/shaders/common_globals_lib.glsl @@ -37,6 +37,20 @@ layout(std140) uniform globalsBlock { vec4 colorBackground; + vec4 colorHandleFree; + vec4 colorHandleAuto; + vec4 colorHandleVect; + vec4 colorHandleAlign; + vec4 colorHandleAutoclamp; + vec4 colorHandleSelFree; + vec4 colorHandleSelAuto; + vec4 colorHandleSelVect; + vec4 colorHandleSelAlign; + vec4 colorHandleSelAutoclamp; + vec4 colorNurbUline; + vec4 colorNurbSelUline; + vec4 colorActiveSpline; + vec4 colorGrid; vec4 colorGridEmphasise; vec4 colorGridAxisX; diff --git a/source/blender/draw/modes/shaders/edit_curve_overlay_handle_geom.glsl b/source/blender/draw/modes/shaders/edit_curve_overlay_handle_geom.glsl new file mode 100644 index 00000000000..419a25f91b4 --- /dev/null +++ b/source/blender/draw/modes/shaders/edit_curve_overlay_handle_geom.glsl @@ -0,0 +1,79 @@ + +#define ACTIVE_NURB 1 << 7 /* Keep the same value of `ACTIVE_NURB` in `draw_cache_imp_curve.c` */ + +layout(lines) in; +layout(line_strip, max_vertices = 6) out; + +uniform vec2 viewportSize; + +flat in int vertFlag[]; + +flat out vec4 finalColor; + +void main() +{ + /* TODO: vertex size */ + + vec4 v1 = gl_in[0].gl_Position; + vec4 v2 = gl_in[1].gl_Position; + + int is_active_nurb = vertFlag[1] & ACTIVE_NURB; + int color_id = vertFlag[1] ^ is_active_nurb; + + if (is_active_nurb != 0) { + /* draw the outline. */ + vec2 v1_2 = v2.xy - v1.xy; + vec2 offset; + + if (abs(v1_2.x * viewportSize.x) < abs(v1_2.y * viewportSize.y)) { + offset = vec2(2.0 / viewportSize.x, 0.0); + } + else { + offset = vec2(0.0, 2.0 / viewportSize.y); + } + + finalColor = colorActiveSpline; + + gl_Position = v1; + gl_Position.xy += offset * v1.w; + EmitVertex(); + + gl_Position = v2; + gl_Position.xy += offset * v2.w; + EmitVertex(); + + EndPrimitive(); + + gl_Position = v1; + gl_Position.xy -= offset * v1.w; + EmitVertex(); + + gl_Position = v2; + gl_Position.xy -= offset * v2.w; + EmitVertex(); + + EndPrimitive(); + } + + if (color_id == 0) finalColor = colorHandleFree; + else if (color_id == 1) finalColor = colorHandleAuto; + else if (color_id == 2) finalColor = colorHandleVect; + else if (color_id == 3) finalColor = colorHandleAlign; + else if (color_id == 4) finalColor = colorHandleAutoclamp; + else if (color_id == 5) finalColor = colorHandleSelFree; + else if (color_id == 6) finalColor = colorHandleSelAuto; + else if (color_id == 7) finalColor = colorHandleSelVect; + else if (color_id == 8) finalColor = colorHandleSelAlign; + else if (color_id == 9) finalColor = colorHandleSelAutoclamp; + else if (color_id == 10) finalColor = colorNurbUline; + else if (color_id == 11) finalColor = colorNurbSelUline; + else finalColor = colorVertexSelect; + + gl_Position = v1; + EmitVertex(); + + gl_Position = v2; + EmitVertex(); + + EndPrimitive(); +} diff --git a/source/blender/draw/modes/shaders/edit_mesh_overlay_facefill_frag.glsl b/source/blender/draw/modes/shaders/edit_mesh_overlay_facefill_frag.glsl index 049333c8e4f..23b794d9b8b 100644 --- a/source/blender/draw/modes/shaders/edit_mesh_overlay_facefill_frag.glsl +++ b/source/blender/draw/modes/shaders/edit_mesh_overlay_facefill_frag.glsl @@ -10,7 +10,7 @@ flat in int faceActive; out vec4 FragColor; -const mat4 stipple_matrix = mat4( +const vec4 stipple_matrix[4] = vec4[4]( vec4(1.0, 0.0, 0.0, 0.0), vec4(0.0, 0.0, 0.0, 0.0), vec4(0.0, 0.0, 1.0, 0.0), diff --git a/source/blender/draw/modes/shaders/edit_mesh_overlay_frag.glsl b/source/blender/draw/modes/shaders/edit_mesh_overlay_frag.glsl index ed7421c1b1d..cf1051b70b3 100644 --- a/source/blender/draw/modes/shaders/edit_mesh_overlay_frag.glsl +++ b/source/blender/draw/modes/shaders/edit_mesh_overlay_frag.glsl @@ -5,12 +5,16 @@ /* This shader follows the principles of * http://developer.download.nvidia.com/SDK/10/direct3d/Source/SolidWireframe/Doc/SolidWireframe.pdf */ +/* This is not perfect. Only a subset of intel gpus are affected. + * This fix have some performance impact. + * TODO Refine the range to only affect GPUs. */ + uniform float faceAlphaMod; flat in vec3 edgesCrease; flat in vec3 edgesBweight; -flat in ivec3 flag; flat in vec4 faceColor; +flat in ivec3 flag; flat in int clipCase; #ifdef VERTEX_SELECTION in vec3 vertexColor; @@ -28,16 +32,16 @@ in float facing; * in the first 2 components of the first vec4. * This needs noperspective interpolation. * The rest is filled with vertex screen positions. - * eData1.zw actually contain v2 - * eData2.xy actually contain v1 - * eData2.zw actually contain v0 + * eData2[0] actually contain v2 + * eData2[1] actually contain v1 + * eData2[2] actually contain v0 * * - Hard case : two 2d edge corner are described by each * vec4 as origin and direction. This is constant over * the triangle and use to detect the correct case. */ -noperspective in vec4 eData1; -flat in vec4 eData2; +noperspective in vec2 eData1; +flat in vec2 eData2[3]; out vec4 FragColor; @@ -72,7 +76,7 @@ const ivec3 clipPointIdx[6] = ivec3[6]( ivec3(2, 1, 0) ); -const mat4 stipple_matrix = mat4( +const vec4 stipple_matrix[4] = vec4[4]( vec4(1.0, 0.0, 0.0, 0.0), vec4(0.0, 0.0, 0.0, 0.0), vec4(0.0, 0.0, 1.0, 0.0), @@ -107,34 +111,34 @@ void main() /* Step 1 : Computing Distances */ if (clipCase == 0) { - e.xy = eData1.xy; + e.xy = eData1; /* computing missing distance */ - vec2 dir = normalize(eData2.zw - eData2.xy); - e.z = distToEdge(eData2.zw, dir); + vec2 dir = normalize(eData2[2] - eData2[1]); + e.z = distToEdge(eData2[2], dir); - p.x = distance(eData2.zw, gl_FragCoord.xy); - p.y = distance(eData2.xy, gl_FragCoord.xy); - p.z = distance(eData1.zw, gl_FragCoord.xy); + p.x = distance(eData2[2], gl_FragCoord.xy); + p.y = distance(eData2[1], gl_FragCoord.xy); + p.z = distance(eData2[0], gl_FragCoord.xy); } else { ivec3 eidxs = clipEdgeIdx[clipCase - 1]; ivec3 pidxs = clipPointIdx[clipCase - 1]; - e[eidxs.x] = distToEdge(eData1.xy, eData1.zw); - e[eidxs.y] = distToEdge(eData2.xy, eData2.zw); + e[eidxs.x] = distToEdge(eData1, eData2[0]); + e[eidxs.y] = distToEdge(eData2[1], eData2[2]); /* Three edges visible cases */ if (clipCase == 1 || clipCase == 2 || clipCase == 4) { - e[eidxs.z] = distToEdge(eData1.xy, normalize(eData2.xy - eData1.xy)); - p[pidxs.y] = distance(eData2.xy, gl_FragCoord.xy); + e[eidxs.z] = distToEdge(eData1, normalize(eData2[1] - eData1)); + p[pidxs.y] = distance(eData2[1], gl_FragCoord.xy); } else { e[eidxs.z] = 1e10; /* off screen */ p[pidxs.y] = 1e10; /* off screen */ } - p[pidxs.x] = distance(eData1.xy, gl_FragCoord.xy); + p[pidxs.x] = distance(eData1, gl_FragCoord.xy); p[pidxs.z] = 1e10; /* off screen */ } diff --git a/source/blender/draw/modes/shaders/edit_mesh_overlay_geom_edge.glsl b/source/blender/draw/modes/shaders/edit_mesh_overlay_geom_edge.glsl index 7d71e1540d5..77bc8a25695 100644 --- a/source/blender/draw/modes/shaders/edit_mesh_overlay_geom_edge.glsl +++ b/source/blender/draw/modes/shaders/edit_mesh_overlay_geom_edge.glsl @@ -22,8 +22,8 @@ in float vFacing[]; * and does not need interpolation */ flat out vec3 edgesCrease; flat out vec3 edgesBweight; -flat out ivec3 flag; flat out vec4 faceColor; +flat out ivec3 flag; flat out int clipCase; #ifdef VERTEX_SELECTION out vec3 vertexColor; @@ -33,8 +33,8 @@ out float facing; #endif /* See fragment shader */ -noperspective out vec4 eData1; -flat out vec4 eData2; +noperspective out vec2 eData1; +flat out vec2 eData2[3]; #define VERTEX_ACTIVE (1 << 0) #define VERTEX_SELECTED (1 << 1) @@ -128,9 +128,10 @@ void main() } /* Edge / Vert data */ - eData1 = vec4(1e10); - eData2.zw = pos[0]; - eData2.xy = pos[1]; + eData1 = vec2(1e10); + eData2[0] = vec2(1e10); + eData2[2] = pos[0]; + eData2[1] = pos[1]; flag[0] = (vData[0].x << 8); flag[1] = (vData[1].x << 8); flag[2] = 0; diff --git a/source/blender/draw/modes/shaders/edit_mesh_overlay_geom_tri.glsl b/source/blender/draw/modes/shaders/edit_mesh_overlay_geom_tri.glsl index f83402e3869..d9c902697b6 100644 --- a/source/blender/draw/modes/shaders/edit_mesh_overlay_geom_tri.glsl +++ b/source/blender/draw/modes/shaders/edit_mesh_overlay_geom_tri.glsl @@ -7,6 +7,10 @@ layout(triangles) in; +/* This is not perfect. Only a subset of intel gpus are affected. + * This fix have some performance impact. + * TODO Refine the range to only affect GPUs. */ + #ifdef EDGE_FIX /* To fix the edge artifacts, we render * an outline strip around the screenspace @@ -37,8 +41,8 @@ in float vFacing[]; * and does not need interpolation */ flat out vec3 edgesCrease; flat out vec3 edgesBweight; -flat out ivec3 flag; flat out vec4 faceColor; +flat out ivec3 flag; flat out int clipCase; #ifdef VERTEX_SELECTION out vec3 vertexColor; @@ -48,9 +52,8 @@ out float facing; #endif /* See fragment shader */ -noperspective out vec4 eData1; -flat out vec4 eData2; - +noperspective out vec2 eData1; +flat out vec2 eData2[3]; #define VERTEX_ACTIVE (1 << 0) #define VERTEX_SELECTED (1 << 1) @@ -103,7 +106,7 @@ vec4 getClipData(vec2 pos[3], ivec2 vidx) return vec4(A, Adir); } -void doVertex(int v, vec4 pos) +void doVertex(int v) { #ifdef VERTEX_SELECTION vertexColor = getVertexColor(v); @@ -113,7 +116,16 @@ void doVertex(int v, vec4 pos) facing = vFacing[v]; #endif - gl_Position = pos; + gl_Position = pPos[v]; + + EmitVertex(); +} + +void doLoopStrip(int v, vec3 offset) +{ + doVertex(v); + + gl_Position.xyz += offset; EmitVertex(); } @@ -164,18 +176,19 @@ void main() if (clipCase == 0) { /* Packing screen positions and 2 distances */ - eData1 = vec4(0.0, 0.0, pos[2]); - eData2 = vec4(pos[1], pos[0]); + eData2[0] = pos[2]; + eData2[1] = pos[1]; + eData2[2] = pos[0]; /* Only pass the first 2 distances */ for (int v = 0; v < 2; ++v) { eData1[v] = dist(pos, pos[v], v); - doVertex(v, pPos[v]); + doVertex(v); eData1[v] = 0.0; } /* and the last vertex */ - doVertex(2, pPos[2]); + doVertex(2); #ifdef EDGE_FIX vec2 fixvec[6]; @@ -233,7 +246,8 @@ void main() faceColor.a = 0.0; /* we don't want other edges : make them far */ - eData1 = vec4(1e10); + eData1 = vec2(1e10); + eData2[0] = vec2(1e10); /* Start with the same last vertex to create a * degenerate triangle in order to "create" @@ -244,49 +258,49 @@ void main() int v = i % 3; /* Position of the "hidden" third vertex */ - eData1.zw = pos[vbe]; - - doVertex(v, pPos[v]); - doVertex(v, pPos[v] + vec4(fixvec[v], Z_OFFSET, 0.0)); + eData2[0] = pos[vbe]; + doLoopStrip(v, vec3(fixvec[v], Z_OFFSET)); /* Now one triangle only shade one edge * so we use the edge distance calculated * in the fragment shader, the third edge; * we do this because we need flat interp to * draw a continuous triangle strip */ - eData2.xy = pos[vaf]; - eData2.zw = pos[v]; + eData2[1] = pos[vaf]; + eData2[2] = pos[v]; flag[0] = (vData[v].x << 8); flag[1] = (vData[vaf].x << 8); flag[2] = eflag[vbe]; edgesCrease[2] = ecrease[vbe]; edgesBweight[2] = ebweight[vbe]; - doVertex(vaf, pPos[vaf]); - doVertex(vaf, pPos[vaf] + vec4(fixvecaf[v], Z_OFFSET, 0.0)); + doLoopStrip(vaf, vec3(fixvecaf[v], Z_OFFSET)); /* corner vertices should not draw edges but draw point only */ flag[2] = (vData[vbe].x << 8); #ifdef VERTEX_SELECTION - doVertex(vaf, pPos[vaf]); - doVertex(vaf, pPos[vaf] + vec4(cornervec[vaf], Z_OFFSET, 0.0)); + doLoopStrip(vaf, vec3(cornervec[vaf], Z_OFFSET)); #endif } /* finish the loop strip */ - doVertex(2, pPos[2]); - doVertex(2, pPos[2] + vec4(fixvec[2], Z_OFFSET, 0.0)); + doLoopStrip(2, vec3(fixvec[2], Z_OFFSET)); #endif } /* Harder case : compute visible edges vectors */ else { ivec4 vindices = clipPointsIdx[clipCase - 1]; - eData1 = getClipData(pos, vindices.xz); - eData2 = getClipData(pos, vindices.yw); + vec4 tmp; + tmp = getClipData(pos, vindices.xz); + eData1 = tmp.xy; + eData2[0] = tmp.zw; + tmp = getClipData(pos, vindices.yw); + eData2[1] = tmp.xy; + eData2[2] = tmp.zw; for (int v = 0; v < 3; ++v) - doVertex(v, pPos[v]); + doVertex(v); } EndPrimitive(); diff --git a/source/blender/draw/modes/shaders/edit_mesh_overlay_loosevert_vert.glsl b/source/blender/draw/modes/shaders/edit_mesh_overlay_loosevert_vert.glsl index 0a396a5325f..53e5b09cb70 100644 --- a/source/blender/draw/modes/shaders/edit_mesh_overlay_loosevert_vert.glsl +++ b/source/blender/draw/modes/shaders/edit_mesh_overlay_loosevert_vert.glsl @@ -15,16 +15,16 @@ in ivec4 data; * and does not need interpolation */ flat out vec3 edgesCrease; flat out vec3 edgesBweight; -flat out ivec3 flag; flat out vec4 faceColor; +flat out ivec3 flag; flat out int clipCase; #ifdef VERTEX_SELECTION out vec3 vertexColor; #endif /* See fragment shader */ -noperspective out vec4 eData1; -flat out vec4 eData2; +noperspective out vec2 eData1; +flat out vec2 eData2[3]; /* project to screen space */ vec2 proj(vec4 pos) @@ -48,11 +48,13 @@ void main() #endif /* only vertex position 0 is used */ - eData1 = eData2 = vec4(1e10); - eData2.zw = proj(pPos); + eData1 = vec2(1e10); + eData2[0] = vec2(1e10); + eData2[1] = vec2(1e10); + eData2[2] = proj(pPos); - flag = ivec3(0); flag[0] = (data.x << 8); + flag[1] = flag[2] = 0; gl_PointSize = sizeEdgeFix; gl_Position = pPos; diff --git a/source/blender/draw/modes/shaders/object_particle_prim_frag.glsl b/source/blender/draw/modes/shaders/object_particle_prim_frag.glsl deleted file mode 100644 index aa455a85cf0..00000000000 --- a/source/blender/draw/modes/shaders/object_particle_prim_frag.glsl +++ /dev/null @@ -1,9 +0,0 @@ - -flat in vec4 finalColor; - -out vec4 fragColor; - -void main() -{ - fragColor = finalColor; -} diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c index afbd8e5bd41..24f6a2dab2c 100644 --- a/source/blender/editors/animation/keyframing.c +++ b/source/blender/editors/animation/keyframing.c @@ -147,7 +147,7 @@ bAction *verify_adt_action(ID *id, short add) BLI_snprintf(actname, sizeof(actname), "%sAction", id->name + 2); /* create action */ - adt->action = add_empty_action(G.main, actname); + adt->action = BKE_action_add(G.main, actname); /* set ID-type from ID-block that this is going to be assigned to * so that users can't accidentally break actions by assigning them diff --git a/source/blender/editors/armature/armature_relations.c b/source/blender/editors/armature/armature_relations.c index 1d63b3aee43..de2611f7092 100644 --- a/source/blender/editors/armature/armature_relations.c +++ b/source/blender/editors/armature/armature_relations.c @@ -126,50 +126,40 @@ typedef struct tJoinArmature_AdtFixData { GHash *names_map; } tJoinArmature_AdtFixData; -/* Callback to pass to void BKE_animdata_main_cb() for fixing driver ID's to point to the new ID */ +/* Callback to pass to BKE_animdata_main_cb() for fixing driver ID's to point to the new ID */ /* FIXME: For now, we only care about drivers here. When editing rigs, it's very rare to have animation * on the rigs being edited already, so it should be safe to skip these. */ -static void joined_armature_fix_animdata_cb(ID *id, AnimData *adt, void *user_data) +static void joined_armature_fix_animdata_cb(ID *id, FCurve *fcu, void *user_data) { tJoinArmature_AdtFixData *afd = (tJoinArmature_AdtFixData *)user_data; ID *src_id = &afd->srcArm->id; ID *dst_id = &afd->tarArm->id; GHashIterator gh_iter; - FCurve *fcu; /* Fix paths - If this is the target object, it will have some "dirty" paths */ - if (id == src_id) { - /* Fix drivers */ - for (fcu = adt->drivers.first; fcu; fcu = fcu->next) { - /* skip driver if it doesn't affect the bones */ - if (strstr(fcu->rna_path, "pose.bones[") == NULL) { - continue; - } + if ((id == src_id) && strstr(fcu->rna_path, "pose.bones[")) { + GHASH_ITER(gh_iter, afd->names_map) { + const char *old_name = BLI_ghashIterator_getKey(&gh_iter); + const char *new_name = BLI_ghashIterator_getValue(&gh_iter); - // FIXME: this is too crude... it just does everything! - GHASH_ITER(gh_iter, afd->names_map) { - const char *old_name = BLI_ghashIterator_getKey(&gh_iter); - const char *new_name = BLI_ghashIterator_getValue(&gh_iter); + /* only remap if changed; this still means there will be some waste if there aren't many drivers/keys */ + if (!STREQ(old_name, new_name) && strstr(fcu->rna_path, old_name)) { + fcu->rna_path = BKE_animsys_fix_rna_path_rename(id, fcu->rna_path, "pose.bones", + old_name, new_name, 0, 0, false); - /* only remap if changed; this still means there will be some waste if there aren't many drivers/keys */ - if (!STREQ(old_name, new_name) && strstr(fcu->rna_path, old_name)) { - fcu->rna_path = BKE_animsys_fix_rna_path_rename(id, fcu->rna_path, "pose.bones", - old_name, new_name, 0, 0, false); - - /* we don't want to apply a second remapping on this driver now, - * so stop trying names, but keep fixing drivers - */ - break; - } + /* we don't want to apply a second remapping on this driver now, + * so stop trying names, but keep fixing drivers + */ + break; } } } /* Driver targets */ - for (fcu = adt->drivers.first; fcu; fcu = fcu->next) { + if (fcu->driver) { ChannelDriver *driver = fcu->driver; DriverVar *dvar; @@ -373,7 +363,7 @@ int join_armature_exec(bContext *C, wmOperator *op) } /* Fix all the drivers (and animation data) */ - BKE_animdata_main_cb(bmain, joined_armature_fix_animdata_cb, &afd); + BKE_fcurves_main_cb(bmain, joined_armature_fix_animdata_cb, &afd); BLI_ghash_free(afd.names_map, MEM_freeN, NULL); /* Only copy over animdata now, after all the remapping has been done, diff --git a/source/blender/editors/armature/editarmature_sketch.c b/source/blender/editors/armature/editarmature_sketch.c index 4dd8e4bd6fa..f4bebfd85e0 100644 --- a/source/blender/editors/armature/editarmature_sketch.c +++ b/source/blender/editors/armature/editarmature_sketch.c @@ -929,7 +929,7 @@ static void sk_interpolateDepth(bContext *C, SK_Stroke *stk, int start, int end, float pval[2] = {0, 0}; ED_view3d_project_float_global(ar, stk->points[i].p, pval, V3D_PROJ_TEST_NOP); - ED_view3d_win_to_ray(ar, v3d, pval, ray_start, ray_normal, false); + ED_view3d_win_to_ray(CTX_data_depsgraph(C), ar, v3d, pval, ray_start, ray_normal, false); mul_v3_fl(ray_normal, distance * progress / length); add_v3_v3(stk->points[i].p, ray_normal); @@ -1486,6 +1486,7 @@ static int cmpIntersections(const void *i1, const void *i2) /* returns the maximum number of intersections per stroke */ static int sk_getIntersections(bContext *C, ListBase *list, SK_Sketch *sketch, SK_Stroke *gesture) { + const Depsgraph *depsgraph = CTX_data_depsgraph(C); ARegion *ar = CTX_wm_region(C); ScrArea *sa = CTX_wm_area(C); View3D *v3d = sa->spacedata.first; @@ -1526,7 +1527,7 @@ static int sk_getIntersections(bContext *C, ListBase *list, SK_Sketch *sketch, S mval[0] = vi[0]; mval[1] = vi[1]; - ED_view3d_win_to_segment(ar, v3d, mval, ray_start, ray_end, true); + ED_view3d_win_to_segment(depsgraph, ar, v3d, mval, ray_start, ray_end, true); isect_line_line_v3(stk->points[s_i].p, stk->points[s_i + 1].p, diff --git a/source/blender/editors/armature/pose_lib.c b/source/blender/editors/armature/pose_lib.c index 0dbe3ddaa0a..d89b2fcfe84 100644 --- a/source/blender/editors/armature/pose_lib.c +++ b/source/blender/editors/armature/pose_lib.c @@ -201,7 +201,7 @@ static bAction *poselib_init_new(Object *ob) if (ob->poselib) id_us_min(&ob->poselib->id); - ob->poselib = add_empty_action(G.main, "PoseLib"); + ob->poselib = BKE_action_add(G.main, "PoseLib"); ob->poselib->idroot = ID_OB; return ob->poselib; diff --git a/source/blender/editors/armature/pose_select.c b/source/blender/editors/armature/pose_select.c index f808f09f1f4..9bc678cd9e6 100644 --- a/source/blender/editors/armature/pose_select.c +++ b/source/blender/editors/armature/pose_select.c @@ -156,7 +156,7 @@ bool ED_do_pose_selectbuffer( * always give predictable behavior in weight paint mode - campbell */ if ((ob_act == NULL) || ((ob_act != ob) && (ob_act->mode & OB_MODE_WEIGHT_PAINT) == 0)) { /* when we are entering into posemode via toggle-select, - * frop another active object - always select the bone. */ + * from another active object - always select the bone. */ if (!extend && !deselect && toggle) { /* re-select below */ nearBone->flag &= ~BONE_SELECTED; diff --git a/source/blender/editors/armature/pose_transform.c b/source/blender/editors/armature/pose_transform.c index 18d6408f026..bfe365d04fd 100644 --- a/source/blender/editors/armature/pose_transform.c +++ b/source/blender/editors/armature/pose_transform.c @@ -158,6 +158,28 @@ static int apply_armature_pose2bones_exec(bContext *C, wmOperator *op) curbone->roll = eul[1]; } + /* combine pose and rest values for bendy bone settings, + * then clear the pchan values (so we don't get a double-up) + */ + if (pchan->bone->segments > 1) { + curbone->curveInX += pchan->curveInX; + curbone->curveInY += pchan->curveInY; + curbone->curveOutX += pchan->curveOutX; + curbone->curveOutY += pchan->curveOutY; + curbone->roll1 += pchan->roll1; + curbone->roll2 += pchan->roll2; + curbone->ease1 += pchan->ease1; + curbone->ease2 += pchan->ease2; + curbone->scaleIn += pchan->scaleIn; + curbone->scaleOut += pchan->scaleOut; + + pchan->curveInX = pchan->curveOutX = 0.0f; + pchan->curveInY = pchan->curveOutY = 0.0f; + pchan->roll1 = pchan->roll2 = 0.0f; + pchan->ease1 = pchan->ease2 = 0.0f; + pchan->scaleIn = pchan->scaleOut = 1.0f; + } + /* clear transform values for pchan */ zero_v3(pchan->loc); zero_v3(pchan->eul); diff --git a/source/blender/editors/curve/curve_ops.c b/source/blender/editors/curve/curve_ops.c index 4dfd4a5c0f0..71cccdfa33d 100644 --- a/source/blender/editors/curve/curve_ops.c +++ b/source/blender/editors/curve/curve_ops.c @@ -241,6 +241,9 @@ void ED_keymap_curve(wmKeyConfig *keyconf) kmi = WM_keymap_add_item(keymap, "CURVE_OT_draw", ACTIONMOUSE, KM_PRESS, KM_SHIFT, 0); RNA_boolean_set(kmi->ptr, "wait_for_input", false); + kmi = WM_keymap_add_item(keymap, "CURVE_OT_draw", TABLET_STYLUS, KM_PRESS, KM_SHIFT, 0); + RNA_boolean_set(kmi->ptr, "wait_for_input", false); + kmi = WM_keymap_add_item(keymap, "CURVE_OT_select_all", AKEY, KM_PRESS, 0, 0); RNA_enum_set(kmi->ptr, "action", SEL_TOGGLE); kmi = WM_keymap_add_item(keymap, "CURVE_OT_select_all", IKEY, KM_PRESS, KM_CTRL, 0); diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c index 79b63f36b76..4b578ba389e 100644 --- a/source/blender/editors/curve/editcurve.c +++ b/source/blender/editors/curve/editcurve.c @@ -6135,8 +6135,10 @@ int join_curve_exec(bContext *C, wmOperator *op) cu = ob->data; BLI_movelisttolist(&cu->nurb, &tempbase); - /* Account for mixed 2D/3D curves when joining */ - BKE_curve_curve_dimension_update(cu); + if (ob->type == OB_CURVE) { + /* Account for mixed 2D/3D curves when joining */ + BKE_curve_curve_dimension_update(cu); + } DEG_relations_tag_update(bmain); // because we removed object(s), call before editmode! diff --git a/source/blender/editors/curve/editcurve_paint.c b/source/blender/editors/curve/editcurve_paint.c index 5a71cc39f80..062b9c94a1b 100644 --- a/source/blender/editors/curve/editcurve_paint.c +++ b/source/blender/editors/curve/editcurve_paint.c @@ -93,6 +93,8 @@ struct StrokeElem { }; struct CurveDrawData { + const Depsgraph *depsgraph; + short init_event_type; short curve_type; @@ -199,7 +201,7 @@ static bool stroke_elem_project( if (cdd->project.use_plane) { /* get the view vector to 'location' */ float ray_origin[3], ray_direction[3]; - ED_view3d_win_to_ray(cdd->vc.ar, v3d, mval_fl, ray_origin, ray_direction, false); + ED_view3d_win_to_ray(cdd->depsgraph, cdd->vc.ar, v3d, mval_fl, ray_origin, ray_direction, false); float lambda; if (isect_ray_plane_v3(ray_origin, ray_direction, cdd->project.plane, &lambda, true)) { @@ -603,6 +605,8 @@ static bool curve_draw_init(bContext *C, wmOperator *op, bool is_invoke) struct CurveDrawData *cdd = MEM_callocN(sizeof(*cdd), __func__); + cdd->depsgraph = CTX_data_depsgraph(C); + if (is_invoke) { view3d_set_viewcontext(C, &cdd->vc); if (ELEM(NULL, cdd->vc.ar, cdd->vc.rv3d, cdd->vc.v3d, cdd->vc.win, cdd->vc.scene)) { diff --git a/source/blender/editors/datafiles/CMakeLists.txt b/source/blender/editors/datafiles/CMakeLists.txt index 2a84ca7f297..65c55b6cd22 100644 --- a/source/blender/editors/datafiles/CMakeLists.txt +++ b/source/blender/editors/datafiles/CMakeLists.txt @@ -31,6 +31,500 @@ set(SRC ) +# Order matches "UI_icons.h", final name will be formatted: "icons{size}_{name}.dat" +set(ICON_NAMES + question + error + cancel + tria_right + tria_down + tria_left + tria_up + arrow_leftright + plus + disclosure_tri_down + disclosure_tri_right + radiobut_off + radiobut_on + menu_panel + blender + grip + dot + collapsemenu + x + go_left + plug + ui + node + node_sel + fullscreen + splitscreen + rightarrow_thin + bordermove + viewzoom + zoomin + zoomout + panel_close + copy_id + eyedropper + link_area + auto + checkbox_dehlt + checkbox_hlt + unlocked + locked + unpinned + pinned + screen_back + rightarrow + downarrow_hlt + dotsup + dotsdown + link + inlink + plugin + help + ghost_enabled + color + linked + unlinked + hand + zoom_all + zoom_selected + zoom_previous + zoom_in + zoom_out + render_region + border_rect + border_lasso + freeze + stylus_pressure + ghost_disabled + new + file_tick + quit + url + recover_last + fullscreen_enter + fullscreen_exit + lamp + material + texture + anim + world + scene + edit + game + radio + script + particles + physics + speaker + texture_shaded + view3d + ipo + oops + buts + filesel + image_col + info + sequence + text + imasel + sound + action + nla + scriptwin + time + nodetree + logic + console + preferences + clip + asset_manager + object_datamode + editmode_hlt + facesel_hlt + vpaint_hlt + tpaint_hlt + wpaint_hlt + sculptmode_hlt + pose_hlt + particlemode + lightpaint + greasepencil_stroke_paint + scene_data + renderlayers + world_data + object_data + mesh_data + curve_data + meta_data + lattice_data + lamp_data + material_data + texture_data + anim_data + camera_data + particle_data + library_data_direct + group + armature_data + pose_data + bone_data + constraint + shapekey_data + constraint_bone + camera_stereo + package + uglypackage + brush_data + image_data + file + fcurve + font_data + render_result + surface_data + empty_data + settings + render_animation + render_still + library_data_broken + boids + strands + library_data_indirect + greasepencil + line_data + library_data_override + group_bone + group_vertex + group_vcol + group_uvs + rna + rna_add + outliner_ob_empty + outliner_ob_mesh + outliner_ob_curve + outliner_ob_lattice + outliner_ob_meta + outliner_ob_lamp + outliner_ob_camera + outliner_ob_armature + outliner_ob_font + outliner_ob_surface + outliner_ob_speaker + outliner_ob_force_field + outliner_ob_group_instance + outliner_ob_greasepencil + restrict_color_off + restrict_color_on + restrict_view_off + restrict_view_on + restrict_select_off + restrict_select_on + restrict_render_off + restrict_render_on + outliner_data_empty + outliner_data_mesh + outliner_data_curve + outliner_data_lattice + outliner_data_meta + outliner_data_lamp + outliner_data_camera + outliner_data_armature + outliner_data_font + outliner_data_surface + outliner_data_speaker + outliner_data_pose + outliner_data_greasepencil + mesh_plane + mesh_cube + mesh_circle + mesh_uvsphere + mesh_icosphere + mesh_grid + mesh_monkey + mesh_cylinder + mesh_torus + mesh_cone + mesh_capsule + lamp_point + lamp_sun + lamp_spot + lamp_hemi + lamp_area + meta_empty + meta_plane + meta_cube + meta_ball + meta_ellipsoid + meta_capsule + surface_ncurve + surface_ncircle + surface_nsurface + surface_ncylinder + surface_nsphere + surface_ntorus + curve_bezcurve + curve_bezcircle + curve_ncurve + curve_ncircle + curve_path + color_red + color_green + color_blue + tria_right_bar + tria_down_bar + tria_left_bar + tria_up_bar + force_force + force_wind + force_vortex + force_magnetic + force_harmonic + force_charge + force_lennardjones + force_texture + force_curve + force_boid + force_turbulence + force_drag + force_smokeflow + node_insert_on + node_insert_off + modifier + mod_wave + mod_build + mod_decim + mod_mirror + mod_soft + mod_subsurf + hook + mod_physics + mod_particles + mod_boolean + mod_edgesplit + mod_array + mod_uvproject + mod_displace + mod_curve + mod_lattice + constraint_data + mod_armature + mod_shrinkwrap + mod_cast + mod_meshdeform + mod_bevel + mod_smooth + mod_simpledeform + mod_mask + mod_cloth + mod_explode + mod_fluidsim + mod_multires + mod_smoke + mod_solidify + mod_screw + mod_vertex_weight + mod_dynamicpaint + mod_remesh + mod_ocean + mod_warp + mod_skin + mod_triangulate + mod_wireframe + mod_data_transfer + mod_normaledit + rec + play + ff + rew + pause + prev_keyframe + next_keyframe + play_audio + play_reverse + preview_range + action_tweak + pmarker_act + pmarker_sel + pmarker + marker_hlt + marker + space2 + space3 + keyingset + key_dehlt + key_hlt + mute_ipo_off + mute_ipo_on + visible_ipo_off + visible_ipo_on + driver + solo_off + solo_on + frame_prev + frame_next + nla_pushdown + ipo_constant + ipo_linear + ipo_bezier + ipo_sine + ipo_quad + ipo_cubic + ipo_quart + ipo_quint + ipo_expo + ipo_circ + ipo_bounce + ipo_elastic + ipo_back + ipo_ease_in + ipo_ease_out + ipo_ease_in_out + normalize_fcurves + vertexsel + edgesel + facesel + loopsel + rotate + cursor + rotatecollection + rotatecenter + rotactive + align + smoothcurve + spherecurve + rootcurve + sharpcurve + lincurve + nocurve + rndcurve + prop_off + prop_on + prop_con + particle_point + particle_tip + particle_path + man_trans + man_rot + man_scale + manipul + snap_off + snap_on + snap_normal + snap_grid + snap_vertex + snap_edge + snap_face + snap_volume + snap_increment + sticky_uvs_loc + sticky_uvs_disable + sticky_uvs_vert + clipuv_dehlt + clipuv_hlt + snap_peel_object + grid + object_origin + pastedown + copydown + pasteflipup + pasteflipdown + snap_surface + automerge_on + automerge_off + retopo + uv_vertexsel + uv_edgesel + uv_facesel + uv_islandsel + uv_sync_select + bbox + wire + solid + smooth + potato + ortho + lockview_off + lockview_on + axis_side + axis_front + axis_top + ndof_dom + ndof_turn + ndof_fly + ndof_trans + layer_used + layer_active + sortalpha + sortbyext + sorttime + sortsize + longdisplay + shortdisplay + ghost + imgdisplay + save_as + save_copy + bookmarks + fontpreview + filter + newfolder + open_recent + file_parent + file_refresh + file_folder + file_blend + file_image + file_movie + file_script + file_sound + file_font + file_text + recover_auto + save_prefs + link_blend + append_blend + import + export + external_data + load_factory + loop_back + loop_forwards + back + forward + file_hidden + file_backup + disk_drive + matplane + matsphere + matcube + monkey + hair + aliased + antialiased + mat_sphere_sky + wordwrap_off + wordwrap_on + syntax_off + syntax_on + linenumbers_off + linenumbers_on + scriptplugins + seq_sequencer + seq_preview + seq_luma_waveform + seq_chroma_scope + seq_histogram + seq_splitview + image_rgb + image_rgb_alpha + image_alpha + image_zdepth + imagefile +) + data_to_c_simple(../../../../release/datafiles/bfont.pfb SRC) data_to_c_simple(../../../../release/datafiles/bfont.ttf SRC) data_to_c_simple(../../../../release/datafiles/bmonofont.ttf SRC) @@ -53,12 +547,12 @@ if(WITH_BLENDER) #../../../../release/datafiles/blender_icons16.png #90 SRC) - data_to_c_simple_icons(../../../../release/datafiles/blender_icons16 SRC) + data_to_c_simple_icons(../../../../release/datafiles/blender_icons16 "icon16_" "${ICON_NAMES}" SRC) #data_to_c_simple(../../../../release/datafiles/blender_icons16.png SRC) #svg_to_png(../../../../release/datafiles/blender_icons.svg #../../../../release/datafiles/blender_icons32.png #180 SRC) - data_to_c_simple_icons(../../../../release/datafiles/blender_icons32 SRC) + data_to_c_simple_icons(../../../../release/datafiles/blender_icons32 "icon32_" "${ICON_NAMES}" SRC) #data_to_c_simple(../../../../release/datafiles/blender_icons32.png SRC) #svg_to_png(../../../../release/datafiles/prvicons.svg #../../../../release/datafiles/prvicons.png @@ -130,4 +624,6 @@ if(WITH_BLENDER) data_to_c_simple(../../../../release/datafiles/startup.blend SRC) endif() +unset(ICON_NAMES) + blender_add_lib(bf_editor_datafiles "${SRC}" "${INC}" "${INC_SYS}") diff --git a/source/blender/editors/gpencil/drawgpencil.c b/source/blender/editors/gpencil/drawgpencil.c index 1674091f138..4a95027528b 100644 --- a/source/blender/editors/gpencil/drawgpencil.c +++ b/source/blender/editors/gpencil/drawgpencil.c @@ -1672,6 +1672,7 @@ void ED_gpencil_draw_view2d(const bContext *C, bool onlyv2d) void ED_gpencil_draw_view3d(wmWindowManager *wm, Scene *scene, ViewLayer *view_layer, + const struct Depsgraph *depsgraph, View3D *v3d, ARegion *ar, bool only3d) @@ -1688,7 +1689,7 @@ void ED_gpencil_draw_view3d(wmWindowManager *wm, * deal with the camera border, otherwise map the coords to the camera border. */ if ((rv3d->persp == RV3D_CAMOB) && !(G.f & G_RENDER_OGL)) { rctf rectf; - ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &rectf, true); /* no shift */ + ED_view3d_calc_camera_border(scene, depsgraph, ar, v3d, rv3d, &rectf, true); /* no shift */ offsx = round_fl_to_int(rectf.xmin); offsy = round_fl_to_int(rectf.ymin); diff --git a/source/blender/editors/gpencil/gpencil_convert.c b/source/blender/editors/gpencil/gpencil_convert.c index f3b12b9bc85..76fa3b3f9ea 100644 --- a/source/blender/editors/gpencil/gpencil_convert.c +++ b/source/blender/editors/gpencil/gpencil_convert.c @@ -1111,7 +1111,8 @@ static int gp_camera_view_subrect(bContext *C, rctf *subrect) /* for camera view set the subrect */ if (rv3d->persp == RV3D_CAMOB) { Scene *scene = CTX_data_scene(C); - ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, subrect, true); /* no shift */ + Depsgraph *depsgraph = CTX_data_depsgraph(C); + ED_view3d_calc_camera_border(scene, depsgraph, ar, v3d, rv3d, subrect, true); /* no shift */ return 1; } } diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c index a82148788c8..22a3224e563 100644 --- a/source/blender/editors/gpencil/gpencil_edit.c +++ b/source/blender/editors/gpencil/gpencil_edit.c @@ -105,7 +105,8 @@ static int gpencil_editmode_toggle_exec(bContext *C, wmOperator *UNUSED(op)) ED_gpencil_reset_layers_parent(gpd); } - WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | ND_GPENCIL_EDITMODE, NULL); + WM_event_add_notifier(C, NC_GPENCIL | ND_DATA, NULL); + WM_event_add_notifier(C, NC_GPENCIL | ND_GPENCIL_EDITMODE, NULL); WM_event_add_notifier(C, NC_SCENE | ND_MODE, NULL); return OPERATOR_FINISHED; @@ -153,7 +154,8 @@ static int gpencil_hideselect_toggle_exec(bContext *C, wmOperator *UNUSED(op)) ts->gp_sculpt.alpha = 1.0f; } - WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | ND_GPENCIL_EDITMODE, NULL); + WM_event_add_notifier(C, NC_GPENCIL | ND_DATA, NULL); + WM_event_add_notifier(C, NC_GPENCIL | ND_GPENCIL_EDITMODE, NULL); WM_event_add_notifier(C, NC_SCENE | ND_MODE, NULL); return OPERATOR_FINISHED; diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c index 09ccc4600ef..472b88cb18b 100644 --- a/source/blender/editors/gpencil/gpencil_paint.c +++ b/source/blender/editors/gpencil/gpencil_paint.c @@ -1609,7 +1609,7 @@ static void gp_session_cleanup(tGPsdata *p) } /* init new stroke */ -static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode) +static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode, const Depsgraph *depsgraph) { Scene *scene = p->scene; ToolSettings *ts = scene->toolsettings; @@ -1738,7 +1738,7 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode) /* for camera view set the subrect */ if (rv3d->persp == RV3D_CAMOB) { - ED_view3d_calc_camera_border(p->scene, p->ar, v3d, rv3d, &p->subrect_data, true); /* no shift */ + ED_view3d_calc_camera_border(p->scene, depsgraph, p->ar, v3d, rv3d, &p->subrect_data, true); /* no shift */ p->subrect = &p->subrect_data; } } @@ -1979,7 +1979,7 @@ static int gpencil_draw_init(bContext *C, wmOperator *op, const wmEvent *event) } /* init painting data */ - gp_paint_initstroke(p, paintmode); + gp_paint_initstroke(p, paintmode, CTX_data_depsgraph(C)); if (p->status == GP_STATUS_ERROR) { gpencil_draw_exit(C, op); return 0; @@ -2056,7 +2056,7 @@ static void gpencil_draw_status_indicators(tGPsdata *p) /* ------------------------------- */ /* create a new stroke point at the point indicated by the painting context */ -static void gpencil_draw_apply(wmOperator *op, tGPsdata *p) +static void gpencil_draw_apply(wmOperator *op, tGPsdata *p, const Depsgraph *depsgraph) { /* handle drawing/erasing -> test for erasing first */ if (p->paintmode == GP_PAINTMODE_ERASER) { @@ -2078,7 +2078,7 @@ static void gpencil_draw_apply(wmOperator *op, tGPsdata *p) /* finish off old stroke */ gp_paint_strokeend(p); /* And start a new one!!! Else, projection errors! */ - gp_paint_initstroke(p, p->paintmode); + gp_paint_initstroke(p, p->paintmode, depsgraph); /* start a new stroke, starting from previous point */ /* XXX Must manually reset inittime... */ @@ -2111,7 +2111,7 @@ static void gpencil_draw_apply(wmOperator *op, tGPsdata *p) } /* handle draw event */ -static void gpencil_draw_apply_event(wmOperator *op, const wmEvent *event) +static void gpencil_draw_apply_event(wmOperator *op, const wmEvent *event, const Depsgraph *depsgraph) { tGPsdata *p = op->customdata; PointerRNA itemptr; @@ -2216,7 +2216,7 @@ static void gpencil_draw_apply_event(wmOperator *op, const wmEvent *event) RNA_float_set(&itemptr, "time", p->curtime - p->inittime); /* apply the current latest drawing point */ - gpencil_draw_apply(op, p); + gpencil_draw_apply(op, p, depsgraph); /* force refresh */ ED_region_tag_redraw(p->ar); /* just active area for now, since doing whole screen is too slow */ @@ -2228,6 +2228,7 @@ static void gpencil_draw_apply_event(wmOperator *op, const wmEvent *event) static int gpencil_draw_exec(bContext *C, wmOperator *op) { tGPsdata *p = NULL; + Depsgraph *depsgraph = CTX_data_depsgraph(C); /* printf("GPencil - Starting Re-Drawing\n"); */ @@ -2265,7 +2266,7 @@ static int gpencil_draw_exec(bContext *C, wmOperator *op) if ((p->flags & GP_PAINTFLAG_FIRSTRUN) == 0) { /* TODO: both of these ops can set error-status, but we probably don't need to worry */ gp_paint_strokeend(p); - gp_paint_initstroke(p, p->paintmode); + gp_paint_initstroke(p, p->paintmode, depsgraph); } } @@ -2280,7 +2281,7 @@ static int gpencil_draw_exec(bContext *C, wmOperator *op) } /* apply this data as necessary now (as per usual) */ - gpencil_draw_apply(op, p); + gpencil_draw_apply(op, p, depsgraph); } RNA_END; @@ -2339,7 +2340,7 @@ static int gpencil_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event p->status = GP_STATUS_PAINTING; /* handle the initial drawing - i.e. for just doing a simple dot */ - gpencil_draw_apply_event(op, event); + gpencil_draw_apply_event(op, event, CTX_data_depsgraph(C)); op->flag |= OP_IS_MODAL_CURSOR_REGION; } else { @@ -2380,7 +2381,7 @@ static tGPsdata *gpencil_stroke_begin(bContext *C, wmOperator *op) * it'd be nice to allow changing paint-mode when in sketching-sessions */ if (gp_session_initdata(C, p)) - gp_paint_initstroke(p, p->paintmode); + gp_paint_initstroke(p, p->paintmode, CTX_data_depsgraph(C)); if (p->status != GP_STATUS_ERROR) { p->status = GP_STATUS_PAINTING; @@ -2671,7 +2672,7 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event) if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE) || (p->flags & GP_PAINTFLAG_FIRSTRUN)) { /* handle drawing event */ /* printf("\t\tGP - add point\n"); */ - gpencil_draw_apply_event(op, event); + gpencil_draw_apply_event(op, event, CTX_data_depsgraph(C)); /* finish painting operation if anything went wrong just now */ if (p->status == GP_STATUS_ERROR) { diff --git a/source/blender/editors/gpencil/gpencil_utils.c b/source/blender/editors/gpencil/gpencil_utils.c index e1e4f850039..94689fb59fa 100644 --- a/source/blender/editors/gpencil/gpencil_utils.c +++ b/source/blender/editors/gpencil/gpencil_utils.c @@ -553,7 +553,7 @@ void gp_point_conversion_init(bContext *C, GP_SpaceConversion *r_gsc) /* for camera view set the subrect */ if (rv3d->persp == RV3D_CAMOB) { - ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &r_gsc->subrect_data, true); /* no shift */ + ED_view3d_calc_camera_border(scene, CTX_data_depsgraph(C), ar, v3d, rv3d, &r_gsc->subrect_data, true); /* no shift */ r_gsc->subrect = &r_gsc->subrect_data; } } diff --git a/source/blender/editors/include/ED_gpencil.h b/source/blender/editors/include/ED_gpencil.h index 7e384e0056b..3ea754b242c 100644 --- a/source/blender/editors/include/ED_gpencil.h +++ b/source/blender/editors/include/ED_gpencil.h @@ -35,6 +35,7 @@ struct ID; struct ListBase; struct bContext; +struct Depsgraph; struct ScrArea; struct ARegion; struct View3D; @@ -152,6 +153,7 @@ void ED_gpencil_draw_view2d(const struct bContext *C, bool onlyv2d); void ED_gpencil_draw_view3d(struct wmWindowManager *wm, struct Scene *scene, struct ViewLayer *view_layer, + const struct Depsgraph *depsgraph, struct View3D *v3d, struct ARegion *ar, bool only3d); diff --git a/source/blender/editors/include/ED_manipulator_library.h b/source/blender/editors/include/ED_manipulator_library.h index 80703321490..7166292147e 100644 --- a/source/blender/editors/include/ED_manipulator_library.h +++ b/source/blender/editors/include/ED_manipulator_library.h @@ -33,6 +33,7 @@ /* initialize manipulators */ void ED_manipulatortypes_arrow_2d(void); void ED_manipulatortypes_arrow_3d(void); +void ED_manipulatortypes_button_2d(void); void ED_manipulatortypes_cage_2d(void); void ED_manipulatortypes_cage_3d(void); void ED_manipulatortypes_dial_3d(void); diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h index 1fd7756df77..78497b29313 100644 --- a/source/blender/editors/include/ED_mesh.h +++ b/source/blender/editors/include/ED_mesh.h @@ -40,6 +40,7 @@ struct EvaluationContext; struct View3D; struct ARegion; struct bContext; +struct Depsgraph; struct wmOperator; struct wmKeyConfig; struct ReportList; @@ -126,6 +127,7 @@ void EDBM_flag_enable_all(struct BMEditMesh *em, const char hflag); void EDBM_flag_disable_all(struct BMEditMesh *em, const char hflag); bool BMBVH_EdgeVisible(struct BMBVHTree *tree, struct BMEdge *e, + const struct Depsgraph *depsgraph, struct ARegion *ar, struct View3D *v3d, struct Object *obedit); /* editmesh_select.c */ diff --git a/source/blender/editors/include/ED_screen.h b/source/blender/editors/include/ED_screen.h index d931109b941..32e6ddf6f54 100644 --- a/source/blender/editors/include/ED_screen.h +++ b/source/blender/editors/include/ED_screen.h @@ -141,7 +141,9 @@ int ED_region_global_size_y(void); /* screens */ void ED_screens_initialize(struct wmWindowManager *wm); -void ED_screen_draw(struct wmWindow *win); +void ED_screen_draw_edges(struct wmWindow *win); +void ED_screen_draw_join_shape(struct ScrArea *sa1, struct ScrArea *sa2); +void ED_screen_draw_split_preview(struct ScrArea *sa, const int dir, const float fac); void ED_screen_refresh(struct wmWindowManager *wm, struct wmWindow *win); void ED_screen_ensure_updated(struct wmWindowManager *wm, struct wmWindow *win, struct bScreen *screen); void ED_screen_do_listen(struct bContext *C, struct wmNotifier *note); diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h index 69061bdcd26..7eee053061e 100644 --- a/source/blender/editors/include/ED_view3d.h +++ b/source/blender/editors/include/ED_view3d.h @@ -70,6 +70,7 @@ struct wmWindowManager; struct GPUFX; struct GPUOffScreen; struct GPUFXSettings; +struct GPUViewport; struct WorkSpace; enum eGPUFXFlags; @@ -223,12 +224,16 @@ eV3DProjStatus ED_view3d_project_float_ex(const struct ARegion *ar, float perspm eV3DProjStatus ED_view3d_project_float_global(const struct ARegion *ar, const float co[3], float r_co[2], const eV3DProjTest flag); eV3DProjStatus ED_view3d_project_float_object(const struct ARegion *ar, const float co[3], float r_co[2], const eV3DProjTest flag); +float ED_view3d_pixel_size(const struct RegionView3D *rv3d, const float co[3]); + float ED_view3d_calc_zfac(const struct RegionView3D *rv3d, const float co[3], bool *r_flip); bool ED_view3d_clip_segment(const struct RegionView3D *rv3d, float ray_start[3], float ray_end[3]); bool ED_view3d_win_to_ray( + const struct Depsgraph *depsgraph, const struct ARegion *ar, const struct View3D *v3d, const float mval[2], float ray_start[3], float ray_normal[3], const bool do_clip); bool ED_view3d_win_to_ray_ex( + const struct Depsgraph *depsgraph, const struct ARegion *ar, const struct View3D *v3d, const float mval[2], float r_ray_co[3], float r_ray_normal[3], float r_ray_start[3], bool do_clip); void ED_view3d_global_to_vector(const struct RegionView3D *rv3d, const float coord[3], float vec[3]); @@ -243,7 +248,8 @@ void ED_view3d_win_to_3d_int( void ED_view3d_win_to_delta(const struct ARegion *ar, const float mval[2], float out[3], const float zfac); void ED_view3d_win_to_origin(const struct ARegion *ar, const float mval[2], float out[3]); void ED_view3d_win_to_vector(const struct ARegion *ar, const float mval[2], float out[3]); -bool ED_view3d_win_to_segment(const struct ARegion *ar, struct View3D *v3d, const float mval[2], +bool ED_view3d_win_to_segment(const struct Depsgraph *depsgraph, + const struct ARegion *ar, struct View3D *v3d, const float mval[2], float r_ray_start[3], float r_ray_end[3], const bool do_clip); void ED_view3d_ob_project_mat_get(const struct RegionView3D *v3d, struct Object *ob, float pmat[4][4]); void ED_view3d_ob_project_mat_get_from_obmat(const struct RegionView3D *rv3d, float obmat[4][4], float pmat[4][4]); @@ -258,24 +264,29 @@ void ED_view3d_dist_range_get( const struct View3D *v3d, float r_dist_range[2]); bool ED_view3d_clip_range_get( + const struct Depsgraph *depsgraph, const struct View3D *v3d, const struct RegionView3D *rv3d, float *r_clipsta, float *r_clipend, const bool use_ortho_factor); bool ED_view3d_viewplane_get( + const struct Depsgraph *depsgraph, const struct View3D *v3d, const struct RegionView3D *rv3d, int winxi, int winyi, struct rctf *r_viewplane, float *r_clipsta, float *r_clipend, float *r_pixsize); void ED_view3d_polygon_offset(const struct RegionView3D *rv3d, const float dist); void ED_view3d_calc_camera_border( - const struct Scene *scene, const struct ARegion *ar, + const struct Scene *scene, const struct Depsgraph *depsgraph, + const struct ARegion *ar, const struct View3D *v3d, const struct RegionView3D *rv3d, struct rctf *r_viewborder, const bool no_shift); void ED_view3d_calc_camera_border_size( - const struct Scene *scene, const struct ARegion *ar, + const struct Scene *scene, const struct Depsgraph *depsgraph, + const struct ARegion *ar, const struct View3D *v3d, const struct RegionView3D *rv3d, float r_size[2]); bool ED_view3d_calc_render_border( - const struct Scene *scene, struct View3D *v3d, + const struct Scene *scene, const struct Depsgraph *depsgraph, + struct View3D *v3d, struct ARegion *ar, struct rcti *rect); void ED_view3d_clipping_calc_from_boundbox(float clip[6][4], const struct BoundBox *clipbb, const bool is_flip); @@ -287,8 +298,6 @@ void ED_view3d_clipping_set(struct RegionView3D *rv3d); void ED_view3d_clipping_enable(void); void ED_view3d_clipping_disable(void); -float ED_view3d_pixel_size(const struct RegionView3D *rv3d, const float co[3]); - float ED_view3d_radius_to_dist_persp(const float angle, const float radius); float ED_view3d_radius_to_dist_ortho(const float lens, const float radius); float ED_view3d_radius_to_dist( @@ -380,7 +389,7 @@ void ED_view3d_draw_offscreen( struct ViewLayer *view_layer, struct View3D *v3d, struct ARegion *ar, int winx, int winy, float viewmat[4][4], float winmat[4][4], bool do_bgpic, bool do_sky, bool is_persp, const char *viewname, struct GPUFX *fx, struct GPUFXSettings *fx_settings, - struct GPUOffScreen *ofs); + struct GPUOffScreen *ofs, struct GPUViewport *viewport); void ED_view3d_draw_setup_view( struct wmWindow *win, const struct EvaluationContext *eval_ctx, struct Scene *scene, struct ARegion *ar, struct View3D *v3d, float viewmat[4][4], float winmat[4][4], const struct rcti *rect); @@ -425,6 +434,9 @@ uint64_t ED_view3d_datamask(const struct Scene *scene, const struct View3D *v3d) uint64_t ED_view3d_screen_datamask(const struct Scene *scene, const struct bScreen *screen); bool ED_view3d_offset_lock_check(const struct View3D *v3d, const struct RegionView3D *rv3d); +void ED_view3d_persp_switch_from_camera(struct View3D *v3d, struct RegionView3D *rv3d, const char persp); +bool ED_view3d_persp_ensure(struct View3D *v3d, struct ARegion *ar); + /* camera lock functions */ bool ED_view3d_camera_lock_check(const struct View3D *v3d, const struct RegionView3D *rv3d); @@ -441,7 +453,7 @@ bool ED_view3d_camera_lock_autokey( struct View3D *v3d, struct RegionView3D *rv3d, struct bContext *C, const bool do_rotate, const bool do_translate); -void ED_view3D_lock_clear(struct View3D *v3d); +void ED_view3d_lock_clear(struct View3D *v3d); #define VIEW3D_MARGIN 1.4f #define VIEW3D_DIST_FALLBACK 1.0f @@ -471,4 +483,11 @@ void ED_view3d_shade_update(struct Main *bmain, struct Scene *scene, struct View void ED_view3d_id_remap(struct View3D *v3d, const struct ID *old_id, struct ID *new_id); +/* view3d_draw_legacy.c */ +/* Try avoid using these more move out of legacy. */ +void ED_view3d_draw_bgpic_test( + struct Scene *scene, const struct Depsgraph *depsgraph, + struct ARegion *ar, struct View3D *v3d, + const bool do_foreground, const bool do_camera_frame); + #endif /* __ED_VIEW3D_H__ */ diff --git a/source/blender/editors/include/UI_icons.h b/source/blender/editors/include/UI_icons.h index 0c83038b7a3..923038a7490 100644 --- a/source/blender/editors/include/UI_icons.h +++ b/source/blender/editors/include/UI_icons.h @@ -190,8 +190,8 @@ DEF_ICON(SCULPTMODE_HLT) DEF_ICON(POSE_HLT) DEF_ICON(PARTICLEMODE) DEF_ICON(LIGHTPAINT) +DEF_ICON(GREASEPENCIL_STROKE_PAINT) #ifndef DEF_ICON_BLANK_SKIP - DEF_ICON(BLANK063) DEF_ICON(BLANK064) DEF_ICON(BLANK065) DEF_ICON(BLANK066) @@ -257,9 +257,7 @@ DEF_ICON(STRANDS) DEF_ICON(LIBRARY_DATA_INDIRECT) DEF_ICON(GREASEPENCIL) DEF_ICON(LINE_DATA) -#ifndef DEF_ICON_BLANK_SKIP - DEF_ICON(BLANK084) -#endif +DEF_ICON(LIBRARY_DATA_OVERRIDE) DEF_ICON(GROUP_BONE) DEF_ICON(GROUP_VERTEX) DEF_ICON(GROUP_VCOL) @@ -315,8 +313,8 @@ DEF_ICON(OUTLINER_OB_SURFACE) DEF_ICON(OUTLINER_OB_SPEAKER) DEF_ICON(OUTLINER_OB_FORCE_FIELD) DEF_ICON(OUTLINER_OB_GROUP_INSTANCE) +DEF_ICON(OUTLINER_OB_GREASEPENCIL) #ifndef DEF_ICON_BLANK_SKIP - DEF_ICON(BLANK122) DEF_ICON(BLANK123) DEF_ICON(BLANK124) DEF_ICON(BLANK125) @@ -346,8 +344,8 @@ DEF_ICON(OUTLINER_DATA_FONT) DEF_ICON(OUTLINER_DATA_SURFACE) DEF_ICON(OUTLINER_DATA_SPEAKER) DEF_ICON(OUTLINER_DATA_POSE) +DEF_ICON(OUTLINER_DATA_GREASEPENCIL) #ifndef DEF_ICON_BLANK_SKIP - DEF_ICON(BLANK130) DEF_ICON(BLANK131) DEF_ICON(BLANK132) DEF_ICON(BLANK133) @@ -715,8 +713,8 @@ DEF_ICON(CLIPUV_DEHLT) DEF_ICON(CLIPUV_HLT) DEF_ICON(SNAP_PEEL_OBJECT) DEF_ICON(GRID) +DEF_ICON(OBJECT_ORIGIN) #ifndef DEF_ICON_BLANK_SKIP - DEF_ICON(BLANK221) DEF_ICON(BLANK222) DEF_ICON(BLANK224) DEF_ICON(BLANK225) diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index 9a816f21fb8..c1f2f68dbeb 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -73,6 +73,7 @@ struct bNodeSocket; struct wmDropBox; struct wmDrag; struct wmEvent; +struct wmManipulator; struct wmMsgBus; typedef struct uiBut uiBut; @@ -667,8 +668,18 @@ void UI_but_string_info_get(struct bContext *C, uiBut *but, ...) ATTR_SENTINEL(0 #define UI_ID_FAKE_USER (1 << 8) #define UI_ID_PIN (1 << 9) #define UI_ID_PREVIEWS (1 << 10) +#define UI_ID_OVERRIDE (1 << 11) #define UI_ID_FULL (UI_ID_RENAME | UI_ID_BROWSE | UI_ID_ADD_NEW | UI_ID_OPEN | UI_ID_ALONE | UI_ID_DELETE | UI_ID_LOCAL) +/** + * Ways to limit what is displayed in ID-search popup. + * \note We may want to add LOCAL, LIBRARY ... as needed. + */ +enum { + UI_TEMPLATE_ID_FILTER_ALL = 0, + UI_TEMPLATE_ID_FILTER_AVAILABLE = 1, +}; + int UI_icon_from_id(struct ID *id); int UI_icon_from_report_type(int type); @@ -952,16 +963,20 @@ uiLayout *uiLayoutRadial(uiLayout *layout); /* templates */ void uiTemplateHeader(uiLayout *layout, struct bContext *C); -void uiTemplateID(uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, const char *propname, - const char *newop, const char *openop, const char *unlinkop); -void uiTemplateIDBrowse(uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, const char *propname, - const char *newop, const char *openop, const char *unlinkop); -void uiTemplateIDPreview(uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, const char *propname, - const char *newop, const char *openop, const char *unlinkop, int rows, int cols); +void uiTemplateID( + uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, const char *propname, + const char *newop, const char *openop, const char *unlinkop, int filter); +void uiTemplateIDBrowse( + uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, const char *propname, + const char *newop, const char *openop, const char *unlinkop, int filter); +void uiTemplateIDPreview( + uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, const char *propname, + const char *newop, const char *openop, const char *unlinkop, int rows, int cols, int filter); void uiTemplateIDTabs( uiLayout *layout, struct bContext *C, PointerRNA *ptr, const char *propname, - const char *newop, const char *openop, const char *unlinkop); + const char *newop, const char *openop, const char *unlinkop, + int filter); void uiTemplateAnyID(uiLayout *layout, struct PointerRNA *ptr, const char *propname, const char *proptypename, const char *text); void uiTemplateSearch( @@ -1125,6 +1140,8 @@ void UI_context_active_but_prop_get_templateID( struct bContext *C, struct PointerRNA *r_ptr, struct PropertyRNA **r_prop); +uiBut *UI_region_active_but_get(struct ARegion *ar); + /* Styled text draw */ void UI_fontstyle_set(const struct uiFontStyle *fs); void UI_fontstyle_draw_ex(const struct uiFontStyle *fs, const struct rcti *rect, const char *str, @@ -1168,6 +1185,13 @@ void UI_butstore_register(uiButStore *bs_handle, uiBut **but_p); bool UI_butstore_register_update(uiBlock *block, uiBut *but_dst, const uiBut *but_src); void UI_butstore_unregister(uiButStore *bs_handle, uiBut **but_p); +/* ui_interface_region_tooltip.c */ +struct ARegion *UI_tooltip_create_from_button(struct bContext *C, struct ARegion *butregion, uiBut *but); +struct ARegion *UI_tooltip_create_from_manipulator(struct bContext *C, struct wmManipulator *mpr); +void UI_tooltip_free(struct bContext *C, struct bScreen *sc, struct ARegion *ar); + +/* How long before a tool-tip shows. */ +#define UI_TOOLTIP_DELAY 0.5 /* Float precision helpers */ #define UI_PRECISION_FLOAT_MAX 6 diff --git a/source/blender/editors/interface/CMakeLists.txt b/source/blender/editors/interface/CMakeLists.txt index 03a2c1ec414..94f377fb35e 100644 --- a/source/blender/editors/interface/CMakeLists.txt +++ b/source/blender/editors/interface/CMakeLists.txt @@ -45,6 +45,11 @@ set(SRC interface_anim.c interface_draw.c interface_eyedropper.c + interface_eyedropper_color.c + interface_eyedropper_colorband.c + interface_eyedropper_datablock.c + interface_eyedropper_depth.c + interface_eyedropper_driver.c interface_handlers.c interface_icons.c interface_layout.c diff --git a/source/blender/editors/interface/interface_draw.c b/source/blender/editors/interface/interface_draw.c index e46c6a0e267..3ecb72353bc 100644 --- a/source/blender/editors/interface/interface_draw.c +++ b/source/blender/editors/interface/interface_draw.c @@ -40,9 +40,9 @@ #include "BLI_string.h" #include "BLI_utildefines.h" +#include "BKE_colorband.h" #include "BKE_colortools.h" #include "BKE_node.h" -#include "BKE_texture.h" #include "BKE_tracking.h" @@ -1335,7 +1335,7 @@ void ui_draw_but_COLORBAND(uiBut *but, uiWidgetColors *UNUSED(wcol), const rcti immBegin(GWN_PRIM_TRI_STRIP, (sizex + 1) * 2); for (int a = 0; a <= sizex; a++) { float pos = ((float)a) / sizex; - do_colorband(coba, pos, colf); + BKE_colorband_evaluate(coba, pos, colf); if (display) IMB_colormanagement_scene_linear_to_display_v3(colf, display); @@ -1354,7 +1354,7 @@ void ui_draw_but_COLORBAND(uiBut *but, uiWidgetColors *UNUSED(wcol), const rcti immBegin(GWN_PRIM_TRI_STRIP, (sizex + 1) * 2); for (int a = 0; a <= sizex; a++) { float pos = ((float)a) / sizex; - do_colorband(coba, pos, colf); + BKE_colorband_evaluate(coba, pos, colf); if (display) IMB_colormanagement_scene_linear_to_display_v3(colf, display); diff --git a/source/blender/editors/interface/interface_eyedropper.c b/source/blender/editors/interface/interface_eyedropper.c index e92139ada0c..8cb55b724fb 100644 --- a/source/blender/editors/interface/interface_eyedropper.c +++ b/source/blender/editors/interface/interface_eyedropper.c @@ -27,55 +27,23 @@ * \ingroup edinterface */ -#include "MEM_guardedalloc.h" - -#include "DNA_anim_types.h" #include "DNA_space_types.h" #include "DNA_screen_types.h" -#include "DNA_object_types.h" #include "BLI_blenlib.h" #include "BLI_math_vector.h" -#include "BLT_translation.h" - #include "BKE_context.h" #include "BKE_screen.h" -#include "BKE_report.h" -#include "BKE_animsys.h" -#include "BKE_idcode.h" -#include "BKE_unit.h" - -#include "DEG_depsgraph.h" -#include "DEG_depsgraph_build.h" - -#include "RNA_access.h" -#include "RNA_define.h" - -#include "BIF_gl.h" #include "UI_interface.h" -#include "IMB_colormanagement.h" - #include "WM_api.h" #include "WM_types.h" #include "interface_intern.h" -/* for HDR color sampling */ -#include "ED_image.h" -#include "ED_node.h" -#include "ED_clip.h" - -/* for ID data eyedropper */ -#include "ED_space_api.h" -#include "ED_screen.h" -#include "ED_view3d.h" - -/* for Driver eyedropper */ -#include "ED_keyframing.h" - +#include "interface_eyedropper_intern.h" /* own include */ /* -------------------------------------------------------------------- */ /* Keymap @@ -83,12 +51,6 @@ /** \name Modal Keymap * \{ */ -enum { - EYE_MODAL_CANCEL = 1, - EYE_MODAL_SAMPLE_CONFIRM, - EYE_MODAL_SAMPLE_BEGIN, - EYE_MODAL_SAMPLE_RESET, -}; wmKeyMap *eyedropper_modal_keymap(wmKeyConfig *keyconf) { @@ -118,6 +80,7 @@ wmKeyMap *eyedropper_modal_keymap(wmKeyConfig *keyconf) WM_modalkeymap_add_item(keymap, SPACEKEY, KM_RELEASE, KM_ANY, 0, EYE_MODAL_SAMPLE_RESET); /* assign to operators */ + WM_modalkeymap_assign(keymap, "UI_OT_eyedropper_colorband"); WM_modalkeymap_assign(keymap, "UI_OT_eyedropper_color"); WM_modalkeymap_assign(keymap, "UI_OT_eyedropper_id"); WM_modalkeymap_assign(keymap, "UI_OT_eyedropper_depth"); @@ -126,6 +89,37 @@ wmKeyMap *eyedropper_modal_keymap(wmKeyConfig *keyconf) return keymap; } +wmKeyMap *eyedropper_colorband_modal_keymap(wmKeyConfig *keyconf) +{ + static const EnumPropertyItem modal_items_point[] = { + {EYE_MODAL_POINT_CANCEL, "CANCEL", 0, "Cancel", ""}, + {EYE_MODAL_POINT_SAMPLE, "SAMPLE_SAMPLE", 0, "Sample a point", ""}, + {EYE_MODAL_POINT_CONFIRM, "SAMPLE_CONFIRM", 0, "Confirm Sampling", ""}, + {EYE_MODAL_POINT_RESET, "SAMPLE_RESET", 0, "Reset Sampling", ""}, + {0, NULL, 0, NULL, NULL} + }; + + wmKeyMap *keymap = WM_modalkeymap_get(keyconf, "Eyedropper ColorBand PointSampling Map"); + if (keymap && keymap->modal_items) + return keymap; + + keymap = WM_modalkeymap_add(keyconf, "Eyedropper ColorBand PointSampling Map", modal_items_point); + + /* items for modal map */ + WM_modalkeymap_add_item(keymap, ESCKEY, KM_PRESS, KM_ANY, 0, EYE_MODAL_CANCEL); + WM_modalkeymap_add_item(keymap, BACKSPACEKEY, KM_PRESS, KM_ANY, 0, EYE_MODAL_POINT_REMOVE_LAST); + WM_modalkeymap_add_item(keymap, RIGHTMOUSE, KM_PRESS, KM_ANY, 0, EYE_MODAL_POINT_CONFIRM); + WM_modalkeymap_add_item(keymap, RETKEY, KM_RELEASE, KM_ANY, 0, EYE_MODAL_POINT_CONFIRM); + WM_modalkeymap_add_item(keymap, PADENTER, KM_RELEASE, KM_ANY, 0, EYE_MODAL_POINT_CONFIRM); + WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_PRESS, KM_ANY, 0, EYE_MODAL_POINT_SAMPLE); + WM_modalkeymap_add_item(keymap, SPACEKEY, KM_RELEASE, KM_ANY, 0, EYE_MODAL_POINT_RESET); + + /* assign to operators */ + WM_modalkeymap_assign(keymap, "UI_OT_eyedropper_colorband_point"); + + return keymap; +} + /** \} */ @@ -135,7 +129,7 @@ wmKeyMap *eyedropper_modal_keymap(wmKeyConfig *keyconf) /** \name Generic Shared Functions * \{ */ -static void eyedropper_draw_cursor_text(const struct bContext *C, ARegion *ar, const char *name) +void eyedropper_draw_cursor_text(const struct bContext *C, const ARegion *ar, const char *name) { const uiFontStyle *fstyle = UI_FSTYLE_WIDGET; wmWindow *win = CTX_wm_window(C); @@ -169,14 +163,14 @@ static void eyedropper_draw_cursor_text(const struct bContext *C, ARegion *ar, c * * \return A button under the mouse which relates to some RNA Property, or NULL */ -static uiBut *eyedropper_get_property_button_under_mouse(bContext *C, const wmEvent *event) +uiBut *eyedropper_get_property_button_under_mouse(bContext *C, const wmEvent *event) { bScreen *screen = CTX_wm_screen(C); ScrArea *sa = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, event->x, event->y); ARegion *ar = BKE_area_find_region_xy(sa, RGN_TYPE_ANY, event->x, event->y); - + uiBut *but = ui_but_find_mouse_over(ar, event); - + if (ELEM(NULL, but, but->rnapoin.data, but->rnaprop)) { return NULL; } @@ -187,1128 +181,3 @@ static uiBut *eyedropper_get_property_button_under_mouse(bContext *C, const wmEv /** \} */ - -/* -------------------------------------------------------------------- */ -/* Eyedropper - */ - -/** \name Eyedropper (RGB Color) - * \{ */ - -typedef struct Eyedropper { - struct ColorManagedDisplay *display; - - PointerRNA ptr; - PropertyRNA *prop; - int index; - - float init_col[3]; /* for resetting on cancel */ - - bool accum_start; /* has mouse been pressed */ - float accum_col[3]; - int accum_tot; -} Eyedropper; - -static bool eyedropper_init(bContext *C, wmOperator *op) -{ - Scene *scene = CTX_data_scene(C); - Eyedropper *eye; - - op->customdata = eye = MEM_callocN(sizeof(Eyedropper), "Eyedropper"); - - UI_context_active_but_prop_get(C, &eye->ptr, &eye->prop, &eye->index); - - if ((eye->ptr.data == NULL) || - (eye->prop == NULL) || - (RNA_property_editable(&eye->ptr, eye->prop) == false) || - (RNA_property_array_length(&eye->ptr, eye->prop) < 3) || - (RNA_property_type(eye->prop) != PROP_FLOAT)) - { - return false; - } - - if (RNA_property_subtype(eye->prop) != PROP_COLOR) { - const char *display_device; - float col[4]; - - display_device = scene->display_settings.display_device; - eye->display = IMB_colormanagement_display_get_named(display_device); - - /* store inital color */ - RNA_property_float_get_array(&eye->ptr, eye->prop, col); - if (eye->display) { - IMB_colormanagement_display_to_scene_linear_v3(col, eye->display); - } - copy_v3_v3(eye->init_col, col); - } - - return true; -} - -static void eyedropper_exit(bContext *C, wmOperator *op) -{ - WM_cursor_modal_restore(CTX_wm_window(C)); - - if (op->customdata) { - MEM_freeN(op->customdata); - op->customdata = NULL; - } -} - -/* *** eyedropper_color_ helper functions *** */ - -/** - * \brief get the color from the screen. - * - * Special check for image or nodes where we MAY have HDR pixels which don't display. - */ -static void eyedropper_color_sample_fl(bContext *C, Eyedropper *UNUSED(eye), int mx, int my, float r_col[3]) -{ - /* we could use some clever */ - bScreen *screen = CTX_wm_screen(C); - ScrArea *sa = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, mx, my); - const char *display_device = CTX_data_scene(C)->display_settings.display_device; - struct ColorManagedDisplay *display = IMB_colormanagement_display_get_named(display_device); - - if (sa) { - if (sa->spacetype == SPACE_IMAGE) { - ARegion *ar = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my); - if (ar) { - SpaceImage *sima = sa->spacedata.first; - int mval[2] = {mx - ar->winrct.xmin, - my - ar->winrct.ymin}; - - if (ED_space_image_color_sample(sima, ar, mval, r_col)) { - return; - } - } - } - else if (sa->spacetype == SPACE_NODE) { - ARegion *ar = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my); - if (ar) { - SpaceNode *snode = sa->spacedata.first; - int mval[2] = {mx - ar->winrct.xmin, - my - ar->winrct.ymin}; - - if (ED_space_node_color_sample(snode, ar, mval, r_col)) { - return; - } - } - } - else if (sa->spacetype == SPACE_CLIP) { - ARegion *ar = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my); - if (ar) { - SpaceClip *sc = sa->spacedata.first; - int mval[2] = {mx - ar->winrct.xmin, - my - ar->winrct.ymin}; - - if (ED_space_clip_color_sample(sc, ar, mval, r_col)) { - return; - } - } - } - } - - /* fallback to simple opengl picker */ - glReadBuffer(GL_FRONT); - glReadPixels(mx, my, 1, 1, GL_RGB, GL_FLOAT, r_col); - glReadBuffer(GL_BACK); - - IMB_colormanagement_display_to_scene_linear_v3(r_col, display); -} - -/* sets the sample color RGB, maintaining A */ -static void eyedropper_color_set(bContext *C, Eyedropper *eye, const float col[3]) -{ - float col_conv[4]; - - /* to maintain alpha */ - RNA_property_float_get_array(&eye->ptr, eye->prop, col_conv); - - /* convert from linear rgb space to display space */ - if (eye->display) { - copy_v3_v3(col_conv, col); - IMB_colormanagement_scene_linear_to_display_v3(col_conv, eye->display); - } - else { - copy_v3_v3(col_conv, col); - } - - RNA_property_float_set_array(&eye->ptr, eye->prop, col_conv); - - RNA_property_update(C, &eye->ptr, eye->prop); -} - -/* set sample from accumulated values */ -static void eyedropper_color_set_accum(bContext *C, Eyedropper *eye) -{ - float col[3]; - mul_v3_v3fl(col, eye->accum_col, 1.0f / (float)eye->accum_tot); - eyedropper_color_set(C, eye, col); -} - -/* single point sample & set */ -static void eyedropper_color_sample(bContext *C, Eyedropper *eye, int mx, int my) -{ - float col[3]; - eyedropper_color_sample_fl(C, eye, mx, my, col); - eyedropper_color_set(C, eye, col); -} - -static void eyedropper_color_sample_accum(bContext *C, Eyedropper *eye, int mx, int my) -{ - float col[3]; - eyedropper_color_sample_fl(C, eye, mx, my, col); - /* delay linear conversion */ - add_v3_v3(eye->accum_col, col); - eye->accum_tot++; -} - -static void eyedropper_cancel(bContext *C, wmOperator *op) -{ - Eyedropper *eye = op->customdata; - eyedropper_color_set(C, eye, eye->init_col); - eyedropper_exit(C, op); -} - -/* main modal status check */ -static int eyedropper_modal(bContext *C, wmOperator *op, const wmEvent *event) -{ - Eyedropper *eye = (Eyedropper *)op->customdata; - - /* handle modal keymap */ - if (event->type == EVT_MODAL_MAP) { - switch (event->val) { - case EYE_MODAL_CANCEL: - eyedropper_cancel(C, op); - return OPERATOR_CANCELLED; - case EYE_MODAL_SAMPLE_CONFIRM: - if (eye->accum_tot == 0) { - eyedropper_color_sample(C, eye, event->x, event->y); - } - else { - eyedropper_color_set_accum(C, eye); - } - eyedropper_exit(C, op); - return OPERATOR_FINISHED; - case EYE_MODAL_SAMPLE_BEGIN: - /* enable accum and make first sample */ - eye->accum_start = true; - eyedropper_color_sample_accum(C, eye, event->x, event->y); - break; - case EYE_MODAL_SAMPLE_RESET: - eye->accum_tot = 0; - zero_v3(eye->accum_col); - eyedropper_color_sample_accum(C, eye, event->x, event->y); - eyedropper_color_set_accum(C, eye); - break; - } - } - else if (event->type == MOUSEMOVE) { - if (eye->accum_start) { - /* button is pressed so keep sampling */ - eyedropper_color_sample_accum(C, eye, event->x, event->y); - eyedropper_color_set_accum(C, eye); - } - } - - return OPERATOR_RUNNING_MODAL; -} - -/* Modal Operator init */ -static int eyedropper_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) -{ - /* init */ - if (eyedropper_init(C, op)) { - WM_cursor_modal_set(CTX_wm_window(C), BC_EYEDROPPER_CURSOR); - - /* add temp handler */ - WM_event_add_modal_handler(C, op); - - return OPERATOR_RUNNING_MODAL; - } - else { - eyedropper_exit(C, op); - return OPERATOR_CANCELLED; - } -} - -/* Repeat operator */ -static int eyedropper_exec(bContext *C, wmOperator *op) -{ - /* init */ - if (eyedropper_init(C, op)) { - - /* do something */ - - /* cleanup */ - eyedropper_exit(C, op); - - return OPERATOR_FINISHED; - } - else { - return OPERATOR_CANCELLED; - } -} - -static int eyedropper_poll(bContext *C) -{ - PointerRNA ptr; - PropertyRNA *prop; - int index_dummy; - uiBut *but; - - /* Only color buttons */ - if ((CTX_wm_window(C) != NULL) && - (but = UI_context_active_but_prop_get(C, &ptr, &prop, &index_dummy)) && - (but->type == UI_BTYPE_COLOR)) - { - return 1; - } - - return 0; -} - -void UI_OT_eyedropper_color(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Eyedropper"; - ot->idname = "UI_OT_eyedropper_color"; - ot->description = "Sample a color from the Blender Window to store in a property"; - - /* api callbacks */ - ot->invoke = eyedropper_invoke; - ot->modal = eyedropper_modal; - ot->cancel = eyedropper_cancel; - ot->exec = eyedropper_exec; - ot->poll = eyedropper_poll; - - /* flags */ - ot->flag = OPTYPE_BLOCKING | OPTYPE_INTERNAL; - - /* properties */ -} - -/** \} */ - - -/* -------------------------------------------------------------------- */ -/* Data Dropper */ - -/** \name Eyedropper (ID data-blocks) - * - * \note: datadropper is only internal name to avoid confusion in this file. - * \{ */ - -typedef struct DataDropper { - PointerRNA ptr; - PropertyRNA *prop; - short idcode; - const char *idcode_name; - - ID *init_id; /* for resetting on cancel */ - - ARegionType *art; - void *draw_handle_pixel; - char name[200]; -} DataDropper; - - -static void datadropper_draw_cb(const struct bContext *C, ARegion *ar, void *arg) -{ - DataDropper *ddr = arg; - eyedropper_draw_cursor_text(C, ar, ddr->name); -} - - -static int datadropper_init(bContext *C, wmOperator *op) -{ - DataDropper *ddr; - int index_dummy; - StructRNA *type; - - SpaceType *st; - ARegionType *art; - - st = BKE_spacetype_from_id(SPACE_VIEW3D); - art = BKE_regiontype_from_id(st, RGN_TYPE_WINDOW); - - op->customdata = ddr = MEM_callocN(sizeof(DataDropper), "DataDropper"); - - UI_context_active_but_prop_get(C, &ddr->ptr, &ddr->prop, &index_dummy); - - if ((ddr->ptr.data == NULL) || - (ddr->prop == NULL) || - (RNA_property_editable(&ddr->ptr, ddr->prop) == false) || - (RNA_property_type(ddr->prop) != PROP_POINTER)) - { - return false; - } - - ddr->art = art; - ddr->draw_handle_pixel = ED_region_draw_cb_activate(art, datadropper_draw_cb, ddr, REGION_DRAW_POST_PIXEL); - - type = RNA_property_pointer_type(&ddr->ptr, ddr->prop); - ddr->idcode = RNA_type_to_ID_code(type); - BLI_assert(ddr->idcode != 0); - /* Note we can translate here (instead of on draw time), because this struct has very short lifetime. */ - ddr->idcode_name = TIP_(BKE_idcode_to_name(ddr->idcode)); - - PointerRNA ptr = RNA_property_pointer_get(&ddr->ptr, ddr->prop); - ddr->init_id = ptr.id.data; - - return true; -} - -static void datadropper_exit(bContext *C, wmOperator *op) -{ - WM_cursor_modal_restore(CTX_wm_window(C)); - - if (op->customdata) { - DataDropper *ddr = (DataDropper *)op->customdata; - - if (ddr->art) { - ED_region_draw_cb_exit(ddr->art, ddr->draw_handle_pixel); - } - - MEM_freeN(op->customdata); - - op->customdata = NULL; - } - - WM_event_add_mousemove(C); -} - -/* *** datadropper id helper functions *** */ -/** - * \brief get the ID from the screen. - * - */ -static void datadropper_id_sample_pt(bContext *C, DataDropper *ddr, int mx, int my, ID **r_id) -{ - /* we could use some clever */ - bScreen *screen = CTX_wm_screen(C); - ScrArea *sa = BKE_screen_find_area_xy(screen, -1, mx, my); - - ScrArea *area_prev = CTX_wm_area(C); - ARegion *ar_prev = CTX_wm_region(C); - - ddr->name[0] = '\0'; - - if (sa) { - if (sa->spacetype == SPACE_VIEW3D) { - ARegion *ar = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my); - if (ar) { - const int mval[2] = { - mx - ar->winrct.xmin, - my - ar->winrct.ymin}; - Base *base; - - CTX_wm_area_set(C, sa); - CTX_wm_region_set(C, ar); - - /* grr, always draw else we leave stale text */ - ED_region_tag_redraw(ar); - - base = ED_view3d_give_base_under_cursor(C, mval); - if (base) { - Object *ob = base->object; - ID *id = NULL; - if (ddr->idcode == ID_OB) { - id = (ID *)ob; - } - else if (ob->data) { - if (GS(((ID *)ob->data)->name) == ddr->idcode) { - id = (ID *)ob->data; - } - else { - BLI_snprintf(ddr->name, sizeof(ddr->name), "Incompatible, expected a %s", - ddr->idcode_name); - } - } - - if (id) { - BLI_snprintf(ddr->name, sizeof(ddr->name), "%s: %s", - ddr->idcode_name, id->name + 2); - *r_id = id; - } - } - } - } - } - - CTX_wm_area_set(C, area_prev); - CTX_wm_region_set(C, ar_prev); -} - -/* sets the ID, returns success */ -static bool datadropper_id_set(bContext *C, DataDropper *ddr, ID *id) -{ - PointerRNA ptr_value; - - RNA_id_pointer_create(id, &ptr_value); - - RNA_property_pointer_set(&ddr->ptr, ddr->prop, ptr_value); - - RNA_property_update(C, &ddr->ptr, ddr->prop); - - ptr_value = RNA_property_pointer_get(&ddr->ptr, ddr->prop); - - return (ptr_value.id.data == id); -} - -/* single point sample & set */ -static bool datadropper_id_sample(bContext *C, DataDropper *ddr, int mx, int my) -{ - ID *id = NULL; - - datadropper_id_sample_pt(C, ddr, mx, my, &id); - return datadropper_id_set(C, ddr, id); -} - -static void datadropper_cancel(bContext *C, wmOperator *op) -{ - DataDropper *ddr = op->customdata; - datadropper_id_set(C, ddr, ddr->init_id); - datadropper_exit(C, op); -} - -/* main modal status check */ -static int datadropper_modal(bContext *C, wmOperator *op, const wmEvent *event) -{ - DataDropper *ddr = (DataDropper *)op->customdata; - - /* handle modal keymap */ - if (event->type == EVT_MODAL_MAP) { - switch (event->val) { - case EYE_MODAL_CANCEL: - datadropper_cancel(C, op); - return OPERATOR_CANCELLED; - case EYE_MODAL_SAMPLE_CONFIRM: - { - bool success; - - success = datadropper_id_sample(C, ddr, event->x, event->y); - datadropper_exit(C, op); - - if (success) { - return OPERATOR_FINISHED; - } - else { - BKE_report(op->reports, RPT_WARNING, "Failed to set value"); - return OPERATOR_CANCELLED; - } - } - } - } - else if (event->type == MOUSEMOVE) { - ID *id = NULL; - datadropper_id_sample_pt(C, ddr, event->x, event->y, &id); - } - - return OPERATOR_RUNNING_MODAL; -} - -/* Modal Operator init */ -static int datadropper_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) -{ - /* init */ - if (datadropper_init(C, op)) { - WM_cursor_modal_set(CTX_wm_window(C), BC_EYEDROPPER_CURSOR); - - /* add temp handler */ - WM_event_add_modal_handler(C, op); - - return OPERATOR_RUNNING_MODAL; - } - else { - datadropper_exit(C, op); - return OPERATOR_CANCELLED; - } -} - -/* Repeat operator */ -static int datadropper_exec(bContext *C, wmOperator *op) -{ - /* init */ - if (datadropper_init(C, op)) { - /* cleanup */ - datadropper_exit(C, op); - - return OPERATOR_FINISHED; - } - else { - return OPERATOR_CANCELLED; - } -} - -static int datadropper_poll(bContext *C) -{ - PointerRNA ptr; - PropertyRNA *prop; - int index_dummy; - uiBut *but; - - /* data dropper only supports object data */ - if ((CTX_wm_window(C) != NULL) && - (but = UI_context_active_but_prop_get(C, &ptr, &prop, &index_dummy)) && - (but->type == UI_BTYPE_SEARCH_MENU) && - (but->flag & UI_BUT_VALUE_CLEAR)) - { - if (prop && RNA_property_type(prop) == PROP_POINTER) { - StructRNA *type = RNA_property_pointer_type(&ptr, prop); - const short idcode = RNA_type_to_ID_code(type); - if ((idcode == ID_OB) || OB_DATA_SUPPORT_ID(idcode)) { - return 1; - } - } - } - - return 0; -} - -void UI_OT_eyedropper_id(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Eyedropper Data-Block"; - ot->idname = "UI_OT_eyedropper_id"; - ot->description = "Sample a data-block from the 3D View to store in a property"; - - /* api callbacks */ - ot->invoke = datadropper_invoke; - ot->modal = datadropper_modal; - ot->cancel = datadropper_cancel; - ot->exec = datadropper_exec; - ot->poll = datadropper_poll; - - /* flags */ - ot->flag = OPTYPE_BLOCKING | OPTYPE_INTERNAL; - - /* properties */ -} - -/** \} */ - - -/* -------------------------------------------------------------------- */ -/* Depth Dropper */ - -/** \name Eyedropper (Depth) - * - * \note: depthdropper is only internal name to avoid confusion in this file. - * \{ */ - -typedef struct DepthDropper { - PointerRNA ptr; - PropertyRNA *prop; - - float init_depth; /* for resetting on cancel */ - - bool accum_start; /* has mouse been presed */ - float accum_depth; - int accum_tot; - - ARegionType *art; - void *draw_handle_pixel; - char name[200]; -} DepthDropper; - - -static void depthdropper_draw_cb(const struct bContext *C, ARegion *ar, void *arg) -{ - DepthDropper *ddr = arg; - eyedropper_draw_cursor_text(C, ar, ddr->name); -} - - -static int depthdropper_init(bContext *C, wmOperator *op) -{ - DepthDropper *ddr; - int index_dummy; - - SpaceType *st; - ARegionType *art; - - st = BKE_spacetype_from_id(SPACE_VIEW3D); - art = BKE_regiontype_from_id(st, RGN_TYPE_WINDOW); - - op->customdata = ddr = MEM_callocN(sizeof(DepthDropper), "DepthDropper"); - - UI_context_active_but_prop_get(C, &ddr->ptr, &ddr->prop, &index_dummy); - - /* fallback to the active camera's dof */ - if (ddr->prop == NULL) { - RegionView3D *rv3d = CTX_wm_region_view3d(C); - if (rv3d && rv3d->persp == RV3D_CAMOB) { - View3D *v3d = CTX_wm_view3d(C); - if (v3d->camera && v3d->camera->data && !ID_IS_LINKED(v3d->camera->data)) { - RNA_id_pointer_create(v3d->camera->data, &ddr->ptr); - ddr->prop = RNA_struct_find_property(&ddr->ptr, "dof_distance"); - } - } - } - - if ((ddr->ptr.data == NULL) || - (ddr->prop == NULL) || - (RNA_property_editable(&ddr->ptr, ddr->prop) == false) || - (RNA_property_type(ddr->prop) != PROP_FLOAT)) - { - return false; - } - - ddr->art = art; - ddr->draw_handle_pixel = ED_region_draw_cb_activate(art, depthdropper_draw_cb, ddr, REGION_DRAW_POST_PIXEL); - ddr->init_depth = RNA_property_float_get(&ddr->ptr, ddr->prop); - - return true; -} - -static void depthdropper_exit(bContext *C, wmOperator *op) -{ - WM_cursor_modal_restore(CTX_wm_window(C)); - - if (op->customdata) { - DepthDropper *ddr = (DepthDropper *)op->customdata; - - if (ddr->art) { - ED_region_draw_cb_exit(ddr->art, ddr->draw_handle_pixel); - } - - MEM_freeN(op->customdata); - - op->customdata = NULL; - } -} - -/* *** depthdropper id helper functions *** */ -/** - * \brief get the ID from the screen. - * - */ -static void depthdropper_depth_sample_pt(bContext *C, DepthDropper *ddr, int mx, int my, float *r_depth) -{ - /* we could use some clever */ - bScreen *screen = CTX_wm_screen(C); - ScrArea *sa = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, mx, my); - Scene *scene = CTX_data_scene(C); - UnitSettings *unit = &scene->unit; - const bool do_split = (unit->flag & USER_UNIT_OPT_SPLIT) != 0; - - ScrArea *area_prev = CTX_wm_area(C); - ARegion *ar_prev = CTX_wm_region(C); - - ddr->name[0] = '\0'; - - if (sa) { - if (sa->spacetype == SPACE_VIEW3D) { - ARegion *ar = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my); - if (ar) { - struct Depsgraph *graph = CTX_data_depsgraph(C); - View3D *v3d = sa->spacedata.first; - RegionView3D *rv3d = ar->regiondata; - /* weak, we could pass in some reference point */ - const float *view_co = v3d->camera ? v3d->camera->obmat[3] : rv3d->viewinv[3]; - const int mval[2] = { - mx - ar->winrct.xmin, - my - ar->winrct.ymin}; - float co[3]; - - EvaluationContext eval_ctx; - CTX_data_eval_ctx(C, &eval_ctx); - - CTX_wm_area_set(C, sa); - CTX_wm_region_set(C, ar); - - /* grr, always draw else we leave stale text */ - ED_region_tag_redraw(ar); - - view3d_operator_needs_opengl(C); - - if (ED_view3d_autodist(&eval_ctx, graph, ar, v3d, mval, co, true, NULL)) { - const float mval_center_fl[2] = { - (float)ar->winx / 2, - (float)ar->winy / 2}; - float co_align[3]; - - /* quick way to get view-center aligned point */ - ED_view3d_win_to_3d(v3d, ar, co, mval_center_fl, co_align); - - *r_depth = len_v3v3(view_co, co_align); - - bUnit_AsString(ddr->name, sizeof(ddr->name), - (double)*r_depth, - 4, unit->system, B_UNIT_LENGTH, do_split, false); - } - else { - BLI_strncpy(ddr->name, "Nothing under cursor", sizeof(ddr->name)); - } - } - } - } - - CTX_wm_area_set(C, area_prev); - CTX_wm_region_set(C, ar_prev); -} - -/* sets the sample depth RGB, maintaining A */ -static void depthdropper_depth_set(bContext *C, DepthDropper *ddr, const float depth) -{ - RNA_property_float_set(&ddr->ptr, ddr->prop, depth); - RNA_property_update(C, &ddr->ptr, ddr->prop); -} - -/* set sample from accumulated values */ -static void depthdropper_depth_set_accum(bContext *C, DepthDropper *ddr) -{ - float depth = ddr->accum_depth; - if (ddr->accum_tot) { - depth /= (float)ddr->accum_tot; - } - depthdropper_depth_set(C, ddr, depth); -} - -/* single point sample & set */ -static void depthdropper_depth_sample(bContext *C, DepthDropper *ddr, int mx, int my) -{ - float depth = -1.0f; - if (depth != -1.0f) { - depthdropper_depth_sample_pt(C, ddr, mx, my, &depth); - depthdropper_depth_set(C, ddr, depth); - } -} - -static void depthdropper_depth_sample_accum(bContext *C, DepthDropper *ddr, int mx, int my) -{ - float depth = -1.0f; - depthdropper_depth_sample_pt(C, ddr, mx, my, &depth); - if (depth != -1.0f) { - ddr->accum_depth += depth; - ddr->accum_tot++; - } -} - -static void depthdropper_cancel(bContext *C, wmOperator *op) -{ - DepthDropper *ddr = op->customdata; - depthdropper_depth_set(C, ddr, ddr->init_depth); - depthdropper_exit(C, op); -} - -/* main modal status check */ -static int depthdropper_modal(bContext *C, wmOperator *op, const wmEvent *event) -{ - DepthDropper *ddr = (DepthDropper *)op->customdata; - - /* handle modal keymap */ - if (event->type == EVT_MODAL_MAP) { - switch (event->val) { - case EYE_MODAL_CANCEL: - depthdropper_cancel(C, op); - return OPERATOR_CANCELLED; - case EYE_MODAL_SAMPLE_CONFIRM: - if (ddr->accum_tot == 0) { - depthdropper_depth_sample(C, ddr, event->x, event->y); - } - else { - depthdropper_depth_set_accum(C, ddr); - } - depthdropper_exit(C, op); - return OPERATOR_FINISHED; - case EYE_MODAL_SAMPLE_BEGIN: - /* enable accum and make first sample */ - ddr->accum_start = true; - depthdropper_depth_sample_accum(C, ddr, event->x, event->y); - break; - case EYE_MODAL_SAMPLE_RESET: - ddr->accum_tot = 0; - ddr->accum_depth = 0.0f; - depthdropper_depth_sample_accum(C, ddr, event->x, event->y); - depthdropper_depth_set_accum(C, ddr); - break; - } - } - else if (event->type == MOUSEMOVE) { - if (ddr->accum_start) { - /* button is pressed so keep sampling */ - depthdropper_depth_sample_accum(C, ddr, event->x, event->y); - depthdropper_depth_set_accum(C, ddr); - } - } - - return OPERATOR_RUNNING_MODAL; -} - -/* Modal Operator init */ -static int depthdropper_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) -{ - /* init */ - if (depthdropper_init(C, op)) { - WM_cursor_modal_set(CTX_wm_window(C), BC_EYEDROPPER_CURSOR); - - /* add temp handler */ - WM_event_add_modal_handler(C, op); - - return OPERATOR_RUNNING_MODAL; - } - else { - depthdropper_exit(C, op); - return OPERATOR_CANCELLED; - } -} - -/* Repeat operator */ -static int depthdropper_exec(bContext *C, wmOperator *op) -{ - /* init */ - if (depthdropper_init(C, op)) { - /* cleanup */ - depthdropper_exit(C, op); - - return OPERATOR_FINISHED; - } - else { - return OPERATOR_CANCELLED; - } -} - -static int depthdropper_poll(bContext *C) -{ - PointerRNA ptr; - PropertyRNA *prop; - int index_dummy; - uiBut *but; - - /* check if there's an active button taking depth value */ - if ((CTX_wm_window(C) != NULL) && - (but = UI_context_active_but_prop_get(C, &ptr, &prop, &index_dummy)) && - (but->type == UI_BTYPE_NUM) && - (prop != NULL)) - { - if ((RNA_property_type(prop) == PROP_FLOAT) && - (RNA_property_subtype(prop) & PROP_UNIT_LENGTH) && - (RNA_property_array_check(prop) == false)) - { - return 1; - } - } - else { - RegionView3D *rv3d = CTX_wm_region_view3d(C); - if (rv3d && rv3d->persp == RV3D_CAMOB) { - View3D *v3d = CTX_wm_view3d(C); - if (v3d->camera && v3d->camera->data && !ID_IS_LINKED(v3d->camera->data)) { - return 1; - } - } - } - - return 0; -} - -void UI_OT_eyedropper_depth(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Eyedropper Depth"; - ot->idname = "UI_OT_eyedropper_depth"; - ot->description = "Sample depth from the 3D view"; - - /* api callbacks */ - ot->invoke = depthdropper_invoke; - ot->modal = depthdropper_modal; - ot->cancel = depthdropper_cancel; - ot->exec = depthdropper_exec; - ot->poll = depthdropper_poll; - - /* flags */ - ot->flag = OPTYPE_BLOCKING | OPTYPE_INTERNAL; - - /* properties */ -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/* Eyedropper - */ - -/* NOTE: This is here (instead of in drivers.c) because we need access the button internals, - * which we cannot access outside of the interface module - */ - -/** \name Eyedropper (Driver Target) - * \{ */ - -typedef struct DriverDropper { - /* Destination property (i.e. where we'll add a driver) */ - PointerRNA ptr; - PropertyRNA *prop; - int index; - - // TODO: new target? -} DriverDropper; - -static bool driverdropper_init(bContext *C, wmOperator *op) -{ - DriverDropper *ddr; - uiBut *but; - - op->customdata = ddr = MEM_callocN(sizeof(DriverDropper), "DriverDropper"); - - but = UI_context_active_but_prop_get(C, &ddr->ptr, &ddr->prop, &ddr->index); - - if ((ddr->ptr.data == NULL) || - (ddr->prop == NULL) || - (RNA_property_editable(&ddr->ptr, ddr->prop) == false) || - (RNA_property_animateable(&ddr->ptr, ddr->prop) == false) || - (but->flag & UI_BUT_DRIVEN)) - { - return false; - } - - return true; -} - -static void driverdropper_exit(bContext *C, wmOperator *op) -{ - WM_cursor_modal_restore(CTX_wm_window(C)); - - if (op->customdata) { - MEM_freeN(op->customdata); - op->customdata = NULL; - } -} - -static void driverdropper_sample(bContext *C, wmOperator *op, const wmEvent *event) -{ - DriverDropper *ddr = (DriverDropper *)op->customdata; - uiBut *but = eyedropper_get_property_button_under_mouse(C, event); - - short mapping_type = RNA_enum_get(op->ptr, "mapping_type"); - short flag = 0; - - /* we can only add a driver if we know what RNA property it corresponds to */ - if (but == NULL) { - return; - } - else { - /* Get paths for src... */ - PointerRNA *target_ptr = &but->rnapoin; - PropertyRNA *target_prop = but->rnaprop; - int target_index = but->rnaindex; - - char *target_path = RNA_path_from_ID_to_property(target_ptr, target_prop); - - /* ... and destination */ - char *dst_path = BKE_animdata_driver_path_hack(C, &ddr->ptr, ddr->prop, NULL); - - /* Now create driver(s) */ - if (target_path && dst_path) { - int success = ANIM_add_driver_with_target(op->reports, - ddr->ptr.id.data, dst_path, ddr->index, - target_ptr->id.data, target_path, target_index, - flag, DRIVER_TYPE_PYTHON, mapping_type); - - if (success) { - /* send updates */ - UI_context_update_anim_flag(C); - DEG_relations_tag_update(CTX_data_main(C)); - DEG_id_tag_update(ddr->ptr.id.data, OB_RECALC_OB | OB_RECALC_DATA); - WM_event_add_notifier(C, NC_ANIMATION | ND_FCURVES_ORDER, NULL); // XXX - } - } - - /* cleanup */ - if (target_path) - MEM_freeN(target_path); - if (dst_path) - MEM_freeN(dst_path); - } -} - -static void driverdropper_cancel(bContext *C, wmOperator *op) -{ - driverdropper_exit(C, op); -} - -/* main modal status check */ -static int driverdropper_modal(bContext *C, wmOperator *op, const wmEvent *event) -{ - /* handle modal keymap */ - if (event->type == EVT_MODAL_MAP) { - switch (event->val) { - case EYE_MODAL_CANCEL: - driverdropper_cancel(C, op); - return OPERATOR_CANCELLED; - - case EYE_MODAL_SAMPLE_CONFIRM: - driverdropper_sample(C, op, event); - driverdropper_exit(C, op); - - return OPERATOR_FINISHED; - } - } - - return OPERATOR_RUNNING_MODAL; -} - -/* Modal Operator init */ -static int driverdropper_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) -{ - /* init */ - if (driverdropper_init(C, op)) { - WM_cursor_modal_set(CTX_wm_window(C), BC_EYEDROPPER_CURSOR); - - /* add temp handler */ - WM_event_add_modal_handler(C, op); - - return OPERATOR_RUNNING_MODAL; - } - else { - driverdropper_exit(C, op); - return OPERATOR_CANCELLED; - } -} - -/* Repeat operator */ -static int driverdropper_exec(bContext *C, wmOperator *op) -{ - /* init */ - if (driverdropper_init(C, op)) { - /* cleanup */ - driverdropper_exit(C, op); - - return OPERATOR_FINISHED; - } - else { - return OPERATOR_CANCELLED; - } -} - -static int driverdropper_poll(bContext *C) -{ - if (!CTX_wm_window(C)) return 0; - else return 1; -} - -void UI_OT_eyedropper_driver(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Eyedropper Driver"; - ot->idname = "UI_OT_eyedropper_driver"; - ot->description = "Pick a property to use as a driver target"; - - /* api callbacks */ - ot->invoke = driverdropper_invoke; - ot->modal = driverdropper_modal; - ot->cancel = driverdropper_cancel; - ot->exec = driverdropper_exec; - ot->poll = driverdropper_poll; - - /* flags */ - ot->flag = OPTYPE_BLOCKING | OPTYPE_INTERNAL | OPTYPE_UNDO; - - /* properties */ - RNA_def_enum(ot->srna, "mapping_type", prop_driver_create_mapping_types, 0, - "Mapping Type", "Method used to match target and driven properties"); -} - -/** \} */ diff --git a/source/blender/editors/interface/interface_eyedropper_color.c b/source/blender/editors/interface/interface_eyedropper_color.c new file mode 100644 index 00000000000..f3301d55284 --- /dev/null +++ b/source/blender/editors/interface/interface_eyedropper_color.c @@ -0,0 +1,356 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2009 Blender Foundation. + * All rights reserved. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/interface/interface_eyedropper_color.c + * \ingroup edinterface + * + * Eyedropper (RGB Color) + * + * Defines: + * - #UI_OT_eyedropper_color + */ + +#include "MEM_guardedalloc.h" + +#include "DNA_space_types.h" +#include "DNA_screen_types.h" + +#include "BLI_math_vector.h" + +#include "BKE_context.h" +#include "BKE_screen.h" + +#include "RNA_access.h" + +#include "BIF_gl.h" + +#include "UI_interface.h" + +#include "IMB_colormanagement.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "interface_intern.h" + +#include "ED_image.h" +#include "ED_node.h" +#include "ED_clip.h" + +#include "interface_eyedropper_intern.h" + +typedef struct Eyedropper { + struct ColorManagedDisplay *display; + + PointerRNA ptr; + PropertyRNA *prop; + int index; + + float init_col[3]; /* for resetting on cancel */ + + bool accum_start; /* has mouse been pressed */ + float accum_col[3]; + int accum_tot; +} Eyedropper; + +static bool eyedropper_init(bContext *C, wmOperator *op) +{ + Scene *scene = CTX_data_scene(C); + Eyedropper *eye; + + op->customdata = eye = MEM_callocN(sizeof(Eyedropper), "Eyedropper"); + + UI_context_active_but_prop_get(C, &eye->ptr, &eye->prop, &eye->index); + + if ((eye->ptr.data == NULL) || + (eye->prop == NULL) || + (RNA_property_editable(&eye->ptr, eye->prop) == false) || + (RNA_property_array_length(&eye->ptr, eye->prop) < 3) || + (RNA_property_type(eye->prop) != PROP_FLOAT)) + { + return false; + } + + if (RNA_property_subtype(eye->prop) != PROP_COLOR) { + const char *display_device; + float col[4]; + + display_device = scene->display_settings.display_device; + eye->display = IMB_colormanagement_display_get_named(display_device); + + /* store inital color */ + RNA_property_float_get_array(&eye->ptr, eye->prop, col); + if (eye->display) { + IMB_colormanagement_display_to_scene_linear_v3(col, eye->display); + } + copy_v3_v3(eye->init_col, col); + } + + return true; +} + +static void eyedropper_exit(bContext *C, wmOperator *op) +{ + WM_cursor_modal_restore(CTX_wm_window(C)); + + if (op->customdata) { + MEM_freeN(op->customdata); + op->customdata = NULL; + } +} + +/* *** eyedropper_color_ helper functions *** */ + +/** + * \brief get the color from the screen. + * + * Special check for image or nodes where we MAY have HDR pixels which don't display. + * + * \note Exposed by 'interface_eyedropper_intern.h' for use with color band picking. + */ +void eyedropper_color_sample_fl(bContext *C, int mx, int my, float r_col[3]) +{ + /* we could use some clever */ + bScreen *screen = CTX_wm_screen(C); + ScrArea *sa = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, mx, my); + const char *display_device = CTX_data_scene(C)->display_settings.display_device; + struct ColorManagedDisplay *display = IMB_colormanagement_display_get_named(display_device); + + if (sa) { + if (sa->spacetype == SPACE_IMAGE) { + ARegion *ar = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my); + if (ar) { + SpaceImage *sima = sa->spacedata.first; + int mval[2] = {mx - ar->winrct.xmin, + my - ar->winrct.ymin}; + + if (ED_space_image_color_sample(sima, ar, mval, r_col)) { + return; + } + } + } + else if (sa->spacetype == SPACE_NODE) { + ARegion *ar = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my); + if (ar) { + SpaceNode *snode = sa->spacedata.first; + int mval[2] = {mx - ar->winrct.xmin, + my - ar->winrct.ymin}; + + if (ED_space_node_color_sample(snode, ar, mval, r_col)) { + return; + } + } + } + else if (sa->spacetype == SPACE_CLIP) { + ARegion *ar = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my); + if (ar) { + SpaceClip *sc = sa->spacedata.first; + int mval[2] = {mx - ar->winrct.xmin, + my - ar->winrct.ymin}; + + if (ED_space_clip_color_sample(sc, ar, mval, r_col)) { + return; + } + } + } + } + + /* fallback to simple opengl picker */ + glReadBuffer(GL_FRONT); + glReadPixels(mx, my, 1, 1, GL_RGB, GL_FLOAT, r_col); + glReadBuffer(GL_BACK); + + IMB_colormanagement_display_to_scene_linear_v3(r_col, display); +} + +/* sets the sample color RGB, maintaining A */ +static void eyedropper_color_set(bContext *C, Eyedropper *eye, const float col[3]) +{ + float col_conv[4]; + + /* to maintain alpha */ + RNA_property_float_get_array(&eye->ptr, eye->prop, col_conv); + + /* convert from linear rgb space to display space */ + if (eye->display) { + copy_v3_v3(col_conv, col); + IMB_colormanagement_scene_linear_to_display_v3(col_conv, eye->display); + } + else { + copy_v3_v3(col_conv, col); + } + + RNA_property_float_set_array(&eye->ptr, eye->prop, col_conv); + + RNA_property_update(C, &eye->ptr, eye->prop); +} + +/* set sample from accumulated values */ +static void eyedropper_color_set_accum(bContext *C, Eyedropper *eye) +{ + float col[3]; + mul_v3_v3fl(col, eye->accum_col, 1.0f / (float)eye->accum_tot); + eyedropper_color_set(C, eye, col); +} + +/* single point sample & set */ +static void eyedropper_color_sample(bContext *C, Eyedropper *eye, int mx, int my) +{ + float col[3]; + eyedropper_color_sample_fl(C, mx, my, col); + eyedropper_color_set(C, eye, col); +} + +static void eyedropper_color_sample_accum(bContext *C, Eyedropper *eye, int mx, int my) +{ + float col[3]; + eyedropper_color_sample_fl(C, mx, my, col); + /* delay linear conversion */ + add_v3_v3(eye->accum_col, col); + eye->accum_tot++; +} + +static void eyedropper_cancel(bContext *C, wmOperator *op) +{ + Eyedropper *eye = op->customdata; + eyedropper_color_set(C, eye, eye->init_col); + eyedropper_exit(C, op); +} + +/* main modal status check */ +static int eyedropper_modal(bContext *C, wmOperator *op, const wmEvent *event) +{ + Eyedropper *eye = (Eyedropper *)op->customdata; + + /* handle modal keymap */ + if (event->type == EVT_MODAL_MAP) { + switch (event->val) { + case EYE_MODAL_CANCEL: + eyedropper_cancel(C, op); + return OPERATOR_CANCELLED; + case EYE_MODAL_SAMPLE_CONFIRM: + if (eye->accum_tot == 0) { + eyedropper_color_sample(C, eye, event->x, event->y); + } + else { + eyedropper_color_set_accum(C, eye); + } + eyedropper_exit(C, op); + return OPERATOR_FINISHED; + case EYE_MODAL_SAMPLE_BEGIN: + /* enable accum and make first sample */ + eye->accum_start = true; + eyedropper_color_sample_accum(C, eye, event->x, event->y); + break; + case EYE_MODAL_SAMPLE_RESET: + eye->accum_tot = 0; + zero_v3(eye->accum_col); + eyedropper_color_sample_accum(C, eye, event->x, event->y); + eyedropper_color_set_accum(C, eye); + break; + } + } + else if (event->type == MOUSEMOVE) { + if (eye->accum_start) { + /* button is pressed so keep sampling */ + eyedropper_color_sample_accum(C, eye, event->x, event->y); + eyedropper_color_set_accum(C, eye); + } + } + + return OPERATOR_RUNNING_MODAL; +} + +/* Modal Operator init */ +static int eyedropper_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +{ + /* init */ + if (eyedropper_init(C, op)) { + WM_cursor_modal_set(CTX_wm_window(C), BC_EYEDROPPER_CURSOR); + + /* add temp handler */ + WM_event_add_modal_handler(C, op); + + return OPERATOR_RUNNING_MODAL; + } + else { + eyedropper_exit(C, op); + return OPERATOR_CANCELLED; + } +} + +/* Repeat operator */ +static int eyedropper_exec(bContext *C, wmOperator *op) +{ + /* init */ + if (eyedropper_init(C, op)) { + + /* do something */ + + /* cleanup */ + eyedropper_exit(C, op); + + return OPERATOR_FINISHED; + } + else { + return OPERATOR_CANCELLED; + } +} + +static int eyedropper_poll(bContext *C) +{ + PointerRNA ptr; + PropertyRNA *prop; + int index_dummy; + uiBut *but; + + /* Only color buttons */ + if ((CTX_wm_window(C) != NULL) && + (but = UI_context_active_but_prop_get(C, &ptr, &prop, &index_dummy)) && + (but->type == UI_BTYPE_COLOR)) + { + return 1; + } + + return 0; +} + +void UI_OT_eyedropper_color(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Eyedropper"; + ot->idname = "UI_OT_eyedropper_color"; + ot->description = "Sample a color from the Blender Window to store in a property"; + + /* api callbacks */ + ot->invoke = eyedropper_invoke; + ot->modal = eyedropper_modal; + ot->cancel = eyedropper_cancel; + ot->exec = eyedropper_exec; + ot->poll = eyedropper_poll; + + /* flags */ + ot->flag = OPTYPE_BLOCKING | OPTYPE_INTERNAL; + + /* properties */ +} diff --git a/source/blender/editors/interface/interface_eyedropper_colorband.c b/source/blender/editors/interface/interface_eyedropper_colorband.c new file mode 100644 index 00000000000..b13d552dbeb --- /dev/null +++ b/source/blender/editors/interface/interface_eyedropper_colorband.c @@ -0,0 +1,337 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2009 Blender Foundation. + * All rights reserved. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/interface/interface_eyedropper_colorband.c + * \ingroup edinterface + * + * Eyedropper (Color Band). + * + * Operates by either: + * - Dragging a straight line, sampling pixels formed by the line to extract a gradient. + * - Clicking on points, adding each color to the end of the color-band. + * + * Defines: + * - #UI_OT_eyedropper_colorband + * - #UI_OT_eyedropper_colorband_point + */ + +#include "MEM_guardedalloc.h" + +#include "DNA_screen_types.h" + +#include "BLI_bitmap_draw_2d.h" +#include "BLI_math_vector.h" + +#include "BKE_context.h" +#include "BKE_colorband.h" + +#include "RNA_access.h" + +#include "UI_interface.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "interface_intern.h" + +#include "interface_eyedropper_intern.h" + +typedef struct Colorband_RNAUpdateCb { + PointerRNA ptr; + PropertyRNA *prop; +} Colorband_RNAUpdateCb; + +typedef struct EyedropperColorband { + int last_x, last_y; + /* Alpha is currently fixed at 1.0, may support in future. */ + float (*color_buffer)[4]; + int color_buffer_alloc; + int color_buffer_len; + bool sample_start; + ColorBand init_color_band; + ColorBand *color_band; + PointerRNA ptr; + PropertyRNA *prop; +} EyedropperColorband; + +/* For user-data only. */ +struct EyedropperColorband_Context { + bContext *context; + EyedropperColorband *eye; +}; + +static bool eyedropper_colorband_init(bContext *C, wmOperator *op) +{ + ColorBand *band = NULL; + EyedropperColorband *eye; + + uiBut *but = UI_context_active_but_get(C); + + if (but == NULL) { + /* pass */ + } + else if (but->type == UI_BTYPE_COLORBAND) { + /* When invoked with a hotkey, we can find the band in 'but->poin'. */ + band = (ColorBand *)but->poin; + } + else { + /* When invoked from a button it's in custom_data field. */ + band = (ColorBand *)but->custom_data; + } + + if (!band) + return false; + + op->customdata = eye = MEM_callocN(sizeof(EyedropperColorband), __func__); + eye->color_buffer_alloc = 16; + eye->color_buffer = MEM_mallocN(sizeof(*eye->color_buffer) * eye->color_buffer_alloc, __func__); + eye->color_buffer_len = 0; + eye->color_band = band; + eye->init_color_band = *eye->color_band; + eye->ptr = ((Colorband_RNAUpdateCb *)but->func_argN)->ptr; + eye->prop = ((Colorband_RNAUpdateCb *)but->func_argN)->prop; + + return true; +} + +static void eyedropper_colorband_sample_point(bContext *C, EyedropperColorband *eye, int mx, int my) +{ + if (eye->last_x != mx || eye->last_y != my) { + float col[4]; + col[3] = 1.0f; /* TODO: sample alpha */ + eyedropper_color_sample_fl(C, mx, my, col); + if (eye->color_buffer_len + 1 == eye->color_buffer_alloc) { + eye->color_buffer_alloc *= 2; + eye->color_buffer = MEM_reallocN(eye->color_buffer, sizeof(*eye->color_buffer) * eye->color_buffer_alloc); + } + copy_v4_v4(eye->color_buffer[eye->color_buffer_len], col); + eye->color_buffer_len += 1; + eye->last_x = mx; + eye->last_y = my; + } +} + +static bool eyedropper_colorband_sample_callback(int mx, int my, void *userdata) +{ + struct EyedropperColorband_Context *data = userdata; + bContext *C = data->context; + EyedropperColorband *eye = data->eye; + eyedropper_colorband_sample_point(C, eye, mx, my); + return true; +} + +static void eyedropper_colorband_sample_segment(bContext *C, EyedropperColorband *eye, int mx, int my) +{ + /* Since the mouse tends to move rather rapidly we use #BLI_bitmap_draw_2d_line_v2v2i + * to interpolate between the reported coordinates */ + struct EyedropperColorband_Context userdata = {C, eye}; + int p1[2] = {eye->last_x, eye->last_y}; + int p2[2] = {mx, my}; + BLI_bitmap_draw_2d_line_v2v2i(p1, p2, eyedropper_colorband_sample_callback, &userdata); +} + +static void eyedropper_colorband_exit(bContext *C, wmOperator *op) +{ + WM_cursor_modal_restore(CTX_wm_window(C)); + + if (op->customdata) { + EyedropperColorband *eye = op->customdata; + MEM_freeN(eye->color_buffer); + MEM_freeN(eye); + op->customdata = NULL; + } +} + +static void eyedropper_colorband_apply(bContext *C, wmOperator *op) +{ + EyedropperColorband *eye = op->customdata; + /* Always filter, avoids noise in resulting color-band. */ + bool filter_samples = true; + BKE_colorband_init_from_table_rgba(eye->color_band, eye->color_buffer, eye->color_buffer_len, filter_samples); + RNA_property_update(C, &eye->ptr, eye->prop); +} + +static void eyedropper_colorband_cancel(bContext *C, wmOperator *op) +{ + EyedropperColorband *eye = op->customdata; + *eye->color_band = eye->init_color_band; + RNA_property_update(C, &eye->ptr, eye->prop); + eyedropper_colorband_exit(C, op); +} + +/* main modal status check */ +static int eyedropper_colorband_modal(bContext *C, wmOperator *op, const wmEvent *event) +{ + EyedropperColorband *eye = op->customdata; + /* handle modal keymap */ + if (event->type == EVT_MODAL_MAP) { + switch (event->val) { + case EYE_MODAL_CANCEL: + eyedropper_colorband_cancel(C, op); + return OPERATOR_CANCELLED; + case EYE_MODAL_SAMPLE_CONFIRM: + eyedropper_colorband_sample_segment(C, eye, event->x, event->y); + eyedropper_colorband_apply(C, op); + eyedropper_colorband_exit(C, op); + return OPERATOR_FINISHED; + case EYE_MODAL_SAMPLE_BEGIN: + /* enable accum and make first sample */ + eye->sample_start = true; + eyedropper_colorband_sample_point(C, eye, event->x, event->y); + eyedropper_colorband_apply(C, op); + eye->last_x = event->x; + eye->last_y = event->y; + break; + case EYE_MODAL_SAMPLE_RESET: + break; + } + } + else if (event->type == MOUSEMOVE) { + if (eye->sample_start) { + eyedropper_colorband_sample_segment(C, eye, event->x, event->y); + eyedropper_colorband_apply(C, op); + } + } + return OPERATOR_RUNNING_MODAL; +} + +static int eyedropper_colorband_point_modal(bContext *C, wmOperator *op, const wmEvent *event) +{ + EyedropperColorband *eye = op->customdata; + /* handle modal keymap */ + if (event->type == EVT_MODAL_MAP) { + switch (event->val) { + case EYE_MODAL_POINT_CANCEL: + eyedropper_colorband_cancel(C, op); + return OPERATOR_CANCELLED; + case EYE_MODAL_POINT_CONFIRM: + eyedropper_colorband_apply(C, op); + eyedropper_colorband_exit(C, op); + return OPERATOR_FINISHED; + case EYE_MODAL_POINT_REMOVE_LAST: + if (eye->color_buffer_len > 0) { + eye->color_buffer_len -= 1; + eyedropper_colorband_apply(C, op); + } + break; + case EYE_MODAL_POINT_SAMPLE: + eyedropper_colorband_sample_point(C, eye, event->x, event->y); + eyedropper_colorband_apply(C, op); + if (eye->color_buffer_len == MAXCOLORBAND ) { + eyedropper_colorband_exit(C, op); + return OPERATOR_FINISHED; + } + break; + case EYE_MODAL_SAMPLE_RESET: + *eye->color_band = eye->init_color_band; + RNA_property_update(C, &eye->ptr, eye->prop); + eye->color_buffer_len = 0; + break; + } + } + return OPERATOR_RUNNING_MODAL; +} + + +/* Modal Operator init */ +static int eyedropper_colorband_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +{ + /* init */ + if (eyedropper_colorband_init(C, op)) { + WM_cursor_modal_set(CTX_wm_window(C), BC_EYEDROPPER_CURSOR); + + /* add temp handler */ + WM_event_add_modal_handler(C, op); + + return OPERATOR_RUNNING_MODAL; + } + else { + eyedropper_colorband_exit(C, op); + return OPERATOR_CANCELLED; + } +} + +/* Repeat operator */ +static int eyedropper_colorband_exec(bContext *C, wmOperator *op) +{ + /* init */ + if (eyedropper_colorband_init(C, op)) { + + /* do something */ + + /* cleanup */ + eyedropper_colorband_exit(C, op); + + return OPERATOR_FINISHED; + } + else { + return OPERATOR_CANCELLED; + } +} + +static int eyedropper_colorband_poll(bContext *C) +{ + uiBut *but = UI_context_active_but_get(C); + return (but && but->type == UI_BTYPE_COLORBAND); +} + + +void UI_OT_eyedropper_colorband(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Eyedropper colorband"; + ot->idname = "UI_OT_eyedropper_colorband"; + ot->description = "Sample a color band"; + + /* api callbacks */ + ot->invoke = eyedropper_colorband_invoke; + ot->modal = eyedropper_colorband_modal; + ot->cancel = eyedropper_colorband_cancel; + ot->exec = eyedropper_colorband_exec; + ot->poll = eyedropper_colorband_poll; + + /* flags */ + ot->flag = OPTYPE_BLOCKING | OPTYPE_INTERNAL; + + /* properties */ +} + +void UI_OT_eyedropper_colorband_point(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Eyedropper colorband (points)"; + ot->idname = "UI_OT_eyedropper_colorband_point"; + ot->description = "Pointsample a color band"; + + /* api callbacks */ + ot->invoke = eyedropper_colorband_invoke; + ot->modal = eyedropper_colorband_point_modal; + ot->cancel = eyedropper_colorband_cancel; + ot->exec = eyedropper_colorband_exec; + ot->poll = eyedropper_colorband_poll; + + /* flags */ + ot->flag = OPTYPE_BLOCKING | OPTYPE_INTERNAL; + + /* properties */ +} diff --git a/source/blender/editors/interface/interface_eyedropper_datablock.c b/source/blender/editors/interface/interface_eyedropper_datablock.c new file mode 100644 index 00000000000..f814048c0c0 --- /dev/null +++ b/source/blender/editors/interface/interface_eyedropper_datablock.c @@ -0,0 +1,351 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2009 Blender Foundation. + * All rights reserved. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/interface/interface_eyedropper_datablock.c + * \ingroup edinterface + * + * Eyedropper (ID data-blocks) + * + * Defines: + * - #UI_OT_eyedropper_id + */ + +#include "MEM_guardedalloc.h" + +#include "DNA_space_types.h" +#include "DNA_screen_types.h" +#include "DNA_object_types.h" + +#include "BLI_string.h" +#include "BLI_math_vector.h" + +#include "BLT_translation.h" + +#include "BKE_context.h" +#include "BKE_screen.h" +#include "BKE_report.h" +#include "BKE_idcode.h" + +#include "RNA_access.h" + +#include "UI_interface.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "ED_space_api.h" +#include "ED_screen.h" +#include "ED_view3d.h" + +#include "interface_intern.h" +#include "interface_eyedropper_intern.h" + +/** + * \note #DataDropper is only internal name to avoid confusion with other kinds of eye-droppers. + */ +typedef struct DataDropper { + PointerRNA ptr; + PropertyRNA *prop; + short idcode; + const char *idcode_name; + + ID *init_id; /* for resetting on cancel */ + + ARegionType *art; + void *draw_handle_pixel; + char name[200]; +} DataDropper; + + +static void datadropper_draw_cb(const struct bContext *C, ARegion *ar, void *arg) +{ + DataDropper *ddr = arg; + eyedropper_draw_cursor_text(C, ar, ddr->name); +} + + +static int datadropper_init(bContext *C, wmOperator *op) +{ + DataDropper *ddr; + int index_dummy; + StructRNA *type; + + SpaceType *st; + ARegionType *art; + + st = BKE_spacetype_from_id(SPACE_VIEW3D); + art = BKE_regiontype_from_id(st, RGN_TYPE_WINDOW); + + op->customdata = ddr = MEM_callocN(sizeof(DataDropper), "DataDropper"); + + UI_context_active_but_prop_get(C, &ddr->ptr, &ddr->prop, &index_dummy); + + if ((ddr->ptr.data == NULL) || + (ddr->prop == NULL) || + (RNA_property_editable(&ddr->ptr, ddr->prop) == false) || + (RNA_property_type(ddr->prop) != PROP_POINTER)) + { + return false; + } + + ddr->art = art; + ddr->draw_handle_pixel = ED_region_draw_cb_activate(art, datadropper_draw_cb, ddr, REGION_DRAW_POST_PIXEL); + + type = RNA_property_pointer_type(&ddr->ptr, ddr->prop); + ddr->idcode = RNA_type_to_ID_code(type); + BLI_assert(ddr->idcode != 0); + /* Note we can translate here (instead of on draw time), because this struct has very short lifetime. */ + ddr->idcode_name = TIP_(BKE_idcode_to_name(ddr->idcode)); + + PointerRNA ptr = RNA_property_pointer_get(&ddr->ptr, ddr->prop); + ddr->init_id = ptr.id.data; + + return true; +} + +static void datadropper_exit(bContext *C, wmOperator *op) +{ + WM_cursor_modal_restore(CTX_wm_window(C)); + + if (op->customdata) { + DataDropper *ddr = (DataDropper *)op->customdata; + + if (ddr->art) { + ED_region_draw_cb_exit(ddr->art, ddr->draw_handle_pixel); + } + + MEM_freeN(op->customdata); + + op->customdata = NULL; + } + + WM_event_add_mousemove(C); +} + +/* *** datadropper id helper functions *** */ +/** + * \brief get the ID from the screen. + * + */ +static void datadropper_id_sample_pt(bContext *C, DataDropper *ddr, int mx, int my, ID **r_id) +{ + /* we could use some clever */ + bScreen *screen = CTX_wm_screen(C); + ScrArea *sa = BKE_screen_find_area_xy(screen, -1, mx, my); + + ScrArea *area_prev = CTX_wm_area(C); + ARegion *ar_prev = CTX_wm_region(C); + + ddr->name[0] = '\0'; + + if (sa) { + if (sa->spacetype == SPACE_VIEW3D) { + ARegion *ar = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my); + if (ar) { + const int mval[2] = { + mx - ar->winrct.xmin, + my - ar->winrct.ymin}; + Base *base; + + CTX_wm_area_set(C, sa); + CTX_wm_region_set(C, ar); + + /* grr, always draw else we leave stale text */ + ED_region_tag_redraw(ar); + + base = ED_view3d_give_base_under_cursor(C, mval); + if (base) { + Object *ob = base->object; + ID *id = NULL; + if (ddr->idcode == ID_OB) { + id = (ID *)ob; + } + else if (ob->data) { + if (GS(((ID *)ob->data)->name) == ddr->idcode) { + id = (ID *)ob->data; + } + else { + BLI_snprintf(ddr->name, sizeof(ddr->name), "Incompatible, expected a %s", + ddr->idcode_name); + } + } + + if (id) { + BLI_snprintf(ddr->name, sizeof(ddr->name), "%s: %s", + ddr->idcode_name, id->name + 2); + *r_id = id; + } + } + } + } + } + + CTX_wm_area_set(C, area_prev); + CTX_wm_region_set(C, ar_prev); +} + +/* sets the ID, returns success */ +static bool datadropper_id_set(bContext *C, DataDropper *ddr, ID *id) +{ + PointerRNA ptr_value; + + RNA_id_pointer_create(id, &ptr_value); + + RNA_property_pointer_set(&ddr->ptr, ddr->prop, ptr_value); + + RNA_property_update(C, &ddr->ptr, ddr->prop); + + ptr_value = RNA_property_pointer_get(&ddr->ptr, ddr->prop); + + return (ptr_value.id.data == id); +} + +/* single point sample & set */ +static bool datadropper_id_sample(bContext *C, DataDropper *ddr, int mx, int my) +{ + ID *id = NULL; + + datadropper_id_sample_pt(C, ddr, mx, my, &id); + return datadropper_id_set(C, ddr, id); +} + +static void datadropper_cancel(bContext *C, wmOperator *op) +{ + DataDropper *ddr = op->customdata; + datadropper_id_set(C, ddr, ddr->init_id); + datadropper_exit(C, op); +} + +/* main modal status check */ +static int datadropper_modal(bContext *C, wmOperator *op, const wmEvent *event) +{ + DataDropper *ddr = (DataDropper *)op->customdata; + + /* handle modal keymap */ + if (event->type == EVT_MODAL_MAP) { + switch (event->val) { + case EYE_MODAL_CANCEL: + datadropper_cancel(C, op); + return OPERATOR_CANCELLED; + case EYE_MODAL_SAMPLE_CONFIRM: + { + bool success; + + success = datadropper_id_sample(C, ddr, event->x, event->y); + datadropper_exit(C, op); + + if (success) { + return OPERATOR_FINISHED; + } + else { + BKE_report(op->reports, RPT_WARNING, "Failed to set value"); + return OPERATOR_CANCELLED; + } + } + } + } + else if (event->type == MOUSEMOVE) { + ID *id = NULL; + datadropper_id_sample_pt(C, ddr, event->x, event->y, &id); + } + + return OPERATOR_RUNNING_MODAL; +} + +/* Modal Operator init */ +static int datadropper_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +{ + /* init */ + if (datadropper_init(C, op)) { + WM_cursor_modal_set(CTX_wm_window(C), BC_EYEDROPPER_CURSOR); + + /* add temp handler */ + WM_event_add_modal_handler(C, op); + + return OPERATOR_RUNNING_MODAL; + } + else { + datadropper_exit(C, op); + return OPERATOR_CANCELLED; + } +} + +/* Repeat operator */ +static int datadropper_exec(bContext *C, wmOperator *op) +{ + /* init */ + if (datadropper_init(C, op)) { + /* cleanup */ + datadropper_exit(C, op); + + return OPERATOR_FINISHED; + } + else { + return OPERATOR_CANCELLED; + } +} + +static int datadropper_poll(bContext *C) +{ + PointerRNA ptr; + PropertyRNA *prop; + int index_dummy; + uiBut *but; + + /* data dropper only supports object data */ + if ((CTX_wm_window(C) != NULL) && + (but = UI_context_active_but_prop_get(C, &ptr, &prop, &index_dummy)) && + (but->type == UI_BTYPE_SEARCH_MENU) && + (but->flag & UI_BUT_VALUE_CLEAR)) + { + if (prop && RNA_property_type(prop) == PROP_POINTER) { + StructRNA *type = RNA_property_pointer_type(&ptr, prop); + const short idcode = RNA_type_to_ID_code(type); + if ((idcode == ID_OB) || OB_DATA_SUPPORT_ID(idcode)) { + return 1; + } + } + } + + return 0; +} + +void UI_OT_eyedropper_id(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Eyedropper Data-Block"; + ot->idname = "UI_OT_eyedropper_id"; + ot->description = "Sample a data-block from the 3D View to store in a property"; + + /* api callbacks */ + ot->invoke = datadropper_invoke; + ot->modal = datadropper_modal; + ot->cancel = datadropper_cancel; + ot->exec = datadropper_exec; + ot->poll = datadropper_poll; + + /* flags */ + ot->flag = OPTYPE_BLOCKING | OPTYPE_INTERNAL; + + /* properties */ +} diff --git a/source/blender/editors/interface/interface_eyedropper_depth.c b/source/blender/editors/interface/interface_eyedropper_depth.c new file mode 100644 index 00000000000..6e85d091fdb --- /dev/null +++ b/source/blender/editors/interface/interface_eyedropper_depth.c @@ -0,0 +1,391 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2009 Blender Foundation. + * All rights reserved. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/interface/interface_eyedropper_depth.c + * \ingroup edinterface + * + * This file defines an eyedropper for picking 3D depth value (primary use is depth-of-field). + * + * Defines: + * - #UI_OT_eyedropper_depth + */ + +#include "MEM_guardedalloc.h" + +#include "DNA_space_types.h" +#include "DNA_screen_types.h" +#include "DNA_object_types.h" +#include "DNA_view3d_types.h" + +#include "BLI_string.h" +#include "BLI_math_vector.h" + +#include "BKE_context.h" +#include "BKE_screen.h" +#include "BKE_unit.h" + +#include "DEG_depsgraph.h" + +#include "RNA_access.h" + +#include "UI_interface.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "ED_screen.h" +#include "ED_space_api.h" +#include "ED_view3d.h" + +#include "interface_intern.h" +#include "interface_eyedropper_intern.h" + +/** + * \note #DepthDropper is only internal name to avoid confusion with other kinds of eye-droppers. + */ +typedef struct DepthDropper { + PointerRNA ptr; + PropertyRNA *prop; + + float init_depth; /* for resetting on cancel */ + + bool accum_start; /* has mouse been presed */ + float accum_depth; + int accum_tot; + + ARegionType *art; + void *draw_handle_pixel; + char name[200]; +} DepthDropper; + + +static void depthdropper_draw_cb(const struct bContext *C, ARegion *ar, void *arg) +{ + DepthDropper *ddr = arg; + eyedropper_draw_cursor_text(C, ar, ddr->name); +} + + +static int depthdropper_init(bContext *C, wmOperator *op) +{ + DepthDropper *ddr; + int index_dummy; + + SpaceType *st; + ARegionType *art; + + st = BKE_spacetype_from_id(SPACE_VIEW3D); + art = BKE_regiontype_from_id(st, RGN_TYPE_WINDOW); + + op->customdata = ddr = MEM_callocN(sizeof(DepthDropper), "DepthDropper"); + + UI_context_active_but_prop_get(C, &ddr->ptr, &ddr->prop, &index_dummy); + + /* fallback to the active camera's dof */ + if (ddr->prop == NULL) { + RegionView3D *rv3d = CTX_wm_region_view3d(C); + if (rv3d && rv3d->persp == RV3D_CAMOB) { + View3D *v3d = CTX_wm_view3d(C); + if (v3d->camera && v3d->camera->data && !ID_IS_LINKED(v3d->camera->data)) { + RNA_id_pointer_create(v3d->camera->data, &ddr->ptr); + ddr->prop = RNA_struct_find_property(&ddr->ptr, "dof_distance"); + } + } + } + + if ((ddr->ptr.data == NULL) || + (ddr->prop == NULL) || + (RNA_property_editable(&ddr->ptr, ddr->prop) == false) || + (RNA_property_type(ddr->prop) != PROP_FLOAT)) + { + return false; + } + + ddr->art = art; + ddr->draw_handle_pixel = ED_region_draw_cb_activate(art, depthdropper_draw_cb, ddr, REGION_DRAW_POST_PIXEL); + ddr->init_depth = RNA_property_float_get(&ddr->ptr, ddr->prop); + + return true; +} + +static void depthdropper_exit(bContext *C, wmOperator *op) +{ + WM_cursor_modal_restore(CTX_wm_window(C)); + + if (op->customdata) { + DepthDropper *ddr = (DepthDropper *)op->customdata; + + if (ddr->art) { + ED_region_draw_cb_exit(ddr->art, ddr->draw_handle_pixel); + } + + MEM_freeN(op->customdata); + + op->customdata = NULL; + } +} + +/* *** depthdropper id helper functions *** */ +/** + * \brief get the ID from the screen. + * + */ +static void depthdropper_depth_sample_pt(bContext *C, DepthDropper *ddr, int mx, int my, float *r_depth) +{ + /* we could use some clever */ + bScreen *screen = CTX_wm_screen(C); + ScrArea *sa = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, mx, my); + Scene *scene = CTX_data_scene(C); + + UnitSettings *unit = &scene->unit; + const bool do_split = (unit->flag & USER_UNIT_OPT_SPLIT) != 0; + + ScrArea *area_prev = CTX_wm_area(C); + ARegion *ar_prev = CTX_wm_region(C); + + ddr->name[0] = '\0'; + + if (sa) { + if (sa->spacetype == SPACE_VIEW3D) { + ARegion *ar = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my); + if (ar) { + struct Depsgraph *graph = CTX_data_depsgraph(C); + View3D *v3d = sa->spacedata.first; + RegionView3D *rv3d = ar->regiondata; + /* weak, we could pass in some reference point */ + const float *view_co = v3d->camera ? v3d->camera->obmat[3] : rv3d->viewinv[3]; + const int mval[2] = { + mx - ar->winrct.xmin, + my - ar->winrct.ymin}; + float co[3]; + + EvaluationContext eval_ctx; + CTX_data_eval_ctx(C, &eval_ctx); + + CTX_wm_area_set(C, sa); + CTX_wm_region_set(C, ar); + + /* grr, always draw else we leave stale text */ + ED_region_tag_redraw(ar); + + view3d_operator_needs_opengl(C); + + if (ED_view3d_autodist(&eval_ctx, graph, ar, v3d, mval, co, true, NULL)) { + const float mval_center_fl[2] = { + (float)ar->winx / 2, + (float)ar->winy / 2}; + float co_align[3]; + + /* quick way to get view-center aligned point */ + ED_view3d_win_to_3d(v3d, ar, co, mval_center_fl, co_align); + + *r_depth = len_v3v3(view_co, co_align); + + bUnit_AsString(ddr->name, sizeof(ddr->name), + (double)*r_depth, + 4, unit->system, B_UNIT_LENGTH, do_split, false); + } + else { + BLI_strncpy(ddr->name, "Nothing under cursor", sizeof(ddr->name)); + } + } + } + } + + CTX_wm_area_set(C, area_prev); + CTX_wm_region_set(C, ar_prev); +} + +/* sets the sample depth RGB, maintaining A */ +static void depthdropper_depth_set(bContext *C, DepthDropper *ddr, const float depth) +{ + RNA_property_float_set(&ddr->ptr, ddr->prop, depth); + RNA_property_update(C, &ddr->ptr, ddr->prop); +} + +/* set sample from accumulated values */ +static void depthdropper_depth_set_accum(bContext *C, DepthDropper *ddr) +{ + float depth = ddr->accum_depth; + if (ddr->accum_tot) { + depth /= (float)ddr->accum_tot; + } + depthdropper_depth_set(C, ddr, depth); +} + +/* single point sample & set */ +static void depthdropper_depth_sample(bContext *C, DepthDropper *ddr, int mx, int my) +{ + float depth = -1.0f; + if (depth != -1.0f) { + depthdropper_depth_sample_pt(C, ddr, mx, my, &depth); + depthdropper_depth_set(C, ddr, depth); + } +} + +static void depthdropper_depth_sample_accum(bContext *C, DepthDropper *ddr, int mx, int my) +{ + float depth = -1.0f; + depthdropper_depth_sample_pt(C, ddr, mx, my, &depth); + if (depth != -1.0f) { + ddr->accum_depth += depth; + ddr->accum_tot++; + } +} + +static void depthdropper_cancel(bContext *C, wmOperator *op) +{ + DepthDropper *ddr = op->customdata; + depthdropper_depth_set(C, ddr, ddr->init_depth); + depthdropper_exit(C, op); +} + +/* main modal status check */ +static int depthdropper_modal(bContext *C, wmOperator *op, const wmEvent *event) +{ + DepthDropper *ddr = (DepthDropper *)op->customdata; + + /* handle modal keymap */ + if (event->type == EVT_MODAL_MAP) { + switch (event->val) { + case EYE_MODAL_CANCEL: + depthdropper_cancel(C, op); + return OPERATOR_CANCELLED; + case EYE_MODAL_SAMPLE_CONFIRM: + if (ddr->accum_tot == 0) { + depthdropper_depth_sample(C, ddr, event->x, event->y); + } + else { + depthdropper_depth_set_accum(C, ddr); + } + depthdropper_exit(C, op); + return OPERATOR_FINISHED; + case EYE_MODAL_SAMPLE_BEGIN: + /* enable accum and make first sample */ + ddr->accum_start = true; + depthdropper_depth_sample_accum(C, ddr, event->x, event->y); + break; + case EYE_MODAL_SAMPLE_RESET: + ddr->accum_tot = 0; + ddr->accum_depth = 0.0f; + depthdropper_depth_sample_accum(C, ddr, event->x, event->y); + depthdropper_depth_set_accum(C, ddr); + break; + } + } + else if (event->type == MOUSEMOVE) { + if (ddr->accum_start) { + /* button is pressed so keep sampling */ + depthdropper_depth_sample_accum(C, ddr, event->x, event->y); + depthdropper_depth_set_accum(C, ddr); + } + } + + return OPERATOR_RUNNING_MODAL; +} + +/* Modal Operator init */ +static int depthdropper_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +{ + /* init */ + if (depthdropper_init(C, op)) { + WM_cursor_modal_set(CTX_wm_window(C), BC_EYEDROPPER_CURSOR); + + /* add temp handler */ + WM_event_add_modal_handler(C, op); + + return OPERATOR_RUNNING_MODAL; + } + else { + depthdropper_exit(C, op); + return OPERATOR_CANCELLED; + } +} + +/* Repeat operator */ +static int depthdropper_exec(bContext *C, wmOperator *op) +{ + /* init */ + if (depthdropper_init(C, op)) { + /* cleanup */ + depthdropper_exit(C, op); + + return OPERATOR_FINISHED; + } + else { + return OPERATOR_CANCELLED; + } +} + +static int depthdropper_poll(bContext *C) +{ + PointerRNA ptr; + PropertyRNA *prop; + int index_dummy; + uiBut *but; + + /* check if there's an active button taking depth value */ + if ((CTX_wm_window(C) != NULL) && + (but = UI_context_active_but_prop_get(C, &ptr, &prop, &index_dummy)) && + (but->type == UI_BTYPE_NUM) && + (prop != NULL)) + { + if ((RNA_property_type(prop) == PROP_FLOAT) && + (RNA_property_subtype(prop) & PROP_UNIT_LENGTH) && + (RNA_property_array_check(prop) == false)) + { + return 1; + } + } + else { + RegionView3D *rv3d = CTX_wm_region_view3d(C); + if (rv3d && rv3d->persp == RV3D_CAMOB) { + View3D *v3d = CTX_wm_view3d(C); + if (v3d->camera && v3d->camera->data && !ID_IS_LINKED(v3d->camera->data)) { + return 1; + } + } + } + + return 0; +} + +void UI_OT_eyedropper_depth(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Eyedropper Depth"; + ot->idname = "UI_OT_eyedropper_depth"; + ot->description = "Sample depth from the 3D view"; + + /* api callbacks */ + ot->invoke = depthdropper_invoke; + ot->modal = depthdropper_modal; + ot->cancel = depthdropper_cancel; + ot->exec = depthdropper_exec; + ot->poll = depthdropper_poll; + + /* flags */ + ot->flag = OPTYPE_BLOCKING | OPTYPE_INTERNAL; + + /* properties */ +} diff --git a/source/blender/editors/interface/interface_eyedropper_driver.c b/source/blender/editors/interface/interface_eyedropper_driver.c new file mode 100644 index 00000000000..50a8473135a --- /dev/null +++ b/source/blender/editors/interface/interface_eyedropper_driver.c @@ -0,0 +1,234 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2009 Blender Foundation. + * All rights reserved. + * + * Contributor(s): Blender Foundation, Joshua Leung + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/interface/interface_eyedropper_driver.c + * \ingroup edinterface + * + * Eyedropper (Animation Driver Targets). + * + * Defines: + * - #UI_OT_eyedropper_driver + */ + +#include "MEM_guardedalloc.h" + +#include "DNA_anim_types.h" +#include "DNA_screen_types.h" +#include "DNA_object_types.h" + +#include "BLI_math_vector.h" + +#include "BKE_context.h" +#include "BKE_animsys.h" + +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_build.h" + +#include "RNA_access.h" +#include "RNA_define.h" + +#include "UI_interface.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "ED_keyframing.h" + +#include "interface_intern.h" +#include "interface_eyedropper_intern.h" + +typedef struct DriverDropper { + /* Destination property (i.e. where we'll add a driver) */ + PointerRNA ptr; + PropertyRNA *prop; + int index; + + // TODO: new target? +} DriverDropper; + +static bool driverdropper_init(bContext *C, wmOperator *op) +{ + DriverDropper *ddr; + uiBut *but; + + op->customdata = ddr = MEM_callocN(sizeof(DriverDropper), "DriverDropper"); + + but = UI_context_active_but_prop_get(C, &ddr->ptr, &ddr->prop, &ddr->index); + + if ((ddr->ptr.data == NULL) || + (ddr->prop == NULL) || + (RNA_property_editable(&ddr->ptr, ddr->prop) == false) || + (RNA_property_animateable(&ddr->ptr, ddr->prop) == false) || + (but->flag & UI_BUT_DRIVEN)) + { + return false; + } + + return true; +} + +static void driverdropper_exit(bContext *C, wmOperator *op) +{ + WM_cursor_modal_restore(CTX_wm_window(C)); + + if (op->customdata) { + MEM_freeN(op->customdata); + op->customdata = NULL; + } +} + +static void driverdropper_sample(bContext *C, wmOperator *op, const wmEvent *event) +{ + DriverDropper *ddr = (DriverDropper *)op->customdata; + uiBut *but = eyedropper_get_property_button_under_mouse(C, event); + + short mapping_type = RNA_enum_get(op->ptr, "mapping_type"); + short flag = 0; + + /* we can only add a driver if we know what RNA property it corresponds to */ + if (but == NULL) { + return; + } + else { + /* Get paths for src... */ + PointerRNA *target_ptr = &but->rnapoin; + PropertyRNA *target_prop = but->rnaprop; + int target_index = but->rnaindex; + + char *target_path = RNA_path_from_ID_to_property(target_ptr, target_prop); + + /* ... and destination */ + char *dst_path = BKE_animdata_driver_path_hack(C, &ddr->ptr, ddr->prop, NULL); + + /* Now create driver(s) */ + if (target_path && dst_path) { + int success = ANIM_add_driver_with_target(op->reports, + ddr->ptr.id.data, dst_path, ddr->index, + target_ptr->id.data, target_path, target_index, + flag, DRIVER_TYPE_PYTHON, mapping_type); + + if (success) { + /* send updates */ + UI_context_update_anim_flag(C); + DEG_relations_tag_update(CTX_data_main(C)); + DEG_id_tag_update(ddr->ptr.id.data, OB_RECALC_OB | OB_RECALC_DATA); + WM_event_add_notifier(C, NC_ANIMATION | ND_FCURVES_ORDER, NULL); // XXX + } + } + + /* cleanup */ + if (target_path) + MEM_freeN(target_path); + if (dst_path) + MEM_freeN(dst_path); + } +} + +static void driverdropper_cancel(bContext *C, wmOperator *op) +{ + driverdropper_exit(C, op); +} + +/* main modal status check */ +static int driverdropper_modal(bContext *C, wmOperator *op, const wmEvent *event) +{ + /* handle modal keymap */ + if (event->type == EVT_MODAL_MAP) { + switch (event->val) { + case EYE_MODAL_CANCEL: + driverdropper_cancel(C, op); + return OPERATOR_CANCELLED; + + case EYE_MODAL_SAMPLE_CONFIRM: + driverdropper_sample(C, op, event); + driverdropper_exit(C, op); + + return OPERATOR_FINISHED; + } + } + + return OPERATOR_RUNNING_MODAL; +} + +/* Modal Operator init */ +static int driverdropper_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +{ + /* init */ + if (driverdropper_init(C, op)) { + WM_cursor_modal_set(CTX_wm_window(C), BC_EYEDROPPER_CURSOR); + + /* add temp handler */ + WM_event_add_modal_handler(C, op); + + return OPERATOR_RUNNING_MODAL; + } + else { + driverdropper_exit(C, op); + return OPERATOR_CANCELLED; + } +} + +/* Repeat operator */ +static int driverdropper_exec(bContext *C, wmOperator *op) +{ + /* init */ + if (driverdropper_init(C, op)) { + /* cleanup */ + driverdropper_exit(C, op); + + return OPERATOR_FINISHED; + } + else { + return OPERATOR_CANCELLED; + } +} + +static int driverdropper_poll(bContext *C) +{ + if (!CTX_wm_window(C)) return 0; + else return 1; +} + +void UI_OT_eyedropper_driver(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Eyedropper Driver"; + ot->idname = "UI_OT_eyedropper_driver"; + ot->description = "Pick a property to use as a driver target"; + + /* api callbacks */ + ot->invoke = driverdropper_invoke; + ot->modal = driverdropper_modal; + ot->cancel = driverdropper_cancel; + ot->exec = driverdropper_exec; + ot->poll = driverdropper_poll; + + /* flags */ + ot->flag = OPTYPE_BLOCKING | OPTYPE_INTERNAL | OPTYPE_UNDO; + + /* properties */ + RNA_def_enum(ot->srna, "mapping_type", prop_driver_create_mapping_types, 0, + "Mapping Type", "Method used to match target and driven properties"); +} diff --git a/source/blender/editors/interface/interface_eyedropper_intern.h b/source/blender/editors/interface/interface_eyedropper_intern.h new file mode 100644 index 00000000000..18935c6cc9f --- /dev/null +++ b/source/blender/editors/interface/interface_eyedropper_intern.h @@ -0,0 +1,54 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/interface/interface_eyedropper_intern.h + * \ingroup edinterface + * + * Share between interface_eyedropper_*.c files. + */ + +#ifndef __INTERFACE_EYEDROPPER_INTERN_H__ +#define __INTERFACE_EYEDROPPER_INTERN_H__ + +/* interface_eyedropper.c */ +void eyedropper_draw_cursor_text(const struct bContext *C, const struct ARegion *ar, const char *name); +uiBut *eyedropper_get_property_button_under_mouse(bContext *C, const wmEvent *event); + +/* interface_eyedropper_color.c (expose for color-band picker) */ +void eyedropper_color_sample_fl(bContext *C, int mx, int my, float r_col[3]); + +/* Used for most eye-dropper operators. */ +enum { + EYE_MODAL_CANCEL = 1, + EYE_MODAL_SAMPLE_CONFIRM, + EYE_MODAL_SAMPLE_BEGIN, + EYE_MODAL_SAMPLE_RESET, +}; + +/* Color-band point sample. */ +enum { + EYE_MODAL_POINT_CANCEL = 1, + EYE_MODAL_POINT_SAMPLE, + EYE_MODAL_POINT_CONFIRM, + EYE_MODAL_POINT_RESET, + EYE_MODAL_POINT_REMOVE_LAST, +}; + +#endif /* __INTERFACE_EYEDROPPER_INTERN_H__ */ diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index 53505fc39a4..9ccb47938d2 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -61,6 +61,7 @@ #include "PIL_time.h" +#include "BKE_colorband.h" #include "BKE_blender_undo.h" #include "BKE_brush.h" #include "BKE_colortools.h" @@ -68,7 +69,6 @@ #include "BKE_idprop.h" #include "BKE_report.h" #include "BKE_screen.h" -#include "BKE_texture.h" #include "BKE_tracking.h" #include "BKE_unit.h" #include "BKE_paint.h" @@ -130,7 +130,6 @@ static bool ui_mouse_motion_keynav_test(struct uiKeyNavLock *keynav, const wmEve /***************** structs and defines ****************/ -#define BUTTON_TOOLTIP_DELAY 0.500 #define BUTTON_FLASH_DELAY 0.020 #define MENU_SCROLL_INTERVAL 0.1 #define PIE_MENU_INTERVAL 0.01 @@ -297,8 +296,6 @@ typedef struct uiHandleButtonData { ColorBand *coba; /* tooltip */ - ARegion *tooltip; - wmTimer *tooltiptimer; unsigned int tooltip_force : 1; /* auto open */ @@ -2295,7 +2292,7 @@ static void ui_but_copy_paste(bContext *C, uiBut *but, uiHandleButtonData *data, char buf_copy[UI_MAX_DRAW_STR]; if (array_length == 4) { - values[3] = RNA_property_float_get_index(&but->rnapoin, but->rnaprop, 3); + values[3] = RNA_property_float_get_index(&but->rnapoin, but->rnaprop, 3); } else { values[3] = 0.0f; @@ -5971,7 +5968,7 @@ static bool ui_numedit_but_COLORBAND(uiBut *but, uiHandleButtonData *data, int m data->dragcbd->pos += dx; CLAMP(data->dragcbd->pos, 0.0f, 1.0f); - colorband_update_sort(data->coba); + BKE_colorband_update_sort(data->coba); data->dragcbd = data->coba->data + data->coba->cur; /* because qsort */ data->draglastx = mx; @@ -6001,7 +5998,7 @@ static int ui_do_but_COLORBAND( if (event->ctrl) { /* insert new key on mouse location */ float pos = ((float)(mx - but->rect.xmin)) / BLI_rctf_size_x(&but->rect); - colorband_element_add(coba, pos); + BKE_colorband_element_add(coba, pos); button_activate_state(C, but, BUTTON_STATE_EXIT); } else { @@ -6022,6 +6019,7 @@ static int ui_do_but_COLORBAND( } data->dragcbd = coba->data + coba->cur; + data->dragfstart = data->dragcbd->pos; button_activate_state(C, but, BUTTON_STATE_NUM_EDITING); } @@ -6038,7 +6036,15 @@ static int ui_do_but_COLORBAND( else if (event->type == LEFTMOUSE && event->val != KM_PRESS) { button_activate_state(C, but, BUTTON_STATE_EXIT); } - + else if (ELEM(event->type, ESCKEY, RIGHTMOUSE)) { + if (event->val == KM_PRESS) { + data->dragcbd->pos = data->dragfstart; + BKE_colorband_update_sort(data->coba); + data->cancel = true; + data->escapecancel = true; + button_activate_state(C, but, BUTTON_STATE_EXIT); + } + } return WM_UI_HANDLER_BREAK; } @@ -6047,8 +6053,8 @@ static int ui_do_but_COLORBAND( static bool ui_numedit_but_CURVE( uiBlock *block, uiBut *but, uiHandleButtonData *data, - int evtx, int evty, - bool snap, const bool shift) + int evtx, int evty, + bool snap, const bool shift) { CurveMapping *cumap = (CurveMapping *)but->poin; CurveMap *cuma = cumap->cm + cumap->cur; @@ -7733,12 +7739,12 @@ static bool button_modal_state(uiHandleButtonState state) */ void UI_but_tooltip_refresh(bContext *C, uiBut *but) { - uiHandleButtonData *data; - - data = but->active; - if (data && data->tooltip) { - ui_tooltip_free(C, data->tooltip); - data->tooltip = ui_tooltip_create(C, data->region, but); + uiHandleButtonData *data = but->active; + if (data) { + bScreen *sc = WM_window_get_active_screen(data->window); + if (sc->tool_tip && sc->tool_tip->region) { + WM_tooltip_refresh(C, data->window); + } } } @@ -7749,39 +7755,38 @@ void UI_but_tooltip_timer_remove(bContext *C, uiBut *but) data = but->active; if (data) { - - if (data->tooltiptimer) { - WM_event_remove_timer(data->wm, data->window, data->tooltiptimer); - data->tooltiptimer = NULL; - } - if (data->tooltip) { - ui_tooltip_free(C, data->tooltip); - data->tooltip = NULL; - } - if (data->autoopentimer) { WM_event_remove_timer(data->wm, data->window, data->autoopentimer); data->autoopentimer = NULL; } + + if (data->window) { + WM_tooltip_clear(C, data->window); + } } } +static ARegion *ui_but_tooltip_init(bContext *C, ARegion *ar, bool *r_exit_on_event) +{ + uiBut *but = UI_region_active_but_get(ar); + *r_exit_on_event = false; + if (but) { + return UI_tooltip_create_from_button(C, ar, but); + } + return NULL; +} + static void button_tooltip_timer_reset(bContext *C, uiBut *but) { wmWindowManager *wm = CTX_wm_manager(C); - uiHandleButtonData *data; - - data = but->active; + uiHandleButtonData *data = but->active; - if (data->tooltiptimer) { - WM_event_remove_timer(data->wm, data->window, data->tooltiptimer); - data->tooltiptimer = NULL; - } + WM_tooltip_timer_clear(C, data->window); if ((U.flag & USER_TOOLTIPS) || (data->tooltip_force)) { if (!but->block->tooltipdisabled) { if (!wm->drags.first) { - data->tooltiptimer = WM_event_add_timer(data->wm, data->window, TIMER, BUTTON_TOOLTIP_DELAY); + WM_tooltip_timer_init(C, data->window, data->region, ui_but_tooltip_init); } } } @@ -8141,12 +8146,10 @@ void ui_but_active_free(const bContext *C, uiBut *but) } /* returns the active button with an optional checking function */ -static uiBut *ui_context_button_active(const bContext *C, bool (*but_check_cb)(uiBut *)) +static uiBut *ui_context_button_active(ARegion *ar, bool (*but_check_cb)(uiBut *)) { uiBut *but_found = NULL; - ARegion *ar = CTX_wm_region(C); - while (ar) { uiBlock *block; uiBut *but, *activebut = NULL; @@ -8189,12 +8192,17 @@ static bool ui_context_rna_button_active_test(uiBut *but) } static uiBut *ui_context_rna_button_active(const bContext *C) { - return ui_context_button_active(C, ui_context_rna_button_active_test); + return ui_context_button_active(CTX_wm_region(C), ui_context_rna_button_active_test); } uiBut *UI_context_active_but_get(const struct bContext *C) { - return ui_context_button_active(C, NULL); + return ui_context_button_active(CTX_wm_region(C), NULL); +} + +uiBut *UI_region_active_but_get(ARegion *ar) +{ + return ui_context_button_active(ar, NULL); } /** @@ -8477,16 +8485,8 @@ static int ui_handle_button_event(bContext *C, const wmEvent *event, uiBut *but) } case TIMER: { - /* handle tooltip timer */ - if (event->customdata == data->tooltiptimer) { - WM_event_remove_timer(data->wm, data->window, data->tooltiptimer); - data->tooltiptimer = NULL; - - if (!data->tooltip) - data->tooltip = ui_tooltip_create(C, data->region, but); - } /* handle menu auto open timer */ - else if (event->customdata == data->autoopentimer) { + if (event->customdata == data->autoopentimer) { WM_event_remove_timer(data->wm, data->window, data->autoopentimer); data->autoopentimer = NULL; diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h index 6f450093d30..b2f7d400254 100644 --- a/source/blender/editors/interface/interface_intern.h +++ b/source/blender/editors/interface/interface_intern.h @@ -595,8 +595,7 @@ struct uiPopupBlockHandle { /* interface_region_*.c */ /* interface_region_tooltip.c */ -struct ARegion *ui_tooltip_create(struct bContext *C, struct ARegion *butregion, uiBut *but); -void ui_tooltip_free(struct bContext *C, struct ARegion *ar); +/* exposed as public API in UI_interface.h */ /* interface_region_color_picker.c */ void ui_rgb_to_color_picker_compat_v(const float rgb[3], float r_cp[3]); @@ -764,9 +763,22 @@ void ui_but_anim_autokey(struct bContext *C, uiBut *but, struct Scene *scene, fl /* interface_eyedropper.c */ struct wmKeyMap *eyedropper_modal_keymap(struct wmKeyConfig *keyconf); +struct wmKeyMap *eyedropper_colorband_modal_keymap(struct wmKeyConfig *keyconf); + +/* interface_eyedropper_color.c */ void UI_OT_eyedropper_color(struct wmOperatorType *ot); + +/* interface_eyedropper_colorband.c */ +void UI_OT_eyedropper_colorband(struct wmOperatorType *ot); +void UI_OT_eyedropper_colorband_point(struct wmOperatorType *ot); + +/* interface_eyedropper_datablock.c */ void UI_OT_eyedropper_id(struct wmOperatorType *ot); + +/* interface_eyedropper_depth.c */ void UI_OT_eyedropper_depth(struct wmOperatorType *ot); + +/* interface_eyedropper_driver.c */ void UI_OT_eyedropper_driver(struct wmOperatorType *ot); /* interface_util.c */ diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c index 645afc03603..27d58c3be1b 100644 --- a/source/blender/editors/interface/interface_layout.c +++ b/source/blender/editors/interface/interface_layout.c @@ -1746,7 +1746,7 @@ void ui_but_add_search(uiBut *but, PointerRNA *ptr, PropertyRNA *prop, PointerRN } else if (but->type == UI_BTYPE_SEARCH_MENU) { /* In case we fail to find proper searchprop, so other code might have already set but->type to search menu... */ - but->type = UI_BTYPE_LABEL; + but->flag |= UI_BUT_DISABLED; } } diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c index bbcd10270d5..16525dfbc9e 100644 --- a/source/blender/editors/interface/interface_ops.c +++ b/source/blender/editors/interface/interface_ops.c @@ -1466,6 +1466,8 @@ void ED_operatortypes_ui(void) /* external */ WM_operatortype_append(UI_OT_eyedropper_color); + WM_operatortype_append(UI_OT_eyedropper_colorband); + WM_operatortype_append(UI_OT_eyedropper_colorband_point); WM_operatortype_append(UI_OT_eyedropper_id); WM_operatortype_append(UI_OT_eyedropper_depth); WM_operatortype_append(UI_OT_eyedropper_driver); @@ -1482,6 +1484,8 @@ void ED_keymap_ui(wmKeyConfig *keyconf) /* eyedroppers - notice they all have the same shortcut, but pass the event * through until a suitable eyedropper for the active button is found */ WM_keymap_add_item(keymap, "UI_OT_eyedropper_color", EKEY, KM_PRESS, 0, 0); + WM_keymap_add_item(keymap, "UI_OT_eyedropper_colorband", EKEY, KM_PRESS, 0, 0); + WM_keymap_add_item(keymap, "UI_OT_eyedropper_colorband_point", EKEY, KM_PRESS, KM_ALT, 0); WM_keymap_add_item(keymap, "UI_OT_eyedropper_id", EKEY, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "UI_OT_eyedropper_depth", EKEY, KM_PRESS, 0, 0); @@ -1504,4 +1508,5 @@ void ED_keymap_ui(wmKeyConfig *keyconf) WM_keymap_add_item(keymap, "ANIM_OT_keyingset_button_remove", KKEY, KM_PRESS, KM_ALT, 0); eyedropper_modal_keymap(keyconf); + eyedropper_colorband_modal_keymap(keyconf); } diff --git a/source/blender/editors/interface/interface_region_tooltip.c b/source/blender/editors/interface/interface_region_tooltip.c index f71b71fce43..07fbefa42e1 100644 --- a/source/blender/editors/interface/interface_region_tooltip.c +++ b/source/blender/editors/interface/interface_region_tooltip.c @@ -29,6 +29,14 @@ * ToolTip Region and Construction */ +/* TODO(campbell): + * We may want to have a higher level API that initializes a timer, + * checks for mouse motion and clears the tool-tip afterwards. + * We never want multiple tool-tips at once so this could be handled on the window / window-manager level. + * + * For now it's not a priority, so leave as-is. + */ + #include <stdarg.h> #include <stdlib.h> #include <string.h> @@ -97,7 +105,6 @@ typedef struct uiTooltipField { } uiTooltipField; -#define MAX_TOOLTIP_LINES 8 typedef struct uiTooltipData { rcti bbox; uiTooltipField *fields; @@ -314,8 +321,6 @@ static uiTooltipData *ui_tooltip_data_from_keymap(bContext *C, wmKeyMap *keymap) /* create tooltip data */ uiTooltipData *data = MEM_callocN(sizeof(uiTooltipData), "uiTooltipData"); - BLI_assert(data->fields_len < MAX_TOOLTIP_LINES); - for (wmKeyMapItem *kmi = keymap->items.first; kmi; kmi = kmi->next) { wmOperatorType *ot = WM_operatortype_find(kmi->idname, true); if (ot != NULL) { @@ -609,8 +614,6 @@ static uiTooltipData *ui_tooltip_data_from_button(bContext *C, uiBut *but) if (rna_prop.strinfo) MEM_freeN(rna_prop.strinfo); - BLI_assert(data->fields_len < MAX_TOOLTIP_LINES); - if (data->fields_len == 0) { MEM_freeN(data); return NULL; @@ -620,13 +623,116 @@ static uiTooltipData *ui_tooltip_data_from_button(bContext *C, uiBut *but) } } -/** \} */ +static uiTooltipData *ui_tooltip_data_from_manipulator(bContext *C, wmManipulator *mpr) +{ + uiTooltipData *data = MEM_callocN(sizeof(uiTooltipData), "uiTooltipData"); -/* -------------------------------------------------------------------- */ -/** \name ToolTip Public API - * \{ */ + /* TODO(campbell): a way for manipulators to have their own descriptions (low priority). */ + + /* Operator Actions */ + { + bool use_drag = mpr->drag_part != -1 && mpr->highlight_part != mpr->drag_part; + + const struct { + int part; + const char *prefix; + } mpop_actions[] = { + { + .part = mpr->highlight_part, + .prefix = use_drag ? TIP_("Click") : NULL, + }, { + .part = use_drag ? mpr->drag_part : -1, + .prefix = use_drag ? TIP_("Drag") : NULL, + }, + }; + + for (int i = 0; i < ARRAY_SIZE(mpop_actions); i++) { + wmManipulatorOpElem *mpop = (mpop_actions[i].part != -1) ? WM_manipulator_operator_get(mpr, mpop_actions[i].part) : NULL; + if (mpop != NULL) { + /* Description */ + const char *info = RNA_struct_ui_description(mpop->type->srna); + if (!(info && info[0])) { + info = RNA_struct_ui_name(mpop->type->srna); + } -ARegion *ui_tooltip_create(bContext *C, ARegion *butregion, uiBut *but) + if (info && info[0]) { + char *text = NULL; + if (mpop_actions[i].prefix != NULL) { + text = BLI_sprintfN("%s: %s", mpop_actions[i].prefix, info); + } + else { + text = BLI_strdup(info); + } + + if (text != NULL) { + uiTooltipField *field = text_field_add( + data, &(uiTooltipFormat){ + .style = UI_TIP_STYLE_HEADER, + .color_id = UI_TIP_LC_VALUE, + .is_pad = true, + }); + field->text = text; + } + } + + /* Shortcut */ + { + bool found = false; + IDProperty *prop = mpop->ptr.data; + char buf[128]; + if (WM_key_event_operator_string( + C, mpop->type->idname, WM_OP_INVOKE_DEFAULT, prop, true, + buf, ARRAY_SIZE(buf))) + { + found = true; + } + uiTooltipField *field = text_field_add( + data, &(uiTooltipFormat){ + .style = UI_TIP_STYLE_NORMAL, + .color_id = UI_TIP_LC_VALUE, + .is_pad = true, + }); + field->text = BLI_sprintfN(TIP_("Shortcut: %s"), found ? buf : "None"); + } + } + } + } + + /* Property Actions */ + if (mpr->type->target_property_defs_len) { + wmManipulatorProperty *mpr_prop_array = WM_manipulator_target_property_array(mpr); + for (int i = 0; i < mpr->type->target_property_defs_len; i++) { + /* TODO(campbell): function callback descriptions. */ + wmManipulatorProperty *mpr_prop = &mpr_prop_array[i]; + if (mpr_prop->prop != NULL) { + const char *info = RNA_property_ui_description(mpr_prop->prop); + if (info && info[0]) { + uiTooltipField *field = text_field_add( + data, &(uiTooltipFormat){ + .style = UI_TIP_STYLE_NORMAL, + .color_id = UI_TIP_LC_VALUE, + .is_pad = true, + }); + field->text = BLI_strdup(info); + } + } + } + } + + if (data->fields_len == 0) { + MEM_freeN(data); + return NULL; + } + else { + return data; + } +} + + +static ARegion *ui_tooltip_create_with_data( + bContext *C, uiTooltipData *data, + const float init_position[2], + const float aspect) { const float pad_px = UI_TIP_PADDING; wmWindow *win = CTX_wm_window(C); @@ -634,43 +740,12 @@ ARegion *ui_tooltip_create(bContext *C, ARegion *butregion, uiBut *but) uiStyle *style = UI_style_get(); static ARegionType type; ARegion *ar; -/* IDProperty *prop;*/ - /* aspect values that shrink text are likely unreadable */ - const float aspect = min_ff(1.0f, but->block->aspect); int fonth, fontw; - int ofsx, ofsy, h, i; + int h, i; rctf rect_fl; rcti rect_i; int font_flag = 0; - if (but->drawflag & UI_BUT_NO_TOOLTIP) { - return NULL; - } - uiTooltipData *data = NULL; - - /* custom tips for pre-defined operators */ - if (but->optype) { - if (STREQ(but->optype->idname, "WM_OT_tool_set")) { - char keymap[64] = ""; - RNA_string_get(but->opptr, "keymap", keymap); - if (keymap[0]) { - ScrArea *sa = CTX_wm_area(C); - wmKeyMap *km = WM_keymap_find_all(C, keymap, sa->spacetype, RGN_TYPE_WINDOW); - if (km != NULL) { - data = ui_tooltip_data_from_keymap(C, km); - } - } - } - } - /* toolsystem exception */ - - if (data == NULL) { - data = ui_tooltip_data_from_button(C, but); - } - if (data == NULL) { - return NULL; - } - /* create area region */ ar = ui_region_temp_add(CTX_wm_screen(C)); @@ -748,31 +823,12 @@ ARegion *ui_tooltip_create(bContext *C, ARegion *butregion, uiBut *but) data->lineh = h; /* compute position */ - ofsx = 0; //(but->block->panel) ? but->block->panel->ofsx : 0; - ofsy = 0; //(but->block->panel) ? but->block->panel->ofsy : 0; - rect_fl.xmin = BLI_rctf_cent_x(&but->rect) + ofsx - TIP_BORDER_X; + rect_fl.xmin = init_position[0] - TIP_BORDER_X; rect_fl.xmax = rect_fl.xmin + fontw + pad_px; - rect_fl.ymax = but->rect.ymin + ofsy - TIP_BORDER_Y; + rect_fl.ymax = init_position[1] - TIP_BORDER_Y; rect_fl.ymin = rect_fl.ymax - fonth - TIP_BORDER_Y; - /* since the text has beens caled already, the size of tooltips is defined now */ - /* here we try to figure out the right location */ - if (butregion) { - float mx, my; - float ofsx_fl = rect_fl.xmin, ofsy_fl = rect_fl.ymax; - ui_block_to_window_fl(butregion, but->block, &ofsx_fl, &ofsy_fl); - -#if 1 - /* use X mouse location */ - mx = (win->eventstate->x + (TIP_BORDER_X * 2)) - BLI_rctf_cent_x(&but->rect); -#else - mx = ofsx_fl - rect_fl.xmin; -#endif - my = ofsy_fl - rect_fl.ymax; - - BLI_rctf_translate(&rect_fl, mx, my); - } BLI_rcti_rctf_copy(&rect_i, &rect_fl); #undef TIP_BORDER_X @@ -827,9 +883,79 @@ ARegion *ui_tooltip_create(bContext *C, ARegion *butregion, uiBut *but) return ar; } -void ui_tooltip_free(bContext *C, ARegion *ar) +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name ToolTip Public API + * \{ */ + + +ARegion *UI_tooltip_create_from_button(bContext *C, ARegion *butregion, uiBut *but) +{ + wmWindow *win = CTX_wm_window(C); + /* aspect values that shrink text are likely unreadable */ + const float aspect = min_ff(1.0f, but->block->aspect); + float init_position[2]; + + if (but->drawflag & UI_BUT_NO_TOOLTIP) { + return NULL; + } + uiTooltipData *data = NULL; + + /* custom tips for pre-defined operators */ + if (but->optype) { + if (STREQ(but->optype->idname, "WM_OT_tool_set")) { + char keymap[64] = ""; + RNA_string_get(but->opptr, "keymap", keymap); + if (keymap[0]) { + ScrArea *sa = CTX_wm_area(C); + wmKeyMap *km = WM_keymap_find_all(C, keymap, sa->spacetype, RGN_TYPE_WINDOW); + if (km != NULL) { + data = ui_tooltip_data_from_keymap(C, km); + } + } + } + } + /* toolsystem exception */ + + if (data == NULL) { + data = ui_tooltip_data_from_button(C, but); + } + if (data == NULL) { + return NULL; + } + + init_position[0] = BLI_rctf_cent_x(&but->rect); + init_position[1] = but->rect.ymin; + + if (butregion) { + ui_block_to_window_fl(butregion, but->block, &init_position[0], &init_position[1]); + init_position[0] = win->eventstate->x; + } + + return ui_tooltip_create_with_data(C, data, init_position, aspect); +} + +ARegion *UI_tooltip_create_from_manipulator(bContext *C, wmManipulator *mpr) +{ + wmWindow *win = CTX_wm_window(C); + const float aspect = 1.0f; + float init_position[2]; + + uiTooltipData *data = ui_tooltip_data_from_manipulator(C, mpr); + if (data == NULL) { + return NULL; + } + + init_position[0] = win->eventstate->x; + init_position[1] = win->eventstate->y; + + return ui_tooltip_create_with_data(C, data, init_position, aspect); +} + +void UI_tooltip_free(bContext *C, bScreen *sc, ARegion *ar) { - ui_region_temp_remove(C, CTX_wm_screen(C), ar); + ui_region_temp_remove(C, sc, ar); } /** \} */ diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index 78874076b92..ce2d3bebb97 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -53,6 +53,7 @@ #include "BLF_api.h" #include "BLT_translation.h" +#include "BKE_colorband.h" #include "BKE_colortools.h" #include "BKE_context.h" #include "BKE_global.h" @@ -60,6 +61,7 @@ #include "BKE_idprop.h" #include "BKE_layer.h" #include "BKE_library.h" +#include "BKE_library_override.h" #include "BKE_linestyle.h" #include "BKE_main.h" #include "BKE_modifier.h" @@ -70,7 +72,6 @@ #include "BKE_report.h" #include "BKE_sca.h" #include "BKE_screen.h" -#include "BKE_texture.h" #include "DEG_depsgraph.h" #include "DEG_depsgraph_build.h" @@ -233,6 +234,8 @@ typedef struct TemplateID { PropertyRNA *prop; ListBase *idlb; + short idcode; + short filter; int prv_rows, prv_cols; bool preview; } TemplateID; @@ -240,73 +243,147 @@ typedef struct TemplateID { /* Search browse menu, assign */ static void template_ID_set_property_cb(bContext *C, void *arg_template, void *item) { - TemplateID *template = (TemplateID *)arg_template; + TemplateID *template_ui = (TemplateID *)arg_template; /* ID */ if (item) { PointerRNA idptr; RNA_id_pointer_create(item, &idptr); - RNA_property_pointer_set(&template->ptr, template->prop, idptr); - RNA_property_update(C, &template->ptr, template->prop); + RNA_property_pointer_set(&template_ui->ptr, template_ui->prop, idptr); + RNA_property_update(C, &template_ui->ptr, template_ui->prop); } } +static bool id_search_add( + const bContext *C, TemplateID *template_ui, + const int flag, const char *str, uiSearchItems *items, + ID *id) +{ + ID *id_from = template_ui->ptr.id.data; + + if (!((flag & PROP_ID_SELF_CHECK) && id == id_from)) { + + /* use filter */ + if (RNA_property_type(template_ui->prop) == PROP_POINTER) { + PointerRNA ptr; + RNA_id_pointer_create(id, &ptr); + if (RNA_property_pointer_poll(&template_ui->ptr, template_ui->prop, &ptr) == 0) { + return true; + } + } + + /* hide dot-datablocks, but only if filter does not force it visible */ + if (U.uiflag & USER_HIDE_DOT) { + if ((id->name[2] == '.') && (str[0] != '.')) { + return true; + } + } + + if (*str == '\0' || BLI_strcasestr(id->name + 2, str)) { + /* +1 is needed because BKE_id_ui_prefix used 3 letter prefix + * followed by ID_NAME-2 characters from id->name + */ + char name_ui[MAX_ID_NAME + 1]; + BKE_id_ui_prefix(name_ui, id); + + int iconid = ui_id_icon_get(C, id, template_ui->preview); + + if (false == UI_search_item_add(items, name_ui, id, iconid)) { + return false; + } + } + } + return true; +} + /* ID Search browse menu, do the search */ static void id_search_cb(const bContext *C, void *arg_template, const char *str, uiSearchItems *items) { - TemplateID *template = (TemplateID *)arg_template; - ListBase *lb = template->idlb; - ID *id, *id_from = template->ptr.id.data; - int iconid; - int flag = RNA_property_flag(template->prop); + TemplateID *template_ui = (TemplateID *)arg_template; + ListBase *lb = template_ui->idlb; + ID *id; + int flag = RNA_property_flag(template_ui->prop); /* ID listbase */ for (id = lb->first; id; id = id->next) { - if (!((flag & PROP_ID_SELF_CHECK) && id == id_from)) { - - /* use filter */ - if (RNA_property_type(template->prop) == PROP_POINTER) { - PointerRNA ptr; - RNA_id_pointer_create(id, &ptr); - if (RNA_property_pointer_poll(&template->ptr, template->prop, &ptr) == 0) - continue; + if (!id_search_add(C, template_ui, flag, str, items, id)) { + break; + } + } +} + +/** + * Use id tags for filtering. + */ +static void id_search_cb_tagged(const bContext *C, void *arg_template, const char *str, uiSearchItems *items) +{ + TemplateID *template_ui = (TemplateID *)arg_template; + ListBase *lb = template_ui->idlb; + ID *id; + int flag = RNA_property_flag(template_ui->prop); + + /* ID listbase */ + for (id = lb->first; id; id = id->next) { + if (id->tag & LIB_TAG_DOIT) { + if (!id_search_add(C, template_ui, flag, str, items, id)) { + break; } + id->tag &= ~LIB_TAG_DOIT; + } + } +} - /* hide dot-datablocks, but only if filter does not force it visible */ - if (U.uiflag & USER_HIDE_DOT) - if ((id->name[2] == '.') && (str[0] != '.')) - continue; +/** + * A version of 'id_search_cb' that lists scene objects. + */ +static void id_search_cb_objects_from_scene(const bContext *C, void *arg_template, const char *str, uiSearchItems *items) +{ + TemplateID *template_ui = (TemplateID *)arg_template; + ListBase *lb = template_ui->idlb; + Scene *scene = NULL; + ID *id_from = template_ui->ptr.id.data; - if (*str == '\0' || BLI_strcasestr(id->name + 2, str)) { - /* +1 is needed because BKE_id_ui_prefix used 3 letter prefix - * followed by ID_NAME-2 characters from id->name - */ - char name_ui[MAX_ID_NAME + 1]; - BKE_id_ui_prefix(name_ui, id); + if (id_from && GS(id_from->name) == ID_SCE) { + scene = (Scene *)id_from; + } + else { + scene = CTX_data_scene(C); + } - iconid = ui_id_icon_get(C, id, template->preview); + BKE_main_id_flag_listbase(lb, LIB_TAG_DOIT, false); - if (false == UI_search_item_add(items, name_ui, id, iconid)) - break; - } - } + FOREACH_SCENE_OBJECT(scene, ob_iter) + { + ob_iter->id.tag |= LIB_TAG_DOIT; } + FOREACH_SCENE_OBJECT_END + id_search_cb_tagged(C, arg_template, str, items); } /* ID Search browse menu, open */ static uiBlock *id_search_menu(bContext *C, ARegion *ar, void *arg_litem) { - static TemplateID template; + static TemplateID template_ui; PointerRNA active_item_ptr; + void (*id_search_cb_p)(const bContext *, void *, const char *, uiSearchItems *) = id_search_cb; /* arg_litem is malloced, can be freed by parent button */ - template = *((TemplateID *)arg_litem); - active_item_ptr = RNA_property_pointer_get(&template.ptr, template.prop); + template_ui = *((TemplateID *)arg_litem); + active_item_ptr = RNA_property_pointer_get(&template_ui.ptr, template_ui.prop); + + if (template_ui.filter) { + /* Currently only used for objects. */ + if (template_ui.idcode == ID_OB) { + if (template_ui.filter == UI_TEMPLATE_ID_FILTER_AVAILABLE) { + id_search_cb_p = id_search_cb_objects_from_scene; + } + } + } return template_common_search_menu( - C, ar, id_search_cb, &template, template_ID_set_property_cb, active_item_ptr.data, - template.prv_rows, template.prv_cols); + C, ar, id_search_cb_p, &template_ui, template_ID_set_property_cb, active_item_ptr.data, + template_ui.prv_rows, template_ui.prv_cols); } /************************ ID Template ***************************/ @@ -317,7 +394,7 @@ void UI_context_active_but_prop_get_templateID( bContext *C, PointerRNA *r_ptr, PropertyRNA **r_prop) { - TemplateID *template; + TemplateID *template_ui; ARegion *ar = CTX_wm_region(C); uiBlock *block; uiBut *but; @@ -333,9 +410,9 @@ void UI_context_active_but_prop_get_templateID( /* find the button before the active one */ if ((but->flag & (UI_BUT_LAST_ACTIVE | UI_ACTIVE))) { if (but->func_argN) { - template = but->func_argN; - *r_ptr = template->ptr; - *r_prop = template->prop; + template_ui = but->func_argN; + *r_ptr = template_ui->ptr; + *r_prop = template_ui->prop; return; } } @@ -346,8 +423,8 @@ void UI_context_active_but_prop_get_templateID( static void template_id_cb(bContext *C, void *arg_litem, void *arg_event) { - TemplateID *template = (TemplateID *)arg_litem; - PointerRNA idptr = RNA_property_pointer_get(&template->ptr, template->prop); + TemplateID *template_ui = (TemplateID *)arg_litem; + PointerRNA idptr = RNA_property_pointer_get(&template_ui->ptr, template_ui->prop); ID *id = idptr.data; int event = GET_INT_FROM_POINTER(arg_event); @@ -362,8 +439,8 @@ static void template_id_cb(bContext *C, void *arg_litem, void *arg_event) break; case UI_ID_DELETE: memset(&idptr, 0, sizeof(idptr)); - RNA_property_pointer_set(&template->ptr, template->prop, idptr); - RNA_property_update(C, &template->ptr, template->prop); + RNA_property_pointer_set(&template_ui->ptr, template_ui->prop, idptr); + RNA_property_update(C, &template_ui->ptr, template_ui->prop); if (id && CTX_wm_window(C)->eventstate->shift) { /* only way to force-remove data (on save) */ @@ -384,20 +461,40 @@ static void template_id_cb(bContext *C, void *arg_litem, void *arg_event) case UI_ID_LOCAL: if (id) { Main *bmain = CTX_data_main(C); - if (id_make_local(bmain, id, false, false)) { - BKE_main_id_clear_newpoins(bmain); + if (CTX_wm_window(C)->eventstate->shift) { + ID *override_id = BKE_override_static_create_from_id(bmain, id); + if (override_id != NULL) { + BKE_main_id_clear_newpoins(bmain); - /* reassign to get get proper updates/notifiers */ - idptr = RNA_property_pointer_get(&template->ptr, template->prop); - RNA_property_pointer_set(&template->ptr, template->prop, idptr); - RNA_property_update(C, &template->ptr, template->prop); + /* Assign new pointer, takes care of updates/notifiers */ + RNA_id_pointer_create(override_id, &idptr); + } } + else { + if (id_make_local(bmain, id, false, false)) { + BKE_main_id_clear_newpoins(bmain); + + /* reassign to get get proper updates/notifiers */ + idptr = RNA_property_pointer_get(&template_ui->ptr, template_ui->prop); + } + } + RNA_property_pointer_set(&template_ui->ptr, template_ui->prop, idptr); + RNA_property_update(C, &template_ui->ptr, template_ui->prop); + } + break; + case UI_ID_OVERRIDE: + if (id && id->override_static) { + BKE_override_static_free(&id->override_static); + /* reassign to get get proper updates/notifiers */ + idptr = RNA_property_pointer_get(&template_ui->ptr, template_ui->prop); + RNA_property_pointer_set(&template_ui->ptr, template_ui->prop, idptr); + RNA_property_update(C, &template_ui->ptr, template_ui->prop); } break; case UI_ID_ALONE: if (id) { const bool do_scene_obj = (GS(id->name) == ID_OB) && - (template->ptr.type == &RNA_SceneObjects); + (template_ui->ptr.type == &RNA_SceneObjects); /* make copy */ if (do_scene_obj) { @@ -410,7 +507,7 @@ static void template_id_cb(bContext *C, void *arg_litem, void *arg_event) else { if (id) { Main *bmain = CTX_data_main(C); - id_single_user(C, id, &template->ptr, template->prop); + id_single_user(C, id, &template_ui->ptr, template_ui->prop); DEG_relations_tag_update(bmain); } } @@ -477,10 +574,10 @@ static const char *template_id_context(StructRNA *type) #endif static uiBut *template_id_def_new_but( - uiBlock *block, const ID *id, const TemplateID *template, StructRNA *type, + uiBlock *block, const ID *id, const TemplateID *template_ui, StructRNA *type, const char * const newop, const bool editable, const bool id_open, const bool use_tab_but) { - ID *idfrom = template->ptr.id.data; + ID *idfrom = template_ui->ptr.id.data; uiBut *but; const int w = id ? UI_UNIT_X : id_open ? UI_UNIT_X * 3 : UI_UNIT_X * 6; const int but_type = use_tab_but ? UI_BTYPE_TAB : UI_BTYPE_BUT; @@ -518,12 +615,12 @@ static uiBut *template_id_def_new_but( if (newop) { but = uiDefIconTextButO(block, but_type, newop, WM_OP_INVOKE_DEFAULT, ICON_ZOOMIN, (id) ? "" : CTX_IFACE_(template_id_context(type), "New"), 0, 0, w, UI_UNIT_Y, NULL); - UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_ADD_NEW)); + UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template_ui), SET_INT_IN_POINTER(UI_ID_ADD_NEW)); } else { but = uiDefIconTextBut(block, but_type, 0, ICON_ZOOMIN, (id) ? "" : CTX_IFACE_(template_id_context(type), "New"), 0, 0, w, UI_UNIT_Y, NULL, 0, 0, 0, 0, NULL); - UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_ADD_NEW)); + UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template_ui), SET_INT_IN_POINTER(UI_ID_ADD_NEW)); } if ((idfrom && idfrom->lib) || !editable) { @@ -538,7 +635,7 @@ static uiBut *template_id_def_new_but( } static void template_ID( - bContext *C, uiLayout *layout, TemplateID *template, StructRNA *type, short idcode, int flag, + bContext *C, uiLayout *layout, TemplateID *template_ui, StructRNA *type, int flag, const char *newop, const char *openop, const char *unlinkop) { uiBut *but; @@ -546,13 +643,13 @@ static void template_ID( PointerRNA idptr; // ListBase *lb; // UNUSED ID *id, *idfrom; - const bool editable = RNA_property_editable(&template->ptr, template->prop); - const bool use_previews = template->preview = (flag & UI_ID_PREVIEWS) != 0; + const bool editable = RNA_property_editable(&template_ui->ptr, template_ui->prop); + const bool use_previews = template_ui->preview = (flag & UI_ID_PREVIEWS) != 0; - idptr = RNA_property_pointer_get(&template->ptr, template->prop); + idptr = RNA_property_pointer_get(&template_ui->ptr, template_ui->prop); id = idptr.data; - idfrom = template->ptr.id.data; - // lb = template->idlb; + idfrom = template_ui->ptr.id.data; + // lb = template_ui->idlb; block = uiLayoutGetBlock(layout); UI_block_align_begin(block); @@ -562,8 +659,8 @@ static void template_ID( if (flag & UI_ID_BROWSE) { template_add_button_search_menu( - C, layout, block, &template->ptr, template->prop, - id_search_menu, MEM_dupallocN(template), TIP_(template_id_browse_tip(type)), + C, layout, block, &template_ui->ptr, template_ui->prop, + id_search_menu, MEM_dupallocN(template_ui), TIP_(template_id_browse_tip(type)), use_previews, editable); } @@ -577,7 +674,7 @@ static void template_ID( but = uiDefButR( block, UI_BTYPE_TEXT, 0, name, 0, 0, TEMPLATE_SEARCH_TEXTBUT_WIDTH, TEMPLATE_SEARCH_TEXTBUT_HEIGHT, &idptr, "name", -1, 0, 0, -1, -1, RNA_struct_ui_description(type)); - UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_RENAME)); + UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template_ui), SET_INT_IN_POINTER(UI_ID_RENAME)); if (user_alert) UI_but_flag_enable(but, UI_BUT_REDALERT); if (id->lib) { @@ -587,13 +684,25 @@ static void template_ID( UI_but_flag_enable(but, UI_BUT_DISABLED); } else { + const bool disabled = (!id_make_local(CTX_data_main(C), id, true /* test */, false) || + (idfrom && idfrom->lib)); but = uiDefIconBut(block, UI_BTYPE_BUT, 0, ICON_LIBRARY_DATA_DIRECT, 0, 0, UI_UNIT_X, UI_UNIT_Y, - NULL, 0, 0, 0, 0, TIP_("Direct linked library data-block, click to make local")); - if (!id_make_local(CTX_data_main(C), id, true /* test */, false) || (idfrom && idfrom->lib)) + NULL, 0, 0, 0, 0, + TIP_("Direct linked library data-block, click to make local, " + "Shift + Click to create a static override")); + if (disabled) { UI_but_flag_enable(but, UI_BUT_DISABLED); + } + else { + UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template_ui), SET_INT_IN_POINTER(UI_ID_LOCAL)); + } } - - UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_LOCAL)); + } + else if (ID_IS_STATIC_OVERRIDE(id)) { + but = uiDefIconBut(block, UI_BTYPE_BUT, 0, ICON_LIBRARY_DATA_OVERRIDE, 0, 0, UI_UNIT_X, UI_UNIT_Y, + NULL, 0, 0, 0, 0, + TIP_("Static override of linked library data-block, click to make fully local")); + UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template_ui), SET_INT_IN_POINTER(UI_ID_OVERRIDE)); } if (id->us > 1) { @@ -607,7 +716,7 @@ static void template_ID( TIP_("Display number of users of this data (click to make a single-user copy)")); but->flag |= UI_BUT_UNDO; - UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_ALONE)); + UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template_ui), SET_INT_IN_POINTER(UI_ID_ALONE)); if (/* test only */ (id_copy(CTX_data_main(C), id, NULL, true) == false) || (idfrom && idfrom->lib) || @@ -627,7 +736,7 @@ static void template_ID( } if (flag & UI_ID_ADD_NEW) { - template_id_def_new_but(block, id, template, type, newop, editable, flag & UI_ID_OPEN, false); + template_id_def_new_but(block, id, template_ui, type, newop, editable, flag & UI_ID_OPEN, false); } /* Due to space limit in UI - skip the "open" icon for packed data, and allow to unpack. @@ -647,12 +756,12 @@ static void template_ID( if (openop) { but = uiDefIconTextButO(block, UI_BTYPE_BUT, openop, WM_OP_INVOKE_DEFAULT, ICON_FILESEL, (id) ? "" : IFACE_("Open"), 0, 0, w, UI_UNIT_Y, NULL); - UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_OPEN)); + UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template_ui), SET_INT_IN_POINTER(UI_ID_OPEN)); } else { but = uiDefIconTextBut(block, UI_BTYPE_BUT, 0, ICON_FILESEL, (id) ? "" : IFACE_("Open"), 0, 0, w, UI_UNIT_Y, NULL, 0, 0, 0, 0, NULL); - UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_OPEN)); + UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template_ui), SET_INT_IN_POINTER(UI_ID_OPEN)); } if ((idfrom && idfrom->lib) || !editable) @@ -668,16 +777,16 @@ static void template_ID( if (unlinkop) { but = uiDefIconButO(block, UI_BTYPE_BUT, unlinkop, WM_OP_INVOKE_REGION_WIN, ICON_X, 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL); /* so we can access the template from operators, font unlinking needs this */ - UI_but_funcN_set(but, NULL, MEM_dupallocN(template), NULL); + UI_but_funcN_set(but, NULL, MEM_dupallocN(template_ui), NULL); } else { - if ((RNA_property_flag(template->prop) & PROP_NEVER_UNLINK) == 0) { + if ((RNA_property_flag(template_ui->prop) & PROP_NEVER_UNLINK) == 0) { but = uiDefIconBut(block, UI_BTYPE_BUT, 0, ICON_X, 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL, 0, 0, 0, 0, TIP_("Unlink data-block " "(Shift + Click to set users to zero, data will then not be saved)")); - UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_DELETE)); + UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template_ui), SET_INT_IN_POINTER(UI_ID_DELETE)); - if (RNA_property_flag(template->prop) & PROP_NEVER_NULL) { + if (RNA_property_flag(template_ui->prop) & PROP_NEVER_NULL) { UI_but_flag_enable(but, UI_BUT_DISABLED); } } @@ -690,9 +799,9 @@ static void template_ID( } } - if (idcode == ID_TE) - uiTemplateTextureShow(layout, C, &template->ptr, template->prop); - + if (template_ui->idcode == ID_TE) { + uiTemplateTextureShow(layout, C, &template_ui->ptr, template_ui->prop); + } UI_block_align_end(block); } @@ -746,9 +855,9 @@ static void ui_template_id( uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname, const char *newop, const char *openop, const char *unlinkop, - int flag, int prv_rows, int prv_cols, bool use_tabs) + int flag, int prv_rows, int prv_cols, int filter, bool use_tabs) { - TemplateID *template; + TemplateID *template_ui; PropertyRNA *prop; StructRNA *type; short idcode; @@ -760,11 +869,18 @@ static void ui_template_id( return; } - template = MEM_callocN(sizeof(TemplateID), "TemplateID"); - template->ptr = *ptr; - template->prop = prop; - template->prv_rows = prv_rows; - template->prv_cols = prv_cols; + template_ui = MEM_callocN(sizeof(TemplateID), "TemplateID"); + template_ui->ptr = *ptr; + template_ui->prop = prop; + template_ui->prv_rows = prv_rows; + template_ui->prv_cols = prv_cols; + + if ((flag & UI_ID_PIN) == 0) { + template_ui->filter = filter; + } + else { + template_ui->filter = 0; + } if (newop) flag |= UI_ID_ADD_NEW; @@ -773,56 +889,57 @@ static void ui_template_id( type = RNA_property_pointer_type(ptr, prop); idcode = RNA_type_to_ID_code(type); - template->idlb = which_libbase(CTX_data_main(C), idcode); - + template_ui->idcode = idcode; + template_ui->idlb = which_libbase(CTX_data_main(C), idcode); + /* create UI elements for this template * - template_ID makes a copy of the template data and assigns it to the relevant buttons */ - if (template->idlb) { + if (template_ui->idlb) { if (use_tabs) { uiLayoutRow(layout, false); - template_ID_tabs(C, layout, template, type, flag, newop, openop, unlinkop); + template_ID_tabs(C, layout, template_ui, type, flag, newop, openop, unlinkop); } else { uiLayoutRow(layout, true); - template_ID(C, layout, template, type, idcode, flag, newop, openop, unlinkop); + template_ID(C, layout, template_ui, type, flag, newop, openop, unlinkop); } } - MEM_freeN(template); + MEM_freeN(template_ui); } void uiTemplateID( uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname, const char *newop, - const char *openop, const char *unlinkop) + const char *openop, const char *unlinkop, int filter) { ui_template_id( layout, C, ptr, propname, newop, openop, unlinkop, UI_ID_BROWSE | UI_ID_RENAME | UI_ID_DELETE, - 0, 0, false); + 0, 0, filter, false); } void uiTemplateIDBrowse( uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname, const char *newop, - const char *openop, const char *unlinkop) + const char *openop, const char *unlinkop, int filter) { ui_template_id( layout, C, ptr, propname, newop, openop, unlinkop, UI_ID_BROWSE | UI_ID_RENAME, - 0, 0, false); + 0, 0, filter, false); } void uiTemplateIDPreview( uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname, const char *newop, - const char *openop, const char *unlinkop, int rows, int cols) + const char *openop, const char *unlinkop, int rows, int cols, int filter) { ui_template_id( layout, C, ptr, propname, newop, openop, unlinkop, UI_ID_BROWSE | UI_ID_RENAME | UI_ID_DELETE | UI_ID_PREVIEWS, - rows, cols, false); + rows, cols, filter, false); } /** @@ -831,13 +948,14 @@ void uiTemplateIDPreview( void uiTemplateIDTabs( uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname, - const char *newop, const char *openop, const char *unlinkop) + const char *newop, const char *openop, const char *unlinkop, + int filter) { ui_template_id( layout, C, ptr, propname, newop, openop, unlinkop, UI_ID_BROWSE | UI_ID_RENAME | UI_ID_DELETE, - 0, 0, true); + 0, 0, filter, true); } /************************ ID Chooser Template ***************************/ @@ -1868,7 +1986,7 @@ static void colorband_add_cb(bContext *C, void *cb_v, void *coba_v) else pos = (coba->data[coba->cur + 1].pos + coba->data[coba->cur].pos) * 0.5f; } - if (colorband_element_add(coba, pos)) { + if (BKE_colorband_element_add(coba, pos)) { rna_update_cb(C, cb_v, NULL); ED_undo_push(C, "Add colorband"); } @@ -1878,7 +1996,7 @@ static void colorband_del_cb(bContext *C, void *cb_v, void *coba_v) { ColorBand *coba = coba_v; - if (colorband_element_remove(coba, coba->cur)) { + if (BKE_colorband_element_remove(coba, coba->cur)) { ED_undo_push(C, "Delete colorband"); rna_update_cb(C, cb_v, NULL); } @@ -1914,7 +2032,7 @@ static void colorband_update_cb(bContext *UNUSED(C), void *bt_v, void *coba_v) /* sneaky update here, we need to sort the colorband points to be in order, * however the RNA pointer then is wrong, so we update it */ - colorband_update_sort(coba); + BKE_colorband_update_sort(coba); bt->rnapoin.data = coba->data + coba->cur; } @@ -1949,6 +2067,11 @@ static void colorband_buttons_layout( bt = uiDefIconTextBut(block, UI_BTYPE_BUT, 0, ICON_ARROW_LEFTRIGHT, "", xs + 4.0f * unit, ys + UI_UNIT_Y, 2.0f * unit, UI_UNIT_Y, NULL, 0, 0, 0, 0, TIP_("Flip the color ramp")); UI_but_funcN_set(bt, colorband_flip_cb, MEM_dupallocN(cb), coba); + + bt = uiDefIconButO(block, UI_BTYPE_BUT, "UI_OT_eyedropper_colorband", WM_OP_INVOKE_DEFAULT, ICON_EYEDROPPER, xs + 6.0f * unit, ys + UI_UNIT_Y, UI_UNIT_X, UI_UNIT_Y, NULL); + bt->custom_data = coba; + bt->func_argN = MEM_dupallocN(cb); + UI_block_align_end(block); UI_block_emboss_set(block, UI_EMBOSS); @@ -3902,6 +4025,7 @@ eAutoPropButsReturn uiTemplateOperatorPropertyButs( uiLayout *col; /* needed to avoid alignment errors with previous buttons */ col = uiLayoutColumn(layout, false); + block = uiLayoutGetBlock(col); but = uiDefIconTextBut(block, UI_BTYPE_BUT, 0, ICON_FILE_REFRESH, IFACE_("Reset"), 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 0.0, 0.0, TIP_("Reset operator defaults")); UI_but_func_set(but, ui_layout_operator_buts__reset_cb, op, NULL); @@ -4493,7 +4617,7 @@ void uiTemplateCacheFile(uiLayout *layout, bContext *C, PointerRNA *ptr, const c uiLayoutSetContextPointer(layout, "edit_cachefile", &fileptr); - uiTemplateID(layout, C, ptr, propname, NULL, "CACHEFILE_OT_open", NULL); + uiTemplateID(layout, C, ptr, propname, NULL, "CACHEFILE_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL); if (!file) { return; diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c index 8c894c7852e..a9c3f973569 100644 --- a/source/blender/editors/interface/interface_widgets.c +++ b/source/blender/editors/interface/interface_widgets.c @@ -707,6 +707,7 @@ static void widgetbase_draw(uiWidgetBase *wtb, uiWidgetColors *wcol) /* backdrop non AA */ if (wtb->draw_inner) { + BLI_assert(wtb->totvert != 0); if (wcol->shaded == 0) { if (wcol->alpha_check) { float inner_v_half[WIDGET_SIZE_MAX][2]; @@ -784,6 +785,7 @@ static void widgetbase_draw(uiWidgetBase *wtb, uiWidgetColors *wcol) /* for each AA step */ if (wtb->draw_outline) { + BLI_assert(wtb->totvert != 0); float triangle_strip[WIDGET_SIZE_MAX * 2 + 2][2]; /* + 2 because the last pair is wrapped */ float triangle_strip_emboss[WIDGET_SIZE_MAX * 2][2]; /* only for emboss */ @@ -2784,6 +2786,10 @@ static void widget_numbut_draw(uiWidgetColors *wcol, rcti *rect, int state, int if (!emboss) { round_box_edges(&wtb, roundboxalign, rect, rad); } + else { + wtb.draw_inner = false; + wtb.draw_outline = false; + } /* decoration */ if (!(state & UI_STATE_TEXT_INPUT)) { diff --git a/source/blender/editors/interface/resources.c b/source/blender/editors/interface/resources.c index cd90da24951..ac5fb3e40cb 100644 --- a/source/blender/editors/interface/resources.c +++ b/source/blender/editors/interface/resources.c @@ -46,10 +46,10 @@ #include "BLI_math.h" #include "BKE_appdir.h" +#include "BKE_colorband.h" #include "BKE_DerivedMesh.h" #include "BKE_global.h" #include "BKE_main.h" -#include "BKE_texture.h" #include "BIF_gl.h" @@ -2011,7 +2011,7 @@ void init_userdef_do_versions(void) rgba_char_args_set(btheme->tv3d.editmesh_active, 255, 255, 255, 128); } if (U.coba_weight.tot == 0) - init_colorband(&U.coba_weight, true); + BKE_colorband_init(&U.coba_weight, true); } if (!USER_VERSION_ATLEAST(245, 3)) { bTheme *btheme; diff --git a/source/blender/editors/interface/view2d_ops.c b/source/blender/editors/interface/view2d_ops.c index b271b0b5bc6..dc68c8b58de 100644 --- a/source/blender/editors/interface/view2d_ops.c +++ b/source/blender/editors/interface/view2d_ops.c @@ -1509,6 +1509,9 @@ static int view2d_smoothview_invoke(bContext *C, wmOperator *UNUSED(op), const w WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), v2d->smooth_timer); v2d->smooth_timer = NULL; + + /* Event handling won't know if a UI item has been moved under the pointer. */ + WM_event_add_mousemove(C); } else { /* ease in/out */ diff --git a/source/blender/editors/io/io_collada.c b/source/blender/editors/io/io_collada.c index fc227a2aa75..1b7fd319da0 100644 --- a/source/blender/editors/io/io_collada.c +++ b/source/blender/editors/io/io_collada.c @@ -40,6 +40,8 @@ #include "BKE_main.h" #include "BKE_report.h" +#include "DEG_depsgraph.h" + #include "ED_screen.h" #include "ED_object.h" @@ -447,6 +449,7 @@ static int wm_collada_import_exec(bContext *C, wmOperator *op) min_chain_length, keep_bind_info) ) { + DEG_id_tag_update(&CTX_data_scene(C)->id, DEG_TAG_BASE_FLAGS_UPDATE); return OPERATOR_FINISHED; } else { diff --git a/source/blender/editors/manipulator_library/CMakeLists.txt b/source/blender/editors/manipulator_library/CMakeLists.txt index 9f7df8c6425..86e1bb3b6d7 100644 --- a/source/blender/editors/manipulator_library/CMakeLists.txt +++ b/source/blender/editors/manipulator_library/CMakeLists.txt @@ -47,6 +47,7 @@ set(SRC geometry/geom_dial_manipulator.c manipulator_types/arrow2d_manipulator.c manipulator_types/arrow3d_manipulator.c + manipulator_types/button2d_manipulator.c manipulator_types/cage2d_manipulator.c manipulator_types/cage3d_manipulator.c manipulator_types/dial3d_manipulator.c diff --git a/source/blender/editors/manipulator_library/manipulator_library_utils.c b/source/blender/editors/manipulator_library/manipulator_library_utils.c index 38b518b1992..12f9d1b48d3 100644 --- a/source/blender/editors/manipulator_library/manipulator_library_utils.c +++ b/source/blender/editors/manipulator_library/manipulator_library_utils.c @@ -195,7 +195,7 @@ bool manipulator_window_project_2d( float ray_origin[3], ray_direction[3]; - if (ED_view3d_win_to_ray(ar, v3d, mval, ray_origin, ray_direction, false)) { + if (ED_view3d_win_to_ray(CTX_data_depsgraph(C), ar, v3d, mval, ray_origin, ray_direction, false)) { float lambda; if (isect_ray_plane_v3(ray_origin, ray_direction, plane, &lambda, true)) { float co[3]; diff --git a/source/blender/editors/manipulator_library/manipulator_types/arrow3d_manipulator.c b/source/blender/editors/manipulator_library/manipulator_types/arrow3d_manipulator.c index e9760e3e270..cc8fd72aa03 100644 --- a/source/blender/editors/manipulator_library/manipulator_types/arrow3d_manipulator.c +++ b/source/blender/editors/manipulator_library/manipulator_types/arrow3d_manipulator.c @@ -236,90 +236,65 @@ static int manipulator_arrow_modal( { ArrowManipulator3D *arrow = (ArrowManipulator3D *)mpr; ManipulatorInteraction *inter = mpr->interaction_data; + View3D *v3d = CTX_wm_view3d(C); ARegion *ar = CTX_wm_region(C); RegionView3D *rv3d = ar->regiondata; - float orig_origin[4]; - float viewvec[3], tangent[3], plane[3]; - float offset[4]; - float m_diff[2]; - float dir_2d[2], dir2d_final[2]; + float offset[3]; float facdir = 1.0f; - bool use_vertical = false; + /* (src, dst) */ + struct { + float mval[2]; + float ray_origin[3], ray_direction[3]; + float location[3]; + } proj[2] = { + {.mval = {UNPACK2(inter->init_mval)}}, + {.mval = {UNPACK2(event->mval)}}, + }; - copy_v3_v3(orig_origin, inter->init_matrix_basis[3]); - orig_origin[3] = 1.0f; - add_v3_v3v3(offset, orig_origin, arrow->manipulator.matrix_basis[2]); - offset[3] = 1.0f; - - /* calculate view vector */ - if (rv3d->is_persp) { - sub_v3_v3v3(viewvec, orig_origin, rv3d->viewinv[3]); - } - else { - copy_v3_v3(viewvec, rv3d->viewinv[2]); - } - normalize_v3(viewvec); - - /* first determine if view vector is really close to the direction. If it is, we use - * vertical movement to determine offset, just like transform system does */ - if (RAD2DEGF(acosf(dot_v3v3(viewvec, arrow->manipulator.matrix_basis[2]))) > 5.0f) { - /* multiply to projection space */ - mul_m4_v4(rv3d->persmat, orig_origin); - mul_v4_fl(orig_origin, 1.0f / orig_origin[3]); - mul_m4_v4(rv3d->persmat, offset); - mul_v4_fl(offset, 1.0f / offset[3]); - - sub_v2_v2v2(dir_2d, offset, orig_origin); - dir_2d[0] *= ar->winx; - dir_2d[1] *= ar->winy; - normalize_v2(dir_2d); - } - else { - dir_2d[0] = 0.0f; - dir_2d[1] = 1.0f; - use_vertical = true; - } - - /* find mouse difference */ - m_diff[0] = event->mval[0] - inter->init_mval[0]; - m_diff[1] = event->mval[1] - inter->init_mval[1]; - - /* project the displacement on the screen space arrow direction */ - project_v2_v2v2(dir2d_final, m_diff, dir_2d); + float arrow_co[3]; + float arrow_no[3]; + copy_v3_v3(arrow_co, inter->init_matrix_basis[3]); + normalize_v3_v3(arrow_no, arrow->manipulator.matrix_basis[2]); + + int ok = 0; + + for (int j = 0; j < 2; j++) { + if (ED_view3d_win_to_ray( + CTX_data_depsgraph(C), + ar, v3d, proj[j].mval, + proj[j].ray_origin, proj[j].ray_direction, false)) + { + /* Force Y axis if we're view aligned */ + if (j == 0) { + if (RAD2DEGF(acosf(dot_v3v3(proj[j].ray_direction, arrow->manipulator.matrix_basis[2]))) < 5.0f) { + normalize_v3_v3(arrow_no, rv3d->viewinv[1]); + } + } - float zfac = ED_view3d_calc_zfac(rv3d, orig_origin, NULL); - ED_view3d_win_to_delta(ar, dir2d_final, offset, zfac); + float arrow_no_proj[3]; + project_plane_v3_v3v3(arrow_no_proj, arrow_no, proj[j].ray_direction); - add_v3_v3v3(orig_origin, offset, inter->init_matrix_basis[3]); + normalize_v3(arrow_no_proj); - /* calculate view vector for the new position */ - if (rv3d->is_persp) { - sub_v3_v3v3(viewvec, orig_origin, rv3d->viewinv[3]); - } - else { - copy_v3_v3(viewvec, rv3d->viewinv[2]); - } + float plane[4]; + plane_from_point_normal_v3(plane, proj[j].ray_origin, arrow_no_proj); - normalize_v3(viewvec); - if (!use_vertical) { - /* now find a plane parallel to the view vector so we can intersect with the arrow direction */ - cross_v3_v3v3(tangent, viewvec, offset); - cross_v3_v3v3(plane, tangent, viewvec); - - const float plane_offset = dot_v3v3(plane, offset); - const float plane_dir = dot_v3v3(plane, arrow->manipulator.matrix_basis[2]); - const float fac = (plane_dir != 0.0f) ? (plane_offset / plane_dir) : 0.0f; - facdir = (fac < 0.0f) ? -1.0f : 1.0f; - if (isfinite(fac)) { - mul_v3_v3fl(offset, arrow->manipulator.matrix_basis[2], fac); + float lambda; + if (isect_ray_plane_v3(arrow_co, arrow_no, plane, &lambda, false)) { + madd_v3_v3v3fl(proj[j].location, arrow_co, arrow_no, lambda); + ok++; + } } } - else { - facdir = (m_diff[1] < 0.0f) ? -1.0f : 1.0f; + + if (ok != 2) { + return OPERATOR_RUNNING_MODAL; } + sub_v3_v3v3(offset, proj[1].location, proj[0].location); + facdir = dot_v3v3(arrow_no, offset) < 0.0f ? -1 : 1; ManipulatorCommonData *data = &arrow->data; const float ofs_new = facdir * len_v3(offset); diff --git a/source/blender/editors/manipulator_library/manipulator_types/button2d_manipulator.c b/source/blender/editors/manipulator_library/manipulator_types/button2d_manipulator.c new file mode 100644 index 00000000000..7e57b48c77c --- /dev/null +++ b/source/blender/editors/manipulator_library/manipulator_types/button2d_manipulator.c @@ -0,0 +1,262 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file button2d_manipulator.c + * \ingroup wm + * + * \name Button Manipulator + * + * 2D Manipulator, also works in 3D views. + * + * \brief Single click button action for use in manipulator groups. + * + * \note Currently only basic icon & vector-shape buttons are supported. + * + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_math.h" + +#include "BKE_context.h" + +#include "BIF_gl.h" +#include "BIF_glutil.h" + +#include "GPU_immediate.h" +#include "GPU_immediate_util.h" +#include "GPU_matrix.h" +#include "GPU_select.h" +#include "GPU_batch.h" + +#include "RNA_access.h" +#include "RNA_define.h" +#include "RNA_enum_types.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "ED_screen.h" +#include "ED_view3d.h" +#include "ED_manipulator_library.h" + +#include "UI_interface_icons.h" +#include "UI_resources.h" + +/* own includes */ +#include "../manipulator_geometry.h" +#include "../manipulator_library_intern.h" + +typedef struct ButtonManipulator2D { + wmManipulator manipulator; + bool is_init; + /* Use an icon or shape */ + int icon; + Gwn_Batch *shape_batch[2]; +} ButtonManipulator2D; + +#define CIRCLE_RESOLUTION 32 + +/* -------------------------------------------------------------------- */ + +static void button2d_geom_draw_backdrop( + const wmManipulator *mpr, const float color[4], const bool select) +{ + glLineWidth(mpr->line_width); + + Gwn_VertFormat *format = immVertexFormat(); + uint pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); + + immUniformColor4fv(color); + + /* TODO, other draw styles */ + imm_draw_circle_fill_2d(pos, 0, 0, 1.0f, CIRCLE_RESOLUTION); + + immUnbindProgram(); + + UNUSED_VARS(select); +} + +static void button2d_draw_intern( + const bContext *UNUSED(C), wmManipulator *mpr, + const bool select, const bool highlight) +{ + ButtonManipulator2D *button = (ButtonManipulator2D *)mpr; + + if (button->is_init == false) { + button->is_init = true; + PropertyRNA *prop = RNA_struct_find_property(mpr->ptr, "icon"); + if (RNA_property_is_set(mpr->ptr, prop)) { + button->icon = RNA_property_enum_get(mpr->ptr, prop); + } + else { + prop = RNA_struct_find_property(mpr->ptr, "shape"); + const uint polys_len = RNA_property_string_length(mpr->ptr, prop); + /* We shouldn't need the +1, but a NULL char is set. */ + char *polys = MEM_mallocN(polys_len + 1, __func__); + RNA_property_string_get(mpr->ptr, prop, polys); + button->shape_batch[0] = GPU_batch_wire_from_poly_2d_encoded((uchar *)polys, polys_len, NULL); + button->shape_batch[1] = GPU_batch_tris_from_poly_2d_encoded((uchar *)polys, polys_len, NULL); + MEM_freeN(polys); + } + } + + float color[4]; + float matrix_final[4][4]; + + manipulator_color_get(mpr, highlight, color); + WM_manipulator_calc_matrix_final(mpr, matrix_final); + + gpuPushMatrix(); + gpuMultMatrix(matrix_final); + + glEnable(GL_BLEND); + + if (select == false) { + if (button->shape_batch[0] != NULL) { + glEnable(GL_LINE_SMOOTH); + glLineWidth(1.0f); + for (uint i = 0; i < ARRAY_SIZE(button->shape_batch) && button->shape_batch[i]; i++) { + /* Invert line color for wire. */ + color[0] = 1.0f - color[0]; + color[1] = 1.0f - color[1]; + color[2] = 1.0f - color[2]; + + GWN_batch_program_set_builtin(button->shape_batch[i], GPU_SHADER_2D_UNIFORM_COLOR); + GWN_batch_uniform_4f(button->shape_batch[i], "color", UNPACK4(color)); + GWN_batch_draw(button->shape_batch[i]); + } + glDisable(GL_LINE_SMOOTH); + gpuPopMatrix(); + } + else if (button->icon != ICON_NONE) { + button2d_geom_draw_backdrop(mpr, color, select); + gpuPopMatrix(); + UI_icon_draw( + mpr->matrix_basis[3][0] - (ICON_DEFAULT_WIDTH / 2.0) * U.ui_scale, + mpr->matrix_basis[3][1] - (ICON_DEFAULT_HEIGHT / 2.0) * U.ui_scale, + button->icon); + } + else { + gpuPopMatrix(); + } + } + glDisable(GL_BLEND); +} + +static void manipulator_button2d_draw_select(const bContext *C, wmManipulator *mpr, int select_id) +{ + GPU_select_load_id(select_id); + button2d_draw_intern(C, mpr, true, false); +} + +static void manipulator_button2d_draw(const bContext *C, wmManipulator *mpr) +{ + const bool is_highlight = (mpr->state & WM_MANIPULATOR_STATE_HIGHLIGHT) != 0; + + glEnable(GL_BLEND); + button2d_draw_intern(C, mpr, false, is_highlight); + glDisable(GL_BLEND); +} + +static int manipulator_button2d_test_select( + bContext *C, wmManipulator *mpr, const wmEvent *event) +{ + float point_local[2]; + + if (0) { + /* correct, but unnecessarily slow. */ + if (manipulator_window_project_2d( + C, mpr, (const float[2]){UNPACK2(event->mval)}, 2, true, point_local) == false) + { + return -1; + } + } + else { + copy_v2_v2(point_local, (float [2]){UNPACK2(event->mval)}); + sub_v2_v2(point_local, mpr->matrix_basis[3]); + mul_v2_fl(point_local, 1.0f / (mpr->scale_basis * U.ui_scale)); + } + /* The 'mpr->scale_final' is already applied when projecting. */ + if (len_squared_v2(point_local) < 1.0f) { + return 0; + } + + return -1; +} + +static int manipulator_button2d_cursor_get(wmManipulator *mpr) +{ + if (RNA_boolean_get(mpr->ptr, "show_drag")) { + return BC_NSEW_SCROLLCURSOR; + } + return CURSOR_STD; +} + +static void manipulator_button2d_free(wmManipulator *mpr) +{ + ButtonManipulator2D *shape = (ButtonManipulator2D *)mpr; + + for (uint i = 0; i < ARRAY_SIZE(shape->shape_batch); i++) { + GWN_BATCH_DISCARD_SAFE(shape->shape_batch[i]); + } +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Button Manipulator API + * + * \{ */ + +static void MANIPULATOR_WT_button_2d(wmManipulatorType *wt) +{ + /* identifiers */ + wt->idname = "MANIPULATOR_WT_button_2d"; + + /* api callbacks */ + wt->draw = manipulator_button2d_draw; + wt->draw_select = manipulator_button2d_draw_select; + wt->test_select = manipulator_button2d_test_select; + wt->cursor_get = manipulator_button2d_cursor_get; + wt->free = manipulator_button2d_free; + + wt->struct_size = sizeof(ButtonManipulator2D); + + /* rna */ + PropertyRNA *prop; + prop = RNA_def_property(wt->srna, "icon", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, rna_enum_icon_items); + + /* Passed to 'GPU_batch_from_poly_2d_encoded' */ + RNA_def_property(wt->srna, "shape", PROP_STRING, PROP_BYTESTRING); + + /* Currently only used for cursor display. */ + RNA_def_boolean(wt->srna, "show_drag", true, "Show Drag", ""); +} + +void ED_manipulatortypes_button_2d(void) +{ + WM_manipulatortype_append(MANIPULATOR_WT_button_2d); +} + +/** \} */ // Button Manipulator API diff --git a/source/blender/editors/manipulator_library/manipulator_types/dial3d_manipulator.c b/source/blender/editors/manipulator_library/manipulator_types/dial3d_manipulator.c index f2f5851ff0c..2991c972f6e 100644 --- a/source/blender/editors/manipulator_library/manipulator_types/dial3d_manipulator.c +++ b/source/blender/editors/manipulator_library/manipulator_types/dial3d_manipulator.c @@ -191,6 +191,7 @@ static void dial_ghostarc_draw( } static void dial_ghostarc_get_angles( + const struct Depsgraph *depsgraph, const wmManipulator *mpr, const wmEvent *event, const ARegion *ar, const View3D *v3d, @@ -218,7 +219,7 @@ static void dial_ghostarc_get_angles( plane_from_point_normal_v3(dial_plane, mpr->matrix_basis[3], axis_vec); - if (!ED_view3d_win_to_ray(ar, v3d, inter->init_mval, ray_co, ray_no, false) || + if (!ED_view3d_win_to_ray(depsgraph, ar, v3d, inter->init_mval, ray_co, ray_no, false) || !isect_ray_plane_v3(ray_co, ray_no, dial_plane, &ray_lambda, false)) { goto fail; @@ -226,7 +227,7 @@ static void dial_ghostarc_get_angles( madd_v3_v3v3fl(proj_mval_init_rel, ray_co, ray_no, ray_lambda); sub_v3_v3(proj_mval_init_rel, mpr->matrix_basis[3]); - if (!ED_view3d_win_to_ray(ar, v3d, mval, ray_co, ray_no, false) || + if (!ED_view3d_win_to_ray(depsgraph, ar, v3d, mval, ray_co, ray_no, false) || !isect_ray_plane_v3(ray_co, ray_no, dial_plane, &ray_lambda, false)) { goto fail; @@ -396,6 +397,7 @@ static int manipulator_dial_modal( dial_calc_matrix(mpr, matrix); dial_ghostarc_get_angles( + CTX_data_depsgraph(C), mpr, event, CTX_wm_region(C), CTX_wm_view3d(C), matrix, co_outer, &angle_ofs, &angle_delta); DialInteraction *inter = mpr->interaction_data; diff --git a/source/blender/editors/manipulator_library/manipulator_types/grab3d_manipulator.c b/source/blender/editors/manipulator_library/manipulator_types/grab3d_manipulator.c index 151e173e5e6..4e62c9c396e 100644 --- a/source/blender/editors/manipulator_library/manipulator_types/grab3d_manipulator.c +++ b/source/blender/editors/manipulator_library/manipulator_types/grab3d_manipulator.c @@ -302,7 +302,8 @@ static int manipulator_grab_test_select( return -1; } - if (len_squared_v2(point_local) < SQUARE(mpr->scale_final)) { + /* The 'mpr->scale_final' is already applied when projecting. */ + if (len_squared_v2(point_local) < 1.0f) { return 0; } diff --git a/source/blender/editors/mesh/editmesh_add.c b/source/blender/editors/mesh/editmesh_add.c index 77772cfc8cc..a21fc2fffde 100644 --- a/source/blender/editors/mesh/editmesh_add.c +++ b/source/blender/editors/mesh/editmesh_add.c @@ -60,30 +60,35 @@ /* ********* add primitive operators ************* */ +typedef struct MakePrimitiveData { + float mat[4][4]; + bool was_editmode; +} MakePrimitiveData; + static Object *make_prim_init(bContext *C, const char *idname, - float *dia, float mat[4][4], - bool *was_editmode, const float loc[3], const float rot[3], const unsigned int layer) + const float loc[3], const float rot[3], const unsigned int layer, + MakePrimitiveData *r_creation_data) { Object *obedit = CTX_data_edit_object(C); - *was_editmode = false; + r_creation_data->was_editmode = false; if (obedit == NULL || obedit->type != OB_MESH) { obedit = ED_object_add_type(C, OB_MESH, idname, loc, rot, false, layer); /* create editmode */ ED_object_editmode_enter(C, EM_DO_UNDO | EM_IGNORE_LAYER); /* rare cases the active layer is messed up */ - *was_editmode = true; + r_creation_data->was_editmode = true; } - *dia = ED_object_new_primitive_matrix(C, obedit, loc, rot, mat); + ED_object_new_primitive_matrix(C, obedit, loc, rot, r_creation_data->mat); return obedit; } -static void make_prim_finish(bContext *C, Object *obedit, bool was_editmode, int enter_editmode) +static void make_prim_finish(bContext *C, Object *obedit, const MakePrimitiveData *creation_data, int enter_editmode) { BMEditMesh *em = BKE_editmesh_from_object(obedit); - const bool exit_editmode = ((was_editmode == true) && (enter_editmode == false)); + const bool exit_editmode = ((creation_data->was_editmode == true) && (enter_editmode == false)); /* Primitive has all verts selected, use vert select flush * to push this up to edges & faces. */ @@ -101,17 +106,17 @@ static void make_prim_finish(bContext *C, Object *obedit, bool was_editmode, int static int add_primitive_plane_exec(bContext *C, wmOperator *op) { + MakePrimitiveData creation_data; Object *obedit; BMEditMesh *em; - float loc[3], rot[3], mat[4][4], dia; + float loc[3], rot[3]; bool enter_editmode; - bool was_editmode; unsigned int layer; const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs"); WM_operator_view3d_unit_defaults(C, op); ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &layer, NULL); - obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Plane"), &dia, mat, &was_editmode, loc, rot, layer); + obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Plane"), loc, rot, layer, &creation_data); em = BKE_editmesh_from_object(obedit); if (calc_uvs) { @@ -121,12 +126,12 @@ static int add_primitive_plane_exec(bContext *C, wmOperator *op) if (!EDBM_op_call_and_selectf( em, op, "verts.out", false, "create_grid x_segments=%i y_segments=%i size=%f matrix=%m4 calc_uvs=%b", - 1, 1, RNA_float_get(op->ptr, "radius"), mat, calc_uvs)) + 1, 1, RNA_float_get(op->ptr, "radius"), creation_data.mat, calc_uvs)) { return OPERATOR_CANCELLED; } - make_prim_finish(C, obedit, was_editmode, enter_editmode); + make_prim_finish(C, obedit, &creation_data, enter_editmode); return OPERATOR_FINISHED; } @@ -152,17 +157,17 @@ void MESH_OT_primitive_plane_add(wmOperatorType *ot) static int add_primitive_cube_exec(bContext *C, wmOperator *op) { + MakePrimitiveData creation_data; Object *obedit; BMEditMesh *em; - float loc[3], rot[3], mat[4][4], dia; + float loc[3], rot[3]; bool enter_editmode; - bool was_editmode; unsigned int layer; const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs"); WM_operator_view3d_unit_defaults(C, op); ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &layer, NULL); - obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Cube"), &dia, mat, &was_editmode, loc, rot, layer); + obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Cube"), loc, rot, layer, &creation_data); em = BKE_editmesh_from_object(obedit); if (calc_uvs) { @@ -172,13 +177,13 @@ static int add_primitive_cube_exec(bContext *C, wmOperator *op) if (!EDBM_op_call_and_selectf( em, op, "verts.out", false, "create_cube matrix=%m4 size=%f calc_uvs=%b", - mat, RNA_float_get(op->ptr, "radius") * 2.0f, calc_uvs)) + creation_data.mat, RNA_float_get(op->ptr, "radius") * 2.0f, calc_uvs)) { return OPERATOR_CANCELLED; } /* BMESH_TODO make plane side this: M_SQRT2 - plane (diameter of 1.41 makes it unit size) */ - make_prim_finish(C, obedit, was_editmode, enter_editmode); + make_prim_finish(C, obedit, &creation_data, enter_editmode); return OPERATOR_FINISHED; } @@ -210,13 +215,13 @@ static const EnumPropertyItem fill_type_items[] = { static int add_primitive_circle_exec(bContext *C, wmOperator *op) { + MakePrimitiveData creation_data; Object *obedit; BMEditMesh *em; - float loc[3], rot[3], mat[4][4], dia; + float loc[3], rot[3]; bool enter_editmode; int cap_end, cap_tri; unsigned int layer; - bool was_editmode; const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs"); cap_end = RNA_enum_get(op->ptr, "fill_type"); @@ -224,7 +229,7 @@ static int add_primitive_circle_exec(bContext *C, wmOperator *op) WM_operator_view3d_unit_defaults(C, op); ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &layer, NULL); - obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Circle"), &dia, mat, &was_editmode, loc, rot, layer); + obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Circle"), loc, rot, layer, &creation_data); em = BKE_editmesh_from_object(obedit); if (calc_uvs) { @@ -235,12 +240,12 @@ static int add_primitive_circle_exec(bContext *C, wmOperator *op) em, op, "verts.out", false, "create_circle segments=%i radius=%f cap_ends=%b cap_tris=%b matrix=%m4 calc_uvs=%b", RNA_int_get(op->ptr, "vertices"), RNA_float_get(op->ptr, "radius"), - cap_end, cap_tri, mat, calc_uvs)) + cap_end, cap_tri, creation_data.mat, calc_uvs)) { return OPERATOR_CANCELLED; } - make_prim_finish(C, obedit, was_editmode, enter_editmode); + make_prim_finish(C, obedit, &creation_data, enter_editmode); return OPERATOR_FINISHED; } @@ -270,12 +275,12 @@ void MESH_OT_primitive_circle_add(wmOperatorType *ot) static int add_primitive_cylinder_exec(bContext *C, wmOperator *op) { + MakePrimitiveData creation_data; Object *obedit; BMEditMesh *em; - float loc[3], rot[3], mat[4][4], dia; + float loc[3], rot[3]; bool enter_editmode; unsigned int layer; - bool was_editmode; const int end_fill_type = RNA_enum_get(op->ptr, "end_fill_type"); const bool cap_end = (end_fill_type != 0); const bool cap_tri = (end_fill_type == 2); @@ -283,7 +288,7 @@ static int add_primitive_cylinder_exec(bContext *C, wmOperator *op) WM_operator_view3d_unit_defaults(C, op); ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &layer, NULL); - obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Cylinder"), &dia, mat, &was_editmode, loc, rot, layer); + obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Cylinder"), loc, rot, layer, &creation_data); em = BKE_editmesh_from_object(obedit); if (calc_uvs) { @@ -297,12 +302,12 @@ static int add_primitive_cylinder_exec(bContext *C, wmOperator *op) RNA_float_get(op->ptr, "radius"), RNA_float_get(op->ptr, "radius"), cap_end, cap_tri, - RNA_float_get(op->ptr, "depth"), mat, calc_uvs)) + RNA_float_get(op->ptr, "depth"), creation_data.mat, calc_uvs)) { return OPERATOR_CANCELLED; } - make_prim_finish(C, obedit, was_editmode, enter_editmode); + make_prim_finish(C, obedit, &creation_data, enter_editmode); return OPERATOR_FINISHED; } @@ -333,12 +338,12 @@ void MESH_OT_primitive_cylinder_add(wmOperatorType *ot) static int add_primitive_cone_exec(bContext *C, wmOperator *op) { + MakePrimitiveData creation_data; Object *obedit; BMEditMesh *em; - float loc[3], rot[3], mat[4][4], dia; + float loc[3], rot[3]; bool enter_editmode; unsigned int layer; - bool was_editmode; const int end_fill_type = RNA_enum_get(op->ptr, "end_fill_type"); const bool cap_end = (end_fill_type != 0); const bool cap_tri = (end_fill_type == 2); @@ -346,7 +351,7 @@ static int add_primitive_cone_exec(bContext *C, wmOperator *op) WM_operator_view3d_unit_defaults(C, op); ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &layer, NULL); - obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Cone"), &dia, mat, &was_editmode, loc, rot, layer); + obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Cone"), loc, rot, layer, &creation_data); em = BKE_editmesh_from_object(obedit); if (calc_uvs) { @@ -357,12 +362,13 @@ static int add_primitive_cone_exec(bContext *C, wmOperator *op) em, op, "verts.out", false, "create_cone segments=%i diameter1=%f diameter2=%f cap_ends=%b cap_tris=%b depth=%f matrix=%m4 calc_uvs=%b", RNA_int_get(op->ptr, "vertices"), RNA_float_get(op->ptr, "radius1"), - RNA_float_get(op->ptr, "radius2"), cap_end, cap_tri, RNA_float_get(op->ptr, "depth"), mat, calc_uvs)) + RNA_float_get(op->ptr, "radius2"), cap_end, cap_tri, RNA_float_get(op->ptr, "depth"), + creation_data.mat, calc_uvs)) { return OPERATOR_CANCELLED; } - make_prim_finish(C, obedit, was_editmode, enter_editmode); + make_prim_finish(C, obedit, &creation_data, enter_editmode); return OPERATOR_FINISHED; } @@ -394,17 +400,17 @@ void MESH_OT_primitive_cone_add(wmOperatorType *ot) static int add_primitive_grid_exec(bContext *C, wmOperator *op) { + MakePrimitiveData creation_data; Object *obedit; BMEditMesh *em; - float loc[3], rot[3], mat[4][4], dia; + float loc[3], rot[3]; bool enter_editmode; - bool was_editmode; unsigned int layer; const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs"); WM_operator_view3d_unit_defaults(C, op); ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &layer, NULL); - obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Grid"), &dia, mat, &was_editmode, loc, rot, layer); + obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Grid"), loc, rot, layer, &creation_data); em = BKE_editmesh_from_object(obedit); if (calc_uvs) { @@ -416,12 +422,12 @@ static int add_primitive_grid_exec(bContext *C, wmOperator *op) "create_grid x_segments=%i y_segments=%i size=%f matrix=%m4 calc_uvs=%b", RNA_int_get(op->ptr, "x_subdivisions"), RNA_int_get(op->ptr, "y_subdivisions"), - RNA_float_get(op->ptr, "radius"), mat, calc_uvs)) + RNA_float_get(op->ptr, "radius"), creation_data.mat, calc_uvs)) { return OPERATOR_CANCELLED; } - make_prim_finish(C, obedit, was_editmode, enter_editmode); + make_prim_finish(C, obedit, &creation_data, enter_editmode); return OPERATOR_FINISHED; } @@ -453,22 +459,21 @@ void MESH_OT_primitive_grid_add(wmOperatorType *ot) static int add_primitive_monkey_exec(bContext *C, wmOperator *op) { + MakePrimitiveData creation_data; Object *obedit; BMEditMesh *em; - float mat[4][4]; float loc[3], rot[3]; float dia; bool enter_editmode; unsigned int layer; - bool was_editmode; const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs"); WM_operator_view3d_unit_defaults(C, op); ED_object_add_generic_get_opts(C, op, 'Y', loc, rot, &enter_editmode, &layer, NULL); - obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Suzanne"), &dia, mat, &was_editmode, loc, rot, layer); + obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Suzanne"), loc, rot, layer, &creation_data); dia = RNA_float_get(op->ptr, "radius"); - mul_mat3_m4_fl(mat, dia); + mul_mat3_m4_fl(creation_data.mat, dia); em = BKE_editmesh_from_object(obedit); @@ -478,12 +483,12 @@ static int add_primitive_monkey_exec(bContext *C, wmOperator *op) if (!EDBM_op_call_and_selectf( em, op, "verts.out", false, - "create_monkey matrix=%m4 calc_uvs=%b", mat, calc_uvs)) + "create_monkey matrix=%m4 calc_uvs=%b", creation_data.mat, calc_uvs)) { return OPERATOR_CANCELLED; } - make_prim_finish(C, obedit, was_editmode, enter_editmode); + make_prim_finish(C, obedit, &creation_data, enter_editmode); return OPERATOR_FINISHED; } @@ -510,17 +515,17 @@ void MESH_OT_primitive_monkey_add(wmOperatorType *ot) static int add_primitive_uvsphere_exec(bContext *C, wmOperator *op) { + MakePrimitiveData creation_data; Object *obedit; BMEditMesh *em; - float loc[3], rot[3], mat[4][4], dia; + float loc[3], rot[3]; bool enter_editmode; - bool was_editmode; unsigned int layer; const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs"); WM_operator_view3d_unit_defaults(C, op); ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &layer, NULL); - obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Sphere"), &dia, mat, &was_editmode, loc, rot, layer); + obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Sphere"), loc, rot, layer, &creation_data); em = BKE_editmesh_from_object(obedit); if (calc_uvs) { @@ -531,12 +536,12 @@ static int add_primitive_uvsphere_exec(bContext *C, wmOperator *op) em, op, "verts.out", false, "create_uvsphere u_segments=%i v_segments=%i diameter=%f matrix=%m4 calc_uvs=%b", RNA_int_get(op->ptr, "segments"), RNA_int_get(op->ptr, "ring_count"), - RNA_float_get(op->ptr, "size"), mat, calc_uvs)) + RNA_float_get(op->ptr, "size"), creation_data.mat, calc_uvs)) { return OPERATOR_CANCELLED; } - make_prim_finish(C, obedit, was_editmode, enter_editmode); + make_prim_finish(C, obedit, &creation_data, enter_editmode); return OPERATOR_FINISHED; } @@ -566,17 +571,17 @@ void MESH_OT_primitive_uv_sphere_add(wmOperatorType *ot) static int add_primitive_icosphere_exec(bContext *C, wmOperator *op) { + MakePrimitiveData creation_data; Object *obedit; BMEditMesh *em; - float loc[3], rot[3], mat[4][4], dia; + float loc[3], rot[3]; bool enter_editmode; - bool was_editmode; unsigned int layer; const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs"); WM_operator_view3d_unit_defaults(C, op); ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &layer, NULL); - obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Icosphere"), &dia, mat, &was_editmode, loc, rot, layer); + obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Icosphere"), loc, rot, layer, &creation_data); em = BKE_editmesh_from_object(obedit); if (calc_uvs) { @@ -587,12 +592,12 @@ static int add_primitive_icosphere_exec(bContext *C, wmOperator *op) em, op, "verts.out", false, "create_icosphere subdivisions=%i diameter=%f matrix=%m4 calc_uvs=%b", RNA_int_get(op->ptr, "subdivisions"), - RNA_float_get(op->ptr, "size"), mat, calc_uvs)) + RNA_float_get(op->ptr, "size"), creation_data.mat, calc_uvs)) { return OPERATOR_CANCELLED; } - make_prim_finish(C, obedit, was_editmode, enter_editmode); + make_prim_finish(C, obedit, &creation_data, enter_editmode); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/mesh/editmesh_inset.c b/source/blender/editors/mesh/editmesh_inset.c index afe52ec69f4..6fd4203e085 100644 --- a/source/blender/editors/mesh/editmesh_inset.c +++ b/source/blender/editors/mesh/editmesh_inset.c @@ -373,10 +373,12 @@ static int edbm_inset_modal(bContext *C, wmOperator *op, const wmEvent *event) case LEFTMOUSE: case PADENTER: case RETKEY: - edbm_inset_calc(op); - edbm_inset_exit(C, op); - return OPERATOR_FINISHED; - + if (event->val == KM_PRESS) { + edbm_inset_calc(op); + edbm_inset_exit(C, op); + return OPERATOR_FINISHED; + } + break; case LEFTSHIFTKEY: case RIGHTSHIFTKEY: if (event->val == KM_PRESS) { diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c index c0501078424..5d5e54edf56 100644 --- a/source/blender/editors/mesh/editmesh_knife.c +++ b/source/blender/editors/mesh/editmesh_knife.c @@ -1562,8 +1562,8 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd) } /* unproject screen line */ - ED_view3d_win_to_segment(kcd->ar, kcd->vc.v3d, s1, v1, v3, true); - ED_view3d_win_to_segment(kcd->ar, kcd->vc.v3d, s2, v2, v4, true); + ED_view3d_win_to_segment(kcd->eval_ctx.depsgraph, kcd->ar, kcd->vc.v3d, s1, v1, v3, true); + ED_view3d_win_to_segment(kcd->eval_ctx.depsgraph, kcd->ar, kcd->vc.v3d, s2, v2, v4, true); mul_m4_v3(kcd->ob->imat, v1); mul_m4_v3(kcd->ob->imat, v2); @@ -2519,7 +2519,8 @@ static void knife_recalc_projmat(KnifeTool_OpData *kcd) mul_v3_mat3_m4v3(kcd->proj_zaxis, kcd->ob->imat, kcd->vc.rv3d->viewinv[2]); normalize_v3(kcd->proj_zaxis); - kcd->is_ortho = ED_view3d_clip_range_get(kcd->vc.v3d, kcd->vc.rv3d, + kcd->is_ortho = ED_view3d_clip_range_get(kcd->eval_ctx.depsgraph, + kcd->vc.v3d, kcd->vc.rv3d, &kcd->clipsta, &kcd->clipend, true); } diff --git a/source/blender/editors/mesh/editmesh_loopcut.c b/source/blender/editors/mesh/editmesh_loopcut.c index 3ab56f2ebcb..793e5609d31 100644 --- a/source/blender/editors/mesh/editmesh_loopcut.c +++ b/source/blender/editors/mesh/editmesh_loopcut.c @@ -762,7 +762,15 @@ static int loopcut_modal(bContext *C, wmOperator *op, const wmEvent *event) handled = true; break; case MOUSEMOVE: /* mouse moved somewhere to select another loop */ - if (!has_numinput) { + + /* This is normally disabled for all modal operators. + * This is an exception since mouse movement doesn't relate to numeric input. + * + * If numeric input changes we'll need to add this back see: D2973 */ +#if 0 + if (!has_numinput) +#endif + { lcd->vc.mval[0] = event->mval[0]; lcd->vc.mval[1] = event->mval[1]; loopcut_mouse_move(&eval_ctx, lcd, (int)lcd->cuts); diff --git a/source/blender/editors/mesh/editmesh_polybuild.c b/source/blender/editors/mesh/editmesh_polybuild.c index f398f087da9..dff501ece13 100644 --- a/source/blender/editors/mesh/editmesh_polybuild.c +++ b/source/blender/editors/mesh/editmesh_polybuild.c @@ -416,6 +416,7 @@ static BMElem *edbm_hover_preselect( BMElem *ele_best = NULL; if (ED_view3d_win_to_ray( + CTX_data_depsgraph(C), vc.ar, vc.v3d, mval_fl, ray_origin, ray_direction, true)) { diff --git a/source/blender/editors/mesh/editmesh_rip.c b/source/blender/editors/mesh/editmesh_rip.c index 1a2f9fdb62b..0c8bd560bb2 100644 --- a/source/blender/editors/mesh/editmesh_rip.c +++ b/source/blender/editors/mesh/editmesh_rip.c @@ -590,7 +590,7 @@ static int edbm_rip_invoke__vert(bContext *C, wmOperator *op, const wmEvent *eve } } - if (e_best && (is_manifold_region == false)) { + if (e_best && e_best->l && (is_manifold_region == false)) { /* Try to split off a non-manifold fan (when we have multiple disconnected fans) */ BMLoop *l_sep = e_best->l->v == v ? e_best->l : e_best->l->next; BMVert *v_new; diff --git a/source/blender/editors/mesh/editmesh_utils.c b/source/blender/editors/mesh/editmesh_utils.c index 27fe93b049a..a52f12ec055 100644 --- a/source/blender/editors/mesh/editmesh_utils.c +++ b/source/blender/editors/mesh/editmesh_utils.c @@ -398,7 +398,7 @@ void EDBM_mesh_load(Object *ob) * of freed data on scene update, especially in cases when there are dependency * cycles. */ - /* +#if 0 for (Object *other_object = G.main->object.first; other_object != NULL; other_object = other_object->id.next) @@ -407,7 +407,7 @@ void EDBM_mesh_load(Object *ob) BKE_object_free_derived_caches(other_object); } } - */ +#endif } /** @@ -1392,7 +1392,9 @@ static void scale_point(float c1[3], const float p[3], const float s) add_v3_v3(c1, p); } -bool BMBVH_EdgeVisible(struct BMBVHTree *tree, BMEdge *e, ARegion *ar, View3D *v3d, Object *obedit) +bool BMBVH_EdgeVisible(struct BMBVHTree *tree, BMEdge *e, + const struct Depsgraph *depsgraph, + ARegion *ar, View3D *v3d, Object *obedit) { BMFace *f; float co1[3], co2[3], co3[3], dir1[3], dir2[3], dir3[3]; @@ -1402,7 +1404,7 @@ bool BMBVH_EdgeVisible(struct BMBVHTree *tree, BMEdge *e, ARegion *ar, View3D *v const float mval_f[2] = {ar->winx / 2.0f, ar->winy / 2.0f}; - ED_view3d_win_to_segment(ar, v3d, mval_f, origin, end, false); + ED_view3d_win_to_segment(depsgraph, ar, v3d, mval_f, origin, end, false); invert_m4_m4(invmat, obedit->obmat); mul_m4_v3(invmat, origin); diff --git a/source/blender/editors/mesh/mesh_navmesh.c b/source/blender/editors/mesh/mesh_navmesh.c index d7e59a05772..bd2ad21d51c 100644 --- a/source/blender/editors/mesh/mesh_navmesh.c +++ b/source/blender/editors/mesh/mesh_navmesh.c @@ -75,7 +75,7 @@ static void createVertsTrisData(bContext *C, LinkNode *obs, DerivedMesh *dm; Scene *scene = CTX_data_scene(C); EvaluationContext eval_ctx; - LinkNode *dms = NULL; + LinkNodePair dms_pair = {NULL, NULL}; int nverts, ntris, *tris; float *verts; @@ -90,7 +90,7 @@ static void createVertsTrisData(bContext *C, LinkNode *obs, ob = (Object *) oblink->link; dm = mesh_create_derived_no_virtual(&eval_ctx, scene, ob, NULL, CD_MASK_MESH); DM_ensure_tessface(dm); - BLI_linklist_prepend(&dms, dm); + BLI_linklist_append(&dms_pair, dm); nverts += dm->getNumVerts(dm); nfaces = dm->getNumTessFaces(dm); @@ -106,6 +106,7 @@ static void createVertsTrisData(bContext *C, LinkNode *obs, *r_lay |= ob->lay; } + LinkNode *dms = dms_pair.list; /* create data */ verts = MEM_mallocN(sizeof(float) * 3 * nverts, "createVertsTrisData verts"); diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c index e8807432328..5c96c13ebed 100644 --- a/source/blender/editors/object/object_add.c +++ b/source/blender/editors/object/object_add.c @@ -92,7 +92,6 @@ #include "BKE_scene.h" #include "BKE_screen.h" #include "BKE_speaker.h" -#include "BKE_texture.h" #include "DEG_depsgraph.h" #include "DEG_depsgraph_build.h" @@ -1101,6 +1100,7 @@ static int group_instance_add_exec(bContext *C, wmOperator *op) /* works without this except if you try render right after, see: 22027 */ DEG_relations_tag_update(bmain); + DEG_id_tag_update(&group->id, 0); WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene); @@ -2086,7 +2086,7 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, ViewLayer #define ID_NEW_REMAP_US(a) if ( (a)->id.newid) { (a) = (void *)(a)->id.newid; (a)->id.us++; } #define ID_NEW_REMAP_US2(a) if (((ID *)a)->newid) { (a) = ((ID *)a)->newid; ((ID *)a)->us++; } - Base *basen = NULL; + Base *base, *basen = NULL; Material ***matarar; Object *obn; ID *id; @@ -2099,7 +2099,14 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, ViewLayer obn = ID_NEW_SET(ob, BKE_object_copy(bmain, ob)); DEG_id_tag_update(&obn->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); - BKE_collection_object_add_from(scene, ob, obn); + base = BKE_view_layer_base_find(view_layer, ob); + if ((base != NULL) && (base->flag & BASE_VISIBLED)) { + BKE_collection_object_add_from(scene, ob, obn); + } + else { + LayerCollection *layer_collection = BKE_layer_collection_get_active_ensure(scene, view_layer); + BKE_collection_object_add(&scene->id, layer_collection->scene_collection, obn); + } basen = BKE_view_layer_base_find(view_layer, obn); /* 1) duplis should end up in same group as the original @@ -2449,13 +2456,13 @@ static int add_named_exec(bContext *C, wmOperator *op) clear_sca_new_poins(); /* BGE logic */ basen = object_add_duplicate_internal(bmain, scene, view_layer, ob, dupflag); - BKE_scene_object_base_flag_sync_from_object(basen); if (basen == NULL) { BKE_report(op->reports, RPT_ERROR, "Object could not be duplicated"); return OPERATOR_CANCELLED; } + BKE_scene_object_base_flag_sync_from_object(basen); basen->object->restrictflag &= ~OB_RESTRICT_VIEW; if (event) { @@ -2473,9 +2480,11 @@ static int add_named_exec(bContext *C, wmOperator *op) BKE_main_id_clear_newpoins(bmain); + /* TODO(sergey): Only update relations for the current scene. */ DEG_relations_tag_update(bmain); - WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT | ND_OB_ACTIVE, scene); + WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); + WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/object/object_intern.h b/source/blender/editors/object/object_intern.h index c38a7d58904..03aacc86ea7 100644 --- a/source/blender/editors/object/object_intern.h +++ b/source/blender/editors/object/object_intern.h @@ -68,7 +68,7 @@ void OBJECT_OT_track_clear(struct wmOperatorType *ot); void OBJECT_OT_slow_parent_set(struct wmOperatorType *ot); void OBJECT_OT_slow_parent_clear(struct wmOperatorType *ot); void OBJECT_OT_make_local(struct wmOperatorType *ot); -void OBJECT_OT_make_override(struct wmOperatorType *ot); +void OBJECT_OT_make_override_static(struct wmOperatorType *ot); void OBJECT_OT_make_single_user(struct wmOperatorType *ot); void OBJECT_OT_make_links_scene(struct wmOperatorType *ot); void OBJECT_OT_make_links_data(struct wmOperatorType *ot); diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c index ceea3b9c0ac..9c321f5cb79 100644 --- a/source/blender/editors/object/object_ops.c +++ b/source/blender/editors/object/object_ops.c @@ -84,7 +84,7 @@ void ED_operatortypes_object(void) WM_operatortype_append(OBJECT_OT_slow_parent_set); WM_operatortype_append(OBJECT_OT_slow_parent_clear); WM_operatortype_append(OBJECT_OT_make_local); - WM_operatortype_append(OBJECT_OT_make_override); + WM_operatortype_append(OBJECT_OT_make_override_static); WM_operatortype_append(OBJECT_OT_make_single_user); WM_operatortype_append(OBJECT_OT_make_links_scene); WM_operatortype_append(OBJECT_OT_make_links_data); diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c index 436364ec6c3..d73e3aabaf0 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -1678,9 +1678,6 @@ static void single_object_users_scene_collection(Main *bmain, Scene *scene, Scen } } - /* we reset filter objects because they should be regenerated after this */ - BLI_freelistN(&sc->filter_objects); - for (SceneCollection *nsc = sc->scene_collections.first; nsc; nsc = nsc->next) { single_object_users_scene_collection(bmain, scene, nsc, flag, copy_groups); } @@ -1740,9 +1737,6 @@ static void single_object_users(Main *bmain, Scene *scene, View3D *v3d, const in libblock_relink_scene_collection(msc); set_sca_new_poins(); - - /* TODO redo filter */ - TODO_LAYER_SYNC_FILTER } /* not an especially efficient function, only added so the single user @@ -2335,42 +2329,194 @@ void OBJECT_OT_make_local(wmOperatorType *ot) ot->prop = RNA_def_enum(ot->srna, "type", type_items, 0, "Type", ""); } -static int make_override_exec(bContext *C, wmOperator *UNUSED(op)) + +static void make_override_static_tag_object(Object *obact, Object *ob) +{ + if (ob == obact) { + return; + } + + if (!ID_IS_LINKED(ob)) { + return; + } + + /* Note: all this is very case-by-case bad handling, ultimately we'll want a real full 'automatic', generic + * handling of all this, will probably require adding some override-aware stuff to library_query code... */ + + if (obact->type == OB_ARMATURE && ob->modifiers.first != NULL) { + for (ModifierData *md = ob->modifiers.first; md != NULL; md = md->next) { + if (md->type == eModifierType_Armature) { + ArmatureModifierData *amd = (ArmatureModifierData *)md; + if (amd->object == obact) { + ob->id.tag |= LIB_TAG_DOIT; + break; + } + } + } + } + else if (ob->parent == obact) { + ob->id.tag |= LIB_TAG_DOIT; + } + + if (ob->id.tag & LIB_TAG_DOIT) { + printf("Indirectly overriding %s for %s\n", ob->id.name, obact->id.name); + } +} + +/* Set the object to override. */ +static int make_override_static_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + Scene *scene = CTX_data_scene(C); + Object *obact = ED_object_active_context(C); + + /* Sanity checks. */ + if (!scene || ID_IS_LINKED(scene) || !obact) { + return OPERATOR_CANCELLED; + } + + /* Get object to work on - use a menu if we need to... */ + if (!ID_IS_LINKED(obact) && obact->dup_group != NULL && ID_IS_LINKED(obact->dup_group)) { + /* Gives menu with list of objects in group. */ + WM_enum_search_invoke(C, op, event); + return OPERATOR_CANCELLED; + } + else if (ID_IS_LINKED(obact)) { + uiPopupMenu *pup = UI_popup_menu_begin(C, IFACE_("OK?"), ICON_QUESTION); + uiLayout *layout = UI_popup_menu_layout(pup); + + /* Create operator menu item with relevant properties filled in. */ + PointerRNA opptr_dummy; + uiItemFullO_ptr(layout, op->type, op->type->name, ICON_NONE, NULL, + WM_OP_EXEC_REGION_WIN, 0, &opptr_dummy); + + /* Present the menu and be done... */ + UI_popup_menu_end(C, pup); + + /* This invoke just calls another instance of this operator... */ + return OPERATOR_INTERFACE; + } + else { + /* Error.. cannot continue. */ + BKE_report(op->reports, RPT_ERROR, "Can only make static override for a referenced object or group"); + return OPERATOR_CANCELLED; + } + +} + +static int make_override_static_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); - Object *locobj, *refobj = CTX_data_active_object(C); + Object *obact = CTX_data_active_object(C); + + bool success = false; + + if (!ID_IS_LINKED(obact) && obact->dup_group != NULL && ID_IS_LINKED(obact->dup_group)) { +#if 0 /* Not working yet! */ + Base *base = BLI_findlink(&obact->dup_group->view_layer->object_bases, RNA_enum_get(op->ptr, "object")); + Object *obgroup = obact; + obact = base->object; + + /* First, we make a static override of the linked group itself. */ + obgroup->dup_group->id.tag |= LIB_TAG_DOIT; + + /* Then, we tag our 'main' object and its detected dependencies to be also overridden. */ + obact->id.tag |= LIB_TAG_DOIT; + + FOREACH_GROUP_OBJECT(obgroup->dup_group, ob) + { + make_override_tag_object(obact, ob); + } + FOREACH_GROUP_OBJECT_END; + + success = BKE_override_static_create_from_tag(bmain); + + /* Intantiate our 'main' newly overridden object in scene, if not yet done. */ + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + Object *new_obact = (Object *)obact->id.newid; + if (new_obact != NULL && (base = BKE_view_layer_base_find(view_layer, new_obact)) == NULL) { + BKE_collection_object_add_from(scene, obact, new_obact); + base = BKE_view_layer_base_find(view_layer, new_obact); + BKE_view_layer_base_select(view_layer, base); + } + + /* Parent the group instantiating object to the new overridden one, or vice-versa, if possible. */ + if (obgroup->parent == NULL) { + obgroup->parent = new_obact; + } + else if (new_obact->parent == NULL) { + new_obact->parent = obgroup; + } + + /* Also, we'd likely want to lock by default things like transformations of implicitly overriden objects? */ + + /* Cleanup. */ + BKE_main_id_clear_newpoins(bmain); + BKE_main_id_tag_listbase(&bmain->object, LIB_TAG_DOIT, false); +#else + UNUSED_VARS(op); +#endif + } + /* Else, poll func ensures us that ID_IS_LINKED(obact) is true. */ + else if (obact->type == OB_ARMATURE) { + BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false); - locobj = (Object *)BKE_override_static_create_from(bmain, &refobj->id); - UNUSED_VARS(locobj); + obact->id.tag |= LIB_TAG_DOIT; + + for (Object *ob = bmain->object.first; ob != NULL; ob = ob->id.next) { + make_override_static_tag_object(obact, ob); + } + + success = BKE_override_static_create_from_tag(bmain); + + /* Also, we'd likely want to lock by default things like transformations of implicitly overriden objects? */ + + /* Cleanup. */ + BKE_main_id_clear_newpoins(bmain); + BKE_main_id_tag_listbase(&bmain->object, LIB_TAG_DOIT, false); + } + /* TODO: probably more cases where we want ot do automated smart things in the future! */ + else { + success = (BKE_override_static_create_from_id(bmain, &obact->id) != NULL); + } WM_event_add_notifier(C, NC_WINDOW, NULL); - return OPERATOR_FINISHED; + return success ? OPERATOR_FINISHED : OPERATOR_CANCELLED; } -static int make_override_poll(bContext *C) +static int make_override_static_poll(bContext *C) { Object *obact = CTX_data_active_object(C); /* Object must be directly linked to be overridable. */ - return (ED_operator_objectmode(C) && obact && obact->id.lib != NULL && obact->id.tag & LIB_TAG_EXTERN); + return (ED_operator_objectmode(C) && obact != NULL && + ((ID_IS_LINKED(obact) && obact->id.tag & LIB_TAG_EXTERN) || + (!ID_IS_LINKED(obact) && obact->dup_group != NULL && ID_IS_LINKED(obact->dup_group)))); } -void OBJECT_OT_make_override(wmOperatorType *ot) +void OBJECT_OT_make_override_static(wmOperatorType *ot) { /* identifiers */ - ot->name = "Make Override"; + ot->name = "Make Static Override"; ot->description = "Make local override of this library linked data-block"; - ot->idname = "OBJECT_OT_make_override"; + ot->idname = "OBJECT_OT_make_override_static"; /* api callbacks */ - ot->exec = make_override_exec; - ot->poll = make_override_poll; + ot->invoke = make_override_static_invoke; + ot->exec = make_override_static_exec; + ot->poll = make_override_static_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; /* properties */ + PropertyRNA *prop; + prop = RNA_def_enum(ot->srna, "object", DummyRNA_DEFAULT_items, 0, "Proxy Object", + "Name of lib-linked/grouped object to make a proxy for"); + RNA_def_enum_funcs(prop, proxy_group_object_itemf); + RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE); + ot->prop = prop; } enum { diff --git a/source/blender/editors/object/object_select.c b/source/blender/editors/object/object_select.c index 552380cebdb..b20fe9a004c 100644 --- a/source/blender/editors/object/object_select.c +++ b/source/blender/editors/object/object_select.c @@ -625,9 +625,9 @@ static bool select_grouped_object_hooks(bContext *C, Object *ob) for (md = ob->modifiers.first; md; md = md->next) { if (md->type == eModifierType_Hook) { hmd = (HookModifierData *) md; - if (hmd->object && !(hmd->object->flag & SELECT)) { + if (hmd->object) { base = BKE_view_layer_base_find(view_layer, hmd->object); - if (base && (BASE_SELECTABLE(base))) { + if (base && ((base->flag & BASE_SELECTED) == 0) && (BASE_SELECTABLE(base))) { ED_object_base_select(base, BA_SELECT); changed = true; } @@ -1107,12 +1107,12 @@ static bool object_select_more_less(bContext *C, const bool select) bool changed = false; const short select_mode = select ? BA_SELECT : BA_DESELECT; - const short select_flag = select ? SELECT : 0; + const short select_flag = select ? BASE_SELECTED : 0; for (ctx_base = ctx_base_list.first; ctx_base; ctx_base = ctx_base->next) { Base *base = ctx_base->ptr.data; Object *ob = base->object; - if ((ob->id.tag & LIB_TAG_DOIT) && ((ob->flag & SELECT) != select_flag)) { + if ((ob->id.tag & LIB_TAG_DOIT) && ((base->flag & BASE_SELECTED) != select_flag)) { ED_object_base_select(base, select_mode); changed = true; } diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c index 53bc289d378..89dd46681cb 100644 --- a/source/blender/editors/physics/particle_edit.c +++ b/source/blender/editors/physics/particle_edit.c @@ -3517,6 +3517,7 @@ static int particle_intersect_dm(const bContext *C, Scene *scene, Object *ob, De static int brush_add(const bContext *C, PEData *data, short number) { EvaluationContext eval_ctx; + const Depsgraph *depsgraph = CTX_data_depsgraph(C); Scene *scene= data->scene; Object *ob= data->ob; DerivedMesh *dm; @@ -3580,7 +3581,7 @@ static int brush_add(const bContext *C, PEData *data, short number) mco[0] = data->mval[0] + dmx; mco[1] = data->mval[1] + dmy; - ED_view3d_win_to_segment(data->vc.ar, data->vc.v3d, mco, co1, co2, true); + ED_view3d_win_to_segment(depsgraph, data->vc.ar, data->vc.v3d, mco, co1, co2, true); mul_m4_v3(imat, co1); mul_m4_v3(imat, co2); diff --git a/source/blender/editors/physics/particle_object.c b/source/blender/editors/physics/particle_object.c index 4fee14dc71d..1536c15525f 100644 --- a/source/blender/editors/physics/particle_object.c +++ b/source/blender/editors/physics/particle_object.c @@ -200,7 +200,7 @@ static int new_particle_settings_exec(bContext *C, wmOperator *UNUSED(op)) if (psys->part) part= BKE_particlesettings_copy(bmain, psys->part); else - part= psys_new_settings("ParticleSettings", bmain); + part= BKE_particlesettings_add(bmain, "ParticleSettings"); ob= ptr.id.data; diff --git a/source/blender/editors/render/render_internal.c b/source/blender/editors/render/render_internal.c index 4e75ca3e6f1..3be890f2c36 100644 --- a/source/blender/editors/render/render_internal.c +++ b/source/blender/editors/render/render_internal.c @@ -295,6 +295,7 @@ static void screen_render_view_layer_set(wmOperator *op, Main *mainp, Scene **sc static int screen_render_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); + RenderEngineType *re_type = RE_engines_find(scene->view_render.engine_id); ViewLayer *view_layer = NULL; Depsgraph *depsgraph = CTX_data_depsgraph(C); Render *re; @@ -306,6 +307,11 @@ static int screen_render_exec(bContext *C, wmOperator *op) const bool is_write_still = RNA_boolean_get(op->ptr, "write_still"); struct Object *camera_override = v3d ? V3D_CAMERA_LOCAL(v3d) : NULL; + /* Cannot do render if there is not this function. */ + if (re_type->render_to_image == NULL) { + return OPERATOR_CANCELLED; + } + /* custom scene and single layer re-render */ screen_render_view_layer_set(op, mainp, &scene, &view_layer); @@ -844,6 +850,7 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even Main *mainp; ViewLayer *view_layer = NULL; Scene *scene = CTX_data_scene(C); + RenderEngineType *re_type = RE_engines_find(scene->view_render.engine_id); Render *re; wmJob *wm_job; RenderJob *rj; @@ -856,6 +863,18 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even struct Object *camera_override = v3d ? V3D_CAMERA_LOCAL(v3d) : NULL; const char *name; ScrArea *sa; + + /* Cannot do render if there is not this function. */ + if (re_type->render_to_image == NULL) { + return OPERATOR_CANCELLED; + } + + /* XXX FIXME If engine is an OpenGL engine do not run modal. + * This is a problem for animation rendering since you cannot abort them. + * This also does not open an image editor space. */ + if (RE_engine_is_opengl(re_type)) { + return screen_render_exec(C, op); + } /* only one render job at a time */ if (WM_jobs_test(CTX_wm_manager(C), scene, WM_JOB_TYPE_RENDER)) @@ -1067,6 +1086,7 @@ typedef struct RenderPreview { wmJob *job; Scene *scene; + Depsgraph *depsgraph; ScrArea *sa; ARegion *ar; View3D *v3d; @@ -1081,7 +1101,8 @@ typedef struct RenderPreview { bool has_freestyle; } RenderPreview; -static int render_view3d_disprect(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D *rv3d, rcti *disprect) +static int render_view3d_disprect(Scene *scene, const Depsgraph *depsgraph, + ARegion *ar, View3D *v3d, RegionView3D *rv3d, rcti *disprect) { /* copied code from view3d_draw.c */ rctf viewborder; @@ -1094,7 +1115,7 @@ static int render_view3d_disprect(Scene *scene, ARegion *ar, View3D *v3d, Region if (draw_border) { if (rv3d->persp == RV3D_CAMOB) { - ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &viewborder, false); + ED_view3d_calc_camera_border(scene, depsgraph, ar, v3d, rv3d, &viewborder, false); disprect->xmin = viewborder.xmin + scene->r.border.xmin * BLI_rctf_size_x(&viewborder); disprect->ymin = viewborder.ymin + scene->r.border.ymin * BLI_rctf_size_y(&viewborder); @@ -1116,13 +1137,15 @@ static int render_view3d_disprect(Scene *scene, ARegion *ar, View3D *v3d, Region } /* returns true if OK */ -static bool render_view3d_get_rects(ARegion *ar, View3D *v3d, RegionView3D *rv3d, rctf *viewplane, RenderEngine *engine, - float *r_clipsta, float *r_clipend, float *r_pixsize, bool *r_ortho) +static bool render_view3d_get_rects( + const Depsgraph *depsgraph, + ARegion *ar, View3D *v3d, RegionView3D *rv3d, rctf *viewplane, RenderEngine *engine, + float *r_clipsta, float *r_clipend, float *r_pixsize, bool *r_ortho) { if (ar->winx < 4 || ar->winy < 4) return false; - *r_ortho = ED_view3d_viewplane_get(v3d, rv3d, ar->winx, ar->winy, viewplane, r_clipsta, r_clipend, r_pixsize); + *r_ortho = ED_view3d_viewplane_get(depsgraph, v3d, rv3d, ar->winx, ar->winy, viewplane, r_clipsta, r_clipend, r_pixsize); engine->resolution_x = ar->winx; engine->resolution_y = ar->winy; @@ -1229,7 +1252,7 @@ static void render_view3d_startjob(void *customdata, short *stop, short *do_upda G.is_break = false; - if (false == render_view3d_get_rects(rp->ar, rp->v3d, rp->rv3d, &viewplane, rp->engine, &clipsta, &clipend, &pixsize, &orth)) + if (false == render_view3d_get_rects(rp->depsgraph, rp->ar, rp->v3d, rp->rv3d, &viewplane, rp->engine, &clipsta, &clipend, &pixsize, &orth)) return; rp->stop = stop; @@ -1262,8 +1285,9 @@ static void render_view3d_startjob(void *customdata, short *stop, short *do_upda } } - use_border = render_view3d_disprect(rp->scene, rp->ar, rp->v3d, - rp->rv3d, &cliprct); + use_border = render_view3d_disprect(rp->scene, rp->depsgraph, + rp->ar, rp->v3d, rp->rv3d, + &cliprct); if ((update_flag & (PR_UPDATE_RENDERSIZE | PR_UPDATE_DATABASE | PR_UPDATE_VIEW)) || rstats->convertdone == 0) { RenderData rdata; @@ -1386,6 +1410,7 @@ static bool render_view3d_flag_changed(RenderEngine *engine, const bContext *C) View3D *v3d = CTX_wm_view3d(C); ARegion *ar = CTX_wm_region(C); Scene *scene = CTX_data_scene(C); + Depsgraph *depsgraph = CTX_data_depsgraph(C); Render *re; rctf viewplane; rcti disprect; @@ -1435,14 +1460,14 @@ static bool render_view3d_flag_changed(RenderEngine *engine, const bContext *C) job_update_flag |= PR_UPDATE_VIEW; } - render_view3d_get_rects(ar, v3d, rv3d, &viewplane, engine, &clipsta, &clipend, NULL, &orth); + render_view3d_get_rects(depsgraph, ar, v3d, rv3d, &viewplane, engine, &clipsta, &clipend, NULL, &orth); if (BLI_rctf_compare(&viewplane, &engine->last_viewplane, 0.00001f) == 0) { engine->last_viewplane = viewplane; job_update_flag |= PR_UPDATE_VIEW; } - render_view3d_disprect(scene, ar, v3d, rv3d, &disprect); + render_view3d_disprect(scene, depsgraph, ar, v3d, rv3d, &disprect); if (BLI_rcti_compare(&disprect, &engine->last_disprect) == 0) { engine->last_disprect = disprect; job_update_flag |= PR_UPDATE_RENDERSIZE; @@ -1462,6 +1487,7 @@ static void render_view3d_do(RenderEngine *engine, const bContext *C) wmJob *wm_job; RenderPreview *rp; Scene *scene = CTX_data_scene(C); + Depsgraph *depsgraph = CTX_data_depsgraph(C); ARegion *ar = CTX_wm_region(C); int width = ar->winx, height = ar->winy; int divider = BKE_render_preview_pixel_size(&scene->r); @@ -1486,6 +1512,7 @@ static void render_view3d_do(RenderEngine *engine, const bContext *C) /* customdata for preview thread */ rp->scene = scene; + rp->depsgraph = depsgraph; rp->engine = engine; rp->sa = CTX_wm_area(C); rp->ar = CTX_wm_region(C); @@ -1543,6 +1570,7 @@ void render_view3d_draw(RenderEngine *engine, const bContext *C) RegionView3D *rv3d = CTX_wm_region_view3d(C); View3D *v3d = CTX_wm_view3d(C); Scene *scene = CTX_data_scene(C); + Depsgraph *depsgraph = CTX_data_depsgraph(C); ARegion *ar = CTX_wm_region(C); bool force_fallback = false; bool need_fallback = true; @@ -1551,7 +1579,7 @@ void render_view3d_draw(RenderEngine *engine, const bContext *C) rcti clip_rect; int xof, yof; - if (render_view3d_disprect(scene, ar, v3d, rv3d, &clip_rect)) { + if (render_view3d_disprect(scene, depsgraph, ar, v3d, rv3d, &clip_rect)) { scale_x = (float) BLI_rcti_size_x(&clip_rect) / rres.rectx; scale_y = (float) BLI_rcti_size_y(&clip_rect) / rres.recty; xof = clip_rect.xmin; diff --git a/source/blender/editors/render/render_opengl.c b/source/blender/editors/render/render_opengl.c index 3c63aed9473..6e969067985 100644 --- a/source/blender/editors/render/render_opengl.c +++ b/source/blender/editors/render/render_opengl.c @@ -279,7 +279,7 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R const short view_context = (v3d != NULL); bool draw_bgpic = true; bool draw_sky = (scene->r.alphamode == R_ADDSKY); - unsigned char *rect = NULL; + float *rectf = NULL; const char *viewname = RE_GetActiveRenderView(oglrender->re); ImBuf *ibuf_result = NULL; EvaluationContext eval_ctx; @@ -360,7 +360,7 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R ibuf_view = ED_view3d_draw_offscreen_imbuf( &eval_ctx, scene, view_layer, v3d, ar, sizex, sizey, - IB_rect, draw_flags, alpha_mode, oglrender->ofs_samples, viewname, + IB_rectfloat, draw_flags, alpha_mode, oglrender->ofs_samples, viewname, oglrender->fx, oglrender->ofs, err_out); /* for stamp only */ @@ -372,7 +372,7 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R draw_flags |= (V3D_OFSDRAW_USE_GPENCIL | V3D_OFSDRAW_USE_BACKGROUND); ibuf_view = ED_view3d_draw_offscreen_imbuf_simple( &eval_ctx, scene, view_layer, scene->camera, oglrender->sizex, oglrender->sizey, - IB_rect, draw_flags, OB_SOLID, + IB_rectfloat, draw_flags, OB_SOLID, alpha_mode, oglrender->ofs_samples, viewname, oglrender->fx, oglrender->ofs, err_out); camera = scene->camera; @@ -380,7 +380,7 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R if (ibuf_view) { ibuf_result = ibuf_view; - rect = (unsigned char *)ibuf_view->rect; + rectf = (float *)ibuf_view->rect_float; } else { fprintf(stderr, "%s: failed to get buffer, %s\n", __func__, err_out); @@ -389,7 +389,7 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R if (ibuf_result != NULL) { if ((scene->r.stamp & R_STAMP_ALL) && (scene->r.stamp & R_STAMP_DRAW)) { - BKE_image_stamp_buf(scene, camera, NULL, rect, NULL, rr->rectx, rr->recty, 4); + BKE_image_stamp_buf(scene, camera, NULL, NULL, rectf, rr->rectx, rr->recty, 4); } RE_render_result_rect_from_ibuf(rr, &scene->r, ibuf_result, oglrender->view_id); IMB_freeImBuf(ibuf_result); @@ -652,7 +652,7 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op) sizey = (scene->r.size * scene->r.ysch) / 100; /* corrects render size with actual size, not every card supports non-power-of-two dimensions */ - ofs = GPU_offscreen_create(sizex, sizey, full_samples ? 0 : samples, err_out); + ofs = GPU_offscreen_create(sizex, sizey, full_samples ? 0 : samples, true, err_out); if (!ofs) { BKE_reportf(op->reports, RPT_ERROR, "Failed to create OpenGL off-screen buffer, %s", err_out); diff --git a/source/blender/editors/render/render_preview.c b/source/blender/editors/render/render_preview.c index 47794e0e357..2e3091268a9 100644 --- a/source/blender/editors/render/render_preview.c +++ b/source/blender/editors/render/render_preview.c @@ -313,11 +313,10 @@ static void set_preview_layer(ViewLayer *view_layer, char pr_type) for (lc = view_layer->layer_collections.first; lc; lc = lc->next) { if (STREQ(lc->scene_collection->name, collection_name)) { - lc->flag = COLLECTION_VISIBLE | COLLECTION_DISABLED; - BKE_collection_enable(view_layer, lc); + lc->flag = COLLECTION_VIEWPORT | COLLECTION_RENDER; } else { - BKE_collection_disable(view_layer, lc); + lc->flag = COLLECTION_DISABLED; } } } @@ -330,7 +329,7 @@ static World *preview_get_localized_world(ShaderPreview *sp, World *world) if (sp->worldcopy != NULL) { return sp->worldcopy; } - sp->worldcopy = localize_world(world); + sp->worldcopy = BKE_world_localize(world); BLI_addtail(&sp->pr_main->world, sp->worldcopy); return sp->worldcopy; } @@ -396,7 +395,7 @@ static Scene *preview_prepare_scene(Main *bmain, Scene *scene, ID *id, int id_ty if (origmat) { /* work on a copy */ - mat = localize_material(origmat); + mat = BKE_material_localize(origmat); sp->matcopy = mat; BLI_addtail(&pr_main->mat, mat); @@ -551,7 +550,7 @@ static Scene *preview_prepare_scene(Main *bmain, Scene *scene, ID *id, int id_ty /* work on a copy */ if (origla) { - la = localize_lamp(origla); + la = BKE_lamp_localize(origla); sp->lampcopy = la; BLI_addtail(&pr_main->lamp, la); } @@ -589,7 +588,7 @@ static Scene *preview_prepare_scene(Main *bmain, Scene *scene, ID *id, int id_ty World *wrld = NULL, *origwrld = (World *)id; if (origwrld) { - wrld = localize_world(origwrld); + wrld = BKE_world_localize(origwrld); sp->worldcopy = wrld; BLI_addtail(&pr_main->world, wrld); } @@ -722,7 +721,7 @@ void ED_preview_draw(const bContext *C, void *idp, void *parentp, void *slotp, r if (ok) *rect = newrect; - /* start a new preview render job if signalled through sbuts->preview, + /* start a new preview render job if signaled through sbuts->preview, * if no render result was found and no preview render job is running, * or if the job is running and the size of preview changed */ if ((sbuts != NULL && sbuts->preview) || diff --git a/source/blender/editors/render/render_shading.c b/source/blender/editors/render/render_shading.c index 04604feab6a..270ba2a7947 100644 --- a/source/blender/editors/render/render_shading.c +++ b/source/blender/editors/render/render_shading.c @@ -427,7 +427,8 @@ static int material_slot_move_exec(bContext *C, wmOperator *op) MEM_freeN(slot_remap); DEG_id_tag_update(&ob->id, OB_RECALC_DATA); - WM_event_add_notifier(C, NC_OBJECT | ND_DRAW | ND_DATA, ob); + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); + WM_event_add_notifier(C, NC_OBJECT | ND_DATA, ob); return OPERATOR_FINISHED; } @@ -582,7 +583,7 @@ static int new_world_exec(bContext *C, wmOperator *UNUSED(op)) wo = BKE_world_copy(bmain, wo); } else { - wo = add_world(bmain, DATA_("World")); + wo = BKE_world_add(bmain, DATA_("World")); if (BKE_scene_use_new_shading_nodes(scene)) { ED_node_shader_default(C, &wo->id); diff --git a/source/blender/editors/render/render_update.c b/source/blender/editors/render/render_update.c index a391b13a000..4943222f038 100644 --- a/source/blender/editors/render/render_update.c +++ b/source/blender/editors/render/render_update.c @@ -153,6 +153,7 @@ void ED_render_scene_update(const DEGEditorUpdateContext *update_ctx, int update DRW_notify_view_update( (&(DRWUpdateContext){ .bmain = bmain, + .depsgraph = update_ctx->depsgraph, .scene = scene, .view_layer = view_layer, .ar = ar, @@ -201,7 +202,9 @@ void ED_render_engine_changed(Main *bmain) update_ctx.bmain = bmain; for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) { update_ctx.scene = scene; - LINKLIST_FOREACH(ViewLayer *, view_layer, &scene->view_layers) { + BLI_LISTBASE_FOREACH(ViewLayer *, view_layer, &scene->view_layers) { + /* TDODO(sergey): Iterate over depsgraphs instead? */ + update_ctx.depsgraph = BKE_scene_get_depsgraph(scene, view_layer, true); update_ctx.view_layer = view_layer; ED_render_id_flush_update(&update_ctx, &scene->id); } @@ -309,7 +312,7 @@ static void material_changed(Main *bmain, Material *ma) BKE_icon_changed(BKE_icon_id_ensure(&ma->id)); /* glsl */ - if (ma->id.tag & LIB_TAG_ID_RECALC) { + if (ma->id.recalc & ID_RECALC) { if (!BLI_listbase_is_empty(&ma->gpumaterial)) { GPU_material_free(&ma->gpumaterial); } @@ -493,7 +496,7 @@ static void world_changed(Main *UNUSED(bmain), World *wo) wo->update_flag = 1; /* glsl */ - if (wo->id.tag & LIB_TAG_ID_RECALC) { + if (wo->id.recalc & ID_RECALC) { if (!BLI_listbase_is_empty(&defmaterial.gpumaterial)) { GPU_material_free(&defmaterial.gpumaterial); } @@ -539,8 +542,6 @@ void ED_render_id_flush_update(const DEGEditorUpdateContext *update_ctx, ID *id) return; } Main *bmain = update_ctx->bmain; - Scene *scene = update_ctx->scene; - ViewLayer *view_layer = update_ctx->view_layer; /* Internal ID update handlers. */ switch (GS(id->name)) { case ID_MA: @@ -567,42 +568,6 @@ void ED_render_id_flush_update(const DEGEditorUpdateContext *update_ctx, ID *id) render_engine_flag_changed(bmain, RE_ENGINE_UPDATE_OTHER); break; } - /* Inform all draw managers about changes. - * - * TODO(sergey): This code is run for every updated ID, via flushing - * mechanism. How can we avoid iterating over the whole interface for - * every of those IDs? One of the ideas would be to call draw manager's - * ID update which is not bound to any of contexts. - */ - { - wmWindowManager *wm = bmain->wm.first; - for (wmWindow *win = wm->windows.first; win; win = win->next) { - bScreen *sc = WM_window_get_active_screen(win); - WorkSpace *workspace = BKE_workspace_active_get(win->workspace_hook); - ViewRender *view_render = BKE_viewrender_get(win->scene, workspace); - for (ScrArea *sa = sc->areabase.first; sa; sa = sa->next) { - if (sa->spacetype != SPACE_VIEW3D) { - continue; - } - for (ARegion *ar = sa->regionbase.first; ar; ar = ar->next) { - if (ar->regiontype != RGN_TYPE_WINDOW) { - continue; - } - RenderEngineType *engine_type = RE_engines_find(view_render->engine_id); - DRW_notify_id_update( - (&(DRWUpdateContext){ - .bmain = bmain, - .scene = scene, - .view_layer = view_layer, - .ar = ar, - .v3d = (View3D *)sa->spacedata.first, - .engine_type = engine_type - }), - id); - } - } - } - } } diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c index dbeac782e10..f886a6ad613 100644 --- a/source/blender/editors/screen/area.c +++ b/source/blender/editors/screen/area.c @@ -769,6 +769,10 @@ static void area_azone_initialize(wmWindow *win, const bScreen *screen, ScrArea return; } + if (U.app_flag & USER_APP_LOCK_UI_LAYOUT) { + return; + } + /* can't click on bottom corners on OS X, already used for resizing */ #ifdef __APPLE__ if (!(sa->totrct.xmin == 0 && sa->totrct.ymin == 0) || WM_window_is_fullscreen(win)) diff --git a/source/blender/editors/screen/screen_draw.c b/source/blender/editors/screen/screen_draw.c index 5690076fedb..2e4e9127ed6 100644 --- a/source/blender/editors/screen/screen_draw.c +++ b/source/blender/editors/screen/screen_draw.c @@ -33,7 +33,6 @@ #include "screen_intern.h" - /** * Draw horizontal shape visualizing future joining (left as well right direction of future joining). */ @@ -289,18 +288,15 @@ static void drawscredge_area(ScrArea *sa, int sizex, int sizey, unsigned int pos } /** - * Only for edge lines between areas, and the blended join arrows. + * Only for edge lines between areas. */ -void ED_screen_draw(wmWindow *win) +void ED_screen_draw_edges(wmWindow *win) { bScreen *screen = WM_window_get_active_screen(win); const int winsize_x = WM_window_pixels_x(win); const int winsize_y = WM_window_pixels_y(win); ScrArea *sa; - ScrArea *sa1 = NULL; - ScrArea *sa2 = NULL; - ScrArea *sa3 = NULL; wmSubWindowSet(win, screen->mainwin); @@ -323,36 +319,47 @@ void ED_screen_draw(wmWindow *win) for (sa = screen->areabase.first; sa; sa = sa->next) { drawscredge_area(sa, winsize_x, winsize_y, pos); - - /* gather area split/join info */ - if (sa->flag & AREA_FLAG_DRAWJOINFROM) sa1 = sa; - if (sa->flag & AREA_FLAG_DRAWJOINTO) sa2 = sa; - if (sa->flag & (AREA_FLAG_DRAWSPLIT_H | AREA_FLAG_DRAWSPLIT_V)) sa3 = sa; } + immUnbindProgram(); + + screen->do_draw = false; +} + +/** + * The blended join arrows. + * + * \param sa1: Area from which the resultant originates. + * \param sa2: Target area that will be replaced. + */ +void ED_screen_draw_join_shape(ScrArea *sa1, ScrArea *sa2) +{ + unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + + glLineWidth(1); + /* blended join arrow */ - if (sa1 && sa2) { - int dir = area_getorientation(sa1, sa2); - int dira = -1; - if (dir != -1) { - switch (dir) { - case 0: /* W */ - dir = 'r'; - dira = 'l'; - break; - case 1: /* N */ - dir = 'd'; - dira = 'u'; - break; - case 2: /* E */ - dir = 'l'; - dira = 'r'; - break; - case 3: /* S */ - dir = 'u'; - dira = 'd'; - break; - } + int dir = area_getorientation(sa1, sa2); + int dira = -1; + if (dir != -1) { + switch (dir) { + case 0: /* W */ + dir = 'r'; + dira = 'l'; + break; + case 1: /* N */ + dir = 'd'; + dira = 'u'; + break; + case 2: /* E */ + dir = 'l'; + dira = 'r'; + break; + case 3: /* S */ + dir = 'u'; + dira = 'd'; + break; } glEnable(GL_BLEND); @@ -363,48 +370,59 @@ void ED_screen_draw(wmWindow *win) glDisable(GL_BLEND); } - /* splitpoint */ - if (sa3) { - glEnable(GL_BLEND); - immUniformColor4ub(255, 255, 255, 100); + immUnbindProgram(); +} - immBegin(GWN_PRIM_LINES, 2); +void ED_screen_draw_split_preview(ScrArea *sa, const int dir, const float fac) +{ + unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); - if (sa3->flag & AREA_FLAG_DRAWSPLIT_H) { - immVertex2f(pos, sa3->totrct.xmin, win->eventstate->y); - immVertex2f(pos, sa3->totrct.xmax, win->eventstate->y); + /* splitpoint */ + glEnable(GL_BLEND); + immUniformColor4ub(255, 255, 255, 100); - immEnd(); + immBegin(GWN_PRIM_LINES, 2); - immUniformColor4ub(0, 0, 0, 100); + if (dir == 'h') { + const float y = (1 - fac) * sa->totrct.ymin + fac * sa->totrct.ymax; - immBegin(GWN_PRIM_LINES, 2); + immVertex2f(pos, sa->totrct.xmin, y); + immVertex2f(pos, sa->totrct.xmax, y); - immVertex2f(pos, sa3->totrct.xmin, win->eventstate->y + 1); - immVertex2f(pos, sa3->totrct.xmax, win->eventstate->y + 1); - } - else { - immVertex2f(pos, win->eventstate->x, sa3->totrct.ymin); - immVertex2f(pos, win->eventstate->x, sa3->totrct.ymax); + immEnd(); - immEnd(); + immUniformColor4ub(0, 0, 0, 100); - immUniformColor4ub(0, 0, 0, 100); + immBegin(GWN_PRIM_LINES, 2); - immBegin(GWN_PRIM_LINES, 2); + immVertex2f(pos, sa->totrct.xmin, y + 1); + immVertex2f(pos, sa->totrct.xmax, y + 1); - immVertex2f(pos, win->eventstate->x + 1, sa3->totrct.ymin); - immVertex2f(pos, win->eventstate->x + 1, sa3->totrct.ymax); - } + immEnd(); + } + else { + BLI_assert(dir == 'v'); + const float x = (1 - fac) * sa->totrct.xmin + fac * sa->totrct.xmax; + + immVertex2f(pos, x, sa->totrct.ymin); + immVertex2f(pos, x, sa->totrct.ymax); immEnd(); - glDisable(GL_BLEND); + immUniformColor4ub(0, 0, 0, 100); + + immBegin(GWN_PRIM_LINES, 2); + + immVertex2f(pos, x + 1, sa->totrct.ymin); + immVertex2f(pos, x + 1, sa->totrct.ymax); + + immEnd(); } - immUnbindProgram(); + glDisable(GL_BLEND); - screen->do_draw = false; + immUnbindProgram(); } @@ -481,7 +499,7 @@ static void screen_preview_draw(const bScreen *screen, int size_x, int size_y) void ED_screen_preview_render(const bScreen *screen, int size_x, int size_y, unsigned int *r_rect) { char err_out[256] = "unknown"; - GPUOffScreen *offscreen = GPU_offscreen_create(size_x, size_y, 0, err_out); + GPUOffScreen *offscreen = GPU_offscreen_create(size_x, size_y, 0, false, err_out); GPU_offscreen_bind(offscreen, true); glClearColor(0.0, 0.0, 0.0, 0.0); diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c index 4b5ce2f4b81..57f45bf95ce 100644 --- a/source/blender/editors/screen/screen_edit.c +++ b/source/blender/editors/screen/screen_edit.c @@ -426,8 +426,6 @@ int screen_area_join(bContext *C, bScreen *scr, ScrArea *sa1, ScrArea *sa2) /*printf("dir is : %i\n", dir);*/ if (dir == -1) { - if (sa1) sa1->flag &= ~AREA_FLAG_DRAWJOINFROM; - if (sa2) sa2->flag &= ~AREA_FLAG_DRAWJOINTO; return 0; } @@ -458,7 +456,6 @@ int screen_area_join(bContext *C, bScreen *scr, ScrArea *sa1, ScrArea *sa2) screen_delarea(C, scr, sa2); BKE_screen_remove_double_scrverts(scr); - sa1->flag &= ~AREA_FLAG_DRAWJOINFROM; /* Update preview thumbnail */ BKE_icon_changed(scr->id.icon_id); diff --git a/source/blender/editors/screen/screen_intern.h b/source/blender/editors/screen/screen_intern.h index 39c3d72af6a..9214b4b7a68 100644 --- a/source/blender/editors/screen/screen_intern.h +++ b/source/blender/editors/screen/screen_intern.h @@ -31,6 +31,7 @@ #ifndef __SCREEN_INTERN_H__ #define __SCREEN_INTERN_H__ +struct bContext; struct bContextDataResult; struct Main; @@ -65,7 +66,8 @@ ScrEdge *screen_find_active_scredge(const bScreen *sc, struct AZone *is_in_area_actionzone(ScrArea *sa, const int xy[2]); /* screen_context.c */ -int ed_screen_context(const struct bContext *C, const char *member, struct bContextDataResult *result); +int ed_screen_context( + const struct bContext *C, const char *member, struct bContextDataResult *result); extern const char *screen_context_dir[]; /* doc access */ diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c index 4e8bf6ea769..09af0d86f84 100644 --- a/source/blender/editors/screen/screen_ops.c +++ b/source/blender/editors/screen/screen_ops.c @@ -90,10 +90,12 @@ #define KM_MODAL_CANCEL 1 #define KM_MODAL_APPLY 2 -#define KM_MODAL_STEP10 3 -#define KM_MODAL_STEP10_OFF 4 +#define KM_MODAL_SNAP_ON 3 +#define KM_MODAL_SNAP_OFF 4 -/* ************** Exported Poll tests ********************** */ +/* -------------------------------------------------------------------- */ +/** \name Public Poll API + * \{ */ int ED_operator_regionactive(bContext *C) { @@ -127,36 +129,6 @@ static int ED_operator_screenactive_norender(bContext *C) return 1; } - -static int screen_active_editable(bContext *C) -{ - if (ED_operator_screenactive(C)) { - /* no full window splitting allowed */ - if (CTX_wm_screen(C)->state != SCREENNORMAL) - return 0; - return 1; - } - return 0; -} - -static ARegion *screen_find_region_type(bContext *C, int type) -{ - ARegion *ar = CTX_wm_region(C); - - /* find the header region - * - try context first, but upon failing, search all regions in area... - */ - if ((ar == NULL) || (ar->regiontype != type)) { - ScrArea *sa = CTX_wm_area(C); - ar = BKE_area_find_region_type(sa, type); - } - else { - ar = NULL; - } - - return ar; -} - /* when mouse is over area-edge */ int ED_operator_screen_mainwinactive(bContext *C) { @@ -589,7 +561,46 @@ int ED_operator_camera(bContext *C) return (cam != NULL); } -/* *************************** action zone operator ************************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Internal Screen Utilities + * \{ */ + +static int screen_active_editable(bContext *C) +{ + if (ED_operator_screenactive(C)) { + /* no full window splitting allowed */ + if (CTX_wm_screen(C)->state != SCREENNORMAL) + return 0; + return 1; + } + return 0; +} + +static ARegion *screen_find_region_type(bContext *C, int type) +{ + ARegion *ar = CTX_wm_region(C); + + /* find the header region + * - try context first, but upon failing, search all regions in area... + */ + if ((ar == NULL) || (ar->regiontype != type)) { + ScrArea *sa = CTX_wm_area(C); + ar = BKE_area_find_region_type(sa, type); + } + else { + ar = NULL; + } + + return ar; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Action Zone Operator + * \{ */ /* operator state vars used: * none @@ -807,8 +818,7 @@ static int actionzone_modal(bContext *C, wmOperator *op, const wmEvent *event) /* once we drag outside the actionzone, register a gesture * check we're not on an edge so join finds the other area */ is_gesture = ((is_in_area_actionzone(sad->sa1, &event->x) != sad->az) && - (screen_find_active_scredge(sc, screen_size_x, screen_size_y, - event->x, event->y) == NULL)); + (screen_find_active_scredge(sc, screen_size_x, screen_size_y, event->x, event->y) == NULL)); } else { const int delta_min = 1; @@ -1098,6 +1108,7 @@ static void SCREEN_OT_area_dupli(wmOperatorType *ot) typedef struct sAreaMoveData { int bigger, smaller, origval, step; char dir; + bool do_snap; } sAreaMoveData; /* helper call to move area-edge, sets limits @@ -1189,55 +1200,98 @@ static int area_move_init(bContext *C, wmOperator *op) return 1; } +static int area_snap_calc_location( + const bScreen *sc, const int delta, + const int origval, const int dir, + const int bigger, const int smaller) +{ + int final_loc = -1; + + const int m_loc = origval + delta; + const int axis = (dir == 'v') ? 0 : 1; + int snap_dist; + int dist; + { + /* Test the snap to middle. */ + int middle = origval + (bigger - smaller) / 2; + middle -= (middle % AREAGRID); + + snap_dist = abs(m_loc - middle); + final_loc = middle; + } + + for (const ScrVert *v1 = sc->vertbase.first; v1; v1 = v1->next) { + if (v1->editflag) { + const int v_loc = (&v1->vec.x)[!axis]; + + for (const ScrVert *v2 = sc->vertbase.first; v2; v2 = v2->next) { + if (!v2->editflag) { + if (v_loc == (&v2->vec.x)[!axis]) { + const int v_loc2 = (&v2->vec.x)[axis]; + /* Do not snap to the vertices at the ends. */ + if ((origval - smaller) < v_loc2 && v_loc2 < (origval + bigger)) { + dist = abs(m_loc - v_loc2); + if (dist <= snap_dist) { + snap_dist = dist; + final_loc = v_loc2; + } + } + } + } + } + } + } + + return final_loc; +} + /* moves selected screen edge amount of delta, used by split & move */ -static void area_move_apply_do(bContext *C, int origval, int delta, int dir, int bigger, int smaller) +static void area_move_apply_do( + const bContext *C, int delta, + const int origval, const int dir, + const int bigger, const int smaller, + const bool do_snap) { - wmWindow *win = CTX_wm_window(C); - const int screen_size_x = WM_window_screen_pixels_x(win); - const int screen_size_y = WM_window_screen_pixels_y(win); bScreen *sc = CTX_wm_screen(C); ScrVert *v1; - ScrArea *sa; - int doredraw = 0; - int oldval; - - delta = CLAMPIS(delta, -smaller, bigger); - + bool doredraw = false; + CLAMP(delta, -smaller, bigger); + + short final_loc = -1; + + if (do_snap) { + final_loc = area_snap_calc_location(sc, delta, origval, dir, bigger, smaller); + } + else { + final_loc = origval + delta; + if (delta != bigger && delta != -smaller) { + final_loc -= (final_loc % AREAGRID); + } + } + + BLI_assert(final_loc != -1); + short axis = (dir == 'v') ? 0 : 1; + for (v1 = sc->vertbase.first; v1; v1 = v1->next) { if (v1->editflag) { - /* that way a nice AREAGRID */ - if ((dir == 'v') && v1->vec.x > 0 && v1->vec.x < screen_size_x - 1) { - oldval = v1->vec.x; - v1->vec.x = origval + delta; - - if (delta != bigger && delta != -smaller) { - v1->vec.x -= (v1->vec.x % AREAGRID); - v1->vec.x = CLAMPIS(v1->vec.x, origval - smaller, origval + bigger); - } - if (oldval != v1->vec.x) - doredraw = 1; - } - if ((dir == 'h') && v1->vec.y > 0 && v1->vec.y < screen_size_y - 1) { - oldval = v1->vec.y; - v1->vec.y = origval + delta; - - if (delta != bigger && delta != smaller) { - v1->vec.y -= (v1->vec.y % AREAGRID); - v1->vec.y = CLAMPIS(v1->vec.y, origval - smaller, origval + bigger); - } - if (oldval != v1->vec.y) - doredraw = 1; + short oldval = (&v1->vec.x)[axis]; + (&v1->vec.x)[axis] = final_loc; + + if (oldval == final_loc) { + /* nothing will change to the other vertices either. */ + break; } + doredraw = true; } } /* only redraw if we actually moved a screen vert, for AREAGRID */ if (doredraw) { - for (sa = sc->areabase.first; sa; sa = sa->next) { - if (sa->v1->editflag || sa->v2->editflag || sa->v3->editflag || sa->v4->editflag) + for (ScrArea *sa = sc->areabase.first; sa; sa = sa->next) { + if (sa->v1->editflag || sa->v2->editflag || sa->v3->editflag || sa->v4->editflag) { ED_area_tag_redraw(sa); + } } - WM_event_add_notifier(C, NC_SCREEN | NA_EDITED, NULL); /* redraw everything */ /* Update preview thumbnail */ BKE_icon_changed(sc->id.icon_id); @@ -1247,10 +1301,9 @@ static void area_move_apply_do(bContext *C, int origval, int delta, int dir, int static void area_move_apply(bContext *C, wmOperator *op) { sAreaMoveData *md = op->customdata; - int delta; - - delta = RNA_int_get(op->ptr, "delta"); - area_move_apply_do(C, md->origval, delta, md->dir, md->bigger, md->smaller); + int delta = RNA_int_get(op->ptr, "delta"); + + area_move_apply_do(C, delta, md->origval, md->dir, md->bigger, md->smaller, md->do_snap); } static void area_move_exit(bContext *C, wmOperator *op) @@ -1312,7 +1365,6 @@ static int area_move_modal(bContext *C, wmOperator *op, const wmEvent *event) y = RNA_int_get(op->ptr, "y"); delta = (md->dir == 'v') ? event->x - x : event->y - y; - if (md->step) delta = delta - (delta % md->step); RNA_int_set(op->ptr, "delta", delta); area_move_apply(C, op); @@ -1328,12 +1380,12 @@ static int area_move_modal(bContext *C, wmOperator *op, const wmEvent *event) case KM_MODAL_CANCEL: area_move_cancel(C, op); return OPERATOR_CANCELLED; - - case KM_MODAL_STEP10: - md->step = 10; + + case KM_MODAL_SNAP_ON: + md->do_snap = true; break; - case KM_MODAL_STEP10_OFF: - md->step = 0; + case KM_MODAL_SNAP_OFF: + md->do_snap = false; break; } break; @@ -1365,7 +1417,11 @@ static void SCREEN_OT_area_move(wmOperatorType *ot) RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX); } -/* ************** split area operator *********************************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Split Area Operator + * \{ */ /* * operator state vars: @@ -1402,13 +1458,13 @@ static void SCREEN_OT_area_move(wmOperatorType *ot) */ typedef struct sAreaSplitData { - int x, y; /* last used mouse position */ - int origval; /* for move areas */ int bigger, smaller; /* constraints for moving new edge */ int delta; /* delta move edge */ int origmin, origsize; /* to calculate fac, for property storage */ int previewmode; /* draw previewline, then split */ + void *draw_callback; /* call `ED_screen_draw_split_preview` */ + bool do_snap; ScrEdge *nedge; /* new edge */ ScrArea *sarea; /* start area */ @@ -1416,6 +1472,19 @@ typedef struct sAreaSplitData { } sAreaSplitData; +static void area_split_draw_cb(const struct wmWindow *UNUSED(win), void *userdata) +{ + const wmOperator *op = userdata; + + sAreaSplitData *sd = op->customdata; + if (sd->sarea) { + int dir = RNA_enum_get(op->ptr, "direction"); + float fac = RNA_float_get(op->ptr, "factor"); + + ED_screen_draw_split_preview(sd->sarea, dir, fac); + } +} + /* generic init, menu case, doesn't need active area */ static int area_split_menu_init(bContext *C, wmOperator *op) { @@ -1426,15 +1495,7 @@ static int area_split_menu_init(bContext *C, wmOperator *op) op->customdata = sd; sd->sarea = CTX_wm_area(C); - - if (sd->sarea) { - int dir = RNA_enum_get(op->ptr, "direction"); - if (dir == 'h') - sd->sarea->flag |= AREA_FLAG_DRAWSPLIT_H; - else - sd->sarea->flag |= AREA_FLAG_DRAWSPLIT_V; - } return 1; } @@ -1545,9 +1606,9 @@ static void area_split_exit(bContext *C, wmOperator *op) if (sd->sarea) ED_area_tag_redraw(sd->sarea); if (sd->narea) ED_area_tag_redraw(sd->narea); - if (sd->sarea) - sd->sarea->flag &= ~(AREA_FLAG_DRAWSPLIT_H | AREA_FLAG_DRAWSPLIT_V); - + if (sd->draw_callback) + WM_draw_cb_exit(CTX_wm_window(C), sd->draw_callback); + MEM_freeN(op->customdata); op->customdata = NULL; } @@ -1560,6 +1621,12 @@ static void area_split_exit(bContext *C, wmOperator *op) BKE_screen_remove_double_scredges(CTX_wm_screen(C)); } +static void area_split_preview_update_cursor(bContext *C, wmOperator *op) +{ + wmWindow *win = CTX_wm_window(C); + int dir = RNA_enum_get(op->ptr, "direction"); + WM_cursor_set(win, (dir == 'v') ? CURSOR_X_MOVE : CURSOR_Y_MOVE); +} /* UI callback, adds new handler */ static int area_split_invoke(bContext *C, wmOperator *op, const wmEvent *event) @@ -1637,9 +1704,6 @@ static int area_split_invoke(bContext *C, wmOperator *op, const wmEvent *event) sd = (sAreaSplitData *)op->customdata; - sd->x = event->x; - sd->y = event->y; - if (event->type == EVT_ACTIONZONE_AREA) { /* do the split */ @@ -1654,9 +1718,11 @@ static int area_split_invoke(bContext *C, wmOperator *op, const wmEvent *event) } else { sd->previewmode = 1; + sd->draw_callback = WM_draw_cb_activate(win, area_split_draw_cb, op); /* add temp handler for edge move or cancel */ WM_event_add_modal_handler(C, op); - + area_split_preview_update_cursor(C, op); + return OPERATOR_RUNNING_MODAL; } @@ -1699,48 +1765,15 @@ static void area_split_cancel(bContext *C, wmOperator *op) static int area_split_modal(bContext *C, wmOperator *op, const wmEvent *event) { sAreaSplitData *sd = (sAreaSplitData *)op->customdata; - float fac; - int dir; - + PropertyRNA *prop_dir = RNA_struct_find_property(op->ptr, "direction"); + bool update_factor = false; + /* execute the events */ switch (event->type) { case MOUSEMOVE: - dir = RNA_enum_get(op->ptr, "direction"); - - sd->delta = (dir == 'v') ? event->x - sd->origval : event->y - sd->origval; - if (sd->previewmode == 0) - area_move_apply_do(C, sd->origval, sd->delta, dir, sd->bigger, sd->smaller); - else { - if (sd->sarea) { - sd->sarea->flag &= ~(AREA_FLAG_DRAWSPLIT_H | AREA_FLAG_DRAWSPLIT_V); - ED_area_tag_redraw(sd->sarea); - } - /* area context not set */ - sd->sarea = BKE_screen_find_area_xy(CTX_wm_screen(C), SPACE_TYPE_ANY, event->x, event->y); - - if (sd->sarea) { - ED_area_tag_redraw(sd->sarea); - if (dir == 'v') { - sd->origsize = sd->sarea->winx; - sd->origmin = sd->sarea->totrct.xmin; - sd->sarea->flag |= AREA_FLAG_DRAWSPLIT_V; - } - else { - sd->origsize = sd->sarea->winy; - sd->origmin = sd->sarea->totrct.ymin; - sd->sarea->flag |= AREA_FLAG_DRAWSPLIT_H; - } - } - - CTX_wm_screen(C)->do_draw = true; - - } - - fac = (dir == 'v') ? event->x - sd->origmin : event->y - sd->origmin; - RNA_float_set(op->ptr, "factor", fac / (float)sd->origsize); - + update_factor = true; break; - + case LEFTMOUSE: if (sd->previewmode) { area_split_apply(C, op); @@ -1758,27 +1791,15 @@ static int area_split_modal(bContext *C, wmOperator *op, const wmEvent *event) case MIDDLEMOUSE: case TABKEY: if (sd->previewmode == 0) { + /* pass */ } else { - dir = RNA_enum_get(op->ptr, "direction"); - if (event->val == KM_PRESS) { if (sd->sarea) { - sd->sarea->flag &= ~(AREA_FLAG_DRAWSPLIT_H | AREA_FLAG_DRAWSPLIT_V); - ED_area_tag_redraw(sd->sarea); - - if (dir == 'v') { - RNA_enum_set(op->ptr, "direction", 'h'); - sd->sarea->flag |= AREA_FLAG_DRAWSPLIT_H; - - WM_cursor_set(CTX_wm_window(C), CURSOR_X_MOVE); - } - else { - RNA_enum_set(op->ptr, "direction", 'v'); - sd->sarea->flag |= AREA_FLAG_DRAWSPLIT_V; - - WM_cursor_set(CTX_wm_window(C), CURSOR_Y_MOVE); - } + int dir = RNA_property_enum_get(op->ptr, prop_dir); + RNA_property_enum_set(op->ptr, prop_dir, (dir == 'v') ? 'h' : 'v'); + area_split_preview_update_cursor(C, op); + update_factor = true; } } } @@ -1789,8 +1810,64 @@ static int area_split_modal(bContext *C, wmOperator *op, const wmEvent *event) case ESCKEY: area_split_cancel(C, op); return OPERATOR_CANCELLED; + + case LEFTCTRLKEY: + sd->do_snap = event->val == KM_PRESS; + update_factor = true; + break; } - + + if (update_factor) { + const int dir = RNA_property_enum_get(op->ptr, prop_dir); + + sd->delta = (dir == 'v') ? event->x - sd->origval : event->y - sd->origval; + + if (sd->previewmode == 0) { + if (sd->do_snap) { + const int snap_loc = area_snap_calc_location( + CTX_wm_screen(C), sd->delta, sd->origval, dir, sd->bigger, sd->smaller); + sd->delta = snap_loc - sd->origval; + } + area_move_apply_do(C, sd->delta, sd->origval, dir, sd->bigger, sd->smaller, false); + } + else { + if (sd->sarea) { + ED_area_tag_redraw(sd->sarea); + } + /* area context not set */ + sd->sarea = BKE_screen_find_area_xy(CTX_wm_screen(C), SPACE_TYPE_ANY, event->x, event->y); + + if (sd->sarea) { + ScrArea *sa = sd->sarea; + if (dir == 'v') { + sd->origsize = sa->winx; + sd->origmin = sa->totrct.xmin; + } + else { + sd->origsize = sa->winy; + sd->origmin = sa->totrct.ymin; + } + + if (sd->do_snap) { + sa->v1->editflag = sa->v2->editflag = sa->v3->editflag = sa->v4->editflag = 1; + + const int snap_loc = area_snap_calc_location( + CTX_wm_screen(C), sd->delta, sd->origval, dir, sd->origmin + sd->origsize, -sd->origmin); + + sa->v1->editflag = sa->v2->editflag = sa->v3->editflag = sa->v4->editflag = 0; + sd->delta = snap_loc - sd->origval; + } + + ED_area_tag_redraw(sd->sarea); + } + + CTX_wm_screen(C)->do_draw = true; + } + + float fac = (float)(sd->delta + sd->origval - sd->origmin) / sd->origsize; + RNA_float_set(op->ptr, "factor", fac); + } + return OPERATOR_RUNNING_MODAL; } @@ -1823,9 +1900,11 @@ static void SCREEN_OT_area_split(wmOperatorType *ot) RNA_def_int(ot->srna, "mouse_y", -100, INT_MIN, INT_MAX, "Mouse Y", "", INT_MIN, INT_MAX); } +/** \} */ - -/* ************** scale region edge operator *********************************** */ +/* -------------------------------------------------------------------- */ +/** \name Scale Region Edge Operator + * \{ */ typedef struct RegionMoveData { AZone *az; @@ -2094,8 +2173,11 @@ static void SCREEN_OT_region_scale(wmOperatorType *ot) ot->flag = OPTYPE_BLOCKING | OPTYPE_INTERNAL; } +/** \} */ -/* ************** frame change operator ***************************** */ +/* -------------------------------------------------------------------- */ +/** \name Frame Change Operator + * \{ */ static void areas_do_frame_follow(bContext *C, bool middle) { @@ -2176,6 +2258,11 @@ static void SCREEN_OT_frame_offset(wmOperatorType *ot) RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Frame Jump Operator + * \{ */ /* function to be called outside UI context, or for redo */ static int frame_jump_exec(bContext *C, wmOperator *op) @@ -2230,8 +2317,11 @@ static void SCREEN_OT_frame_jump(wmOperatorType *ot) RNA_def_boolean(ot->srna, "end", 0, "Last Frame", "Jump to the last frame of the frame range"); } +/** \} */ -/* ************** jump to keyframe operator ***************************** */ +/* -------------------------------------------------------------------- */ +/** \name Jump to Key-Frame Operator + * \{ */ /* function to be called outside UI context, or for redo */ static int keyframe_jump_exec(bContext *C, wmOperator *op) @@ -2340,7 +2430,11 @@ static void SCREEN_OT_keyframe_jump(wmOperatorType *ot) RNA_def_boolean(ot->srna, "next", true, "Next Keyframe", ""); } -/* ************** jump to marker operator ***************************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Jump to Marker Operator + * \{ */ /* function to be called outside UI context, or for redo */ static int marker_jump_exec(bContext *C, wmOperator *op) @@ -2403,7 +2497,11 @@ static void SCREEN_OT_marker_jump(wmOperatorType *ot) RNA_def_boolean(ot->srna, "next", true, "Next Marker", ""); } -/* ************** switch screen operator ***************************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Set Screen Operator + * \{ */ /* function to be called outside UI context, or for redo */ static int screen_set_exec(bContext *C, wmOperator *op) @@ -2431,8 +2529,11 @@ static void SCREEN_OT_screen_set(wmOperatorType *ot) RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX); } -/* ************** screen full-area operator ***************************** */ +/** \} */ +/* -------------------------------------------------------------------- */ +/** \name Screen Full-Area Operator + * \{ */ /* function to be called outside UI context, or for redo */ static int screen_maximize_area_exec(bContext *C, wmOperator *op) @@ -2491,7 +2592,11 @@ static void SCREEN_OT_screen_full_area(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_SKIP_SAVE); } -/* ************** join area operator ********************************************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Screen Join-Area Operator + * \{ */ /* operator state vars used: * x1, y1 mouse coord in first area, which will disappear @@ -2521,13 +2626,23 @@ static void SCREEN_OT_screen_full_area(wmOperatorType *ot) */ typedef struct sAreaJoinData { - ScrArea *sa1; /* first area to be considered */ - ScrArea *sa2; /* second area to be considered */ - ScrArea *scr; /* designed for removal */ + ScrArea *sa1; /* first area to be considered */ + ScrArea *sa2; /* second area to be considered */ + void *draw_callback; /* call `ED_screen_draw_join_shape` */ } sAreaJoinData; +static void area_join_draw_cb(const struct wmWindow *UNUSED(win), void *userdata) +{ + const wmOperator *op = userdata; + + sAreaJoinData *sd = op->customdata; + if (sd->sa1 && sd->sa2) { + ED_screen_draw_join_shape(sd->sa1, sd->sa2); + } +} + /* validate selection inside screen, set variables OK */ /* return 0: init failed */ /* XXX todo: find edge based on (x,y) and set other area? */ @@ -2561,14 +2676,14 @@ static int area_join_init(bContext *C, wmOperator *op) } jd = (sAreaJoinData *)MEM_callocN(sizeof(sAreaJoinData), "op_area_join"); - + jd->sa1 = sa1; - jd->sa1->flag |= AREA_FLAG_DRAWJOINFROM; jd->sa2 = sa2; - jd->sa2->flag |= AREA_FLAG_DRAWJOINTO; - + op->customdata = jd; - + + jd->draw_callback = WM_draw_cb_activate(CTX_wm_window(C), area_join_draw_cb, op); + return 1; } @@ -2592,8 +2707,13 @@ static int area_join_apply(bContext *C, wmOperator *op) /* finish operation */ static void area_join_exit(bContext *C, wmOperator *op) { - if (op->customdata) { - MEM_freeN(op->customdata); + sAreaJoinData *jd = (sAreaJoinData *)op->customdata; + + if (jd) { + if (jd->draw_callback) + WM_draw_cb_exit(CTX_wm_window(C), jd->draw_callback); + + MEM_freeN(jd); op->customdata = NULL; } @@ -2652,17 +2772,6 @@ static int area_join_invoke(bContext *C, wmOperator *op, const wmEvent *event) static void area_join_cancel(bContext *C, wmOperator *op) { - sAreaJoinData *jd = (sAreaJoinData *)op->customdata; - - if (jd->sa1) { - jd->sa1->flag &= ~AREA_FLAG_DRAWJOINFROM; - jd->sa1->flag &= ~AREA_FLAG_DRAWJOINTO; - } - if (jd->sa2) { - jd->sa2->flag &= ~AREA_FLAG_DRAWJOINFROM; - jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO; - } - WM_event_add_notifier(C, NC_WINDOW, NULL); area_join_exit(C, op); @@ -2686,9 +2795,7 @@ static int area_join_modal(bContext *C, wmOperator *op, const wmEvent *event) if (jd->sa1 != sa) { dir = area_getorientation(jd->sa1, sa); if (dir != -1) { - if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO; jd->sa2 = sa; - jd->sa2->flag |= AREA_FLAG_DRAWJOINTO; } else { /* we are not bordering on the previously selected area @@ -2697,15 +2804,10 @@ static int area_join_modal(bContext *C, wmOperator *op, const wmEvent *event) */ dir = area_getorientation(sa, jd->sa2); if (dir != -1) { - if (jd->sa1) jd->sa1->flag &= ~AREA_FLAG_DRAWJOINFROM; - if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO; jd->sa1 = jd->sa2; jd->sa2 = sa; - if (jd->sa1) jd->sa1->flag |= AREA_FLAG_DRAWJOINFROM; - if (jd->sa2) jd->sa2->flag |= AREA_FLAG_DRAWJOINTO; } else { - if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO; jd->sa2 = NULL; } } @@ -2715,12 +2817,8 @@ static int area_join_modal(bContext *C, wmOperator *op, const wmEvent *event) /* we are back in the area previously selected for keeping * we swap the areas if possible to allow user to choose */ if (jd->sa2 != NULL) { - if (jd->sa1) jd->sa1->flag &= ~AREA_FLAG_DRAWJOINFROM; - if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO; jd->sa1 = jd->sa2; jd->sa2 = sa; - if (jd->sa1) jd->sa1->flag |= AREA_FLAG_DRAWJOINFROM; - if (jd->sa2) jd->sa2->flag |= AREA_FLAG_DRAWJOINTO; dir = area_getorientation(jd->sa1, jd->sa2); if (dir == -1) { printf("oops, didn't expect that!\n"); @@ -2729,9 +2827,7 @@ static int area_join_modal(bContext *C, wmOperator *op, const wmEvent *event) else { dir = area_getorientation(jd->sa1, sa); if (dir != -1) { - if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO; jd->sa2 = sa; - jd->sa2->flag |= AREA_FLAG_DRAWJOINTO; } } WM_event_add_notifier(C, NC_WINDOW, NULL); @@ -2785,7 +2881,11 @@ static void SCREEN_OT_area_join(wmOperatorType *ot) RNA_def_int(ot->srna, "max_y", -100, INT_MIN, INT_MAX, "Y 2", "", INT_MIN, INT_MAX); } -/* ******************************* */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Screen Area Options Operator + * \{ */ static int screen_area_options_invoke(bContext *C, wmOperator *op, const wmEvent *event) { @@ -2838,9 +2938,11 @@ static void SCREEN_OT_area_options(wmOperatorType *ot) ot->flag = OPTYPE_INTERNAL; } +/** \} */ -/* ******************************* */ - +/* -------------------------------------------------------------------- */ +/** \name Space Data Cleanup Operator + * \{ */ static int spacedata_cleanup_exec(bContext *C, wmOperator *op) { @@ -2879,7 +2981,11 @@ static void SCREEN_OT_spacedata_cleanup(wmOperatorType *ot) } -/* ************** repeat last operator ***************************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Repeat Last Operator + * \{ */ static int repeat_last_exec(bContext *C, wmOperator *UNUSED(op)) { @@ -2918,6 +3024,12 @@ static void SCREEN_OT_repeat_last(wmOperatorType *ot) } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Repeat History Operator + * \{ */ + static int repeat_history_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { wmWindowManager *wm = CTX_wm_manager(C); @@ -2975,7 +3087,11 @@ static void SCREEN_OT_repeat_history(wmOperatorType *ot) RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "", 0, 1000); } -/* ********************** redo operator ***************************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Redo Operator + * \{ */ static int redo_last_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNUSED(event)) { @@ -3000,7 +3116,11 @@ static void SCREEN_OT_redo_last(wmOperatorType *ot) ot->poll = ED_operator_screenactive; } -/* ************** region four-split operator ***************************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Region Quad-View Operator + * \{ */ static void view3d_localview_update_rv3d(struct RegionView3D *rv3d) { @@ -3153,8 +3273,11 @@ static void SCREEN_OT_region_quadview(wmOperatorType *ot) ot->flag = 0; } +/** \} */ -/* ************** region flip operator ***************************** */ +/* -------------------------------------------------------------------- */ +/** \name Region Flip Operator + * \{ */ /* flip a region alignment */ static int region_flip_exec(bContext *C, wmOperator *UNUSED(op)) @@ -3205,7 +3328,11 @@ static void SCREEN_OT_region_flip(wmOperatorType *ot) ot->flag = 0; } -/* ************** header operator ***************************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Header Toggle Operator + * \{ */ static int header_exec(bContext *C, wmOperator *UNUSED(op)) { @@ -3235,8 +3362,11 @@ static void SCREEN_OT_header(wmOperatorType *ot) ot->exec = header_exec; } +/** \} */ -/* ************** show menus operator ***************************** */ +/* -------------------------------------------------------------------- */ +/** \name Header Toggle Menu Operator + * \{ */ /* show/hide header text menus */ static int header_toggle_menus_exec(bContext *C, wmOperator *UNUSED(op)) @@ -3265,8 +3395,11 @@ static void SCREEN_OT_header_toggle_menus(wmOperatorType *ot) ot->flag = 0; } +/** \} */ -/* ************** header tools operator ***************************** */ +/* -------------------------------------------------------------------- */ +/** \name Header Tools Operator + * \{ */ void ED_screens_header_tools_menu_create(bContext *C, uiLayout *layout, void *UNUSED(arg)) { @@ -3318,7 +3451,13 @@ static void SCREEN_OT_header_toolbox(wmOperatorType *ot) ot->invoke = header_toolbox_invoke; } -/* ****************** anim player, with timer ***************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Animation Step Operator + * + * Animation Step. + * \{ */ static int match_area_with_refresh(int spacetype, int refresh) { @@ -3615,7 +3754,13 @@ static void SCREEN_OT_animation_step(wmOperatorType *ot) } -/* ****************** anim player, starts or ends timer ***************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Animation Playback Operator + * + * Animation Playback with Timer. + * \{ */ /* find window that owns the animation timer */ bScreen *ED_screen_animation_playing(const wmWindowManager *wm) @@ -3708,6 +3853,12 @@ static void SCREEN_OT_animation_play(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_SKIP_SAVE); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Animation Cancel Operator + * \{ */ + static int screen_animation_cancel_exec(bContext *C, wmOperator *op) { bScreen *screen = ED_screen_animation_playing(CTX_wm_manager(C)); @@ -3747,7 +3898,11 @@ static void SCREEN_OT_animation_cancel(wmOperatorType *ot) RNA_def_boolean(ot->srna, "restore_frame", true, "Restore Frame", "Restore the frame when animation was initialized"); } -/* ************** border select operator (template) ***************************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Border Select Operator (Template) + * \{ */ /* operator state vars used: (added by default WM callbacks) * xmin, ymin @@ -3802,6 +3957,12 @@ static void SCREEN_OT_border_select(wmOperatorType *ot) } #endif +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Full Screen Back Operator + * \{ */ + /* *********************** generic fullscreen 'back' button *************** */ @@ -3836,7 +3997,11 @@ static void SCREEN_OT_back_to_previous(struct wmOperatorType *ot) ot->poll = ED_operator_screenactive; } -/* *********** show user pref window ****** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Show User Preferences Operator + * \{ */ static int userpref_show_invoke(bContext *C, wmOperator *op, const wmEvent *event) { @@ -3866,7 +4031,11 @@ static void SCREEN_OT_userpref_show(struct wmOperatorType *ot) ot->poll = ED_operator_screenactive; } -/********************* new screen operator *********************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name New Screen Operator + * \{ */ static int screen_new_exec(bContext *C, wmOperator *UNUSED(op)) { @@ -3893,7 +4062,11 @@ static void SCREEN_OT_new(wmOperatorType *ot) ot->poll = WM_operator_winactive; } -/********************* delete screen operator *********************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Delete Screen Operator + * \{ */ static int screen_delete_exec(bContext *C, wmOperator *UNUSED(op)) { @@ -3917,7 +4090,11 @@ static void SCREEN_OT_delete(wmOperatorType *ot) ot->exec = screen_delete_exec; } -/* ***************** region alpha blending ***************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Region Alpha Blending Operator + * \{ */ /* implementation note: a disappearing region needs at least 1 last draw with 100% backbuffer * texture over it- then triple buffer will clear it entirely. @@ -4059,7 +4236,11 @@ static void SCREEN_OT_region_blend(wmOperatorType *ot) /* properties */ } -/* ******************** space context cycling operator ******************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Space Context Cycle Operator + * \{ */ /* SCREEN_OT_space_context_cycle direction */ enum { @@ -4142,9 +4323,11 @@ static void SCREEN_OT_space_context_cycle(wmOperatorType *ot) "Direction to cycle through"); } +/** \} */ -/* **************** Assigning operatortypes to global list, adding handlers **************** */ - +/* -------------------------------------------------------------------- */ +/** \name Assigning Operator Types + * \{ */ /* called in spacetypes.c */ void ED_operatortypes_screen(void) @@ -4203,13 +4386,19 @@ void ED_operatortypes_screen(void) } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Operator Key Map + * \{ */ + static void keymap_modal_set(wmKeyConfig *keyconf) { static const EnumPropertyItem modal_items[] = { {KM_MODAL_CANCEL, "CANCEL", 0, "Cancel", ""}, {KM_MODAL_APPLY, "APPLY", 0, "Apply", ""}, - {KM_MODAL_STEP10, "STEP10", 0, "Steps on", ""}, - {KM_MODAL_STEP10_OFF, "STEP10_OFF", 0, "Steps off", ""}, + {KM_MODAL_SNAP_ON, "SNAP", 0, "Snap on", ""}, + {KM_MODAL_SNAP_OFF, "SNAP_OFF", 0, "Snap off", ""}, {0, NULL, 0, NULL, NULL}}; wmKeyMap *keymap; @@ -4221,8 +4410,8 @@ static void keymap_modal_set(wmKeyConfig *keyconf) WM_modalkeymap_add_item(keymap, RETKEY, KM_PRESS, KM_ANY, 0, KM_MODAL_APPLY); WM_modalkeymap_add_item(keymap, PADENTER, KM_PRESS, KM_ANY, 0, KM_MODAL_APPLY); - WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_PRESS, KM_ANY, 0, KM_MODAL_STEP10); - WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_RELEASE, KM_ANY, 0, KM_MODAL_STEP10_OFF); + WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_PRESS, KM_ANY, 0, KM_MODAL_SNAP_ON); + WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_RELEASE, KM_ANY, 0, KM_MODAL_SNAP_OFF); WM_modalkeymap_assign(keymap, "SCREEN_OT_area_move"); @@ -4404,3 +4593,4 @@ void ED_keymap_screen(wmKeyConfig *keyconf) keymap_modal_set(keyconf); } +/** \} */ diff --git a/source/blender/editors/sculpt_paint/paint_cursor.c b/source/blender/editors/sculpt_paint/paint_cursor.c index e1e90506299..3a43c7a6585 100644 --- a/source/blender/editors/sculpt_paint/paint_cursor.c +++ b/source/blender/editors/sculpt_paint/paint_cursor.c @@ -151,7 +151,10 @@ typedef struct LoadTexData { float radius; } LoadTexData; -static void load_tex_task_cb_ex(void *userdata, void *UNUSED(userdata_chunck), const int j, const int thread_id) +static void load_tex_task_cb_ex( + void *__restrict userdata, + const int j, + const ParallelRangeTLS *__restrict tls) { LoadTexData *data = userdata; Brush *br = data->br; @@ -212,7 +215,7 @@ static void load_tex_task_cb_ex(void *userdata, void *UNUSED(userdata_chunck), c if (col) { float rgba[4]; - paint_get_tex_pixel_col(mtex, x, y, rgba, pool, thread_id, convert_to_linear, colorspace); + paint_get_tex_pixel_col(mtex, x, y, rgba, pool, tls->thread_id, convert_to_linear, colorspace); buffer[index * 4] = rgba[0] * 255; buffer[index * 4 + 1] = rgba[1] * 255; @@ -220,7 +223,7 @@ static void load_tex_task_cb_ex(void *userdata, void *UNUSED(userdata_chunck), c buffer[index * 4 + 3] = rgba[3] * 255; } else { - float avg = paint_get_tex_pixel(mtex, x, y, pool, thread_id); + float avg = paint_get_tex_pixel(mtex, x, y, pool, tls->thread_id); avg += br->texture_sample_bias; @@ -318,7 +321,9 @@ static int load_tex(Brush *br, ViewContext *vc, float zoom, bool col, bool prima .pool = pool, .size = size, .rotation = rotation, .radius = radius, }; - BLI_task_parallel_range_ex(0, size, &data, NULL, 0, load_tex_task_cb_ex, true, false); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + BLI_task_parallel_range(0, size, &data, load_tex_task_cb_ex, &settings); if (mtex->tex && mtex->tex->nodetree) ntreeTexEndExecTree(mtex->tex->nodetree->execdata); @@ -365,7 +370,10 @@ static int load_tex(Brush *br, ViewContext *vc, float zoom, bool col, bool prima return 1; } -static void load_tex_cursor_task_cb(void *userdata, const int j) +static void load_tex_cursor_task_cb( + void *__restrict userdata, + const int j, + const ParallelRangeTLS *__restrict UNUSED(tls)) { LoadTexData *data = userdata; Brush *br = data->br; @@ -445,7 +453,9 @@ static int load_tex_cursor(Brush *br, ViewContext *vc, float zoom) .br = br, .buffer = buffer, .size = size, }; - BLI_task_parallel_range(0, size, &data, load_tex_cursor_task_cb, true); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + BLI_task_parallel_range(0, size, &data, load_tex_cursor_task_cb, &settings); if (!cursor_snap.overlay_texture) glGenTextures(1, &cursor_snap.overlay_texture); diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c index 2d1f0cb3b0d..aebd0c10e9c 100644 --- a/source/blender/editors/sculpt_paint/paint_image.c +++ b/source/blender/editors/sculpt_paint/paint_image.c @@ -50,6 +50,7 @@ #include "DNA_node_types.h" #include "DNA_object_types.h" +#include "BKE_colorband.h" #include "BKE_context.h" #include "BKE_DerivedMesh.h" #include "BKE_brush.h" @@ -58,7 +59,6 @@ #include "BKE_material.h" #include "BKE_node.h" #include "BKE_paint.h" -#include "BKE_texture.h" #include "DEG_depsgraph.h" @@ -666,17 +666,17 @@ void paint_brush_color_get(struct Scene *scene, struct Brush *br, bool color_cor float color_gr[4]; switch (br->gradient_stroke_mode) { case BRUSH_GRADIENT_PRESSURE: - do_colorband(br->gradient, pressure, color_gr); + BKE_colorband_evaluate(br->gradient, pressure, color_gr); break; case BRUSH_GRADIENT_SPACING_REPEAT: { float coord = fmod(distance / br->gradient_spacing, 1.0); - do_colorband(br->gradient, coord, color_gr); + BKE_colorband_evaluate(br->gradient, coord, color_gr); break; } case BRUSH_GRADIENT_SPACING_CLAMP: { - do_colorband(br->gradient, distance / br->gradient_spacing, color_gr); + BKE_colorband_evaluate(br->gradient, distance / br->gradient_spacing, color_gr); break; } } diff --git a/source/blender/editors/sculpt_paint/paint_image_2d.c b/source/blender/editors/sculpt_paint/paint_image_2d.c index 30830e4e7bc..2ce7c51b6b4 100644 --- a/source/blender/editors/sculpt_paint/paint_image_2d.c +++ b/source/blender/editors/sculpt_paint/paint_image_2d.c @@ -44,12 +44,12 @@ #include "BLI_bitmap.h" #include "BLI_task.h" +#include "BKE_colorband.h" #include "BKE_context.h" #include "BKE_brush.h" #include "BKE_image.h" #include "BKE_paint.h" #include "BKE_report.h" -#include "BKE_texture.h" #include "DEG_depsgraph.h" @@ -1071,7 +1071,10 @@ typedef struct Paint2DForeachData { int tilew; } Paint2DForeachData; -static void paint_2d_op_foreach_do(void *data_v, const int iter) +static void paint_2d_op_foreach_do( + void *__restrict data_v, + const int iter, + const ParallelRangeTLS *__restrict UNUSED(tls)) { Paint2DForeachData *data = (Paint2DForeachData *)data_v; paint_2d_do_making_brush(data->s, data->region, data->curveb, @@ -1157,9 +1160,12 @@ static int paint_2d_op(void *state, ImBuf *ibufb, unsigned short *curveb, unsign data.blend = blend; data.tilex = tilex; data.tilew = tilew; + + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); BLI_task_parallel_range(tiley, tileh + 1, &data, paint_2d_op_foreach_do, - true); + &settings); } } @@ -1667,7 +1673,7 @@ void paint_2d_gradient_fill( break; } } - do_colorband(br->gradient, f, color_f); + BKE_colorband_evaluate(br->gradient, f, color_f); /* convert to premultiplied */ mul_v3_fl(color_f, color_f[3]); color_f[3] *= br->alpha; @@ -1697,7 +1703,7 @@ void paint_2d_gradient_fill( } } - do_colorband(br->gradient, f, color_f); + BKE_colorband_evaluate(br->gradient, f, color_f); linearrgb_to_srgb_v3_v3(color_f, color_f); rgba_float_to_uchar((unsigned char *)&color_b, color_f); ((unsigned char *)&color_b)[3] *= br->alpha; diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c index 900ca844dbf..4a14e985827 100644 --- a/source/blender/editors/sculpt_paint/paint_image_proj.c +++ b/source/blender/editors/sculpt_paint/paint_image_proj.c @@ -62,6 +62,7 @@ #include "DNA_object_types.h" #include "BKE_camera.h" +#include "BKE_colorband.h" #include "BKE_context.h" #include "BKE_colortools.h" #include "BKE_DerivedMesh.h" @@ -226,6 +227,7 @@ typedef struct ProjPaintState { View3D *v3d; RegionView3D *rv3d; ARegion *ar; + const Depsgraph *depsgraph; Scene *scene; int source; /* PROJ_SRC_**** */ @@ -3132,7 +3134,7 @@ static void proj_paint_state_viewport_init( ED_view3d_ob_project_mat_get_from_obmat(ps->rv3d, ps->obmat, ps->projectMat); - ps->is_ortho = ED_view3d_clip_range_get(ps->v3d, ps->rv3d, &ps->clipsta, &ps->clipend, true); + ps->is_ortho = ED_view3d_clip_range_get(ps->depsgraph, ps->v3d, ps->rv3d, &ps->clipsta, &ps->clipend, true); } else { /* re-projection */ @@ -4582,7 +4584,7 @@ static void *do_projectpaint_thread(void *ph_v) break; } } - do_colorband(brush->gradient, f, color_f); + BKE_colorband_evaluate(brush->gradient, f, color_f); color_f[3] *= ((float)projPixel->mask) * (1.0f / 65535.0f) * brush->alpha; if (is_floatbuf) { @@ -5097,6 +5099,7 @@ static void project_state_init(bContext *C, Object *ob, ProjPaintState *ps, int ps->rv3d = CTX_wm_region_view3d(C); ps->ar = CTX_wm_region(C); + ps->depsgraph = CTX_data_depsgraph(C); ps->scene = scene; ps->ob = ob; /* allow override of active object */ @@ -5507,7 +5510,7 @@ static int texture_paint_image_from_view_exec(bContext *C, wmOperator *op) array = (float *)IDP_Array(view_data); memcpy(array, rv3d->winmat, sizeof(rv3d->winmat)); array += sizeof(rv3d->winmat) / sizeof(float); memcpy(array, rv3d->viewmat, sizeof(rv3d->viewmat)); array += sizeof(rv3d->viewmat) / sizeof(float); - is_ortho = ED_view3d_clip_range_get(v3d, rv3d, &array[0], &array[1], true); + is_ortho = ED_view3d_clip_range_get(CTX_data_depsgraph(C), v3d, rv3d, &array[0], &array[1], true); /* using float for a bool is dodgy but since its an extra member in the array... * easier then adding a single bool prop */ array[2] = is_ortho ? 1.0f : 0.0f; diff --git a/source/blender/editors/sculpt_paint/paint_mask.c b/source/blender/editors/sculpt_paint/paint_mask.c index 0fec4c4fc80..ff261a808da 100644 --- a/source/blender/editors/sculpt_paint/paint_mask.c +++ b/source/blender/editors/sculpt_paint/paint_mask.c @@ -104,7 +104,10 @@ typedef struct MaskTaskData { float (*clip_planes_final)[4]; } MaskTaskData; -static void mask_flood_fill_task_cb(void *userdata, const int i) +static void mask_flood_fill_task_cb( + void *__restrict userdata, + const int i, + const ParallelRangeTLS *__restrict UNUSED(tls)) { MaskTaskData *data = userdata; @@ -158,9 +161,12 @@ static int mask_flood_fill_exec(bContext *C, wmOperator *op) .mode = mode, .value = value, }; + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT); BLI_task_parallel_range( 0, totnode, &data, mask_flood_fill_task_cb, - ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT)); + &settings); if (multires) multires_mark_as_modified(ob, MULTIRES_COORDS_MODIFIED); @@ -221,7 +227,10 @@ static void flip_plane(float out[4], const float in[4], const char symm) out[3] = in[3]; } -static void mask_box_select_task_cb(void *userdata, const int i) +static void mask_box_select_task_cb( + void *__restrict userdata, + const int i, + const ParallelRangeTLS *__restrict UNUSED(tls)) { MaskTaskData *data = userdata; @@ -303,9 +312,12 @@ int ED_sculpt_mask_box_select(struct bContext *C, ViewContext *vc, const rcti *r .mode = mode, .value = value, .clip_planes_final = clip_planes_final, }; + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT); BLI_task_parallel_range( 0, totnode, &data, mask_box_select_task_cb, - ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT)); + &settings); if (nodes) MEM_freeN(nodes); @@ -377,7 +389,10 @@ static void mask_lasso_px_cb(int x, int x_end, int y, void *user_data) } while (++index != index_end); } -static void mask_gesture_lasso_task_cb(void *userdata, const int i) +static void mask_gesture_lasso_task_cb( + void *__restrict userdata, + const int i, + const ParallelRangeTLS *__restrict UNUSED(tls)) { LassoMaskData *lasso_data = userdata; MaskTaskData *data = &lasso_data->task_data; @@ -484,9 +499,12 @@ static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op) data.task_data.mode = mode; data.task_data.value = value; + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && (totnode > SCULPT_THREADED_LIMIT)); BLI_task_parallel_range( 0, totnode, &data, mask_gesture_lasso_task_cb, - ((sd->flags & SCULPT_USE_OPENMP) && (totnode > SCULPT_THREADED_LIMIT))); + &settings); if (nodes) MEM_freeN(nodes); diff --git a/source/blender/editors/sculpt_paint/paint_ops.c b/source/blender/editors/sculpt_paint/paint_ops.c index 40210d63566..004d2757a71 100644 --- a/source/blender/editors/sculpt_paint/paint_ops.c +++ b/source/blender/editors/sculpt_paint/paint_ops.c @@ -68,10 +68,13 @@ static int brush_add_exec(bContext *C, wmOperator *UNUSED(op)) Main *bmain = CTX_data_main(C); ePaintMode mode = BKE_paintmode_get_active_from_context(C); - if (br) + if (br) { br = BKE_brush_copy(bmain, br); - else + } + else { br = BKE_brush_add(bmain, "Brush", BKE_paint_object_mode_from_paint_mode(mode)); + id_us_min(&br->id); /* fake user only */ + } BKE_paint_brush_set(paint, br); @@ -376,6 +379,7 @@ static int brush_generic_tool_set(Main *bmain, Paint *paint, const int tool, if (!brush && brush_tool(brush_orig, tool_offset) != tool && create_missing) { brush = BKE_brush_add(bmain, tool_name, ob_mode); + id_us_min(&brush->id); /* fake user only */ brush_tool_set(brush, tool_offset, tool); brush->toggle_brush = brush_orig; } @@ -1273,6 +1277,10 @@ void ED_keymap_paint(wmKeyConfig *keyconf) WM_keymap_add_item(keymap, "PAINT_OT_mask_lasso_gesture", LEFTMOUSE, KM_PRESS, KM_CTRL | KM_SHIFT, 0); + /* Toggle mask visibility */ + kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", MKEY, KM_PRESS, KM_CTRL, 0); + RNA_string_set(kmi->ptr, "data_path", "scene.tool_settings.sculpt.show_mask"); + /* Toggle dynamic topology */ WM_keymap_add_item(keymap, "SCULPT_OT_dynamic_topology_toggle", DKEY, KM_PRESS, KM_CTRL, 0); diff --git a/source/blender/editors/sculpt_paint/paint_stroke.c b/source/blender/editors/sculpt_paint/paint_stroke.c index dacaea6a96e..3982c9a3c30 100644 --- a/source/blender/editors/sculpt_paint/paint_stroke.c +++ b/source/blender/editors/sculpt_paint/paint_stroke.c @@ -109,6 +109,8 @@ typedef struct PaintStroke { * e.g. in sculpt mode, stroke doesn't start until cursor * passes over the mesh */ bool stroke_started; + /* Set when enough motion was found for rake rotation */ + bool rake_started; /* event that started stroke, for modal() return */ int event_type; /* check if stroke variables have been initialized */ @@ -233,6 +235,9 @@ static bool paint_brush_update(bContext *C, UnifiedPaintSettings *ups = stroke->ups; bool location_sampled = false; bool location_success = false; + /* Use to perform all operations except applying the stroke, + * needed for operations that require cursor motion (rake). */ + bool is_dry_run = false; bool do_random = false; bool do_random_mask = false; /* XXX: Use pressure value from first brush step for brushes which don't @@ -371,7 +376,15 @@ static bool paint_brush_update(bContext *C, } /* curve strokes do their own rake calculation */ else if (!(brush->flag & BRUSH_CURVE)) { - paint_calculate_rake_rotation(ups, brush, mouse_init); + if (!paint_calculate_rake_rotation(ups, brush, mouse_init)) { + /* Not enough motion to define an angle. */ + if (!stroke->rake_started) { + is_dry_run = true; + } + } + else { + stroke->rake_started = true; + } } } @@ -402,7 +415,7 @@ static bool paint_brush_update(bContext *C, } } - return location_success; + return location_success && (is_dry_run == false); } static bool paint_stroke_use_jitter(ePaintMode mode, Brush *brush, bool invert) diff --git a/source/blender/editors/sculpt_paint/paint_utils.c b/source/blender/editors/sculpt_paint/paint_utils.c index 57a3044cc2b..1ec1e052d43 100644 --- a/source/blender/editors/sculpt_paint/paint_utils.c +++ b/source/blender/editors/sculpt_paint/paint_utils.c @@ -282,7 +282,7 @@ static void imapaint_pick_uv(EvaluationContext *eval_ctx, Scene *scene, Object * float p[2], w[3], absw, minabsw; float matrix[4][4], proj[4][4]; GLint view[4]; - const eImageePaintMode mode = scene->toolsettings->imapaint.mode; + const eImagePaintMode mode = scene->toolsettings->imapaint.mode; const MLoopTri *lt = dm->getLoopTriArray(dm); const MPoly *mpoly = dm->getPolyArray(dm); const MLoop *mloop = dm->getLoopArray(dm); diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c index d9df8c78ba9..0c1df71b1aa 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex.c +++ b/source/blender/editors/sculpt_paint/paint_vertex.c @@ -1195,7 +1195,7 @@ static void vwpaint_update_cache_invariants( cache->invert = mode == BRUSH_STROKE_INVERT; cache->alt_smooth = mode == BRUSH_STROKE_SMOOTH; /* not very nice, but with current events system implementation - * we can't handle brush appearance inversion hotkey separately (sergey) */ + * we can't handle brush appearance inversion hotkey separately (sergey) */ if (cache->invert) ups->draw_inverted = true; else ups->draw_inverted = false; @@ -1441,7 +1441,9 @@ static float wpaint_get_active_weight(const MDeformVert *dv, const WeightPaintIn } static void do_wpaint_precompute_weight_cb_ex( - void *userdata, void *UNUSED(userdata_chunk), const int n, const int UNUSED(thread_id)) + void *__restrict userdata, + const int n, + const ParallelRangeTLS *__restrict UNUSED(tls)) { SculptThreadedTaskData *data = userdata; const MDeformVert *dv = &data->me->dvert[n]; @@ -1460,15 +1462,21 @@ static void precompute_weight_values( .C = C, .ob = ob, .wpd = wpd, .wpi = wpi, .me = me, }; - BLI_task_parallel_range_ex( - 0, me->totvert, &data, NULL, 0, do_wpaint_precompute_weight_cb_ex, - true, false); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + BLI_task_parallel_range( + 0, me->totvert, + &data, + do_wpaint_precompute_weight_cb_ex, + &settings); wpd->precomputed_weight_ready = true; } static void do_wpaint_brush_blur_task_cb_ex( - void *userdata, void *UNUSED(userdata_chunk), const int n, const int UNUSED(thread_id)) + void *__restrict userdata, + const int n, + const ParallelRangeTLS *__restrict UNUSED(tls)) { SculptThreadedTaskData *data = userdata; SculptSession *ss = data->ob->sculpt; @@ -1557,7 +1565,9 @@ static void do_wpaint_brush_blur_task_cb_ex( } static void do_wpaint_brush_smear_task_cb_ex( - void *userdata, void *UNUSED(userdata_chunk), const int n, const int UNUSED(thread_id)) + void *__restrict userdata, + const int n, + const ParallelRangeTLS *__restrict UNUSED(tls)) { SculptThreadedTaskData *data = userdata; SculptSession *ss = data->ob->sculpt; @@ -1664,7 +1674,9 @@ static void do_wpaint_brush_smear_task_cb_ex( } static void do_wpaint_brush_draw_task_cb_ex( - void *userdata, void *UNUSED(userdata_chunk), const int n, const int UNUSED(thread_id)) + void *__restrict userdata, + const int n, + const ParallelRangeTLS *__restrict UNUSED(tls)) { SculptThreadedTaskData *data = userdata; SculptSession *ss = data->ob->sculpt; @@ -1734,7 +1746,9 @@ static void do_wpaint_brush_draw_task_cb_ex( } static void do_wpaint_brush_calc_average_weight_cb_ex( - void *userdata, void *UNUSED(userdata_chunk), const int n, const int UNUSED(thread_id)) + void *__restrict userdata, + const int n, + const ParallelRangeTLS *__restrict UNUSED(tls)) { SculptThreadedTaskData *data = userdata; SculptSession *ss = data->ob->sculpt; @@ -1785,9 +1799,14 @@ static void calculate_average_weight(SculptThreadedTaskData *data, PBVHNode **UN struct WPaintAverageAccum *accum = MEM_mallocN(sizeof(*accum) * totnode, __func__); data->custom_data = accum; - BLI_task_parallel_range_ex( - 0, totnode, data, NULL, 0, do_wpaint_brush_calc_average_weight_cb_ex, - ((data->sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = ((data->sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT); + BLI_task_parallel_range( + 0, totnode, + data, + do_wpaint_brush_calc_average_weight_cb_ex, + &settings); uint accum_len = 0; double accum_weight = 0.0; @@ -1819,30 +1838,40 @@ static void wpaint_paint_leaves( /* Use this so average can modify its weight without touching the brush. */ data.strength = BKE_brush_weight_get(scene, brush); - /* current mirroring code cannot be run in parallel */ - bool use_threading = !(me->editflag & ME_EDIT_MIRROR_X); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + /* NOTE: current mirroring code cannot be run in parallel */ + settings.use_threading = !(me->editflag & ME_EDIT_MIRROR_X); switch (brush->vertexpaint_tool) { case PAINT_BLEND_AVERAGE: calculate_average_weight(&data, nodes, totnode); - BLI_task_parallel_range_ex( - 0, totnode, &data, NULL, 0, - do_wpaint_brush_draw_task_cb_ex, use_threading, false); + BLI_task_parallel_range( + 0, totnode, + &data, + do_wpaint_brush_draw_task_cb_ex, + &settings); break; case PAINT_BLEND_SMEAR: - BLI_task_parallel_range_ex( - 0, totnode, &data, NULL, 0, - do_wpaint_brush_smear_task_cb_ex, use_threading, false); + BLI_task_parallel_range( + 0, totnode, + &data, + do_wpaint_brush_smear_task_cb_ex, + &settings); break; case PAINT_BLEND_BLUR: - BLI_task_parallel_range_ex( - 0, totnode, &data, NULL, 0, - do_wpaint_brush_blur_task_cb_ex, use_threading, false); + BLI_task_parallel_range( + 0, totnode, + &data, + do_wpaint_brush_blur_task_cb_ex, + &settings); break; default: - BLI_task_parallel_range_ex( - 0, totnode, &data, NULL, 0, - do_wpaint_brush_draw_task_cb_ex, use_threading, false); + BLI_task_parallel_range( + 0, totnode, + &data, + do_wpaint_brush_draw_task_cb_ex, + &settings); break; } } @@ -2398,7 +2427,9 @@ static bool vpaint_stroke_test_start(bContext *C, struct wmOperator *op, const f } static void do_vpaint_brush_calc_average_color_cb_ex( - void *userdata, void *UNUSED(userdata_chunk), const int n, const int UNUSED(thread_id)) + void *__restrict userdata, + const int n, + const ParallelRangeTLS *__restrict UNUSED(tls)) { SculptThreadedTaskData *data = userdata; SculptSession *ss = data->ob->sculpt; @@ -2460,7 +2491,9 @@ static float tex_color_alpha_ubyte( } static void do_vpaint_brush_draw_task_cb_ex( - void *userdata, void *UNUSED(userdata_chunk), const int n, const int UNUSED(thread_id)) + void *__restrict userdata, + const int n, + const ParallelRangeTLS *__restrict UNUSED(tls)) { SculptThreadedTaskData *data = userdata; SculptSession *ss = data->ob->sculpt; @@ -2552,7 +2585,9 @@ static void do_vpaint_brush_draw_task_cb_ex( } static void do_vpaint_brush_blur_task_cb_ex( - void *userdata, void *UNUSED(userdata_chunk), const int n, const int UNUSED(thread_id)) + void *__restrict userdata, + const int n, + const ParallelRangeTLS *__restrict UNUSED(tls)) { SculptThreadedTaskData *data = userdata; SculptSession *ss = data->ob->sculpt; @@ -2661,7 +2696,9 @@ static void do_vpaint_brush_blur_task_cb_ex( } static void do_vpaint_brush_smear_task_cb_ex( - void *userdata, void *UNUSED(userdata_chunk), const int n, const int UNUSED(thread_id)) + void *__restrict userdata, + const int n, + const ParallelRangeTLS *__restrict UNUSED(tls)) { SculptThreadedTaskData *data = userdata; SculptSession *ss = data->ob->sculpt; @@ -2799,9 +2836,13 @@ static void calculate_average_color(SculptThreadedTaskData *data, PBVHNode **UNU struct VPaintAverageAccum *accum = MEM_mallocN(sizeof(*accum) * totnode, __func__); data->custom_data = accum; - BLI_task_parallel_range_ex( - 0, totnode, data, NULL, 0, do_vpaint_brush_calc_average_color_cb_ex, - true, false); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + BLI_task_parallel_range( + 0, totnode, + data, + do_vpaint_brush_calc_average_color_cb_ex, + &settings); uint accum_len = 0; uint accum_value[3] = {0}; @@ -2833,27 +2874,37 @@ static void vpaint_paint_leaves( .sd = sd, .ob = ob, .brush = brush, .nodes = nodes, .vp = vp, .vpd = vpd, .lcol = (uint *)me->mloopcol, .me = me, .C = C, }; + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); switch (brush->vertexpaint_tool) { case PAINT_BLEND_AVERAGE: calculate_average_color(&data, nodes, totnode); - BLI_task_parallel_range_ex( - 0, totnode, &data, NULL, 0, - do_vpaint_brush_draw_task_cb_ex, true, false); + BLI_task_parallel_range( + 0, totnode, + &data, + do_vpaint_brush_draw_task_cb_ex, + &settings); break; case PAINT_BLEND_BLUR: - BLI_task_parallel_range_ex( - 0, totnode, &data, NULL, 0, - do_vpaint_brush_blur_task_cb_ex, true, false); + BLI_task_parallel_range( + 0, totnode, + &data, + do_vpaint_brush_blur_task_cb_ex, + &settings); break; case PAINT_BLEND_SMEAR: - BLI_task_parallel_range_ex( - 0, totnode, &data, NULL, 0, - do_vpaint_brush_smear_task_cb_ex, true, false); + BLI_task_parallel_range( + 0, totnode, + &data, + do_vpaint_brush_smear_task_cb_ex, + &settings); break; default: - BLI_task_parallel_range_ex( - 0, totnode, &data, NULL, 0, - do_vpaint_brush_draw_task_cb_ex, true, false); + BLI_task_parallel_range( + 0, totnode, + &data, + do_vpaint_brush_draw_task_cb_ex, + &settings); break; } } diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index 6e08f47f60d..c9d550aa4bd 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -377,7 +377,10 @@ static bool sculpt_stroke_is_dynamic_topology( /*** paint mesh ***/ -static void paint_mesh_restore_co_task_cb(void *userdata, const int n) +static void paint_mesh_restore_co_task_cb( + void *__restrict userdata, + const int n, + const ParallelRangeTLS *__restrict UNUSED(tls)) { SculptThreadedTaskData *data = userdata; SculptSession *ss = data->ob->sculpt; @@ -439,9 +442,14 @@ static void paint_mesh_restore_co(Sculpt *sd, Object *ob) .sd = sd, .ob = ob, .brush = brush, .nodes = nodes, }; + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && !ss->bm && totnode > SCULPT_THREADED_LIMIT); BLI_task_parallel_range( - 0, totnode, &data, paint_mesh_restore_co_task_cb, - ((sd->flags & SCULPT_USE_OPENMP) && !ss->bm && totnode > SCULPT_THREADED_LIMIT)); + 0, totnode, + &data, + paint_mesh_restore_co_task_cb, + &settings); if (nodes) MEM_freeN(nodes); @@ -794,7 +802,10 @@ static float calc_symmetry_feather(Sculpt *sd, StrokeCache *cache) * \note These are all _very_ similar, when changing one, check others. * \{ */ -static void calc_area_normal_and_center_task_cb(void *userdata, const int n) +static void calc_area_normal_and_center_task_cb( + void *__restrict userdata, + const int n, + const ParallelRangeTLS *__restrict UNUSED(tls)) { SculptThreadedTaskData *data = userdata; SculptSession *ss = data->ob->sculpt; @@ -946,9 +957,14 @@ static void calc_area_center( }; BLI_mutex_init(&data.mutex); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT); BLI_task_parallel_range( - 0, totnode, &data, calc_area_normal_and_center_task_cb, - ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT)); + 0, totnode, + &data, + calc_area_normal_and_center_task_cb, + &settings); BLI_mutex_end(&data.mutex); @@ -996,9 +1012,14 @@ void sculpt_pbvh_calc_area_normal( }; BLI_mutex_init(&data.mutex); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = use_threading; BLI_task_parallel_range( - 0, totnode, &data, calc_area_normal_and_center_task_cb, - use_threading); + 0, totnode, + &data, + calc_area_normal_and_center_task_cb, + &settings); BLI_mutex_end(&data.mutex); @@ -1036,9 +1057,14 @@ static void calc_area_normal_and_center( }; BLI_mutex_init(&data.mutex); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT); BLI_task_parallel_range( - 0, totnode, &data, calc_area_normal_and_center_task_cb, - ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT)); + 0, totnode, + &data, + calc_area_normal_and_center_task_cb, + &settings); BLI_mutex_end(&data.mutex); @@ -1626,7 +1652,9 @@ typedef struct { } SculptFindNearestToRayData; static void do_smooth_brush_mesh_task_cb_ex( - void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id) + void *__restrict userdata, + const int n, + const ParallelRangeTLS *__restrict tls) { SculptThreadedTaskData *data = userdata; SculptSession *ss = data->ob->sculpt; @@ -1648,7 +1676,7 @@ static void do_smooth_brush_mesh_task_cb_ex( if (sculpt_brush_test_sq_fn(&test, vd.co)) { const float fade = bstrength * tex_strength( ss, brush, vd.co, sqrtf(test.dist), - vd.no, vd.fno, smooth_mask ? 0.0f : (vd.mask ? *vd.mask : 0.0f), thread_id); + vd.no, vd.fno, smooth_mask ? 0.0f : (vd.mask ? *vd.mask : 0.0f), tls->thread_id); if (smooth_mask) { float val = neighbor_average_mask(ss, vd.vert_indices[vd.i]) - *vd.mask; val *= fade * bstrength; @@ -1674,7 +1702,9 @@ static void do_smooth_brush_mesh_task_cb_ex( } static void do_smooth_brush_bmesh_task_cb_ex( - void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id) + void *__restrict userdata, + const int n, + const ParallelRangeTLS *__restrict tls) { SculptThreadedTaskData *data = userdata; SculptSession *ss = data->ob->sculpt; @@ -1696,7 +1726,7 @@ static void do_smooth_brush_bmesh_task_cb_ex( if (sculpt_brush_test_sq_fn(&test, vd.co)) { const float fade = bstrength * tex_strength( ss, brush, vd.co, sqrtf(test.dist), - vd.no, vd.fno, smooth_mask ? 0.0f : *vd.mask, thread_id); + vd.no, vd.fno, smooth_mask ? 0.0f : *vd.mask, tls->thread_id); if (smooth_mask) { float val = bmesh_neighbor_average_mask(vd.bm_vert, vd.cd_vert_mask_offset) - *vd.mask; val *= fade * bstrength; @@ -1722,10 +1752,12 @@ static void do_smooth_brush_bmesh_task_cb_ex( } static void do_smooth_brush_multires_task_cb_ex( - void *userdata, void *userdata_chunk, const int n, const int thread_id) + void *__restrict userdata, + const int n, + const ParallelRangeTLS *__restrict tls) { SculptThreadedTaskData *data = userdata; - SculptDoBrushSmoothGridDataChunk *data_chunk = userdata_chunk; + SculptDoBrushSmoothGridDataChunk *data_chunk = tls->userdata_chunk; SculptSession *ss = data->ob->sculpt; Sculpt *sd = data->sd; const Brush *brush = data->brush; @@ -1837,7 +1869,7 @@ static void do_smooth_brush_multires_task_cb_ex( const float strength_mask = (smooth_mask ? 0.0f : *mask); const float fade = bstrength * tex_strength( ss, brush, co, sqrtf(test.dist), - NULL, fno, strength_mask, thread_id); + NULL, fno, strength_mask, tls->thread_id); float f = 1.0f / 16.0f; if (x == 0 || x == gridsize - 1) @@ -1895,6 +1927,10 @@ static void smooth( .smooth_mask = smooth_mask, .strength = strength, }; + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT); + switch (type) { case PBVH_GRIDS: { @@ -1909,22 +1945,30 @@ static void smooth( data_chunk->tmpgrid_size = size; size += sizeof(*data_chunk); - BLI_task_parallel_range_ex( - 0, totnode, &data, data_chunk, size, do_smooth_brush_multires_task_cb_ex, - ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false); + settings.userdata_chunk = data_chunk; + settings.userdata_chunk_size = size; + BLI_task_parallel_range( + 0, totnode, + &data, + do_smooth_brush_multires_task_cb_ex, + &settings); MEM_freeN(data_chunk); break; } case PBVH_FACES: - BLI_task_parallel_range_ex( - 0, totnode, &data, NULL, 0, do_smooth_brush_mesh_task_cb_ex, - ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false); + BLI_task_parallel_range( + 0, totnode, + &data, + do_smooth_brush_mesh_task_cb_ex, + &settings); break; case PBVH_BMESH: - BLI_task_parallel_range_ex( - 0, totnode, &data, NULL, 0, do_smooth_brush_bmesh_task_cb_ex, - ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false); + BLI_task_parallel_range( + 0, totnode, + &data, + do_smooth_brush_bmesh_task_cb_ex, + &settings); break; } @@ -1940,7 +1984,9 @@ static void do_smooth_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod } static void do_mask_brush_draw_task_cb_ex( - void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id) + void *__restrict userdata, + const int n, + const ParallelRangeTLS *__restrict tls) { SculptThreadedTaskData *data = userdata; SculptSession *ss = data->ob->sculpt; @@ -1958,7 +2004,7 @@ static void do_mask_brush_draw_task_cb_ex( if (sculpt_brush_test_sq_fn(&test, vd.co)) { const float fade = tex_strength( ss, brush, vd.co, sqrtf(test.dist), - vd.no, vd.fno, 0.0f, thread_id); + vd.no, vd.fno, 0.0f, tls->thread_id); (*vd.mask) += fade * bstrength; CLAMP(*vd.mask, 0, 1); @@ -1979,9 +2025,14 @@ static void do_mask_brush_draw(Sculpt *sd, Object *ob, PBVHNode **nodes, int tot .sd = sd, .ob = ob, .brush = brush, .nodes = nodes, }; - BLI_task_parallel_range_ex( - 0, totnode, &data, NULL, 0, do_mask_brush_draw_task_cb_ex, - ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT); + BLI_task_parallel_range( + 0, totnode, + &data, + do_mask_brush_draw_task_cb_ex, + &settings); } static void do_mask_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) @@ -2000,7 +2051,9 @@ static void do_mask_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) } static void do_draw_brush_task_cb_ex( - void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id) + void *__restrict userdata, + const int n, + const ParallelRangeTLS *__restrict tls) { SculptThreadedTaskData *data = userdata; SculptSession *ss = data->ob->sculpt; @@ -2022,7 +2075,7 @@ static void do_draw_brush_task_cb_ex( /* offset vertex */ const float fade = tex_strength( ss, brush, vd.co, sqrtf(test.dist), - vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id); + vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, tls->thread_id); mul_v3_v3fl(proxy[vd.i], offset, fade); @@ -2055,16 +2108,23 @@ static void do_draw_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) .offset = offset, }; - BLI_task_parallel_range_ex( - 0, totnode, &data, NULL, 0, do_draw_brush_task_cb_ex, - ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT); + BLI_task_parallel_range( + 0, totnode, + &data, + do_draw_brush_task_cb_ex, + &settings); } /** * Used for 'SCULPT_TOOL_CREASE' and 'SCULPT_TOOL_BLOB' */ static void do_crease_brush_task_cb_ex( - void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id) + void *__restrict userdata, + const int n, + const ParallelRangeTLS *__restrict tls) { SculptThreadedTaskData *data = userdata; SculptSession *ss = data->ob->sculpt; @@ -2088,7 +2148,7 @@ static void do_crease_brush_task_cb_ex( /* offset vertex */ const float fade = tex_strength( ss, brush, vd.co, sqrtf(test.dist), - vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id); + vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, tls->thread_id); float val1[3]; float val2[3]; @@ -2152,13 +2212,20 @@ static void do_crease_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod .spvc = &spvc, .offset = offset, .flippedbstrength = flippedbstrength, }; - BLI_task_parallel_range_ex( - 0, totnode, &data, NULL, 0, do_crease_brush_task_cb_ex, - ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT); + BLI_task_parallel_range( + 0, totnode, + &data, + do_crease_brush_task_cb_ex, + &settings); } static void do_pinch_brush_task_cb_ex( - void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id) + void *__restrict userdata, + const int n, + const ParallelRangeTLS *__restrict tls) { SculptThreadedTaskData *data = userdata; SculptSession *ss = data->ob->sculpt; @@ -2179,7 +2246,7 @@ static void do_pinch_brush_task_cb_ex( if (sculpt_brush_test_sq_fn(&test, vd.co)) { const float fade = bstrength * tex_strength( ss, brush, vd.co, sqrtf(test.dist), - vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id); + vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, tls->thread_id); float val[3]; sub_v3_v3v3(val, test.location, vd.co); @@ -2203,13 +2270,20 @@ static void do_pinch_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode .sd = sd, .ob = ob, .brush = brush, .nodes = nodes, }; - BLI_task_parallel_range_ex( - 0, totnode, &data, NULL, 0, do_pinch_brush_task_cb_ex, - ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT); + BLI_task_parallel_range( + 0, totnode, + &data, + do_pinch_brush_task_cb_ex, + &settings); } static void do_grab_brush_task_cb_ex( - void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id) + void *__restrict userdata, + const int n, + const ParallelRangeTLS *__restrict tls) { SculptThreadedTaskData *data = userdata; SculptSession *ss = data->ob->sculpt; @@ -2236,7 +2310,7 @@ static void do_grab_brush_task_cb_ex( if (sculpt_brush_test_sq_fn(&test, orig_data.co)) { const float fade = bstrength * tex_strength( ss, brush, orig_data.co, sqrtf(test.dist), - orig_data.no, NULL, vd.mask ? *vd.mask : 0.0f, thread_id); + orig_data.no, NULL, vd.mask ? *vd.mask : 0.0f, tls->thread_id); mul_v3_v3fl(proxy[vd.i], grab_delta, fade); @@ -2264,13 +2338,20 @@ static void do_grab_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) .grab_delta = grab_delta, }; - BLI_task_parallel_range_ex( - 0, totnode, &data, NULL, 0, do_grab_brush_task_cb_ex, - ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT); + BLI_task_parallel_range( + 0, totnode, + &data, + do_grab_brush_task_cb_ex, + &settings); } static void do_nudge_brush_task_cb_ex( - void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id) + void *__restrict userdata, + const int n, + const ParallelRangeTLS *__restrict tls) { SculptThreadedTaskData *data = userdata; SculptSession *ss = data->ob->sculpt; @@ -2292,7 +2373,7 @@ static void do_nudge_brush_task_cb_ex( if (sculpt_brush_test_sq_fn(&test, vd.co)) { const float fade = bstrength * tex_strength( ss, brush, vd.co, sqrtf(test.dist), - vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id); + vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, tls->thread_id); mul_v3_v3fl(proxy[vd.i], cono, fade); @@ -2320,13 +2401,20 @@ static void do_nudge_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode .cono = cono, }; - BLI_task_parallel_range_ex( - 0, totnode, &data, NULL, 0, do_nudge_brush_task_cb_ex, - ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT); + BLI_task_parallel_range( + 0, totnode, + &data, + do_nudge_brush_task_cb_ex, + &settings); } static void do_snake_hook_brush_task_cb_ex( - void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id) + void *__restrict userdata, + const int n, + const ParallelRangeTLS *__restrict tls) { SculptThreadedTaskData *data = userdata; SculptSession *ss = data->ob->sculpt; @@ -2353,7 +2441,7 @@ static void do_snake_hook_brush_task_cb_ex( if (sculpt_brush_test_sq_fn(&test, vd.co)) { const float fade = bstrength * tex_strength( ss, brush, vd.co, sqrtf(test.dist), - vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id); + vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, tls->thread_id); mul_v3_v3fl(proxy[vd.i], grab_delta, fade); @@ -2426,13 +2514,20 @@ static void do_snake_hook_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int to .spvc = &spvc, .grab_delta = grab_delta, }; - BLI_task_parallel_range_ex( - 0, totnode, &data, NULL, 0, do_snake_hook_brush_task_cb_ex, - ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT); + BLI_task_parallel_range( + 0, totnode, + &data, + do_snake_hook_brush_task_cb_ex, + &settings); } static void do_thumb_brush_task_cb_ex( - void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id) + void *__restrict userdata, + const int n, + const ParallelRangeTLS *__restrict tls) { SculptThreadedTaskData *data = userdata; SculptSession *ss = data->ob->sculpt; @@ -2459,7 +2554,7 @@ static void do_thumb_brush_task_cb_ex( if (sculpt_brush_test_sq_fn(&test, orig_data.co)) { const float fade = bstrength * tex_strength( ss, brush, orig_data.co, sqrtf(test.dist), - orig_data.no, NULL, vd.mask ? *vd.mask : 0.0f, thread_id); + orig_data.no, NULL, vd.mask ? *vd.mask : 0.0f, tls->thread_id); mul_v3_v3fl(proxy[vd.i], cono, fade); @@ -2487,13 +2582,20 @@ static void do_thumb_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode .cono = cono, }; - BLI_task_parallel_range_ex( - 0, totnode, &data, NULL, 0, do_thumb_brush_task_cb_ex, - ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT); + BLI_task_parallel_range( + 0, totnode, + &data, + do_thumb_brush_task_cb_ex, + &settings); } static void do_rotate_brush_task_cb_ex( - void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id) + void *__restrict userdata, + const int n, + const ParallelRangeTLS *__restrict tls) { SculptThreadedTaskData *data = userdata; SculptSession *ss = data->ob->sculpt; @@ -2521,7 +2623,7 @@ static void do_rotate_brush_task_cb_ex( float vec[3], rot[3][3]; const float fade = bstrength * tex_strength( ss, brush, orig_data.co, sqrtf(test.dist), - orig_data.no, NULL, vd.mask ? *vd.mask : 0.0f, thread_id); + orig_data.no, NULL, vd.mask ? *vd.mask : 0.0f, tls->thread_id); sub_v3_v3v3(vec, orig_data.co, ss->cache->location); axis_angle_normalized_to_mat3(rot, ss->cache->sculpt_normal_symm, angle * fade); @@ -2549,13 +2651,20 @@ static void do_rotate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod .angle = angle, }; - BLI_task_parallel_range_ex( - 0, totnode, &data, NULL, 0, do_rotate_brush_task_cb_ex, - ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT); + BLI_task_parallel_range( + 0, totnode, + &data, + do_rotate_brush_task_cb_ex, + &settings); } static void do_layer_brush_task_cb_ex( - void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id) + void *__restrict userdata, + const int n, + const ParallelRangeTLS *__restrict tls) { SculptThreadedTaskData *data = userdata; SculptSession *ss = data->ob->sculpt; @@ -2589,7 +2698,7 @@ static void do_layer_brush_task_cb_ex( if (sculpt_brush_test_sq_fn(&test, orig_data.co)) { const float fade = bstrength * tex_strength( ss, brush, vd.co, sqrtf(test.dist), - vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id); + vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, tls->thread_id); float *disp = &layer_disp[vd.i]; float val[3]; @@ -2634,15 +2743,22 @@ static void do_layer_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode }; BLI_mutex_init(&data.mutex); - BLI_task_parallel_range_ex( - 0, totnode, &data, NULL, 0, do_layer_brush_task_cb_ex, - ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT); + BLI_task_parallel_range( + 0, totnode, + &data, + do_layer_brush_task_cb_ex, + &settings); BLI_mutex_end(&data.mutex); } static void do_inflate_brush_task_cb_ex( - void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id) + void *__restrict userdata, + const int n, + const ParallelRangeTLS *__restrict tls) { SculptThreadedTaskData *data = userdata; SculptSession *ss = data->ob->sculpt; @@ -2663,7 +2779,7 @@ static void do_inflate_brush_task_cb_ex( if (sculpt_brush_test_sq_fn(&test, vd.co)) { const float fade = bstrength * tex_strength( ss, brush, vd.co, sqrtf(test.dist), - vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id); + vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, tls->thread_id); float val[3]; if (vd.fno) @@ -2689,9 +2805,14 @@ static void do_inflate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totno .sd = sd, .ob = ob, .brush = brush, .nodes = nodes, }; - BLI_task_parallel_range_ex( - 0, totnode, &data, NULL, 0, do_inflate_brush_task_cb_ex, - ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT); + BLI_task_parallel_range( + 0, totnode, + &data, + do_inflate_brush_task_cb_ex, + &settings); } static void calc_sculpt_plane( @@ -2806,7 +2927,9 @@ static float get_offset(Sculpt *sd, SculptSession *ss) } static void do_flatten_brush_task_cb_ex( - void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id) + void *__restrict userdata, + const int n, + const ParallelRangeTLS *__restrict tls) { SculptThreadedTaskData *data = userdata; SculptSession *ss = data->ob->sculpt; @@ -2839,7 +2962,7 @@ static void do_flatten_brush_task_cb_ex( if (plane_trim(ss->cache, brush, val)) { const float fade = bstrength * tex_strength( ss, brush, vd.co, sqrtf(test.dist), - vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id); + vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, tls->thread_id); mul_v3_v3fl(proxy[vd.i], val, fade); @@ -2878,13 +3001,20 @@ static void do_flatten_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totno .area_no = area_no, .area_co = area_co, }; - BLI_task_parallel_range_ex( - 0, totnode, &data, NULL, 0, do_flatten_brush_task_cb_ex, - ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT); + BLI_task_parallel_range( + 0, totnode, + &data, + do_flatten_brush_task_cb_ex, + &settings); } static void do_clay_brush_task_cb_ex( - void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id) + void *__restrict userdata, + const int n, + const ParallelRangeTLS *__restrict tls) { SculptThreadedTaskData *data = userdata; SculptSession *ss = data->ob->sculpt; @@ -2921,7 +3051,7 @@ static void do_clay_brush_task_cb_ex( * causes glitch with planes, see: T44390 */ const float fade = bstrength * tex_strength( ss, brush, vd.co, sqrtf(test.dist), - vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id); + vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, tls->thread_id); mul_v3_v3fl(proxy[vd.i], val, fade); @@ -2964,13 +3094,20 @@ static void do_clay_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) .area_no = area_no, .area_co = area_co, }; - BLI_task_parallel_range_ex( - 0, totnode, &data, NULL, 0, do_clay_brush_task_cb_ex, - ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT); + BLI_task_parallel_range( + 0, totnode, + &data, + do_clay_brush_task_cb_ex, + &settings); } static void do_clay_strips_brush_task_cb_ex( - void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id) + void *__restrict userdata, + const int n, + const ParallelRangeTLS *__restrict tls) { SculptThreadedTaskData *data = userdata; SculptSession *ss = data->ob->sculpt; @@ -3006,7 +3143,7 @@ static void do_clay_strips_brush_task_cb_ex( * causes glitch with planes, see: T44390 */ const float fade = bstrength * tex_strength( ss, brush, vd.co, ss->cache->radius * test.dist, - vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id); + vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, tls->thread_id); mul_v3_v3fl(proxy[vd.i], val, fade); @@ -3074,13 +3211,20 @@ static void do_clay_strips_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int t .area_no_sp = area_no_sp, .area_co = area_co, .mat = mat, }; - BLI_task_parallel_range_ex( - 0, totnode, &data, NULL, 0, do_clay_strips_brush_task_cb_ex, - ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT); + BLI_task_parallel_range( + 0, totnode, + &data, + do_clay_strips_brush_task_cb_ex, + &settings); } static void do_fill_brush_task_cb_ex( - void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id) + void *__restrict userdata, + const int n, + const ParallelRangeTLS *__restrict tls) { SculptThreadedTaskData *data = userdata; SculptSession *ss = data->ob->sculpt; @@ -3114,7 +3258,7 @@ static void do_fill_brush_task_cb_ex( if (plane_trim(ss->cache, brush, val)) { const float fade = bstrength * tex_strength( ss, brush, vd.co, sqrtf(test.dist), - vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id); + vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, tls->thread_id); mul_v3_v3fl(proxy[vd.i], val, fade); @@ -3155,13 +3299,20 @@ static void do_fill_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) .area_no = area_no, .area_co = area_co, }; - BLI_task_parallel_range_ex( - 0, totnode, &data, NULL, 0, do_fill_brush_task_cb_ex, - ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT); + BLI_task_parallel_range( + 0, totnode, + &data, + do_fill_brush_task_cb_ex, + &settings); } static void do_scrape_brush_task_cb_ex( - void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id) + void *__restrict userdata, + const int n, + const ParallelRangeTLS *__restrict tls) { SculptThreadedTaskData *data = userdata; SculptSession *ss = data->ob->sculpt; @@ -3194,7 +3345,7 @@ static void do_scrape_brush_task_cb_ex( if (plane_trim(ss->cache, brush, val)) { const float fade = bstrength * tex_strength( ss, brush, vd.co, sqrtf(test.dist), - vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id); + vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, tls->thread_id); mul_v3_v3fl(proxy[vd.i], val, fade); @@ -3235,13 +3386,20 @@ static void do_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod .area_no = area_no, .area_co = area_co, }; - BLI_task_parallel_range_ex( - 0, totnode, &data, NULL, 0, do_scrape_brush_task_cb_ex, - ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT); + BLI_task_parallel_range( + 0, totnode, + &data, + do_scrape_brush_task_cb_ex, + &settings); } static void do_gravity_task_cb_ex( - void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id) + void *__restrict userdata, + const int n, + const ParallelRangeTLS *__restrict tls) { SculptThreadedTaskData *data = userdata; SculptSession *ss = data->ob->sculpt; @@ -3261,7 +3419,7 @@ static void do_gravity_task_cb_ex( if (sculpt_brush_test_sq_fn(&test, vd.co)) { const float fade = tex_strength( ss, brush, vd.co, sqrtf(test.dist), - vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id); + vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, tls->thread_id); mul_v3_v3fl(proxy[vd.i], offset, fade); @@ -3292,9 +3450,14 @@ static void do_gravity(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, fl .offset = offset, }; - BLI_task_parallel_range_ex( - 0, totnode, &data, NULL, 0, do_gravity_task_cb_ex, - ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT); + BLI_task_parallel_range( + 0, totnode, + &data, + do_gravity_task_cb_ex, + &settings); } @@ -3396,7 +3559,10 @@ static void sculpt_topology_update(Sculpt *sd, Object *ob, Brush *brush, Unified } } -static void do_brush_action_task_cb(void *userdata, const int n) +static void do_brush_action_task_cb( + void *__restrict userdata, + const int n, + const ParallelRangeTLS *__restrict UNUSED(tls)) { SculptThreadedTaskData *data = userdata; @@ -3423,9 +3589,14 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe .sd = sd, .ob = ob, .brush = brush, .nodes = nodes, }; + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT); BLI_task_parallel_range( - 0, totnode, &task_data, do_brush_action_task_cb, - ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT)); + 0, totnode, + &task_data, + do_brush_action_task_cb, + &settings); if (sculpt_brush_needs_normal(brush, ss->cache->normal_weight)) update_sculpt_normal(sd, ob, nodes, totnode); @@ -3537,7 +3708,10 @@ static void sculpt_flush_pbvhvert_deform(Object *ob, PBVHVertexIter *vd) copy_v3_v3(me->mvert[index].co, newco); } -static void sculpt_combine_proxies_task_cb(void *userdata, const int n) +static void sculpt_combine_proxies_task_cb( + void *__restrict userdata, + const int n, + const ParallelRangeTLS *__restrict UNUSED(tls)) { SculptThreadedTaskData *data = userdata; SculptSession *ss = data->ob->sculpt; @@ -3604,9 +3778,14 @@ static void sculpt_combine_proxies(Sculpt *sd, Object *ob) .sd = sd, .ob = ob, .brush = brush, .nodes = nodes, }; + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT); BLI_task_parallel_range( - 0, totnode, &data, sculpt_combine_proxies_task_cb, - ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT)); + 0, totnode, + &data, + sculpt_combine_proxies_task_cb, + &settings); } if (nodes) @@ -3632,7 +3811,10 @@ static void sculpt_update_keyblock(Object *ob) } } -static void sculpt_flush_stroke_deform_task_cb(void *userdata, const int n) +static void sculpt_flush_stroke_deform_task_cb( + void *__restrict userdata, + const int n, + const ParallelRangeTLS *__restrict UNUSED(tls)) { SculptThreadedTaskData *data = userdata; SculptSession *ss = data->ob->sculpt; @@ -3685,9 +3867,14 @@ static void sculpt_flush_stroke_deform(Sculpt *sd, Object *ob) .vertCos = vertCos, }; + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT); BLI_task_parallel_range( - 0, totnode, &data, sculpt_flush_stroke_deform_task_cb, - ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT)); + 0, totnode, + &data, + sculpt_flush_stroke_deform_task_cb, + &settings); if (vertCos) { sculpt_vertcos_to_key(ob, ss->kb, vertCos); @@ -4505,7 +4692,7 @@ static float sculpt_raycast_init( RegionView3D *rv3d = vc->ar->regiondata; /* TODO: what if the segment is totally clipped? (return == 0) */ - ED_view3d_win_to_segment(vc->ar, vc->v3d, mouse, ray_start, ray_end, true); + ED_view3d_win_to_segment(vc->depsgraph, vc->ar, vc->v3d, mouse, ray_start, ray_end, true); invert_m4_m4(obimat, ob->obmat); mul_m4_v3(obimat, ray_start); diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h index aaea13ce5d0..5fb9eee805f 100644 --- a/source/blender/editors/sculpt_paint/sculpt_intern.h +++ b/source/blender/editors/sculpt_paint/sculpt_intern.h @@ -119,7 +119,7 @@ typedef struct SculptUndoNode { } SculptUndoNode; /* Factor of brush to have rake point following behind -* (could be configurable but this is reasonable default). */ + * (could be configurable but this is reasonable default). */ #define SCULPT_RAKE_BRUSH_FACTOR 0.25f struct SculptRakeData { @@ -148,7 +148,7 @@ typedef struct SculptThreadedTaskData { /* Data specific to some callbacks. */ /* Note: even if only one or two of those are used at a time, keeping them separated, names help figuring out - * what it is, and memory overhead is ridiculous anyway... */ + * what it is, and memory overhead is ridiculous anyway... */ float flippedbstrength; float angle; float strength; @@ -239,10 +239,10 @@ void sculpt_pbvh_calc_area_normal( float r_area_no[3]); /* Cache stroke properties. Used because -* RNA property lookup isn't particularly fast. -* -* For descriptions of these settings, check the operator properties. -*/ + * RNA property lookup isn't particularly fast. + * + * For descriptions of these settings, check the operator properties. + */ typedef struct StrokeCache { /* Invariants */ @@ -296,13 +296,13 @@ typedef struct StrokeCache { float view_normal[3]; /* sculpt_normal gets calculated by calc_sculpt_normal(), then the - * sculpt_normal_symm gets updated quickly with the usual symmetry - * transforms */ + * sculpt_normal_symm gets updated quickly with the usual symmetry + * transforms */ float sculpt_normal[3]; float sculpt_normal_symm[3]; /* Used for area texture mode, local_mat gets calculated by - * calc_brush_local_mat() and used in tex_strength(). */ + * calc_brush_local_mat() and used in tex_strength(). */ float brush_local_mat[4][4]; float plane_offset[3]; /* used to shift the plane around when doing tiled strokes */ diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c index a10c7477dc6..63017a0e576 100644 --- a/source/blender/editors/sculpt_paint/sculpt_undo.c +++ b/source/blender/editors/sculpt_paint/sculpt_undo.c @@ -319,7 +319,10 @@ static bool sculpt_undo_restore_mask(bContext *C, DerivedMesh *dm, SculptUndoNod return 1; } -static void sculpt_undo_bmesh_restore_generic_task_cb(void *userdata, const int n) +static void sculpt_undo_bmesh_restore_generic_task_cb( + void *__restrict userdata, + const int n, + const ParallelRangeTLS *__restrict UNUSED(tls)) { PBVHNode **nodes = userdata; @@ -347,9 +350,14 @@ static void sculpt_undo_bmesh_restore_generic(bContext *C, BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT); BLI_task_parallel_range( - 0, totnode, nodes, sculpt_undo_bmesh_restore_generic_task_cb, - ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT)); + 0, totnode, + nodes, + sculpt_undo_bmesh_restore_generic_task_cb, + &settings); if (nodes) MEM_freeN(nodes); diff --git a/source/blender/editors/space_action/action_data.c b/source/blender/editors/space_action/action_data.c index fdf2dfe8371..29b3c6f2f6c 100644 --- a/source/blender/editors/space_action/action_data.c +++ b/source/blender/editors/space_action/action_data.c @@ -125,7 +125,7 @@ static bAction *action_create_new(bContext *C, bAction *oldact) } else { /* just make a new (empty) action */ - action = add_empty_action(CTX_data_main(C), "Action"); + action = BKE_action_add(CTX_data_main(C), "Action"); } /* when creating new ID blocks, there is already 1 user (as for all new datablocks), diff --git a/source/blender/editors/space_action/action_select.c b/source/blender/editors/space_action/action_select.c index 1c55a0d76cf..110c4d1789d 100644 --- a/source/blender/editors/space_action/action_select.c +++ b/source/blender/editors/space_action/action_select.c @@ -1127,7 +1127,8 @@ static int actkeys_select_leftright_exec(bContext *C, wmOperator *op) actkeys_select_leftright(&ac, leftright, selectmode); /* set notifier that keyframe selection (and channels too) have changed */ - WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | ND_ANIMCHAN | NA_SELECTED, NULL); + WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL); + WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_SELECTED, NULL); return OPERATOR_FINISHED; } @@ -1577,7 +1578,8 @@ static int actkeys_clickselect_invoke(bContext *C, wmOperator *op, const wmEvent mouse_action_keys(&ac, event->mval, selectmode, column, channel); /* set notifier that keyframe selection (and channels too) have changed */ - WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | ND_ANIMCHAN | NA_SELECTED, NULL); + WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL); + WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_SELECTED, NULL); /* for tweak grab to work */ return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH; diff --git a/source/blender/editors/space_api/spacetypes.c b/source/blender/editors/space_api/spacetypes.c index 7850a57f534..e47841ab574 100644 --- a/source/blender/editors/space_api/spacetypes.c +++ b/source/blender/editors/space_api/spacetypes.c @@ -128,6 +128,7 @@ void ED_spacetypes_init(void) ED_operatortypes_ui(); /* manipulator types */ + ED_manipulatortypes_button_2d(); ED_manipulatortypes_dial_3d(); ED_manipulatortypes_grab_3d(); ED_manipulatortypes_arrow_2d(); diff --git a/source/blender/editors/space_buttons/space_buttons.c b/source/blender/editors/space_buttons/space_buttons.c index d2f407bfa8c..179780bf517 100644 --- a/source/blender/editors/space_buttons/space_buttons.c +++ b/source/blender/editors/space_buttons/space_buttons.c @@ -225,6 +225,28 @@ static void buttons_header_region_draw(const bContext *C, ARegion *ar) ED_region_header(C, ar); } +static void buttons_header_region_message_subscribe( + const bContext *UNUSED(C), + WorkSpace *UNUSED(workspace), Scene *UNUSED(scene), + bScreen *UNUSED(screen), ScrArea *sa, ARegion *ar, + struct wmMsgBus *mbus) +{ + SpaceButs *sbuts = sa->spacedata.first; + wmMsgSubscribeValue msg_sub_value_region_tag_redraw = { + .owner = ar, + .user_data = ar, + .notify = ED_region_do_msg_notify_tag_redraw, + }; + + /* Don't check for SpaceButs.mainb here, we may toggle between view-layers + * where one has no active object, so that available contexts changes. */ + WM_msg_subscribe_rna_anon_prop(mbus, Window, view_layer, &msg_sub_value_region_tag_redraw); + + if (!ELEM(sbuts->mainb, BCONTEXT_RENDER, BCONTEXT_SCENE, BCONTEXT_WORLD)) { + WM_msg_subscribe_rna_anon_prop(mbus, ViewLayer, name, &msg_sub_value_region_tag_redraw); + } +} + /* draw a certain button set only if properties area is currently * showing that button set, to reduce unnecessary drawing. */ static void buttons_area_redraw(ScrArea *sa, short buttons) @@ -503,6 +525,7 @@ void ED_spacetype_buttons(void) art->init = buttons_header_region_init; art->draw = buttons_header_region_draw; + art->message_subscribe = buttons_header_region_message_subscribe; BLI_addhead(&st->regiontypes, art); BKE_spacetype_register(st); diff --git a/source/blender/editors/space_clip/clip_buttons.c b/source/blender/editors/space_clip/clip_buttons.c index eb9aadd2e72..469d94fed3a 100644 --- a/source/blender/editors/space_clip/clip_buttons.c +++ b/source/blender/editors/space_clip/clip_buttons.c @@ -107,7 +107,7 @@ void uiTemplateMovieClip(uiLayout *layout, bContext *C, PointerRNA *ptr, const c uiLayoutSetContextPointer(layout, "edit_movieclip", &clipptr); if (!compact) - uiTemplateID(layout, C, ptr, propname, NULL, "CLIP_OT_open", NULL); + uiTemplateID(layout, C, ptr, propname, NULL, "CLIP_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL); if (clip) { uiLayout *col; diff --git a/source/blender/editors/space_clip/clip_intern.h b/source/blender/editors/space_clip/clip_intern.h index 60736cfb885..7e37ae1238c 100644 --- a/source/blender/editors/space_clip/clip_intern.h +++ b/source/blender/editors/space_clip/clip_intern.h @@ -138,6 +138,8 @@ void clip_graph_tracking_iterate(struct SpaceClip *sc, bool selected_only, bool void clip_delete_track(struct bContext *C, struct MovieClip *clip, struct MovieTrackingTrack *track); void clip_delete_marker(struct bContext *C, struct MovieClip *clip, struct MovieTrackingTrack *track, struct MovieTrackingMarker *marker); +void clip_delete_plane_track(struct bContext *C, struct MovieClip *clip, struct MovieTrackingPlaneTrack *plane_track); + void clip_view_center_to_point(SpaceClip *sc, float x, float y); void clip_draw_cfra(struct SpaceClip *sc, struct ARegion *ar, struct Scene *scene); diff --git a/source/blender/editors/space_clip/clip_utils.c b/source/blender/editors/space_clip/clip_utils.c index 40661937bae..7f9d9bf577c 100644 --- a/source/blender/editors/space_clip/clip_utils.c +++ b/source/blender/editors/space_clip/clip_utils.c @@ -184,37 +184,37 @@ void clip_delete_track(bContext *C, MovieClip *clip, MovieTrackingTrack *track) MovieTrackingTrack *act_track = BKE_tracking_track_get_active(tracking); ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking); bool has_bundle = false; - char track_name_escaped[MAX_NAME], prefix[MAX_NAME * 2]; - const bool used_for_stabilization = (track->flag & (TRACK_USE_2D_STAB | TRACK_USE_2D_STAB_ROT)); - - if (track == act_track) + const bool used_for_stabilization = + (track->flag & (TRACK_USE_2D_STAB | TRACK_USE_2D_STAB_ROT)) != 0; + if (track == act_track) { tracking->act_track = NULL; - - /* handle reconstruction display in 3d viewport */ - if (track->flag & TRACK_HAS_BUNDLE) + } + /* Handle reconstruction display in 3d viewport. */ + if (track->flag & TRACK_HAS_BUNDLE) { has_bundle = true; - + } /* Make sure no plane will use freed track */ BKE_tracking_plane_tracks_remove_point_track(tracking, track); - /* Delete f-curves associated with the track (such as weight, i.e.) */ - BLI_strescape(track_name_escaped, track->name, sizeof(track_name_escaped)); - BLI_snprintf(prefix, sizeof(prefix), "tracks[\"%s\"]", track_name_escaped); - BKE_animdata_fix_paths_remove(&clip->id, prefix); - + /* Escaped object name, escaped track name, rest of the path. */ + char rna_path[MAX_NAME * 4 + 64]; + BKE_tracking_get_rna_path_for_track(tracking, + track, + rna_path, sizeof(rna_path)); + BKE_animdata_fix_paths_remove(&clip->id, rna_path); + /* Delete track itself. */ BKE_tracking_track_free(track); BLI_freelinkN(tracksbase, track); - + /* Send notifiers. */ WM_event_add_notifier(C, NC_MOVIECLIP | NA_EDITED, clip); - if (used_for_stabilization) { WM_event_add_notifier(C, NC_MOVIECLIP | ND_DISPLAY, clip); } - + /* Inform dependency graph. */ DEG_id_tag_update(&clip->id, 0); - - if (has_bundle) + if (has_bundle) { WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, NULL); + } } void clip_delete_marker(bContext *C, MovieClip *clip, MovieTrackingTrack *track, @@ -230,6 +230,28 @@ void clip_delete_marker(bContext *C, MovieClip *clip, MovieTrackingTrack *track, } } +void clip_delete_plane_track(bContext *C, + MovieClip *clip, + MovieTrackingPlaneTrack *plane_track) +{ + MovieTracking *tracking = &clip->tracking; + ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(tracking); + /* Delete f-curves associated with the track (such as weight, i.e.) */ + /* Escaped object name, escaped track name, rest of the path. */ + char rna_path[MAX_NAME * 4 + 64]; + BKE_tracking_get_rna_path_for_plane_track(tracking, + plane_track, + rna_path, sizeof(rna_path)); + BKE_animdata_fix_paths_remove(&clip->id, rna_path); + /* Delete the plane track itself. */ + BKE_tracking_plane_track_free(plane_track); + BLI_freelinkN(plane_tracks_base, plane_track); + /* TODO(sergey): Any notifiers to be sent here? */ + (void) C; + /* Inform dependency graph. */ + DEG_id_tag_update(&clip->id, 0); +} + void clip_view_center_to_point(SpaceClip *sc, float x, float y) { int width, height; diff --git a/source/blender/editors/space_clip/tracking_ops.c b/source/blender/editors/space_clip/tracking_ops.c index 2439ac06d9c..4ca2b54eaaf 100644 --- a/source/blender/editors/space_clip/tracking_ops.c +++ b/source/blender/editors/space_clip/tracking_ops.c @@ -227,7 +227,6 @@ static int delete_track_exec(bContext *C, wmOperator *UNUSED(op)) MovieClip *clip = ED_space_clip_get_clip(sc); MovieTracking *tracking = &clip->tracking; bool changed = false; - /* Delete selected plane tracks. */ ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(tracking); for (MovieTrackingPlaneTrack *plane_track = plane_tracks_base->first, @@ -236,14 +235,11 @@ static int delete_track_exec(bContext *C, wmOperator *UNUSED(op)) plane_track = next_plane_track) { next_plane_track = plane_track->next; - if (PLANE_TRACK_VIEW_SELECTED(plane_track)) { - BKE_tracking_plane_track_free(plane_track); - BLI_freelinkN(plane_tracks_base, plane_track); + clip_delete_plane_track(C, clip, plane_track); changed = true; } } - /* Remove selected point tracks (they'll also be removed from planes which * uses them). */ @@ -258,14 +254,11 @@ static int delete_track_exec(bContext *C, wmOperator *UNUSED(op)) changed = true; } } - /* Nothing selected now, unlock view so it can be scrolled nice again. */ sc->flag &= ~SC_LOCK_SELECTION; - if (changed) { WM_event_add_notifier(C, NC_MOVIECLIP | NA_EDITED, clip); } - return OPERATOR_FINISHED; } @@ -1866,6 +1859,10 @@ static bool is_track_clean(MovieTrackingTrack *track, int frames, int del) } } + if (count == 0) { + ok = 0; + } + if (del) { MEM_freeN(track->markers); diff --git a/source/blender/editors/space_clip/tracking_select.c b/source/blender/editors/space_clip/tracking_select.c index eddd65475a2..4ee85ace271 100644 --- a/source/blender/editors/space_clip/tracking_select.c +++ b/source/blender/editors/space_clip/tracking_select.c @@ -906,7 +906,7 @@ void CLIP_OT_select_all(wmOperatorType *ot) /********************** select grouped operator *********************/ -static int select_groped_exec(bContext *C, wmOperator *op) +static int select_grouped_exec(bContext *C, wmOperator *op) { SpaceClip *sc = CTX_wm_space_clip(C); MovieClip *clip = ED_space_clip_get_clip(sc); @@ -989,7 +989,7 @@ void CLIP_OT_select_grouped(wmOperatorType *ot) ot->idname = "CLIP_OT_select_grouped"; /* api callbacks */ - ot->exec = select_groped_exec; + ot->exec = select_grouped_exec; ot->poll = ED_space_clip_tracking_poll; /* flags */ diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c index 3f26604c23a..3c90f2957df 100644 --- a/source/blender/editors/space_file/space_file.c +++ b/source/blender/editors/space_file/space_file.c @@ -289,8 +289,9 @@ static void file_refresh(const bContext *C, ScrArea *sa) file_tools_region(sa); ED_area_initialize(wm, CTX_wm_window(C), sa); - ED_area_tag_redraw(sa); } + + ED_area_tag_redraw(sa); } static void file_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *wmn, Scene *UNUSED(scene), @@ -304,16 +305,13 @@ static void file_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *wmn, Sce switch (wmn->data) { case ND_SPACE_FILE_LIST: ED_area_tag_refresh(sa); - ED_area_tag_redraw(sa); break; case ND_SPACE_FILE_PARAMS: ED_area_tag_refresh(sa); - ED_area_tag_redraw(sa); break; case ND_SPACE_FILE_PREVIEW: if (sfile->files && filelist_cache_previews_update(sfile->files)) { ED_area_tag_refresh(sa); - ED_area_tag_redraw(sa); } break; } @@ -372,6 +370,15 @@ static void file_main_region_message_subscribe( .notify = ED_area_do_msg_notify_tag_refresh, }; + /* SpaceFile itself. */ + { + PointerRNA ptr; + RNA_pointer_create(&screen->id, &RNA_SpaceFileBrowser, sfile, &ptr); + + /* All properties for this space type. */ + WM_msg_subscribe_rna(mbus, &ptr, NULL, &msg_sub_value_area_tag_refresh, __func__); + } + /* FileSelectParams */ { PointerRNA ptr; diff --git a/source/blender/editors/space_graph/graph_edit.c b/source/blender/editors/space_graph/graph_edit.c index 2876fccaa51..29e3f99e1d4 100644 --- a/source/blender/editors/space_graph/graph_edit.c +++ b/source/blender/editors/space_graph/graph_edit.c @@ -2747,3 +2747,89 @@ void GRAPH_OT_driver_variables_paste(wmOperatorType *ot) } /* ************************************************************************** */ + +static int graph_driver_delete_invalid_exec(bContext *C, wmOperator *op) +{ + bAnimContext ac; + ListBase anim_data = {NULL, NULL}; + bAnimListElem *ale; + int filter; + bool ok = false; + unsigned int deleted = 0; + + /* get editor data */ + if (ANIM_animdata_get_context(C, &ac) == 0) + return OPERATOR_CANCELLED; + + /* NOTE: we might need a scene update to evaluate the driver flags */ + + /* filter data */ + filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_NODUPLIS); + ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); + + /* find invalid drivers */ + for (ale = anim_data.first; ale; ale = ale->next) { + FCurve *fcu = (FCurve *)ale->data; + if (ELEM(NULL, fcu, fcu->driver)) { + continue; + } + if (!(fcu->driver->flag & DRIVER_FLAG_INVALID)) { + continue; + } + + ok |= ANIM_remove_driver(op->reports, ale->id, fcu->rna_path, fcu->array_index, 0); + if (!ok) { + break; + } + deleted += 1; + } + + /* cleanup */ + ANIM_animdata_freelist(&anim_data); + + if (deleted > 0) { + /* notify the world of any changes */ + DEG_relations_tag_update(CTX_data_main(C)); + WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_REMOVED, NULL); + WM_reportf(RPT_INFO, "Deleted %u drivers", deleted); + } + else { + WM_report(RPT_INFO, "No drivers deleted"); + } + + /* successful or not? */ + if (!ok) { + return OPERATOR_CANCELLED; + } + + return OPERATOR_FINISHED; +} + +static int graph_driver_delete_invalid_poll(bContext *C) +{ + bAnimContext ac; + ScrArea *sa = CTX_wm_area(C); + + /* firstly, check if in Graph Editor */ + if ((sa == NULL) || (sa->spacetype != SPACE_IPO)) + return 0; + + /* try to init Anim-Context stuff ourselves and check */ + return ANIM_animdata_get_context(C, &ac) != 0; +} + + +void GRAPH_OT_driver_delete_invalid(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Delete Invalid Drivers"; + ot->idname = "GRAPH_OT_driver_delete_invalid"; + ot->description = "Delete all visible drivers considered invalid"; + + /* api callbacks */ + ot->exec = graph_driver_delete_invalid_exec; + ot->poll = graph_driver_delete_invalid_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} diff --git a/source/blender/editors/space_graph/graph_intern.h b/source/blender/editors/space_graph/graph_intern.h index 534b712fd5e..6c375b23352 100644 --- a/source/blender/editors/space_graph/graph_intern.h +++ b/source/blender/editors/space_graph/graph_intern.h @@ -152,6 +152,7 @@ void GRAPH_OT_fmodifier_paste(struct wmOperatorType *ot); void GRAPH_OT_driver_variables_copy(struct wmOperatorType *ot); void GRAPH_OT_driver_variables_paste(struct wmOperatorType *ot); +void GRAPH_OT_driver_delete_invalid(struct wmOperatorType *ot); /* ----------- */ diff --git a/source/blender/editors/space_graph/graph_ops.c b/source/blender/editors/space_graph/graph_ops.c index 62275abcd02..57d8f45905d 100644 --- a/source/blender/editors/space_graph/graph_ops.c +++ b/source/blender/editors/space_graph/graph_ops.c @@ -468,6 +468,7 @@ void graphedit_operatortypes(void) /* Drivers */ WM_operatortype_append(GRAPH_OT_driver_variables_copy); WM_operatortype_append(GRAPH_OT_driver_variables_paste); + WM_operatortype_append(GRAPH_OT_driver_delete_invalid); } void ED_operatormacros_graph(void) diff --git a/source/blender/editors/space_graph/graph_select.c b/source/blender/editors/space_graph/graph_select.c index 1683fbdbdb9..392db4ef4b5 100644 --- a/source/blender/editors/space_graph/graph_select.c +++ b/source/blender/editors/space_graph/graph_select.c @@ -1003,7 +1003,8 @@ static int graphkeys_select_leftright_exec(bContext *C, wmOperator *op) graphkeys_select_leftright(&ac, leftright, selectmode); /* set notifier that keyframe selection (and channels too) have changed */ - WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | ND_ANIMCHAN | NA_SELECTED, NULL); + WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL); + WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_SELECTED, NULL); return OPERATOR_FINISHED; } @@ -1517,7 +1518,8 @@ static int graphkeys_clickselect_invoke(bContext *C, wmOperator *op, const wmEve } /* set notifier that keyframe selection (and also channel selection in some cases) has changed */ - WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | ND_ANIMCHAN | NA_SELECTED, NULL); + WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL); + WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_SELECTED, NULL); /* for tweak grab to work */ return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH; diff --git a/source/blender/editors/space_image/image_buttons.c b/source/blender/editors/space_image/image_buttons.c index 51ccaf6800a..20f9658020d 100644 --- a/source/blender/editors/space_image/image_buttons.c +++ b/source/blender/editors/space_image/image_buttons.c @@ -871,8 +871,11 @@ void uiTemplateImage(uiLayout *layout, bContext *C, PointerRNA *ptr, const char uiLayoutSetContextPointer(layout, "edit_image", &imaptr); uiLayoutSetContextPointer(layout, "edit_image_user", userptr); - if (!compact) - uiTemplateID(layout, C, ptr, propname, ima ? NULL : "IMAGE_OT_new", "IMAGE_OT_open", NULL); + if (!compact) { + uiTemplateID( + layout, C, ptr, propname, + ima ? NULL : "IMAGE_OT_new", "IMAGE_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL); + } if (ima) { UI_block_funcN_set(block, rna_update_cb, MEM_dupallocN(cb), NULL); diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c index a95f7ccd69e..de158f84a4d 100644 --- a/source/blender/editors/space_image/image_ops.c +++ b/source/blender/editors/space_image/image_ops.c @@ -1152,9 +1152,10 @@ static int image_cmp_frame(const void *a, const void *b) } /** - * \brief Return the start (offset) and the length of the sequence of continuous frames in the list of frames - * \param frames [in] the list of frame numbers, as a side-effect the list is sorted - * \param ofs [out] offest, the first frame number in the sequence + * Return the start (offset) and the length of the sequence of continuous frames in the list of frames + * + * \param frames: [in] the list of frame numbers, as a side-effect the list is sorted. + * \param ofs: [out] offset the first frame number in the sequence. * \return the number of contiguous frames in the sequence */ static int image_sequence_get_len(ListBase *frames, int *ofs) @@ -1857,7 +1858,7 @@ static bool save_image_doit(bContext *C, SpaceImage *sima, wmOperator *op, SaveI scene = CTX_data_scene(C); rr = BKE_image_acquire_renderresult(scene, ima); bool is_mono = rr ? BLI_listbase_count_ex(&rr->views, 2) < 2 : BLI_listbase_count_ex(&ima->views, 2) < 2; - bool is_exr_rr = rr && ELEM(imf->imtype, R_IMF_IMTYPE_OPENEXR, R_IMF_IMTYPE_MULTILAYER); + bool is_exr_rr = rr && ELEM(imf->imtype, R_IMF_IMTYPE_OPENEXR, R_IMF_IMTYPE_MULTILAYER) && RE_HasFloatPixels(rr); /* error handling */ if (!rr) { diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c index 4f595ad98c6..a89ae2b869a 100644 --- a/source/blender/editors/space_image/space_image.c +++ b/source/blender/editors/space_image/space_image.c @@ -95,6 +95,18 @@ static void image_scopes_tag_refresh(ScrArea *sa) sima->scopes.ok = 0; } +static void image_user_refresh_scene(const bContext *C, SpaceImage *sima) +{ + if (sima->image && sima->image->type == IMA_TYPE_R_RESULT) { + /* for render result, try to use the currently rendering scene */ + Scene *render_scene = ED_render_job_get_current_scene(C); + if (render_scene) { + sima->iuser.scene = render_scene; + return; + } + } + sima->iuser.scene = CTX_data_scene(C); +} /* ******************** manage regions ********************* */ @@ -734,17 +746,7 @@ static void image_main_region_draw(const bContext *C, ARegion *ar) glClearColor(col[0], col[1], col[2], 0.0); glClear(GL_COLOR_BUFFER_BIT); - /* put scene context variable in iuser */ - if (sima->image && sima->image->type == IMA_TYPE_R_RESULT) { - /* for render result, try to use the currently rendering scene */ - Scene *render_scene = ED_render_job_get_current_scene(C); - if (render_scene) - sima->iuser.scene = render_scene; - else - sima->iuser.scene = scene; - } - else - sima->iuser.scene = scene; + image_user_refresh_scene(C, sima); /* we set view2d from own zoom and offset each time */ image_main_region_set_view2d(sima, ar); @@ -1014,6 +1016,11 @@ static void image_header_region_init(wmWindowManager *UNUSED(wm), ARegion *ar) static void image_header_region_draw(const bContext *C, ARegion *ar) { + ScrArea *sa = CTX_wm_area(C); + SpaceImage *sima = sa->spacedata.first; + + image_user_refresh_scene(C, sima); + ED_region_header(C, ar); } diff --git a/source/blender/editors/space_info/space_info.c b/source/blender/editors/space_info/space_info.c index 4f042364c63..b13152883c3 100644 --- a/source/blender/editors/space_info/space_info.c +++ b/source/blender/editors/space_info/space_info.c @@ -50,6 +50,9 @@ #include "WM_api.h" #include "WM_types.h" +#include "WM_message.h" + +#include "RNA_access.h" #include "UI_resources.h" #include "UI_interface.h" @@ -284,6 +287,22 @@ static void info_header_listener( } +static void info_header_region_message_subscribe( + const bContext *UNUSED(C), + WorkSpace *UNUSED(workspace), Scene *UNUSED(scene), + bScreen *UNUSED(screen), ScrArea *UNUSED(sa), ARegion *ar, + struct wmMsgBus *mbus) +{ + wmMsgSubscribeValue msg_sub_value_region_tag_redraw = { + .owner = ar, + .user_data = ar, + .notify = ED_region_do_msg_notify_tag_redraw, + }; + + WM_msg_subscribe_rna_anon_prop(mbus, Window, view_layer, &msg_sub_value_region_tag_redraw); + WM_msg_subscribe_rna_anon_prop(mbus, ViewLayer, name, &msg_sub_value_region_tag_redraw); +} + static void recent_files_menu_draw(const bContext *UNUSED(C), Menu *menu) { struct RecentFile *recent; @@ -347,6 +366,7 @@ void ED_spacetype_info(void) art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_HEADER; art->listener = info_header_listener; + art->message_subscribe = info_header_region_message_subscribe; art->init = info_header_region_init; art->draw = info_header_region_draw; diff --git a/source/blender/editors/space_logic/logic_window.c b/source/blender/editors/space_logic/logic_window.c index 69bf51ade3a..c6fd70a60dd 100644 --- a/source/blender/editors/space_logic/logic_window.c +++ b/source/blender/editors/space_logic/logic_window.c @@ -2011,7 +2011,7 @@ static void draw_actuator_sound(uiLayout *layout, PointerRNA *ptr, bContext *C) { uiLayout *row, *col; - uiTemplateID(layout, C, ptr, "sound", NULL, "SOUND_OT_open", NULL); + uiTemplateID(layout, C, ptr, "sound", NULL, "SOUND_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL); if (!RNA_pointer_get(ptr, "sound").data) { uiItemL(layout, IFACE_("Select a sound from the list or load a new one"), ICON_NONE); return; diff --git a/source/blender/editors/space_nla/nla_buttons.c b/source/blender/editors/space_nla/nla_buttons.c index c774b99629c..3080ac2de84 100644 --- a/source/blender/editors/space_nla/nla_buttons.c +++ b/source/blender/editors/space_nla/nla_buttons.c @@ -285,7 +285,9 @@ static void nla_panel_animdata(const bContext *C, Panel *pa) /* Active Action Properties ------------------------------------- */ /* action */ row = uiLayoutRow(layout, true); - uiTemplateID(row, (bContext *)C, &adt_ptr, "action", "ACTION_OT_new", NULL, "NLA_OT_action_unlink"); + uiTemplateID( + row, (bContext *)C, &adt_ptr, "action", + "ACTION_OT_new", NULL, "NLA_OT_action_unlink", UI_TEMPLATE_ID_FILTER_ALL); /* extrapolation */ row = uiLayoutRow(layout, true); diff --git a/source/blender/editors/space_nla/nla_select.c b/source/blender/editors/space_nla/nla_select.c index 1179401f346..e09e4417d5d 100644 --- a/source/blender/editors/space_nla/nla_select.c +++ b/source/blender/editors/space_nla/nla_select.c @@ -444,7 +444,8 @@ static int nlaedit_select_leftright_exec(bContext *C, wmOperator *op) nlaedit_select_leftright(C, &ac, leftright, selectmode); /* set notifier that keyframe selection (and channels too) have changed */ - WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | ND_ANIMCHAN | NA_SELECTED, NULL); + WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL); + WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_SELECTED, NULL); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c index c591433f7b1..1bee2716e65 100644 --- a/source/blender/editors/space_node/drawnode.c +++ b/source/blender/editors/space_node/drawnode.c @@ -284,7 +284,7 @@ static int node_resize_area_default(bNode *node, int x, int y) static void node_draw_buttons_group(uiLayout *layout, bContext *C, PointerRNA *ptr) { - uiTemplateIDBrowse(layout, C, ptr, "node_tree", NULL, NULL, NULL); + uiTemplateIDBrowse(layout, C, ptr, "node_tree", NULL, NULL, NULL, UI_TEMPLATE_ID_FILTER_ALL); } /* XXX Does a bounding box update by iterating over all children. @@ -633,7 +633,8 @@ static void node_common_set_butfunc(bNodeType *ntype) /* ****************** BUTTON CALLBACKS FOR SHADER NODES ***************** */ static void node_buts_image_user(uiLayout *layout, bContext *C, PointerRNA *ptr, - PointerRNA *imaptr, PointerRNA *iuserptr) + PointerRNA *imaptr, PointerRNA *iuserptr, + bool compositor) { uiLayout *col; int source; @@ -668,7 +669,8 @@ static void node_buts_image_user(uiLayout *layout, bContext *C, PointerRNA *ptr, uiItemR(col, ptr, "use_auto_refresh", 0, NULL, ICON_NONE); } - if (RNA_enum_get(imaptr, "type") == IMA_TYPE_MULTILAYER && + if (compositor && + RNA_enum_get(imaptr, "type") == IMA_TYPE_MULTILAYER && RNA_boolean_get(ptr, "has_layers")) { col = uiLayoutColumn(layout, false); @@ -681,7 +683,7 @@ static void node_shader_buts_material(uiLayout *layout, bContext *C, PointerRNA bNode *node = ptr->data; uiLayout *col; - uiTemplateID(layout, C, ptr, "material", "MATERIAL_OT_new", NULL, NULL); + uiTemplateID(layout, C, ptr, "material", "MATERIAL_OT_new", NULL, NULL, UI_TEMPLATE_ID_FILTER_ALL); if (!node->id) return; @@ -778,7 +780,7 @@ static void node_shader_buts_tex_image(uiLayout *layout, bContext *C, PointerRNA PointerRNA iuserptr = RNA_pointer_get(ptr, "image_user"); uiLayoutSetContextPointer(layout, "image_user", &iuserptr); - uiTemplateID(layout, C, ptr, "image", NULL, "IMAGE_OT_open", NULL); + uiTemplateID(layout, C, ptr, "image", NULL, "IMAGE_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL); uiItemR(layout, ptr, "color_space", 0, "", ICON_NONE); uiItemR(layout, ptr, "interpolation", 0, "", ICON_NONE); uiItemR(layout, ptr, "projection", 0, "", ICON_NONE); @@ -792,7 +794,7 @@ static void node_shader_buts_tex_image(uiLayout *layout, bContext *C, PointerRNA /* note: image user properties used directly here, unlike compositor image node, * which redefines them in the node struct RNA to get proper updates. */ - node_buts_image_user(layout, C, &iuserptr, &imaptr, &iuserptr); + node_buts_image_user(layout, C, &iuserptr, &imaptr, &iuserptr, false); } static void node_shader_buts_tex_image_ex(uiLayout *layout, bContext *C, PointerRNA *ptr) @@ -807,9 +809,11 @@ static void node_shader_buts_tex_environment(uiLayout *layout, bContext *C, Poin PointerRNA iuserptr = RNA_pointer_get(ptr, "image_user"); uiLayoutSetContextPointer(layout, "image_user", &iuserptr); - uiTemplateID(layout, C, ptr, "image", NULL, "IMAGE_OT_open", NULL); + uiTemplateID( + layout, C, ptr, "image", + NULL, "IMAGE_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL); - node_buts_image_user(layout, C, &iuserptr, &imaptr, &iuserptr); + node_buts_image_user(layout, C, &iuserptr, &imaptr, &iuserptr, false); uiItemR(layout, ptr, "color_space", 0, "", ICON_NONE); uiItemR(layout, ptr, "interpolation", 0, "", ICON_NONE); @@ -823,7 +827,9 @@ static void node_shader_buts_tex_environment_ex(uiLayout *layout, bContext *C, P Image *ima = imaptr.data; uiLayoutSetContextPointer(layout, "image_user", &iuserptr); - uiTemplateID(layout, C, ptr, "image", ima ? NULL : "IMAGE_OT_new", "IMAGE_OT_open", NULL); + uiTemplateID( + layout, C, ptr, "image", + ima ? NULL : "IMAGE_OT_new", "IMAGE_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL); if (!ima) return; @@ -1250,12 +1256,14 @@ static void node_composit_buts_image(uiLayout *layout, bContext *C, PointerRNA * RNA_pointer_create((ID *)ptr->id.data, &RNA_ImageUser, node->storage, &iuserptr); uiLayoutSetContextPointer(layout, "image_user", &iuserptr); - uiTemplateID(layout, C, ptr, "image", NULL, "IMAGE_OT_open", NULL); + uiTemplateID( + layout, C, ptr, "image", + NULL, "IMAGE_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL); if (!node->id) return; imaptr = RNA_pointer_get(ptr, "image"); - node_buts_image_user(layout, C, ptr, &imaptr, &iuserptr); + node_buts_image_user(layout, C, ptr, &imaptr, &iuserptr, true); node_buts_image_views(layout, C, ptr, &imaptr); } @@ -1280,7 +1288,7 @@ static void node_composit_buts_viewlayers(uiLayout *layout, bContext *C, Pointer const char *layer_name; char scene_name[MAX_ID_NAME - 2]; - uiTemplateID(layout, C, ptr, "scene", NULL, NULL, NULL); + uiTemplateID(layout, C, ptr, "scene", NULL, NULL, NULL, UI_TEMPLATE_ID_FILTER_ALL); if (!node->id) return; @@ -1394,7 +1402,7 @@ static void node_composit_buts_defocus(uiLayout *layout, bContext *C, PointerRNA col = uiLayoutColumn(layout, false); uiItemR(col, ptr, "use_preview", 0, NULL, ICON_NONE); - uiTemplateID(layout, C, ptr, "scene", NULL, NULL, NULL); + uiTemplateID(layout, C, ptr, "scene", NULL, NULL, NULL, UI_TEMPLATE_ID_FILTER_ALL); col = uiLayoutColumn(layout, false); uiItemR(col, ptr, "use_zbuffer", 0, NULL, ICON_NONE); @@ -1961,7 +1969,7 @@ static void node_composit_buts_ycc(uiLayout *layout, bContext *UNUSED(C), Pointe static void node_composit_buts_movieclip(uiLayout *layout, bContext *C, PointerRNA *ptr) { - uiTemplateID(layout, C, ptr, "clip", NULL, "CLIP_OT_open", NULL); + uiTemplateID(layout, C, ptr, "clip", NULL, "CLIP_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL); } static void node_composit_buts_movieclip_ex(uiLayout *layout, bContext *C, PointerRNA *ptr) @@ -1969,7 +1977,7 @@ static void node_composit_buts_movieclip_ex(uiLayout *layout, bContext *C, Point bNode *node = ptr->data; PointerRNA clipptr; - uiTemplateID(layout, C, ptr, "clip", NULL, "CLIP_OT_open", NULL); + uiTemplateID(layout, C, ptr, "clip", NULL, "CLIP_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL); if (!node->id) return; @@ -1983,7 +1991,7 @@ static void node_composit_buts_stabilize2d(uiLayout *layout, bContext *C, Pointe { bNode *node = ptr->data; - uiTemplateID(layout, C, ptr, "clip", NULL, "CLIP_OT_open", NULL); + uiTemplateID(layout, C, ptr, "clip", NULL, "CLIP_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL); if (!node->id) return; @@ -2007,7 +2015,7 @@ static void node_composit_buts_moviedistortion(uiLayout *layout, bContext *C, Po { bNode *node = ptr->data; - uiTemplateID(layout, C, ptr, "clip", NULL, "CLIP_OT_open", NULL); + uiTemplateID(layout, C, ptr, "clip", NULL, "CLIP_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL); if (!node->id) return; @@ -2315,7 +2323,7 @@ static void node_composit_buts_mask(uiLayout *layout, bContext *C, PointerRNA *p { bNode *node = ptr->data; - uiTemplateID(layout, C, ptr, "mask", NULL, NULL, NULL); + uiTemplateID(layout, C, ptr, "mask", NULL, NULL, NULL, UI_TEMPLATE_ID_FILTER_ALL); uiItemR(layout, ptr, "use_antialiasing", 0, NULL, ICON_NONE); uiItemR(layout, ptr, "use_feather", 0, NULL, ICON_NONE); @@ -2337,7 +2345,7 @@ static void node_composit_buts_keyingscreen(uiLayout *layout, bContext *C, Point { bNode *node = ptr->data; - uiTemplateID(layout, C, ptr, "clip", NULL, NULL, NULL); + uiTemplateID(layout, C, ptr, "clip", NULL, NULL, NULL, UI_TEMPLATE_ID_FILTER_ALL); if (node->id) { MovieClip *clip = (MovieClip *) node->id; @@ -2373,7 +2381,7 @@ static void node_composit_buts_trackpos(uiLayout *layout, bContext *C, PointerRN { bNode *node = ptr->data; - uiTemplateID(layout, C, ptr, "clip", NULL, "CLIP_OT_open", NULL); + uiTemplateID(layout, C, ptr, "clip", NULL, "CLIP_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL); if (node->id) { MovieClip *clip = (MovieClip *) node->id; @@ -2413,7 +2421,7 @@ static void node_composit_buts_planetrackdeform(uiLayout *layout, bContext *C, P bNode *node = ptr->data; NodePlaneTrackDeformData *data = node->storage; - uiTemplateID(layout, C, ptr, "clip", NULL, "CLIP_OT_open", NULL); + uiTemplateID(layout, C, ptr, "clip", NULL, "CLIP_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL); if (node->id) { MovieClip *clip = (MovieClip *) node->id; @@ -2791,7 +2799,7 @@ static void node_texture_buts_proc(uiLayout *layout, bContext *UNUSED(C), Pointe static void node_texture_buts_image(uiLayout *layout, bContext *C, PointerRNA *ptr) { - uiTemplateID(layout, C, ptr, "image", NULL, "IMAGE_OT_open", NULL); + uiTemplateID(layout, C, ptr, "image", NULL, "IMAGE_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL); } static void node_texture_buts_image_ex(uiLayout *layout, bContext *C, PointerRNA *ptr) diff --git a/source/blender/editors/space_node/node_relationships.c b/source/blender/editors/space_node/node_relationships.c index 64c019d12a3..70f7553cf41 100644 --- a/source/blender/editors/space_node/node_relationships.c +++ b/source/blender/editors/space_node/node_relationships.c @@ -31,12 +31,14 @@ #include "MEM_guardedalloc.h" +#include "DNA_anim_types.h" #include "DNA_node_types.h" #include "BLI_math.h" #include "BLI_blenlib.h" #include "BLI_easing.h" +#include "BKE_animsys.h" #include "BKE_context.h" #include "BKE_global.h" #include "BKE_library.h" @@ -63,6 +65,15 @@ /* ****************** Relations helpers *********************** */ +static bool ntree_has_drivers(bNodeTree *ntree) +{ + AnimData *adt = BKE_animdata_from_id(&ntree->id); + if (adt == NULL) { + return false; + } + return !BLI_listbase_is_empty(&adt->drivers); +} + static bool ntree_check_nodes_connected_dfs(bNodeTree *ntree, bNode *from, bNode *to) @@ -134,6 +145,14 @@ static bool node_group_has_output(bNode *node) bool node_connected_to_output(bNodeTree *ntree, bNode *node) { + /* Special case for drivers: if node tree has any drivers we assume it is + * always to be tagged for update when node changes. Otherwise we will be + * doomed to do some deep and nasty deep search of indirect dependencies, + * which will be too complicated without real benefit. + */ + if (ntree_has_drivers(ntree)) { + return true; + } for (bNode *current_node = ntree->nodes.first; current_node != NULL; current_node = current_node->next) @@ -144,11 +163,17 @@ bool node_connected_to_output(bNodeTree *ntree, bNode *node) * We could make check more grained here by taking which socket the node * is connected to and so eventually. */ - if (current_node->type == NODE_GROUP && - ntree_check_nodes_connected(ntree, node, current_node) && - node_group_has_output(current_node)) - { - return true; + if (current_node->type == NODE_GROUP) { + if (current_node->id != NULL && + ntree_has_drivers((bNodeTree *)current_node->id)) + { + return true; + } + if (ntree_check_nodes_connected(ntree, node, current_node) && + node_group_has_output(current_node)) + { + return true; + } } if (current_node->flag & NODE_DO_OUTPUT) { if (ntree_check_nodes_connected(ntree, node, current_node)) { diff --git a/source/blender/editors/space_outliner/outliner_collections.c b/source/blender/editors/space_outliner/outliner_collections.c index d5c833a7b5f..8999555521a 100644 --- a/source/blender/editors/space_outliner/outliner_collections.c +++ b/source/blender/editors/space_outliner/outliner_collections.c @@ -51,13 +51,13 @@ #include "outliner_intern.h" /* own include */ +/* Prototypes. */ +static int collection_delete_exec(struct bContext *C, struct wmOperator *op); + /* -------------------------------------------------------------------- */ static LayerCollection *outliner_collection_active(bContext *C) { - TODO_LAYER_OPERATORS; - /* consider that we may have overrides or objects active - * leading to no active collections */ return CTX_data_layer_collection(C); } @@ -76,14 +76,20 @@ SceneCollection *outliner_scene_collection_from_tree_element(TreeElement *te) return NULL; } -#if 0 -static CollectionOverride *outliner_override_active(bContext *UNUSED(C)) +/* -------------------------------------------------------------------- */ +/* Poll functions. */ + +static int collections_editor_poll(bContext *C) { - TODO_LAYER_OPERATORS; - TODO_LAYER_OVERRIDE; - return NULL; + SpaceOops *so = CTX_wm_space_outliner(C); + return (so != NULL) && (so->outlinevis == SO_COLLECTIONS); +} + +static int view_layer_editor_poll(bContext *C) +{ + SpaceOops *so = CTX_wm_space_outliner(C); + return (so != NULL) && (so->outlinevis == SO_VIEW_LAYER); } -#endif /* -------------------------------------------------------------------- */ /* collection manager operators */ @@ -108,6 +114,44 @@ static SceneCollection *scene_collection_from_index(ListBase *lb, const int numb return NULL; } +typedef struct TreeElementFindData { + SceneCollection *collection; + TreeElement *r_result_te; +} TreeElementFindData; + +static TreeTraversalAction tree_element_find_by_scene_collection_cb(TreeElement *te, void *customdata) +{ + TreeElementFindData *data = customdata; + const SceneCollection *current_element_sc = outliner_scene_collection_from_tree_element(te); + + if (current_element_sc == data->collection) { + data->r_result_te = te; + return TRAVERSE_BREAK; + } + + return TRAVERSE_CONTINUE; +} + +static TreeElement *outliner_tree_element_from_layer_collection_index( + SpaceOops *soops, ViewLayer *view_layer, + const int index) +{ + LayerCollection *lc = BKE_layer_collection_from_index(view_layer, index); + + if (lc == NULL) { + return NULL; + } + + /* Find the tree element containing the LayerCollection's scene_collection. */ + TreeElementFindData data = { + .collection = lc->scene_collection, + .r_result_te = NULL, + }; + outliner_tree_traverse(soops, &soops->tree, 0, 0, tree_element_find_by_scene_collection_cb, &data); + + return data.r_result_te; +} + static int collection_link_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); @@ -187,7 +231,7 @@ void OUTLINER_OT_collection_link(wmOperatorType *ot) PropertyRNA *prop; /* identifiers */ - ot->name = "Add Collection"; + ot->name = "Link Collection"; ot->idname = "OUTLINER_OT_collection_link"; ot->description = "Link a new collection to the active layer"; @@ -210,6 +254,10 @@ void OUTLINER_OT_collection_link(wmOperatorType *ot) */ static int collection_unlink_poll(bContext *C) { + if (view_layer_editor_poll(C) == 0) { + return 0; + } + LayerCollection *lc = outliner_collection_active(C); if (lc == NULL) { @@ -249,7 +297,7 @@ static int collection_unlink_exec(bContext *C, wmOperator *op) void OUTLINER_OT_collection_unlink(wmOperatorType *ot) { /* identifiers */ - ot->name = "Add Collection"; + ot->name = "Unlink Collection"; ot->idname = "OUTLINER_OT_collection_unlink"; ot->description = "Unlink collection from the active layer"; @@ -292,40 +340,218 @@ void OUTLINER_OT_collection_new(wmOperatorType *ot) } /**********************************************************************************/ +/* Add new nested collection. */ -/** - * Returns true is selected element is a collection - */ -static int collection_override_new_poll(bContext *(C)) +struct CollectionNewData +{ + bool error; + SceneCollection *scene_collection; +}; + +static TreeTraversalAction collection_find_selected_to_add(TreeElement *te, void *customdata) +{ + struct CollectionNewData *data = customdata; + SceneCollection *scene_collection = outliner_scene_collection_from_tree_element(te); + + if (!scene_collection) { + return TRAVERSE_SKIP_CHILDS; + } + + if (data->scene_collection != NULL) { + data->error = true; + return TRAVERSE_BREAK; + } + + data->scene_collection = scene_collection; + return TRAVERSE_CONTINUE; +} + +static int collection_nested_new_exec(bContext *C, wmOperator *op) +{ + SpaceOops *soops = CTX_wm_space_outliner(C); + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + + struct CollectionNewData data = { + .error = false, + .scene_collection = NULL, + }; + + outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, collection_find_selected_to_add, &data); + + if (data.error) { + BKE_report(op->reports, RPT_ERROR, "More than one collection is selected"); + return OPERATOR_CANCELLED; + } + + BKE_collection_add( + &scene->id, + data.scene_collection, + COLLECTION_TYPE_NONE, + NULL); + + outliner_cleanup_tree(soops); + DEG_relations_tag_update(bmain); + WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL); + return OPERATOR_FINISHED; +} + +void OUTLINER_OT_collection_nested_new(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "New Nested Collection"; + ot->idname = "OUTLINER_OT_collection_nested_new"; + ot->description = "Add a new collection inside selected collection"; + + /* api callbacks */ + ot->exec = collection_nested_new_exec; + ot->poll = collections_editor_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +/**********************************************************************************/ +/* Delete selected collection. */ + +void OUTLINER_OT_collection_delete_selected(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Delete Selected Collections"; + ot->idname = "OUTLINER_OT_collection_delete_selected"; + ot->description = "Delete all the selected collections"; + + /* api callbacks */ + ot->exec = collection_delete_exec; + ot->poll = collections_editor_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +/**********************************************************************************/ +/* Add new selected objects. */ + +struct SceneCollectionSelectedData { + ListBase scene_collections_array; +}; + +static TreeTraversalAction collection_find_selected_scene_collections(TreeElement *te, void *customdata) +{ + struct SceneCollectionSelectedData *data = customdata; + SceneCollection *scene_collection = outliner_scene_collection_from_tree_element(te); + + if (!scene_collection) { + return TRAVERSE_SKIP_CHILDS; + } + + BLI_addtail(&data->scene_collections_array, BLI_genericNodeN(scene_collection)); + return TRAVERSE_CONTINUE; +} + +static int collection_objects_add_exec(bContext *C, wmOperator *op) +{ + SpaceOops *soops = CTX_wm_space_outliner(C); + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + + struct SceneCollectionSelectedData data = { + .scene_collections_array = {NULL, NULL}, + }; + + outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, collection_find_selected_scene_collections, &data); + + if (BLI_listbase_is_empty(&data.scene_collections_array)) { + BKE_report(op->reports, RPT_ERROR, "No collection is selected"); + return OPERATOR_CANCELLED; + } + + CTX_DATA_BEGIN (C, struct Object *, ob, selected_objects) + { + BLI_LISTBASE_FOREACH (LinkData *, link, &data.scene_collections_array) { + SceneCollection *scene_collection = link->data; + BKE_collection_object_add( + &scene->id, + scene_collection, + ob); + } + } + CTX_DATA_END; + BLI_freelistN(&data.scene_collections_array); + + outliner_cleanup_tree(soops); + DEG_relations_tag_update(bmain); + WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL); + return OPERATOR_FINISHED; +} + +void OUTLINER_OT_collection_objects_add(wmOperatorType *ot) { -#ifdef TODO_LAYER_OVERRIDE - /* disable for now, since it's not implemented */ - (void) C; - return 0; -#else - return outliner_collection_active(C) ? 1 : 0; -#endif + /* identifiers */ + ot->name = "Add Objects"; + ot->idname = "OUTLINER_OT_collection_objects_add"; + ot->description = "Add selected objects to collection"; + + /* api callbacks */ + ot->exec = collection_objects_add_exec; + ot->poll = collections_editor_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -static int collection_override_new_invoke(bContext *UNUSED(C), wmOperator *op, const wmEvent *UNUSED(event)) +/**********************************************************************************/ +/* Remove selected objects. */ + + +static int collection_objects_remove_exec(bContext *C, wmOperator *op) { - TODO_LAYER_OPERATORS; - TODO_LAYER_OVERRIDE; - BKE_report(op->reports, RPT_ERROR, "OUTLINER_OT_collections_override_new not implemented yet"); - return OPERATOR_CANCELLED; + SpaceOops *soops = CTX_wm_space_outliner(C); + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + + struct SceneCollectionSelectedData data = { + .scene_collections_array = {NULL, NULL}, + }; + + outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, collection_find_selected_scene_collections, &data); + + if (BLI_listbase_is_empty(&data.scene_collections_array)) { + BKE_report(op->reports, RPT_ERROR, "No collection is selected"); + return OPERATOR_CANCELLED; + } + + CTX_DATA_BEGIN (C, struct Object *, ob, selected_objects) + { + BLI_LISTBASE_FOREACH (LinkData *, link, &data.scene_collections_array) { + SceneCollection *scene_collection = link->data; + BKE_collection_object_remove( + bmain, + &scene->id, + scene_collection, + ob, + true); + } + } + CTX_DATA_END; + BLI_freelistN(&data.scene_collections_array); + + outliner_cleanup_tree(soops); + DEG_relations_tag_update(bmain); + WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL); + return OPERATOR_FINISHED; } -/* in the middle of renames remove s */ -void OUTLINER_OT_collection_override_new(wmOperatorType *ot) +void OUTLINER_OT_collection_objects_remove(wmOperatorType *ot) { /* identifiers */ - ot->name = "New Override"; - ot->idname = "OUTLINER_OT_collection_override_new"; - ot->description = "Add a new override to the active collection"; + ot->name = "Remove Objects"; + ot->idname = "OUTLINER_OT_collection_objects_remove"; + ot->description = "Remove selected objects from collection"; /* api callbacks */ - ot->invoke = collection_override_new_invoke; - ot->poll = collection_override_new_poll; + ot->exec = collection_objects_remove_exec; + ot->poll = collections_editor_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -352,6 +578,26 @@ static TreeTraversalAction collection_find_data_to_delete(TreeElement *te, void } else { BLI_gset_add(data->collections_to_delete, scene_collection); + return TRAVERSE_SKIP_CHILDS; /* Childs will be gone anyway, no need to recurse deeper. */ + } + + return TRAVERSE_CONTINUE; +} + +static TreeTraversalAction collection_delete_elements_from_collection(TreeElement *te, void *customdata) +{ + struct CollectionDeleteData *data = customdata; + SceneCollection *scene_collection = outliner_scene_collection_from_tree_element(te); + + if (!scene_collection) { + return TRAVERSE_SKIP_CHILDS; + } + + const bool will_be_deleted = BLI_gset_haskey(data->collections_to_delete, scene_collection); + if (will_be_deleted) { + outliner_free_tree_element(te, te->parent ? &te->parent->subtree : &data->soops->tree); + /* Childs are freed now, so don't recurse into them. */ + return TRAVERSE_SKIP_CHILDS; } return TRAVERSE_CONTINUE; @@ -365,26 +611,33 @@ static int collection_delete_exec(bContext *C, wmOperator *UNUSED(op)) data.collections_to_delete = BLI_gset_ptr_new(__func__); - TODO_LAYER_OVERRIDE; /* handle overrides */ - /* We first walk over and find the SceneCollections we actually want to delete (ignoring duplicates). */ outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, collection_find_data_to_delete, &data); + /* Now, delete all tree elements representing a collection that will be deleted. We'll look for a + * new element to select in a few lines, so we can't wait until the tree is recreated on redraw. */ + outliner_tree_traverse(soops, &soops->tree, 0, 0, collection_delete_elements_from_collection, &data); + /* Effectively delete the collections. */ GSetIterator collections_to_delete_iter; GSET_ITER(collections_to_delete_iter, data.collections_to_delete) { - SceneCollection *sc = BLI_gsetIterator_getKey(&collections_to_delete_iter); BKE_collection_remove(&data.scene->id, sc); } BLI_gset_free(data.collections_to_delete, NULL); + TreeElement *select_te = outliner_tree_element_from_layer_collection_index(soops, CTX_data_view_layer(C), 0); + if (select_te) { + outliner_item_select(soops, select_te, false, false); + } + DEG_relations_tag_update(CTX_data_main(C)); /* TODO(sergey): Use proper flag for tagging here. */ DEG_id_tag_update(&scene->id, 0); + soops->storeflag |= SO_TREESTORE_REDRAW; WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL); return OPERATOR_FINISHED; @@ -438,13 +691,12 @@ static int collection_toggle_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); int action = RNA_enum_get(op->ptr, "action"); LayerCollection *layer_collection = CTX_data_layer_collection(C); if (layer_collection->flag & COLLECTION_DISABLED) { if (ELEM(action, ACTION_TOGGLE, ACTION_ENABLE)) { - BKE_collection_enable(view_layer, layer_collection); + layer_collection->flag &= ~COLLECTION_DISABLED; } else { /* ACTION_DISABLE */ BKE_reportf(op->reports, RPT_ERROR, "Layer collection %s already disabled", @@ -454,7 +706,7 @@ static int collection_toggle_exec(bContext *C, wmOperator *op) } else { if (ELEM(action, ACTION_TOGGLE, ACTION_DISABLE)) { - BKE_collection_disable(view_layer, layer_collection); + layer_collection->flag |= COLLECTION_DISABLED; } else { /* ACTION_ENABLE */ BKE_reportf(op->reports, RPT_ERROR, "Layer collection %s already enabled", @@ -505,68 +757,3 @@ void OUTLINER_OT_collection_toggle(wmOperatorType *ot) #undef ACTION_TOGGLE #undef ACTION_ENABLE #undef ACTION_DISABLE - -/* -------------------------------------------------------------------- */ - -static int stubs_invoke(bContext *UNUSED(C), wmOperator *op, const wmEvent *UNUSED(event)) -{ - TODO_LAYER_OPERATORS; - BKE_report(op->reports, RPT_ERROR, "Operator not implemented yet"); - return OPERATOR_CANCELLED; -} - -void OUTLINER_OT_collection_objects_add(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Add Objects"; - ot->idname = "OUTLINER_OT_collection_objects_add"; - ot->description = "Add selected objects to collection"; - - /* api callbacks */ - ot->invoke = stubs_invoke; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; -} - -void OUTLINER_OT_collection_objects_remove(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Remove Object"; - ot->idname = "OUTLINER_OT_collection_objects_remove"; - ot->description = "Remove objects from collection"; - - /* api callbacks */ - ot->invoke = stubs_invoke; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; -} - -void OUTLINER_OT_collection_objects_select(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Select Objects"; - ot->idname = "OUTLINER_OT_collection_objects_select"; - ot->description = "Select collection objects"; - - /* api callbacks */ - ot->invoke = stubs_invoke; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; -} - -void OUTLINER_OT_collection_objects_deselect(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Deselect Objects"; - ot->idname = "OUTLINER_OT_collection_objects_deselect"; - ot->description = "Deselect collection objects"; - - /* api callbacks */ - ot->invoke = stubs_invoke; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; -} diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c index 670fc4e6627..1478792b38b 100644 --- a/source/blender/editors/space_outliner/outliner_draw.c +++ b/source/blender/editors/space_outliner/outliner_draw.c @@ -247,49 +247,16 @@ static void restrictbutton_gp_layer_flag_cb(bContext *C, void *UNUSED(poin), voi WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); } -static void enablebutton_collection_flag_cb(bContext *C, void *poin, void *poin2) -{ - Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); - ID *id = poin; - LayerCollection *layer_collection = poin2; - ViewLayer *view_layer = BKE_view_layer_find_from_collection(id, layer_collection); - - /* TODO: This breaks when you see the collections of a group. (dfelinto) */ - if (view_layer == NULL) { - WM_reportf(RPT_INFO, "Enable/disable of group collections disabled for now"); - return; - } - - /* We need to toggle the flag since this is called after the flag is already set. */ - layer_collection->flag ^= COLLECTION_DISABLED; - - if (layer_collection->flag & COLLECTION_DISABLED) { - BKE_collection_enable(view_layer, layer_collection); - } - else { - BKE_collection_disable(view_layer, layer_collection); - } - - DEG_relations_tag_update(bmain); - /* TODO(sergey): Use proper flag for tagging here. */ - DEG_id_tag_update(&scene->id, 0); - WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); - WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, NULL); -} - static void restrictbutton_collection_flag_cb(bContext *C, void *poin, void *UNUSED(poin2)) { ID *id = (ID *)poin; - /* hide and deselect bases that are directly influenced by this LayerCollection */ /* TODO(sergey): Use proper flag for tagging here. */ DEG_id_tag_update(id, 0); if (GS(id->name) == ID_SCE) { WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, id); } - WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, NULL); } @@ -602,21 +569,6 @@ static void outliner_draw_restrictbuts(uiBlock *block, Scene *scene, ARegion *ar UI_block_emboss_set(block, UI_EMBOSS_NONE); - bt = uiDefIconButBitS(block, UI_BTYPE_BUT_TOGGLE, COLLECTION_DISABLED, 0, - is_enabled ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT, - (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_ENABLEX), te->ys, UI_UNIT_X, - UI_UNIT_Y, &collection->flag, 0, 0, 0, 0, - TIP_("Enable/Disable collection from depsgraph")); - UI_but_func_set(bt, enablebutton_collection_flag_cb, tselem->id, collection); - UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); - - bt = uiDefIconButBitS(block, UI_BTYPE_ICON_TOGGLE_N, COLLECTION_VISIBLE, 0, ICON_RESTRICT_VIEW_OFF, - (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), te->ys, UI_UNIT_X, - UI_UNIT_Y, &collection->flag, 0, 0, 0, 0, - TIP_("Restrict/Allow 3D View visibility of objects in the collection")); - UI_but_func_set(bt, restrictbutton_collection_flag_cb, tselem->id, collection); - UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); - if (collection->scene_collection->type == COLLECTION_TYPE_NONE) { bt = uiDefIconButBitS(block, UI_BTYPE_ICON_TOGGLE_N, COLLECTION_SELECTABLE, 0, ICON_RESTRICT_SELECT_OFF, (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), te->ys, UI_UNIT_X, @@ -625,6 +577,31 @@ static void outliner_draw_restrictbuts(uiBlock *block, Scene *scene, ARegion *ar UI_but_func_set(bt, restrictbutton_collection_flag_cb, scene, collection); UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); } + else if ((soops->outlinevis == SO_GROUPS) && + (collection->scene_collection->type == COLLECTION_TYPE_GROUP_INTERNAL)) + { + bt = uiDefIconButBitS(block, UI_BTYPE_ICON_TOGGLE_N, COLLECTION_VIEWPORT, 0, ICON_RESTRICT_VIEW_OFF, + (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), te->ys, UI_UNIT_X, + UI_UNIT_Y, &collection->flag, 0, 0, 0, 0, + TIP_("Restrict/Allow 3D View selection of objects in the collection")); + UI_but_func_set(bt, restrictbutton_collection_flag_cb, tselem->id, collection); + UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); + + bt = uiDefIconButBitS(block, UI_BTYPE_ICON_TOGGLE_N, COLLECTION_RENDER, 0, ICON_RESTRICT_RENDER_OFF, + (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), te->ys, UI_UNIT_X, + UI_UNIT_Y, &collection->flag, 0, 0, 0, 0, + TIP_("Restrict/Allow 3D View selection of objects in the collection")); + UI_but_func_set(bt, restrictbutton_collection_flag_cb, tselem->id, collection); + UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); + } + + bt = uiDefIconButBitS(block, UI_BTYPE_BUT_TOGGLE, COLLECTION_DISABLED, 0, + is_enabled ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT, + (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX), te->ys, UI_UNIT_X, + UI_UNIT_Y, &collection->flag, 0, 0, 0, 0, + TIP_("Enable/Disable collection")); + UI_but_func_set(bt, restrictbutton_collection_flag_cb, tselem->id, collection); + UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); UI_block_emboss_set(block, UI_EMBOSS); } @@ -694,7 +671,7 @@ static void outliner_draw_userbuts(uiBlock *block, ARegion *ar, SpaceOops *soops } } -static void outliner_draw_rnacols(ARegion *ar, int sizex) +static void UNUSED_FUNCTION(outliner_draw_rnacols)(ARegion *ar, int sizex) { View2D *v2d = &ar->v2d; @@ -720,6 +697,7 @@ static void outliner_draw_rnacols(ARegion *ar, int sizex) immUnbindProgram(); } +#if 0 static void outliner_draw_rnabuts(uiBlock *block, ARegion *ar, SpaceOops *soops, int sizex, ListBase *lb) { TreeElement *te; @@ -764,6 +742,7 @@ static void outliner_draw_rnabuts(uiBlock *block, ARegion *ar, SpaceOops *soops, UI_block_emboss_set(block, UI_EMBOSS); } +#endif static void outliner_buttons(const bContext *C, uiBlock *block, ARegion *ar, TreeElement *te) { @@ -1131,6 +1110,10 @@ static void tselem_draw_icon(uiBlock *block, int xmax, float x, float y, TreeSto ICON_DRAW(icon); } break; + case TSE_LAYER_COLLECTION: + case TSE_SCENE_COLLECTION: + ICON_DRAW(ICON_COLLAPSEMENU); + break; /* Removed the icons from outliner. Need a better structure with Layers, Palettes and Colors */ #if 0 case TSE_GP_LAYER: @@ -1378,22 +1361,24 @@ static void outliner_draw_tree_element( } else if (te->idcode == ID_OB) { Object *ob = (Object *)tselem->id; - - if (ob == OBACT(view_layer) || (ob->flag & SELECT)) { + Base *base = (Base *)te->directdata; + const bool is_selected = (base != NULL) && ((base->flag & BASE_SELECTED) != 0); + + if (ob == OBACT(view_layer) || is_selected) { char col[4] = {0, 0, 0, 0}; /* outliner active ob: always white text, circle color now similar to view3d */ active = OL_DRAWSEL_ACTIVE; if (ob == OBACT(view_layer)) { - if (ob->flag & SELECT) { + if (is_selected) { UI_GetThemeColorType4ubv(TH_ACTIVE, SPACE_VIEW3D, col); col[3] = alpha; } active = OL_DRAWSEL_NORMAL; } - else if (ob->flag & SELECT) { + else if (is_selected) { UI_GetThemeColorType4ubv(TH_SELECT, SPACE_VIEW3D, col); col[3] = alpha; } @@ -1432,13 +1417,12 @@ static void outliner_draw_tree_element( te->flag |= TE_ACTIVE; // for lookup in display hierarchies } + if ((soops->outlinevis == SO_COLLECTIONS) && (tselem->type == TSE_SCENE_COLLECTION) && (te->parent == NULL)) { + /* Master collection can't expand/collapse. */ + } + else if (te->subtree.first || (tselem->type == 0 && te->idcode == ID_SCE) || (te->flag & TE_LAZY_CLOSED)) { /* open/close icon, only when sublevels, except for scene */ - if (te->subtree.first || (tselem->type == 0 && te->idcode == ID_SCE) || (te->flag & TE_LAZY_CLOSED)) { - int icon_x; - if (tselem->type == 0 && ELEM(te->idcode, ID_OB, ID_SCE)) - icon_x = startx; - else - icon_x = startx + 5 * ufac; + int icon_x = startx; // icons a bit higher if (TSELEM_OPEN(tselem, soops)) @@ -1474,6 +1458,11 @@ static void outliner_draw_tree_element( } offsx += UI_UNIT_X + 2 * ufac; } + else if (tselem->type == 0 && ID_IS_STATIC_OVERRIDE(tselem->id)) { + UI_icon_draw_alpha((float)startx + offsx + 2 * ufac, (float)*starty + 2 * ufac, ICON_LIBRARY_DATA_OVERRIDE, + alpha_fac); + offsx += UI_UNIT_X + 2 * ufac; + } glDisable(GL_BLEND); /* name */ @@ -1612,7 +1601,7 @@ static void outliner_draw_hierarchy_lines_recursive(unsigned pos, SpaceOops *soo const unsigned char col[4], bool draw_grayed_out, int *starty) { - TreeElement *te; + TreeElement *te, *te_vertical_line_last = NULL; TreeStoreElem *tselem; int y1, y2; @@ -1622,10 +1611,10 @@ static void outliner_draw_hierarchy_lines_recursive(unsigned pos, SpaceOops *soo const unsigned char grayed_alpha = col[3] / 2; - y1 = y2 = *starty; /* for vertical lines between objects */ + /* For vertical lines between objects. */ + y1 = *starty; for (te = lb->first; te; te = te->next) { bool draw_childs_grayed_out = draw_grayed_out || (te->drag_data != NULL); - y2 = *starty; tselem = TREESTORE(te); if (draw_childs_grayed_out) { @@ -1635,10 +1624,17 @@ static void outliner_draw_hierarchy_lines_recursive(unsigned pos, SpaceOops *soo immUniformColor4ubv(col); } - /* horizontal line? */ - if (tselem->type == 0 && (te->idcode == ID_OB || te->idcode == ID_SCE)) + /* Horizontal Line? */ + if (tselem->type == 0 && (te->idcode == ID_OB || te->idcode == ID_SCE)) { immRecti(pos, startx, *starty, startx + UI_UNIT_X, *starty - 1); - + + /* Vertical Line? */ + if (te->idcode == ID_OB) { + te_vertical_line_last = te; + y2 = *starty; + } + } + *starty -= UI_UNIT_Y; if (TSELEM_OPEN(tselem, soops)) @@ -1653,12 +1649,10 @@ static void outliner_draw_hierarchy_lines_recursive(unsigned pos, SpaceOops *soo immUniformColor4ubv(col); } - /* vertical line */ - te = lb->last; - if (te->parent || lb->first != lb->last) { - tselem = TREESTORE(te); - if (tselem->type == 0 && te->idcode == ID_OB) - immRecti(pos, startx, y1 + UI_UNIT_Y, startx + 1, y2); + /* Vertical line. */ + te = te_vertical_line_last; + if ((te != NULL) && (te->parent || lb->first != lb->last)) { + immRecti(pos, startx, y1 + UI_UNIT_Y, startx + 1, y2); } } @@ -1724,7 +1718,9 @@ static void outliner_draw_highlights_recursive( int start_x, int *io_start_y) { const bool is_searching = SEARCHING_OUTLINER(soops) || - (soops->outlinevis == SO_DATABLOCKS && soops->search_string[0] != 0); + (soops->outlinevis == SO_DATABLOCKS && + (soops->filter & SO_FILTER_SEARCH) && + soops->search_string[0] != 0); for (TreeElement *te = lb->first; te; te = te->next) { const TreeStoreElem *tselem = TREESTORE(te); @@ -1790,7 +1786,7 @@ static void outliner_draw_tree( glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // only once - if (ELEM(soops->outlinevis, SO_DATABLOCKS, SO_USERDEF)) { + if (soops->outlinevis == SO_DATABLOCKS) { /* struct marks */ starty = (int)ar->v2d.tot.ymax - UI_UNIT_Y - OL_Y_OFFSET; outliner_draw_struct_marks(ar, soops, &soops->tree, &starty); @@ -1814,7 +1810,7 @@ static void outliner_draw_tree( // gray hierarchy lines starty = (int)ar->v2d.tot.ymax - UI_UNIT_Y / 2 - OL_Y_OFFSET; - startx = 6; + startx = UI_UNIT_X / 2 - 1.0f; outliner_draw_hierarchy_lines(soops, &soops->tree, startx, &starty); // items themselves @@ -1879,15 +1875,12 @@ static void outliner_draw_restrictcols(ARegion *ar) immUniformThemeColorShadeAlpha(TH_BACK, -15, -200); immBegin(GWN_PRIM_LINES, 6); - /* view */ immVertex2i(pos, (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), (int)ar->v2d.cur.ymax); immVertex2i(pos, (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), (int)ar->v2d.cur.ymin); - /* render */ immVertex2i(pos, (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), (int)ar->v2d.cur.ymax); immVertex2i(pos, (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), (int)ar->v2d.cur.ymin); - /* render */ immVertex2i(pos, (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX), (int)ar->v2d.cur.ymax); immVertex2i(pos, (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX), (int)ar->v2d.cur.ymin); @@ -1911,12 +1904,12 @@ void draw_outliner(const bContext *C) TreeElement *te_edit = NULL; bool has_restrict_icons; - outliner_build_tree(mainvar, scene, view_layer, soops); // always + outliner_build_tree(mainvar, scene, view_layer, soops, ar); // always /* get extents of data */ outliner_height(soops, &soops->tree, &sizey); - if (ELEM(soops->outlinevis, SO_DATABLOCKS, SO_USERDEF)) { + if (soops->outlinevis == SO_DATABLOCKS) { /* RNA has two columns: * - column 1 is (max_width + OL_RNA_COL_SPACEX) or * (OL_RNA_COL_X), whichever is wider... @@ -1941,8 +1934,9 @@ void draw_outliner(const bContext *C) /* constant offset for restriction columns */ // XXX this isn't that great yet... - if ((soops->flag & SO_HIDE_RESTRICTCOLS) == 0) + if ((soops->flag & SO_HIDE_RESTRICTCOLS) == 0) { sizex += OL_TOGW * 3; + } has_restrict_icons = !(soops->flag & SO_HIDE_RESTRICTCOLS); } @@ -1962,13 +1956,8 @@ void draw_outliner(const bContext *C) outliner_back(ar); block = UI_block_begin(C, ar, __func__, UI_EMBOSS); outliner_draw_tree((bContext *)C, block, scene, view_layer, ar, soops, has_restrict_icons, &te_edit); - - if (ELEM(soops->outlinevis, SO_DATABLOCKS, SO_USERDEF)) { - /* draw rna buttons */ - outliner_draw_rnacols(ar, sizex_rna); - outliner_draw_rnabuts(block, ar, soops, sizex_rna, &soops->tree); - } - else if ((soops->outlinevis == SO_ID_ORPHANS) && has_restrict_icons) { + + if ((soops->outlinevis == SO_ID_ORPHANS) && has_restrict_icons) { /* draw user toggle columns */ outliner_draw_restrictcols(ar); outliner_draw_userbuts(block, ar, soops, &soops->tree); diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c index 8cd76179f23..fc0e30c78ce 100644 --- a/source/blender/editors/space_outliner/outliner_edit.c +++ b/source/blender/editors/space_outliner/outliner_edit.c @@ -949,7 +949,7 @@ static void outliner_set_coordinates_element_recursive(SpaceOops *soops, TreeEle } /* to retrieve coordinates with redrawing the entire tree */ -static void outliner_set_coordinates(ARegion *ar, SpaceOops *soops) +void outliner_set_coordinates(ARegion *ar, SpaceOops *soops) { TreeElement *te; int starty = (int)(ar->v2d.tot.ymax) - UI_UNIT_Y; @@ -2085,7 +2085,7 @@ static int outliner_parenting_poll(bContext *C) SpaceOops *soops = CTX_wm_space_outliner(C); if (soops) { - return ELEM(soops->outlinevis, SO_ALL_SCENES, SO_CUR_SCENE, SO_VISIBLE, SO_GROUPS); + return ELEM(soops->outlinevis, SO_VIEW_LAYER, SO_COLLECTIONS, SO_GROUPS); } return false; diff --git a/source/blender/editors/space_outliner/outliner_intern.h b/source/blender/editors/space_outliner/outliner_intern.h index f69eb9af1bf..b06c9b85eb8 100644 --- a/source/blender/editors/space_outliner/outliner_intern.h +++ b/source/blender/editors/space_outliner/outliner_intern.h @@ -36,6 +36,7 @@ /* internal exports only */ +struct ARegion; struct wmOperatorType; struct TreeElement; struct TreeStoreElem; @@ -47,6 +48,7 @@ struct ID; struct Object; struct bPoseChannel; struct EditBone; +struct wmEvent; struct wmKeyConfig; @@ -69,8 +71,11 @@ typedef enum TreeTraversalAction { * Callback type for reinserting elements at a different position, used to allow user customizable element order. */ typedef void (*TreeElementReinsertFunc)(struct Main *bmain, + struct SpaceOops *soops, struct TreeElement *insert_element, - struct TreeElement *insert_handle, TreeElementInsertType action); + struct TreeElement *insert_handle, + TreeElementInsertType action, + const struct wmEvent *event); /** * Executed on (almost) each mouse move while dragging. It's supposed to give info * if reinserting insert_element before/after/into insert_handle would be allowed. @@ -102,6 +107,7 @@ typedef struct TreeElement { TreeElementInsertType insert_type; /* the element before/after/into which we may insert the dragged one (NULL to insert at top) */ struct TreeElement *insert_handle; + void *tooltip_draw_handle; } *drag_data; } TreeElement; @@ -143,17 +149,19 @@ typedef enum { /* size constants */ #define OL_Y_OFFSET 2 -#define OL_TOG_RESTRICT_ENABLEX (UI_UNIT_X * 3.0f) -#define OL_TOG_RESTRICT_VIEWX (UI_UNIT_X * 2.0f) -#define OL_TOG_RESTRICT_SELECTX UI_UNIT_X +#define OL_TOG_RESTRICT_VIEWX (UI_UNIT_X * 3.0f) +#define OL_TOG_RESTRICT_SELECTX (UI_UNIT_X * 2.0f) #define OL_TOG_RESTRICT_RENDERX UI_UNIT_X -#define OL_TOGW OL_TOG_RESTRICT_ENABLEX +#define OL_TOGW OL_TOG_RESTRICT_VIEWX #define OL_RNA_COLX (UI_UNIT_X * 15) #define OL_RNA_COL_SIZEX (UI_UNIT_X * 7.5f) #define OL_RNA_COL_SPACEX (UI_UNIT_X * 2.5f) +/* The outliner display modes that support the filter system. + * Note: keep it synced with space_outliner.py */ +#define SUPPORT_FILTER_OUTLINER(soops_) ELEM((soops_)->outlinevis, SO_VIEW_LAYER, SO_COLLECTIONS) /* Outliner Searching -- * @@ -171,18 +179,20 @@ typedef enum { * - not searching into RNA items helps but isn't the complete solution */ -#define SEARCHING_OUTLINER(sov) (sov->search_flags & SO_SEARCH_RECURSIVE) +#define SEARCHING_OUTLINER(sov) ((sov->search_flags & SO_SEARCH_RECURSIVE) && (sov->filter & SO_FILTER_SEARCH)) /* is the currrent element open? if so we also show children */ #define TSELEM_OPEN(telm, sv) ( (telm->flag & TSE_CLOSED) == 0 || (SEARCHING_OUTLINER(sv) && (telm->flag & TSE_CHILDSEARCH)) ) /* outliner_tree.c ----------------------------------------------- */ -void outliner_free_tree(ListBase *lb); +void outliner_free_tree(ListBase *tree); void outliner_cleanup_tree(struct SpaceOops *soops); +void outliner_free_tree_element(TreeElement *element, ListBase *parent_subtree); void outliner_remove_treestore_element(struct SpaceOops *soops, TreeStoreElem *tselem); -void outliner_build_tree(struct Main *mainvar, struct Scene *scene, struct ViewLayer *view_layer, struct SpaceOops *soops); +void outliner_build_tree(struct Main *mainvar, struct Scene *scene, struct ViewLayer *view_layer, + struct SpaceOops *soops, struct ARegion *ar); /* outliner_draw.c ---------------------------------------------- */ @@ -203,6 +213,10 @@ int outliner_item_do_activate_from_cursor( struct bContext *C, const int mval[2], bool extend, bool recursive); +void outliner_item_select( + struct SpaceOops *soops, const struct TreeElement *te, + const bool extend, const bool toggle); + /* outliner_edit.c ---------------------------------------------- */ typedef void (*outliner_operation_cb)( struct bContext *C, struct ReportList *, struct Scene *scene, @@ -260,6 +274,8 @@ void id_remap_cb( TreeElement *outliner_dropzone_find(const struct SpaceOops *soops, const float fmval[2], const bool children); +void outliner_set_coordinates(struct ARegion *ar, struct SpaceOops *soops); + /* ...................................................... */ void OUTLINER_OT_highlight_update(struct wmOperatorType *ot); @@ -328,11 +344,11 @@ void OUTLINER_OT_collection_toggle(struct wmOperatorType *ot); void OUTLINER_OT_collection_link(struct wmOperatorType *ot); void OUTLINER_OT_collection_unlink(struct wmOperatorType *ot); void OUTLINER_OT_collection_new(struct wmOperatorType *ot); -void OUTLINER_OT_collection_override_new(struct wmOperatorType *ot); -void OUTLINER_OT_collection_objects_add(struct wmOperatorType *ot); void OUTLINER_OT_collection_objects_remove(struct wmOperatorType *ot); -void OUTLINER_OT_collection_objects_select(struct wmOperatorType *ot); -void OUTLINER_OT_collection_objects_deselect(struct wmOperatorType *ot); + +void OUTLINER_OT_collection_objects_add(struct wmOperatorType *ot); +void OUTLINER_OT_collection_nested_new(struct wmOperatorType *ot); +void OUTLINER_OT_collection_delete_selected(struct wmOperatorType *ot); /* outliner_utils.c ---------------------------------------------- */ diff --git a/source/blender/editors/space_outliner/outliner_ops.c b/source/blender/editors/space_outliner/outliner_ops.c index 856dd022c14..52f27b9708e 100644 --- a/source/blender/editors/space_outliner/outliner_ops.c +++ b/source/blender/editors/space_outliner/outliner_ops.c @@ -33,9 +33,13 @@ #include "BLI_listbase.h" #include "BLI_math.h" +#include "BLT_translation.h" + #include "BKE_context.h" #include "BKE_main.h" +#include "GPU_immediate.h" + #include "RNA_access.h" #include "UI_interface.h" @@ -48,6 +52,11 @@ #include "outliner_intern.h" +typedef struct OutlinerDragDropTooltip { + TreeElement *te; + void *handle; +} OutlinerDragDropTooltip; + enum { OUTLINER_ITEM_DRAG_CANCEL, OUTLINER_ITEM_DRAG_CONFIRM, @@ -58,7 +67,7 @@ static int outliner_item_drag_drop_poll(bContext *C) SpaceOops *soops = CTX_wm_space_outliner(C); return ED_operator_outliner_active(C) && /* Only collection display modes supported for now. Others need more design work */ - ELEM(soops->outlinevis, SO_ACT_LAYER, SO_COLLECTIONS, SO_GROUPS); + ELEM(soops->outlinevis, SO_VIEW_LAYER, SO_COLLECTIONS, SO_GROUPS); } static TreeElement *outliner_item_drag_element_find(SpaceOops *soops, ARegion *ar, const wmEvent *event) @@ -69,9 +78,15 @@ static TreeElement *outliner_item_drag_element_find(SpaceOops *soops, ARegion *a return outliner_find_item_at_y(soops, &soops->tree, my); } -static void outliner_item_drag_end(TreeElement *dragged_te) +static void outliner_item_drag_end(wmWindow *win, OutlinerDragDropTooltip *data) { - MEM_SAFE_FREE(dragged_te->drag_data); + MEM_SAFE_FREE(data->te->drag_data); + + if (data->handle) { + WM_draw_cb_exit(win, data->handle); + } + + MEM_SAFE_FREE(data); } static void outliner_item_drag_get_insert_data( @@ -164,8 +179,35 @@ static void outliner_item_drag_handle( te_dragged->drag_data->insert_handle = te_insert_handle; } -static bool outliner_item_drag_drop_apply(Main *bmain, TreeElement *dragged_te) +/** + * Returns true if it is a collection and empty. + */ +static bool is_empty_collection(TreeElement *te) +{ + if (!ELEM(TREESTORE(te)->type, TSE_SCENE_COLLECTION, TSE_LAYER_COLLECTION)) { + return false; + } + + SceneCollection *scene_collection; + if (TREESTORE(te)->type == TSE_SCENE_COLLECTION) { + scene_collection = (SceneCollection *)te->directdata; + } + else { + BLI_assert(TREESTORE(te)->type == TSE_LAYER_COLLECTION); + scene_collection = ((LayerCollection *)te->directdata)->scene_collection; + } + + return BLI_listbase_is_empty(&scene_collection->objects) && + BLI_listbase_is_empty(&scene_collection->scene_collections); +} + +static bool outliner_item_drag_drop_apply( + Main *bmain, + SpaceOops *soops, + OutlinerDragDropTooltip *data, + const wmEvent *event) { + TreeElement *dragged_te = data->te; TreeElement *insert_handle = dragged_te->drag_data->insert_handle; TreeElementInsertType insert_type = dragged_te->drag_data->insert_type; @@ -178,7 +220,16 @@ static bool outliner_item_drag_drop_apply(Main *bmain, TreeElement *dragged_te) /* call of assert above should not have changed insert_handle and insert_type at this point */ BLI_assert(dragged_te->drag_data->insert_handle == insert_handle && dragged_te->drag_data->insert_type == insert_type); - dragged_te->reinsert(bmain, dragged_te, insert_handle, insert_type); + + /* If the collection was just created and you moved objects/collections inside it, + * it is strange to have it closed and we not see the newly dragged elements. */ + const bool should_open_collection = (insert_type == TE_INSERT_INTO) && is_empty_collection(insert_handle); + + dragged_te->reinsert(bmain, soops, dragged_te, insert_handle, insert_type, event); + + if (should_open_collection && !is_empty_collection(insert_handle)) { + TREESTORE(insert_handle)->flag &= ~TSE_CLOSED; + } return true; } @@ -190,7 +241,8 @@ static int outliner_item_drag_drop_modal(bContext *C, wmOperator *op, const wmEv Main *bmain = CTX_data_main(C); ARegion *ar = CTX_wm_region(C); SpaceOops *soops = CTX_wm_space_outliner(C); - TreeElement *te_dragged = op->customdata; + OutlinerDragDropTooltip *data = op->customdata; + TreeElement *te_dragged = data->te; int retval = OPERATOR_RUNNING_MODAL; bool redraw = false; bool skip_rebuild = true; @@ -198,7 +250,7 @@ static int outliner_item_drag_drop_modal(bContext *C, wmOperator *op, const wmEv switch (event->type) { case EVT_MODAL_MAP: if (event->val == OUTLINER_ITEM_DRAG_CONFIRM) { - if (outliner_item_drag_drop_apply(bmain, te_dragged)) { + if (outliner_item_drag_drop_apply(bmain, soops, data, event)) { skip_rebuild = false; } retval = OPERATOR_FINISHED; @@ -210,7 +262,7 @@ static int outliner_item_drag_drop_modal(bContext *C, wmOperator *op, const wmEv BLI_assert(0); } WM_event_add_mousemove(C); /* update highlight */ - outliner_item_drag_end(te_dragged); + outliner_item_drag_end(CTX_wm_window(C), data); redraw = true; break; case MOUSEMOVE: @@ -229,6 +281,93 @@ static int outliner_item_drag_drop_modal(bContext *C, wmOperator *op, const wmEv return retval; } +/** + * Check if the given TreeElement is a collection + * + * This test is mainly used to see if next/prev TreeElement is a collection. + * It will fail when there is no next/prev TreeElement, or when the + * element is an Override or something else in the future. + */ +static bool tree_element_is_collection_get(const TreeElement *te) { + if (te == NULL) { + return false; + } + + TreeStoreElem *tselem = TREESTORE(te); + return ELEM(tselem->type, TSE_LAYER_COLLECTION, TSE_SCENE_COLLECTION); +} + +static const char *outliner_drag_drop_tooltip_get( + const TreeElement *te_float) +{ + const char *name = NULL; + + const TreeElement *te_insert = te_float->drag_data->insert_handle; + if (tree_element_is_collection_get(te_float)) { + if (te_insert == NULL) { + name = TIP_("Move collection"); + } + else { + switch (te_float->drag_data->insert_type) { + case TE_INSERT_BEFORE: + if (tree_element_is_collection_get(te_insert->prev)) { + name = TIP_("Move between collections"); + } + else { + name = TIP_("Move before collection"); + } + break; + case TE_INSERT_AFTER: + if (tree_element_is_collection_get(te_insert->next)) { + name = TIP_("Move between collections"); + } + else { + name = TIP_("Move after collection"); + } + break; + case TE_INSERT_INTO: + name = TIP_("Move inside collection"); + break; + } + } + } + else if ((TREESTORE(te_float)->type == 0) && (te_float->idcode == ID_OB)) { + name = TIP_("Move to collection (Ctrl to add)"); + } + + return name; +} + +static void outliner_drag_drop_tooltip_cb(const wmWindow *win, void *vdata) +{ + OutlinerDragDropTooltip *data = vdata; + const char *tooltip; + + int cursorx, cursory; + int x, y; + + tooltip = outliner_drag_drop_tooltip_get(data->te); + if (tooltip == NULL) { + return; + } + + cursorx = win->eventstate->x; + cursory = win->eventstate->y; + + x = cursorx + U.widget_unit; + y = cursory - U.widget_unit; + + /* Drawing. */ + const uiFontStyle *fstyle = UI_FSTYLE_WIDGET; + + const float col_fg[4] = {1.0f, 1.0f, 1.0f, 1.0f}; + const float col_bg[4] = {0.0f, 0.0f, 0.0f, 0.2f}; + + glEnable(GL_BLEND); + UI_fontstyle_draw_simple_backdrop(fstyle, x, y, tooltip, col_fg, col_bg); + glDisable(GL_BLEND); +} + static int outliner_item_drag_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event) { ARegion *ar = CTX_wm_region(C); @@ -239,7 +378,10 @@ static int outliner_item_drag_drop_invoke(bContext *C, wmOperator *op, const wmE return (OPERATOR_FINISHED | OPERATOR_PASS_THROUGH); } - op->customdata = te_dragged; + OutlinerDragDropTooltip *data = MEM_mallocN(sizeof(OutlinerDragDropTooltip), __func__); + data->te = te_dragged; + + op->customdata = data; te_dragged->drag_data = MEM_callocN(sizeof(*te_dragged->drag_data), __func__); /* by default we don't change the item position */ te_dragged->drag_data->insert_handle = te_dragged; @@ -251,6 +393,8 @@ static int outliner_item_drag_drop_invoke(bContext *C, wmOperator *op, const wmE WM_event_add_modal_handler(C, op); + data->handle = WM_draw_cb_activate(CTX_wm_window(C), outliner_drag_drop_tooltip_cb, data); + return OPERATOR_RUNNING_MODAL; } @@ -330,11 +474,11 @@ void outliner_operatortypes(void) WM_operatortype_append(OUTLINER_OT_collection_link); WM_operatortype_append(OUTLINER_OT_collection_unlink); WM_operatortype_append(OUTLINER_OT_collection_new); - WM_operatortype_append(OUTLINER_OT_collection_override_new); + + WM_operatortype_append(OUTLINER_OT_collection_nested_new); + WM_operatortype_append(OUTLINER_OT_collection_delete_selected); WM_operatortype_append(OUTLINER_OT_collection_objects_add); WM_operatortype_append(OUTLINER_OT_collection_objects_remove); - WM_operatortype_append(OUTLINER_OT_collection_objects_select); - WM_operatortype_append(OUTLINER_OT_collection_objects_deselect); } static wmKeyMap *outliner_item_drag_drop_modal_keymap(wmKeyConfig *keyconf) @@ -432,6 +576,9 @@ void outliner_keymap(wmKeyConfig *keyconf) WM_keymap_verify_item(keymap, "OUTLINER_OT_drivers_add_selected", DKEY, KM_PRESS, 0, 0); WM_keymap_verify_item(keymap, "OUTLINER_OT_drivers_delete_selected", DKEY, KM_PRESS, KM_ALT, 0); + WM_keymap_verify_item(keymap, "OUTLINER_OT_collection_nested_new", CKEY, KM_PRESS, 0, 0); + WM_keymap_verify_item(keymap, "OUTLINER_OT_collection_delete_selected", XKEY, KM_PRESS, 0, 0); + outliner_item_drag_drop_modal_keymap(keyconf); } diff --git a/source/blender/editors/space_outliner/outliner_select.c b/source/blender/editors/space_outliner/outliner_select.c index 08b5f337936..b9222e62bb0 100644 --- a/source/blender/editors/space_outliner/outliner_select.c +++ b/source/blender/editors/space_outliner/outliner_select.c @@ -97,8 +97,8 @@ static eOLDrawState tree_element_active_renderlayer( /** * Select object tree: - * CTRL+LMB: Select/Deselect object and all cildren - * CTRL+SHIFT+LMB: Add/Remove object and all children + * CTRL+LMB: Select/Deselect object and all children. + * CTRL+SHIFT+LMB: Add/Remove object and all children. */ static void do_outliner_object_select_recursive(ViewLayer *view_layer, Object *ob_parent, bool select) { @@ -185,7 +185,7 @@ static eOLDrawState tree_element_set_active_object( if (recursive) { /* Recursive select/deselect for Object hierarchies */ - do_outliner_object_select_recursive(view_layer, ob, (ob->flag & SELECT) != 0); + do_outliner_object_select_recursive(view_layer, ob, (base->flag & BASE_SELECTED) != 0); } if (set != OL_SETSEL_NONE) { @@ -973,7 +973,7 @@ static void do_outliner_item_activate_tree_element( * \param extend: Don't deselect other items, only modify \a te. * \param toggle: Select \a te when not selected, deselect when selected. */ -static void outliner_item_select(SpaceOops *soops, const TreeElement *te, const bool extend, const bool toggle) +void outliner_item_select(SpaceOops *soops, const TreeElement *te, const bool extend, const bool toggle) { TreeStoreElem *tselem = TREESTORE(te); const short new_flag = toggle ? (tselem->flag ^ TSE_SELECTED) : (tselem->flag | TSE_SELECTED); @@ -1005,7 +1005,7 @@ static bool outliner_item_is_co_within_close_toggle(TreeElement *te, float view_ static bool outliner_is_co_within_restrict_columns(const SpaceOops *soops, const ARegion *ar, float view_co_x) { - return (!ELEM(soops->outlinevis, SO_DATABLOCKS, SO_USERDEF) && + return ((soops->outlinevis != SO_DATABLOCKS) && !(soops->flag & SO_HIDE_RESTRICTCOLS) && (view_co_x > ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX)); } diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c index 99fd539293f..9f0165d1272 100644 --- a/source/blender/editors/space_outliner/outliner_tools.c +++ b/source/blender/editors/space_outliner/outliner_tools.c @@ -57,6 +57,7 @@ #include "BKE_group.h" #include "BKE_layer.h" #include "BKE_library.h" +#include "BKE_library_override.h" #include "BKE_library_query.h" #include "BKE_library_remap.h" #include "BKE_main.h" @@ -454,6 +455,19 @@ static void id_local_cb( } } +static void id_static_override_cb( + bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te), + TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) +{ + if (ID_IS_LINKED(tselem->id) && (tselem->id->tag & LIB_TAG_EXTERN)) { + Main *bmain = CTX_data_main(C); + ID *override_id = BKE_override_static_create_from_id(bmain, tselem->id); + if (override_id != NULL) { + BKE_main_id_clear_newpoins(bmain); + } + } +} + static void id_fake_user_set_cb( bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te), TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) @@ -1002,9 +1016,6 @@ static const EnumPropertyItem prop_object_op_types[] = { {OL_OP_DELETE_HIERARCHY, "DELETE_HIERARCHY", 0, "Delete Hierarchy", ""}, {OL_OP_REMAP, "REMAP", 0, "Remap Users", "Make all users of selected data-blocks to use instead a new chosen one"}, - {OL_OP_TOGVIS, "TOGVIS", 0, "Toggle Visible", ""}, - {OL_OP_TOGSEL, "TOGSEL", 0, "Toggle Selectable", ""}, - {OL_OP_TOGREN, "TOGREN", 0, "Toggle Renderable", ""}, {OL_OP_RENAME, "RENAME", 0, "Rename", ""}, {0, NULL, 0, NULL, NULL} }; @@ -1117,6 +1128,7 @@ void OUTLINER_OT_object_operation(wmOperatorType *ot) typedef enum eOutliner_PropGroupOps { OL_GROUPOP_UNLINK = 1, OL_GROUPOP_LOCAL, + OL_GROUPOP_STATIC_OVERRIDE, OL_GROUPOP_LINK, OL_GROUPOP_DELETE, OL_GROUPOP_REMAP, @@ -1130,6 +1142,8 @@ typedef enum eOutliner_PropGroupOps { static const EnumPropertyItem prop_group_op_types[] = { {OL_GROUPOP_UNLINK, "UNLINK", 0, "Unlink Group", ""}, {OL_GROUPOP_LOCAL, "LOCAL", 0, "Make Local Group", ""}, + {OL_GROUPOP_STATIC_OVERRIDE, "STATIC_OVERRIDE", + 0, "Add Static Override", "Add a local static override of that group"}, {OL_GROUPOP_LINK, "LINK", 0, "Link Group Objects to Scene", ""}, {OL_GROUPOP_DELETE, "DELETE", 0, "Delete Group", ""}, {OL_GROUPOP_REMAP, "REMAP", 0, "Remap Users", @@ -1161,6 +1175,9 @@ static int outliner_group_operation_exec(bContext *C, wmOperator *op) case OL_GROUPOP_LOCAL: outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_local_cb, NULL); break; + case OL_GROUPOP_STATIC_OVERRIDE: + outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_static_override_cb, NULL); + break; case OL_GROUPOP_LINK: outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, group_linkobs2scene_cb, NULL); break; @@ -1213,6 +1230,7 @@ typedef enum eOutlinerIdOpTypes { OUTLINER_IDOP_UNLINK, OUTLINER_IDOP_LOCAL, + OUTLINER_IDOP_STATIC_OVERRIDE, OUTLINER_IDOP_SINGLE, OUTLINER_IDOP_DELETE, OUTLINER_IDOP_REMAP, @@ -1228,6 +1246,8 @@ typedef enum eOutlinerIdOpTypes { static const EnumPropertyItem prop_id_op_types[] = { {OUTLINER_IDOP_UNLINK, "UNLINK", 0, "Unlink", ""}, {OUTLINER_IDOP_LOCAL, "LOCAL", 0, "Make Local", ""}, + {OUTLINER_IDOP_STATIC_OVERRIDE, "STATIC_OVERRIDE", + 0, "Add Static Override", "Add a local static override of this data-block"}, {OUTLINER_IDOP_SINGLE, "SINGLE", 0, "Make Single User", ""}, {OUTLINER_IDOP_DELETE, "DELETE", 0, "Delete", "WARNING: no undo"}, {OUTLINER_IDOP_REMAP, "REMAP", 0, "Remap Users", @@ -1297,6 +1317,13 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op) ED_undo_push(C, "Localized Data"); break; } + case OUTLINER_IDOP_STATIC_OVERRIDE: + { + /* make local */ + outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_static_override_cb, NULL); + ED_undo_push(C, "Overrided Data"); + break; + } case OUTLINER_IDOP_SINGLE: { /* make single user */ @@ -1841,7 +1868,7 @@ static const EnumPropertyItem *outliner_collection_operation_type_itemf( switch (soops->outlinevis) { case SO_GROUPS: return prop_collection_op_group_internal_types; - case SO_ACT_LAYER: + case SO_VIEW_LAYER: return prop_collection_op_none_types; } return NULL; @@ -2021,7 +2048,7 @@ static int do_outliner_operation_event(bContext *C, ARegion *ar, SpaceOops *soop } } else if (objectlevel) { - WM_operator_name_call(C, "OUTLINER_OT_object_operation", WM_OP_INVOKE_REGION_WIN, NULL); + WM_menu_name_call(C, "OUTLINER_MT_context_object", WM_OP_INVOKE_REGION_WIN); } else if (idlevel) { if (idlevel == -1 || datalevel) { @@ -2066,6 +2093,9 @@ static int do_outliner_operation_event(bContext *C, ARegion *ar, SpaceOops *soop else if (datalevel == TSE_LAYER_COLLECTION) { WM_operator_name_call(C, "OUTLINER_OT_collection_operation", WM_OP_INVOKE_REGION_WIN, NULL); } + else if (datalevel == TSE_SCENE_COLLECTION) { + WM_menu_name_call(C, "OUTLINER_MT_context_scene_collection", WM_OP_INVOKE_REGION_WIN); + } else { WM_operator_name_call(C, "OUTLINER_OT_data_operation", WM_OP_INVOKE_REGION_WIN, NULL); } diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c index a9c9ab74970..06b3319935d 100644 --- a/source/blender/editors/space_outliner/outliner_tree.c +++ b/source/blender/editors/space_outliner/outliner_tree.c @@ -71,6 +71,7 @@ #include "BKE_idcode.h" #include "BKE_outliner_treehash.h" +#include "DEG_depsgraph.h" #include "DEG_depsgraph_build.h" #include "ED_armature.h" @@ -81,6 +82,8 @@ #include "RNA_access.h" +#include "UI_interface.h" + #include "outliner_intern.h" #ifdef WIN32 @@ -89,7 +92,11 @@ /* prototypes */ static void outliner_add_layer_collections_recursive( - SpaceOops *soops, ListBase *tree, ID *id, ListBase *layer_collections, TreeElement *parent_ten); + SpaceOops *soops, ListBase *tree, ID *id, ListBase *layer_collections, TreeElement *parent_ten, + const bool show_objects); +static void outliner_add_view_layer( + SpaceOops *soops, ListBase *tree, TreeElement *parent, + Scene *scene, ViewLayer *layer, const bool show_objects); static void outliner_make_hierarchy(ListBase *lb); /* ********************************************************* */ @@ -189,16 +196,11 @@ static void check_persistent(SpaceOops *soops, TreeElement *te, ID *id, short ty /* ********************************************************* */ /* Tree Management */ -void outliner_free_tree(ListBase *lb) +void outliner_free_tree(ListBase *tree) { - while (lb->first) { - TreeElement *te = lb->first; - - outliner_free_tree(&te->subtree); - BLI_remlink(lb, te); - - if (te->flag & TE_FREE_NAME) MEM_freeN((void *)te->name); - MEM_freeN(te); + for (TreeElement *element = tree->first, *element_next; element; element = element_next) { + element_next = element->next; + outliner_free_tree_element(element, tree); } } @@ -208,6 +210,25 @@ void outliner_cleanup_tree(SpaceOops *soops) outliner_storage_cleanup(soops); } +/** + * Free \a element and its sub-tree and remove its link in \a parent_subtree. + * + * \note Does not remove the TreeStoreElem of \a element! + * \param parent_subtree Subtree of the parent element, so the list containing \a element. + */ +void outliner_free_tree_element(TreeElement *element, ListBase *parent_subtree) +{ + BLI_assert(BLI_findindex(parent_subtree, element) > -1); + BLI_remlink(parent_subtree, element); + + outliner_free_tree(&element->subtree); + + if (element->flag & TE_FREE_NAME) { + MEM_freeN((void *)element->name); + } + MEM_freeN(element); +} + /* ********************************************************* */ @@ -365,12 +386,21 @@ static void outliner_add_scene_contents(SpaceOops *soops, ListBase *lb, Scene *s TreeElement *tenla = outliner_add_element(soops, lb, sce, te, TSE_R_LAYER_BASE, 0); int a; - tenla->name = IFACE_("RenderLayers"); + tenla->name = IFACE_("View Layers"); for (a = 0, view_layer = sce->view_layers.first; view_layer; view_layer = view_layer->next, a++) { TreeElement *tenlay = outliner_add_element(soops, &tenla->subtree, sce, te, TSE_R_LAYER, a); tenlay->name = view_layer->name; tenlay->directdata = &view_layer->flag; - outliner_add_passes(soops, tenlay, &sce->id, view_layer); + + TreeElement *te_view_layers; + te_view_layers = outliner_add_element(soops, &tenlay->subtree, sce, tenlay, TSE_LAYER_COLLECTION_BASE, 0); + te_view_layers->name = IFACE_("Collections"); + outliner_add_view_layer(soops, &te_view_layers->subtree, te_view_layers, sce, view_layer, false); + + TreeElement *te_passes; + te_passes = outliner_add_element(soops, &tenlay->subtree, sce, tenlay, TSE_LAYER_COLLECTION_BASE, 0); + te_passes->name = IFACE_("Passes"); + outliner_add_passes(soops, te_passes, &sce->id, view_layer); } // TODO: move this to the front? @@ -379,20 +409,45 @@ static void outliner_add_scene_contents(SpaceOops *soops, ListBase *lb, Scene *s outliner_add_element(soops, lb, sce->gpd, te, 0, 0); - outliner_add_element(soops, lb, sce->world, te, 0, 0); - #ifdef WITH_FREESTYLE if (STREQ(sce->view_render->engine_id, RE_engine_id_BLENDER_RENDER) && (sce->r.mode & R_EDGE_FRS)) outliner_add_line_styles(soops, lb, sce, te); #endif } +struct ObjectsSelectedData { + ListBase objects_selected_array; +}; + +static TreeTraversalAction outliner_find_selected_objects(TreeElement *te, void *customdata) +{ + struct ObjectsSelectedData *data = customdata; + TreeStoreElem *tselem = TREESTORE(te); + + if (ELEM(tselem->type, TSE_LAYER_COLLECTION, TSE_SCENE_COLLECTION)) { + return TRAVERSE_CONTINUE; + } + + if (tselem->type || (tselem->id == NULL) || (GS(tselem->id->name) != ID_OB)) { + return TRAVERSE_SKIP_CHILDS; + } + + BLI_addtail(&data->objects_selected_array, BLI_genericNodeN(te)); + + return TRAVERSE_CONTINUE; +} + +/** + * Move objects from a collection to another. + * We ignore the original object being inserted, we used it for polling only. + * Instead we move all the selected objects around. + */ static void outliner_object_reorder( - Main *UNUSED(bmain), - TreeElement *insert_element, TreeElement *insert_handle, TreeElementInsertType action) + Main *bmain, SpaceOops *soops, + TreeElement *insert_element, + TreeElement *insert_handle, TreeElementInsertType action, + const wmEvent *event) { - TreeStoreElem *tselem_insert = TREESTORE(insert_element); - Object *ob = (Object *)tselem_insert->id; SceneCollection *sc = outliner_scene_collection_from_tree_element(insert_handle); SceneCollection *sc_ob_parent = NULL; ID *id = insert_handle->store_elem->id; @@ -400,19 +455,49 @@ static void outliner_object_reorder( BLI_assert(action == TE_INSERT_INTO); UNUSED_VARS_NDEBUG(action); - /* find parent scene-collection of object */ - if (insert_element->parent) { - for (TreeElement *te_ob_parent = insert_element->parent; te_ob_parent; te_ob_parent = te_ob_parent->parent) { - if (ELEM(TREESTORE(te_ob_parent)->type, TSE_SCENE_COLLECTION, TSE_LAYER_COLLECTION)) { - sc_ob_parent = outliner_scene_collection_from_tree_element(te_ob_parent); - break; + struct ObjectsSelectedData data = { + .objects_selected_array = {NULL, NULL}, + }; + + const bool is_append = event->ctrl; + + /* Make sure we include the originally inserted element as well. */ + TREESTORE(insert_element)->flag |= TSE_SELECTED; + + outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, outliner_find_selected_objects, &data); + BLI_LISTBASE_FOREACH (LinkData *, link, &data.objects_selected_array) { + TreeElement *ten_selected = (TreeElement *)link->data; + Object *ob = (Object *)TREESTORE(ten_selected)->id; + + if (is_append) { + BKE_collection_object_add(id, sc, ob); + continue; + } + + /* Find parent scene-collection of object. */ + if (ten_selected->parent) { + for (TreeElement *te_ob_parent = ten_selected->parent; te_ob_parent; te_ob_parent = te_ob_parent->parent) { + if (ELEM(TREESTORE(te_ob_parent)->type, TSE_SCENE_COLLECTION, TSE_LAYER_COLLECTION)) { + sc_ob_parent = outliner_scene_collection_from_tree_element(te_ob_parent); + break; + } } } + else { + sc_ob_parent = BKE_collection_master(id); + } + + BKE_collection_object_move(id, sc, sc_ob_parent, ob); } - else { - sc_ob_parent = BKE_collection_master(id); - } - BKE_collection_object_move(id, sc, sc_ob_parent, ob); + + BLI_freelistN(&data.objects_selected_array); + + DEG_relations_tag_update(bmain); + + /* TODO(sergey): Use proper flag for tagging here. */ + DEG_id_tag_update(id, 0); + + WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL); } static bool outliner_object_reorder_poll( @@ -1202,9 +1287,9 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i te->flag |= TE_LAZY_CLOSED; } - if ((type != TSE_LAYER_COLLECTION) && GS(id->name) == ID_GR) { + if ((type != TSE_LAYER_COLLECTION) && (te->idcode == ID_GR)) { Group *group = (Group *)id; - outliner_add_layer_collections_recursive(soops, &te->subtree, id, &group->view_layer->layer_collections, NULL); + outliner_add_layer_collections_recursive(soops, &te->subtree, id, &group->view_layer->layer_collections, NULL, true); } return te; @@ -1358,7 +1443,9 @@ static void outliner_add_orphaned_datablocks(Main *mainvar, SpaceOops *soops) static void outliner_layer_collections_reorder( Main *bmain, - TreeElement *insert_element, TreeElement *insert_handle, TreeElementInsertType action) + SpaceOops *UNUSED(soops), + TreeElement *insert_element, TreeElement *insert_handle, TreeElementInsertType action, + const wmEvent *UNUSED(event)) { LayerCollection *lc_insert = insert_element->directdata; LayerCollection *lc_handle = insert_handle->directdata; @@ -1393,7 +1480,8 @@ static bool outliner_layer_collections_reorder_poll( } static void outliner_add_layer_collections_recursive( - SpaceOops *soops, ListBase *tree, ID *id, ListBase *layer_collections, TreeElement *parent_ten) + SpaceOops *soops, ListBase *tree, ID *id, ListBase *layer_collections, TreeElement *parent_ten, + const bool show_objects) { for (LayerCollection *collection = layer_collections->first; collection; collection = collection->next) { TreeElement *ten = outliner_add_element(soops, tree, id, parent_ten, TSE_LAYER_COLLECTION, 0); @@ -1403,23 +1491,29 @@ static void outliner_add_layer_collections_recursive( ten->reinsert = outliner_layer_collections_reorder; ten->reinsert_poll = outliner_layer_collections_reorder_poll; - outliner_add_layer_collections_recursive(soops, &ten->subtree, id, &collection->layer_collections, ten); - for (LinkData *link = collection->object_bases.first; link; link = link->next) { - Base *base = (Base *)link->data; - TreeElement *te_object = outliner_add_element(soops, &ten->subtree, base->object, ten, 0, 0); - te_object->directdata = base; + outliner_add_layer_collections_recursive(soops, &ten->subtree, id, &collection->layer_collections, ten, show_objects); + if (show_objects) { + for (LinkData *link = collection->object_bases.first; link; link = link->next) { + Base *base = (Base *)link->data; + TreeElement *te_object = outliner_add_element(soops, &ten->subtree, base->object, ten, 0, 0); + te_object->directdata = base; + } } outliner_make_hierarchy(&ten->subtree); } } -static void outliner_add_collections_act_layer(SpaceOops *soops, Scene *scene, ViewLayer *layer) + +static void outliner_add_view_layer(SpaceOops *soops, ListBase *tree, TreeElement *parent, + Scene *scene, ViewLayer *layer, const bool show_objects) { - outliner_add_layer_collections_recursive(soops, &soops->tree, &scene->id, &layer->layer_collections, NULL); + outliner_add_layer_collections_recursive(soops, tree, &scene->id, &layer->layer_collections, parent, show_objects); } static void outliner_scene_collections_reorder( Main *bmain, - TreeElement *insert_element, TreeElement *insert_handle, TreeElementInsertType action) + SpaceOops *UNUSED(soops), + TreeElement *insert_element, TreeElement *insert_handle, TreeElementInsertType action, + const wmEvent *UNUSED(event)) { SceneCollection *sc_insert = insert_element->directdata; SceneCollection *sc_handle = insert_handle->directdata; @@ -1474,35 +1568,46 @@ static bool outliner_scene_collections_reorder_poll( return true; } -static void outliner_add_scene_collection_objects( +BLI_INLINE void outliner_add_scene_collection_init(TreeElement *te, SceneCollection *collection) +{ + te->name = collection->name; + te->directdata = collection; + te->reinsert = outliner_scene_collections_reorder; + te->reinsert_poll = outliner_scene_collections_reorder_poll; +} + +BLI_INLINE void outliner_add_scene_collection_objects( SpaceOops *soops, ListBase *tree, SceneCollection *collection, TreeElement *parent) { for (LinkData *link = collection->objects.first; link; link = link->next) { outliner_add_element(soops, tree, link->data, parent, 0, 0); } - outliner_make_hierarchy(tree); } -static void outliner_add_scene_collections_recursive( - SpaceOops *soops, ListBase *tree, ListBase *scene_collections, TreeElement *parent_ten) +static TreeElement *outliner_add_scene_collection_recursive( + SpaceOops *soops, ListBase *tree, ID *id, SceneCollection *scene_collection, TreeElement *parent_ten) { - for (SceneCollection *collection = scene_collections->first; collection; collection = collection->next) { - TreeElement *ten = outliner_add_element(soops, tree, collection, parent_ten, TSE_SCENE_COLLECTION, 0); + TreeElement *ten = outliner_add_element(soops, tree, id, parent_ten, TSE_SCENE_COLLECTION, 0); + outliner_add_scene_collection_init(ten, scene_collection); + outliner_add_scene_collection_objects(soops, &ten->subtree, scene_collection, ten); - ten->name = collection->name; - ten->directdata = collection; - ten->reinsert = outliner_scene_collections_reorder; - ten->reinsert_poll = outliner_scene_collections_reorder_poll; - - outliner_add_scene_collections_recursive(soops, &ten->subtree, &collection->scene_collections, ten); - outliner_add_scene_collection_objects(soops, &ten->subtree, collection, ten); + for (SceneCollection *scene_collection_nested = scene_collection->scene_collections.first; + scene_collection_nested != NULL; + scene_collection_nested = scene_collection_nested->next) + { + outliner_add_scene_collection_recursive(soops, &ten->subtree, id, scene_collection_nested, ten); } + + outliner_make_hierarchy(&ten->subtree); + return ten; } -static void outliner_add_collections_master(SpaceOops *soops, Scene *scene) + +static void outliner_add_collections(SpaceOops *soops, Scene *scene) { - SceneCollection *master = BKE_collection_master(&scene->id); - outliner_add_scene_collections_recursive(soops, &soops->tree, &master->scene_collections, NULL); - outliner_add_scene_collection_objects(soops, &soops->tree, master, NULL); + SceneCollection *master_collection = BKE_collection_master(&scene->id); + TreeElement *ten = outliner_add_scene_collection_recursive(soops, &soops->tree, &scene->id, master_collection, NULL); + /* Master Collection should always be expanded. */ + TREESTORE(ten)->flag &= ~TSE_CLOSED; } /* ======================================================= */ @@ -1676,6 +1781,305 @@ static void outliner_sort(ListBase *lb) /* Filtering ----------------------------------------------- */ +typedef struct OutlinerTreeElementFocus { + TreeStoreElem *tselem; + int ys; +} OutlinerTreeElementFocus; + +/** + * Bring the outliner scrolling back to where it was in relation to the original focus element + * Caller is expected to handle redrawing of ARegion. + */ +static void outliner_restore_scrolling_position(SpaceOops *soops, ARegion *ar, OutlinerTreeElementFocus *focus) +{ + View2D *v2d = &ar->v2d; + int ytop; + + if (focus->tselem != NULL) { + outliner_set_coordinates(ar, soops); + + TreeElement *te_new = outliner_find_tree_element(&soops->tree, focus->tselem); + + if (te_new != NULL) { + int ys_new, ys_old; + + ys_new = te_new->ys; + ys_old = focus->ys; + + ytop = v2d->cur.ymax + (ys_new - ys_old) -1; + if (ytop > 0) ytop = 0; + + v2d->cur.ymax = (float)ytop; + v2d->cur.ymin = (float)(ytop - BLI_rcti_size_y(&v2d->mask)); + } + else { + return; + } + + soops->storeflag |= SO_TREESTORE_REDRAW; + } +} + +static bool test_collection_callback(TreeElement *te) +{ + TreeStoreElem *tselem = TREESTORE(te); + return ELEM(tselem->type, TSE_LAYER_COLLECTION, TSE_SCENE_COLLECTION); +} + +static bool test_object_callback(TreeElement *te) +{ + TreeStoreElem *tselem = TREESTORE(te); + return ((tselem->type == 0) && (te->idcode == ID_OB)); +} + +/** + * See if TreeElement or any of its children pass the callback_test. + */ +static TreeElement *outliner_find_first_desired_element_at_y_recursive( + const SpaceOops *soops, + TreeElement *te, + const float limit, + bool (*callback_test)(TreeElement *)) +{ + if (callback_test(te)) { + return te; + } + + if (TSELEM_OPEN(te->store_elem, soops)) { + TreeElement *te_iter, *te_sub; + for (te_iter = te->subtree.first; te_iter; te_iter = te_iter->next) { + te_sub = outliner_find_first_desired_element_at_y_recursive(soops, te_iter, limit, callback_test); + if (te_sub != NULL) { + return te_sub; + } + } + } + + return NULL; +} + +/** + * Find the first element that passes a test starting from a reference vertical coordinate + * + * If the element that is in the position is not what we are looking for, keep looking for its + * children, siblings, and eventually, aunts, cousins, disntant families, ... + * + * Basically we keep going up and down the outliner tree from that point forward, until we find + * what we are looking for. If we are past the visible range and we can't find a valid element + * we return NULL. + */ +static TreeElement *outliner_find_first_desired_element_at_y( + const SpaceOops *soops, + const float view_co, + const float view_co_limit) +{ + TreeElement *te, *te_sub; + te = outliner_find_item_at_y(soops, &soops->tree, view_co); + + bool (*callback_test)(TreeElement *); + if (soops->filter & SO_FILTER_NO_COLLECTION) { + callback_test = test_object_callback; + } + else { + callback_test = test_collection_callback; + } + + while (te != NULL) { + te_sub = outliner_find_first_desired_element_at_y_recursive(soops, te, view_co_limit, callback_test); + if (te_sub != NULL) { + /* Skip the element if it was not visible to start with. */ + if (te->ys + UI_UNIT_Y > view_co_limit) { + return te_sub; + } + else { + return NULL; + } + } + + if (te->next) { + te = te->next; + continue; + } + + if (te->parent == NULL) { + break; + } + + while (te->parent) { + if (te->parent->next) { + te = te->parent->next; + break; + } + te = te->parent; + } + } + + return NULL; +} + +/** + * Store information of current outliner scrolling status to be restored later + * + * Finds the top-most collection visible in the outliner and populates the OutlinerTreeElementFocus + * struct to retrieve this element later to make sure it is in the same original position as before filtering + */ +static void outliner_store_scrolling_position(SpaceOops *soops, ARegion *ar, OutlinerTreeElementFocus *focus) +{ + TreeElement *te; + float limit = ar->v2d.cur.ymin; + + outliner_set_coordinates(ar, soops); + + te = outliner_find_first_desired_element_at_y(soops, ar->v2d.cur.ymax, limit); + + if (te != NULL) { + focus->tselem = TREESTORE(te); + focus->ys = te->ys; + } + else { + focus->tselem = NULL; + } +} + +static int outliner_exclude_filter_get(SpaceOops *soops) +{ + int exclude_filter = soops->filter & ~(SO_FILTER_OB_STATE_VISIBLE | + SO_FILTER_OB_STATE_SELECTED | + SO_FILTER_OB_STATE_ACTIVE); + + if (soops->filter & SO_FILTER_SEARCH) { + if (soops->search_string[0] == 0) { + exclude_filter &= ~SO_FILTER_SEARCH; + } + } + + /* Let's have this for the collection options at first. */ + if (!SUPPORT_FILTER_OUTLINER(soops)) { + return (exclude_filter & SO_FILTER_SEARCH); + } + + if ((exclude_filter & SO_FILTER_NO_OB_ALL) == 0) { + exclude_filter &= ~SO_FILTER_OB_TYPE; + } + + if (exclude_filter & SO_FILTER_OB_STATE) { + switch (soops->filter_state) { + case SO_FILTER_OB_VISIBLE: + exclude_filter |= SO_FILTER_OB_STATE_VISIBLE; + break; + case SO_FILTER_OB_SELECTED: + exclude_filter |= SO_FILTER_OB_STATE_SELECTED; + break; + case SO_FILTER_OB_ACTIVE: + exclude_filter |= SO_FILTER_OB_STATE_ACTIVE; + break; + } + } + + if ((exclude_filter & SO_FILTER_ANY) == 0) { + exclude_filter &= ~(SO_FILTER_OB_STATE); + } + + return exclude_filter; +} + +static bool outliner_element_visible_get(ViewLayer *view_layer, TreeElement *te, const int exclude_filter) +{ + if ((exclude_filter & SO_FILTER_ENABLE) == 0) { + return true; + } + + TreeStoreElem *tselem = TREESTORE(te); + if ((tselem->type == 0) && (te->idcode == ID_OB)) { + if ((exclude_filter & SO_FILTER_NO_OBJECT)) { + return false; + } + + Object *ob = (Object *)tselem->id; + Base *base = (Base *)te->directdata; + BLI_assert((base == NULL) || (base->object == ob)); + + if (exclude_filter & SO_FILTER_OB_TYPE) { + switch (ob->type) { + case OB_MESH: + if (exclude_filter & SO_FILTER_NO_OB_MESH) { + return false; + } + break; + case OB_ARMATURE: + if (exclude_filter & SO_FILTER_NO_OB_ARMATURE) { + return false; + } + break; + case OB_EMPTY: + if (exclude_filter & SO_FILTER_NO_OB_EMPTY) { + return false; + } + break; + case OB_LAMP: + if (exclude_filter & SO_FILTER_NO_OB_LAMP) { + return false; + } + break; + case OB_CAMERA: + if (exclude_filter & SO_FILTER_NO_OB_CAMERA) { + return false; + } + break; + default: + if (exclude_filter & SO_FILTER_NO_OB_OTHERS) { + return false; + } + break; + } + } + + if (exclude_filter & SO_FILTER_OB_STATE) { + if (base == NULL) { + base = BKE_view_layer_base_find(view_layer, ob); + + if (base == NULL) { + return false; + } + } + + if (exclude_filter & SO_FILTER_OB_STATE_VISIBLE) { + if ((base->flag & BASE_VISIBLED) == 0) { + return false; + } + } + else if (exclude_filter & SO_FILTER_OB_STATE_SELECTED) { + if ((base->flag & BASE_SELECTED) == 0) { + return false; + } + } + else { + BLI_assert(exclude_filter & SO_FILTER_OB_STATE_ACTIVE); + if (base != BASACT(view_layer)) { + return false; + } + } + } + + if ((te->parent != NULL) && + (TREESTORE(te->parent)->type == 0) && (te->parent->idcode == ID_OB)) + { + if (exclude_filter & SO_FILTER_NO_CHILDREN) { + return false; + } + } + } + else if (te->parent != NULL && + TREESTORE(te->parent)->type == 0 && te->parent->idcode == ID_OB) + { + if (exclude_filter & SO_FILTER_NO_OB_CONTENT) { + return false; + } + } + + return true; +} + static bool outliner_filter_has_name(TreeElement *te, const char *name, int flags) { int fn_flag = 0; @@ -1686,31 +2090,25 @@ static bool outliner_filter_has_name(TreeElement *te, const char *name, int flag return fnmatch(name, te->name, fn_flag) == 0; } -static int outliner_filter_tree(SpaceOops *soops, ListBase *lb) +static int outliner_filter_subtree( + SpaceOops *soops, ViewLayer *view_layer, ListBase *lb, const char *search_string, const int exclude_filter) { - TreeElement *te, *ten; + TreeElement *te, *te_next; TreeStoreElem *tselem; - char search_buff[sizeof(((struct SpaceOops *)NULL)->search_string) + 2]; - char *search_string; - /* although we don't have any search string, we return true - * since the entire tree is ok then... - */ - if (soops->search_string[0] == 0) - return 1; + for (te = lb->first; te; te = te_next) { + te_next = te->next; - if (soops->search_flags & SO_FIND_COMPLETE) { - search_string = soops->search_string; - } - else { - /* Implicitly add heading/trailing wildcards if needed. */ - BLI_strncpy_ensure_pad(search_buff, soops->search_string, '*', sizeof(search_buff)); - search_string = search_buff; - } + if ((outliner_element_visible_get(view_layer, te, exclude_filter) == false)) { + outliner_free_tree_element(te, lb); + continue; + } + else if ((exclude_filter & SO_FILTER_SEARCH) == 0) { + /* Filter subtree too. */ + outliner_filter_subtree(soops, view_layer, &te->subtree, search_string, exclude_filter); + continue; + } - for (te = lb->first; te; te = ten) { - ten = te->next; - if (!outliner_filter_has_name(te, search_string, soops->search_flags)) { /* item isn't something we're looking for, but... * - if the subtree is expanded, check if there are any matches that can be easily found @@ -1719,39 +2117,60 @@ static int outliner_filter_tree(SpaceOops *soops, ListBase *lb) * so these can be safely ignored (i.e. the subtree can get freed) */ tselem = TREESTORE(te); - + /* flag as not a found item */ tselem->flag &= ~TSE_SEARCHMATCH; - if ((!TSELEM_OPEN(tselem, soops)) || outliner_filter_tree(soops, &te->subtree) == 0) { - outliner_free_tree(&te->subtree); - BLI_remlink(lb, te); - - if (te->flag & TE_FREE_NAME) MEM_freeN((void *)te->name); - MEM_freeN(te); + if ((!TSELEM_OPEN(tselem, soops)) || + outliner_filter_subtree(soops, view_layer, &te->subtree, search_string, exclude_filter) == 0) + { + outliner_free_tree_element(te, lb); } } else { tselem = TREESTORE(te); - + /* flag as a found item - we can then highlight it */ tselem->flag |= TSE_SEARCHMATCH; - + /* filter subtree too */ - outliner_filter_tree(soops, &te->subtree); + outliner_filter_subtree(soops, view_layer, &te->subtree, search_string, exclude_filter); } } - + /* if there are still items in the list, that means that there were still some matches */ return (BLI_listbase_is_empty(lb) == false); } +static void outliner_filter_tree(SpaceOops *soops, ViewLayer *view_layer) +{ + char search_buff[sizeof(((struct SpaceOops *)NULL)->search_string) + 2]; + char *search_string; + + const int exclude_filter = outliner_exclude_filter_get(soops); + + if (exclude_filter == 0) { + return; + } + + if (soops->search_flags & SO_FIND_COMPLETE) { + search_string = soops->search_string; + } + else { + /* Implicitly add heading/trailing wildcards if needed. */ + BLI_strncpy_ensure_pad(search_buff, soops->search_string, '*', sizeof(search_buff)); + search_string = search_buff; + } + + outliner_filter_subtree(soops, view_layer, &soops->tree, search_string, exclude_filter); +} + /* ======================================================= */ /* Main Tree Building API */ /* Main entry point for building the tree data-structure that the outliner represents */ // TODO: split each mode into its own function? -void outliner_build_tree(Main *mainvar, Scene *scene, ViewLayer *view_layer, SpaceOops *soops) +void outliner_build_tree(Main *mainvar, Scene *scene, ViewLayer *view_layer, SpaceOops *soops, ARegion *ar) { TreeElement *te = NULL, *ten; TreeStoreElem *tselem; @@ -1773,6 +2192,9 @@ void outliner_build_tree(Main *mainvar, Scene *scene, ViewLayer *view_layer, Spa if (soops->tree.first && (soops->storeflag & SO_TREESTORE_REDRAW)) return; + OutlinerTreeElementFocus focus; + outliner_store_scrolling_position(soops, ar, &focus); + outliner_free_tree(&soops->tree); outliner_storage_cleanup(soops); @@ -1826,51 +2248,19 @@ void outliner_build_tree(Main *mainvar, Scene *scene, ViewLayer *view_layer, Spa lib->id.newid = NULL; } - else if (soops->outlinevis == SO_ALL_SCENES) { + else if (soops->outlinevis == SO_SCENES) { Scene *sce; for (sce = mainvar->scene.first; sce; sce = sce->id.next) { te = outliner_add_element(soops, &soops->tree, sce, NULL, 0, 0); tselem = TREESTORE(te); - if (sce == scene && show_opened) - tselem->flag &= ~TSE_CLOSED; - FOREACH_SCENE_OBJECT(scene, ob) - { - outliner_add_element(soops, &te->subtree, ob, te, 0, 0); + if (sce == scene && show_opened) { + tselem->flag &= ~TSE_CLOSED; } - FOREACH_SCENE_OBJECT_END outliner_make_hierarchy(&te->subtree); - - /* clear id.newid, to prevent objects be inserted in wrong scenes (parent in other scene) */ - FOREACH_SCENE_OBJECT(scene, ob) - { - ob->id.newid = NULL; - } - FOREACH_SCENE_OBJECT_END } } - else if (soops->outlinevis == SO_CUR_SCENE) { - - outliner_add_scene_contents(soops, &soops->tree, scene, NULL); - - FOREACH_SCENE_OBJECT(scene, ob) - { - outliner_add_element(soops, &soops->tree, ob, NULL, 0, 0); - } - FOREACH_SCENE_OBJECT_END - outliner_make_hierarchy(&soops->tree); - } - else if (soops->outlinevis == SO_VISIBLE) { - FOREACH_VISIBLE_BASE(view_layer, base) - { - ten = outliner_add_element(soops, &soops->tree, base->object, NULL, 0, 0); - ten->directdata = base; - - } - FOREACH_VISIBLE_BASE_END - outliner_make_hierarchy(&soops->tree); - } else if (soops->outlinevis == SO_GROUPS) { Group *group; for (group = mainvar->group.first; group; group = group->id.next) { @@ -1878,28 +2268,6 @@ void outliner_build_tree(Main *mainvar, Scene *scene, ViewLayer *view_layer, Spa outliner_make_hierarchy(&te->subtree); } } - else if (soops->outlinevis == SO_SAME_TYPE) { - Object *ob_active = OBACT(view_layer); - if (ob_active) { - FOREACH_SCENE_OBJECT(scene, ob) - { - if (ob->type == ob_active->type) { - outliner_add_element(soops, &soops->tree, ob, NULL, 0, 0); - } - } - FOREACH_SCENE_OBJECT_END - outliner_make_hierarchy(&soops->tree); - } - } - else if (soops->outlinevis == SO_SELECTED) { - FOREACH_SELECTED_BASE(view_layer, base) - { - ten = outliner_add_element(soops, &soops->tree, base->object, NULL, 0, 0); - ten->directdata = base; - } - FOREACH_SELECTED_BASE_END - outliner_make_hierarchy(&soops->tree); - } else if (soops->outlinevis == SO_SEQUENCE) { Sequence *seq; Editing *ed = BKE_sequencer_editing_get(scene, false); @@ -1936,36 +2304,47 @@ void outliner_build_tree(Main *mainvar, Scene *scene, ViewLayer *view_layer, Spa tselem->flag &= ~TSE_CLOSED; } } - else if (soops->outlinevis == SO_USERDEF) { - PointerRNA userdefptr; - - RNA_pointer_create(NULL, &RNA_UserPreferences, &U, &userdefptr); - - ten = outliner_add_element(soops, &soops->tree, (void *)&userdefptr, NULL, TSE_RNA_STRUCT, -1); - - if (show_opened) { - tselem = TREESTORE(ten); - tselem->flag &= ~TSE_CLOSED; - } - } else if (soops->outlinevis == SO_ID_ORPHANS) { outliner_add_orphaned_datablocks(mainvar, soops); } - else if (soops->outlinevis == SO_ACT_LAYER) { - outliner_add_collections_act_layer(soops, scene, view_layer); + else if (soops->outlinevis == SO_VIEW_LAYER) { + if ((soops->filter & SO_FILTER_ENABLE) && (soops->filter & SO_FILTER_NO_COLLECTION)) { + for (Base *base = view_layer->object_bases.first; base; base = base->next) { + TreeElement *te_object = outliner_add_element(soops, &soops->tree, base->object, NULL, 0, 0); + te_object->directdata = base; + } + outliner_make_hierarchy(&soops->tree); + } + else { + outliner_add_view_layer(soops, &soops->tree, NULL, scene, view_layer, true); + } } else if (soops->outlinevis == SO_COLLECTIONS) { - outliner_add_collections_master(soops, scene); + if ((soops->filter & SO_FILTER_ENABLE) && (soops->filter & SO_FILTER_NO_COLLECTION)) { + FOREACH_SCENE_OBJECT(scene, ob) + { + outliner_add_element(soops, &soops->tree, ob, NULL, 0, 0); + } + FOREACH_SCENE_OBJECT_END + outliner_make_hierarchy(&soops->tree); + } + else { + outliner_add_collections(soops, scene); + } } else { - ten = outliner_add_element(soops, &soops->tree, OBACT(view_layer), NULL, 0, 0); - ten->directdata = BASACT(view_layer); + if (BASACT(view_layer)) { + ten = outliner_add_element(soops, &soops->tree, OBACT(view_layer), NULL, 0, 0); + ten->directdata = BASACT(view_layer); + } } if ((soops->flag & SO_SKIP_SORT_ALPHA) == 0) { outliner_sort(&soops->tree); } - outliner_filter_tree(soops, &soops->tree); + + outliner_filter_tree(soops, view_layer); + outliner_restore_scrolling_position(soops, ar, &focus); BKE_main_id_clear_newpoins(mainvar); } diff --git a/source/blender/editors/space_outliner/space_outliner.c b/source/blender/editors/space_outliner/space_outliner.c index 1bc1a227a03..1529e6143c3 100644 --- a/source/blender/editors/space_outliner/space_outliner.c +++ b/source/blender/editors/space_outliner/space_outliner.c @@ -48,6 +48,7 @@ #include "ED_screen.h" #include "WM_api.h" +#include "WM_message.h" #include "WM_types.h" #include "BIF_gl.h" @@ -162,7 +163,7 @@ static int outliner_parent_clear_poll(bContext *C, wmDrag *drag, const wmEvent * UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]); - if (!ELEM(soops->outlinevis, SO_ALL_SCENES, SO_CUR_SCENE, SO_VISIBLE, SO_GROUPS)) { + if (!ELEM(soops->outlinevis, SO_SCENES, SO_GROUPS, SO_VIEW_LAYER, SO_COLLECTIONS)) { return false; } @@ -423,6 +424,24 @@ static void outliner_main_region_listener( } +static void outliner_main_region_message_subscribe( + const struct bContext *UNUSED(C), + struct WorkSpace *UNUSED(workspace), struct Scene *UNUSED(scene), + struct bScreen *UNUSED(screen), struct ScrArea *sa, struct ARegion *ar, + struct wmMsgBus *mbus) +{ + SpaceOops *soops = sa->spacedata.first; + wmMsgSubscribeValue msg_sub_value_region_tag_redraw = { + .owner = ar, + .user_data = ar, + .notify = ED_region_do_msg_notify_tag_redraw, + }; + + if (ELEM(soops->outlinevis, SO_VIEW_LAYER, SO_COLLECTIONS)) { + WM_msg_subscribe_rna_anon_prop(mbus, Window, view_layer, &msg_sub_value_region_tag_redraw); + } +} + /* ************************ header outliner area region *********************** */ @@ -576,6 +595,7 @@ void ED_spacetype_outliner(void) art->draw = outliner_main_region_draw; art->free = outliner_main_region_free; art->listener = outliner_main_region_listener; + art->message_subscribe = outliner_main_region_message_subscribe; BLI_addhead(&st->regiontypes, art); /* regions: header */ diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c index 8f6eb064b0d..cb0c5bd3717 100644 --- a/source/blender/editors/space_sequencer/sequencer_edit.c +++ b/source/blender/editors/space_sequencer/sequencer_edit.c @@ -2190,23 +2190,24 @@ static int sequencer_delete_exec(bContext *C, wmOperator *UNUSED(op)) Editing *ed = BKE_sequencer_editing_get(scene, false); Sequence *seq; MetaStack *ms; - bool nothingSelected = true; + bool nothing_selected = true; seq = BKE_sequencer_active_get(scene); if (seq && seq->flag & SELECT) { /* avoid a loop since this is likely to be selected */ - nothingSelected = false; + nothing_selected = false; } else { for (seq = ed->seqbasep->first; seq; seq = seq->next) { if (seq->flag & SELECT) { - nothingSelected = false; + nothing_selected = false; break; } } } - if (nothingSelected) + if (nothing_selected) { return OPERATOR_FINISHED; + } /* for effects and modifiers, try to find a replacement input */ for (seq = ed->seqbasep->first; seq; seq = seq->next) { diff --git a/source/blender/editors/space_sequencer/sequencer_scopes.c b/source/blender/editors/space_sequencer/sequencer_scopes.c index 80cb42c0b3d..c5d6edadb53 100644 --- a/source/blender/editors/space_sequencer/sequencer_scopes.c +++ b/source/blender/editors/space_sequencer/sequencer_scopes.c @@ -459,13 +459,15 @@ typedef struct MakeHistogramViewData { } MakeHistogramViewData; static void make_histogram_view_from_ibuf_byte_cb_ex( - void *userdata, void *userdata_chunk, const int y, const int UNUSED(threadid)) + void *__restrict userdata, + const int y, + const ParallelRangeTLS *__restrict tls) { MakeHistogramViewData *data = userdata; const ImBuf *ibuf = data->ibuf; const unsigned char *src = (unsigned char *)ibuf->rect; - uint32_t (*cur_bins)[HIS_STEPS] = userdata_chunk; + uint32_t (*cur_bins)[HIS_STEPS] = tls->userdata_chunk; for (int x = 0; x < ibuf->x; x++) { const unsigned char *pixel = src + (y * ibuf->x + x) * 4; @@ -476,7 +478,8 @@ static void make_histogram_view_from_ibuf_byte_cb_ex( } } -static void make_histogram_view_from_ibuf_finalize(void *userdata, void *userdata_chunk) +static void make_histogram_view_from_ibuf_finalize(void *__restrict userdata, + void *__restrict userdata_chunk) { MakeHistogramViewData *data = userdata; uint32_t (*bins)[HIS_STEPS] = data->bins; @@ -501,9 +504,17 @@ static ImBuf *make_histogram_view_from_ibuf_byte(ImBuf *ibuf) memset(bins, 0, sizeof(bins)); MakeHistogramViewData data = {.ibuf = ibuf, .bins = bins}; - BLI_task_parallel_range_finalize( - 0, ibuf->y, &data, bins, sizeof(bins), make_histogram_view_from_ibuf_byte_cb_ex, - make_histogram_view_from_ibuf_finalize, ibuf->y >= 256, false); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = (ibuf->y >= 256); + settings.userdata_chunk = bins; + settings.userdata_chunk_size = sizeof(bins); + settings.func_finalize = make_histogram_view_from_ibuf_finalize; + BLI_task_parallel_range( + 0, ibuf->y, + &data, + make_histogram_view_from_ibuf_byte_cb_ex, + &settings); nr = nb = ng = 0; for (x = 0; x < HIS_STEPS; x++) { @@ -548,13 +559,15 @@ BLI_INLINE int get_bin_float(float f) } static void make_histogram_view_from_ibuf_float_cb_ex( - void *userdata, void *userdata_chunk, const int y, const int UNUSED(threadid)) + void *__restrict userdata, + const int y, + const ParallelRangeTLS *__restrict tls) { const MakeHistogramViewData *data = userdata; const ImBuf *ibuf = data->ibuf; const float *src = ibuf->rect_float; - uint32_t (*cur_bins)[HIS_STEPS] = userdata_chunk; + uint32_t (*cur_bins)[HIS_STEPS] = tls->userdata_chunk; for (int x = 0; x < ibuf->x; x++) { const float *pixel = src + (y * ibuf->x + x) * 4; @@ -576,9 +589,17 @@ static ImBuf *make_histogram_view_from_ibuf_float(ImBuf *ibuf) memset(bins, 0, sizeof(bins)); MakeHistogramViewData data = {.ibuf = ibuf, .bins = bins}; - BLI_task_parallel_range_finalize( - 0, ibuf->y, &data, bins, sizeof(bins), make_histogram_view_from_ibuf_float_cb_ex, - make_histogram_view_from_ibuf_finalize, ibuf->y >= 256, false); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = (ibuf->y >= 256); + settings.userdata_chunk = bins; + settings.userdata_chunk_size = sizeof(bins); + settings.func_finalize = make_histogram_view_from_ibuf_finalize; + BLI_task_parallel_range( + 0, ibuf->y, + &data, + make_histogram_view_from_ibuf_float_cb_ex, + &settings); nr = nb = ng = 0; for (x = 0; x < HIS_STEPS; x++) { diff --git a/source/blender/editors/space_text/text_draw.c b/source/blender/editors/space_text/text_draw.c index fcb675abcf2..62fde49cade 100644 --- a/source/blender/editors/space_text/text_draw.c +++ b/source/blender/editors/space_text/text_draw.c @@ -596,7 +596,7 @@ static void text_update_drawcache(SpaceText *st, ARegion *ar) drawcache->total_lines = 0; if (st->showlinenrs) - st->linenrs_tot = (int)floor(log10((float)nlines)) + 1; + st->linenrs_tot = integer_digits_i(nlines); while (line) { if (drawcache->valid_head) { /* we're inside valid head lines */ @@ -630,7 +630,7 @@ static void text_update_drawcache(SpaceText *st, ARegion *ar) nlines = BLI_listbase_count(&txt->lines); if (st->showlinenrs) - st->linenrs_tot = (int)floor(log10((float)nlines)) + 1; + st->linenrs_tot = integer_digits_i(nlines); } drawcache->total_lines = nlines; diff --git a/source/blender/editors/space_view3d/CMakeLists.txt b/source/blender/editors/space_view3d/CMakeLists.txt index de8380aa8bb..d148ef3c6fe 100644 --- a/source/blender/editors/space_view3d/CMakeLists.txt +++ b/source/blender/editors/space_view3d/CMakeLists.txt @@ -64,6 +64,8 @@ set(SRC view3d_manipulator_empty.c view3d_manipulator_forcefield.c view3d_manipulator_lamp.c + view3d_manipulator_navigate.c + view3d_manipulator_navigate_type.c view3d_manipulator_ruler.c view3d_ops.c view3d_project.c @@ -71,6 +73,7 @@ set(SRC view3d_select.c view3d_snap.c view3d_toolbar.c + view3d_utils.c view3d_view.c view3d_intern.h diff --git a/source/blender/editors/space_view3d/drawanimviz.c b/source/blender/editors/space_view3d/drawanimviz.c index 66355a50478..9fa85b55362 100644 --- a/source/blender/editors/space_view3d/drawanimviz.c +++ b/source/blender/editors/space_view3d/drawanimviz.c @@ -77,15 +77,15 @@ void draw_motion_paths_init(View3D *v3d, ARegion *ar) } /* set color -* - more intense for active/selected bones, less intense for unselected bones -* - black for before current frame, green for current frame, blue for after current frame -* - intensity decreases as distance from current frame increases -* -* If the user select custom color, the color is replaced for the color selected in UI panel -* - 75% Darker color is used for previous frames -* - 50% Darker color for current frame -* - User selected color for next frames -*/ + * - more intense for active/selected bones, less intense for unselected bones + * - black for before current frame, green for current frame, blue for after current frame + * - intensity decreases as distance from current frame increases + * + * If the user select custom color, the color is replaced for the color selected in UI panel + * - 75% Darker color is used for previous frames + * - 50% Darker color for current frame + * - User selected color for next frames + */ static void set_motion_path_color(Scene *scene, bMotionPath *mpath, int i, short sel, int sfra, int efra, float prev_color[3], float frame_color[3], float next_color[3], unsigned color) { diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c index 08ef9cc21cb..51dc56bafaf 100644 --- a/source/blender/editors/space_view3d/drawobject.c +++ b/source/blender/editors/space_view3d/drawobject.c @@ -980,14 +980,12 @@ void view3d_cached_text_draw_end(View3D *v3d, ARegion *ar, bool depth_write) col_pack_prev = vos->col.pack; } - ((vos->flag & V3D_CACHE_TEXT_ASCII) ? - BLF_draw_default_ascii : - BLF_draw_default - )((float)(vos->sco[0] + vos->xoffs), - (float)(vos->sco[1]), - (depth_write) ? 0.0f : 2.0f, - vos->str, - vos->str_len); + ((vos->flag & V3D_CACHE_TEXT_ASCII) ? BLF_draw_default_ascii : BLF_draw_default)( + (float)(vos->sco[0] + vos->xoffs), + (float)(vos->sco[1]), + (depth_write) ? 0.0f : 2.0f, + vos->str, + vos->str_len); } } @@ -1036,7 +1034,7 @@ static void drawcube_size(float size, unsigned pos) { size, size, size} }; - const GLubyte indices[24] = {0,1,1,3,3,2,2,0,0,4,4,5,5,7,7,6,6,4,1,5,3,7,2,6}; + const GLubyte indices[24] = {0, 1, 1, 3, 3, 2, 2, 0, 0, 4, 4, 5, 5, 7, 7, 6, 6, 4, 1, 5, 3, 7, 2, 6}; #if 0 glEnableClientState(GL_VERTEX_ARRAY); @@ -6098,46 +6096,46 @@ static void draw_new_particle_system( /* 4. */ if (draw_as && ELEM(draw_as, PART_DRAW_PATH, PART_DRAW_CIRC) == 0) { - int tot_vec_size = (totpart + totchild) * 3 * sizeof(float); + int partsize = 3 * sizeof(float); int create_ndata = 0; if (!pdd) pdd = psys->pdd = MEM_callocN(sizeof(ParticleDrawData), "ParticleDrawData"); if (part->draw_as == PART_DRAW_REND && part->trail_count > 1) { - tot_vec_size *= part->trail_count; + partsize *= part->trail_count; psys_make_temp_pointcache(ob, psys); } switch (draw_as) { case PART_DRAW_AXIS: case PART_DRAW_CROSS: - tot_vec_size *= 6; + partsize *= 6; if (draw_as != PART_DRAW_CROSS) create_cdata = 1; break; case PART_DRAW_LINE: - tot_vec_size *= 2; + partsize *= 2; break; case PART_DRAW_BB: - tot_vec_size *= 6; /* New OGL only understands tris, no choice here. */ + partsize *= 6; /* New OGL only understands tris, no choice here. */ create_ndata = 1; break; } - if (pdd->tot_vec_size != tot_vec_size) + if (pdd->totpart != totpart + totchild || pdd->partsize != partsize) psys_free_pdd(psys); if (!pdd->vdata) - pdd->vdata = MEM_callocN(tot_vec_size, "particle_vdata"); + pdd->vdata = MEM_calloc_arrayN(totpart + totchild, partsize, "particle_vdata"); if (create_cdata && !pdd->cdata) - pdd->cdata = MEM_callocN(tot_vec_size, "particle_cdata"); + pdd->cdata = MEM_calloc_arrayN(totpart + totchild, partsize, "particle_cdata"); if (create_ndata && !pdd->ndata) - pdd->ndata = MEM_callocN(tot_vec_size, "particle_ndata"); + pdd->ndata = MEM_calloc_arrayN(totpart + totchild, partsize, "particle_ndata"); if (part->draw & PART_DRAW_VEL && draw_as != PART_DRAW_LINE) { if (!pdd->vedata) - pdd->vedata = MEM_callocN(2 * (totpart + totchild) * 3 * sizeof(float), "particle_vedata"); + pdd->vedata = MEM_calloc_arrayN(totpart + totchild, 2 * 3 * sizeof(float), "particle_vedata"); need_v = 1; } @@ -6151,7 +6149,8 @@ static void draw_new_particle_system( pdd->ved = pdd->vedata; pdd->cd = pdd->cdata; pdd->nd = pdd->ndata; - pdd->tot_vec_size = tot_vec_size; + pdd->totpart = totpart + totchild; + pdd->partsize = partsize; } else if (psys->pdd) { psys_free_pdd(psys); @@ -6630,7 +6629,7 @@ static void draw_ptcache_edit(Scene *scene, View3D *v3d, PTCacheEdit *edit) const int totkeys = (*edit->pathcache)->segments + 1; glEnable(GL_BLEND); - float *pathcol = MEM_callocN(totkeys * 4 * sizeof(float), "particle path color data"); + float *pathcol = MEM_calloc_arrayN(totkeys, 4 * sizeof(float), "particle path color data"); if (pset->brushtype == PE_BRUSH_WEIGHT) glLineWidth(2.0f); @@ -6707,8 +6706,8 @@ static void draw_ptcache_edit(Scene *scene, View3D *v3d, PTCacheEdit *edit) if (totkeys_visible) { if (edit->points && !(edit->points->keys->flag & PEK_USE_WCO)) - pd = pdata = MEM_callocN(totkeys_visible * 3 * sizeof(float), "particle edit point data"); - cd = cdata = MEM_callocN(totkeys_visible * (timed ? 4 : 3) * sizeof(float), "particle edit color data"); + pd = pdata = MEM_calloc_arrayN(totkeys_visible, 3 * sizeof(float), "particle edit point data"); + cd = cdata = MEM_calloc_arrayN(totkeys_visible, (timed ? 4 : 3) * sizeof(float), "particle edit color data"); } for (i = 0, point = edit->points; i < totpoint; i++, point++) { @@ -7405,7 +7404,7 @@ static void draw_editnurb( } #else /* Same as loop above */ - count += 4 * max_ii((nr + max_ii(skip - 1, 0)) / (skip + 1), 0); + count += 4 * ((nr / (skip + 1)) + ((nr % (skip + 1)) != 0)); #endif } @@ -8066,7 +8065,7 @@ static void imm_draw_box(const float vec[8][3], bool solid, unsigned pos) if (solid) { /* Adpated from "Optimizing Triangle Strips for Fast Rendering" by F. Evans, S. Skiena and A. Varshney * (http://www.cs.umd.edu/gvil/papers/av_ts.pdf). */ - static const GLubyte tris_strip_indices[14] = {0,1,3,2,6,1,5,0,4,3,7,6,4,5}; + static const GLubyte tris_strip_indices[14] = {0, 1, 3, 2, 6, 1, 5, 0, 4, 3, 7, 6, 4, 5}; immBegin(GWN_PRIM_TRI_STRIP, 14); for (int i = 0; i < 14; ++i) { immVertex3fv(pos, vec[tris_strip_indices[i]]); @@ -8074,7 +8073,8 @@ static void imm_draw_box(const float vec[8][3], bool solid, unsigned pos) immEnd(); } else { - static const GLubyte line_indices[24] = {0,1,1,2,2,3,3,0,0,4,4,5,5,6,6,7,7,4,1,5,2,6,3,7}; + static const GLubyte line_indices[24] = + {0, 1, 1, 2, 2, 3, 3, 0, 0, 4, 4, 5, 5, 6, 6, 7, 7, 4, 1, 5, 2, 6, 3, 7}; immBegin(GWN_PRIM_LINES, 24); for (int i = 0; i < 24; ++i) { immVertex3fv(pos, vec[line_indices[i]]); @@ -9217,7 +9217,10 @@ afterdraw: /* help lines and so */ if (ob != scene->obedit && ob->parent) { - if (BKE_object_is_visible(ob->parent)) { + const eObjectVisibilityCheck mode = eval_ctx->mode != DAG_EVAL_VIEWPORT ? + OB_VISIBILITY_CHECK_FOR_RENDER : + OB_VISIBILITY_CHECK_FOR_VIEWPORT; + if (BKE_object_is_visible(ob->parent, mode)) { setlinestyle(3); immBegin(GWN_PRIM_LINES, 2); immVertex3fv(pos, ob->obmat[3]); @@ -9769,8 +9772,9 @@ void draw_object_backbufsel( bbs_mesh_solid_EM(em, scene, v3d, ob, dm, (ts->selectmode & SCE_SELECT_FACE) != 0); if (ts->selectmode & SCE_SELECT_FACE) bm_solidoffs = 1 + em->bm->totface; - else + else { bm_solidoffs = 1; + } ED_view3d_polygon_offset(rv3d, 1.0); @@ -9779,6 +9783,10 @@ void draw_object_backbufsel( bbs_mesh_wire(em, dm, bm_solidoffs); bm_wireoffs = bm_solidoffs + em->bm->totedge; } + else { + /* `bm_vertoffs` is calculated from `bm_wireoffs`. (otherwise see T53512) */ + bm_wireoffs = bm_solidoffs; + } /* we draw verts if vert select mode. */ if (ts->selectmode & SCE_SELECT_VERTEX) { diff --git a/source/blender/editors/space_view3d/drawvolume.c b/source/blender/editors/space_view3d/drawvolume.c index 3a80624acd9..d39f3937a9d 100644 --- a/source/blender/editors/space_view3d/drawvolume.c +++ b/source/blender/editors/space_view3d/drawvolume.c @@ -41,7 +41,7 @@ #include "BLI_math.h" #include "BKE_DerivedMesh.h" -#include "BKE_texture.h" +#include "BKE_colorband.h" #include "BKE_particle.h" #include "smoke_API.h" @@ -111,7 +111,7 @@ static void create_flame_spectrum_texture(float *data) static void create_color_ramp(const ColorBand *coba, float *data) { for (int i = 0; i < TFUNC_WIDTH; i++) { - do_colorband(coba, (float)i / TFUNC_WIDTH, &data[i * 4]); + BKE_colorband_evaluate(coba, (float)i / TFUNC_WIDTH, &data[i * 4]); } } diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c index 7cf1573de43..6540a1fb234 100644 --- a/source/blender/editors/space_view3d/space_view3d.c +++ b/source/blender/editors/space_view3d/space_view3d.c @@ -711,6 +711,9 @@ static void view3d_widgets(void) WM_manipulatorgrouptype_append(VIEW3D_WGT_ruler); WM_manipulatortype_append(VIEW3D_WT_ruler_item); + + WM_manipulatorgrouptype_append_and_link(mmap_type, VIEW3D_WGT_navigate); + WM_manipulatortype_append(VIEW3D_WT_navigate_rotate); } @@ -1055,6 +1058,8 @@ static void view3d_main_region_message_subscribe( /* Only subscribe to types. */ StructRNA *type_array[] = { + &RNA_Window, + /* These object have properties that impact drawing. */ &RNA_AreaLamp, &RNA_Camera, @@ -1102,10 +1107,12 @@ static void view3d_main_region_message_subscribe( extern StructRNA RNA_ViewLayerEngineSettingsEevee; WM_msg_subscribe_rna_anon_type(mbus, ViewLayerEngineSettingsEevee, &msg_sub_value_region_tag_redraw); } +#ifdef WITH_CLAY_ENGINE else if (STREQ(view_render->engine_id, RE_engine_id_BLENDER_CLAY)) { extern StructRNA RNA_ViewLayerEngineSettingsClay; WM_msg_subscribe_rna_anon_type(mbus, ViewLayerEngineSettingsClay, &msg_sub_value_region_tag_redraw); } +#endif } /* concept is to retrieve cursor type context-less */ diff --git a/source/blender/editors/space_view3d/view3d_camera_control.c b/source/blender/editors/space_view3d/view3d_camera_control.c index 9b07593e576..c39057431c2 100644 --- a/source/blender/editors/space_view3d/view3d_camera_control.c +++ b/source/blender/editors/space_view3d/view3d_camera_control.c @@ -138,13 +138,10 @@ Object *ED_view3d_cameracontrol_object_get(View3DCameraControl *vctrl) * the view for first-person style navigation. */ struct View3DCameraControl *ED_view3d_cameracontrol_acquire( - const bContext *C, Scene *scene, View3D *v3d, RegionView3D *rv3d, + const EvaluationContext *eval_ctx, Scene *scene, View3D *v3d, RegionView3D *rv3d, const bool use_parent_root) { View3DCameraControl *vctrl; - EvaluationContext eval_ctx; - - CTX_data_eval_ctx(C, &eval_ctx); vctrl = MEM_callocN(sizeof(View3DCameraControl), __func__); @@ -181,7 +178,7 @@ struct View3DCameraControl *ED_view3d_cameracontrol_acquire( /* store the original camera loc and rot */ vctrl->obtfm = BKE_object_tfm_backup(ob_back); - BKE_object_where_is_calc(&eval_ctx, scene, v3d->camera); + BKE_object_where_is_calc(eval_ctx, scene, v3d->camera); negate_v3_v3(rv3d->ofs, v3d->camera->obmat[3]); rv3d->dist = 0.0; diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c index 6ea2ff10af2..f734bb085d0 100644 --- a/source/blender/editors/space_view3d/view3d_draw.c +++ b/source/blender/editors/space_view3d/view3d_draw.c @@ -123,21 +123,28 @@ void ED_view3d_update_viewmat( const EvaluationContext *eval_ctx, Scene *scene, View3D *v3d, ARegion *ar, float viewmat[4][4], float winmat[4][4], const rcti *rect) { + const Depsgraph *depsgraph = eval_ctx->depsgraph; RegionView3D *rv3d = ar->regiondata; - /* setup window matrices */ if (winmat) copy_m4_m4(rv3d->winmat, winmat); else - view3d_winmatrix_set(ar, v3d, rect); + view3d_winmatrix_set(depsgraph, ar, v3d, rect); /* setup view matrix */ - if (viewmat) + if (viewmat) { copy_m4_m4(rv3d->viewmat, viewmat); - else - view3d_viewmatrix_set(eval_ctx, scene, v3d, rv3d); /* note: calls BKE_object_where_is_calc for camera... */ - + } + else { + float rect_scale[2]; + if (rect) { + rect_scale[0] = (float)BLI_rcti_size_x(rect) / (float)ar->winx; + rect_scale[1] = (float)BLI_rcti_size_y(rect) / (float)ar->winy; + } + /* note: calls BKE_object_where_is_calc for camera... */ + view3d_viewmatrix_set(eval_ctx, scene, v3d, rv3d, rect ? rect_scale : NULL); + } /* update utility matrices */ mul_m4_m4m4(rv3d->persmat, rv3d->winmat, rv3d->viewmat); invert_m4_m4(rv3d->persinv, rv3d->persmat); @@ -148,7 +155,7 @@ void ED_view3d_update_viewmat( /* store window coordinates scaling/offset */ if (rv3d->persp == RV3D_CAMOB && v3d->camera) { rctf cameraborder; - ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &cameraborder, false); + ED_view3d_calc_camera_border(scene, eval_ctx->depsgraph, ar, v3d, rv3d, &cameraborder, false); rv3d->viewcamtexcofac[0] = (float)ar->winx / BLI_rctf_size_x(&cameraborder); rv3d->viewcamtexcofac[1] = (float)ar->winy / BLI_rctf_size_y(&cameraborder); @@ -307,7 +314,8 @@ void ED_view3d_draw_setup_view( /* ******************** view border ***************** */ static void view3d_camera_border( - const Scene *scene, const ARegion *ar, const View3D *v3d, const RegionView3D *rv3d, + const Scene *scene, const struct Depsgraph *depsgraph, + const ARegion *ar, const View3D *v3d, const RegionView3D *rv3d, rctf *r_viewborder, const bool no_shift, const bool no_zoom) { CameraParams params; @@ -315,7 +323,7 @@ static void view3d_camera_border( /* get viewport viewplane */ BKE_camera_params_init(¶ms); - BKE_camera_params_from_view3d(¶ms, v3d, rv3d); + BKE_camera_params_from_view3d(¶ms, depsgraph, v3d, rv3d); if (no_zoom) params.zoom = 1.0f; BKE_camera_params_compute_viewplane(¶ms, ar->winx, ar->winy, 1.0f, 1.0f); @@ -342,21 +350,23 @@ static void view3d_camera_border( } void ED_view3d_calc_camera_border_size( - const Scene *scene, const ARegion *ar, const View3D *v3d, const RegionView3D *rv3d, + const Scene *scene, const Depsgraph *depsgraph, + const ARegion *ar, const View3D *v3d, const RegionView3D *rv3d, float r_size[2]) { rctf viewborder; - view3d_camera_border(scene, ar, v3d, rv3d, &viewborder, true, true); + view3d_camera_border(scene, depsgraph, ar, v3d, rv3d, &viewborder, true, true); r_size[0] = BLI_rctf_size_x(&viewborder); r_size[1] = BLI_rctf_size_y(&viewborder); } void ED_view3d_calc_camera_border( - const Scene *scene, const ARegion *ar, const View3D *v3d, const RegionView3D *rv3d, + const Scene *scene, const Depsgraph *depsgraph, + const ARegion *ar, const View3D *v3d, const RegionView3D *rv3d, rctf *r_viewborder, const bool no_shift) { - view3d_camera_border(scene, ar, v3d, rv3d, r_viewborder, no_shift, false); + view3d_camera_border(scene, depsgraph, ar, v3d, rv3d, r_viewborder, no_shift, false); } static void drawviewborder_grid3(uint shdr_pos, float x1, float x2, float y1, float y2, float fac) @@ -435,7 +445,7 @@ static void drawviewborder_triangle( immEnd(); } -static void drawviewborder(Scene *scene, ARegion *ar, View3D *v3d) +static void drawviewborder(Scene *scene, const Depsgraph *depsgraph, ARegion *ar, View3D *v3d) { float x1, x2, y1, y2; float x1i, x2i, y1i, y2i; @@ -449,7 +459,7 @@ static void drawviewborder(Scene *scene, ARegion *ar, View3D *v3d) if (v3d->camera->type == OB_CAMERA) ca = v3d->camera->data; - ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &viewborder, false); + ED_view3d_calc_camera_border(scene, depsgraph, ar, v3d, rv3d, &viewborder, false); /* the offsets */ x1 = viewborder.xmin; y1 = viewborder.ymin; @@ -1318,6 +1328,10 @@ float ED_view3d_grid_scale(Scene *scene, View3D *v3d, const char **grid_unit) static bool is_cursor_visible(Scene *scene, ViewLayer *view_layer) { + if (U.app_flag & USER_APP_VIEW3D_HIDE_CURSOR) { + return false; + } + Object *ob = OBACT(view_layer); /* don't draw cursor in paint modes, but with a few exceptions */ @@ -1594,11 +1608,12 @@ static void UNUSED_FUNCTION(draw_rotation_guide)(RegionView3D *rv3d) static void view3d_draw_border(const bContext *C, ARegion *ar) { Scene *scene = CTX_data_scene(C); + Depsgraph *depsgraph = CTX_data_depsgraph(C); RegionView3D *rv3d = ar->regiondata; View3D *v3d = CTX_wm_view3d(C); if (rv3d->persp == RV3D_CAMOB) { - drawviewborder(scene, ar, v3d); + drawviewborder(scene, depsgraph, ar, v3d); } else if (v3d->flag2 & V3D_RENDER_BORDER) { drawrenderborder(ar, v3d); @@ -1966,7 +1981,7 @@ void ED_view3d_draw_offscreen( float viewmat[4][4], float winmat[4][4], bool do_bgpic, bool do_sky, bool is_persp, const char *viewname, GPUFX *fx, GPUFXSettings *fx_settings, - GPUOffScreen *ofs) + GPUOffScreen *ofs, GPUViewport *viewport) { bool do_compositing = false; RegionView3D *rv3d = ar->regiondata; @@ -2015,6 +2030,10 @@ void ED_view3d_draw_offscreen( else view3d_main_region_setup_view(eval_ctx, scene, v3d, ar, viewmat, winmat, NULL); + /* XXX, should take depsgraph as arg */ + Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer, false); + BLI_assert(depsgraph != NULL); + /* main drawing call */ RenderEngineType *engine_type = eval_ctx->engine_type; if (engine_type->flag & RE_USE_LEGACY_PIPELINE) { @@ -2049,7 +2068,7 @@ void ED_view3d_draw_offscreen( if (v3d->flag2 & V3D_SHOW_GPENCIL) { /* draw grease-pencil stuff - needed to get paint-buffer shown too (since it's 2D) */ - ED_gpencil_draw_view3d(NULL, scene, view_layer, v3d, ar, false); + ED_gpencil_draw_view3d(NULL, scene, view_layer, depsgraph, v3d, ar, false); } /* freeing the images again here could be done after the operator runs, leaving for now */ @@ -2057,10 +2076,7 @@ void ED_view3d_draw_offscreen( } } else { - /* XXX, should take depsgraph as arg */ - Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer, false); - BLI_assert(depsgraph != NULL); - DRW_draw_render_loop_offscreen(depsgraph, eval_ctx->engine_type, ar, v3d, ofs); + DRW_draw_render_loop_offscreen(depsgraph, eval_ctx->engine_type, ar, v3d, do_sky, ofs, viewport); } /* restore size */ @@ -2090,6 +2106,7 @@ ImBuf *ED_view3d_draw_offscreen_imbuf( /* output vars */ GPUFX *fx, GPUOffScreen *ofs, char err_out[256]) { + const Depsgraph *depsgraph = eval_ctx->depsgraph; RegionView3D *rv3d = ar->regiondata; const bool draw_sky = (alpha_mode == R_ADDSKY); const bool draw_background = (draw_flags & V3D_OFSDRAW_USE_BACKGROUND); @@ -2109,7 +2126,7 @@ ImBuf *ED_view3d_draw_offscreen_imbuf( if (own_ofs) { /* bind */ - ofs = GPU_offscreen_create(sizex, sizey, use_full_sample ? 0 : samples, err_out); + ofs = GPU_offscreen_create(sizex, sizey, use_full_sample ? 0 : samples, false, err_out); if (ofs == NULL) { return NULL; } @@ -2145,7 +2162,7 @@ ImBuf *ED_view3d_draw_offscreen_imbuf( rctf viewplane; float clipsta, clipend; - is_ortho = ED_view3d_viewplane_get(v3d, rv3d, sizex, sizey, &viewplane, &clipsta, &clipend, NULL); + is_ortho = ED_view3d_viewplane_get(depsgraph, v3d, rv3d, sizex, sizey, &viewplane, &clipsta, &clipend, NULL); if (is_ortho) { orthographic_m4(winmat, viewplane.xmin, viewplane.xmax, viewplane.ymin, viewplane.ymax, -clipend, clipend); } @@ -2159,7 +2176,7 @@ ImBuf *ED_view3d_draw_offscreen_imbuf( ED_view3d_draw_offscreen( eval_ctx, scene, view_layer, v3d, ar, sizex, sizey, NULL, winmat, draw_background, draw_sky, !is_ortho, viewname, - fx, &fx_settings, ofs); + fx, &fx_settings, ofs, NULL); if (ibuf->rect_float) { GPU_offscreen_read_pixels(ofs, GL_FLOAT, ibuf->rect_float); @@ -2173,9 +2190,9 @@ ImBuf *ED_view3d_draw_offscreen_imbuf( * Use because OpenGL may use a lower quality MSAA, and only over-sample edges. */ static float jit_ofs[32][2]; float winmat_jitter[4][4]; - /* use imbuf as temp storage, before writing into it from accumulation buffer */ - unsigned char *rect_temp = ibuf->rect ? (void *)ibuf->rect : (void *)ibuf->rect_float; - unsigned int *accum_buffer = MEM_mallocN(sizex * sizey * sizeof(int[4]), "accum1"); + float *rect_temp = (ibuf->rect_float) ? ibuf->rect_float : MEM_mallocN(sizex * sizey * sizeof(float[4]), "rect_temp"); + float *accum_buffer = MEM_mallocN(sizex * sizey * sizeof(float[4]), "accum_buffer"); + GPUViewport *viewport = GPU_viewport_create_from_offscreen(ofs); BLI_jitter_init(jit_ofs, samples); @@ -2183,13 +2200,8 @@ ImBuf *ED_view3d_draw_offscreen_imbuf( ED_view3d_draw_offscreen( eval_ctx, scene, view_layer, v3d, ar, sizex, sizey, NULL, winmat, draw_background, draw_sky, !is_ortho, viewname, - fx, &fx_settings, ofs); - GPU_offscreen_read_pixels(ofs, GL_UNSIGNED_BYTE, rect_temp); - - unsigned i = sizex * sizey * 4; - while (i--) { - accum_buffer[i] = rect_temp[i]; - } + fx, &fx_settings, ofs, viewport); + GPU_offscreen_read_pixels(ofs, GL_FLOAT, accum_buffer); /* skip the first sample */ for (int j = 1; j < samples; j++) { @@ -2202,27 +2214,38 @@ ImBuf *ED_view3d_draw_offscreen_imbuf( ED_view3d_draw_offscreen( eval_ctx, scene, view_layer, v3d, ar, sizex, sizey, NULL, winmat_jitter, draw_background, draw_sky, !is_ortho, viewname, - fx, &fx_settings, ofs); - GPU_offscreen_read_pixels(ofs, GL_UNSIGNED_BYTE, rect_temp); + fx, &fx_settings, ofs, viewport); + GPU_offscreen_read_pixels(ofs, GL_FLOAT, rect_temp); - i = sizex * sizey * 4; + unsigned int i = sizex * sizey * 4; while (i--) { accum_buffer[i] += rect_temp[i]; } } + { + /* don't free data owned by 'ofs' */ + GPU_viewport_clear_from_offscreen(viewport); + GPU_viewport_free(viewport); + MEM_freeN(viewport); + } + + if (ibuf->rect_float == NULL) { + MEM_freeN(rect_temp); + } + if (ibuf->rect_float) { float *rect_float = ibuf->rect_float; - i = sizex * sizey * 4; + unsigned int i = sizex * sizey * 4; while (i--) { - rect_float[i] = (float)(accum_buffer[i] / samples) * (1.0f / 255.0f); + rect_float[i] = accum_buffer[i] / samples; } } else { unsigned char *rect_ub = (unsigned char *)ibuf->rect; - i = sizex * sizey * 4; + unsigned int i = sizex * sizey * 4; while (i--) { - rect_ub[i] = accum_buffer[i] / samples; + rect_ub[i] = (unsigned char)(255.0f * accum_buffer[i] / samples); } } @@ -2383,9 +2406,9 @@ bool VP_legacy_use_depth(Scene *scene, View3D *v3d) return use_depth_doit(scene, v3d); } -void VP_drawviewborder(Scene *scene, ARegion *ar, View3D *v3d) +void VP_drawviewborder(Scene *scene, const struct Depsgraph *depsgraph, ARegion *ar, View3D *v3d) { - drawviewborder(scene, ar, v3d); + drawviewborder(scene, depsgraph, ar, v3d); } void VP_drawrenderborder(ARegion *ar, View3D *v3d) diff --git a/source/blender/editors/space_view3d/view3d_draw_legacy.c b/source/blender/editors/space_view3d/view3d_draw_legacy.c index 84f0f96fe0b..7cb362ffb92 100644 --- a/source/blender/editors/space_view3d/view3d_draw_legacy.c +++ b/source/blender/editors/space_view3d/view3d_draw_legacy.c @@ -284,7 +284,7 @@ static void backdrawview3d(const struct EvaluationContext *eval_ctx, Scene *scen } if (!rv3d->gpuoffscreen) { - rv3d->gpuoffscreen = GPU_offscreen_create(w, h, 0, error); + rv3d->gpuoffscreen = GPU_offscreen_create(w, h, 0, false, error); if (!rv3d->gpuoffscreen) fprintf(stderr, "Failed to create offscreen selection buffer for multisample: %s\n", error); @@ -530,7 +530,8 @@ static void view3d_stereo_bgpic_setup(Scene *scene, View3D *v3d, Image *ima, Ima } } -static void view3d_draw_bgpic(Scene *scene, ARegion *ar, View3D *v3d, +static void view3d_draw_bgpic(Scene *scene, const Depsgraph *depsgraph, + ARegion *ar, View3D *v3d, const bool do_foreground, const bool do_camera_frame) { RegionView3D *rv3d = ar->regiondata; @@ -629,7 +630,7 @@ static void view3d_draw_bgpic(Scene *scene, ARegion *ar, View3D *v3d, { if (do_camera_frame) { rctf vb; - ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &vb, false); + ED_view3d_calc_camera_border(scene, depsgraph, ar, v3d, rv3d, &vb, false); x1 = vb.xmin; y1 = vb.ymin; x2 = vb.xmax; @@ -773,8 +774,10 @@ static void view3d_draw_bgpic(Scene *scene, ARegion *ar, View3D *v3d, } } -void view3d_draw_bgpic_test(Scene *scene, ARegion *ar, View3D *v3d, - const bool do_foreground, const bool do_camera_frame) +void ED_view3d_draw_bgpic_test( + Scene *scene, const Depsgraph *depsgraph, + ARegion *ar, View3D *v3d, + const bool do_foreground, const bool do_camera_frame) { RegionView3D *rv3d = ar->regiondata; @@ -797,11 +800,11 @@ void view3d_draw_bgpic_test(Scene *scene, ARegion *ar, View3D *v3d, if ((rv3d->view == RV3D_VIEW_USER) || (rv3d->persp != RV3D_ORTHO)) { if (rv3d->persp == RV3D_CAMOB) { - view3d_draw_bgpic(scene, ar, v3d, do_foreground, do_camera_frame); + view3d_draw_bgpic(scene, depsgraph, ar, v3d, do_foreground, do_camera_frame); } } else { - view3d_draw_bgpic(scene, ar, v3d, do_foreground, do_camera_frame); + view3d_draw_bgpic(scene, depsgraph, ar, v3d, do_foreground, do_camera_frame); } } @@ -1182,7 +1185,7 @@ void ED_view3d_draw_depth_gpencil( glEnable(GL_DEPTH_TEST); if (v3d->flag2 & V3D_SHOW_GPENCIL) { - ED_gpencil_draw_view3d(NULL, scene, eval_ctx->view_layer, v3d, ar, true); + ED_gpencil_draw_view3d(NULL, scene, eval_ctx->view_layer, eval_ctx->depsgraph, v3d, ar, true); } v3d->zbuf = zbuf; @@ -1423,7 +1426,7 @@ static void gpu_update_lamps_shadows_world(const EvaluationContext *eval_ctx, Sc ED_view3d_draw_offscreen( eval_ctx, scene, eval_ctx->view_layer, v3d, &ar, winsize, winsize, viewmat, winmat, false, false, true, - NULL, NULL, NULL, NULL); + NULL, NULL, NULL, NULL, NULL); GPU_lamp_shadow_buffer_unbind(shadow->lamp); v3d->drawtype = drawtype; @@ -1500,6 +1503,7 @@ static void view3d_draw_objects( const bool do_bgpic, const bool draw_offscreen, GPUFX *fx) { ViewLayer *view_layer = C ? CTX_data_view_layer(C) : BKE_view_layer_from_scene_get(scene); + Depsgraph *depsgraph = CTX_data_depsgraph(C); RegionView3D *rv3d = ar->regiondata; Base *base; const bool do_camera_frame = !draw_offscreen; @@ -1544,7 +1548,7 @@ static void view3d_draw_objects( /* important to do before clipping */ if (do_bgpic) { - view3d_draw_bgpic_test(scene, ar, v3d, false, do_camera_frame); + ED_view3d_draw_bgpic_test(scene, depsgraph, ar, v3d, false, do_camera_frame); } if (rv3d->rflag & RV3D_CLIPPING) { @@ -1625,7 +1629,7 @@ static void view3d_draw_objects( /* must be before xray draw which clears the depth buffer */ if (v3d->zbuf) glDisable(GL_DEPTH_TEST); - ED_gpencil_draw_view3d(wm, scene, view_layer, v3d, ar, true); + ED_gpencil_draw_view3d(wm, scene, view_layer, depsgraph, v3d, ar, true); if (v3d->zbuf) glEnable(GL_DEPTH_TEST); } @@ -1654,7 +1658,7 @@ static void view3d_draw_objects( /* important to do after clipping */ if (do_bgpic) { - view3d_draw_bgpic_test(scene, ar, v3d, true, do_camera_frame); + ED_view3d_draw_bgpic_test(scene, depsgraph, ar, v3d, true, do_camera_frame); } /* cleanup */ @@ -1773,7 +1777,7 @@ static bool view3d_main_region_do_render_draw(const Scene *scene) return (type && type->view_update && type->render_to_view); } -bool ED_view3d_calc_render_border(const Scene *scene, View3D *v3d, ARegion *ar, rcti *rect) +bool ED_view3d_calc_render_border(const Scene *scene, const Depsgraph *depsgraph, View3D *v3d, ARegion *ar, rcti *rect) { RegionView3D *rv3d = ar->regiondata; bool use_border; @@ -1794,7 +1798,7 @@ bool ED_view3d_calc_render_border(const Scene *scene, View3D *v3d, ARegion *ar, /* compute border */ if (rv3d->persp == RV3D_CAMOB) { rctf viewborder; - ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &viewborder, false); + ED_view3d_calc_camera_border(scene, depsgraph, ar, v3d, rv3d, &viewborder, false); rect->xmin = viewborder.xmin + scene->r.border.xmin * BLI_rctf_size_x(&viewborder); rect->ymin = viewborder.ymin + scene->r.border.ymin * BLI_rctf_size_y(&viewborder); @@ -1823,11 +1827,11 @@ static bool view3d_main_region_draw_engine( ARegion *ar, View3D *v3d, bool clip_border, const rcti *border_rect) { + const Depsgraph *depsgraph = CTX_data_depsgraph(C); RegionView3D *rv3d = ar->regiondata; RenderEngineType *type; GLint scissor[4]; - /* create render engine */ if (!rv3d->render_engine) { RenderEngine *engine; @@ -1872,7 +1876,7 @@ static bool view3d_main_region_draw_engine( Camera *cam = ED_view3d_camera_data_get(v3d, rv3d); if (cam->flag & CAM_SHOW_BG_IMAGE) { show_image = true; - view3d_draw_bgpic_test(scene, ar, v3d, false, true); + ED_view3d_draw_bgpic_test(scene, depsgraph, ar, v3d, false, true); } else { imm_draw_box_checker_2d(0, 0, ar->winx, ar->winy); @@ -1880,7 +1884,7 @@ static bool view3d_main_region_draw_engine( } if (show_image) { - view3d_draw_bgpic_test(scene, ar, v3d, false, true); + ED_view3d_draw_bgpic_test(scene, depsgraph, ar, v3d, false, true); } else { imm_draw_box_checker_2d(0, 0, ar->winx, ar->winy); @@ -1891,7 +1895,7 @@ static bool view3d_main_region_draw_engine( type->render_to_view(rv3d->render_engine, C); if (show_image) { - view3d_draw_bgpic_test(scene, ar, v3d, true, true); + ED_view3d_draw_bgpic_test(scene, depsgraph, ar, v3d, true, true); } if (clip_border) { @@ -2007,11 +2011,6 @@ static void view3d_main_region_draw_objects(const bContext *C, Scene *scene, Vie /* main drawing call */ view3d_draw_objects(C, &eval_ctx, scene, v3d, ar, grid_unit, true, false, do_compositing ? rv3d->compositor : NULL); - /* draw depth culled manipulators - manipulators need to be updated *after* view matrix was set up */ - /* TODO depth culling manipulators is not yet supported, just drawing _3D here, should - * later become _IN_SCENE (and draw _3D separate) */ - WM_manipulatormap_draw(ar->manipulator_map, C, WM_MANIPULATORMAP_DRAWSTEP_3D); - /* post process */ if (do_compositing) { GPU_fx_do_composite_pass(rv3d->compositor, rv3d->winmat, rv3d->is_persp, scene, NULL); @@ -2038,6 +2037,7 @@ static void view3d_main_region_draw_info(const bContext *C, Scene *scene, ARegion *ar, View3D *v3d, const char *grid_unit, bool render_border) { + const Depsgraph *depsgraph = CTX_data_depsgraph(C); ViewLayer *view_layer = CTX_data_view_layer(C); wmWindowManager *wm = CTX_wm_manager(C); RegionView3D *rv3d = ar->regiondata; @@ -2047,7 +2047,7 @@ static void view3d_main_region_draw_info(const bContext *C, Scene *scene, ED_region_visible_rect(ar, &rect); if (rv3d->persp == RV3D_CAMOB) { - VP_drawviewborder(scene, ar, v3d); + VP_drawviewborder(scene, CTX_data_depsgraph(C), ar, v3d); } else if (v3d->flag2 & V3D_RENDER_BORDER) { VP_drawrenderborder(ar, v3d); @@ -2055,7 +2055,7 @@ static void view3d_main_region_draw_info(const bContext *C, Scene *scene, if (v3d->flag2 & V3D_SHOW_GPENCIL) { /* draw grease-pencil stuff - needed to get paint-buffer shown too (since it's 2D) */ - ED_gpencil_draw_view3d(wm, scene, view_layer, v3d, ar, false); + ED_gpencil_draw_view3d(wm, scene, view_layer, depsgraph, v3d, ar, false); } if ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) { @@ -2102,6 +2102,7 @@ static void view3d_main_region_draw_info(const bContext *C, Scene *scene, void view3d_main_region_draw_legacy(const bContext *C, ARegion *ar) { + const Depsgraph *depsgraph = CTX_data_depsgraph(C); EvaluationContext eval_ctx; Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); @@ -2111,7 +2112,7 @@ void view3d_main_region_draw_legacy(const bContext *C, ARegion *ar) /* if we only redraw render border area, skip opengl draw and also * don't do scissor because it's already set */ - bool render_border = ED_view3d_calc_render_border(scene, v3d, ar, &border_rect); + bool render_border = ED_view3d_calc_render_border(scene, depsgraph, v3d, ar, &border_rect); bool clip_border = (render_border && !BLI_rcti_compare(&ar->drawrct, &border_rect)); gpuPushProjectionMatrix(); @@ -2141,12 +2142,14 @@ void view3d_main_region_draw_legacy(const bContext *C, ARegion *ar) VP_legacy_view3d_main_region_setup_view(&eval_ctx, scene, v3d, ar, NULL, NULL); glClear(GL_DEPTH_BUFFER_BIT); - ED_region_pixelspace(ar); + WM_manipulatormap_draw(ar->manipulator_map, C, WM_MANIPULATORMAP_DRAWSTEP_3D); - WM_manipulatormap_draw(ar->manipulator_map, C, WM_MANIPULATORMAP_DRAWSTEP_2D); + ED_region_pixelspace(ar); view3d_main_region_draw_info(C, scene, ar, v3d, grid_unit, render_border); + WM_manipulatormap_draw(ar->manipulator_map, C, WM_MANIPULATORMAP_DRAWSTEP_2D); + gpuPopProjectionMatrix(); gpuPopMatrix(); diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c index 0dba87bef25..2457a890f71 100644 --- a/source/blender/editors/space_view3d/view3d_edit.c +++ b/source/blender/editors/space_view3d/view3d_edit.c @@ -26,6 +26,8 @@ /** \file blender/editors/space_view3d/view3d_edit.c * \ingroup spview3d + * + * 3D view manipulation/operators. */ #include <string.h> @@ -42,9 +44,7 @@ #include "MEM_guardedalloc.h" -#include "BLI_bitmap_draw_2d.h" #include "BLI_blenlib.h" -#include "BLI_kdopbvh.h" #include "BLI_math.h" #include "BLI_utildefines.h" @@ -63,7 +63,6 @@ #include "DEG_depsgraph.h" -#include "BIF_gl.h" #include "WM_api.h" #include "WM_types.h" @@ -73,499 +72,129 @@ #include "ED_armature.h" #include "ED_particle.h" -#include "ED_keyframing.h" #include "ED_screen.h" #include "ED_transform.h" #include "ED_mesh.h" #include "ED_gpencil.h" #include "ED_view3d.h" -#include "DEG_depsgraph_query.h" - #include "UI_resources.h" -#include "PIL_time.h" /* smoothview */ +#include "PIL_time.h" #include "view3d_intern.h" /* own include */ -static bool view3d_ensure_persp(struct View3D *v3d, ARegion *ar); - -bool ED_view3d_offset_lock_check(const View3D *v3d, const RegionView3D *rv3d) -{ - return (rv3d->persp != RV3D_CAMOB) && (v3d->ob_centre_cursor || v3d->ob_centre); -} - -/* ********************** view3d_edit: view manipulations ********************* */ - -/** - * \return true when the view-port is locked to its camera. - */ -bool ED_view3d_camera_lock_check(const View3D *v3d, const RegionView3D *rv3d) -{ - return ((v3d->camera) && - (!ID_IS_LINKED(v3d->camera)) && - (v3d->flag2 & V3D_LOCK_CAMERA) && - (rv3d->persp == RV3D_CAMOB)); -} - -/** - * Apply the camera object transformation to the view-port. - * (needed so we can use regular view-port manipulation operators, that sync back to the camera). - */ -void ED_view3d_camera_lock_init_ex(View3D *v3d, RegionView3D *rv3d, const bool calc_dist) -{ - if (ED_view3d_camera_lock_check(v3d, rv3d)) { - if (calc_dist) { - /* using a fallback dist is OK here since ED_view3d_from_object() compensates for it */ - rv3d->dist = ED_view3d_offset_distance(v3d->camera->obmat, rv3d->ofs, VIEW3D_DIST_FALLBACK); - } - ED_view3d_from_object(v3d->camera, rv3d->ofs, rv3d->viewquat, &rv3d->dist, NULL); - } -} - -void ED_view3d_camera_lock_init(View3D *v3d, RegionView3D *rv3d) -{ - ED_view3d_camera_lock_init_ex(v3d, rv3d, true); -} - -/** - * Apply the view-port transformation back to the camera object. - * - * \return true if the camera is moved. - */ -bool ED_view3d_camera_lock_sync(View3D *v3d, RegionView3D *rv3d) -{ - if (ED_view3d_camera_lock_check(v3d, rv3d)) { - ObjectTfmProtectedChannels obtfm; - Object *root_parent; - - if ((U.uiflag & USER_CAM_LOCK_NO_PARENT) == 0 && (root_parent = v3d->camera->parent)) { - Object *ob_update; - float tmat[4][4]; - float imat[4][4]; - float view_mat[4][4]; - float diff_mat[4][4]; - float parent_mat[4][4]; - - while (root_parent->parent) { - root_parent = root_parent->parent; - } - - ED_view3d_to_m4(view_mat, rv3d->ofs, rv3d->viewquat, rv3d->dist); - - normalize_m4_m4(tmat, v3d->camera->obmat); - - invert_m4_m4(imat, tmat); - mul_m4_m4m4(diff_mat, view_mat, imat); - - mul_m4_m4m4(parent_mat, diff_mat, root_parent->obmat); - - BKE_object_tfm_protected_backup(root_parent, &obtfm); - BKE_object_apply_mat4(root_parent, parent_mat, true, false); - BKE_object_tfm_protected_restore(root_parent, &obtfm, root_parent->protectflag); - - ob_update = v3d->camera; - while (ob_update) { - DEG_id_tag_update(&ob_update->id, OB_RECALC_OB); - WM_main_add_notifier(NC_OBJECT | ND_TRANSFORM, ob_update); - ob_update = ob_update->parent; - } - } - else { - /* always maintain the same scale */ - const short protect_scale_all = (OB_LOCK_SCALEX | OB_LOCK_SCALEY | OB_LOCK_SCALEZ); - BKE_object_tfm_protected_backup(v3d->camera, &obtfm); - ED_view3d_to_object(v3d->camera, rv3d->ofs, rv3d->viewquat, rv3d->dist); - BKE_object_tfm_protected_restore(v3d->camera, &obtfm, v3d->camera->protectflag | protect_scale_all); - - DEG_id_tag_update(&v3d->camera->id, OB_RECALC_OB); - WM_main_add_notifier(NC_OBJECT | ND_TRANSFORM, v3d->camera); - } - - return true; - } - else { - return false; - } -} - -bool ED_view3d_camera_autokey( - Scene *scene, ID *id_key, - struct bContext *C, const bool do_rotate, const bool do_translate) -{ - if (autokeyframe_cfra_can_key(scene, id_key)) { - const float cfra = (float)CFRA; - ListBase dsources = {NULL, NULL}; - - /* add data-source override for the camera object */ - ANIM_relative_keyingset_add_source(&dsources, id_key, NULL, NULL); - - /* insert keyframes - * 1) on the first frame - * 2) on each subsequent frame - * TODO: need to check in future that frame changed before doing this - */ - if (do_rotate) { - struct KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, ANIM_KS_ROTATION_ID); - ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra); - } - if (do_translate) { - struct KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, ANIM_KS_LOCATION_ID); - ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra); - } - - /* free temp data */ - BLI_freelistN(&dsources); - - return true; - } - else { - return false; - } -} - -/** - * Call after modifying a locked view. - * - * \note Not every view edit currently auto-keys (numpad for eg), - * this is complicated because of smoothview. - */ -bool ED_view3d_camera_lock_autokey( - View3D *v3d, RegionView3D *rv3d, - struct bContext *C, const bool do_rotate, const bool do_translate) -{ - /* similar to ED_view3d_cameracontrol_update */ - if (ED_view3d_camera_lock_check(v3d, rv3d)) { - Scene *scene = CTX_data_scene(C); - ID *id_key; - Object *root_parent; - if ((U.uiflag & USER_CAM_LOCK_NO_PARENT) == 0 && (root_parent = v3d->camera->parent)) { - while (root_parent->parent) { - root_parent = root_parent->parent; - } - id_key = &root_parent->id; - } - else { - id_key = &v3d->camera->id; - } - - return ED_view3d_camera_autokey(scene, id_key, C, do_rotate, do_translate); - } - else { - return false; - } -} - -/** - * For viewport operators that exit camera persp. - * - * \note This differs from simply setting ``rv3d->persp = persp`` because it - * sets the ``ofs`` and ``dist`` values of the viewport so it matches the camera, - * otherwise switching out of camera view may jump to a different part of the scene. - */ -static void view3d_persp_switch_from_camera(View3D *v3d, RegionView3D *rv3d, const char persp) -{ - BLI_assert(rv3d->persp == RV3D_CAMOB); - BLI_assert(persp != RV3D_CAMOB); - - if (v3d->camera) { - rv3d->dist = ED_view3d_offset_distance(v3d->camera->obmat, rv3d->ofs, VIEW3D_DIST_FALLBACK); - ED_view3d_from_object(v3d->camera, rv3d->ofs, rv3d->viewquat, &rv3d->dist, NULL); - } - - if (!ED_view3d_camera_lock_check(v3d, rv3d)) { - rv3d->persp = persp; - } -} - -/* ********************* box view support ***************** */ - -static void view3d_boxview_clip(ScrArea *sa) -{ - ARegion *ar; - BoundBox *bb = MEM_callocN(sizeof(BoundBox), "clipbb"); - float clip[6][4]; - float x1 = 0.0f, y1 = 0.0f, z1 = 0.0f, ofs[3] = {0.0f, 0.0f, 0.0f}; - int val; - - /* create bounding box */ - for (ar = sa->regionbase.first; ar; ar = ar->next) { - if (ar->regiontype == RGN_TYPE_WINDOW) { - RegionView3D *rv3d = ar->regiondata; - - if (rv3d->viewlock & RV3D_BOXCLIP) { - if (ELEM(rv3d->view, RV3D_VIEW_TOP, RV3D_VIEW_BOTTOM)) { - if (ar->winx > ar->winy) x1 = rv3d->dist; - else x1 = ar->winx * rv3d->dist / ar->winy; - - if (ar->winx > ar->winy) y1 = ar->winy * rv3d->dist / ar->winx; - else y1 = rv3d->dist; - copy_v2_v2(ofs, rv3d->ofs); - } - else if (ELEM(rv3d->view, RV3D_VIEW_FRONT, RV3D_VIEW_BACK)) { - ofs[2] = rv3d->ofs[2]; - - if (ar->winx > ar->winy) z1 = ar->winy * rv3d->dist / ar->winx; - else z1 = rv3d->dist; - } - } - } - } - - for (val = 0; val < 8; val++) { - if (ELEM(val, 0, 3, 4, 7)) - bb->vec[val][0] = -x1 - ofs[0]; - else - bb->vec[val][0] = x1 - ofs[0]; - - if (ELEM(val, 0, 1, 4, 5)) - bb->vec[val][1] = -y1 - ofs[1]; - else - bb->vec[val][1] = y1 - ofs[1]; - - if (val > 3) - bb->vec[val][2] = -z1 - ofs[2]; - else - bb->vec[val][2] = z1 - ofs[2]; - } - - /* normals for plane equations */ - normal_tri_v3(clip[0], bb->vec[0], bb->vec[1], bb->vec[4]); - normal_tri_v3(clip[1], bb->vec[1], bb->vec[2], bb->vec[5]); - normal_tri_v3(clip[2], bb->vec[2], bb->vec[3], bb->vec[6]); - normal_tri_v3(clip[3], bb->vec[3], bb->vec[0], bb->vec[7]); - normal_tri_v3(clip[4], bb->vec[4], bb->vec[5], bb->vec[6]); - normal_tri_v3(clip[5], bb->vec[0], bb->vec[2], bb->vec[1]); - - /* then plane equations */ - for (val = 0; val < 6; val++) { - clip[val][3] = -dot_v3v3(clip[val], bb->vec[val % 5]); - } - - /* create bounding box */ - for (ar = sa->regionbase.first; ar; ar = ar->next) { - if (ar->regiontype == RGN_TYPE_WINDOW) { - RegionView3D *rv3d = ar->regiondata; - - if (rv3d->viewlock & RV3D_BOXCLIP) { - rv3d->rflag |= RV3D_CLIPPING; - memcpy(rv3d->clip, clip, sizeof(clip)); - if (rv3d->clipbb) MEM_freeN(rv3d->clipbb); - rv3d->clipbb = MEM_dupallocN(bb); - } - } - } - MEM_freeN(bb); -} - -/** - * Find which axis values are shared between both views and copy to \a rv3d_dst - * taking axis flipping into account. - */ -static void view3d_boxview_sync_axis(RegionView3D *rv3d_dst, RegionView3D *rv3d_src) -{ - /* absolute axis values above this are considered to be set (will be ~1.0f) */ - const float axis_eps = 0.5f; - float viewinv[4]; - - /* use the view rotation to identify which axis to sync on */ - float view_axis_all[4][3] = { - {1.0f, 0.0f, 0.0f}, - {0.0f, 1.0f, 0.0f}, - {1.0f, 0.0f, 0.0f}, - {0.0f, 1.0f, 0.0f}}; - - float *view_src_x = &view_axis_all[0][0]; - float *view_src_y = &view_axis_all[1][0]; - - float *view_dst_x = &view_axis_all[2][0]; - float *view_dst_y = &view_axis_all[3][0]; - int i; - - - /* we could use rv3d->viewinv, but better not depend on view matrix being updated */ - if (UNLIKELY(ED_view3d_quat_from_axis_view(rv3d_src->view, viewinv) == false)) { - return; - } - invert_qt_normalized(viewinv); - mul_qt_v3(viewinv, view_src_x); - mul_qt_v3(viewinv, view_src_y); - - if (UNLIKELY(ED_view3d_quat_from_axis_view(rv3d_dst->view, viewinv) == false)) { - return; - } - invert_qt_normalized(viewinv); - mul_qt_v3(viewinv, view_dst_x); - mul_qt_v3(viewinv, view_dst_y); +/* -------------------------------------------------------------------- */ +/** \name Generic View Operator Properties + * \{ */ - /* check source and dest have a matching axis */ - for (i = 0; i < 3; i++) { - if (((fabsf(view_src_x[i]) > axis_eps) || (fabsf(view_src_y[i]) > axis_eps)) && - ((fabsf(view_dst_x[i]) > axis_eps) || (fabsf(view_dst_y[i]) > axis_eps))) - { - rv3d_dst->ofs[i] = rv3d_src->ofs[i]; - } - } -} +enum eV3D_OpPropFlag { + V3D_OP_PROP_MOUSE_CO = (1 << 0), + V3D_OP_PROP_DELTA = (1 << 1), + V3D_OP_PROP_USE_ALL_REGIONS = (1 << 2), + V3D_OP_PROP_USE_MOUSE_INIT = (1 << 3), +}; -/* sync center/zoom view of region to others, for view transforms */ -static void view3d_boxview_sync(ScrArea *sa, ARegion *ar) +static void view3d_operator_properties_common(wmOperatorType *ot, const enum eV3D_OpPropFlag flag) { - ARegion *artest; - RegionView3D *rv3d = ar->regiondata; - short clip = 0; - - for (artest = sa->regionbase.first; artest; artest = artest->next) { - if (artest != ar && artest->regiontype == RGN_TYPE_WINDOW) { - RegionView3D *rv3dtest = artest->regiondata; - - if (rv3dtest->viewlock & RV3D_LOCKED) { - rv3dtest->dist = rv3d->dist; - view3d_boxview_sync_axis(rv3dtest, rv3d); - clip |= rv3dtest->viewlock & RV3D_BOXCLIP; - - ED_region_tag_redraw(artest); - } - } + if (flag & V3D_OP_PROP_MOUSE_CO) { + PropertyRNA *prop; + prop = RNA_def_int(ot->srna, "mx", 0, 0, INT_MAX, "Region Position X", "", 0, INT_MAX); + RNA_def_property_flag(prop, PROP_HIDDEN); + prop = RNA_def_int(ot->srna, "my", 0, 0, INT_MAX, "Region Position Y", "", 0, INT_MAX); + RNA_def_property_flag(prop, PROP_HIDDEN); } - - if (clip) { - view3d_boxview_clip(sa); + if (flag & V3D_OP_PROP_DELTA) { + RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX); } -} - -/* for home, center etc */ -void view3d_boxview_copy(ScrArea *sa, ARegion *ar) -{ - ARegion *artest; - RegionView3D *rv3d = ar->regiondata; - bool clip = false; - - for (artest = sa->regionbase.first; artest; artest = artest->next) { - if (artest != ar && artest->regiontype == RGN_TYPE_WINDOW) { - RegionView3D *rv3dtest = artest->regiondata; - - if (rv3dtest->viewlock) { - rv3dtest->dist = rv3d->dist; - copy_v3_v3(rv3dtest->ofs, rv3d->ofs); - ED_region_tag_redraw(artest); - - clip |= ((rv3dtest->viewlock & RV3D_BOXCLIP) != 0); - } - } + if (flag & V3D_OP_PROP_USE_ALL_REGIONS) { + PropertyRNA *prop; + prop = RNA_def_boolean(ot->srna, "use_all_regions", 0, "All Regions", "View selected for all regions"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); } - - if (clip) { - view3d_boxview_clip(sa); + if (flag & V3D_OP_PROP_USE_MOUSE_INIT) { + /* Disable when view operators are initialized from buttons. */ + PropertyRNA *prop; + prop = RNA_def_boolean(ot->srna, "use_mouse_init", true, "Mouse Init", "Use initial mouse position"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN); } } -/* 'clip' is used to know if our clip setting has changed */ -void ED_view3d_quadview_update(ScrArea *sa, ARegion *ar, bool do_clip) -{ - ARegion *ar_sync = NULL; - RegionView3D *rv3d = ar->regiondata; - short viewlock; - /* this function copies flags from the first of the 3 other quadview - * regions to the 2 other, so it assumes this is the region whose - * properties are always being edited, weak */ - viewlock = rv3d->viewlock; - - if ((viewlock & RV3D_LOCKED) == 0) { - do_clip = (viewlock & RV3D_BOXCLIP) != 0; - viewlock = 0; - } - else if ((viewlock & RV3D_BOXVIEW) == 0 && (viewlock & RV3D_BOXCLIP) != 0) { - do_clip = true; - viewlock &= ~RV3D_BOXCLIP; - } - - for (; ar; ar = ar->prev) { - if (ar->alignment == RGN_ALIGN_QSPLIT) { - rv3d = ar->regiondata; - rv3d->viewlock = viewlock; - - if (do_clip && (viewlock & RV3D_BOXCLIP) == 0) { - rv3d->rflag &= ~RV3D_BOXCLIP; - } - - /* use ar_sync so we sync with one of the aligned views below - * else the view jumps on changing view settings like 'clip' - * since it copies from the perspective view */ - ar_sync = ar; - } - } - - if (rv3d->viewlock & RV3D_BOXVIEW) { - view3d_boxview_sync(sa, ar_sync ? ar_sync : sa->regionbase.last); - } - - /* ensure locked regions have an axis, locked user views don't make much sense */ - if (viewlock & RV3D_LOCKED) { - int index_qsplit = 0; - for (ar = sa->regionbase.first; ar; ar = ar->next) { - if (ar->alignment == RGN_ALIGN_QSPLIT) { - rv3d = ar->regiondata; - if (rv3d->viewlock) { - if (!RV3D_VIEW_IS_AXIS(rv3d->view)) { - rv3d->view = ED_view3d_lock_view_from_index(index_qsplit); - rv3d->persp = RV3D_ORTHO; - ED_view3d_lock(rv3d); - } - } - index_qsplit++; - } - } - } - - ED_area_tag_redraw(sa); -} +/** \} */ -/* ************************** init for view ops **********************************/ +/* -------------------------------------------------------------------- */ +/** \name Generic View Operator Custom-Data + * \{ */ typedef struct ViewOpsData { - /* context pointers (assigned by viewops_data_alloc) */ + /** Context pointers (assigned by #viewops_data_alloc). */ Scene *scene; ScrArea *sa; ARegion *ar; View3D *v3d; RegionView3D *rv3d; + Depsgraph *depsgraph; - /* needed for continuous zoom */ + /** Needed for continuous zoom. */ wmTimer *timer; - double timer_lastdraw; - float oldquat[4]; - float viewquat[4]; /* working copy of rv3d->viewquat */ - float trackvec[3]; - float mousevec[3]; /* dolly only */ + /** Viewport state on initialization, don't change afterwards. */ + struct { + float dist; + float camzoom; + float quat[4]; + /** #wmEvent.x, y. */ + int event_xy[2]; + /** Offset to use when #VIEWOPS_FLAG_USE_MOUSE_INIT is not set. + * so we can simulate pressing in the middle of the screen. */ + int event_xy_offset[2]; + /** #wmEvent.type that triggered the operator. */ + int event_type; + float ofs[3]; + /** Initial distance to 'ofs'. */ + float zfac; + + /** Trackball rotation only. */ + float trackvec[3]; + /** Dolly only. */ + float mousevec[3]; + } init; + + /** Previous state (previous modal event handled). */ + struct { + int event_xy[2]; + /** For operators that use time-steps (continuous zoom). */ + double time; + } prev; + + /** Current state. */ + struct { + /** Working copy of #RegionView3D.viewquat, needed for rotation calculation + * so we can apply snap to the view-port while keeping the unsnapped rotation + * here to use when snap is disabled and for continued calculation. */ + float viewquat[4]; + } curr; + float reverse; - float dist_prev, camzoom_prev; - float grid, far; bool axis_snap; /* view rotate only */ - float zfac; - /* use for orbit selection and auto-dist */ - float ofs[3], dyn_ofs[3]; + /** Use for orbit selection and auto-dist. */ + float dyn_ofs[3]; bool use_dyn_ofs; - - int origx, origy, oldx, oldy; - int origkey; /* the key that triggered the operator */ - } ViewOpsData; #define TRACKBALLSIZE (1.1f) -static void calctrackballvec(const rcti *rect, int mx, int my, float vec[3]) +static void calctrackballvec(const rcti *rect, const int event_xy[2], float vec[3]) { const float radius = TRACKBALLSIZE; const float t = radius / (float)M_SQRT2; float x, y, z, d; /* normalize x and y */ - x = BLI_rcti_cent_x(rect) - mx; + x = BLI_rcti_cent_x(rect) - event_xy[0]; x /= (float)(BLI_rcti_size_x(rect) / 4); - y = BLI_rcti_cent_y(rect) - my; + y = BLI_rcti_cent_y(rect) - event_xy[1]; y /= (float)(BLI_rcti_size_y(rect) / 2); d = sqrtf(x * x + y * y); if (d < t) { /* Inside sphere */ @@ -580,13 +209,6 @@ static void calctrackballvec(const rcti *rect, int mx, int my, float vec[3]) vec[2] = -z; /* yah yah! */ } - -/* -------------------------------------------------------------------- */ -/* ViewOpsData */ - -/** \name Generic View Operator Custom-Data. - * \{ */ - /** * Allocate and fill in context pointers for #ViewOpsData */ @@ -596,6 +218,7 @@ static void viewops_data_alloc(bContext *C, wmOperator *op) /* store data */ op->customdata = vod; + vod->depsgraph = CTX_data_depsgraph(C); vod->scene = CTX_data_scene(C); vod->sa = CTX_wm_area(C); vod->ar = CTX_wm_region(C); @@ -604,7 +227,7 @@ static void viewops_data_alloc(bContext *C, wmOperator *op) } void view3d_orbit_apply_dyn_ofs( - float r_ofs[3], const float ofs_old[3], const float viewquat_old[4], + float r_ofs[3], const float ofs_init[3], const float viewquat_old[4], const float viewquat_new[4], const float dyn_ofs[3]) { float q[4]; @@ -613,7 +236,7 @@ void view3d_orbit_apply_dyn_ofs( invert_qt_normalized(q); - sub_v3_v3v3(r_ofs, ofs_old, dyn_ofs); + sub_v3_v3v3(r_ofs, ofs_init, dyn_ofs); mul_qt_v3(q, r_ofs); add_v3_v3(r_ofs, dyn_ofs); } @@ -702,48 +325,58 @@ static bool view3d_orbit_calc_center(bContext *C, float r_dyn_ofs[3]) return is_set; } -enum eViewOpsOrbit { - VIEWOPS_ORBIT_SELECT = (1 << 0), - VIEWOPS_ORBIT_DEPTH = (1 << 1), +enum eViewOpsFlag { + /** When enabled, rotate around the selection. */ + VIEWOPS_FLAG_ORBIT_SELECT = (1 << 0), + /** When enabled, use the depth under the cursor for navigation. */ + VIEWOPS_FLAG_DEPTH_NAVIGATE = (1 << 1), + /** + * When enabled run #ED_view3d_persp_ensure this may switch out of + * camera view when orbiting or switch from ortho to perspective when auto-persp is enabled. + * Some operations don't require this (view zoom/pan or ndof where subtle rotation is common + * so we don't want it to trigger auto-perspective). */ + VIEWOPS_FLAG_PERSP_ENSURE = (1 << 2), + /** When set, ignore any options that depend on initial cursor location. */ + VIEWOPS_FLAG_USE_MOUSE_INIT = (1 << 3), }; -static enum eViewOpsOrbit viewops_orbit_mode_ex(bool use_select, bool use_depth) +static enum eViewOpsFlag viewops_flag_from_args(bool use_select, bool use_depth) { - enum eViewOpsOrbit flag = 0; + enum eViewOpsFlag flag = 0; if (use_select) { - flag |= VIEWOPS_ORBIT_SELECT; + flag |= VIEWOPS_FLAG_ORBIT_SELECT; } if (use_depth) { - flag |= VIEWOPS_ORBIT_DEPTH; + flag |= VIEWOPS_FLAG_DEPTH_NAVIGATE; } return flag; } -static enum eViewOpsOrbit viewops_orbit_mode(void) +static enum eViewOpsFlag viewops_flag_from_prefs(void) { - return viewops_orbit_mode_ex( + return viewops_flag_from_args( (U.uiflag & USER_ORBIT_SELECTION) != 0, - (U.uiflag & USER_ZBUF_ORBIT) != 0); + (U.uiflag & USER_DEPTH_NAVIGATE) != 0); } /** * Calculate the values for #ViewOpsData - * - * \param use_ensure_persp: When enabled run #view3d_ensure_persp this may switch out of - * camera view when orbiting or switch from ortho to perspective when auto-persp is enabled. - * Some operations don't require this (view zoom/pan or ndof where subtle rotation is common - * so we don't want it to trigger auto-perspective). */ -static void viewops_data_create_ex( +static void viewops_data_create( bContext *C, wmOperator *op, const wmEvent *event, - bool use_ensure_persp, enum eViewOpsOrbit orbit_mode) + enum eViewOpsFlag viewops_flag) { ViewOpsData *vod = op->customdata; RegionView3D *rv3d = vod->rv3d; + /* Could do this more nicely. */ + if ((viewops_flag & VIEWOPS_FLAG_USE_MOUSE_INIT) == 0) { + viewops_flag &= ~VIEWOPS_FLAG_DEPTH_NAVIGATE; + } + /* we need the depth info before changing any viewport options */ - if (orbit_mode & VIEWOPS_ORBIT_DEPTH) { + if (viewops_flag & VIEWOPS_FLAG_DEPTH_NAVIGATE) { EvaluationContext eval_ctx; struct Depsgraph *graph = CTX_data_depsgraph(C); float fallback_depth_pt[3]; @@ -762,8 +395,8 @@ static void viewops_data_create_ex( vod->use_dyn_ofs = false; } - if (use_ensure_persp) { - if (view3d_ensure_persp(vod->v3d, vod->ar)) { + if (viewops_flag & VIEWOPS_FLAG_PERSP_ENSURE) { + if (ED_view3d_persp_ensure(vod->v3d, vod->ar)) { /* If we're switching from camera view to the perspective one, * need to tag viewport update, so camera vuew and borders * are properly updated. @@ -776,25 +409,37 @@ static void viewops_data_create_ex( * we may want to make this optional but for now its needed always */ ED_view3d_camera_lock_init(vod->v3d, vod->rv3d); - vod->dist_prev = rv3d->dist; - vod->camzoom_prev = rv3d->camzoom; - copy_qt_qt(vod->viewquat, rv3d->viewquat); - copy_qt_qt(vod->oldquat, rv3d->viewquat); - vod->origx = vod->oldx = event->x; - vod->origy = vod->oldy = event->y; - vod->origkey = event->type; /* the key that triggered the operator. */ - copy_v3_v3(vod->ofs, rv3d->ofs); + vod->init.dist = rv3d->dist; + vod->init.camzoom = rv3d->camzoom; + copy_qt_qt(vod->init.quat, rv3d->viewquat); + vod->init.event_xy[0] = vod->prev.event_xy[0] = event->x; + vod->init.event_xy[1] = vod->prev.event_xy[1] = event->y; + + if (viewops_flag & VIEWOPS_FLAG_USE_MOUSE_INIT) { + vod->init.event_xy_offset[0] = 0; + vod->init.event_xy_offset[1] = 0; + } + else { + /* Simulate the event starting in the middle of the region. */ + vod->init.event_xy_offset[0] = BLI_rcti_cent_x(&vod->ar->winrct) - event->x; + vod->init.event_xy_offset[1] = BLI_rcti_cent_y(&vod->ar->winrct) - event->y; + } - if (orbit_mode & VIEWOPS_ORBIT_SELECT) { + vod->init.event_type = event->type; + copy_v3_v3(vod->init.ofs, rv3d->ofs); + + copy_qt_qt(vod->curr.viewquat, rv3d->viewquat); + + if (viewops_flag & VIEWOPS_FLAG_ORBIT_SELECT) { float ofs[3]; if (view3d_orbit_calc_center(C, ofs) || (vod->use_dyn_ofs == false)) { vod->use_dyn_ofs = true; negate_v3_v3(vod->dyn_ofs, ofs); - orbit_mode &= ~VIEWOPS_ORBIT_DEPTH; + viewops_flag &= ~VIEWOPS_FLAG_DEPTH_NAVIGATE; } } - if (orbit_mode & VIEWOPS_ORBIT_DEPTH) { + if (viewops_flag & VIEWOPS_FLAG_DEPTH_NAVIGATE) { if (vod->use_dyn_ofs) { if (rv3d->is_persp) { float my_origin[3]; /* original G.vd->ofs */ @@ -821,7 +466,7 @@ static void viewops_data_create_ex( /* find a new ofs value that is along the view axis (rather than the mouse location) */ closest_to_line_v3(dvec, vod->dyn_ofs, my_pivot, my_origin); - vod->dist_prev = rv3d->dist = len_v3v3(my_pivot, dvec); + vod->init.dist = rv3d->dist = len_v3v3(my_pivot, dvec); negate_v3_v3(rv3d->ofs, dvec); } @@ -834,27 +479,26 @@ static void viewops_data_create_ex( negate_v3(rv3d->ofs); } negate_v3(vod->dyn_ofs); - copy_v3_v3(vod->ofs, rv3d->ofs); + copy_v3_v3(vod->init.ofs, rv3d->ofs); } } + /* For dolly */ + ED_view3d_win_to_vector(vod->ar, (const float[2]){UNPACK2(event->mval)}, vod->init.mousevec); + { - /* for dolly */ - const float mval_f[2] = {(float)event->mval[0], - (float)event->mval[1]}; - ED_view3d_win_to_vector(vod->ar, mval_f, vod->mousevec); + const int event_xy_offset[2] = { + event->x + vod->init.event_xy_offset[0], + event->y + vod->init.event_xy_offset[1], + }; + /* For rotation with trackball rotation. */ + calctrackballvec(&vod->ar->winrct, event_xy_offset, vod->init.trackvec); } - /* lookup, we don't pass on v3d to prevent confusement */ - vod->grid = vod->v3d->grid; - vod->far = vod->v3d->far; - - calctrackballvec(&vod->ar->winrct, event->x, event->y, vod->trackvec); - { float tvec[3]; negate_v3_v3(tvec, rv3d->ofs); - vod->zfac = ED_view3d_calc_zfac(rv3d, tvec, NULL); + vod->init.zfac = ED_view3d_calc_zfac(rv3d, tvec, NULL); } vod->reverse = 1.0f; @@ -864,12 +508,6 @@ static void viewops_data_create_ex( rv3d->rflag |= RV3D_NAVIGATING; } -static void viewops_data_create(bContext *C, wmOperator *op, const wmEvent *event, bool use_ensure_persp) -{ - enum eViewOpsOrbit orbit_mode = viewops_orbit_mode(); - viewops_data_create_ex(C, op, event, use_ensure_persp, orbit_mode); -} - static void viewops_data_free(bContext *C, wmOperator *op) { ARegion *ar; @@ -896,10 +534,12 @@ static void viewops_data_free(bContext *C, wmOperator *op) #endif ED_region_tag_redraw(ar); } -/** \} */ +/** \} */ -/* ************************** viewrotate **********************************/ +/* -------------------------------------------------------------------- */ +/** \name View Rotate Operator + * \{ */ enum { VIEW_PASS = 0, @@ -908,12 +548,14 @@ enum { }; /* NOTE: these defines are saved in keymap files, do not change values but just add new ones */ -#define VIEW_MODAL_CONFIRM 1 /* used for all view operations */ -#define VIEWROT_MODAL_AXIS_SNAP_ENABLE 2 -#define VIEWROT_MODAL_AXIS_SNAP_DISABLE 3 -#define VIEWROT_MODAL_SWITCH_ZOOM 4 -#define VIEWROT_MODAL_SWITCH_MOVE 5 -#define VIEWROT_MODAL_SWITCH_ROTATE 6 +enum { + VIEW_MODAL_CONFIRM = 1, /* used for all view operations */ + VIEWROT_MODAL_AXIS_SNAP_ENABLE = 2, + VIEWROT_MODAL_AXIS_SNAP_DISABLE = 3, + VIEWROT_MODAL_SWITCH_ZOOM = 4, + VIEWROT_MODAL_SWITCH_MOVE = 5, + VIEWROT_MODAL_SWITCH_ROTATE = 6, +}; /* called in transform_ops.c, on each regeneration of keymaps */ void viewrotate_modal_keymap(wmKeyConfig *keyconf) @@ -923,7 +565,7 @@ void viewrotate_modal_keymap(wmKeyConfig *keyconf) {VIEWROT_MODAL_AXIS_SNAP_ENABLE, "AXIS_SNAP_ENABLE", 0, "Enable Axis Snap", ""}, {VIEWROT_MODAL_AXIS_SNAP_DISABLE, "AXIS_SNAP_DISABLE", 0, "Disable Axis Snap", ""}, - + {VIEWROT_MODAL_SWITCH_ZOOM, "SWITCH_TO_ZOOM", 0, "Switch to Zoom"}, {VIEWROT_MODAL_SWITCH_MOVE, "SWITCH_TO_MOVE", 0, "Switch to Move"}, @@ -950,17 +592,16 @@ void viewrotate_modal_keymap(wmKeyConfig *keyconf) WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_PRESS, KM_ANY, 0, VIEWROT_MODAL_SWITCH_ZOOM); WM_modalkeymap_add_item(keymap, LEFTSHIFTKEY, KM_PRESS, KM_ANY, 0, VIEWROT_MODAL_SWITCH_MOVE); #endif - + /* assign map to operators */ WM_modalkeymap_assign(keymap, "VIEW3D_OT_rotate"); - } static void viewrotate_apply_dyn_ofs(ViewOpsData *vod, const float viewquat_new[4]) { if (vod->use_dyn_ofs) { RegionView3D *rv3d = vod->rv3d; - view3d_orbit_apply_dyn_ofs(rv3d->ofs, vod->ofs, vod->oldquat, viewquat_new, vod->dyn_ofs); + view3d_orbit_apply_dyn_ofs(rv3d->ofs, vod->init.ofs, vod->init.quat, viewquat_new, vod->dyn_ofs); } } @@ -976,7 +617,7 @@ static void viewrotate_apply_snap(ViewOpsData *vod) int x, y, z; bool found = false; - invert_qt_qt_normalized(viewquat_inv, vod->viewquat); + invert_qt_qt_normalized(viewquat_inv, vod->curr.viewquat); mul_qt_v3(viewquat_inv, zaxis); normalize_v3(zaxis); @@ -1012,7 +653,7 @@ static void viewrotate_apply_snap(ViewOpsData *vod) * for testing roll */ rotation_between_vecs_to_quat(viewquat_align, zaxis_best, zaxis); normalize_qt(viewquat_align); - mul_qt_qtqt(viewquat_align, vod->viewquat, viewquat_align); + mul_qt_qtqt(viewquat_align, vod->curr.viewquat, viewquat_align); normalize_qt(viewquat_align); invert_qt_qt_normalized(viewquat_align_inv, viewquat_align); @@ -1066,7 +707,7 @@ static void viewrotate_apply_snap(ViewOpsData *vod) } } -static void viewrotate_apply(ViewOpsData *vod, int x, int y) +static void viewrotate_apply(ViewOpsData *vod, const int event_xy[2]) { RegionView3D *rv3d = vod->rv3d; @@ -1076,9 +717,15 @@ static void viewrotate_apply(ViewOpsData *vod, int x, int y) float axis[3], q1[4], dvec[3], newvec[3]; float angle; - calctrackballvec(&vod->ar->winrct, x, y, newvec); + { + const int event_xy_offset[2] = { + event_xy[0] + vod->init.event_xy_offset[0], + event_xy[1] + vod->init.event_xy_offset[1], + }; + calctrackballvec(&vod->ar->winrct, event_xy_offset, newvec); + } - sub_v3_v3v3(dvec, newvec, vod->trackvec); + sub_v3_v3v3(dvec, newvec, vod->init.trackvec); angle = (len_v3(dvec) / (2.0f * TRACKBALLSIZE)) * (float)M_PI; @@ -1089,12 +736,12 @@ static void viewrotate_apply(ViewOpsData *vod, int x, int y) * so that the angle of rotation is linearly proportional to * the distance that the mouse is dragged. */ - cross_v3_v3v3(axis, vod->trackvec, newvec); + cross_v3_v3v3(axis, vod->init.trackvec, newvec); axis_angle_to_quat(q1, axis, angle); - mul_qt_qtqt(vod->viewquat, q1, vod->oldquat); + mul_qt_qtqt(vod->curr.viewquat, q1, vod->init.quat); - viewrotate_apply_dyn_ofs(vod, vod->viewquat); + viewrotate_apply_dyn_ofs(vod, vod->curr.viewquat); } else { /* New turntable view code by John Aughey */ @@ -1111,7 +758,7 @@ static void viewrotate_apply(ViewOpsData *vod, int x, int y) const float sensitivity = 0.007f; /* Get the 3x3 matrix and its inverse from the quaternion */ - quat_to_mat3(m, vod->viewquat); + quat_to_mat3(m, vod->curr.viewquat); invert_m3_m3(m_inv, m); /* avoid gimble lock */ @@ -1138,30 +785,30 @@ static void viewrotate_apply(ViewOpsData *vod, int x, int y) /* This can likely be computed directly from the quaternion. */ /* Perform the up/down rotation */ - axis_angle_to_quat(quat_local_x, xaxis, sensitivity * -(y - vod->oldy)); - mul_qt_qtqt(quat_local_x, vod->viewquat, quat_local_x); + axis_angle_to_quat(quat_local_x, xaxis, sensitivity * -(event_xy[1] - vod->prev.event_xy[1])); + mul_qt_qtqt(quat_local_x, vod->curr.viewquat, quat_local_x); /* Perform the orbital rotation */ - axis_angle_to_quat_single(quat_global_z, 'Z', sensitivity * vod->reverse * (x - vod->oldx)); - mul_qt_qtqt(vod->viewquat, quat_local_x, quat_global_z); + axis_angle_to_quat_single(quat_global_z, 'Z', sensitivity * vod->reverse * (event_xy[0] - vod->prev.event_xy[0])); + mul_qt_qtqt(vod->curr.viewquat, quat_local_x, quat_global_z); - viewrotate_apply_dyn_ofs(vod, vod->viewquat); + viewrotate_apply_dyn_ofs(vod, vod->curr.viewquat); } /* avoid precision loss over time */ - normalize_qt(vod->viewquat); + normalize_qt(vod->curr.viewquat); /* use a working copy so view rotation locking doesnt overwrite the locked * rotation back into the view we calculate with */ - copy_qt_qt(rv3d->viewquat, vod->viewquat); + copy_qt_qt(rv3d->viewquat, vod->curr.viewquat); /* check for view snap, * note: don't apply snap to vod->viewquat so the view wont jam up */ if (vod->axis_snap) { viewrotate_apply_snap(vod); } - vod->oldx = x; - vod->oldy = y; + vod->prev.event_xy[0] = event_xy[0]; + vod->prev.event_xy[1] = event_xy[1]; ED_view3d_camera_lock_sync(vod->v3d, rv3d); @@ -1202,12 +849,12 @@ static int viewrotate_modal(bContext *C, wmOperator *op, const wmEvent *event) break; } } - else if (event->type == vod->origkey && event->val == KM_RELEASE) { + else if (event->type == vod->init.event_type && event->val == KM_RELEASE) { event_code = VIEW_CONFIRM; } if (event_code == VIEW_APPLY) { - viewrotate_apply(vod, event->x, event->y); + viewrotate_apply(vod, &event->x); if (ED_screen_animation_playing(CTX_wm_manager(C))) { use_autokey = true; } @@ -1229,41 +876,12 @@ static int viewrotate_modal(bContext *C, wmOperator *op, const wmEvent *event) return ret; } -/** - * Action to take when rotating the view, - * handle auto-persp and logic for switching out of views. - * - * shared with NDOF. - */ -static bool view3d_ensure_persp(struct View3D *v3d, ARegion *ar) -{ - RegionView3D *rv3d = ar->regiondata; - const bool autopersp = (U.uiflag & USER_AUTOPERSP) != 0; - - BLI_assert((rv3d->viewlock & RV3D_LOCKED) == 0); - - if (ED_view3d_camera_lock_check(v3d, rv3d)) - return false; - - if (rv3d->persp != RV3D_PERSP) { - if (rv3d->persp == RV3D_CAMOB) { - /* If autopersp and previous view was an axis one, switch back to PERSP mode, else reuse previous mode. */ - char persp = (autopersp && RV3D_VIEW_IS_AXIS(rv3d->lview)) ? RV3D_PERSP : rv3d->lpersp; - view3d_persp_switch_from_camera(v3d, rv3d, persp); - } - else if (autopersp && RV3D_VIEW_IS_AXIS(rv3d->view)) { - rv3d->persp = RV3D_PERSP; - } - return true; - } - - return false; -} - static int viewrotate_invoke(bContext *C, wmOperator *op, const wmEvent *event) { ViewOpsData *vod; + const bool use_mouse_init = RNA_boolean_get(op->ptr, "use_mouse_init"); + /* makes op->customdata */ viewops_data_alloc(C, op); vod = op->customdata; @@ -1276,29 +894,33 @@ static int viewrotate_invoke(bContext *C, wmOperator *op, const wmEvent *event) ED_view3d_smooth_view_force_finish(C, vod->v3d, vod->ar); - viewops_data_create(C, op, event, true); + viewops_data_create( + C, op, event, + viewops_flag_from_prefs() | + VIEWOPS_FLAG_PERSP_ENSURE | + (use_mouse_init ? VIEWOPS_FLAG_USE_MOUSE_INIT : 0)); if (ELEM(event->type, MOUSEPAN, MOUSEROTATE)) { /* Rotate direction we keep always same */ - int x, y; + int event_xy[2]; if (event->type == MOUSEPAN) { if (U.uiflag2 & USER_TRACKPAD_NATURAL) { - x = 2 * event->x - event->prevx; - y = 2 * event->y - event->prevy; + event_xy[0] = 2 * event->x - event->prevx; + event_xy[1] = 2 * event->y - event->prevy; } else { - x = event->prevx; - y = event->prevy; + event_xy[0] = event->prevx; + event_xy[1] = event->prevy; } } else { /* MOUSEROTATE performs orbital rotation, so y axis delta is set to 0 */ - x = event->prevx; - y = event->y; + event_xy[0] = event->prevx; + event_xy[1] = event->y; } - viewrotate_apply(vod, x, y); + viewrotate_apply(vod, event_xy); ED_view3d_depth_tag_update(vod->rv3d); viewops_data_free(C, op); @@ -1361,13 +983,17 @@ void VIEW3D_OT_rotate(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR; + + view3d_operator_properties_common(ot, V3D_OP_PROP_USE_MOUSE_INIT); } -#ifdef WITH_INPUT_NDOF +/** \} */ +/* -------------------------------------------------------------------- */ /** \name NDOF Utility Functions * \{ */ +#ifdef WITH_INPUT_NDOF #define NDOF_HAS_TRANSLATE ((!ED_view3d_offset_lock_check(v3d, rv3d)) && !is_zero_v3(ndof->tvec)) #define NDOF_HAS_ROTATE (((rv3d->viewlock & RV3D_LOCKED) == 0) && !is_zero_v3(ndof->rvec)) @@ -1417,8 +1043,9 @@ static float view3d_ndof_pan_speed_calc(RegionView3D *rv3d) * * \param has_zoom zoom, otherwise dolly, often `!rv3d->is_persp` since it doesnt make sense to dolly in ortho. */ -static void view3d_ndof_pan_zoom(const struct wmNDOFMotionData *ndof, ScrArea *sa, ARegion *ar, - const bool has_translate, const bool has_zoom) +static void view3d_ndof_pan_zoom( + const struct wmNDOFMotionData *ndof, ScrArea *sa, ARegion *ar, + const bool has_translate, const bool has_zoom) { RegionView3D *rv3d = ar->regiondata; float view_inv[4]; @@ -1479,9 +1106,10 @@ static void view3d_ndof_pan_zoom(const struct wmNDOFMotionData *ndof, ScrArea *s } -static void view3d_ndof_orbit(const struct wmNDOFMotionData *ndof, ScrArea *sa, ARegion *ar, - /* optional, can be NULL*/ - ViewOpsData *vod) +static void view3d_ndof_orbit( + const struct wmNDOFMotionData *ndof, ScrArea *sa, ARegion *ar, + /* optional, can be NULL*/ + ViewOpsData *vod) { View3D *v3d = sa->spacedata.first; RegionView3D *rv3d = ar->regiondata; @@ -1490,7 +1118,7 @@ static void view3d_ndof_orbit(const struct wmNDOFMotionData *ndof, ScrArea *sa, BLI_assert((rv3d->viewlock & RV3D_LOCKED) == 0); - view3d_ensure_persp(v3d, ar); + ED_view3d_persp_ensure(v3d, ar); rv3d->view = RV3D_VIEW_USER; @@ -1525,7 +1153,6 @@ static void view3d_ndof_orbit(const struct wmNDOFMotionData *ndof, ScrArea *sa, axis_angle_to_quat_single(quat, 'Z', angle); mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, quat); - } else { float quat[4]; @@ -1666,14 +1293,16 @@ void view3d_ndof_fly( /** \} */ +/* -------------------------------------------------------------------- */ +/** \name NDOF Operators + * + * - "orbit" navigation (trackball/turntable) + * - zooming + * - panning in rotationally-locked views + * \{ */ -/* -- "orbit" navigation (trackball/turntable) - * -- zooming - * -- panning in rotationally-locked views - */ static int ndof_orbit_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - if (event->type != NDOF_MOTION) { return OPERATOR_CANCELLED; } @@ -1685,9 +1314,9 @@ static int ndof_orbit_invoke(bContext *C, wmOperator *op, const wmEvent *event) const wmNDOFMotionData *ndof = event->customdata; viewops_data_alloc(C, op); - viewops_data_create_ex( + viewops_data_create( C, op, event, - false, viewops_orbit_mode_ex((U.uiflag & USER_ORBIT_SELECTION) != 0, false)); + viewops_flag_from_args((U.uiflag & USER_ORBIT_SELECTION) != 0, false)); vod = op->customdata; ED_view3d_smooth_view_force_finish(C, vod->v3d, vod->ar); @@ -1742,7 +1371,6 @@ void VIEW3D_OT_ndof_orbit(struct wmOperatorType *ot) static int ndof_orbit_zoom_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - if (event->type != NDOF_MOTION) { return OPERATOR_CANCELLED; } @@ -1754,9 +1382,9 @@ static int ndof_orbit_zoom_invoke(bContext *C, wmOperator *op, const wmEvent *ev const wmNDOFMotionData *ndof = event->customdata; viewops_data_alloc(C, op); - viewops_data_create_ex( + viewops_data_create( C, op, event, - false, viewops_orbit_mode_ex((U.uiflag & USER_ORBIT_SELECTION) != 0, false)); + viewops_flag_from_args((U.uiflag & USER_ORBIT_SELECTION) != 0, false)); vod = op->customdata; @@ -1934,8 +1562,11 @@ void VIEW3D_OT_ndof_all(struct wmOperatorType *ot) #endif /* WITH_INPUT_NDOF */ -/* ************************ viewmove ******************************** */ +/** \} */ +/* -------------------------------------------------------------------- */ +/** \name View Move (Pan) Operator + * \{ */ /* NOTE: these defines are saved in keymap files, do not change values but just add new ones */ @@ -1944,7 +1575,7 @@ void viewmove_modal_keymap(wmKeyConfig *keyconf) { static const EnumPropertyItem modal_items[] = { {VIEW_MODAL_CONFIRM, "CONFIRM", 0, "Confirm", ""}, - + {VIEWROT_MODAL_SWITCH_ZOOM, "SWITCH_TO_ZOOM", 0, "Switch to Zoom"}, {VIEWROT_MODAL_SWITCH_ROTATE, "SWITCH_TO_ROTATE", 0, "Switch to Rotate"}, @@ -1968,7 +1599,7 @@ void viewmove_modal_keymap(wmKeyConfig *keyconf) WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_PRESS, KM_ANY, 0, VIEWROT_MODAL_SWITCH_ZOOM); WM_modalkeymap_add_item(keymap, LEFTSHIFTKEY, KM_RELEASE, KM_ANY, 0, VIEWROT_MODAL_SWITCH_ROTATE); #endif - + /* assign map to operators */ WM_modalkeymap_assign(keymap, "VIEW3D_OT_move"); } @@ -1977,13 +1608,13 @@ void viewmove_modal_keymap(wmKeyConfig *keyconf) static void viewmove_apply(ViewOpsData *vod, int x, int y) { if (ED_view3d_offset_lock_check(vod->v3d, vod->rv3d)) { - vod->rv3d->ofs_lock[0] -= ((vod->oldx - x) * 2.0f) / (float)vod->ar->winx; - vod->rv3d->ofs_lock[1] -= ((vod->oldy - y) * 2.0f) / (float)vod->ar->winy; + vod->rv3d->ofs_lock[0] -= ((vod->prev.event_xy[0] - x) * 2.0f) / (float)vod->ar->winx; + vod->rv3d->ofs_lock[1] -= ((vod->prev.event_xy[1] - y) * 2.0f) / (float)vod->ar->winy; } else if ((vod->rv3d->persp == RV3D_CAMOB) && !ED_view3d_camera_lock_check(vod->v3d, vod->rv3d)) { const float zoomfac = BKE_screen_view3d_zoom_to_fac(vod->rv3d->camzoom) * 2.0f; - vod->rv3d->camdx += (vod->oldx - x) / (vod->ar->winx * zoomfac); - vod->rv3d->camdy += (vod->oldy - y) / (vod->ar->winy * zoomfac); + vod->rv3d->camdx += (vod->prev.event_xy[0] - x) / (vod->ar->winx * zoomfac); + vod->rv3d->camdy += (vod->prev.event_xy[1] - y) / (vod->ar->winy * zoomfac); CLAMP(vod->rv3d->camdx, -1.0f, 1.0f); CLAMP(vod->rv3d->camdy, -1.0f, 1.0f); } @@ -1991,18 +1622,19 @@ static void viewmove_apply(ViewOpsData *vod, int x, int y) float dvec[3]; float mval_f[2]; - mval_f[0] = x - vod->oldx; - mval_f[1] = y - vod->oldy; - ED_view3d_win_to_delta(vod->ar, mval_f, dvec, vod->zfac); + mval_f[0] = x - vod->prev.event_xy[0]; + mval_f[1] = y - vod->prev.event_xy[1]; + ED_view3d_win_to_delta(vod->ar, mval_f, dvec, vod->init.zfac); add_v3_v3(vod->rv3d->ofs, dvec); - if (vod->rv3d->viewlock & RV3D_BOXVIEW) + if (vod->rv3d->viewlock & RV3D_BOXVIEW) { view3d_boxview_sync(vod->sa, vod->ar); + } } - vod->oldx = x; - vod->oldy = y; + vod->prev.event_xy[0] = x; + vod->prev.event_xy[1] = y; ED_view3d_camera_lock_sync(vod->v3d, vod->rv3d); @@ -2037,7 +1669,7 @@ static int viewmove_modal(bContext *C, wmOperator *op, const wmEvent *event) break; } } - else if (event->type == vod->origkey && event->val == KM_RELEASE) { + else if (event->type == vod->init.event_type && event->val == KM_RELEASE) { event_code = VIEW_CONFIRM; } @@ -2068,9 +1700,14 @@ static int viewmove_invoke(bContext *C, wmOperator *op, const wmEvent *event) { ViewOpsData *vod; + const bool use_mouse_init = RNA_boolean_get(op->ptr, "use_mouse_init"); + /* makes op->customdata */ viewops_data_alloc(C, op); - viewops_data_create(C, op, event, false); + viewops_data_create( + C, op, event, + viewops_flag_from_prefs() | + (use_mouse_init ? VIEWOPS_FLAG_USE_MOUSE_INIT : 0)); vod = op->customdata; ED_view3d_smooth_view_force_finish(C, vod->v3d, vod->ar); @@ -2079,9 +1716,9 @@ static int viewmove_invoke(bContext *C, wmOperator *op, const wmEvent *event) /* invert it, trackpad scroll follows same principle as 2d windows this way */ viewmove_apply(vod, 2 * event->x - event->prevx, 2 * event->y - event->prevy); ED_view3d_depth_tag_update(vod->rv3d); - + viewops_data_free(C, op); - + return OPERATOR_FINISHED; } else { @@ -2113,9 +1750,16 @@ void VIEW3D_OT_move(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR; + + /* properties */ + view3d_operator_properties_common(ot, V3D_OP_PROP_USE_MOUSE_INIT); } -/* ************************ viewzoom ******************************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View Zoom Operator + * \{ */ /* viewdolly_modal_keymap has an exact copy of this, apply fixes to both */ /* called in transform_ops.c, on each regeneration of keymaps */ @@ -2123,7 +1767,7 @@ void viewzoom_modal_keymap(wmKeyConfig *keyconf) { static const EnumPropertyItem modal_items[] = { {VIEW_MODAL_CONFIRM, "CONFIRM", 0, "Confirm", ""}, - + {VIEWROT_MODAL_SWITCH_ROTATE, "SWITCH_TO_ROTATE", 0, "Switch to Rotate"}, {VIEWROT_MODAL_SWITCH_MOVE, "SWITCH_TO_MOVE", 0, "Switch to Move"}, @@ -2147,14 +1791,17 @@ void viewzoom_modal_keymap(wmKeyConfig *keyconf) WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_RELEASE, KM_ANY, 0, VIEWROT_MODAL_SWITCH_ROTATE); WM_modalkeymap_add_item(keymap, LEFTSHIFTKEY, KM_PRESS, KM_ANY, 0, VIEWROT_MODAL_SWITCH_MOVE); #endif - + /* assign map to operators */ WM_modalkeymap_assign(keymap, "VIEW3D_OT_zoom"); } -static void view_zoom_mouseloc_camera( - Scene *scene, View3D *v3d, - ARegion *ar, float dfac, int mx, int my) +/** + * \param zoom_xy: Optionally zoom to window location (coords compatible w/ #wmEvent.x, y). Use when not NULL. + */ +static void view_zoom_to_window_xy_camera( + Scene *scene, const Depsgraph *depsgraph, View3D *v3d, + ARegion *ar, float dfac, const int zoom_xy[2]) { RegionView3D *rv3d = ar->regiondata; const float zoomfac = BKE_screen_view3d_zoom_to_fac(rv3d->camzoom); @@ -2162,22 +1809,22 @@ static void view_zoom_mouseloc_camera( const float camzoom_new = BKE_screen_view3d_zoom_from_fac(zoomfac_new); - if (U.uiflag & USER_ZOOM_TO_MOUSEPOS) { + if (zoom_xy != NULL) { float zoomfac_px; rctf camera_frame_old; rctf camera_frame_new; - const float pt_src[2] = {mx, my}; + const float pt_src[2] = {zoom_xy[0], zoom_xy[1]}; float pt_dst[2]; float delta_px[2]; - ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &camera_frame_old, false); + ED_view3d_calc_camera_border(scene, depsgraph, ar, v3d, rv3d, &camera_frame_old, false); BLI_rctf_translate(&camera_frame_old, ar->winrct.xmin, ar->winrct.ymin); rv3d->camzoom = camzoom_new; CLAMP(rv3d->camzoom, RV3D_CAMZOOM_MIN, RV3D_CAMZOOM_MAX); - ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &camera_frame_new, false); + ED_view3d_calc_camera_border(scene, depsgraph, ar, v3d, rv3d, &camera_frame_new, false); BLI_rctf_translate(&camera_frame_new, ar->winrct.xmin, ar->winrct.ymin); BLI_rctf_transform_pt_v(&camera_frame_new, &camera_frame_old, pt_dst, pt_src); @@ -2198,12 +1845,15 @@ static void view_zoom_mouseloc_camera( } } -static void view_zoom_mouseloc_3d(ARegion *ar, float dfac, int mx, int my) +/** + * \param zoom_xy: Optionally zoom to window location (coords compatible w/ #wmEvent.x, y). Use when not NULL. + */ +static void view_zoom_to_window_xy_3d(ARegion *ar, float dfac, const int zoom_xy[2]) { RegionView3D *rv3d = ar->regiondata; const float dist_new = rv3d->dist * dfac; - if (U.uiflag & USER_ZOOM_TO_MOUSEPOS) { + if (zoom_xy != NULL) { float dvec[3]; float tvec[3]; float tpos[3]; @@ -2213,8 +1863,8 @@ static void view_zoom_mouseloc_3d(ARegion *ar, float dfac, int mx, int my) negate_v3_v3(tpos, rv3d->ofs); - mval_f[0] = (float)(((mx - ar->winrct.xmin) * 2) - ar->winx) / 2.0f; - mval_f[1] = (float)(((my - ar->winrct.ymin) * 2) - ar->winy) / 2.0f; + mval_f[0] = (float)(((zoom_xy[0] - ar->winrct.xmin) * 2) - ar->winx) / 2.0f; + mval_f[1] = (float)(((zoom_xy[1] - ar->winrct.ymin) * 2) - ar->winy) / 2.0f; /* Project cursor position into 3D space */ zfac = ED_view3d_calc_zfac(rv3d, tpos, NULL); @@ -2240,7 +1890,7 @@ static float viewzoom_scale_value( const rcti *winrct, const short viewzoom, const bool zoom_invert, const bool zoom_invert_force, - const int xy[2], const int xy_orig[2], + const int xy_curr[2], const int xy_init[2], const float val, const float val_orig, double *r_timer_lastdraw) { @@ -2252,10 +1902,10 @@ static float viewzoom_scale_value( float fac; if (U.uiflag & USER_ZOOM_HORIZ) { - fac = (float)(xy_orig[0] - xy[0]); + fac = (float)(xy_init[0] - xy_curr[0]); } else { - fac = (float)(xy_orig[1] - xy[1]); + fac = (float)(xy_init[1] - xy_curr[1]); } if (zoom_invert != zoom_invert_force) { @@ -2273,8 +1923,8 @@ static float viewzoom_scale_value( BLI_rcti_cent_x(winrct), BLI_rcti_cent_y(winrct), }; - float len_new = 5 + len_v2v2_int(ctr, xy); - float len_old = 5 + len_v2v2_int(ctr, xy_orig); + float len_new = 5 + len_v2v2_int(ctr, xy_curr); + float len_old = 5 + len_v2v2_int(ctr, xy_init); /* intentionally ignore 'zoom_invert' for scale */ if (zoom_invert_force) { @@ -2288,12 +1938,12 @@ static float viewzoom_scale_value( float len_old = 5; if (U.uiflag & USER_ZOOM_HORIZ) { - len_new += (winrct->xmax - xy[0]); - len_old += (winrct->xmax - xy_orig[0]); + len_new += (winrct->xmax - (xy_curr[0])); + len_old += (winrct->xmax - (xy_init[0])); } else { - len_new += (winrct->ymax - xy[1]); - len_old += (winrct->ymax - xy_orig[1]); + len_new += (winrct->ymax - (xy_curr[1])); + len_old += (winrct->ymax - (xy_init[1])); } if (zoom_invert != zoom_invert_force) { @@ -2307,25 +1957,48 @@ static float viewzoom_scale_value( return zfac; } +static float viewzoom_scale_value_offset( + const rcti *winrct, + const short viewzoom, + const bool zoom_invert, const bool zoom_invert_force, + const int xy_curr[2], const int xy_init[2], const int xy_offset[2], + const float val, const float val_orig, + double *r_timer_lastdraw) +{ + const int xy_curr_offset[2] = { + xy_curr[0] + xy_offset[0], + xy_curr[1] + xy_offset[1], + }; + const int xy_init_offset[2] = { + xy_init[0] + xy_offset[0], + xy_init[1] + xy_offset[1], + }; + return viewzoom_scale_value( + winrct, viewzoom, zoom_invert, zoom_invert_force, + xy_curr_offset, xy_init_offset, + val, val_orig, r_timer_lastdraw); +} + static void viewzoom_apply_camera( ViewOpsData *vod, const int xy[2], - const short viewzoom, const bool zoom_invert) + const short viewzoom, const bool zoom_invert, const bool zoom_to_pos) { float zfac; - float zoomfac_prev = BKE_screen_view3d_zoom_to_fac(vod->camzoom_prev) * 2.0f; + float zoomfac_prev = BKE_screen_view3d_zoom_to_fac(vod->init.camzoom) * 2.0f; float zoomfac = BKE_screen_view3d_zoom_to_fac(vod->rv3d->camzoom) * 2.0f; - zfac = viewzoom_scale_value( - &vod->ar->winrct, viewzoom, zoom_invert, true, xy, &vod->origx, + zfac = viewzoom_scale_value_offset( + &vod->ar->winrct, viewzoom, zoom_invert, true, + xy, vod->init.event_xy, vod->init.event_xy_offset, zoomfac, zoomfac_prev, - &vod->timer_lastdraw); + &vod->prev.time); if (zfac != 1.0f && zfac != 0.0f) { /* calculate inverted, then invert again (needed because of camera zoom scaling) */ zfac = 1.0f / zfac; - view_zoom_mouseloc_camera( - vod->scene, vod->v3d, - vod->ar, zfac, vod->oldx, vod->oldy); + view_zoom_to_window_xy_camera( + vod->scene, vod->depsgraph, vod->v3d, + vod->ar, zfac, zoom_to_pos ? vod->prev.event_xy : NULL); } ED_region_tag_redraw(vod->ar); @@ -2333,32 +2006,34 @@ static void viewzoom_apply_camera( static void viewzoom_apply_3d( ViewOpsData *vod, const int xy[2], - const short viewzoom, const bool zoom_invert) + const short viewzoom, const bool zoom_invert, const bool zoom_to_pos) { float zfac; float dist_range[2]; ED_view3d_dist_range_get(vod->v3d, dist_range); - zfac = viewzoom_scale_value( - &vod->ar->winrct, viewzoom, zoom_invert, false, xy, &vod->origx, - vod->rv3d->dist, vod->dist_prev, - &vod->timer_lastdraw); + zfac = viewzoom_scale_value_offset( + &vod->ar->winrct, viewzoom, zoom_invert, false, + xy, vod->init.event_xy, vod->init.event_xy_offset, + vod->rv3d->dist, vod->init.dist, + &vod->prev.time); if (zfac != 1.0f) { const float zfac_min = dist_range[0] / vod->rv3d->dist; const float zfac_max = dist_range[1] / vod->rv3d->dist; CLAMP(zfac, zfac_min, zfac_max); - view_zoom_mouseloc_3d( - vod->ar, zfac, vod->oldx, vod->oldy); + view_zoom_to_window_xy_3d( + vod->ar, zfac, zoom_to_pos ? vod->prev.event_xy : NULL); } /* these limits were in old code too */ CLAMP(vod->rv3d->dist, dist_range[0], dist_range[1]); - if (vod->rv3d->viewlock & RV3D_BOXVIEW) + if (vod->rv3d->viewlock & RV3D_BOXVIEW) { view3d_boxview_sync(vod->sa, vod->ar); + } ED_view3d_camera_lock_sync(vod->v3d, vod->rv3d); @@ -2367,15 +2042,15 @@ static void viewzoom_apply_3d( static void viewzoom_apply( ViewOpsData *vod, const int xy[2], - const short viewzoom, const bool zoom_invert) + const short viewzoom, const bool zoom_invert, const bool zoom_to_pos) { if ((vod->rv3d->persp == RV3D_CAMOB) && (vod->rv3d->is_persp && ED_view3d_camera_lock_check(vod->v3d, vod->rv3d)) == 0) { - viewzoom_apply_camera(vod, xy, viewzoom, zoom_invert); + viewzoom_apply_camera(vod, xy, viewzoom, zoom_invert, zoom_to_pos); } else { - viewzoom_apply_3d(vod, xy, viewzoom, zoom_invert); + viewzoom_apply_3d(vod, xy, viewzoom, zoom_invert, zoom_to_pos); } } @@ -2409,12 +2084,16 @@ static int viewzoom_modal(bContext *C, wmOperator *op, const wmEvent *event) break; } } - else if (event->type == vod->origkey && event->val == KM_RELEASE) { + else if (event->type == vod->init.event_type && event->val == KM_RELEASE) { event_code = VIEW_CONFIRM; } if (event_code == VIEW_APPLY) { - viewzoom_apply(vod, &event->x, U.viewzoom, (U.uiflag & USER_ZOOM_INVERT) != 0); + const bool use_mouse_init = RNA_boolean_get(op->ptr, "use_mouse_init"); + viewzoom_apply( + vod, &event->x, U.viewzoom, + (U.uiflag & USER_ZOOM_INVERT) != 0, + (use_mouse_init && (U.uiflag & USER_ZOOM_TO_MOUSEPOS)) ? vod->prev.event_xy : NULL); if (ED_screen_animation_playing(CTX_wm_manager(C))) { use_autokey = true; } @@ -2438,6 +2117,7 @@ static int viewzoom_modal(bContext *C, wmOperator *op, const wmEvent *event) static int viewzoom_exec(bContext *C, wmOperator *op) { + const Depsgraph *depsgraph = CTX_data_depsgraph(C); Scene *scene = CTX_data_scene(C); View3D *v3d; RegionView3D *rv3d; @@ -2447,7 +2127,7 @@ static int viewzoom_exec(bContext *C, wmOperator *op) float dist_range[2]; const int delta = RNA_int_get(op->ptr, "delta"); - int mx, my; + const bool use_mouse_init = RNA_boolean_get(op->ptr, "use_mouse_init"); if (op->customdata) { ViewOpsData *vod = op->customdata; @@ -2463,39 +2143,46 @@ static int viewzoom_exec(bContext *C, wmOperator *op) v3d = sa->spacedata.first; rv3d = ar->regiondata; - mx = RNA_struct_property_is_set(op->ptr, "mx") ? RNA_int_get(op->ptr, "mx") : ar->winx / 2; - my = RNA_struct_property_is_set(op->ptr, "my") ? RNA_int_get(op->ptr, "my") : ar->winy / 2; use_cam_zoom = (rv3d->persp == RV3D_CAMOB) && !(rv3d->is_persp && ED_view3d_camera_lock_check(v3d, rv3d)); + int zoom_xy_buf[2]; + const int *zoom_xy = NULL; + if (use_mouse_init && (U.uiflag & USER_ZOOM_TO_MOUSEPOS)) { + zoom_xy_buf[0] = RNA_struct_property_is_set(op->ptr, "mx") ? RNA_int_get(op->ptr, "mx") : ar->winx / 2; + zoom_xy_buf[1] = RNA_struct_property_is_set(op->ptr, "my") ? RNA_int_get(op->ptr, "my") : ar->winy / 2; + zoom_xy = zoom_xy_buf; + } + ED_view3d_dist_range_get(v3d, dist_range); if (delta < 0) { const float step = 1.2f; /* this min and max is also in viewmove() */ if (use_cam_zoom) { - view_zoom_mouseloc_camera(scene, v3d, ar, step, mx, my); + view_zoom_to_window_xy_camera(scene, depsgraph, v3d, ar, step, zoom_xy); } else { if (rv3d->dist < dist_range[1]) { - view_zoom_mouseloc_3d(ar, step, mx, my); + view_zoom_to_window_xy_3d(ar, step, zoom_xy); } } } else { const float step = 1.0f / 1.2f; if (use_cam_zoom) { - view_zoom_mouseloc_camera(scene, v3d, ar, step, mx, my); + view_zoom_to_window_xy_camera(scene, depsgraph, v3d, ar, step, zoom_xy); } else { if (rv3d->dist > dist_range[0]) { - view_zoom_mouseloc_3d(ar, step, mx, my); + view_zoom_to_window_xy_3d(ar, step, zoom_xy); } } } - if (rv3d->viewlock & RV3D_BOXVIEW) + if (rv3d->viewlock & RV3D_BOXVIEW) { view3d_boxview_sync(sa, ar); + } ED_view3d_depth_tag_update(rv3d); @@ -2509,49 +2196,19 @@ static int viewzoom_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -/* this is an exact copy of viewzoom_modal_keymap */ -/* called in transform_ops.c, on each regeneration of keymaps */ -void viewdolly_modal_keymap(wmKeyConfig *keyconf) -{ - static const EnumPropertyItem modal_items[] = { - {VIEW_MODAL_CONFIRM, "CONFIRM", 0, "Confirm", ""}, - - {VIEWROT_MODAL_SWITCH_ROTATE, "SWITCH_TO_ROTATE", 0, "Switch to Rotate"}, - {VIEWROT_MODAL_SWITCH_MOVE, "SWITCH_TO_MOVE", 0, "Switch to Move"}, - - {0, NULL, 0, NULL, NULL} - }; - - wmKeyMap *keymap = WM_modalkeymap_get(keyconf, "View3D Dolly Modal"); - - /* this function is called for each spacetype, only needs to add map once */ - if (keymap && keymap->modal_items) return; - - keymap = WM_modalkeymap_add(keyconf, "View3D Dolly Modal", modal_items); - - /* items for modal map */ - WM_modalkeymap_add_item(keymap, MIDDLEMOUSE, KM_RELEASE, KM_ANY, 0, VIEW_MODAL_CONFIRM); - WM_modalkeymap_add_item(keymap, ESCKEY, KM_PRESS, KM_ANY, 0, VIEW_MODAL_CONFIRM); - - /* disabled mode switching for now, can re-implement better, later on */ -#if 0 - WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_RELEASE, KM_ANY, 0, VIEWROT_MODAL_SWITCH_ROTATE); - WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_RELEASE, KM_ANY, 0, VIEWROT_MODAL_SWITCH_ROTATE); - WM_modalkeymap_add_item(keymap, LEFTSHIFTKEY, KM_PRESS, KM_ANY, 0, VIEWROT_MODAL_SWITCH_MOVE); -#endif - - /* assign map to operators */ - WM_modalkeymap_assign(keymap, "VIEW3D_OT_dolly"); -} - /* viewdolly_invoke() copied this function, changes here may apply there */ static int viewzoom_invoke(bContext *C, wmOperator *op, const wmEvent *event) { ViewOpsData *vod; + const bool use_mouse_init = RNA_boolean_get(op->ptr, "use_mouse_init"); + /* makes op->customdata */ viewops_data_alloc(C, op); - viewops_data_create(C, op, event, false); + viewops_data_create( + C, op, event, + viewops_flag_from_prefs() | + (use_mouse_init ? VIEWOPS_FLAG_USE_MOUSE_INIT : 0)); vod = op->customdata; ED_view3d_smooth_view_force_finish(C, vod->v3d, vod->ar); @@ -2569,14 +2226,16 @@ static int viewzoom_invoke(bContext *C, wmOperator *op, const wmEvent *event) if (event->type == MOUSEZOOM || event->type == MOUSEPAN) { if (U.uiflag & USER_ZOOM_HORIZ) { - vod->origx = vod->oldx = event->x; - viewzoom_apply(vod, &event->prevx, USER_ZOOM_DOLLY, (U.uiflag & USER_ZOOM_INVERT) != 0); + vod->init.event_xy[0] = vod->prev.event_xy[0] = event->x; } else { /* Set y move = x move as MOUSEZOOM uses only x axis to pass magnification value */ - vod->origy = vod->oldy = vod->origy + event->x - event->prevx; - viewzoom_apply(vod, &event->prevx, USER_ZOOM_DOLLY, (U.uiflag & USER_ZOOM_INVERT) != 0); + vod->init.event_xy[1] = vod->prev.event_xy[1] = vod->init.event_xy[1] + event->x - event->prevx; } + viewzoom_apply( + vod, &event->prevx, USER_ZOOM_DOLLY, + (U.uiflag & USER_ZOOM_INVERT) != 0, + (use_mouse_init && (U.uiflag & USER_ZOOM_TO_MOUSEPOS))); ED_view3d_camera_lock_autokey(vod->v3d, vod->rv3d, C, false, true); ED_view3d_depth_tag_update(vod->rv3d); @@ -2588,7 +2247,7 @@ static int viewzoom_invoke(bContext *C, wmOperator *op, const wmEvent *event) if (U.viewzoom == USER_ZOOM_CONT) { /* needs a timer to continue redrawing */ vod->timer = WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER, 0.01f); - vod->timer_lastdraw = PIL_check_seconds_timer(); + vod->prev.time = PIL_check_seconds_timer(); } /* add temp handler */ @@ -2607,8 +2266,6 @@ static void viewzoom_cancel(bContext *C, wmOperator *op) void VIEW3D_OT_zoom(wmOperatorType *ot) { - PropertyRNA *prop; - /* identifiers */ ot->name = "Zoom View"; ot->description = "Zoom in/out in the view"; @@ -2624,15 +2281,56 @@ void VIEW3D_OT_zoom(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR; - RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX); - prop = RNA_def_int(ot->srna, "mx", 0, 0, INT_MAX, "Zoom Position X", "", 0, INT_MAX); - RNA_def_property_flag(prop, PROP_HIDDEN); - prop = RNA_def_int(ot->srna, "my", 0, 0, INT_MAX, "Zoom Position Y", "", 0, INT_MAX); - RNA_def_property_flag(prop, PROP_HIDDEN); + /* properties */ + view3d_operator_properties_common( + ot, + V3D_OP_PROP_DELTA | V3D_OP_PROP_MOUSE_CO | V3D_OP_PROP_USE_MOUSE_INIT); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View Dolly Operator + * + * Like zoom but translates the view offset along the view direction + * which avoids #RegionView3D.dist approaching zero. + * \{ */ + +/* this is an exact copy of viewzoom_modal_keymap */ +/* called in transform_ops.c, on each regeneration of keymaps */ +void viewdolly_modal_keymap(wmKeyConfig *keyconf) +{ + static const EnumPropertyItem modal_items[] = { + {VIEW_MODAL_CONFIRM, "CONFIRM", 0, "Confirm", ""}, + + {VIEWROT_MODAL_SWITCH_ROTATE, "SWITCH_TO_ROTATE", 0, "Switch to Rotate"}, + {VIEWROT_MODAL_SWITCH_MOVE, "SWITCH_TO_MOVE", 0, "Switch to Move"}, + + {0, NULL, 0, NULL, NULL} + }; + + wmKeyMap *keymap = WM_modalkeymap_get(keyconf, "View3D Dolly Modal"); + + /* this function is called for each spacetype, only needs to add map once */ + if (keymap && keymap->modal_items) return; + + keymap = WM_modalkeymap_add(keyconf, "View3D Dolly Modal", modal_items); + + /* items for modal map */ + WM_modalkeymap_add_item(keymap, MIDDLEMOUSE, KM_RELEASE, KM_ANY, 0, VIEW_MODAL_CONFIRM); + WM_modalkeymap_add_item(keymap, ESCKEY, KM_PRESS, KM_ANY, 0, VIEW_MODAL_CONFIRM); + + /* disabled mode switching for now, can re-implement better, later on */ +#if 0 + WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_RELEASE, KM_ANY, 0, VIEWROT_MODAL_SWITCH_ROTATE); + WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_RELEASE, KM_ANY, 0, VIEWROT_MODAL_SWITCH_ROTATE); + WM_modalkeymap_add_item(keymap, LEFTSHIFTKEY, KM_PRESS, KM_ANY, 0, VIEWROT_MODAL_SWITCH_MOVE); +#endif + + /* assign map to operators */ + WM_modalkeymap_assign(keymap, "VIEW3D_OT_dolly"); +} -/* ************************ viewdolly ******************************** */ static bool viewdolly_offset_lock_check(bContext *C, wmOperator *op) { View3D *v3d = CTX_wm_view3d(C); @@ -2646,13 +2344,13 @@ static bool viewdolly_offset_lock_check(bContext *C, wmOperator *op) } } -static void view_dolly_mouseloc(ARegion *ar, float orig_ofs[3], float dvec[3], float dfac) +static void view_dolly_to_vector_3d(ARegion *ar, float orig_ofs[3], float dvec[3], float dfac) { RegionView3D *rv3d = ar->regiondata; madd_v3_v3v3fl(rv3d->ofs, orig_ofs, dvec, -(1.0f - dfac)); } -static void viewdolly_apply(ViewOpsData *vod, int x, int y, const short zoom_invert) +static void viewdolly_apply(ViewOpsData *vod, const int xy[2], const short zoom_invert) { float zfac = 1.0; @@ -2660,24 +2358,27 @@ static void viewdolly_apply(ViewOpsData *vod, int x, int y, const short zoom_inv float len1, len2; if (U.uiflag & USER_ZOOM_HORIZ) { - len1 = (vod->ar->winrct.xmax - x) + 5; - len2 = (vod->ar->winrct.xmax - vod->origx) + 5; + len1 = (vod->ar->winrct.xmax - xy[0]) + 5; + len2 = (vod->ar->winrct.xmax - vod->init.event_xy[0]) + 5; } else { - len1 = (vod->ar->winrct.ymax - y) + 5; - len2 = (vod->ar->winrct.ymax - vod->origy) + 5; + len1 = (vod->ar->winrct.ymax - xy[1]) + 5; + len2 = (vod->ar->winrct.ymax - vod->init.event_xy[1]) + 5; } - if (zoom_invert) + if (zoom_invert) { SWAP(float, len1, len2); + } zfac = 1.0f + ((len1 - len2) * 0.01f * vod->rv3d->dist); } - if (zfac != 1.0f) - view_dolly_mouseloc(vod->ar, vod->ofs, vod->mousevec, zfac); + if (zfac != 1.0f) { + view_dolly_to_vector_3d(vod->ar, vod->init.ofs, vod->init.mousevec, zfac); + } - if (vod->rv3d->viewlock & RV3D_BOXVIEW) + if (vod->rv3d->viewlock & RV3D_BOXVIEW) { view3d_boxview_sync(vod->sa, vod->ar); + } ED_view3d_camera_lock_sync(vod->v3d, vod->rv3d); @@ -2711,12 +2412,12 @@ static int viewdolly_modal(bContext *C, wmOperator *op, const wmEvent *event) break; } } - else if (event->type == vod->origkey && event->val == KM_RELEASE) { + else if (event->type == vod->init.event_type && event->val == KM_RELEASE) { event_code = VIEW_CONFIRM; } if (event_code == VIEW_APPLY) { - viewdolly_apply(vod, event->x, event->y, (U.uiflag & USER_ZOOM_INVERT) != 0); + viewdolly_apply(vod, &event->x, (U.uiflag & USER_ZOOM_INVERT) != 0); if (ED_screen_animation_playing(CTX_wm_manager(C))) { use_autokey = true; } @@ -2753,7 +2454,7 @@ static int viewdolly_exec(bContext *C, wmOperator *op) sa = vod->sa; ar = vod->ar; - copy_v3_v3(mousevec, vod->mousevec); + copy_v3_v3(mousevec, vod->init.mousevec); } else { sa = CTX_wm_area(C); @@ -2765,20 +2466,18 @@ static int viewdolly_exec(bContext *C, wmOperator *op) v3d = sa->spacedata.first; rv3d = ar->regiondata; + const bool use_mouse_init = RNA_boolean_get(op->ptr, "use_mouse_init"); + /* overwrite the mouse vector with the view direction (zoom into the center) */ - if ((U.uiflag & USER_ZOOM_TO_MOUSEPOS) == 0) { + if ((use_mouse_init && (U.uiflag & USER_ZOOM_TO_MOUSEPOS)) == 0) { normalize_v3_v3(mousevec, rv3d->viewinv[2]); } - if (delta < 0) { - view_dolly_mouseloc(ar, rv3d->ofs, mousevec, 0.2f); - } - else { - view_dolly_mouseloc(ar, rv3d->ofs, mousevec, 1.8f); - } + view_dolly_to_vector_3d(ar, rv3d->ofs, mousevec, delta < 0 ? 0.2f : 1.8f); - if (rv3d->viewlock & RV3D_BOXVIEW) + if (rv3d->viewlock & RV3D_BOXVIEW) { view3d_boxview_sync(sa, ar); + } ED_view3d_depth_tag_update(rv3d); @@ -2816,7 +2515,7 @@ static int viewdolly_invoke(bContext *C, wmOperator *op, const wmEvent *event) if (vod->rv3d->persp != RV3D_PERSP) { if (vod->rv3d->persp == RV3D_CAMOB) { /* ignore rv3d->lpersp because dolly only makes sense in perspective mode */ - view3d_persp_switch_from_camera(vod->v3d, vod->rv3d, RV3D_PERSP); + ED_view3d_persp_switch_from_camera(vod->v3d, vod->rv3d, RV3D_PERSP); } else { vod->rv3d->persp = RV3D_PERSP; @@ -2824,7 +2523,12 @@ static int viewdolly_invoke(bContext *C, wmOperator *op, const wmEvent *event) ED_region_tag_redraw(vod->ar); } - viewops_data_create(C, op, event, false); + const bool use_mouse_init = RNA_boolean_get(op->ptr, "use_mouse_init"); + + viewops_data_create( + C, op, event, + viewops_flag_from_prefs() | + (use_mouse_init ? VIEWOPS_FLAG_USE_MOUSE_INIT : 0)); /* if one or the other zoom position aren't set, set from event */ @@ -2838,24 +2542,22 @@ static int viewdolly_invoke(bContext *C, wmOperator *op, const wmEvent *event) } else { /* overwrite the mouse vector with the view direction (zoom into the center) */ - if ((U.uiflag & USER_ZOOM_TO_MOUSEPOS) == 0) { - negate_v3_v3(vod->mousevec, vod->rv3d->viewinv[2]); - normalize_v3(vod->mousevec); + if ((use_mouse_init && (U.uiflag & USER_ZOOM_TO_MOUSEPOS)) == 0) { + negate_v3_v3(vod->init.mousevec, vod->rv3d->viewinv[2]); + normalize_v3(vod->init.mousevec); } if (event->type == MOUSEZOOM) { /* Bypass Zoom invert flag for track pads (pass false always) */ if (U.uiflag & USER_ZOOM_HORIZ) { - vod->origx = vod->oldx = event->x; - viewdolly_apply(vod, event->prevx, event->prevy, (U.uiflag & USER_ZOOM_INVERT) == 0); + vod->init.event_xy[0] = vod->prev.event_xy[0] = event->x; } else { - /* Set y move = x move as MOUSEZOOM uses only x axis to pass magnification value */ - vod->origy = vod->oldy = vod->origy + event->x - event->prevx; - viewdolly_apply(vod, event->prevx, event->prevy, (U.uiflag & USER_ZOOM_INVERT) == 0); + vod->init.event_xy[1] = vod->prev.event_xy[1] = vod->init.event_xy[1] + event->x - event->prevx; } + viewdolly_apply(vod, &event->prevx, (U.uiflag & USER_ZOOM_INVERT) == 0); ED_view3d_depth_tag_update(vod->rv3d); viewops_data_free(C, op); @@ -2893,14 +2595,23 @@ void VIEW3D_OT_dolly(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR; - RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX); - RNA_def_int(ot->srna, "mx", 0, 0, INT_MAX, "Zoom Position X", "", 0, INT_MAX); - RNA_def_int(ot->srna, "my", 0, 0, INT_MAX, "Zoom Position Y", "", 0, INT_MAX); + /* properties */ + view3d_operator_properties_common( + ot, V3D_OP_PROP_DELTA | V3D_OP_PROP_MOUSE_CO | V3D_OP_PROP_USE_MOUSE_INIT); } -static void view3d_from_minmax(bContext *C, View3D *v3d, ARegion *ar, - const float min[3], const float max[3], - bool ok_dist, const int smooth_viewtx) +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View All Operator + * + * Move & Zoom the view to fit all of it's contents. + * \{ */ + +static void view3d_from_minmax( + bContext *C, View3D *v3d, ARegion *ar, + const float min[3], const float max[3], + bool ok_dist, const int smooth_viewtx) { RegionView3D *rv3d = ar->regiondata; float afm[3]; @@ -2966,10 +2677,13 @@ static void view3d_from_minmax(bContext *C, View3D *v3d, ARegion *ar, /* smooth view does viewlock RV3D_BOXVIEW copy */ } -/* same as view3d_from_minmax but for all regions (except cameras) */ -static void view3d_from_minmax_multi(bContext *C, View3D *v3d, - const float min[3], const float max[3], - const bool ok_dist, const int smooth_viewtx) +/** + * Same as #view3d_from_minmax but for all regions (except cameras). + */ +static void view3d_from_minmax_multi( + bContext *C, View3D *v3d, + const float min[3], const float max[3], + const bool ok_dist, const int smooth_viewtx) { ScrArea *sa = CTX_wm_area(C); ARegion *ar; @@ -2985,7 +2699,7 @@ static void view3d_from_minmax_multi(bContext *C, View3D *v3d, } } -static int view3d_all_exec(bContext *C, wmOperator *op) /* was view3d_home() in 2.4x */ +static int view3d_all_exec(bContext *C, wmOperator *op) { ARegion *ar = CTX_wm_region(C); View3D *v3d = CTX_wm_view3d(C); @@ -3050,8 +2764,6 @@ static int view3d_all_exec(bContext *C, wmOperator *op) /* was view3d_home() in void VIEW3D_OT_view_all(wmOperatorType *ot) { - PropertyRNA *prop; - /* identifiers */ ot->name = "View All"; ot->description = "View all objects in scene"; @@ -3064,11 +2776,19 @@ void VIEW3D_OT_view_all(wmOperatorType *ot) /* flags */ ot->flag = 0; - prop = RNA_def_boolean(ot->srna, "use_all_regions", 0, "All Regions", "View selected for all regions"); - RNA_def_property_flag(prop, PROP_SKIP_SAVE); + /* properties */ + view3d_operator_properties_common(ot, V3D_OP_PROP_USE_ALL_REGIONS); RNA_def_boolean(ot->srna, "center", 0, "Center", ""); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View Selected Operator + * + * Move & Zoom the view to fit selected contents. + * \{ */ + /* like a localview without local!, was centerview() in 2.4x */ static int viewselected_exec(bContext *C, wmOperator *op) { @@ -3180,8 +2900,6 @@ static int viewselected_exec(bContext *C, wmOperator *op) void VIEW3D_OT_view_selected(wmOperatorType *ot) { - PropertyRNA *prop; - /* identifiers */ ot->name = "View Selected"; ot->description = "Move the view to the selection center"; @@ -3194,17 +2912,22 @@ void VIEW3D_OT_view_selected(wmOperatorType *ot) /* flags */ ot->flag = 0; - /* rna later */ - prop = RNA_def_boolean(ot->srna, "use_all_regions", 0, "All Regions", "View selected for all regions"); - RNA_def_property_flag(prop, PROP_SKIP_SAVE); + /* properties */ + view3d_operator_properties_common(ot, V3D_OP_PROP_USE_ALL_REGIONS); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View Lock Clear Operator + * \{ */ + static int view_lock_clear_exec(bContext *C, wmOperator *UNUSED(op)) { View3D *v3d = CTX_wm_view3d(C); if (v3d) { - ED_view3D_lock_clear(v3d); + ED_view3d_lock_clear(v3d); WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d); @@ -3231,6 +2954,12 @@ void VIEW3D_OT_view_lock_clear(wmOperatorType *ot) ot->flag = 0; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View Lock to Active Operator + * \{ */ + static int view_lock_to_active_exec(bContext *C, wmOperator *UNUSED(op)) { View3D *v3d = CTX_wm_view3d(C); @@ -3238,7 +2967,7 @@ static int view_lock_to_active_exec(bContext *C, wmOperator *UNUSED(op)) if (v3d) { - ED_view3D_lock_clear(v3d); + ED_view3d_lock_clear(v3d); v3d->ob_centre = obact; /* can be NULL */ @@ -3282,12 +3011,18 @@ void VIEW3D_OT_view_lock_to_active(wmOperatorType *ot) ot->flag = 0; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View Center Cursor Operator + * \{ */ + static int viewcenter_cursor_exec(bContext *C, wmOperator *op) { View3D *v3d = CTX_wm_view3d(C); RegionView3D *rv3d = CTX_wm_region_view3d(C); Scene *scene = CTX_data_scene(C); - + if (rv3d) { ARegion *ar = CTX_wm_region(C); const int smooth_viewtx = WM_operator_smooth_viewtx_get(op); @@ -3303,7 +3038,7 @@ static int viewcenter_cursor_exec(bContext *C, wmOperator *op) /* smooth view does viewlock RV3D_BOXVIEW copy */ } - + return OPERATOR_FINISHED; } @@ -3313,15 +3048,21 @@ void VIEW3D_OT_view_center_cursor(wmOperatorType *ot) ot->name = "Center View to Cursor"; ot->description = "Center the view so that the cursor is in the middle of the view"; ot->idname = "VIEW3D_OT_view_center_cursor"; - + /* api callbacks */ ot->exec = viewcenter_cursor_exec; ot->poll = ED_operator_view3d_active; - + /* flags */ ot->flag = 0; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View Center Pick Operator + * \{ */ + static int viewcenter_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event) { View3D *v3d = CTX_wm_view3d(C); @@ -3372,8 +3113,15 @@ void VIEW3D_OT_view_center_pick(wmOperatorType *ot) ot->flag = 0; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View Camera Center Operator + * \{ */ + static int view3d_center_camera_exec(bContext *C, wmOperator *UNUSED(op)) /* was view3d_home() in 2.4x */ { + const Depsgraph *depsgraph = CTX_data_depsgraph(C); Scene *scene = CTX_data_scene(C); float xfac, yfac; float size[2]; @@ -3388,7 +3136,7 @@ static int view3d_center_camera_exec(bContext *C, wmOperator *UNUSED(op)) /* was rv3d->camdx = rv3d->camdy = 0.0f; - ED_view3d_calc_camera_border_size(scene, ar, v3d, rv3d, size); + ED_view3d_calc_camera_border_size(scene, depsgraph, ar, v3d, rv3d, size); /* 4px is just a little room from the edge of the area */ xfac = (float)ar->winx / (float)(size[0] + 4); @@ -3417,6 +3165,12 @@ void VIEW3D_OT_view_center_camera(wmOperatorType *ot) ot->flag = 0; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View Lock Center Operator + * \{ */ + static int view3d_center_lock_exec(bContext *C, wmOperator *UNUSED(op)) /* was view3d_home() in 2.4x */ { RegionView3D *rv3d = CTX_wm_region_view3d(C); @@ -3443,10 +3197,15 @@ void VIEW3D_OT_view_center_lock(wmOperatorType *ot) ot->flag = 0; } -/* ********************* Set render border operator ****************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Set Render Border Operator + * \{ */ static int render_border_exec(bContext *C, wmOperator *op) { + const Depsgraph *depsgraph = CTX_data_depsgraph(C); View3D *v3d = CTX_wm_view3d(C); ARegion *ar = CTX_wm_region(C); RegionView3D *rv3d = ED_view3d_context_rv3d(C); @@ -3467,7 +3226,7 @@ static int render_border_exec(bContext *C, wmOperator *op) /* calculate range */ if (rv3d->persp == RV3D_CAMOB) { - ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &vb, false); + ED_view3d_calc_camera_border(scene, depsgraph, ar, v3d, rv3d, &vb, false); } else { vb.xmin = 0; @@ -3513,7 +3272,6 @@ static int render_border_exec(bContext *C, wmOperator *op) } return OPERATOR_FINISHED; - } void VIEW3D_OT_render_border(wmOperatorType *ot) @@ -3536,7 +3294,7 @@ void VIEW3D_OT_render_border(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* rna */ + /* properties */ WM_operator_properties_border(ot); prop = RNA_def_boolean(ot->srna, "camera_only", false, "Camera Only", @@ -3544,7 +3302,11 @@ void VIEW3D_OT_render_border(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_HIDDEN); } -/* ********************* Clear render border operator ****************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Clear Render Border Operator + * \{ */ static int clear_render_border_exec(bContext *C, wmOperator *UNUSED(op)) { @@ -3573,7 +3335,6 @@ static int clear_render_border_exec(bContext *C, wmOperator *UNUSED(op)) border->ymax = 1.0f; return OPERATOR_FINISHED; - } void VIEW3D_OT_clear_render_border(wmOperatorType *ot) @@ -3591,7 +3352,11 @@ void VIEW3D_OT_clear_render_border(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -/* ********************* Border Zoom operator ****************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Border Zoom Operator + * \{ */ static int view3d_zoom_border_exec(bContext *C, wmOperator *op) { @@ -3612,7 +3377,7 @@ static int view3d_zoom_border_exec(bContext *C, wmOperator *op) /* ZBuffer depth vars */ float depth_close = FLT_MAX; - float p[3]; + float cent[2], p[3]; /* note; otherwise opengl won't work */ view3d_operator_needs_opengl(C); @@ -3629,22 +3394,22 @@ static int view3d_zoom_border_exec(bContext *C, wmOperator *op) /* Get Z Depths, needed for perspective, nice for ortho */ ED_view3d_draw_depth(&eval_ctx, CTX_data_depsgraph(C), ar, v3d, true); - + { /* avoid allocating the whole depth buffer */ ViewDepths depth_temp = {0}; /* avoid view3d_update_depths() for speed. */ view3d_update_depths_rect(ar, &depth_temp, &rect); - + /* find the closest Z pixel */ depth_close = view3d_depth_near(&depth_temp); - + MEM_SAFE_FREE(depth_temp.depths); } - float centx = (((float)rect.xmin) + ((float)rect.xmax)) / 2; - float centy = (((float)rect.ymin) + ((float)rect.ymax)) / 2; + cent[0] = (((float)rect.xmin) + ((float)rect.xmax)) / 2; + cent[1] = (((float)rect.ymin) + ((float)rect.ymax)) / 2; if (rv3d->is_persp) { float p_corner[3]; @@ -3655,7 +3420,7 @@ static int view3d_zoom_border_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } /* convert border to 3d coordinates */ - if ((!ED_view3d_unproject(ar, centx, centy, depth_close, p)) || + if ((!ED_view3d_unproject(ar, cent[0], cent[1], depth_close, p)) || (!ED_view3d_unproject(ar, rect.xmin, rect.ymin, depth_close, p_corner))) { return OPERATOR_CANCELLED; @@ -3677,7 +3442,7 @@ static int view3d_zoom_border_exec(bContext *C, wmOperator *op) new_dist = rv3d->dist; /* convert the drawn rectangle into 3d space */ - if (depth_close != FLT_MAX && ED_view3d_unproject(ar, centx, centy, depth_close, p)) { + if (depth_close != FLT_MAX && ED_view3d_unproject(ar, cent[0], cent[1], depth_close, p)) { negate_v3_v3(new_ofs, p); } else { @@ -3719,8 +3484,9 @@ static int view3d_zoom_border_exec(bContext *C, wmOperator *op) C, v3d, ar, smooth_viewtx, &(const V3D_SmoothParams) {.ofs = new_ofs, .dist = &new_dist}); - if (rv3d->viewlock & RV3D_BOXVIEW) + if (rv3d->viewlock & RV3D_BOXVIEW) { view3d_boxview_sync(CTX_wm_area(C), ar); + } return OPERATOR_FINISHED; } @@ -3755,18 +3521,25 @@ void VIEW3D_OT_zoom_border(wmOperatorType *ot) /* flags */ ot->flag = 0; - /* rna */ + /* properties */ WM_operator_properties_gesture_border_zoom(ot); } -/* sets the view to 1:1 camera/render-pixel */ -static void view3d_set_1_to_1_viewborder(Scene *scene, ARegion *ar, View3D *v3d) +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Set Camera Zoom 1:1 Operator + * + * Sets the view to 1:1 camera/render-pixel. + * \{ */ + +static void view3d_set_1_to_1_viewborder(Scene *scene, const Depsgraph *depsgraph, ARegion *ar, View3D *v3d) { RegionView3D *rv3d = ar->regiondata; float size[2]; int im_width = (scene->r.size * scene->r.xsch) / 100; - - ED_view3d_calc_camera_border_size(scene, ar, v3d, rv3d, size); + + ED_view3d_calc_camera_border_size(scene, depsgraph, ar, v3d, rv3d, size); rv3d->camzoom = BKE_screen_view3d_zoom_from_fac((float)im_width / size[0]); CLAMP(rv3d->camzoom, RV3D_CAMZOOM_MIN, RV3D_CAMZOOM_MAX); @@ -3774,6 +3547,7 @@ static void view3d_set_1_to_1_viewborder(Scene *scene, ARegion *ar, View3D *v3d) static int view3d_zoom_1_to_1_camera_exec(bContext *C, wmOperator *UNUSED(op)) { + const Depsgraph *depsgraph = CTX_data_depsgraph(C); Scene *scene = CTX_data_scene(C); View3D *v3d; @@ -3782,7 +3556,7 @@ static int view3d_zoom_1_to_1_camera_exec(bContext *C, wmOperator *UNUSED(op)) /* no NULL check is needed, poll checks */ ED_view3d_context_user_region(C, &v3d, &ar); - view3d_set_1_to_1_viewborder(scene, ar, v3d); + view3d_set_1_to_1_viewborder(scene, depsgraph, ar, v3d); WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d); @@ -3804,7 +3578,11 @@ void VIEW3D_OT_zoom_camera_1_to_1(wmOperatorType *ot) ot->flag = 0; } -/* ********************* Changing view operator ****************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View Axis/Type Operator + * \{ */ static const EnumPropertyItem prop_view_items[] = { {RV3D_VIEW_LEFT, "LEFT", ICON_TRIA_LEFT, "Left", "View From the Left"}, @@ -3820,10 +3598,11 @@ static const EnumPropertyItem prop_view_items[] = { /* would like to make this a generic function - outside of transform */ -static void axis_set_view(bContext *C, View3D *v3d, ARegion *ar, - const float quat_[4], - short view, int perspo, bool align_active, - const int smooth_viewtx) +static void axis_set_view( + bContext *C, View3D *v3d, ARegion *ar, + const float quat_[4], + short view, int perspo, bool align_active, + const int smooth_viewtx) { RegionView3D *rv3d = ar->regiondata; /* no NULL check is needed, poll checks */ float quat[4]; @@ -4002,7 +3781,6 @@ static int viewnumpad_exec(bContext *C, wmOperator *op) &(const V3D_SmoothParams) { .camera = v3d->camera, .ofs = rv3d->ofs, .quat = rv3d->viewquat, .dist = &rv3d->dist, .lens = &v3d->lens}); - } else { /* return to settings of last view */ @@ -4043,6 +3821,14 @@ void VIEW3D_OT_viewnumpad(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_SKIP_SAVE); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View Orbit Operator + * + * Rotate (orbit) in incremental steps. For interactive orbit see #VIEW3D_OT_rotate. + * \{ */ + static const EnumPropertyItem prop_view_orbit_items[] = { {V3D_VIEW_STEPLEFT, "ORBITLEFT", 0, "Orbit Left", "Orbit the view around to the Left"}, {V3D_VIEW_STEPRIGHT, "ORBITRIGHT", 0, "Orbit Right", "Orbit the view around to the Right"}, @@ -4086,7 +3872,7 @@ static int vieworbit_exec(bContext *C, wmOperator *op) float quat_new[4]; if (view_opposite == RV3D_VIEW_USER) { - view3d_ensure_persp(v3d, ar); + ED_view3d_persp_ensure(v3d, ar); } if (ELEM(orbitdir, V3D_VIEW_STEPLEFT, V3D_VIEW_STEPRIGHT)) { @@ -4157,17 +3943,19 @@ void VIEW3D_OT_view_orbit(wmOperatorType *ot) /* flags */ ot->flag = 0; - + /* properties */ prop = RNA_def_float(ot->srna, "angle", 0, -FLT_MAX, FLT_MAX, "Roll", "", -FLT_MAX, FLT_MAX); RNA_def_property_flag(prop, PROP_SKIP_SAVE); ot->prop = RNA_def_enum(ot->srna, "type", prop_view_orbit_items, 0, "Orbit", "Direction of View Orbit"); - } +/** \} */ -/* ************************ viewroll ******************************** */ +/* -------------------------------------------------------------------- */ +/** \name View Roll Operator + * \{ */ static void view_roll_angle(ARegion *ar, float quat[4], const float orig_quat[4], const float dvec[3], float angle) { @@ -4194,19 +3982,20 @@ static void viewroll_apply(ViewOpsData *vod, int x, int UNUSED(y)) tot = vod->ar->winrct.xmax - vod->ar->winrct.xmin; len1 = (vod->ar->winrct.xmax - x) / tot; - len2 = (vod->ar->winrct.xmax - vod->origx) / tot; + len2 = (vod->ar->winrct.xmax - vod->init.event_xy[0]) / tot; angle = (len1 - len2) * (float)M_PI * 4.0f; } if (angle != 0.0f) - view_roll_angle(vod->ar, vod->rv3d->viewquat, vod->oldquat, vod->mousevec, angle); + view_roll_angle(vod->ar, vod->rv3d->viewquat, vod->init.quat, vod->init.mousevec, angle); if (vod->use_dyn_ofs) { - view3d_orbit_apply_dyn_ofs(vod->rv3d->ofs, vod->ofs, vod->oldquat, vod->rv3d->viewquat, vod->dyn_ofs); + view3d_orbit_apply_dyn_ofs(vod->rv3d->ofs, vod->init.ofs, vod->init.quat, vod->rv3d->viewquat, vod->dyn_ofs); } - if (vod->rv3d->viewlock & RV3D_BOXVIEW) + if (vod->rv3d->viewlock & RV3D_BOXVIEW) { view3d_boxview_sync(vod->sa, vod->ar); + } ED_view3d_camera_lock_sync(vod->v3d, vod->rv3d); @@ -4239,7 +4028,7 @@ static int viewroll_modal(bContext *C, wmOperator *op, const wmEvent *event) break; } } - else if (event->type == vod->origkey && event->val == KM_RELEASE) { + else if (event->type == vod->init.event_type && event->val == KM_RELEASE) { event_code = VIEW_CONFIRM; } @@ -4343,17 +4132,17 @@ static int viewroll_invoke(bContext *C, wmOperator *op, const wmEvent *event) else { /* makes op->customdata */ viewops_data_alloc(C, op); - viewops_data_create(C, op, event, false); + viewops_data_create(C, op, event, viewops_flag_from_prefs()); vod = op->customdata; ED_view3d_smooth_view_force_finish(C, vod->v3d, vod->ar); /* overwrite the mouse vector with the view direction */ - normalize_v3_v3(vod->mousevec, vod->rv3d->viewinv[2]); - negate_v3(vod->mousevec); + normalize_v3_v3(vod->init.mousevec, vod->rv3d->viewinv[2]); + negate_v3(vod->init.mousevec); if (event->type == MOUSEROTATE) { - vod->origx = vod->oldx = event->x; + vod->init.event_xy[0] = vod->prev.event_xy[0] = event->x; viewroll_apply(vod, event->prevx, event->prevy); ED_view3d_depth_tag_update(vod->rv3d); @@ -4409,6 +4198,14 @@ static const EnumPropertyItem prop_view_pan_items[] = { {0, NULL, 0, NULL, NULL} }; +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View Pan Operator + * + * Move (pan) in incremental steps. For interactive pan see #VIEW3D_OT_move. + * \{ */ + static int viewpan_invoke(bContext *C, wmOperator *op, const wmEvent *event) { int x = 0, y = 0; @@ -4420,10 +4217,10 @@ static int viewpan_invoke(bContext *C, wmOperator *op, const wmEvent *event) else if (pandir == V3D_VIEW_PANDOWN) { y = 25; } viewops_data_alloc(C, op); - viewops_data_create(C, op, event, false); + viewops_data_create(C, op, event, viewops_flag_from_prefs()); ViewOpsData *vod = op->customdata; - viewmove_apply(vod, vod->oldx + x, vod->oldy + y); + viewmove_apply(vod, vod->prev.event_xy[0] + x, vod->prev.event_xy[1] + y); ED_view3d_depth_tag_update(vod->rv3d); viewops_data_free(C, op); @@ -4444,11 +4241,17 @@ void VIEW3D_OT_view_pan(wmOperatorType *ot) /* flags */ ot->flag = 0; - + /* Properties */ ot->prop = RNA_def_enum(ot->srna, "type", prop_view_pan_items, 0, "Pan", "Direction of View Pan"); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View Toggle Perspective/Orthographic Operator + * \{ */ + static int viewpersportho_exec(bContext *C, wmOperator *UNUSED(op)) { View3D *v3d_dummy; @@ -4467,7 +4270,6 @@ static int viewpersportho_exec(bContext *C, wmOperator *UNUSED(op)) } return OPERATOR_FINISHED; - } void VIEW3D_OT_view_persportho(wmOperatorType *ot) @@ -4485,6 +4287,14 @@ void VIEW3D_OT_view_persportho(wmOperatorType *ot) ot->flag = 0; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View Navigate Operator + * + * Wraps walk/fly modes. + * \{ */ + static int view3d_navigate_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNUSED(event)) { eViewNavigation_Method mode = U.navigation_mode; @@ -4514,8 +4324,11 @@ void VIEW3D_OT_navigate(wmOperatorType *ot) ot->poll = ED_operator_view3d_active; } +/** \} */ -/* ******************** add background image operator **************** */ +/* -------------------------------------------------------------------- */ +/** \name Background Image Add Operator + * \{ */ static CameraBGImage *background_image_add(bContext *C) { @@ -4536,7 +4349,7 @@ static int background_image_add_invoke(bContext *C, wmOperator *op, const wmEven Camera *cam = CTX_data_pointer_get_type(C, "camera", &RNA_Camera).data; Image *ima; CameraBGImage *bgpic; - + ima = (Image *)WM_operator_drop_load_path(C, op, ID_IM); /* may be NULL, continue anyway */ @@ -4566,7 +4379,7 @@ void VIEW3D_OT_background_image_add(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_UNDO; - + /* properties */ RNA_def_string(ot->srna, "name", "Image", MAX_ID_NAME - 2, "Name", "Image name to assign"); WM_operator_properties_filesel( @@ -4574,8 +4387,12 @@ void VIEW3D_OT_background_image_add(wmOperatorType *ot) WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Background Image Remove Operator + * \{ */ -/* ***** remove image operator ******* */ static int background_image_remove_exec(bContext *C, wmOperator *op) { Camera *cam = CTX_data_pointer_get_type(C, "camera", &RNA_Camera).data; @@ -4593,13 +4410,11 @@ static int background_image_remove_exec(bContext *C, wmOperator *op) BKE_camera_background_image_remove(cam, bgpic_rem); WM_event_add_notifier(C, NC_CAMERA | ND_DRAW_RENDER_VIEWPORT, cam); - return OPERATOR_FINISHED; } else { return OPERATOR_CANCELLED; } - } void VIEW3D_OT_background_image_remove(wmOperatorType *ot) @@ -4615,12 +4430,18 @@ void VIEW3D_OT_background_image_remove(wmOperatorType *ot) /* flags */ ot->flag = 0; - + /* properties */ RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "Background image index to remove", 0, INT_MAX); } -/* ********************* set clipping operator ****************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View Clipping Planes Operator + * + * Draw border or toggle off. + * \{ */ static void calc_local_clipping(float clip_local[6][4], BoundBox *clipbb, float mat[4][4]) { @@ -4677,7 +4498,6 @@ static int view3d_clipping_invoke(bContext *C, wmOperator *op, const wmEvent *ev } } -/* toggles */ void VIEW3D_OT_clip_border(wmOperatorType *ot) { @@ -4697,11 +4517,15 @@ void VIEW3D_OT_clip_border(wmOperatorType *ot) /* flags */ ot->flag = 0; - /* rna */ + /* properties */ WM_operator_properties_border(ot); } -/* ***************** 3d cursor cursor op ******************* */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Set Cursor Operator + * \{ */ /* cursor position in vec, result in vec, mval in region coords */ /* note: cannot use event->mval here (called by object_add() */ @@ -4712,14 +4536,14 @@ void ED_view3d_cursor3d_position(bContext *C, float fp[3], const int mval[2]) RegionView3D *rv3d = ar->regiondata; bool flip; bool depth_used = false; - + /* normally the caller should ensure this, * but this is called from areas that aren't already dealing with the viewport */ if (rv3d == NULL) return; ED_view3d_calc_zfac(rv3d, fp, &flip); - + /* reset the depth based on the view offset (we _know_ the offset is infront of us) */ if (flip) { negate_v3_v3(fp, rv3d->ofs); @@ -4727,7 +4551,7 @@ void ED_view3d_cursor3d_position(bContext *C, float fp[3], const int mval[2]) ED_view3d_calc_zfac(rv3d, fp, NULL /* &flip */ ); } - if (U.uiflag & USER_ZBUF_CURSOR) { /* maybe this should be accessed some other way */ + if (U.uiflag & USER_DEPTH_CURSOR) { /* maybe this should be accessed some other way */ EvaluationContext eval_ctx; struct Depsgraph *graph = CTX_data_depsgraph(C); @@ -4808,26 +4632,27 @@ void VIEW3D_OT_cursor3d(wmOperatorType *ot) /* flags */ // ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO; - - /* rna later */ - } -/* ***************** manipulator op ******************* */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Enable Transform Manipulator Operator + * \{ */ static int enable_manipulator_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { View3D *v3d = CTX_wm_view3d(C); v3d->twtype = 0; - + if (RNA_boolean_get(op->ptr, "translate")) v3d->twtype |= V3D_MANIP_TRANSLATE; if (RNA_boolean_get(op->ptr, "rotate")) v3d->twtype |= V3D_MANIP_ROTATE; if (RNA_boolean_get(op->ptr, "scale")) v3d->twtype |= V3D_MANIP_SCALE; - + WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d); return OPERATOR_FINISHED; @@ -4841,12 +4666,12 @@ void VIEW3D_OT_enable_manipulator(wmOperatorType *ot) ot->name = "Enable 3D Manipulator"; ot->description = "Enable the transform manipulator for use"; ot->idname = "VIEW3D_OT_enable_manipulator"; - + /* api callbacks */ ot->invoke = enable_manipulator_invoke; ot->poll = ED_operator_view3d_active; - - /* rna later */ + + /* properties */ prop = RNA_def_boolean(ot->srna, "translate", 0, "Translate", "Enable the translate manipulator"); RNA_def_property_flag(prop, PROP_SKIP_SAVE); prop = RNA_def_boolean(ot->srna, "rotate", 0, "Rotate", "Enable the rotate manipulator"); @@ -4855,7 +4680,11 @@ void VIEW3D_OT_enable_manipulator(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_SKIP_SAVE); } -/* ************************* Toggle rendered shading *********************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Toggle Render Shading Operator + * \{ */ static int toggle_render_exec(bContext *C, wmOperator *UNUSED(op)) { @@ -4884,315 +4713,4 @@ void VIEW3D_OT_toggle_render(wmOperatorType *ot) ot->poll = ED_operator_view3d_active; } -/* ************************* below the line! *********************** */ - - -static float view_autodist_depth_margin(ARegion *ar, const int mval[2], int margin) -{ - ViewDepths depth_temp = {0}; - rcti rect; - float depth_close; - - if (margin == 0) { - /* Get Z Depths, needed for perspective, nice for ortho */ - rect.xmin = mval[0]; - rect.ymin = mval[1]; - rect.xmax = mval[0] + 1; - rect.ymax = mval[1] + 1; - } - else { - BLI_rcti_init_pt_radius(&rect, mval, margin); - } - - view3d_update_depths_rect(ar, &depth_temp, &rect); - depth_close = view3d_depth_near(&depth_temp); - MEM_SAFE_FREE(depth_temp.depths); - return depth_close; -} - -/** - * Get the world-space 3d location from a screen-space 2d point. - * - * \param mval: Input screen-space pixel location. - * \param mouse_worldloc: Output world-space location. - * \param fallback_depth_pt: Use this points depth when no depth can be found. - */ -bool ED_view3d_autodist( - const EvaluationContext *eval_ctx, struct Depsgraph *graph, ARegion *ar, View3D *v3d, - const int mval[2], float mouse_worldloc[3], - const bool alphaoverride, const float fallback_depth_pt[3]) -{ - float depth_close; - int margin_arr[] = {0, 2, 4}; - int i; - bool depth_ok = false; - - /* Get Z Depths, needed for perspective, nice for ortho */ - ED_view3d_draw_depth(eval_ctx, graph, ar, v3d, alphaoverride); - - /* Attempt with low margin's first */ - i = 0; - do { - depth_close = view_autodist_depth_margin(ar, mval, margin_arr[i++] * U.pixelsize); - depth_ok = (depth_close != FLT_MAX); - } while ((depth_ok == false) && (i < ARRAY_SIZE(margin_arr))); - - if (depth_ok) { - float centx = (float)mval[0] + 0.5f; - float centy = (float)mval[1] + 0.5f; - - if (ED_view3d_unproject(ar, centx, centy, depth_close, mouse_worldloc)) { - return true; - } - } - - if (fallback_depth_pt) { - ED_view3d_win_to_3d_int(v3d, ar, fallback_depth_pt, mval, mouse_worldloc); - return true; - } - else { - return false; - } -} - -void ED_view3d_autodist_init( - const EvaluationContext *eval_ctx, struct Depsgraph *graph, - ARegion *ar, View3D *v3d, int mode) -{ - /* Get Z Depths, needed for perspective, nice for ortho */ - switch (mode) { - case 0: - ED_view3d_draw_depth(eval_ctx, graph, ar, v3d, true); - break; - case 1: - { - Scene *scene = DEG_get_evaluated_scene(graph); - ED_view3d_draw_depth_gpencil(eval_ctx, scene, ar, v3d); - break; - } - } -} - -/* no 4x4 sampling, run #ED_view3d_autodist_init first */ -bool ED_view3d_autodist_simple(ARegion *ar, const int mval[2], float mouse_worldloc[3], - int margin, float *force_depth) -{ - float depth; - - /* Get Z Depths, needed for perspective, nice for ortho */ - if (force_depth) - depth = *force_depth; - else - depth = view_autodist_depth_margin(ar, mval, margin); - - if (depth == FLT_MAX) - return false; - - float centx = (float)mval[0] + 0.5f; - float centy = (float)mval[1] + 0.5f; - return ED_view3d_unproject(ar, centx, centy, depth, mouse_worldloc); -} - -bool ED_view3d_autodist_depth(ARegion *ar, const int mval[2], int margin, float *depth) -{ - *depth = view_autodist_depth_margin(ar, mval, margin); - - return (*depth != FLT_MAX); -} - -static bool depth_segment_cb(int x, int y, void *userData) -{ - struct { ARegion *ar; int margin; float depth; } *data = userData; - int mval[2]; - float depth; - - mval[0] = x; - mval[1] = y; - - depth = view_autodist_depth_margin(data->ar, mval, data->margin); - - if (depth != FLT_MAX) { - data->depth = depth; - return 0; - } - else { - return 1; - } -} - -bool ED_view3d_autodist_depth_seg(ARegion *ar, const int mval_sta[2], const int mval_end[2], - int margin, float *depth) -{ - struct { ARegion *ar; int margin; float depth; } data = {NULL}; - int p1[2]; - int p2[2]; - - data.ar = ar; - data.margin = margin; - data.depth = FLT_MAX; - - copy_v2_v2_int(p1, mval_sta); - copy_v2_v2_int(p2, mval_end); - - BLI_bitmap_draw_2d_line_v2v2i(p1, p2, depth_segment_cb, &data); - - *depth = data.depth; - - return (*depth != FLT_MAX); -} - -/* problem - ofs[3] can be on same location as camera itself. - * Blender needs proper dist value for zoom. - * use fallback_dist to override small values - */ -float ED_view3d_offset_distance(float mat[4][4], const float ofs[3], const float fallback_dist) -{ - float pos[4] = {0.0f, 0.0f, 0.0f, 1.0f}; - float dir[4] = {0.0f, 0.0f, 1.0f, 0.0f}; - float dist; - - mul_m4_v4(mat, pos); - add_v3_v3(pos, ofs); - mul_m4_v4(mat, dir); - normalize_v3(dir); - - dist = dot_v3v3(pos, dir); - - if ((dist < FLT_EPSILON) && (fallback_dist != 0.0f)) { - dist = fallback_dist; - } - - return dist; -} - -/** - * Set the dist without moving the view (compensate with #RegionView3D.ofs) - * - * \note take care that viewinv is up to date, #ED_view3d_update_viewmat first. - */ -void ED_view3d_distance_set(RegionView3D *rv3d, const float dist) -{ - float viewinv[4]; - float tvec[3]; - - BLI_assert(dist >= 0.0f); - - copy_v3_fl3(tvec, 0.0f, 0.0f, rv3d->dist - dist); - /* rv3d->viewinv isn't always valid */ -#if 0 - mul_mat3_m4_v3(rv3d->viewinv, tvec); -#else - invert_qt_qt_normalized(viewinv, rv3d->viewquat); - mul_qt_v3(viewinv, tvec); -#endif - sub_v3_v3(rv3d->ofs, tvec); - - rv3d->dist = dist; -} - -/** - * Set the view transformation from a 4x4 matrix. - * - * \param mat The view 4x4 transformation matrix to assign. - * \param ofs The view offset, normally from RegionView3D.ofs. - * \param quat The view rotation, quaternion normally from RegionView3D.viewquat. - * \param dist The view distance from ofs, normally from RegionView3D.dist. - */ -void ED_view3d_from_m4(float mat[4][4], float ofs[3], float quat[4], float *dist) -{ - float nmat[3][3]; - - /* dist depends on offset */ - BLI_assert(dist == NULL || ofs != NULL); - - copy_m3_m4(nmat, mat); - normalize_m3(nmat); - - /* Offset */ - if (ofs) - negate_v3_v3(ofs, mat[3]); - - /* Quat */ - if (quat) { - mat3_normalized_to_quat(quat, nmat); - invert_qt_normalized(quat); - } - - if (ofs && dist) { - madd_v3_v3fl(ofs, nmat[2], *dist); - } -} - -/** - * Calculate the view transformation matrix from RegionView3D input. - * The resulting matrix is equivalent to RegionView3D.viewinv - * \param mat The view 4x4 transformation matrix to calculate. - * \param ofs The view offset, normally from RegionView3D.ofs. - * \param quat The view rotation, quaternion normally from RegionView3D.viewquat. - * \param dist The view distance from ofs, normally from RegionView3D.dist. - */ -void ED_view3d_to_m4(float mat[4][4], const float ofs[3], const float quat[4], const float dist) -{ - float iviewquat[4] = {-quat[0], quat[1], quat[2], quat[3]}; - float dvec[3] = {0.0f, 0.0f, dist}; - - quat_to_mat4(mat, iviewquat); - mul_mat3_m4_v3(mat, dvec); - sub_v3_v3v3(mat[3], dvec, ofs); -} - -/** - * Set the RegionView3D members from an objects transformation and optionally lens. - * \param ob The object to set the view to. - * \param ofs The view offset to be set, normally from RegionView3D.ofs. - * \param quat The view rotation to be set, quaternion normally from RegionView3D.viewquat. - * \param dist The view distance from ofs to be set, normally from RegionView3D.dist. - * \param lens The view lens angle set for cameras and lamps, normally from View3D.lens. - */ -void ED_view3d_from_object(Object *ob, float ofs[3], float quat[4], float *dist, float *lens) -{ - ED_view3d_from_m4(ob->obmat, ofs, quat, dist); - - if (lens) { - CameraParams params; - - BKE_camera_params_init(¶ms); - BKE_camera_params_from_object(¶ms, ob); - *lens = params.lens; - } -} - -/** - * Set the object transformation from RegionView3D members. - * \param ob The object which has the transformation assigned. - * \param ofs The view offset, normally from RegionView3D.ofs. - * \param quat The view rotation, quaternion normally from RegionView3D.viewquat. - * \param dist The view distance from ofs, normally from RegionView3D.dist. - */ -void ED_view3d_to_object(Object *ob, const float ofs[3], const float quat[4], const float dist) -{ - float mat[4][4]; - - ED_view3d_to_m4(mat, ofs, quat, dist); - BKE_object_apply_mat4(ob, mat, true, true); -} - -/** - * Use to store the last view, before entering camera view. - */ -void ED_view3d_lastview_store(RegionView3D *rv3d) -{ - copy_qt_qt(rv3d->lviewquat, rv3d->viewquat); - rv3d->lview = rv3d->view; - if (rv3d->persp != RV3D_CAMOB) { - rv3d->lpersp = rv3d->persp; - } -} - -void ED_view3D_lock_clear(View3D *v3d) -{ - v3d->ob_centre = NULL; - v3d->ob_centre_bone[0] = '\0'; - v3d->ob_centre_cursor = false; - v3d->flag2 &= ~V3D_LOCK_CAMERA; -} +/** \} */ diff --git a/source/blender/editors/space_view3d/view3d_fly.c b/source/blender/editors/space_view3d/view3d_fly.c index 5e7eddb1c22..d2aa19509d7 100644 --- a/source/blender/editors/space_view3d/view3d_fly.c +++ b/source/blender/editors/space_view3d/view3d_fly.c @@ -58,6 +58,8 @@ #include "GPU_immediate.h" +#include "DEG_depsgraph.h" + #include "view3d_intern.h" /* own include */ /* NOTE: these defines are saved in keymap files, do not change values but just add new ones */ @@ -193,6 +195,7 @@ typedef struct FlyInfo { RegionView3D *rv3d; View3D *v3d; ARegion *ar; + const struct Depsgraph *depsgraph; Scene *scene; wmTimer *timer; /* needed for redraws */ @@ -242,7 +245,7 @@ static void drawFlyPixel(const struct bContext *UNUSED(C), ARegion *UNUSED(ar), float x1, x2, y1, y2; if (fly->scene->camera) { - ED_view3d_calc_camera_border(fly->scene, fly->ar, fly->v3d, fly->rv3d, &viewborder, false); + ED_view3d_calc_camera_border(fly->scene, fly->depsgraph, fly->ar, fly->v3d, fly->rv3d, &viewborder, false); xoff = viewborder.xmin; yoff = viewborder.ymin; } @@ -343,6 +346,10 @@ enum { static bool initFlyInfo(bContext *C, FlyInfo *fly, wmOperator *op, const wmEvent *event) { wmWindow *win = CTX_wm_window(C); + EvaluationContext eval_ctx; + + CTX_data_eval_ctx(C, &eval_ctx); + rctf viewborder; float upvec[3]; /* tmp */ @@ -351,6 +358,7 @@ static bool initFlyInfo(bContext *C, FlyInfo *fly, wmOperator *op, const wmEvent fly->rv3d = CTX_wm_region_view3d(C); fly->v3d = CTX_wm_view3d(C); fly->ar = CTX_wm_region(C); + fly->depsgraph = CTX_data_depsgraph(C); fly->scene = CTX_data_scene(C); #ifdef NDOF_FLY_DEBUG @@ -417,12 +425,12 @@ static bool initFlyInfo(bContext *C, FlyInfo *fly, wmOperator *op, const wmEvent } fly->v3d_camera_control = ED_view3d_cameracontrol_acquire( - C, fly->scene, fly->v3d, fly->rv3d, + &eval_ctx, fly->scene, fly->v3d, fly->rv3d, (U.uiflag & USER_CAM_LOCK_NO_PARENT) == 0); /* calculate center */ if (fly->scene->camera) { - ED_view3d_calc_camera_border(fly->scene, fly->ar, fly->v3d, fly->rv3d, &viewborder, false); + ED_view3d_calc_camera_border(fly->scene, fly->depsgraph, fly->ar, fly->v3d, fly->rv3d, &viewborder, false); fly->width = BLI_rctf_size_x(&viewborder); fly->height = BLI_rctf_size_y(&viewborder); diff --git a/source/blender/editors/space_view3d/view3d_intern.h b/source/blender/editors/space_view3d/view3d_intern.h index f86f6423f93..d1968166904 100644 --- a/source/blender/editors/space_view3d/view3d_intern.h +++ b/source/blender/editors/space_view3d/view3d_intern.h @@ -111,6 +111,7 @@ void VIEW3D_OT_zoom_border(struct wmOperatorType *ot); void VIEW3D_OT_toggle_render(struct wmOperatorType *ot); void view3d_boxview_copy(ScrArea *sa, ARegion *ar); +void view3d_boxview_sync(ScrArea *sa, ARegion *ar); void view3d_orbit_apply_dyn_ofs( float r_ofs[3], const float ofs_old[3], const float viewquat_old[4], @@ -153,7 +154,7 @@ void draw_object_select( const struct EvaluationContext *eval_ctx, Scene *scene, struct ViewLayer *view_layer, struct ARegion *ar, View3D *v3d, Base *base, const short dflag); -void draw_mesh_object_outline(View3D *v3d, Object *ob, struct DerivedMesh *dm, const unsigned char ob_wire_col[4]); +void draw_mesh_object_outline(View3D *v3d, struct Object *ob, struct DerivedMesh *dm, const unsigned char ob_wire_col[4]); bool draw_glsl_material(Scene *scene, struct ViewLayer *view_layer, struct Object *ob, View3D *v3d, const char dt); void draw_object_instance(const struct EvaluationContext *eval_ctx, Scene *scene, struct ViewLayer *view_layer, View3D *v3d, RegionView3D *rv3d, struct Object *ob, const char dt, int outline, const float wire_col[4]); @@ -233,9 +234,6 @@ void ED_view3d_draw_select_loop( void ED_view3d_draw_depth_loop( const struct EvaluationContext *eval_ctx, Scene *scene, ARegion *ar, View3D *v3d); -void view3d_draw_bgpic_test(Scene *scene, ARegion *ar, View3D *v3d, - const bool do_foreground, const bool do_camera_frame); - void ED_view3d_after_add(ListBase *lb, Base *base, const short dflag); void view3d_update_depths_rect(struct ARegion *ar, struct ViewDepths *d, struct rcti *rect); @@ -279,8 +277,12 @@ void ED_view3d_smooth_view_force_finish( struct bContext *C, struct View3D *v3d, struct ARegion *ar); -void view3d_winmatrix_set(ARegion *ar, const View3D *v3d, const rcti *rect); -void view3d_viewmatrix_set(const struct EvaluationContext *eval_ctx, Scene *scene, const View3D *v3d, RegionView3D *rv3d); +void view3d_winmatrix_set( + const struct Depsgraph *depsgraph, + ARegion *ar, const View3D *v3d, const rcti *rect); +void view3d_viewmatrix_set( + const struct EvaluationContext *eval_ctx, Scene *scene, + const View3D *v3d, RegionView3D *rv3d, const float rect_scale[2]); void fly_modal_keymap(struct wmKeyConfig *keyconf); void walk_modal_keymap(struct wmKeyConfig *keyconf); @@ -295,7 +297,7 @@ void view3d_buttons_register(struct ARegionType *art); /* view3d_camera_control.c */ struct View3DCameraControl *ED_view3d_cameracontrol_acquire( - const struct bContext *C, Scene *scene, View3D *v3d, RegionView3D *rv3d, + const struct EvaluationContext *eval_ctx, Scene *scene, View3D *v3d, RegionView3D *rv3d, const bool use_parent_root); void ED_view3d_cameracontrol_update( struct View3DCameraControl *vctrl, @@ -304,7 +306,7 @@ void ED_view3d_cameracontrol_update( void ED_view3d_cameracontrol_release( struct View3DCameraControl *vctrl, const bool restore); -Object *ED_view3d_cameracontrol_object_get( +struct Object *ED_view3d_cameracontrol_object_get( struct View3DCameraControl *vctrl); /* view3d_toolbar.c */ @@ -337,11 +339,14 @@ void VIEW3D_WGT_camera_view(struct wmManipulatorGroupType *wgt); void VIEW3D_WGT_force_field(struct wmManipulatorGroupType *wgt); void VIEW3D_WGT_empty_image(struct wmManipulatorGroupType *wgt); void VIEW3D_WGT_armature_spline(struct wmManipulatorGroupType *wgt); +void VIEW3D_WGT_navigate(struct wmManipulatorGroupType *wgt); void VIEW3D_WGT_ruler(struct wmManipulatorGroupType *wgt); void VIEW3D_WT_ruler_item(struct wmManipulatorType *wt); void VIEW3D_OT_ruler_add(struct wmOperatorType *ot); +void VIEW3D_WT_navigate_rotate(struct wmManipulatorType *wt); + /* draw_volume.c */ void draw_smoke_volume(struct SmokeDomainSettings *sds, struct Object *ob, const float min[3], const float max[3], @@ -364,7 +369,7 @@ extern bool view3d_camera_border_hack_test; void VP_legacy_drawcursor(Scene *scene, struct ViewLayer *view_layer, ARegion *ar, View3D *v3d); void VP_legacy_draw_view_axis(RegionView3D *rv3d, rcti *rect); void VP_legacy_draw_viewport_name(ARegion *ar, View3D *v3d, rcti *rect); -void VP_legacy_draw_selected_name(Scene *scene, Object *ob, rcti *rect); +void VP_legacy_draw_selected_name(Scene *scene, struct Object *ob, rcti *rect); void VP_legacy_drawgrid(UnitSettings *unit, ARegion *ar, View3D *v3d, const char **grid_unit); void VP_legacy_drawfloor(Scene *scene, View3D *v3d, const char **grid_unit, bool write_depth); void VP_legacy_view3d_main_region_setup_view(const struct EvaluationContext *eval_ctx, Scene *scene, View3D *v3d, ARegion *ar, float viewmat[4][4], float winmat[4][4]); @@ -372,7 +377,7 @@ bool VP_legacy_view3d_stereo3d_active(struct wmWindow *win, Scene *scene, View3D void VP_legacy_view3d_stereo3d_setup(const struct EvaluationContext *eval_ctx, Scene *scene, View3D *v3d, ARegion *ar); void draw_dupli_objects(const struct EvaluationContext *eval_ctx, Scene *scene, ViewLayer *view_layer, ARegion *ar, View3D *v3d, Base *base); bool VP_legacy_use_depth(Scene *scene, View3D *v3d); -void VP_drawviewborder(Scene *scene, ARegion *ar, View3D *v3d); +void VP_drawviewborder(Scene *scene, const struct Depsgraph *depsgraph, ARegion *ar, View3D *v3d); void VP_drawrenderborder(ARegion *ar, View3D *v3d); void VP_view3d_draw_background_none(void); void VP_view3d_draw_background_world(Scene *scene, RegionView3D *rv3d); diff --git a/source/blender/editors/space_view3d/view3d_manipulator_camera.c b/source/blender/editors/space_view3d/view3d_manipulator_camera.c index d020571930a..6a45ec5095f 100644 --- a/source/blender/editors/space_view3d/view3d_manipulator_camera.c +++ b/source/blender/editors/space_view3d/view3d_manipulator_camera.c @@ -378,11 +378,12 @@ static void WIDGETGROUP_camera_view_draw_prepare(const bContext *C, wmManipulato struct CameraViewWidgetGroup *viewgroup = mgroup->customdata; ARegion *ar = CTX_wm_region(C); + struct Depsgraph *depsgraph = CTX_data_depsgraph(C); RegionView3D *rv3d = ar->regiondata; if (rv3d->persp == RV3D_CAMOB) { Scene *scene = CTX_data_scene(C); View3D *v3d = CTX_wm_view3d(C); - ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &viewgroup->state.view_border, false); + ED_view3d_calc_camera_border(scene, depsgraph, ar, v3d, rv3d, &viewgroup->state.view_border, false); } else { viewgroup->state.view_border = (rctf){.xmin = 0, .ymin = 0, .xmax = ar->winx, .ymax = ar->winy}; diff --git a/source/blender/editors/space_view3d/view3d_manipulator_navigate.c b/source/blender/editors/space_view3d/view3d_manipulator_navigate.c new file mode 100644 index 00000000000..6a5d63b180f --- /dev/null +++ b/source/blender/editors/space_view3d/view3d_manipulator_navigate.c @@ -0,0 +1,359 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/space_view3d/view3d_manipulator_navigate.c + * \ingroup spview3d + */ + +#include "BLI_blenlib.h" +#include "BLI_math.h" +#include "BLI_utildefines.h" + +#include "BKE_context.h" +#include "BKE_object.h" + +#include "DNA_object_types.h" + +#include "ED_screen.h" +#include "ED_manipulator_library.h" + +#include "UI_resources.h" + +#include "MEM_guardedalloc.h" + +#include "RNA_access.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "view3d_intern.h" /* own include */ + +/* -------------------------------------------------------------------- */ +/** \name View3D Navigation Manipulator Group + * \{ */ + +/* Offset from screen edge. */ +#define MANIPULATOR_OFFSET_FAC 2.5 +/* Size of main icon. */ +#define MANIPULATOR_SIZE 64 +/* Factor for size of smaller button. */ +#define MANIPULATOR_MINI_FAC 0.5 +/* How much mini buttons offset from the primary. */ +#define MANIPULATOR_MINI_OFFSET_FAC 0.6666f + + +enum { + MPR_MOVE = 0, + MPR_ROTATE = 1, + MPR_ZOOM = 2, + + /* just buttons */ + /* overlaps MPR_ORTHO (switch between) */ + MPR_PERSP = 3, + MPR_ORTHO = 4, + MPR_CAMERA = 5, + + MPR_TOTAL = 6, +}; + +/* Vector icons compatible with 'GPU_batch_from_poly_2d_encoded' */ +static const uchar shape_camera[] = { + 0xa3, 0x19, 0x78, 0x55, 0x4d, 0x19, 0x4f, 0x0a, 0x7f, 0x00, 0xb0, 0x0a, 0xa9, 0x19, + 0xa9, 0x19, 0x25, 0xda, 0x0a, 0xb0, 0x00, 0x7f, 0x0a, 0x4f, 0x25, 0x25, 0x4f, 0x0a, + 0x4d, 0x19, 0x47, 0x19, 0x65, 0x55, 0x41, 0x55, 0x41, 0x9e, 0x43, 0xa8, 0x38, 0xb3, + 0x34, 0xc3, 0x38, 0xd2, 0x43, 0xdd, 0x53, 0xe1, 0x62, 0xdd, 0x6d, 0xd2, 0x72, 0xc3, + 0x78, 0xc3, 0x7c, 0xd2, 0x87, 0xdd, 0x96, 0xe1, 0xa6, 0xdd, 0xb1, 0xd2, 0xb5, 0xc3, + 0xb1, 0xb3, 0xa6, 0xa8, 0xa9, 0x9e, 0xa9, 0x8c, 0xbb, 0x8c, 0xbb, 0x86, 0xc7, 0x86, + 0xe0, 0x9e, 0xe0, 0x55, 0xc7, 0x6d, 0xbb, 0x6d, 0xbb, 0x67, 0xa9, 0x67, 0xa9, 0x55, + 0x8a, 0x55, 0xa9, 0x19, 0xb0, 0x0a, 0xda, 0x25, 0xf5, 0x4f, 0xff, 0x80, 0xf5, 0xb0, + 0xda, 0xda, 0xb0, 0xf5, 0x80, 0xff, 0x4f, 0xf5, 0x4f, 0xf5, 0x7c, 0xb3, 0x78, 0xc3, + 0x72, 0xc3, 0x6d, 0xb3, 0x62, 0xa8, 0x53, 0xa4, 0x43, 0xa8, 0x41, 0x9e, 0xa9, 0x9e, + 0xa6, 0xa8, 0x96, 0xa4, 0x87, 0xa8, 0x87, 0xa8, +}; +static const uchar shape_ortho[] = { + 0x85, 0x15, 0x85, 0x7c, 0xde, 0xb3, 0xde, 0xb8, 0xd9, 0xba, 0x80, 0x85, 0x27, 0xba, + 0x22, 0xb8, 0x22, 0xb3, 0x7b, 0x7c, 0x7b, 0x15, 0x80, 0x12, 0x80, 0x12, 0x1d, 0xba, + 0x80, 0xf2, 0x80, 0xff, 0x4f, 0xf5, 0x25, 0xda, 0x0a, 0xb0, 0x00, 0x7f, 0x0a, 0x4f, + 0x25, 0x25, 0x4f, 0x0a, 0x7f, 0x00, 0x80, 0x0d, 0x1d, 0x45, 0x1d, 0x45, 0xb0, 0x0a, + 0xda, 0x25, 0xf5, 0x4f, 0xff, 0x80, 0xf5, 0xb0, 0xda, 0xda, 0xb0, 0xf5, 0x80, 0xff, + 0x80, 0xf2, 0xe3, 0xba, 0xe3, 0x45, 0x80, 0x0d, 0x7f, 0x00, 0x7f, 0x00, +}; +static const uchar shape_pan[] = { + 0xbf, 0x4c, 0xbf, 0x66, 0x99, 0x66, 0x99, 0x40, 0xb2, 0x40, 0x7f, 0x0d, 0x7f, 0x00, + 0xb0, 0x0a, 0xda, 0x25, 0xf5, 0x4f, 0xff, 0x80, 0xf5, 0xb0, 0xda, 0xda, 0xb0, 0xf5, + 0x80, 0xff, 0x80, 0xf2, 0xb3, 0xbf, 0x99, 0xbf, 0x99, 0x99, 0xbf, 0x99, 0xbf, 0xb2, + 0xf2, 0x7f, 0xf2, 0x7f, 0x40, 0xb3, 0x40, 0x99, 0x66, 0x99, 0x66, 0xbf, 0x4d, 0xbf, + 0x80, 0xf2, 0x80, 0xff, 0x4f, 0xf5, 0x25, 0xda, 0x0a, 0xb0, 0x00, 0x7f, 0x0a, 0x4f, + 0x25, 0x25, 0x4f, 0x0a, 0x7f, 0x00, 0x7f, 0x0d, 0x4c, 0x40, 0x66, 0x40, 0x66, 0x66, + 0x40, 0x66, 0x40, 0x4d, 0x0d, 0x80, 0x0d, 0x80, +}; +static const uchar shape_persp[] = { + 0xda, 0xda, 0xb0, 0xf5, 0x80, 0xff, 0x4f, 0xf5, 0x25, 0xda, 0x0a, 0xb0, 0x00, 0x7f, + 0x0a, 0x4f, 0x25, 0x25, 0x4f, 0x0a, 0x7f, 0x00, 0x80, 0x07, 0x30, 0x50, 0x18, 0xbd, + 0x80, 0xdb, 0xe8, 0xbd, 0xf5, 0xb0, 0xf5, 0xb0, 0x83, 0x0f, 0x87, 0x7b, 0xe2, 0xb7, + 0xe3, 0xba, 0xe0, 0xbb, 0x80, 0x87, 0x20, 0xbb, 0x1d, 0xba, 0x1d, 0xb7, 0x78, 0x7b, + 0x7d, 0x0f, 0x80, 0x0c, 0x80, 0x0c, 0xd0, 0x50, 0x80, 0x07, 0x7f, 0x00, 0xb0, 0x0a, + 0xda, 0x25, 0xf5, 0x4f, 0xff, 0x80, 0xf5, 0xb0, 0xe8, 0xbd, 0xe8, 0xbd, +}; +static const uchar shape_zoom[] = { + 0xad, 0x7f, 0xf1, 0x7f, 0xff, 0x80, 0xf5, 0xb0, 0xda, 0xda, 0xb0, 0xf5, 0x80, 0xff, + 0x4f, 0xf5, 0x25, 0xda, 0x0a, 0xb0, 0x00, 0x7f, 0x0d, 0x7f, 0x52, 0x7f, 0x69, 0xb7, + 0x48, 0xb7, 0x80, 0xd8, 0xb8, 0xb7, 0x96, 0xb7, 0x96, 0xb7, 0x7f, 0x2f, 0x0d, 0x7f, + 0x00, 0x7f, 0x0a, 0x4f, 0x25, 0x25, 0x4f, 0x0a, 0x7f, 0x00, 0xb0, 0x0a, 0xda, 0x25, + 0xf5, 0x4f, 0xff, 0x80, 0xf1, 0x7f, 0xf1, 0x7f, +}; + + +struct NavigateManipulatorInfo { + const char *opname; + const char *manipulator; + const unsigned char *shape; + uint shape_size; +}; + +#define SHAPE_VARS(shape_id) shape = shape_id, .shape_size = ARRAY_SIZE(shape_id) + +struct NavigateManipulatorInfo g_navigate_params[MPR_TOTAL] = { + { + .opname = "VIEW3D_OT_move", + .manipulator = "MANIPULATOR_WT_button_2d", + .SHAPE_VARS(shape_pan), + }, { + .opname = "VIEW3D_OT_rotate", + .manipulator = "VIEW3D_WT_navigate_rotate", + .shape = NULL, + .shape_size = 0, + }, { + .opname = "VIEW3D_OT_zoom", + .manipulator = "MANIPULATOR_WT_button_2d", + .SHAPE_VARS(shape_zoom), + }, { + .opname = "VIEW3D_OT_view_persportho", + .manipulator = "MANIPULATOR_WT_button_2d", + .SHAPE_VARS(shape_persp), + }, { + .opname = "VIEW3D_OT_view_persportho", + .manipulator = "MANIPULATOR_WT_button_2d", + .SHAPE_VARS(shape_ortho), + }, { + .opname = "VIEW3D_OT_viewnumpad", + .manipulator = "MANIPULATOR_WT_button_2d", + .SHAPE_VARS(shape_camera), + }, +}; + +#undef SHAPE_VARS + +struct NavigateWidgetGroup { + wmManipulator *mpr_array[MPR_TOTAL]; + /* Store the view state to check for changes. */ + struct { + struct { + short winx, winy; + } ar; + struct { + char is_persp; + char viewlock; + } rv3d; + } state; + int region_size[2]; + bool is_persp; +}; + +static bool WIDGETGROUP_navigate_poll(const bContext *UNUSED(C), wmManipulatorGroupType *UNUSED(wgt)) +{ + if (U.manipulator_flag & USER_MANIPULATOR_DRAW_NAVIGATE) { + return true; + } + return false; + +} + +static void WIDGETGROUP_navigate_setup(const bContext *UNUSED(C), wmManipulatorGroup *mgroup) +{ + struct NavigateWidgetGroup *navgroup = MEM_callocN(sizeof(struct NavigateWidgetGroup), __func__); + + navgroup->region_size[0] = -1; + navgroup->region_size[1] = -1; + + wmOperatorType *ot_viewnumpad = WM_operatortype_find("VIEW3D_OT_viewnumpad", true); + + for (int i = 0; i < MPR_TOTAL; i++) { + const struct NavigateManipulatorInfo *info = &g_navigate_params[i]; + navgroup->mpr_array[i] = WM_manipulator_new(info->manipulator, mgroup, NULL); + wmManipulator *mpr = navgroup->mpr_array[i]; + mpr->flag |= WM_MANIPULATOR_GRAB_CURSOR | WM_MANIPULATOR_DRAW_MODAL; + mpr->color[3] = 0.2f; + mpr->color_hi[3] = 0.4f; + + /* may be overwritten later */ + mpr->scale_basis = (MANIPULATOR_SIZE * MANIPULATOR_MINI_FAC) / 2; + if (info->shape != NULL) { + PropertyRNA *prop = RNA_struct_find_property(mpr->ptr, "shape"); + RNA_property_string_set_bytes( + mpr->ptr, prop, + (const char *)info->shape, info->shape_size); + } + + wmOperatorType *ot = WM_operatortype_find(info->opname, true); + WM_manipulator_operator_set(mpr, 0, ot, NULL); + } + + { + wmManipulator *mpr = navgroup->mpr_array[MPR_CAMERA]; + PointerRNA *ptr = WM_manipulator_operator_set(mpr, 0, ot_viewnumpad, NULL); + RNA_enum_set(ptr, "type", RV3D_VIEW_CAMERA); + } + + /* Click only buttons (not modal). */ + { + int mpr_ids[] = {MPR_PERSP, MPR_ORTHO, MPR_CAMERA}; + for (int i = 0; i < ARRAY_SIZE(mpr_ids); i++) { + wmManipulator *mpr = navgroup->mpr_array[mpr_ids[i]]; + RNA_boolean_set(mpr->ptr, "show_drag", false); + } + } + + /* Modal operators, don't use initial mouse location since we're clicking on a button. */ + { + int mpr_ids[] = {MPR_MOVE, MPR_ROTATE, MPR_ZOOM}; + for (int i = 0; i < ARRAY_SIZE(mpr_ids); i++) { + wmManipulator *mpr = navgroup->mpr_array[mpr_ids[i]]; + wmManipulatorOpElem *mpop = WM_manipulator_operator_get(mpr, 0); + RNA_boolean_set(&mpop->ptr, "use_mouse_init", false); + } + } + + { + wmManipulator *mpr = navgroup->mpr_array[MPR_ROTATE]; + mpr->scale_basis = MANIPULATOR_SIZE / 2; + char mapping[6] = { + RV3D_VIEW_LEFT, + RV3D_VIEW_RIGHT, + RV3D_VIEW_FRONT, + RV3D_VIEW_BACK, + RV3D_VIEW_BOTTOM, + RV3D_VIEW_TOP, + }; + + for (int part_index = 0; part_index < 6; part_index += 1) { + PointerRNA *ptr = WM_manipulator_operator_set(mpr, part_index + 1, ot_viewnumpad, NULL); + RNA_enum_set(ptr, "type", mapping[part_index]); + } + + /* When dragging an axis, use this instead. */ + mpr->drag_part = 0; + } + + mgroup->customdata = navgroup; +} + +static void WIDGETGROUP_navigate_draw_prepare(const bContext *C, wmManipulatorGroup *mgroup) +{ + struct NavigateWidgetGroup *navgroup = mgroup->customdata; + ARegion *ar = CTX_wm_region(C); + const RegionView3D *rv3d = ar->regiondata; + + for (int i = 0; i < 3; i++) { + copy_v3_v3(navgroup->mpr_array[MPR_ROTATE]->matrix_offset[i], rv3d->viewmat[i]); + } + + if ((navgroup->state.ar.winx == ar->winx) && + (navgroup->state.ar.winy == ar->winy) && + (navgroup->state.rv3d.is_persp == rv3d->is_persp) && + (navgroup->state.rv3d.viewlock == rv3d->viewlock)) + { + return; + } + + + navgroup->state.ar.winx = ar->winx; + navgroup->state.ar.winy = ar->winy; + navgroup->state.rv3d.is_persp = rv3d->is_persp; + navgroup->state.rv3d.viewlock = rv3d->viewlock; + + + const float icon_size = MANIPULATOR_SIZE; + const float icon_offset = (icon_size / 2.0) * MANIPULATOR_OFFSET_FAC * U.ui_scale; + const float icon_offset_mini = icon_size * MANIPULATOR_MINI_OFFSET_FAC * U.ui_scale; + const float co[2] = {ar->winx - icon_offset, ar->winy - icon_offset}; + + wmManipulator *mpr; + + for (uint i = 0; i < ARRAY_SIZE(navgroup->mpr_array); i++) { + mpr = navgroup->mpr_array[i]; + WM_manipulator_set_flag(mpr, WM_MANIPULATOR_HIDDEN, true); + } + + if ((rv3d->viewlock & RV3D_LOCKED) == 0) { + mpr = navgroup->mpr_array[MPR_ROTATE]; + mpr->matrix_basis[3][0] = co[0]; + mpr->matrix_basis[3][1] = co[1]; + WM_manipulator_set_flag(mpr, WM_MANIPULATOR_HIDDEN, false); + + mpr = navgroup->mpr_array[MPR_MOVE]; + mpr->matrix_basis[3][0] = co[0] + icon_offset_mini; + mpr->matrix_basis[3][1] = co[1] - icon_offset_mini; + WM_manipulator_set_flag(mpr, WM_MANIPULATOR_HIDDEN, false); + + mpr = navgroup->mpr_array[MPR_ZOOM]; + mpr->matrix_basis[3][0] = co[0] - icon_offset_mini; + mpr->matrix_basis[3][1] = co[1] - icon_offset_mini; + WM_manipulator_set_flag(mpr, WM_MANIPULATOR_HIDDEN, false); + + mpr = navgroup->mpr_array[rv3d->is_persp ? MPR_ORTHO : MPR_PERSP]; + mpr->matrix_basis[3][0] = co[0] + icon_offset_mini; + mpr->matrix_basis[3][1] = co[1] + icon_offset_mini; + WM_manipulator_set_flag(mpr, WM_MANIPULATOR_HIDDEN, false); + + mpr = navgroup->mpr_array[MPR_CAMERA]; + mpr->matrix_basis[3][0] = co[0] - icon_offset_mini; + mpr->matrix_basis[3][1] = co[1] + icon_offset_mini; + WM_manipulator_set_flag(mpr, WM_MANIPULATOR_HIDDEN, false); + } + else { + /* RV3D_LOCKED: only show supported buttons. */ + mpr = navgroup->mpr_array[MPR_MOVE]; + mpr->matrix_basis[3][0] = co[0] + icon_offset_mini; + mpr->matrix_basis[3][1] = co[1] + icon_offset_mini; + WM_manipulator_set_flag(mpr, WM_MANIPULATOR_HIDDEN, false); + + mpr = navgroup->mpr_array[MPR_ZOOM]; + mpr->matrix_basis[3][0] = co[0]; + mpr->matrix_basis[3][1] = co[1] + icon_offset_mini; + WM_manipulator_set_flag(mpr, WM_MANIPULATOR_HIDDEN, false); + } +} + +void VIEW3D_WGT_navigate(wmManipulatorGroupType *wgt) +{ + wgt->name = "View3D Navigate"; + wgt->idname = "VIEW3D_WGT_navigate"; + + wgt->flag |= (WM_MANIPULATORGROUPTYPE_PERSISTENT | + WM_MANIPULATORGROUPTYPE_SCALE | + WM_MANIPULATORGROUPTYPE_DRAW_MODAL_ALL); + + wgt->poll = WIDGETGROUP_navigate_poll; + wgt->setup = WIDGETGROUP_navigate_setup; + wgt->draw_prepare = WIDGETGROUP_navigate_draw_prepare; +} + +/** \} */ diff --git a/source/blender/editors/space_view3d/view3d_manipulator_navigate_type.c b/source/blender/editors/space_view3d/view3d_manipulator_navigate_type.c new file mode 100644 index 00000000000..424b5dae402 --- /dev/null +++ b/source/blender/editors/space_view3d/view3d_manipulator_navigate_type.c @@ -0,0 +1,307 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file view3d_manipulator_navigate_type.c + * \ingroup wm + * + * \name Custom Orientation/Navigation Manipulator for the 3D View + * + * \brief Simple manipulator to axis and translate. + * + * - scale_basis: used for the size. + * - matrix_basis: used for the location. + * - matrix_offset: used to store the orientation. + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_math.h" +#include "BLI_sort_utils.h" + +#include "BKE_context.h" + +#include "BIF_gl.h" +#include "BIF_glutil.h" + +#include "GPU_immediate.h" +#include "GPU_immediate_util.h" +#include "GPU_matrix.h" + +#include "RNA_access.h" +#include "RNA_define.h" + +#include "UI_resources.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "ED_screen.h" + +#include "view3d_intern.h" + +#define DIAL_RESOLUTION 32 + +#define HANDLE_SIZE 0.33 + +static void axis_geom_draw( + const wmManipulator *mpr, const float color[4], const bool UNUSED(select)) +{ + glLineWidth(mpr->line_width); + + Gwn_VertFormat *format = immVertexFormat(); + const uint pos_id = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT); + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); + + /* flip z for reverse */ + const float cone_coords[5][3] = { + {-1, -1, 4}, + {-1, +1, 4}, + {+1, +1, 4}, + {+1, -1, 4}, + {0, 0, 2}, + }; + + struct { + float depth; + char index; + char axis; + char is_pos; + } axis_order[6] = { + {-mpr->matrix_offset[0][2], 0, 0, false}, + {+mpr->matrix_offset[0][2], 1, 0, true}, + {-mpr->matrix_offset[1][2], 2, 1, false}, + {+mpr->matrix_offset[1][2], 3, 1, true}, + {-mpr->matrix_offset[2][2], 4, 2, false}, + {+mpr->matrix_offset[2][2], 5, 2, true}, + }; + qsort(&axis_order, ARRAY_SIZE(axis_order), sizeof(axis_order[0]), BLI_sortutil_cmp_float); + + const float scale_axis = 0.25f; + static const float axis_highlight[4] = {1, 1, 1, 1}; + static const float axis_nop[4] = {1, 1, 1, 0}; + static const float axis_black[4] = {0, 0, 0, 1}; + static float axis_color[3][4]; + gpuPushMatrix(); + gpuMultMatrix(mpr->matrix_offset); + + bool draw_center_done = false; + + for (int axis_index = 0; axis_index < ARRAY_SIZE(axis_order); axis_index++) { + const int index = axis_order[axis_index].index; + const int axis = axis_order[axis_index].axis; + const bool is_pos = axis_order[axis_index].is_pos; + + /* Draw slightly before, so axis aligned arrows draw ontop. */ + if ((draw_center_done == false) && (axis_order[axis_index].depth > -0.01f)) { + + /* Circle defining active area (revert back to 2D space). */ + { + gpuPopMatrix(); + immUniformColor4fv(color); + imm_draw_circle_fill_3d(pos_id, 0, 0, 1.0f, DIAL_RESOLUTION); + gpuPushMatrix(); + gpuMultMatrix(mpr->matrix_offset); + } + + /* Center cube. */ + { + float center[3], size[3]; + + zero_v3(center); + copy_v3_fl(size, HANDLE_SIZE); + + glEnable(GL_DEPTH_TEST); + glDepthMask(GL_TRUE); + glDepthFunc(GL_LEQUAL); + glBlendFunc(GL_ONE, GL_ZERO); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + glEnable(GL_LINE_SMOOTH); + glEnable(GL_BLEND); + glLineWidth(1.0f); + /* Just draw depth values. */ + immUniformColor4fv(axis_nop); + imm_draw_cube_fill_3d(pos_id, center, size); + immUniformColor4fv(axis_black); + madd_v3_v3fl( + center, + (float [3]){ + mpr->matrix_offset[0][2], + mpr->matrix_offset[1][2], + mpr->matrix_offset[2][2]}, + 0.08f); + imm_draw_cube_wire_3d(pos_id, center, size); + glDisable(GL_BLEND); + glDisable(GL_LINE_SMOOTH); + glDisable(GL_DEPTH_TEST); + } + + draw_center_done = true; + } + UI_GetThemeColor3fv(TH_AXIS_X + axis, axis_color[axis]); + axis_color[axis][3] = 1.0f; + + const int index_z = axis; + const int index_y = (axis + 1) % 3; + const int index_x = (axis + 2) % 3; + +#define ROTATED_VERT(v_orig) \ + { \ + float v[3]; \ + copy_v3_v3(v, v_orig); \ + if (is_pos == 0) { \ + v[2] *= -1.0f; \ + } \ + immVertex3f(pos_id, v[index_x] * scale_axis, v[index_y] * scale_axis, v[index_z] * scale_axis); \ + } ((void)0) + + bool ok = true; + + /* skip view align axis */ + if (len_squared_v2(mpr->matrix_offset[axis]) < 1e-6f && (mpr->matrix_offset[axis][2] > 0.0f) == is_pos) { + ok = false; + } + if (ok) { + immUniformColor4fv(index + 1 == mpr->highlight_part ? axis_highlight : axis_color[axis]); + immBegin(GWN_PRIM_TRI_FAN, 6); + ROTATED_VERT(cone_coords[4]); + for (int j = 0; j <= 4; j++) { + ROTATED_VERT(cone_coords[j % 4]); + } + immEnd(); + } + +#undef ROTATED_VERT + } + + gpuPopMatrix(); + immUnbindProgram(); +} + +static void axis3d_draw_intern( + const bContext *UNUSED(C), wmManipulator *mpr, + const bool select, const bool highlight) +{ + const float *color = highlight ? mpr->color_hi : mpr->color; + float matrix_final[4][4]; + float matrix_unit[4][4]; + + unit_m4(matrix_unit); + + WM_manipulator_calc_matrix_final_params( + mpr, + &((struct WM_ManipulatorMatrixParams) { + .matrix_offset = matrix_unit, + }), matrix_final); + + gpuPushMatrix(); + gpuMultMatrix(matrix_final); + + glEnable(GL_BLEND); + axis_geom_draw(mpr, color, select); + glDisable(GL_BLEND); + gpuPopMatrix(); +} + +static void manipulator_axis_draw(const bContext *C, wmManipulator *mpr) +{ + const bool is_modal = mpr->state & WM_MANIPULATOR_STATE_MODAL; + const bool is_highlight = (mpr->state & WM_MANIPULATOR_STATE_HIGHLIGHT) != 0; + + (void)is_modal; + + glEnable(GL_BLEND); + axis3d_draw_intern(C, mpr, false, is_highlight); + glDisable(GL_BLEND); +} + +static int manipulator_axis_test_select( + bContext *UNUSED(C), wmManipulator *mpr, const wmEvent *event) +{ + float point_local[2] = {UNPACK2(event->mval)}; + sub_v2_v2(point_local, mpr->matrix_basis[3]); + mul_v2_fl(point_local, 1.0f / (mpr->scale_basis * U.ui_scale)); + + const float len_sq = len_squared_v2(point_local); + if (len_sq > 1.0) { + return -1; + } + + int part_best = -1; + int part_index = 1; + /* Use 'SQUARE(HANDLE_SIZE)' if we want to be able to _not_ focus on one of the axis. */ + float i_best_len_sq = FLT_MAX; + for (int i = 0; i < 3; i++) { + for (int is_pos = 0; is_pos < 2; is_pos++) { + float co[2] = { + mpr->matrix_offset[i][0] * (is_pos ? 1 : -1), + mpr->matrix_offset[i][1] * (is_pos ? 1 : -1), + }; + + bool ok = true; + + /* Check if we're viewing on an axis, there is no point to clicking on the current axis so show the reverse. */ + if (len_squared_v2(co) < 1e-6f && (mpr->matrix_offset[i][2] > 0.0f) == is_pos) { + ok = false; + } + + if (ok) { + const float len_axis_sq = len_squared_v2v2(co, point_local); + if (len_axis_sq < i_best_len_sq) { + part_best = part_index; + i_best_len_sq = len_axis_sq; + } + } + part_index += 1; + } + } + + if (part_best != -1) { + return part_best; + } + + /* The 'mpr->scale_final' is already applied when projecting. */ + if (len_sq < 1.0f) { + return 0; + } + + return -1; +} + +static int manipulator_axis_cursor_get(wmManipulator *mpr) +{ + if (mpr->highlight_part > 0) { + return CURSOR_EDIT; + } + return BC_NSEW_SCROLLCURSOR; +} + +void VIEW3D_WT_navigate_rotate(wmManipulatorType *wt) +{ + /* identifiers */ + wt->idname = "VIEW3D_WT_navigate_rotate"; + + /* api callbacks */ + wt->draw = manipulator_axis_draw; + wt->test_select = manipulator_axis_test_select; + wt->cursor_get = manipulator_axis_cursor_get; + + wt->struct_size = sizeof(wmManipulator); +} diff --git a/source/blender/editors/space_view3d/view3d_manipulator_ruler.c b/source/blender/editors/space_view3d/view3d_manipulator_ruler.c index 230b4f44c16..e8d540bcc9d 100644 --- a/source/blender/editors/space_view3d/view3d_manipulator_ruler.c +++ b/source/blender/editors/space_view3d/view3d_manipulator_ruler.c @@ -148,6 +148,11 @@ static RulerItem *ruler_item_add(wmManipulatorGroup *mgroup) return ruler_item; } +static void ruler_item_remove(bContext *C, wmManipulatorGroup *mgroup, RulerItem *ruler_item) +{ + WM_manipulator_unlink(&mgroup->manipulators, mgroup->parent_mmap, &ruler_item->mpr, C); +} + static void ruler_item_as_string(RulerItem *ruler_item, UnitSettings *unit, char *numstr, size_t numstr_size, int prec) { @@ -908,16 +913,24 @@ static void manipulator_ruler_exit(bContext *C, wmManipulator *mpr, const bool c { wmManipulatorGroup *mgroup = mpr->parent_mgroup; RulerInfo *ruler_info = mgroup->customdata; - RulerItem *ruler_item = (RulerItem *)mpr; - RulerInteraction *inter = mpr->interaction_data; if (!cancel) { if (ruler_info->state == RULER_STATE_DRAG) { + RulerItem *ruler_item = (RulerItem *)mpr; + RulerInteraction *inter = mpr->interaction_data; /* rubber-band angle removal */ - if (ruler_item && (inter->co_index == 1) && (ruler_item->flag & RULERITEM_USE_ANGLE)) { - if (!inter->inside_region) { + if (!inter->inside_region) { + if ((inter->co_index == 1) && (ruler_item->flag & RULERITEM_USE_ANGLE)) { ruler_item->flag &= ~RULERITEM_USE_ANGLE; } + else { + /* Not ideal, since the ruler isn't a mode and we don't want to override delete key + * use dragging out of the view for removal. */ + ruler_item_remove(C, mgroup, ruler_item); + ruler_item = NULL; + mpr = NULL; + inter = NULL; + } } if (ruler_info->snap_flag & RULER_SNAP_OK) { ruler_info->snap_flag &= ~RULER_SNAP_OK; @@ -928,7 +941,9 @@ static void manipulator_ruler_exit(bContext *C, wmManipulator *mpr, const bool c view3d_ruler_to_gpencil(C, mgroup); } - MEM_SAFE_FREE(mpr->interaction_data); + if (mpr) { + MEM_SAFE_FREE(mpr->interaction_data); + } ruler_state_set(C, ruler_info, RULER_STATE_NORMAL); } @@ -996,7 +1011,7 @@ void VIEW3D_WGT_ruler(wmManipulatorGroupType *wgt) wgt->name = "Ruler Widgets"; wgt->idname = view3d_wgt_ruler_id; - wgt->flag |= WM_MANIPULATORGROUPTYPE_SCALE; + wgt->flag |= WM_MANIPULATORGROUPTYPE_SCALE | WM_MANIPULATORGROUPTYPE_DRAW_MODAL_ALL; wgt->mmap_params.spaceid = SPACE_VIEW3D; wgt->mmap_params.regionid = RGN_TYPE_WINDOW; diff --git a/source/blender/editors/space_view3d/view3d_project.c b/source/blender/editors/space_view3d/view3d_project.c index f8b02f0b405..ba3e78b25b9 100644 --- a/source/blender/editors/space_view3d/view3d_project.c +++ b/source/blender/editors/space_view3d/view3d_project.c @@ -277,6 +277,11 @@ eV3DProjStatus ED_view3d_project_float_object(const ARegion *ar, const float co[ /* More Generic Window/Ray/Vector projection functions * *************************************************** */ +float ED_view3d_pixel_size(const RegionView3D *rv3d, const float co[3]) +{ + return mul_project_m4_v3_zfac((float(*)[4])rv3d->persmat, co) * rv3d->pixsize * U.pixelsize; +} + /** * Calculate a depth value from \a co, use with #ED_view3d_win_to_delta */ @@ -304,6 +309,7 @@ float ED_view3d_calc_zfac(const RegionView3D *rv3d, const float co[3], bool *r_f } static void view3d_win_to_ray_segment( + const struct Depsgraph *depsgraph, const ARegion *ar, const View3D *v3d, const float mval[2], float r_ray_co[3], float r_ray_dir[3], float r_ray_start[3], float r_ray_end[3]) { @@ -321,7 +327,7 @@ static void view3d_win_to_ray_segment( start_offset = -end_offset; } else { - ED_view3d_clip_range_get(v3d, rv3d, &start_offset, &end_offset, false); + ED_view3d_clip_range_get(depsgraph, v3d, rv3d, &start_offset, &end_offset, false); } if (r_ray_start) { @@ -360,12 +366,13 @@ bool ED_view3d_clip_segment(const RegionView3D *rv3d, float ray_start[3], float * \return success, false if the ray is totally clipped. */ bool ED_view3d_win_to_ray_ex( + const struct Depsgraph *depsgraph, const ARegion *ar, const View3D *v3d, const float mval[2], float r_ray_co[3], float r_ray_normal[3], float r_ray_start[3], bool do_clip) { float ray_end[3]; - view3d_win_to_ray_segment(ar, v3d, mval, r_ray_co, r_ray_normal, r_ray_start, ray_end); + view3d_win_to_ray_segment(depsgraph, ar, v3d, mval, r_ray_co, r_ray_normal, r_ray_start, ray_end); /* bounds clipping */ if (do_clip) { @@ -389,10 +396,11 @@ bool ED_view3d_win_to_ray_ex( * \return success, false if the ray is totally clipped. */ bool ED_view3d_win_to_ray( + const struct Depsgraph *depsgraph, const ARegion *ar, const View3D *v3d, const float mval[2], float r_ray_start[3], float r_ray_normal[3], const bool do_clip) { - return ED_view3d_win_to_ray_ex(ar, v3d, mval, NULL, r_ray_normal, r_ray_start, do_clip); + return ED_view3d_win_to_ray_ex(depsgraph,ar, v3d, mval, NULL, r_ray_normal, r_ray_start, do_clip); } /** @@ -622,10 +630,11 @@ void ED_view3d_win_to_vector(const ARegion *ar, const float mval[2], float out[3 * \param do_clip Optionally clip the ray by the view clipping planes. * \return success, false if the segment is totally clipped. */ -bool ED_view3d_win_to_segment(const ARegion *ar, View3D *v3d, const float mval[2], +bool ED_view3d_win_to_segment(const struct Depsgraph *depsgraph, + const ARegion *ar, View3D *v3d, const float mval[2], float r_ray_start[3], float r_ray_end[3], const bool do_clip) { - view3d_win_to_ray_segment(ar, v3d, mval, NULL, NULL, r_ray_start, r_ray_end); + view3d_win_to_ray_segment(depsgraph, ar, v3d, mval, NULL, NULL, r_ray_start, r_ray_end); /* bounds clipping */ if (do_clip) { diff --git a/source/blender/editors/space_view3d/view3d_utils.c b/source/blender/editors/space_view3d/view3d_utils.c new file mode 100644 index 00000000000..7bb3f443ac6 --- /dev/null +++ b/source/blender/editors/space_view3d/view3d_utils.c @@ -0,0 +1,1436 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2008 Blender Foundation. + * All rights reserved. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/space_view3d/view3d_utils.c + * \ingroup spview3d + * + * 3D View checks and manipulation (no operators). + */ + +#include <string.h> +#include <stdio.h> +#include <math.h> +#include <float.h> + +#include "DNA_camera_types.h" +#include "DNA_curve_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" + +#include "MEM_guardedalloc.h" + +#include "BLI_bitmap_draw_2d.h" +#include "BLI_blenlib.h" +#include "BLI_math.h" +#include "BLI_utildefines.h" + +#include "BKE_camera.h" +#include "BKE_context.h" +#include "BKE_object.h" +#include "BKE_screen.h" + +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_query.h" + +#include "BIF_gl.h" +#include "BIF_glutil.h" + +#include "GPU_matrix.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "ED_keyframing.h" +#include "ED_screen.h" +#include "ED_view3d.h" + +#include "view3d_intern.h" /* own include */ + +/* -------------------------------------------------------------------- */ +/** \name View Data Access Utilities + * + * \{ */ + +float *ED_view3d_cursor3d_get(Scene *scene, View3D *v3d) +{ + if (v3d && v3d->localvd) return v3d->cursor; + else return scene->cursor; +} + +Camera *ED_view3d_camera_data_get(View3D *v3d, RegionView3D *rv3d) +{ + /* establish the camera object, so we can default to view mapping if anything is wrong with it */ + if ((rv3d->persp == RV3D_CAMOB) && v3d->camera && (v3d->camera->type == OB_CAMERA)) { + return v3d->camera->data; + } + else { + return NULL; + } +} + +void ED_view3d_dist_range_get( + const View3D *v3d, + float r_dist_range[2]) +{ + r_dist_range[0] = v3d->grid * 0.001f; + r_dist_range[1] = v3d->far * 10.0f; +} + +/** + * \note copies logic of #ED_view3d_viewplane_get(), keep in sync. + */ +bool ED_view3d_clip_range_get( + const Depsgraph *depsgraph, + const View3D *v3d, const RegionView3D *rv3d, + float *r_clipsta, float *r_clipend, + const bool use_ortho_factor) +{ + CameraParams params; + + BKE_camera_params_init(¶ms); + BKE_camera_params_from_view3d(¶ms, depsgraph, v3d, rv3d); + + if (use_ortho_factor && params.is_ortho) { + const float fac = 2.0f / (params.clipend - params.clipsta); + params.clipsta *= fac; + params.clipend *= fac; + } + + if (r_clipsta) *r_clipsta = params.clipsta; + if (r_clipend) *r_clipend = params.clipend; + + return params.is_ortho; +} + +bool ED_view3d_viewplane_get( + const Depsgraph *depsgraph, + const View3D *v3d, const RegionView3D *rv3d, int winx, int winy, + rctf *r_viewplane, float *r_clipsta, float *r_clipend, float *r_pixsize) +{ + CameraParams params; + + BKE_camera_params_init(¶ms); + BKE_camera_params_from_view3d(¶ms, depsgraph, v3d, rv3d); + BKE_camera_params_compute_viewplane(¶ms, winx, winy, 1.0f, 1.0f); + + if (r_viewplane) *r_viewplane = params.viewplane; + if (r_clipsta) *r_clipsta = params.clipsta; + if (r_clipend) *r_clipend = params.clipend; + if (r_pixsize) *r_pixsize = params.viewdx; + + return params.is_ortho; +} + +/** \} */ + + +/* -------------------------------------------------------------------- */ +/** \name View State/Context Utilities + * + * \{ */ + +/** + * Use this call when executing an operator, + * event system doesn't set for each event the OpenGL drawing context. + */ +void view3d_operator_needs_opengl(const bContext *C) +{ + wmWindow *win = CTX_wm_window(C); + ARegion *ar = CTX_wm_region(C); + + view3d_region_operator_needs_opengl(win, ar); +} + +void view3d_region_operator_needs_opengl(wmWindow *win, ARegion *ar) +{ + /* for debugging purpose, context should always be OK */ + if ((ar == NULL) || (ar->regiontype != RGN_TYPE_WINDOW)) { + printf("view3d_region_operator_needs_opengl error, wrong region\n"); + } + else { + RegionView3D *rv3d = ar->regiondata; + + wmSubWindowSet(win, ar->swinid); + gpuLoadProjectionMatrix(rv3d->winmat); + gpuLoadMatrix(rv3d->viewmat); + } +} + +/** + * Use instead of: ``bglPolygonOffset(rv3d->dist, ...)`` see bug [#37727] + */ +void ED_view3d_polygon_offset(const RegionView3D *rv3d, const float dist) +{ + float viewdist; + + if (rv3d->rflag & RV3D_ZOFFSET_DISABLED) { + return; + } + + viewdist = rv3d->dist; + + /* special exception for ortho camera (viewdist isnt used for perspective cameras) */ + if (dist != 0.0f) { + if (rv3d->persp == RV3D_CAMOB) { + if (rv3d->is_persp == false) { + viewdist = 1.0f / max_ff(fabsf(rv3d->winmat[0][0]), fabsf(rv3d->winmat[1][1])); + } + } + } + + bglPolygonOffset(viewdist, dist); +} + +bool ED_view3d_context_activate(bContext *C) +{ + bScreen *sc = CTX_wm_screen(C); + ScrArea *sa = CTX_wm_area(C); + ARegion *ar; + + /* sa can be NULL when called from python */ + if (sa == NULL || sa->spacetype != SPACE_VIEW3D) { + sa = BKE_screen_find_big_area(sc, SPACE_VIEW3D, 0); + } + + if (sa == NULL) { + return false; + } + + ar = BKE_area_find_region_active_win(sa); + if (ar == NULL) { + return false; + } + + /* bad context switch .. */ + CTX_wm_area_set(C, sa); + CTX_wm_region_set(C, ar); + + return true; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View Clipping Utilities + * + * \{ */ + +void ED_view3d_clipping_calc_from_boundbox(float clip[4][4], const BoundBox *bb, const bool is_flip) +{ + int val; + + for (val = 0; val < 4; val++) { + normal_tri_v3(clip[val], bb->vec[val], bb->vec[val == 3 ? 0 : val + 1], bb->vec[val + 4]); + if (UNLIKELY(is_flip)) { + negate_v3(clip[val]); + } + + clip[val][3] = -dot_v3v3(clip[val], bb->vec[val]); + } +} + +void ED_view3d_clipping_calc(BoundBox *bb, float planes[4][4], const ARegion *ar, const Object *ob, const rcti *rect) +{ + /* init in case unproject fails */ + memset(bb->vec, 0, sizeof(bb->vec)); + + /* four clipping planes and bounding volume */ + /* first do the bounding volume */ + for (int val = 0; val < 4; val++) { + float xs = (val == 0 || val == 3) ? rect->xmin : rect->xmax; + float ys = (val == 0 || val == 1) ? rect->ymin : rect->ymax; + + ED_view3d_unproject(ar, xs, ys, 0.0, bb->vec[val]); + ED_view3d_unproject(ar, xs, ys, 1.0, bb->vec[4 + val]); + } + + /* optionally transform to object space */ + if (ob) { + float imat[4][4]; + invert_m4_m4(imat, ob->obmat); + + for (int val = 0; val < 8; val++) { + mul_m4_v3(imat, bb->vec[val]); + } + } + + /* verify if we have negative scale. doing the transform before cross + * product flips the sign of the vector compared to doing cross product + * before transform then, so we correct for that. */ + int flip_sign = (ob) ? is_negative_m4(ob->obmat) : false; + + ED_view3d_clipping_calc_from_boundbox(planes, bb, flip_sign); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View Bound-Box Utilities + * + * \{ */ + +static bool view3d_boundbox_clip_m4(const BoundBox *bb, float persmatob[4][4]) +{ + int a, flag = -1, fl; + + for (a = 0; a < 8; a++) { + float vec[4], min, max; + copy_v3_v3(vec, bb->vec[a]); + vec[3] = 1.0; + mul_m4_v4(persmatob, vec); + max = vec[3]; + min = -vec[3]; + + fl = 0; + if (vec[0] < min) fl += 1; + if (vec[0] > max) fl += 2; + if (vec[1] < min) fl += 4; + if (vec[1] > max) fl += 8; + if (vec[2] < min) fl += 16; + if (vec[2] > max) fl += 32; + + flag &= fl; + if (flag == 0) return true; + } + + return false; +} + +bool ED_view3d_boundbox_clip_ex(const RegionView3D *rv3d, const BoundBox *bb, float obmat[4][4]) +{ + /* return 1: draw */ + + float persmatob[4][4]; + + if (bb == NULL) return true; + if (bb->flag & BOUNDBOX_DISABLED) return true; + + mul_m4_m4m4(persmatob, (float(*)[4])rv3d->persmat, obmat); + + return view3d_boundbox_clip_m4(bb, persmatob); +} + +bool ED_view3d_boundbox_clip(RegionView3D *rv3d, const BoundBox *bb) +{ + if (bb == NULL) return true; + if (bb->flag & BOUNDBOX_DISABLED) return true; + + return view3d_boundbox_clip_m4(bb, rv3d->persmatob); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View Perspective & Mode Switching + * + * Misc view utility functions. + * \{ */ + +bool ED_view3d_offset_lock_check(const View3D *v3d, const RegionView3D *rv3d) +{ + return (rv3d->persp != RV3D_CAMOB) && (v3d->ob_centre_cursor || v3d->ob_centre); +} + +/** + * Use to store the last view, before entering camera view. + */ +void ED_view3d_lastview_store(RegionView3D *rv3d) +{ + copy_qt_qt(rv3d->lviewquat, rv3d->viewquat); + rv3d->lview = rv3d->view; + if (rv3d->persp != RV3D_CAMOB) { + rv3d->lpersp = rv3d->persp; + } +} + +void ED_view3d_lock_clear(View3D *v3d) +{ + v3d->ob_centre = NULL; + v3d->ob_centre_bone[0] = '\0'; + v3d->ob_centre_cursor = false; + v3d->flag2 &= ~V3D_LOCK_CAMERA; +} + +/** + * For viewport operators that exit camera perspective. + * + * \note This differs from simply setting ``rv3d->persp = persp`` because it + * sets the ``ofs`` and ``dist`` values of the viewport so it matches the camera, + * otherwise switching out of camera view may jump to a different part of the scene. + */ +void ED_view3d_persp_switch_from_camera(View3D *v3d, RegionView3D *rv3d, const char persp) +{ + BLI_assert(rv3d->persp == RV3D_CAMOB); + BLI_assert(persp != RV3D_CAMOB); + + if (v3d->camera) { + rv3d->dist = ED_view3d_offset_distance(v3d->camera->obmat, rv3d->ofs, VIEW3D_DIST_FALLBACK); + ED_view3d_from_object(v3d->camera, rv3d->ofs, rv3d->viewquat, &rv3d->dist, NULL); + } + + if (!ED_view3d_camera_lock_check(v3d, rv3d)) { + rv3d->persp = persp; + } +} +/** + * Action to take when rotating the view, + * handle auto-persp and logic for switching out of views. + * + * shared with NDOF. + */ +bool ED_view3d_persp_ensure(struct View3D *v3d, ARegion *ar) +{ + RegionView3D *rv3d = ar->regiondata; + const bool autopersp = (U.uiflag & USER_AUTOPERSP) != 0; + + BLI_assert((rv3d->viewlock & RV3D_LOCKED) == 0); + + if (ED_view3d_camera_lock_check(v3d, rv3d)) + return false; + + if (rv3d->persp != RV3D_PERSP) { + if (rv3d->persp == RV3D_CAMOB) { + /* If autopersp and previous view was an axis one, switch back to PERSP mode, else reuse previous mode. */ + char persp = (autopersp && RV3D_VIEW_IS_AXIS(rv3d->lview)) ? RV3D_PERSP : rv3d->lpersp; + ED_view3d_persp_switch_from_camera(v3d, rv3d, persp); + } + else if (autopersp && RV3D_VIEW_IS_AXIS(rv3d->view)) { + rv3d->persp = RV3D_PERSP; + } + return true; + } + + return false; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Camera Lock API + * + * Lock the camera to the view-port, allowing view manipulation to transform the camera. + * \{ */ + +/** + * \return true when the view-port is locked to its camera. + */ +bool ED_view3d_camera_lock_check(const View3D *v3d, const RegionView3D *rv3d) +{ + return ((v3d->camera) && + (!ID_IS_LINKED(v3d->camera)) && + (v3d->flag2 & V3D_LOCK_CAMERA) && + (rv3d->persp == RV3D_CAMOB)); +} + +/** + * Apply the camera object transformation to the view-port. + * (needed so we can use regular view-port manipulation operators, that sync back to the camera). + */ +void ED_view3d_camera_lock_init_ex(View3D *v3d, RegionView3D *rv3d, const bool calc_dist) +{ + if (ED_view3d_camera_lock_check(v3d, rv3d)) { + if (calc_dist) { + /* using a fallback dist is OK here since ED_view3d_from_object() compensates for it */ + rv3d->dist = ED_view3d_offset_distance(v3d->camera->obmat, rv3d->ofs, VIEW3D_DIST_FALLBACK); + } + ED_view3d_from_object(v3d->camera, rv3d->ofs, rv3d->viewquat, &rv3d->dist, NULL); + } +} + +void ED_view3d_camera_lock_init(View3D *v3d, RegionView3D *rv3d) +{ + ED_view3d_camera_lock_init_ex(v3d, rv3d, true); +} + +/** + * Apply the view-port transformation back to the camera object. + * + * \return true if the camera is moved. + */ +bool ED_view3d_camera_lock_sync(View3D *v3d, RegionView3D *rv3d) +{ + if (ED_view3d_camera_lock_check(v3d, rv3d)) { + ObjectTfmProtectedChannels obtfm; + Object *root_parent; + + if ((U.uiflag & USER_CAM_LOCK_NO_PARENT) == 0 && (root_parent = v3d->camera->parent)) { + Object *ob_update; + float tmat[4][4]; + float imat[4][4]; + float view_mat[4][4]; + float diff_mat[4][4]; + float parent_mat[4][4]; + + while (root_parent->parent) { + root_parent = root_parent->parent; + } + + ED_view3d_to_m4(view_mat, rv3d->ofs, rv3d->viewquat, rv3d->dist); + + normalize_m4_m4(tmat, v3d->camera->obmat); + + invert_m4_m4(imat, tmat); + mul_m4_m4m4(diff_mat, view_mat, imat); + + mul_m4_m4m4(parent_mat, diff_mat, root_parent->obmat); + + BKE_object_tfm_protected_backup(root_parent, &obtfm); + BKE_object_apply_mat4(root_parent, parent_mat, true, false); + BKE_object_tfm_protected_restore(root_parent, &obtfm, root_parent->protectflag); + + ob_update = v3d->camera; + while (ob_update) { + DEG_id_tag_update(&ob_update->id, OB_RECALC_OB); + WM_main_add_notifier(NC_OBJECT | ND_TRANSFORM, ob_update); + ob_update = ob_update->parent; + } + } + else { + /* always maintain the same scale */ + const short protect_scale_all = (OB_LOCK_SCALEX | OB_LOCK_SCALEY | OB_LOCK_SCALEZ); + BKE_object_tfm_protected_backup(v3d->camera, &obtfm); + ED_view3d_to_object(v3d->camera, rv3d->ofs, rv3d->viewquat, rv3d->dist); + BKE_object_tfm_protected_restore(v3d->camera, &obtfm, v3d->camera->protectflag | protect_scale_all); + + DEG_id_tag_update(&v3d->camera->id, OB_RECALC_OB); + WM_main_add_notifier(NC_OBJECT | ND_TRANSFORM, v3d->camera); + } + + return true; + } + else { + return false; + } +} + +bool ED_view3d_camera_autokey( + Scene *scene, ID *id_key, + struct bContext *C, const bool do_rotate, const bool do_translate) +{ + if (autokeyframe_cfra_can_key(scene, id_key)) { + const float cfra = (float)CFRA; + ListBase dsources = {NULL, NULL}; + + /* add data-source override for the camera object */ + ANIM_relative_keyingset_add_source(&dsources, id_key, NULL, NULL); + + /* insert keyframes + * 1) on the first frame + * 2) on each subsequent frame + * TODO: need to check in future that frame changed before doing this + */ + if (do_rotate) { + struct KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, ANIM_KS_ROTATION_ID); + ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra); + } + if (do_translate) { + struct KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, ANIM_KS_LOCATION_ID); + ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra); + } + + /* free temp data */ + BLI_freelistN(&dsources); + + return true; + } + else { + return false; + } +} + +/** + * Call after modifying a locked view. + * + * \note Not every view edit currently auto-keys (numpad for eg), + * this is complicated because of smoothview. + */ +bool ED_view3d_camera_lock_autokey( + View3D *v3d, RegionView3D *rv3d, + struct bContext *C, const bool do_rotate, const bool do_translate) +{ + /* similar to ED_view3d_cameracontrol_update */ + if (ED_view3d_camera_lock_check(v3d, rv3d)) { + Scene *scene = CTX_data_scene(C); + ID *id_key; + Object *root_parent; + if ((U.uiflag & USER_CAM_LOCK_NO_PARENT) == 0 && (root_parent = v3d->camera->parent)) { + while (root_parent->parent) { + root_parent = root_parent->parent; + } + id_key = &root_parent->id; + } + else { + id_key = &v3d->camera->id; + } + + return ED_view3d_camera_autokey(scene, id_key, C, do_rotate, do_translate); + } + else { + return false; + } +} + +/** \} */ + + + +/* -------------------------------------------------------------------- */ +/** \name Box View Support + * + * Use with quad-split so each view is clipped by the bounds of each view axis. + * \{ */ + +static void view3d_boxview_clip(ScrArea *sa) +{ + ARegion *ar; + BoundBox *bb = MEM_callocN(sizeof(BoundBox), "clipbb"); + float clip[6][4]; + float x1 = 0.0f, y1 = 0.0f, z1 = 0.0f, ofs[3] = {0.0f, 0.0f, 0.0f}; + int val; + + /* create bounding box */ + for (ar = sa->regionbase.first; ar; ar = ar->next) { + if (ar->regiontype == RGN_TYPE_WINDOW) { + RegionView3D *rv3d = ar->regiondata; + + if (rv3d->viewlock & RV3D_BOXCLIP) { + if (ELEM(rv3d->view, RV3D_VIEW_TOP, RV3D_VIEW_BOTTOM)) { + if (ar->winx > ar->winy) x1 = rv3d->dist; + else x1 = ar->winx * rv3d->dist / ar->winy; + + if (ar->winx > ar->winy) y1 = ar->winy * rv3d->dist / ar->winx; + else y1 = rv3d->dist; + copy_v2_v2(ofs, rv3d->ofs); + } + else if (ELEM(rv3d->view, RV3D_VIEW_FRONT, RV3D_VIEW_BACK)) { + ofs[2] = rv3d->ofs[2]; + + if (ar->winx > ar->winy) z1 = ar->winy * rv3d->dist / ar->winx; + else z1 = rv3d->dist; + } + } + } + } + + for (val = 0; val < 8; val++) { + if (ELEM(val, 0, 3, 4, 7)) + bb->vec[val][0] = -x1 - ofs[0]; + else + bb->vec[val][0] = x1 - ofs[0]; + + if (ELEM(val, 0, 1, 4, 5)) + bb->vec[val][1] = -y1 - ofs[1]; + else + bb->vec[val][1] = y1 - ofs[1]; + + if (val > 3) + bb->vec[val][2] = -z1 - ofs[2]; + else + bb->vec[val][2] = z1 - ofs[2]; + } + + /* normals for plane equations */ + normal_tri_v3(clip[0], bb->vec[0], bb->vec[1], bb->vec[4]); + normal_tri_v3(clip[1], bb->vec[1], bb->vec[2], bb->vec[5]); + normal_tri_v3(clip[2], bb->vec[2], bb->vec[3], bb->vec[6]); + normal_tri_v3(clip[3], bb->vec[3], bb->vec[0], bb->vec[7]); + normal_tri_v3(clip[4], bb->vec[4], bb->vec[5], bb->vec[6]); + normal_tri_v3(clip[5], bb->vec[0], bb->vec[2], bb->vec[1]); + + /* then plane equations */ + for (val = 0; val < 6; val++) { + clip[val][3] = -dot_v3v3(clip[val], bb->vec[val % 5]); + } + + /* create bounding box */ + for (ar = sa->regionbase.first; ar; ar = ar->next) { + if (ar->regiontype == RGN_TYPE_WINDOW) { + RegionView3D *rv3d = ar->regiondata; + + if (rv3d->viewlock & RV3D_BOXCLIP) { + rv3d->rflag |= RV3D_CLIPPING; + memcpy(rv3d->clip, clip, sizeof(clip)); + if (rv3d->clipbb) MEM_freeN(rv3d->clipbb); + rv3d->clipbb = MEM_dupallocN(bb); + } + } + } + MEM_freeN(bb); +} + +/** + * Find which axis values are shared between both views and copy to \a rv3d_dst + * taking axis flipping into account. + */ +static void view3d_boxview_sync_axis(RegionView3D *rv3d_dst, RegionView3D *rv3d_src) +{ + /* absolute axis values above this are considered to be set (will be ~1.0f) */ + const float axis_eps = 0.5f; + float viewinv[4]; + + /* use the view rotation to identify which axis to sync on */ + float view_axis_all[4][3] = { + {1.0f, 0.0f, 0.0f}, + {0.0f, 1.0f, 0.0f}, + {1.0f, 0.0f, 0.0f}, + {0.0f, 1.0f, 0.0f}}; + + float *view_src_x = &view_axis_all[0][0]; + float *view_src_y = &view_axis_all[1][0]; + + float *view_dst_x = &view_axis_all[2][0]; + float *view_dst_y = &view_axis_all[3][0]; + int i; + + + /* we could use rv3d->viewinv, but better not depend on view matrix being updated */ + if (UNLIKELY(ED_view3d_quat_from_axis_view(rv3d_src->view, viewinv) == false)) { + return; + } + invert_qt_normalized(viewinv); + mul_qt_v3(viewinv, view_src_x); + mul_qt_v3(viewinv, view_src_y); + + if (UNLIKELY(ED_view3d_quat_from_axis_view(rv3d_dst->view, viewinv) == false)) { + return; + } + invert_qt_normalized(viewinv); + mul_qt_v3(viewinv, view_dst_x); + mul_qt_v3(viewinv, view_dst_y); + + /* check source and dest have a matching axis */ + for (i = 0; i < 3; i++) { + if (((fabsf(view_src_x[i]) > axis_eps) || (fabsf(view_src_y[i]) > axis_eps)) && + ((fabsf(view_dst_x[i]) > axis_eps) || (fabsf(view_dst_y[i]) > axis_eps))) + { + rv3d_dst->ofs[i] = rv3d_src->ofs[i]; + } + } +} + +/* sync center/zoom view of region to others, for view transforms */ +void view3d_boxview_sync(ScrArea *sa, ARegion *ar) +{ + ARegion *artest; + RegionView3D *rv3d = ar->regiondata; + short clip = 0; + + for (artest = sa->regionbase.first; artest; artest = artest->next) { + if (artest != ar && artest->regiontype == RGN_TYPE_WINDOW) { + RegionView3D *rv3dtest = artest->regiondata; + + if (rv3dtest->viewlock & RV3D_LOCKED) { + rv3dtest->dist = rv3d->dist; + view3d_boxview_sync_axis(rv3dtest, rv3d); + clip |= rv3dtest->viewlock & RV3D_BOXCLIP; + + ED_region_tag_redraw(artest); + } + } + } + + if (clip) { + view3d_boxview_clip(sa); + } +} + +/* for home, center etc */ +void view3d_boxview_copy(ScrArea *sa, ARegion *ar) +{ + ARegion *artest; + RegionView3D *rv3d = ar->regiondata; + bool clip = false; + + for (artest = sa->regionbase.first; artest; artest = artest->next) { + if (artest != ar && artest->regiontype == RGN_TYPE_WINDOW) { + RegionView3D *rv3dtest = artest->regiondata; + + if (rv3dtest->viewlock) { + rv3dtest->dist = rv3d->dist; + copy_v3_v3(rv3dtest->ofs, rv3d->ofs); + ED_region_tag_redraw(artest); + + clip |= ((rv3dtest->viewlock & RV3D_BOXCLIP) != 0); + } + } + } + + if (clip) { + view3d_boxview_clip(sa); + } +} + +/* 'clip' is used to know if our clip setting has changed */ +void ED_view3d_quadview_update(ScrArea *sa, ARegion *ar, bool do_clip) +{ + ARegion *ar_sync = NULL; + RegionView3D *rv3d = ar->regiondata; + short viewlock; + /* this function copies flags from the first of the 3 other quadview + * regions to the 2 other, so it assumes this is the region whose + * properties are always being edited, weak */ + viewlock = rv3d->viewlock; + + if ((viewlock & RV3D_LOCKED) == 0) { + do_clip = (viewlock & RV3D_BOXCLIP) != 0; + viewlock = 0; + } + else if ((viewlock & RV3D_BOXVIEW) == 0 && (viewlock & RV3D_BOXCLIP) != 0) { + do_clip = true; + viewlock &= ~RV3D_BOXCLIP; + } + + for (; ar; ar = ar->prev) { + if (ar->alignment == RGN_ALIGN_QSPLIT) { + rv3d = ar->regiondata; + rv3d->viewlock = viewlock; + + if (do_clip && (viewlock & RV3D_BOXCLIP) == 0) { + rv3d->rflag &= ~RV3D_BOXCLIP; + } + + /* use ar_sync so we sync with one of the aligned views below + * else the view jumps on changing view settings like 'clip' + * since it copies from the perspective view */ + ar_sync = ar; + } + } + + if (rv3d->viewlock & RV3D_BOXVIEW) { + view3d_boxview_sync(sa, ar_sync ? ar_sync : sa->regionbase.last); + } + + /* ensure locked regions have an axis, locked user views don't make much sense */ + if (viewlock & RV3D_LOCKED) { + int index_qsplit = 0; + for (ar = sa->regionbase.first; ar; ar = ar->next) { + if (ar->alignment == RGN_ALIGN_QSPLIT) { + rv3d = ar->regiondata; + if (rv3d->viewlock) { + if (!RV3D_VIEW_IS_AXIS(rv3d->view)) { + rv3d->view = ED_view3d_lock_view_from_index(index_qsplit); + rv3d->persp = RV3D_ORTHO; + ED_view3d_lock(rv3d); + } + } + index_qsplit++; + } + } + } + + ED_area_tag_redraw(sa); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View Auto-Depth Utilities + * \{ */ + +static float view_autodist_depth_margin(ARegion *ar, const int mval[2], int margin) +{ + ViewDepths depth_temp = {0}; + rcti rect; + float depth_close; + + if (margin == 0) { + /* Get Z Depths, needed for perspective, nice for ortho */ + rect.xmin = mval[0]; + rect.ymin = mval[1]; + rect.xmax = mval[0] + 1; + rect.ymax = mval[1] + 1; + } + else { + BLI_rcti_init_pt_radius(&rect, mval, margin); + } + + view3d_update_depths_rect(ar, &depth_temp, &rect); + depth_close = view3d_depth_near(&depth_temp); + MEM_SAFE_FREE(depth_temp.depths); + return depth_close; +} + +/** + * Get the world-space 3d location from a screen-space 2d point. + * + * \param mval: Input screen-space pixel location. + * \param mouse_worldloc: Output world-space location. + * \param fallback_depth_pt: Use this points depth when no depth can be found. + */ +bool ED_view3d_autodist( + const EvaluationContext *eval_ctx, struct Depsgraph *graph, ARegion *ar, View3D *v3d, + const int mval[2], float mouse_worldloc[3], + const bool alphaoverride, const float fallback_depth_pt[3]) +{ + float depth_close; + int margin_arr[] = {0, 2, 4}; + int i; + bool depth_ok = false; + + /* Get Z Depths, needed for perspective, nice for ortho */ + ED_view3d_draw_depth(eval_ctx, graph, ar, v3d, alphaoverride); + + /* Attempt with low margin's first */ + i = 0; + do { + depth_close = view_autodist_depth_margin(ar, mval, margin_arr[i++] * U.pixelsize); + depth_ok = (depth_close != FLT_MAX); + } while ((depth_ok == false) && (i < ARRAY_SIZE(margin_arr))); + + if (depth_ok) { + float centx = (float)mval[0] + 0.5f; + float centy = (float)mval[1] + 0.5f; + + if (ED_view3d_unproject(ar, centx, centy, depth_close, mouse_worldloc)) { + return true; + } + } + + if (fallback_depth_pt) { + ED_view3d_win_to_3d_int(v3d, ar, fallback_depth_pt, mval, mouse_worldloc); + return true; + } + else { + return false; + } +} + +void ED_view3d_autodist_init( + const EvaluationContext *eval_ctx, struct Depsgraph *graph, + ARegion *ar, View3D *v3d, int mode) +{ + /* Get Z Depths, needed for perspective, nice for ortho */ + switch (mode) { + case 0: + ED_view3d_draw_depth(eval_ctx, graph, ar, v3d, true); + break; + case 1: + { + Scene *scene = DEG_get_evaluated_scene(graph); + ED_view3d_draw_depth_gpencil(eval_ctx, scene, ar, v3d); + break; + } + } +} + +/* no 4x4 sampling, run #ED_view3d_autodist_init first */ +bool ED_view3d_autodist_simple(ARegion *ar, const int mval[2], float mouse_worldloc[3], + int margin, float *force_depth) +{ + float depth; + + /* Get Z Depths, needed for perspective, nice for ortho */ + if (force_depth) + depth = *force_depth; + else + depth = view_autodist_depth_margin(ar, mval, margin); + + if (depth == FLT_MAX) + return false; + + float centx = (float)mval[0] + 0.5f; + float centy = (float)mval[1] + 0.5f; + return ED_view3d_unproject(ar, centx, centy, depth, mouse_worldloc); +} + +bool ED_view3d_autodist_depth(ARegion *ar, const int mval[2], int margin, float *depth) +{ + *depth = view_autodist_depth_margin(ar, mval, margin); + + return (*depth != FLT_MAX); +} + +static bool depth_segment_cb(int x, int y, void *userData) +{ + struct { ARegion *ar; int margin; float depth; } *data = userData; + int mval[2]; + float depth; + + mval[0] = x; + mval[1] = y; + + depth = view_autodist_depth_margin(data->ar, mval, data->margin); + + if (depth != FLT_MAX) { + data->depth = depth; + return 0; + } + else { + return 1; + } +} + +bool ED_view3d_autodist_depth_seg( + ARegion *ar, const int mval_sta[2], const int mval_end[2], + int margin, float *depth) +{ + struct { ARegion *ar; int margin; float depth; } data = {NULL}; + int p1[2]; + int p2[2]; + + data.ar = ar; + data.margin = margin; + data.depth = FLT_MAX; + + copy_v2_v2_int(p1, mval_sta); + copy_v2_v2_int(p2, mval_end); + + BLI_bitmap_draw_2d_line_v2v2i(p1, p2, depth_segment_cb, &data); + + *depth = data.depth; + + return (*depth != FLT_MAX); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View Radius/Distance Utilities + * + * Use to calculate a distance to a point based on it's radius. + * \{ */ + +float ED_view3d_radius_to_dist_persp(const float angle, const float radius) +{ + return radius * (1.0f / tanf(angle / 2.0f)); +} + +float ED_view3d_radius_to_dist_ortho(const float lens, const float radius) +{ + return radius / (DEFAULT_SENSOR_WIDTH / lens); +} + +/** + * Return a new RegionView3D.dist value to fit the \a radius. + * + * \note Depth isn't taken into account, this will fit a flat plane exactly, + * but points towards the view (with a perspective projection), + * may be within the radius but outside the view. eg: + * + * <pre> + * + + * pt --> + /^ radius + * / | + * / | + * view + + + * \ | + * \ | + * \| + * + + * </pre> + * + * \param ar Can be NULL if \a use_aspect is false. + * \param persp Allow the caller to tell what kind of perspective to use (ortho/view/camera) + * \param use_aspect Increase the distance to account for non 1:1 view aspect. + * \param radius The radius will be fitted exactly, typically pre-scaled by a margin (#VIEW3D_MARGIN). + */ +float ED_view3d_radius_to_dist( + const View3D *v3d, const ARegion *ar, + const char persp, const bool use_aspect, + const float radius) +{ + float dist; + + BLI_assert(ELEM(persp, RV3D_ORTHO, RV3D_PERSP, RV3D_CAMOB)); + BLI_assert((persp != RV3D_CAMOB) || v3d->camera); + + if (persp == RV3D_ORTHO) { + dist = ED_view3d_radius_to_dist_ortho(v3d->lens, radius); + } + else { + float lens, sensor_size, zoom; + float angle; + + if (persp == RV3D_CAMOB) { + CameraParams params; + BKE_camera_params_init(¶ms); + params.clipsta = v3d->near; + params.clipend = v3d->far; + BKE_camera_params_from_object(¶ms, v3d->camera); + + lens = params.lens; + sensor_size = BKE_camera_sensor_size(params.sensor_fit, params.sensor_x, params.sensor_y); + + /* ignore 'rv3d->camzoom' because we want to fit to the cameras frame */ + zoom = CAMERA_PARAM_ZOOM_INIT_CAMOB; + } + else { + lens = v3d->lens; + sensor_size = DEFAULT_SENSOR_WIDTH; + zoom = CAMERA_PARAM_ZOOM_INIT_PERSP; + } + + angle = focallength_to_fov(lens, sensor_size); + + /* zoom influences lens, correct this by scaling the angle as a distance (by the zoom-level) */ + angle = atanf(tanf(angle / 2.0f) * zoom) * 2.0f; + + dist = ED_view3d_radius_to_dist_persp(angle, radius); + } + + if (use_aspect) { + const RegionView3D *rv3d = ar->regiondata; + + float winx, winy; + + if (persp == RV3D_CAMOB) { + /* camera frame x/y in pixels */ + winx = ar->winx / rv3d->viewcamtexcofac[0]; + winy = ar->winy / rv3d->viewcamtexcofac[1]; + } + else { + winx = ar->winx; + winy = ar->winy; + } + + if (winx && winy) { + float aspect = winx / winy; + if (aspect < 1.0f) { + aspect = 1.0f / aspect; + } + dist *= aspect; + } + } + + return dist; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View Distance Utilities + * \{ */ + +/* problem - ofs[3] can be on same location as camera itself. + * Blender needs proper dist value for zoom. + * use fallback_dist to override small values + */ +float ED_view3d_offset_distance(float mat[4][4], const float ofs[3], const float fallback_dist) +{ + float pos[4] = {0.0f, 0.0f, 0.0f, 1.0f}; + float dir[4] = {0.0f, 0.0f, 1.0f, 0.0f}; + float dist; + + mul_m4_v4(mat, pos); + add_v3_v3(pos, ofs); + mul_m4_v4(mat, dir); + normalize_v3(dir); + + dist = dot_v3v3(pos, dir); + + if ((dist < FLT_EPSILON) && (fallback_dist != 0.0f)) { + dist = fallback_dist; + } + + return dist; +} + +/** + * Set the dist without moving the view (compensate with #RegionView3D.ofs) + * + * \note take care that viewinv is up to date, #ED_view3d_update_viewmat first. + */ +void ED_view3d_distance_set(RegionView3D *rv3d, const float dist) +{ + float viewinv[4]; + float tvec[3]; + + BLI_assert(dist >= 0.0f); + + copy_v3_fl3(tvec, 0.0f, 0.0f, rv3d->dist - dist); + /* rv3d->viewinv isn't always valid */ +#if 0 + mul_mat3_m4_v3(rv3d->viewinv, tvec); +#else + invert_qt_qt_normalized(viewinv, rv3d->viewquat); + mul_qt_v3(viewinv, tvec); +#endif + sub_v3_v3(rv3d->ofs, tvec); + + rv3d->dist = dist; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View Axis Utilities + * \{ */ +static float view3d_quat_axis[6][4] = { + {M_SQRT1_2, -M_SQRT1_2, 0.0f, 0.0f}, /* RV3D_VIEW_FRONT */ + {0.0f, 0.0f, -M_SQRT1_2, -M_SQRT1_2}, /* RV3D_VIEW_BACK */ + {0.5f, -0.5f, 0.5f, 0.5f}, /* RV3D_VIEW_LEFT */ + {0.5f, -0.5f, -0.5f, -0.5f}, /* RV3D_VIEW_RIGHT */ + {1.0f, 0.0f, 0.0f, 0.0f}, /* RV3D_VIEW_TOP */ + {0.0f, -1.0f, 0.0f, 0.0f}, /* RV3D_VIEW_BOTTOM */ +}; + + +bool ED_view3d_quat_from_axis_view(const char view, float quat[4]) +{ + if (RV3D_VIEW_IS_AXIS(view)) { + copy_qt_qt(quat, view3d_quat_axis[view - RV3D_VIEW_FRONT]); + return true; + } + else { + return false; + } +} + +char ED_view3d_quat_to_axis_view(const float quat[4], const float epsilon) +{ + /* quat values are all unit length */ + + char view; + + for (view = RV3D_VIEW_FRONT; view <= RV3D_VIEW_BOTTOM; view++) { + if (fabsf(angle_signed_qtqt(quat, view3d_quat_axis[view - RV3D_VIEW_FRONT])) < epsilon) { + return view; + } + } + + return RV3D_VIEW_USER; +} + +char ED_view3d_lock_view_from_index(int index) +{ + switch (index) { + case 0: return RV3D_VIEW_FRONT; + case 1: return RV3D_VIEW_TOP; + case 2: return RV3D_VIEW_RIGHT; + default: return RV3D_VIEW_USER; + } + +} + +char ED_view3d_axis_view_opposite(char view) +{ + switch (view) { + case RV3D_VIEW_FRONT: return RV3D_VIEW_BACK; + case RV3D_VIEW_BACK: return RV3D_VIEW_FRONT; + case RV3D_VIEW_LEFT: return RV3D_VIEW_RIGHT; + case RV3D_VIEW_RIGHT: return RV3D_VIEW_LEFT; + case RV3D_VIEW_TOP: return RV3D_VIEW_BOTTOM; + case RV3D_VIEW_BOTTOM: return RV3D_VIEW_TOP; + } + + return RV3D_VIEW_USER; +} + + +bool ED_view3d_lock(RegionView3D *rv3d) +{ + return ED_view3d_quat_from_axis_view(rv3d->view, rv3d->viewquat); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View Transform Utilities + * \{ */ + +/** + * Set the view transformation from a 4x4 matrix. + * + * \param mat The view 4x4 transformation matrix to assign. + * \param ofs The view offset, normally from RegionView3D.ofs. + * \param quat The view rotation, quaternion normally from RegionView3D.viewquat. + * \param dist The view distance from ofs, normally from RegionView3D.dist. + */ +void ED_view3d_from_m4(float mat[4][4], float ofs[3], float quat[4], float *dist) +{ + float nmat[3][3]; + + /* dist depends on offset */ + BLI_assert(dist == NULL || ofs != NULL); + + copy_m3_m4(nmat, mat); + normalize_m3(nmat); + + /* Offset */ + if (ofs) + negate_v3_v3(ofs, mat[3]); + + /* Quat */ + if (quat) { + mat3_normalized_to_quat(quat, nmat); + invert_qt_normalized(quat); + } + + if (ofs && dist) { + madd_v3_v3fl(ofs, nmat[2], *dist); + } +} + +/** + * Calculate the view transformation matrix from RegionView3D input. + * The resulting matrix is equivalent to RegionView3D.viewinv + * \param mat The view 4x4 transformation matrix to calculate. + * \param ofs The view offset, normally from RegionView3D.ofs. + * \param quat The view rotation, quaternion normally from RegionView3D.viewquat. + * \param dist The view distance from ofs, normally from RegionView3D.dist. + */ +void ED_view3d_to_m4(float mat[4][4], const float ofs[3], const float quat[4], const float dist) +{ + float iviewquat[4] = {-quat[0], quat[1], quat[2], quat[3]}; + float dvec[3] = {0.0f, 0.0f, dist}; + + quat_to_mat4(mat, iviewquat); + mul_mat3_m4_v3(mat, dvec); + sub_v3_v3v3(mat[3], dvec, ofs); +} + +/** + * Set the RegionView3D members from an objects transformation and optionally lens. + * \param ob The object to set the view to. + * \param ofs The view offset to be set, normally from RegionView3D.ofs. + * \param quat The view rotation to be set, quaternion normally from RegionView3D.viewquat. + * \param dist The view distance from ofs to be set, normally from RegionView3D.dist. + * \param lens The view lens angle set for cameras and lamps, normally from View3D.lens. + */ +void ED_view3d_from_object(Object *ob, float ofs[3], float quat[4], float *dist, float *lens) +{ + ED_view3d_from_m4(ob->obmat, ofs, quat, dist); + + if (lens) { + CameraParams params; + + BKE_camera_params_init(¶ms); + BKE_camera_params_from_object(¶ms, ob); + *lens = params.lens; + } +} + +/** + * Set the object transformation from RegionView3D members. + * \param ob The object which has the transformation assigned. + * \param ofs The view offset, normally from RegionView3D.ofs. + * \param quat The view rotation, quaternion normally from RegionView3D.viewquat. + * \param dist The view distance from ofs, normally from RegionView3D.dist. + */ +void ED_view3d_to_object(Object *ob, const float ofs[3], const float quat[4], const float dist) +{ + float mat[4][4]; + ED_view3d_to_m4(mat, ofs, quat, dist); + BKE_object_apply_mat4(ob, mat, true, true); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Depth Buffer Utilities + * \{ */ + +float ED_view3d_depth_read_cached(const ViewContext *vc, const int mval[2]) +{ + ViewDepths *vd = vc->rv3d->depths; + + int x = mval[0]; + int y = mval[1]; + + if (vd && vd->depths && x > 0 && y > 0 && x < vd->w && y < vd->h) { + return vd->depths[y * vd->w + x]; + } + else { + BLI_assert(1.0 <= vd->depth_range[1]); + return 1.0f; + } +} + +bool ED_view3d_depth_read_cached_normal( + const ViewContext *vc, const int mval[2], + float r_normal[3]) +{ + /* Note: we could support passing in a radius. + * For now just read 9 pixels. */ + + /* pixels surrounding */ + bool depths_valid[9] = {false}; + float coords[9][3] = {{0}}; + + ARegion *ar = vc->ar; + const ViewDepths *depths = vc->rv3d->depths; + + for (int x = 0, i = 0; x < 2; x++) { + for (int y = 0; y < 2; y++) { + const int mval_ofs[2] = {mval[0] + (x - 1), mval[1] + (y - 1)}; + + const double depth = (double)ED_view3d_depth_read_cached(vc, mval_ofs); + if ((depth > depths->depth_range[0]) && (depth < depths->depth_range[1])) { + if (ED_view3d_depth_unproject(ar, mval_ofs, depth, coords[i])) { + depths_valid[i] = true; + } + } + i++; + } + } + + const int edges[2][6][2] = { + /* x edges */ + {{0, 1}, {1, 2}, + {3, 4}, {4, 5}, + {6, 7}, {7, 8}}, + /* y edges */ + {{0, 3}, {3, 6}, + {1, 4}, {4, 7}, + {2, 5}, {5, 8}}, + }; + + float cross[2][3] = {{0.0f}}; + + for (int i = 0; i < 6; i++) { + for (int axis = 0; axis < 2; axis++) { + if (depths_valid[edges[axis][i][0]] && depths_valid[edges[axis][i][1]]) { + float delta[3]; + sub_v3_v3v3(delta, coords[edges[axis][i][0]], coords[edges[axis][i][1]]); + add_v3_v3(cross[axis], delta); + } + } + } + + cross_v3_v3v3(r_normal, cross[0], cross[1]); + + if (normalize_v3(r_normal) != 0.0f) { + return true; + } + else { + return false; + } +} + +bool ED_view3d_depth_unproject( + const ARegion *ar, + const int mval[2], const double depth, + float r_location_world[3]) +{ + float centx = (float)mval[0] + 0.5f; + float centy = (float)mval[1] + 0.5f; + return ED_view3d_unproject(ar, centx, centy, depth, r_location_world); +} + +void ED_view3d_depth_tag_update(RegionView3D *rv3d) +{ + if (rv3d->depths) + rv3d->depths->damaged = true; +} + +/** \} */ diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c index 882f0ec0bc0..0597f2806b3 100644 --- a/source/blender/editors/space_view3d/view3d_view.c +++ b/source/blender/editors/space_view3d/view3d_view.c @@ -28,7 +28,6 @@ * \ingroup spview3d */ - #include "DNA_camera_types.h" #include "DNA_scene_types.h" #include "DNA_object_types.h" @@ -39,7 +38,6 @@ #include "BLI_rect.h" #include "BLI_utildefines.h" -#include "BKE_anim.h" #include "BKE_action.h" #include "BKE_camera.h" #include "BKE_context.h" @@ -48,12 +46,9 @@ #include "BKE_main.h" #include "BKE_report.h" #include "BKE_scene.h" -#include "BKE_screen.h" #include "DEG_depsgraph.h" -#include "BIF_glutil.h" - #include "UI_resources.h" #include "GPU_glew.h" @@ -64,10 +59,10 @@ #include "WM_types.h" #include "ED_screen.h" -#include "ED_armature.h" #include "DRW_engine.h" +#include "DEG_depsgraph_query.h" #ifdef WITH_GAMEENGINE # include "BLI_listbase.h" @@ -78,53 +73,14 @@ # include "BL_System.h" #endif - #include "view3d_intern.h" /* own include */ -/* use this call when executing an operator, - * event system doesn't set for each event the - * opengl drawing context */ -void view3d_operator_needs_opengl(const bContext *C) -{ - wmWindow *win = CTX_wm_window(C); - ARegion *ar = CTX_wm_region(C); - - view3d_region_operator_needs_opengl(win, ar); -} - -void view3d_region_operator_needs_opengl(wmWindow *win, ARegion *ar) -{ - /* for debugging purpose, context should always be OK */ - if ((ar == NULL) || (ar->regiontype != RGN_TYPE_WINDOW)) { - printf("view3d_region_operator_needs_opengl error, wrong region\n"); - } - else { - RegionView3D *rv3d = ar->regiondata; - - wmSubWindowSet(win, ar->swinid); - gpuLoadProjectionMatrix(rv3d->winmat); - gpuLoadMatrix(rv3d->viewmat); - } -} - -float *ED_view3d_cursor3d_get(Scene *scene, View3D *v3d) -{ - if (v3d && v3d->localvd) return v3d->cursor; - else return scene->cursor; -} - -Camera *ED_view3d_camera_data_get(View3D *v3d, RegionView3D *rv3d) -{ - /* establish the camera object, so we can default to view mapping if anything is wrong with it */ - if ((rv3d->persp == RV3D_CAMOB) && v3d->camera && (v3d->camera->type == OB_CAMERA)) { - return v3d->camera->data; - } - else { - return NULL; - } -} +/* -------------------------------------------------------------------- */ +/** \name Smooth View Operator & Utilities + * + * Use for view transitions to have smooth (animated) transitions. + * \{ */ -/* ****************** smooth view operator ****************** */ /* This operator is one of the 'timer refresh' ones like animation playback */ struct SmoothView3DState { @@ -273,7 +229,7 @@ void ED_view3d_smooth_view_ex( * this means small rotations wont lag */ if (sview->quat && !sview->ofs && !sview->dist) { /* scale the time allowed by the rotation */ - sms.time_allowed *= (double)angle_normalized_qtqt(sms.dst.quat, sms.src.quat) / M_PI; /* 180deg == 1.0 */ + sms.time_allowed *= (double)fabsf(angle_signed_normalized_qtqt(sms.dst.quat, sms.src.quat)) / M_PI; /* 180deg == 1.0 */ } /* ensure it shows correct */ @@ -401,6 +357,8 @@ static void view3d_smoothview_apply(bContext *C, View3D *v3d, ARegion *ar, bool ED_view3d_camera_lock_autokey(v3d, rv3d, C, true, true); } + /* Event handling won't know if a UI item has been moved under the pointer. */ + WM_event_add_mousemove(C); } if (sync_boxview && (rv3d->viewlock & RV3D_BOXVIEW)) { @@ -462,22 +420,25 @@ void ED_view3d_smooth_view_force_finish( void VIEW3D_OT_smoothview(wmOperatorType *ot) { - /* identifiers */ ot->name = "Smooth View"; ot->description = ""; ot->idname = "VIEW3D_OT_smoothview"; - + /* api callbacks */ ot->invoke = view3d_smoothview_invoke; - + /* flags */ ot->flag = OPTYPE_INTERNAL; ot->poll = ED_operator_view3d_active; } -/* ****************** change view operators ****************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Camera to View Operator + * \{ */ static int view3d_camera_to_view_exec(bContext *C, wmOperator *UNUSED(op)) { @@ -541,6 +502,12 @@ void VIEW3D_OT_camera_to_view(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Camera Fit Frame to Selected Operator + * \{ */ + /* unlike VIEW3D_OT_view_selected this is for framing a render and not * meant to take into account vertex/bone selection for eg. */ static int view3d_camera_to_view_selected_exec(bContext *C, wmOperator *op) @@ -600,6 +567,12 @@ void VIEW3D_OT_camera_to_view_selected(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Object as Camera Operator + * \{ */ + static void sync_viewport_camera_smoothview(bContext *C, View3D *v3d, Object *ob, const int smooth_viewtx) { Main *bmain = CTX_data_main(C); @@ -650,7 +623,7 @@ static void sync_viewport_camera_smoothview(bContext *C, View3D *v3d, Object *ob } static int view3d_setobjectascamera_exec(bContext *C, wmOperator *op) -{ +{ View3D *v3d; ARegion *ar; RegionView3D *rv3d; @@ -703,7 +676,6 @@ int ED_operator_rv3d_user_region_poll(bContext *C) void VIEW3D_OT_object_as_camera(wmOperatorType *ot) { - /* identifiers */ ot->name = "Set Active Object as Camera"; ot->description = "Set the active object as the active camera for this view or scene"; @@ -717,289 +689,23 @@ void VIEW3D_OT_object_as_camera(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -/* ********************************** */ - -void ED_view3d_clipping_calc_from_boundbox(float clip[4][4], const BoundBox *bb, const bool is_flip) -{ - int val; - - for (val = 0; val < 4; val++) { - normal_tri_v3(clip[val], bb->vec[val], bb->vec[val == 3 ? 0 : val + 1], bb->vec[val + 4]); - if (UNLIKELY(is_flip)) { - negate_v3(clip[val]); - } - - clip[val][3] = -dot_v3v3(clip[val], bb->vec[val]); - } -} - -void ED_view3d_clipping_calc(BoundBox *bb, float planes[4][4], const ARegion *ar, const Object *ob, const rcti *rect) -{ - /* init in case unproject fails */ - memset(bb->vec, 0, sizeof(bb->vec)); - - /* four clipping planes and bounding volume */ - /* first do the bounding volume */ - for (int val = 0; val < 4; val++) { - float xs = (val == 0 || val == 3) ? rect->xmin : rect->xmax; - float ys = (val == 0 || val == 1) ? rect->ymin : rect->ymax; - - ED_view3d_unproject(ar, xs, ys, 0.0, bb->vec[val]); - ED_view3d_unproject(ar, xs, ys, 1.0, bb->vec[4 + val]); - } - - /* optionally transform to object space */ - if (ob) { - float imat[4][4]; - invert_m4_m4(imat, ob->obmat); - - for (int val = 0; val < 8; val++) { - mul_m4_v3(imat, bb->vec[val]); - } - } - - /* verify if we have negative scale. doing the transform before cross - * product flips the sign of the vector compared to doing cross product - * before transform then, so we correct for that. */ - int flip_sign = (ob) ? is_negative_m4(ob->obmat) : false; - - ED_view3d_clipping_calc_from_boundbox(planes, bb, flip_sign); -} - -static bool view3d_boundbox_clip_m4(const BoundBox *bb, float persmatob[4][4]) -{ - int a, flag = -1, fl; - - for (a = 0; a < 8; a++) { - float vec[4], min, max; - copy_v3_v3(vec, bb->vec[a]); - vec[3] = 1.0; - mul_m4_v4(persmatob, vec); - max = vec[3]; - min = -vec[3]; - - fl = 0; - if (vec[0] < min) fl += 1; - if (vec[0] > max) fl += 2; - if (vec[1] < min) fl += 4; - if (vec[1] > max) fl += 8; - if (vec[2] < min) fl += 16; - if (vec[2] > max) fl += 32; - - flag &= fl; - if (flag == 0) return true; - } - - return false; -} - -bool ED_view3d_boundbox_clip_ex(const RegionView3D *rv3d, const BoundBox *bb, float obmat[4][4]) -{ - /* return 1: draw */ - - float persmatob[4][4]; - - if (bb == NULL) return true; - if (bb->flag & BOUNDBOX_DISABLED) return true; - - mul_m4_m4m4(persmatob, (float(*)[4])rv3d->persmat, obmat); - - return view3d_boundbox_clip_m4(bb, persmatob); -} - -bool ED_view3d_boundbox_clip(RegionView3D *rv3d, const BoundBox *bb) -{ - if (bb == NULL) return true; - if (bb->flag & BOUNDBOX_DISABLED) return true; - - return view3d_boundbox_clip_m4(bb, rv3d->persmatob); -} +/** \} */ /* -------------------------------------------------------------------- */ - -/** \name Depth Utilities +/** \name Window and View Matrix Calculation * \{ */ -float ED_view3d_depth_read_cached(const ViewContext *vc, const int mval[2]) -{ - ViewDepths *vd = vc->rv3d->depths; - - int x = mval[0]; - int y = mval[1]; - - if (vd && vd->depths && x > 0 && y > 0 && x < vd->w && y < vd->h) { - return vd->depths[y * vd->w + x]; - } - else { - BLI_assert(1.0 <= vd->depth_range[1]); - return 1.0f; - } -} - -bool ED_view3d_depth_read_cached_normal( - const ViewContext *vc, const int mval[2], - float r_normal[3]) -{ - /* Note: we could support passing in a radius. - * For now just read 9 pixels. */ - - /* pixels surrounding */ - bool depths_valid[9] = {false}; - float coords[9][3] = {{0}}; - - ARegion *ar = vc->ar; - const ViewDepths *depths = vc->rv3d->depths; - - for (int x = 0, i = 0; x < 2; x++) { - for (int y = 0; y < 2; y++) { - const int mval_ofs[2] = {mval[0] + (x - 1), mval[1] + (y - 1)}; - - const double depth = (double)ED_view3d_depth_read_cached(vc, mval_ofs); - if ((depth > depths->depth_range[0]) && (depth < depths->depth_range[1])) { - if (ED_view3d_depth_unproject(ar, mval_ofs, depth, coords[i])) { - depths_valid[i] = true; - } - } - i++; - } - } - - const int edges[2][6][2] = { - /* x edges */ - {{0, 1}, {1, 2}, - {3, 4}, {4, 5}, - {6, 7}, {7, 8}}, - /* y edges */ - {{0, 3}, {3, 6}, - {1, 4}, {4, 7}, - {2, 5}, {5, 8}}, - }; - - float cross[2][3] = {{0.0f}}; - - for (int i = 0; i < 6; i++) { - for (int axis = 0; axis < 2; axis++) { - if (depths_valid[edges[axis][i][0]] && depths_valid[edges[axis][i][1]]) { - float delta[3]; - sub_v3_v3v3(delta, coords[edges[axis][i][0]], coords[edges[axis][i][1]]); - add_v3_v3(cross[axis], delta); - } - } - } - - cross_v3_v3v3(r_normal, cross[0], cross[1]); - - if (normalize_v3(r_normal) != 0.0f) { - return true; - } - else { - return false; - } -} - -bool ED_view3d_depth_unproject( - const ARegion *ar, - const int mval[2], const double depth, - float r_location_world[3]) -{ - float centx = (float)mval[0] + 0.5f; - float centy = (float)mval[1] + 0.5f; - return ED_view3d_unproject(ar, centx, centy, depth, r_location_world); -} - -/** \} */ - -void ED_view3d_depth_tag_update(RegionView3D *rv3d) -{ - if (rv3d->depths) - rv3d->depths->damaged = true; -} - -void ED_view3d_dist_range_get( - const View3D *v3d, - float r_dist_range[2]) -{ - r_dist_range[0] = v3d->grid * 0.001f; - r_dist_range[1] = v3d->far * 10.0f; -} - -/* copies logic of get_view3d_viewplane(), keep in sync */ -bool ED_view3d_clip_range_get( - const View3D *v3d, const RegionView3D *rv3d, - float *r_clipsta, float *r_clipend, - const bool use_ortho_factor) -{ - CameraParams params; - - BKE_camera_params_init(¶ms); - BKE_camera_params_from_view3d(¶ms, v3d, rv3d); - - if (use_ortho_factor && params.is_ortho) { - const float fac = 2.0f / (params.clipend - params.clipsta); - params.clipsta *= fac; - params.clipend *= fac; - } - - if (r_clipsta) *r_clipsta = params.clipsta; - if (r_clipend) *r_clipend = params.clipend; - - return params.is_ortho; -} - -bool ED_view3d_viewplane_get( - const View3D *v3d, const RegionView3D *rv3d, int winx, int winy, - rctf *r_viewplane, float *r_clipsta, float *r_clipend, float *r_pixsize) -{ - CameraParams params; - - BKE_camera_params_init(¶ms); - BKE_camera_params_from_view3d(¶ms, v3d, rv3d); - BKE_camera_params_compute_viewplane(¶ms, winx, winy, 1.0f, 1.0f); - - if (r_viewplane) *r_viewplane = params.viewplane; - if (r_clipsta) *r_clipsta = params.clipsta; - if (r_clipend) *r_clipend = params.clipend; - if (r_pixsize) *r_pixsize = params.viewdx; - - return params.is_ortho; -} - -/** - * Use instead of: ``bglPolygonOffset(rv3d->dist, ...)`` see bug [#37727] - */ -void ED_view3d_polygon_offset(const RegionView3D *rv3d, const float dist) -{ - float viewdist; - - if (rv3d->rflag & RV3D_ZOFFSET_DISABLED) { - return; - } - - viewdist = rv3d->dist; - - /* special exception for ortho camera (viewdist isnt used for perspective cameras) */ - if (dist != 0.0f) { - if (rv3d->persp == RV3D_CAMOB) { - if (rv3d->is_persp == false) { - viewdist = 1.0f / max_ff(fabsf(rv3d->winmat[0][0]), fabsf(rv3d->winmat[1][1])); - } - } - } - - bglPolygonOffset(viewdist, dist); -} - /** * \param rect optional for picking (can be NULL). */ -void view3d_winmatrix_set(ARegion *ar, const View3D *v3d, const rcti *rect) +void view3d_winmatrix_set(const Depsgraph *depsgraph, ARegion *ar, const View3D *v3d, const rcti *rect) { RegionView3D *rv3d = ar->regiondata; rctf viewplane; float clipsta, clipend; bool is_ortho; - is_ortho = ED_view3d_viewplane_get(v3d, rv3d, ar->winx, ar->winy, &viewplane, &clipsta, &clipend, NULL); + is_ortho = ED_view3d_viewplane_get(depsgraph, v3d, rv3d, ar->winx, ar->winy, &viewplane, &clipsta, &clipend, NULL); rv3d->is_persp = !is_ortho; #if 0 @@ -1041,80 +747,28 @@ static void obmat_to_viewmat(RegionView3D *rv3d, Object *ob) mat4_normalized_to_quat(rv3d->viewquat, rv3d->viewmat); } -static float view3d_quat_axis[6][4] = { - {M_SQRT1_2, -M_SQRT1_2, 0.0f, 0.0f}, /* RV3D_VIEW_FRONT */ - {0.0f, 0.0f, -M_SQRT1_2, -M_SQRT1_2}, /* RV3D_VIEW_BACK */ - {0.5f, -0.5f, 0.5f, 0.5f}, /* RV3D_VIEW_LEFT */ - {0.5f, -0.5f, -0.5f, -0.5f}, /* RV3D_VIEW_RIGHT */ - {1.0f, 0.0f, 0.0f, 0.0f}, /* RV3D_VIEW_TOP */ - {0.0f, -1.0f, 0.0f, 0.0f}, /* RV3D_VIEW_BOTTOM */ -}; - - -bool ED_view3d_quat_from_axis_view(const char view, float quat[4]) -{ - if (RV3D_VIEW_IS_AXIS(view)) { - copy_qt_qt(quat, view3d_quat_axis[view - RV3D_VIEW_FRONT]); - return true; - } - else { - return false; - } -} - -char ED_view3d_quat_to_axis_view(const float quat[4], const float epsilon) -{ - /* quat values are all unit length */ - - char view; - - for (view = RV3D_VIEW_FRONT; view <= RV3D_VIEW_BOTTOM; view++) { - if (angle_qtqt(quat, view3d_quat_axis[view - RV3D_VIEW_FRONT]) < epsilon) { - return view; - } - } - - return RV3D_VIEW_USER; -} - -char ED_view3d_lock_view_from_index(int index) -{ - switch (index) { - case 0: return RV3D_VIEW_FRONT; - case 1: return RV3D_VIEW_TOP; - case 2: return RV3D_VIEW_RIGHT; - default: return RV3D_VIEW_USER; - } - -} - -char ED_view3d_axis_view_opposite(char view) -{ - switch (view) { - case RV3D_VIEW_FRONT: return RV3D_VIEW_BACK; - case RV3D_VIEW_BACK: return RV3D_VIEW_FRONT; - case RV3D_VIEW_LEFT: return RV3D_VIEW_RIGHT; - case RV3D_VIEW_RIGHT: return RV3D_VIEW_LEFT; - case RV3D_VIEW_TOP: return RV3D_VIEW_BOTTOM; - case RV3D_VIEW_BOTTOM: return RV3D_VIEW_TOP; - } - - return RV3D_VIEW_USER; -} - - -bool ED_view3d_lock(RegionView3D *rv3d) -{ - return ED_view3d_quat_from_axis_view(rv3d->view, rv3d->viewquat); -} - -/* don't set windows active in here, is used by renderwin too */ -void view3d_viewmatrix_set(const EvaluationContext *eval_ctx, Scene *scene, const View3D *v3d, RegionView3D *rv3d) +/** + * Sets #RegionView3D.viewmat + * + * \param eval_ctx: Context. + * \param scene: Scene for camera and cursor location. + * \param v3d: View 3D space data. + * \param rv3d: 3D region which stores the final matrices. + * \param rect_scale: Optional 2D scale argument, + * Use when displaying a sub-region, eg: when #view3d_winmatrix_set takes a 'rect' argument. + * + * \note don't set windows active in here, is used by renderwin too. + */ +void view3d_viewmatrix_set( + const EvaluationContext *eval_ctx, Scene *scene, + const View3D *v3d, RegionView3D *rv3d, const float rect_scale[2]) { if (rv3d->persp == RV3D_CAMOB) { /* obs/camera */ if (v3d->camera) { - BKE_object_where_is_calc(eval_ctx, scene, v3d->camera); - obmat_to_viewmat(rv3d, v3d->camera); + const Depsgraph *depsgraph = eval_ctx->depsgraph; + Object *camera_object = DEG_get_evaluated_object(depsgraph, v3d->camera); + BKE_object_where_is_calc(eval_ctx, scene, camera_object); + obmat_to_viewmat(rv3d, camera_object); } else { quat_to_mat4(rv3d->viewmat, rv3d->viewquat); @@ -1168,6 +822,17 @@ void view3d_viewmatrix_set(const EvaluationContext *eval_ctx, Scene *scene, cons mul_v2_v2fl(vec, rv3d->ofs_lock, rv3d->is_persp ? rv3d->dist : 1.0f); vec[2] = 0.0f; + + if (rect_scale) { + /* Since 'RegionView3D.winmat' has been calculated and this function doesn't take the 'ARegion' + * we don't know about the region size. + * Use 'rect_scale' when drawing a sub-region to apply 2D offset, + * scaled by the difference between the sub-region and the region size. + */ + vec[0] /= rect_scale[0]; + vec[1] /= rect_scale[1]; + } + mul_mat3_m4_v3(persinv, vec); translate_m4(rv3d->viewmat, vec[0], vec[1], vec[2]); } @@ -1175,6 +840,12 @@ void view3d_viewmatrix_set(const EvaluationContext *eval_ctx, Scene *scene, cons } } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name OpenGL Select Utilities + * \{ */ + /** * Optionally cache data for multiple calls to #view3d_opengl_select * @@ -1326,6 +997,12 @@ finally: return hits; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View Layer Utilities + * \{ */ + int ED_view3d_view_layer_set(int lay, const int *values, int *active) { int i, tot = 0; @@ -1364,43 +1041,43 @@ int ED_view3d_view_layer_set(int lay, const int *values, int *active) return lay; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Game Engine Operator + * + * Start the game engine (handles context switching). + * \{ */ + #ifdef WITH_GAMEENGINE static ListBase queue_back; -static void SaveState(bContext *C, wmWindow *win) +static void game_engine_save_state(bContext *C, wmWindow *win) { Object *obact = CTX_data_active_object(C); - + glPushAttrib(GL_ALL_ATTRIB_BITS); if (obact && obact->mode & OB_MODE_TEXTURE_PAINT) GPU_paint_set_mipmap(1); - + queue_back = win->queue; - + BLI_listbase_clear(&win->queue); - - //XXX waitcursor(1); } -static void RestoreState(bContext *C, wmWindow *win) +static void game_engine_restore_state(bContext *C, wmWindow *win) { Object *obact = CTX_data_active_object(C); - + if (obact && obact->mode & OB_MODE_TEXTURE_PAINT) GPU_paint_set_mipmap(0); - //XXX curarea->win_swap = 0; - //XXX curarea->head_swap = 0; - //XXX allqueue(REDRAWVIEW3D, 1); - //XXX allqueue(REDRAWBUTSALL, 0); - //XXX reset_slowparents(); - //XXX waitcursor(0); - //XXX G.qual = 0; - - if (win) /* check because closing win can set to NULL */ + /* check because closing win can set to NULL */ + if (win) { win->queue = queue_back; - + } + GPU_state_init(); glPopAttrib(); @@ -1471,33 +1148,6 @@ static int game_engine_poll(bContext *C) return 1; } -bool ED_view3d_context_activate(bContext *C) -{ - bScreen *sc = CTX_wm_screen(C); - ScrArea *sa = CTX_wm_area(C); - ARegion *ar; - - /* sa can be NULL when called from python */ - if (sa == NULL || sa->spacetype != SPACE_VIEW3D) { - sa = BKE_screen_find_big_area(sc, SPACE_VIEW3D, 0); - } - - if (sa == NULL) { - return false; - } - - ar = BKE_area_find_region_active_win(sa); - if (ar == NULL) { - return false; - } - - /* bad context switch .. */ - CTX_wm_area_set(C, sa); - CTX_wm_region_set(C, ar); - - return true; -} - static int game_engine_exec(bContext *C, wmOperator *op) { #ifdef WITH_GAMEENGINE @@ -1509,12 +1159,12 @@ static int game_engine_exec(bContext *C, wmOperator *op) RegionView3D *rv3d; rcti cam_frame; - (void)op; /* unused */ - + UNUSED_VARS(op); + /* bad context switch .. */ if (!ED_view3d_context_activate(C)) return OPERATOR_CANCELLED; - + /* redraw to hide any menus/popups, we don't go back to * the window manager until after this operator exits */ WM_redraw_windows(C); @@ -1526,16 +1176,17 @@ static int game_engine_exec(bContext *C, wmOperator *op) ar = CTX_wm_region(C); view3d_operator_needs_opengl(C); - + game_set_commmandline_options(&startscene->gm); if ((rv3d->persp == RV3D_CAMOB) && (startscene->gm.framing.type == SCE_GAMEFRAMING_BARS) && (startscene->gm.stereoflag != STEREO_DOME)) { + const Depsgraph *depsgraph = CTX_data_depsgraph(C); /* Letterbox */ rctf cam_framef; - ED_view3d_calc_camera_border(startscene, ar, CTX_wm_view3d(C), rv3d, &cam_framef, false); + ED_view3d_calc_camera_border(startscene, depsgraph, ar, CTX_wm_view3d(C), rv3d, &cam_framef, false); cam_frame.xmin = cam_framef.xmin + ar->winrct.xmin; cam_frame.xmax = cam_framef.xmax + ar->winrct.xmin; cam_frame.ymin = cam_framef.ymin + ar->winrct.ymin; @@ -1550,7 +1201,7 @@ static int game_engine_exec(bContext *C, wmOperator *op) } - SaveState(C, prevwin); + game_engine_save_state(C, prevwin); StartKetsjiShell(C, ar, &cam_frame, 1); @@ -1559,7 +1210,7 @@ static int game_engine_exec(bContext *C, wmOperator *op) prevwin = NULL; CTX_wm_window_set(C, NULL); } - + ED_area_tag_redraw(CTX_wm_area(C)); if (prevwin) { @@ -1570,7 +1221,7 @@ static int game_engine_exec(bContext *C, wmOperator *op) CTX_wm_area_set(C, prevsa); } - RestoreState(C, prevwin); + game_engine_restore_state(C, prevwin); //XXX restore_all_scene_cfra(scene_cfra_store); BKE_scene_set_background(CTX_data_main(C), startscene); @@ -1580,7 +1231,7 @@ static int game_engine_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; #else - (void)C; /* unused */ + UNUSED_VARS(C); BKE_report(op->reports, RPT_ERROR, "Game engine is disabled in this build"); return OPERATOR_CANCELLED; #endif @@ -1588,168 +1239,15 @@ static int game_engine_exec(bContext *C, wmOperator *op) void VIEW3D_OT_game_start(wmOperatorType *ot) { - /* identifiers */ ot->name = "Start Game Engine"; ot->description = "Start game engine"; ot->idname = "VIEW3D_OT_game_start"; - + /* api callbacks */ ot->exec = game_engine_exec; - - ot->poll = game_engine_poll; -} - -/* ************************************** */ - -float ED_view3d_pixel_size(const RegionView3D *rv3d, const float co[3]) -{ - return mul_project_m4_v3_zfac((float(*)[4])rv3d->persmat, co) * rv3d->pixsize * U.pixelsize; -} - -float ED_view3d_radius_to_dist_persp(const float angle, const float radius) -{ - return radius * (1.0f / tanf(angle / 2.0f)); -} - -float ED_view3d_radius_to_dist_ortho(const float lens, const float radius) -{ - return radius / (DEFAULT_SENSOR_WIDTH / lens); -} - -/** - * Return a new RegionView3D.dist value to fit the \a radius. - * - * \note Depth isn't taken into account, this will fit a flat plane exactly, - * but points towards the view (with a perspective projection), - * may be within the radius but outside the view. eg: - * - * <pre> - * + - * pt --> + /^ radius - * / | - * / | - * view + + - * \ | - * \ | - * \| - * + - * </pre> - * - * \param ar Can be NULL if \a use_aspect is false. - * \param persp Allow the caller to tell what kind of perspective to use (ortho/view/camera) - * \param use_aspect Increase the distance to account for non 1:1 view aspect. - * \param radius The radius will be fitted exactly, typically pre-scaled by a margin (#VIEW3D_MARGIN). - */ -float ED_view3d_radius_to_dist( - const View3D *v3d, const ARegion *ar, - const char persp, const bool use_aspect, - const float radius) -{ - float dist; - - BLI_assert(ELEM(persp, RV3D_ORTHO, RV3D_PERSP, RV3D_CAMOB)); - BLI_assert((persp != RV3D_CAMOB) || v3d->camera); - - if (persp == RV3D_ORTHO) { - dist = ED_view3d_radius_to_dist_ortho(v3d->lens, radius); - } - else { - float lens, sensor_size, zoom; - float angle; - - if (persp == RV3D_CAMOB) { - CameraParams params; - BKE_camera_params_init(¶ms); - params.clipsta = v3d->near; - params.clipend = v3d->far; - BKE_camera_params_from_object(¶ms, v3d->camera); - - lens = params.lens; - sensor_size = BKE_camera_sensor_size(params.sensor_fit, params.sensor_x, params.sensor_y); - /* ignore 'rv3d->camzoom' because we want to fit to the cameras frame */ - zoom = CAMERA_PARAM_ZOOM_INIT_CAMOB; - } - else { - lens = v3d->lens; - sensor_size = DEFAULT_SENSOR_WIDTH; - zoom = CAMERA_PARAM_ZOOM_INIT_PERSP; - } - - angle = focallength_to_fov(lens, sensor_size); - - /* zoom influences lens, correct this by scaling the angle as a distance (by the zoom-level) */ - angle = atanf(tanf(angle / 2.0f) * zoom) * 2.0f; - - dist = ED_view3d_radius_to_dist_persp(angle, radius); - } - - if (use_aspect) { - const RegionView3D *rv3d = ar->regiondata; - - float winx, winy; - - if (persp == RV3D_CAMOB) { - /* camera frame x/y in pixels */ - winx = ar->winx / rv3d->viewcamtexcofac[0]; - winy = ar->winy / rv3d->viewcamtexcofac[1]; - } - else { - winx = ar->winx; - winy = ar->winy; - } - - if (winx && winy) { - float aspect = winx / winy; - if (aspect < 1.0f) { - aspect = 1.0f / aspect; - } - dist *= aspect; - } - } - - return dist; -} - -/* view matrix properties utilities */ - -/* unused */ -#if 0 -void ED_view3d_operator_properties_viewmat(wmOperatorType *ot) -{ - PropertyRNA *prop; - - prop = RNA_def_int(ot->srna, "region_width", 0, 0, INT_MAX, "Region Width", "", 0, INT_MAX); - RNA_def_property_flag(prop, PROP_HIDDEN); - - prop = RNA_def_int(ot->srna, "region_height", 0, 0, INT_MAX, "Region height", "", 0, INT_MAX); - RNA_def_property_flag(prop, PROP_HIDDEN); - - prop = RNA_def_float_matrix(ot->srna, "perspective_matrix", 4, 4, NULL, 0.0f, 0.0f, "", "Perspective Matrix", 0.0f, 0.0f); - RNA_def_property_flag(prop, PROP_HIDDEN); -} - -void ED_view3d_operator_properties_viewmat_set(bContext *C, wmOperator *op) -{ - ARegion *ar = CTX_wm_region(C); - RegionView3D *rv3d = ED_view3d_context_rv3d(C); - - if (!RNA_struct_property_is_set(op->ptr, "region_width")) - RNA_int_set(op->ptr, "region_width", ar->winx); - - if (!RNA_struct_property_is_set(op->ptr, "region_height")) - RNA_int_set(op->ptr, "region_height", ar->winy); - - if (!RNA_struct_property_is_set(op->ptr, "perspective_matrix")) - RNA_float_set_array(op->ptr, "perspective_matrix", (float *)rv3d->persmat); + ot->poll = game_engine_poll; } -void ED_view3d_operator_properties_viewmat_get(wmOperator *op, int *winx, int *winy, float persmat[4][4]) -{ - *winx = RNA_int_get(op->ptr, "region_width"); - *winy = RNA_int_get(op->ptr, "region_height"); - - RNA_float_get_array(op->ptr, "perspective_matrix", (float *)persmat); -} -#endif +/** \} */ diff --git a/source/blender/editors/space_view3d/view3d_walk.c b/source/blender/editors/space_view3d/view3d_walk.c index 76da1faf530..e65f9abae27 100644 --- a/source/blender/editors/space_view3d/view3d_walk.c +++ b/source/blender/editors/space_view3d/view3d_walk.c @@ -60,6 +60,8 @@ #include "RE_engine.h" +#include "DEG_depsgraph.h" + #include "view3d_intern.h" /* own include */ #ifdef WITH_INPUT_NDOF @@ -249,6 +251,7 @@ typedef struct WalkInfo { RegionView3D *rv3d; View3D *v3d; ARegion *ar; + const struct Depsgraph *depsgraph; Scene *scene; ViewLayer *view_layer; RenderEngineType *engine_type; @@ -334,7 +337,7 @@ static void drawWalkPixel(const struct bContext *UNUSED(C), ARegion *ar, void *a rctf viewborder; if (walk->scene->camera) { - ED_view3d_calc_camera_border(walk->scene, ar, walk->v3d, walk->rv3d, &viewborder, false); + ED_view3d_calc_camera_border(walk->scene, walk->depsgraph, ar, walk->v3d, walk->rv3d, &viewborder, false); xoff = viewborder.xmin + BLI_rctf_size_x(&viewborder) * 0.5f; yoff = viewborder.ymin + BLI_rctf_size_y(&viewborder) * 0.5f; } @@ -509,10 +512,14 @@ static float userdef_speed = -1.f; static bool initWalkInfo(bContext *C, WalkInfo *walk, wmOperator *op) { wmWindow *win = CTX_wm_window(C); + EvaluationContext eval_ctx; + + CTX_data_eval_ctx(C, &eval_ctx); walk->rv3d = CTX_wm_region_view3d(C); walk->v3d = CTX_wm_view3d(C); walk->ar = CTX_wm_region(C); + walk->depsgraph = CTX_data_depsgraph(C); walk->scene = CTX_data_scene(C); walk->view_layer = CTX_data_view_layer(C); walk->engine_type = CTX_data_engine_type(C); @@ -608,7 +615,7 @@ static bool initWalkInfo(bContext *C, WalkInfo *walk, wmOperator *op) walk->ar, walk->v3d); walk->v3d_camera_control = ED_view3d_cameracontrol_acquire( - C, walk->scene, walk->v3d, walk->rv3d, + &eval_ctx, walk->scene, walk->v3d, walk->rv3d, (U.uiflag & USER_CAM_LOCK_NO_PARENT) == 0); /* center the mouse */ @@ -716,7 +723,7 @@ static void walkEvent(bContext *C, wmOperator *op, WalkInfo *walk, const wmEvent return; } - if ((walk->is_cursor_absolute == false) && WM_event_is_absolute(event)) { + if ((walk->is_cursor_absolute == false) && event->is_motion_absolute) { walk->is_cursor_absolute = true; copy_v2_v2_int(walk->prev_mval, event->mval); copy_v2_v2_int(walk->center_mval, event->mval); diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index 5a63532b0f5..9f7b438e338 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -1969,7 +1969,7 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op) } // If modal, save settings back in scene if not set as operator argument - if (t->flag & T_MODAL) { + if ((t->flag & T_MODAL) || (op->flag & OP_IS_REPEAT)) { /* save settings if not set in operator */ /* skip saving proportional edit if it was not actually used */ @@ -1989,10 +1989,9 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op) ts->proportional_objects = (proportional != PROP_EDIT_OFF); } - if ((prop = RNA_struct_find_property(op->ptr, "proportional_size")) && - !RNA_property_is_set(op->ptr, prop)) - { - ts->proportional_size = t->prop_size; + if ((prop = RNA_struct_find_property(op->ptr, "proportional_size"))) { + ts->proportional_size = + RNA_property_is_set(op->ptr, prop) ? RNA_property_float_get(op->ptr, prop) : t->prop_size; } if ((prop = RNA_struct_find_property(op->ptr, "proportional_edit_falloff")) && @@ -5654,12 +5653,12 @@ static void slide_origdata_interp_data_vert( if (sod->layer_math_map_num) { if (do_loop_weight) { for (j = 0; j < sod->layer_math_map_num; j++) { - BM_vert_loop_groups_data_layer_merge_weights(bm, sv->cd_loop_groups[j], sod->layer_math_map[j], loop_weights); + BM_vert_loop_groups_data_layer_merge_weights(bm, sv->cd_loop_groups[j], sod->layer_math_map[j], loop_weights); } } else { for (j = 0; j < sod->layer_math_map_num; j++) { - BM_vert_loop_groups_data_layer_merge(bm, sv->cd_loop_groups[j], sod->layer_math_map[j]); + BM_vert_loop_groups_data_layer_merge(bm, sv->cd_loop_groups[j], sod->layer_math_map[j]); } } } @@ -6034,7 +6033,9 @@ static void calcEdgeSlide_mval_range( continue; /* This test is only relevant if object is not wire-drawn! See [#32068]. */ - if (use_occlude_geometry && !BMBVH_EdgeVisible(bmbvh, e_other, ar, v3d, t->obedit)) { + if (use_occlude_geometry && + !BMBVH_EdgeVisible(bmbvh, e_other, t->depsgraph, ar, v3d, t->obedit)) + { continue; } diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h index d9bfcd0c289..4ad66c0a9a5 100644 --- a/source/blender/editors/transform/transform.h +++ b/source/blender/editors/transform/transform.h @@ -43,6 +43,7 @@ /* ************************** Types ***************************** */ +struct Depsgraph; struct TransInfo; struct TransData; struct TransformOrientation; @@ -468,6 +469,7 @@ typedef struct TransInfo { struct bContext *context; /* Only valid (non null) during an operator called function. */ struct ScrArea *sa; struct ARegion *ar; + struct Depsgraph *depsgraph; struct Scene *scene; struct ViewLayer *view_layer; struct RenderEngineType *engine_type; diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c index 10a7677f42b..1aa4513e99b 100644 --- a/source/blender/editors/transform/transform_generics.c +++ b/source/blender/editors/transform/transform_generics.c @@ -1115,6 +1115,7 @@ static int initTransInfo_edit_pet_to_flag(const int proportional) */ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *event) { + Depsgraph *depsgraph = CTX_data_depsgraph(C); Scene *sce = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); ToolSettings *ts = CTX_data_tool_settings(C); @@ -1125,7 +1126,8 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve bGPdata *gpd = CTX_data_gpencil_data(C); RenderEngineType *engine_type = CTX_data_engine_type(C); PropertyRNA *prop; - + + t->depsgraph = depsgraph; t->scene = sce; t->view_layer = view_layer; t->engine_type = engine_type; diff --git a/source/blender/editors/transform/transform_manipulator.c b/source/blender/editors/transform/transform_manipulator.c index 0e0c2f3ae25..0643687c29a 100644 --- a/source/blender/editors/transform/transform_manipulator.c +++ b/source/blender/editors/transform/transform_manipulator.c @@ -1155,6 +1155,8 @@ static void manipulator_xform_message_subscribe( else { BLI_assert(0); } + + WM_msg_subscribe_rna_anon_prop(mbus, Window, view_layer, &msg_sub_value_mpr_tag_refresh); } /** \} */ @@ -1177,14 +1179,17 @@ static ManipulatorGroup *manipulatorgroup_init(wmManipulatorGroup *mgroup) #define MANIPULATOR_NEW_ARROW(v, draw_style) { \ man->manipulators[v] = WM_manipulator_new_ptr(wt_arrow, mgroup, NULL); \ RNA_enum_set(man->manipulators[v]->ptr, "draw_style", draw_style); \ + WM_manipulator_set_flag(man->manipulators[v], WM_MANIPULATOR_GRAB_CURSOR, true); \ } ((void)0) #define MANIPULATOR_NEW_DIAL(v, draw_options) { \ man->manipulators[v] = WM_manipulator_new_ptr(wt_dial, mgroup, NULL); \ RNA_enum_set(man->manipulators[v]->ptr, "draw_options", draw_options); \ + WM_manipulator_set_flag(man->manipulators[v], WM_MANIPULATOR_GRAB_CURSOR, true); \ } ((void)0) #define MANIPULATOR_NEW_PRIM(v, draw_style) { \ man->manipulators[v] = WM_manipulator_new_ptr(wt_prim, mgroup, NULL); \ RNA_enum_set(man->manipulators[v]->ptr, "draw_style", draw_style); \ + WM_manipulator_set_flag(man->manipulators[v], WM_MANIPULATOR_GRAB_CURSOR, true); \ } ((void)0) /* add/init widgets - order matters! */ @@ -1604,6 +1609,7 @@ static void WIDGETGROUP_xform_cage_refresh(const bContext *C, wmManipulatorGroup manipulator_prepare_mat(C, v3d, rv3d, &tbounds); WM_manipulator_set_flag(mpr, WM_MANIPULATOR_HIDDEN, false); + WM_manipulator_set_flag(mpr, WM_MANIPULATOR_GRAB_CURSOR, true); float dims[3]; sub_v3_v3v3(dims, rv3d->tw_axis_max, rv3d->tw_axis_min); diff --git a/source/blender/editors/transform/transform_orientations.c b/source/blender/editors/transform/transform_orientations.c index 63cd5291193..f8b11a0bcae 100644 --- a/source/blender/editors/transform/transform_orientations.c +++ b/source/blender/editors/transform/transform_orientations.c @@ -735,10 +735,19 @@ int getTransformOrientation_ex(const bContext *C, float normal[3], float plane[3 SWAP(BMVert *, v_pair[0], v_pair[1]); } - add_v3_v3v3(normal, v_pair[0]->no, v_pair[1]->no); - sub_v3_v3v3(plane, v_pair[0]->co, v_pair[1]->co); - /* flip the plane normal so we point outwards */ - negate_v3(plane); + add_v3_v3v3(normal, v_pair[1]->no, v_pair[0]->no); + sub_v3_v3v3(plane, v_pair[1]->co, v_pair[0]->co); + + if (normalize_v3(plane) != 0.0f) { + /* For edges it'd important the resulting matrix can rotate around the edge, + * project onto the plane so we can use a fallback value. */ + project_plane_normalized_v3_v3v3(normal, normal, plane); + if (UNLIKELY(normalize_v3(normal) == 0.0f)) { + /* in the case the normal and plane are aligned, + * use a fallback normal which is orthogonal to the plane. */ + ortho_v3_v3(normal, plane); + } + } } result = ORIENTATION_EDGE; diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c index ce8de2ef4d3..8f0590eb5b9 100644 --- a/source/blender/editors/transform/transform_snap_object.c +++ b/source/blender/editors/transform/transform_snap_object.c @@ -141,7 +141,7 @@ struct SnapObjectContext { /* -------------------------------------------------------------------- */ /** Common utilities -* \{ */ + * \{ */ typedef void(*IterSnapObjsCallback)(SnapObjectContext *sctx, bool is_obedit, Object *ob, float obmat[4][4], void *data); @@ -264,7 +264,7 @@ static int dm_looptri_to_poly_index(DerivedMesh *dm, const MLoopTri *lt); /* -------------------------------------------------------------------- */ /** \name Ray Cast Funcs -* \{ */ + * \{ */ /* Store all ray-hits * Support for storing all depths, not just the first (raycast 'all') */ @@ -2372,6 +2372,7 @@ bool ED_transform_snap_object_project_view3d_ex( ED_view3d_win_to_vector(ar, mval, ray_normal); ED_view3d_clip_range_get( + sctx->eval_ctx.depsgraph, sctx->v3d_data.v3d, sctx->v3d_data.ar->regiondata, &depth_range[0], &depth_range[1], false); @@ -2438,6 +2439,7 @@ bool ED_transform_snap_object_project_all_view3d_ex( float ray_start[3], ray_normal[3]; if (!ED_view3d_win_to_ray_ex( + sctx->eval_ctx.depsgraph, sctx->v3d_data.ar, sctx->v3d_data.v3d, mval, NULL, ray_normal, ray_start, true)) { diff --git a/source/blender/editors/uvedit/uvedit_draw.c b/source/blender/editors/uvedit/uvedit_draw.c index db6f2c27623..45fa35766f1 100644 --- a/source/blender/editors/uvedit/uvedit_draw.c +++ b/source/blender/editors/uvedit/uvedit_draw.c @@ -622,7 +622,7 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, ViewLayer *view_layer, Obje const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); - unsigned int pos; + unsigned int pos, color; efa_act = EDBM_uv_active_face_get(em, false, false); /* will be set to NULL if hidden */ ts = scene->toolsettings; @@ -671,58 +671,61 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, ViewLayer *view_layer, Obje if (sima->flag & SI_DRAW_STRETCH) { draw_uvs_stretch(sima, scene, em, efa_act); } - else if (!(sima->flag & SI_NO_DRAWFACES)) { - /* draw transparent faces */ - UI_GetThemeColor4ubv(TH_FACE, col1); - UI_GetThemeColor4ubv(TH_FACE_SELECT, col2); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glEnable(GL_BLEND); - - pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); - - immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); - - for (unsigned int i = 0; i < em->tottri; i++) { - efa = em->looptris[i][0]->f; + else { + unsigned int tri_count = 0; + BM_ITER_MESH(efa, &iter, bm, BM_FACES_OF_MESH) { if (uvedit_face_visible_test(scene, ima, efa)) { - const bool is_select = uvedit_face_select_test(scene, efa, cd_loop_uv_offset); BM_elem_flag_enable(efa, BM_ELEM_TAG); - - if (efa == efa_act) { - /* only once */ - immUniformThemeColor(TH_EDITMESH_ACTIVE); - } - else { - immUniformColor4ubv(is_select ? col2 : col1); - } - - immBegin(GWN_PRIM_TRIS, (em->looptris[i][0]->f->len - 2) * 3); - draw_uvs_looptri(em, &i, cd_loop_uv_offset, pos); - immEnd(); + tri_count += efa->len - 2; } else { BM_elem_flag_disable(efa, BM_ELEM_TAG); } } - immUnbindProgram(); + if (tri_count && !(sima->flag & SI_NO_DRAWFACES)) { + /* draw transparent faces */ + UI_GetThemeColor4ubv(TH_FACE, col1); + UI_GetThemeColor4ubv(TH_FACE_SELECT, col2); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glEnable(GL_BLEND); - glDisable(GL_BLEND); - } - else { - /* would be nice to do this within a draw loop but most below are optional, so it would involve too many checks */ - - BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { - if (uvedit_face_visible_test(scene, ima, efa)) { - BM_elem_flag_enable(efa, BM_ELEM_TAG); + Gwn_VertFormat *format = immVertexFormat(); + pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); + color = GWN_vertformat_attr_add(format, "color", GWN_COMP_U8, 4, GWN_FETCH_INT_TO_FLOAT_UNIT); + + immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR); + + immBegin(GWN_PRIM_TRIS, tri_count * 3); + for (unsigned int i = 0; i < em->tottri; i++) { + efa = em->looptris[i][0]->f; + if (BM_elem_flag_test(efa, BM_ELEM_TAG)) { + const bool is_select = uvedit_face_select_test(scene, efa, cd_loop_uv_offset); + + if (efa == efa_act) { + /* only once */ + unsigned char tmp_col[4]; + UI_GetThemeColor4ubv(TH_EDITMESH_ACTIVE, tmp_col); + immAttrib4ubv(color, tmp_col); + } + else { + immAttrib4ubv(color, is_select ? col2 : col1); + } + + draw_uvs_looptri(em, &i, cd_loop_uv_offset, pos); + } } - else { - if (efa == efa_act) - efa_act = NULL; - BM_elem_flag_disable(efa, BM_ELEM_TAG); + immEnd(); + + immUnbindProgram(); + + glDisable(GL_BLEND); + } + else { + if (efa_act && !uvedit_face_visible_test(scene, ima, efa_act)) { + efa_act = NULL; } } - } /* 3. draw active face stippled */ @@ -813,7 +816,7 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, ViewLayer *view_layer, Obje Gwn_VertFormat *format = immVertexFormat(); pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); - unsigned int color = GWN_vertformat_attr_add(format, "color", GWN_COMP_U8, 4, GWN_FETCH_INT_TO_FLOAT_UNIT); + color = GWN_vertformat_attr_add(format, "color", GWN_COMP_U8, 4, GWN_FETCH_INT_TO_FLOAT_UNIT); if (interpedges) { immBindBuiltinProgram(GPU_SHADER_2D_SMOOTH_COLOR); @@ -900,7 +903,7 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, ViewLayer *view_layer, Obje Gwn_VertFormat *format = immVertexFormat(); pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); - unsigned int color = GWN_vertformat_attr_add(format, "color", GWN_COMP_U8, 3, GWN_FETCH_INT_TO_FLOAT_UNIT); + color = GWN_vertformat_attr_add(format, "color", GWN_COMP_U8, 3, GWN_FETCH_INT_TO_FLOAT_UNIT); immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR); diff --git a/source/blender/freestyle/intern/python/BPy_Freestyle.cpp b/source/blender/freestyle/intern/python/BPy_Freestyle.cpp index f8aef2a08ae..0b09a3c2442 100644 --- a/source/blender/freestyle/intern/python/BPy_Freestyle.cpp +++ b/source/blender/freestyle/intern/python/BPy_Freestyle.cpp @@ -157,7 +157,7 @@ static PyObject *Freestyle_blendRamp(PyObject * /*self*/, PyObject *args) return Vector_CreatePyObject(a, 3, NULL); } -#include "BKE_texture.h" /* do_colorband() */ +#include "BKE_colorband.h" /* BKE_colorband_evaluate() */ static char Freestyle_evaluateColorRamp___doc__[] = ".. function:: evaluateColorRamp(ramp, in)\n" @@ -184,7 +184,7 @@ static PyObject *Freestyle_evaluateColorRamp(PyObject * /*self*/, PyObject *args return NULL; } coba = (ColorBand *)py_srna->ptr.data; - if (!do_colorband(coba, in, out)) { + if (!BKE_colorband_evaluate(coba, in, out)) { PyErr_SetString(PyExc_ValueError, "failed to evaluate the color ramp"); return NULL; } diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt index 18a1ef36bdc..0ac842d90a0 100644 --- a/source/blender/gpu/CMakeLists.txt +++ b/source/blender/gpu/CMakeLists.txt @@ -52,6 +52,7 @@ set(INC_SYS set(SRC intern/gpu_basic_shader.c intern/gpu_batch.c + intern/gpu_batch_presets.c intern/gpu_buffers.c intern/gpu_codegen.c intern/gpu_compositing.c diff --git a/source/blender/gpu/GPU_batch.h b/source/blender/gpu/GPU_batch.h index 6d16092996e..d2f3409dc07 100644 --- a/source/blender/gpu/GPU_batch.h +++ b/source/blender/gpu/GPU_batch.h @@ -33,19 +33,36 @@ #include "../../../intern/gawain/gawain/gwn_batch.h" +struct rctf; + // TODO: CMake magic to do this: // #include "gawain/batch.h" +#include "BLI_compiler_attrs.h" + #include "GPU_shader.h" /* Extend GWN_batch_program_set to use Blender’s library of built-in shader programs. */ -void GWN_batch_program_set_builtin(Gwn_Batch *, GPUBuiltinShader); -/* Replacement for gluSphere */ -Gwn_Batch *GPU_batch_preset_sphere(int lod); -Gwn_Batch *GPU_batch_preset_sphere_wire(int lod); +/* gpu_batch.c */ +void GWN_batch_program_set_builtin(Gwn_Batch *batch, GPUBuiltinShader shader_id) ATTR_NONNULL(1); + +Gwn_Batch *GPU_batch_tris_from_poly_2d_encoded( + const uchar *polys_flat, uint polys_flat_len, const struct rctf *rect + ) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1); +Gwn_Batch *GPU_batch_wire_from_poly_2d_encoded( + const uchar *polys_flat, uint polys_flat_len, const struct rctf *rect + ) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1); void gpu_batch_init(void); void gpu_batch_exit(void); +/* gpu_batch_presets.c */ +/* Replacement for gluSphere */ +Gwn_Batch *GPU_batch_preset_sphere(int lod) ATTR_WARN_UNUSED_RESULT; +Gwn_Batch *GPU_batch_preset_sphere_wire(int lod) ATTR_WARN_UNUSED_RESULT; + +void gpu_batch_presets_init(void); +void gpu_batch_presets_exit(void); + #endif /* __GPU_BATCH_H__ */ diff --git a/source/blender/gpu/GPU_buffers.h b/source/blender/gpu/GPU_buffers.h index 30fd4bd30b8..0d8a7a45ee9 100644 --- a/source/blender/gpu/GPU_buffers.h +++ b/source/blender/gpu/GPU_buffers.h @@ -238,10 +238,16 @@ GPU_PBVH_Buffers *GPU_pbvh_bmesh_buffers_build(bool smooth_shading); /* update */ +enum { + GPU_PBVH_BUFFERS_SHOW_DIFFUSE_COLOR = (1 << 0), + GPU_PBVH_BUFFERS_SHOW_MASK = (1 << 1), +}; + void GPU_pbvh_mesh_buffers_update( GPU_PBVH_Buffers *buffers, const struct MVert *mvert, const int *vert_indices, int totvert, const float *vmask, - const int (*face_vert_indices)[3], bool show_diffuse_color); + const int (*face_vert_indices)[3], + const int update_flags); void GPU_pbvh_bmesh_buffers_update( GPU_PBVH_Buffers *buffers, @@ -249,13 +255,13 @@ void GPU_pbvh_bmesh_buffers_update( struct GSet *bm_faces, struct GSet *bm_unique_verts, struct GSet *bm_other_verts, - bool show_diffuse_color); + const int update_flags); void GPU_pbvh_grid_buffers_update( GPU_PBVH_Buffers *buffers, struct CCGElem **grids, const struct DMFlagMat *grid_flag_mats, int *grid_indices, int totgrid, const struct CCGKey *key, - bool show_diffuse_color); + const int update_flags); /* draw */ void GPU_pbvh_buffers_draw( @@ -267,6 +273,7 @@ struct Gwn_Batch *GPU_pbvh_buffers_batch_get(GPU_PBVH_Buffers *buffers, bool fas void GPU_pbvh_BB_draw(float min[3], float max[3], bool leaf, unsigned int pos); bool GPU_pbvh_buffers_diffuse_changed(GPU_PBVH_Buffers *buffers, struct GSet *bm_faces, bool show_diffuse_color); +bool GPU_pbvh_buffers_mask_changed(GPU_PBVH_Buffers *buffers, bool show_mask); void GPU_pbvh_buffers_free(GPU_PBVH_Buffers *buffers); void GPU_pbvh_multires_buffers_free(struct GridCommonGPUBuffer **grid_common_gpu_buffer); diff --git a/source/blender/gpu/GPU_framebuffer.h b/source/blender/gpu/GPU_framebuffer.h index 705ef1997c1..c58d98c201e 100644 --- a/source/blender/gpu/GPU_framebuffer.h +++ b/source/blender/gpu/GPU_framebuffer.h @@ -83,7 +83,7 @@ void GPU_framebuffer_recursive_downsample( * - wrapper around framebuffer and texture for simple offscreen drawing * - changes size if graphics card can't support it */ -GPUOffScreen *GPU_offscreen_create(int width, int height, int samples, char err_out[256]); +GPUOffScreen *GPU_offscreen_create(int width, int height, int samples, bool high_bitdepth, char err_out[256]); void GPU_offscreen_free(GPUOffScreen *ofs); void GPU_offscreen_bind(GPUOffScreen *ofs, bool save); void GPU_offscreen_unbind(GPUOffScreen *ofs, bool restore); diff --git a/source/blender/gpu/GPU_texture.h b/source/blender/gpu/GPU_texture.h index 82e215f6fae..1b64d66469b 100644 --- a/source/blender/gpu/GPU_texture.h +++ b/source/blender/gpu/GPU_texture.h @@ -67,6 +67,7 @@ typedef enum GPUTextureFormat { GPU_RGBA8, GPU_RG32F, GPU_RG16F, + GPU_RG16I, GPU_R32F, GPU_R16F, GPU_RG8, @@ -82,7 +83,6 @@ typedef enum GPUTextureFormat { GPU_RG32I, GPU_RG32UI, GPU_RG16, - GPU_RG16I, GPU_RG16UI, GPU_RG8I, GPU_RG8UI, @@ -152,6 +152,8 @@ GPUTexture *GPU_texture_create_2D(int w, int h, const float *pixels, char err_ou GPUTexture *GPU_texture_create_2D_custom( int w, int h, int channels, GPUTextureFormat data_type, const float *pixels, char err_out[256]); GPUTexture *GPU_texture_create_2D_multisample(int w, int h, const float *pixels, int samples, char err_out[256]); +GPUTexture *GPU_texture_create_2D_custom_multisample( + int w, int h, int channels, GPUTextureFormat data_type, const float *pixels, int samples, char err_out[256]); GPUTexture *GPU_texture_create_2D_array_custom( int w, int h, int d, int channels, GPUTextureFormat data_type, const float *pixels, char err_out[256]); GPUTexture *GPU_texture_create_3D(int w, int h, int d, const float *pixels, char err_out[256]); diff --git a/source/blender/gpu/GPU_viewport.h b/source/blender/gpu/GPU_viewport.h index f2bb05a6d1e..580ff64befb 100644 --- a/source/blender/gpu/GPU_viewport.h +++ b/source/blender/gpu/GPU_viewport.h @@ -47,10 +47,8 @@ typedef struct GPUViewport GPUViewport; typedef struct ViewportMemoryPool { struct BLI_mempool *calls; struct BLI_mempool *calls_generate; - struct BLI_mempool *calls_dynamic; struct BLI_mempool *shgroups; struct BLI_mempool *uniforms; - struct BLI_mempool *attribs; struct BLI_mempool *passes; } ViewportMemoryPool; @@ -106,6 +104,7 @@ GPUViewport *GPU_viewport_create_from_offscreen(struct GPUOffScreen *ofs); void GPU_viewport_clear_from_offscreen(GPUViewport *viewport); ViewportMemoryPool *GPU_viewport_mempool_get(GPUViewport *viewport); +struct DRWInstanceDataList *GPU_viewport_instance_data_list_get(GPUViewport *viewport); void *GPU_viewport_engine_data_create(GPUViewport *viewport, void *engine_type); void *GPU_viewport_engine_data_get(GPUViewport *viewport, void *engine_type); diff --git a/source/blender/gpu/intern/gpu_batch.c b/source/blender/gpu/intern/gpu_batch.c index 5d347fc80e8..0400fc1025b 100644 --- a/source/blender/gpu/intern/gpu_batch.c +++ b/source/blender/gpu/intern/gpu_batch.c @@ -25,147 +25,257 @@ * ***** END GPL LICENSE BLOCK ***** */ +/** \file blender/gpu/intern/gpu_basic_shader.c + * \ingroup gpu + */ + +#include "MEM_guardedalloc.h" + #include "BLI_utildefines.h" +#include "BLI_rect.h" #include "BLI_math.h" +#include "BLI_polyfill2d.h" +#include "BLI_sort_utils.h" -#include "GPU_batch.h" + +#include "GPU_batch.h" /* own include */ #include "gpu_shader_private.h" +/* -------------------------------------------------------------------- */ +/** \name Utilities + * \{ */ + void GWN_batch_program_set_builtin(Gwn_Batch *batch, GPUBuiltinShader shader_id) { GPUShader *shader = GPU_shader_get_builtin_shader(shader_id); GWN_batch_program_set(batch, shader->program, shader->interface); } -static Gwn_Batch *sphere_high = NULL; -static Gwn_Batch *sphere_med = NULL; -static Gwn_Batch *sphere_low = NULL; -static Gwn_Batch *sphere_wire_low = NULL; -static Gwn_Batch *sphere_wire_med = NULL; +/** \} */ -static Gwn_VertBuf *vbo; -static Gwn_VertFormat format = {0}; -static unsigned int pos_id, nor_id; -static unsigned int vert; -static void batch_sphere_lat_lon_vert(float lat, float lon) -{ - float pos[3]; - pos[0] = sinf(lat) * cosf(lon); - pos[1] = cosf(lat); - pos[2] = sinf(lat) * sinf(lon); - GWN_vertbuf_attr_set(vbo, nor_id, vert, pos); - GWN_vertbuf_attr_set(vbo, pos_id, vert++, pos); -} +/* -------------------------------------------------------------------- */ +/** \name Batch Creation + * \{ */ -/* Replacement for gluSphere */ -static Gwn_Batch *batch_sphere(int lat_res, int lon_res) +/** + * Creates triangles from a byte-array of polygons. + * + * See 'make_shape_2d_from_blend.py' utility to create data to pass to this function. + * + * \param polys_flat: Pairs of X, Y coordinates (repeating to signify closing the polygon). + * \param polys_flat_len: Length of the array (must be an even number). + * \param rect: Optional region to map the byte 0..255 coords to. When not set use -1..1. + */ +Gwn_Batch *GPU_batch_tris_from_poly_2d_encoded( + const uchar *polys_flat, uint polys_flat_len, const rctf *rect) { - const float lon_inc = 2 * M_PI / lon_res; - const float lat_inc = M_PI / lat_res; - float lon, lat; + const uchar (*polys)[2] = (const void *)polys_flat; + const uint polys_len = polys_flat_len / 2; + BLI_assert(polys_flat_len == polys_len * 2); - if (format.attrib_ct == 0) { - pos_id = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT); - nor_id = GWN_vertformat_attr_add(&format, "nor", GWN_COMP_F32, 3, GWN_FETCH_FLOAT); - } + /* Over alloc in both cases */ + float (*verts)[2] = MEM_mallocN(sizeof(*verts) * polys_len, __func__); + float (*verts_step)[2] = verts; + uint (*tris)[3] = MEM_mallocN(sizeof(*tris) * polys_len, __func__); + uint (*tris_step)[3] = tris; - vbo = GWN_vertbuf_create_with_format(&format); - GWN_vertbuf_data_alloc(vbo, (lat_res - 1) * lon_res * 6); - vert = 0; - - lon = 0.0f; - for (int i = 0; i < lon_res; i++, lon += lon_inc) { - lat = 0.0f; - for (int j = 0; j < lat_res; j++, lat += lat_inc) { - if (j != lat_res - 1) { /* Pole */ - batch_sphere_lat_lon_vert(lat + lat_inc, lon + lon_inc); - batch_sphere_lat_lon_vert(lat + lat_inc, lon); - batch_sphere_lat_lon_vert(lat, lon); - } + const float range_uchar[2] = { + (rect ? (rect->xmax - rect->xmin) : 2.0f) / 255.0f, + (rect ? (rect->ymax - rect->ymin) : 2.0f) / 255.0f, + }; + const float min_uchar[2] = { + (rect ? rect->xmin : -1.0f), + (rect ? rect->ymin : -1.0f), + }; - if (j != 0) { /* Pole */ - batch_sphere_lat_lon_vert(lat, lon + lon_inc); - batch_sphere_lat_lon_vert(lat + lat_inc, lon + lon_inc); - batch_sphere_lat_lon_vert(lat, lon); + uint i_poly = 0; + uint i_vert = 0; + while (i_poly != polys_len) { + for (uint j = 0; j < 2; j++) { + verts[i_vert][j] = min_uchar[j] + ((float)polys[i_poly][j] * range_uchar[j]); + } + i_vert++; + i_poly++; + if (polys[i_poly - 1][0] == polys[i_poly][0] && + polys[i_poly - 1][1] == polys[i_poly][1]) + { + const uint verts_step_len = (&verts[i_vert]) - verts_step; + BLI_assert(verts_step_len >= 3); + const uint tris_len = (verts_step_len - 2); + BLI_polyfill_calc(verts_step, verts_step_len, -1, tris_step); + /* offset indices */ + if (verts_step != verts) { + uint *t = tris_step[0]; + const uint offset = (verts_step - verts); + uint tot = tris_len * 3; + while (tot--) { + *t += offset; + t++; + } + BLI_assert(t == tris_step[tris_len]); } + verts_step += verts_step_len; + tris_step += tris_len; + i_poly++; + /* ignore the duplicate point */ } } - return GWN_batch_create_ex(GWN_PRIM_TRIS, vbo, NULL, GWN_BATCH_OWNS_VBO); + /* We have vertices and tris, make a batch from this. */ + static Gwn_VertFormat format = {0}; + static struct { uint pos; } attr_id; + if (format.attrib_ct == 0) { + attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); + } + + const uint verts_len = (verts_step - verts); + const uint tris_len = (tris_step - tris); + Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format); + GWN_vertbuf_data_alloc(vbo, verts_len); + + Gwn_VertBufRaw pos_step; + GWN_vertbuf_attr_get_raw_data(vbo, attr_id.pos, &pos_step); + + for (uint i = 0; i < verts_len; i++) { + copy_v2_v2(GWN_vertbuf_raw_step(&pos_step), verts[i]); + } + + Gwn_IndexBufBuilder elb; + GWN_indexbuf_init(&elb, GWN_PRIM_TRIS, tris_len, verts_len); + for (uint i = 0; i < tris_len; i++) { + GWN_indexbuf_add_tri_verts(&elb, UNPACK3(tris[i])); + } + Gwn_IndexBuf *indexbuf = GWN_indexbuf_build(&elb); + + MEM_freeN(tris); + MEM_freeN(verts); + + return GWN_batch_create_ex( + GWN_PRIM_TRIS, vbo, + indexbuf, + GWN_BATCH_OWNS_VBO | GWN_BATCH_OWNS_INDEX); } -static Gwn_Batch *batch_sphere_wire(int lat_res, int lon_res) +Gwn_Batch *GPU_batch_wire_from_poly_2d_encoded( + const uchar *polys_flat, uint polys_flat_len, const rctf *rect) { - const float lon_inc = 2 * M_PI / lon_res; - const float lat_inc = M_PI / lat_res; - float lon, lat; + const uchar (*polys)[2] = (const void *)polys_flat; + const uint polys_len = polys_flat_len / 2; + BLI_assert(polys_flat_len == polys_len * 2); - if (format.attrib_ct == 0) { - pos_id = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT); - nor_id = GWN_vertformat_attr_add(&format, "nor", GWN_COMP_F32, 3, GWN_FETCH_FLOAT); + /* Over alloc */ + /* Lines are pairs of (x, y) byte locations packed into an int32_t. */ + int32_t *lines = MEM_mallocN(sizeof(*lines) * polys_len, __func__); + int32_t *lines_step = lines; + + const float range_uchar[2] = { + (rect ? (rect->xmax - rect->xmin) : 2.0f) / 255.0f, + (rect ? (rect->ymax - rect->ymin) : 2.0f) / 255.0f, + }; + const float min_uchar[2] = { + (rect ? rect->xmin : -1.0f), + (rect ? rect->ymin : -1.0f), + }; + + uint i_poly_prev = 0; + uint i_poly = 0; + while (i_poly != polys_len) { + i_poly++; + if (polys[i_poly - 1][0] == polys[i_poly][0] && + polys[i_poly - 1][1] == polys[i_poly][1]) + { + const uchar (*polys_step)[2] = polys + i_poly_prev; + const uint polys_step_len = i_poly - i_poly_prev; + BLI_assert(polys_step_len >= 2); + for (uint i_prev = polys_step_len - 1, i = 0; i < polys_step_len; i_prev = i++) { + union { + uint8_t as_u8[4]; + uint16_t as_u16[2]; + uint32_t as_u32; + } data; + data.as_u16[0] = *((const uint16_t *)polys_step[i_prev]); + data.as_u16[1] = *((const uint16_t *)polys_step[i]); + if (data.as_u16[0] > data.as_u16[1]) { + SWAP(uint16_t, data.as_u16[0], data.as_u16[1]); + } + *lines_step = data.as_u32; + lines_step++; + } + i_poly++; + i_poly_prev = i_poly; + /* ignore the duplicate point */ + } } - vbo = GWN_vertbuf_create_with_format(&format); - GWN_vertbuf_data_alloc(vbo, (lat_res * lon_res * 2) + ((lat_res - 1) * lon_res * 2)); - vert = 0; + uint lines_len = lines_step - lines; - lon = 0.0f; - for (int i = 0; i < lon_res; i++, lon += lon_inc) { - lat = 0.0f; - for (int j = 0; j < lat_res; j++, lat += lat_inc) { - batch_sphere_lat_lon_vert(lat + lat_inc, lon); - batch_sphere_lat_lon_vert(lat, lon); + /* Hide Lines (we could make optional) */ + { + qsort(lines, lines_len, sizeof(int32_t), BLI_sortutil_cmp_int); + lines_step = lines; - if (j != lat_res - 1) { /* Pole */ - batch_sphere_lat_lon_vert(lat + lat_inc, lon + lon_inc); - batch_sphere_lat_lon_vert(lat + lat_inc, lon); + if (lines[0] != lines[1]) { + *lines_step++ = lines[0]; + } + for (uint i_prev = 0, i = 1; i < lines_len; i_prev = i++) { + if (lines[i] != lines[i_prev]) { + *lines_step++ = lines[i]; } } + lines_len = lines_step - lines; } - return GWN_batch_create_ex(GWN_PRIM_LINES, vbo, NULL, GWN_BATCH_OWNS_VBO); -} + /* We have vertices and tris, make a batch from this. */ + static Gwn_VertFormat format = {0}; + static struct { uint pos; } attr_id; + if (format.attrib_ct == 0) { + attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); + } -Gwn_Batch *GPU_batch_preset_sphere(int lod) -{ - BLI_assert(lod >= 0 && lod <= 2); - - if (lod == 0) - return sphere_low; - else if (lod == 1) - return sphere_med; - else - return sphere_high; -} + Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format); + const uint vbo_len_capacity = lines_len * 2; + GWN_vertbuf_data_alloc(vbo, vbo_len_capacity); -Gwn_Batch *GPU_batch_preset_sphere_wire(int lod) -{ - BLI_assert(lod >= 0 && lod <= 1); + Gwn_VertBufRaw pos_step; + GWN_vertbuf_attr_get_raw_data(vbo, attr_id.pos, &pos_step); - if (lod == 0) - return sphere_wire_low; - else - return sphere_wire_med; + for (uint i = 0; i < lines_len; i++) { + union { + uint8_t as_u8_pair[2][2]; + uint32_t as_u32; + } data; + data.as_u32 = lines[i]; + for (uint k = 0; k < 2; k++) { + float *pos_v2 = GWN_vertbuf_raw_step(&pos_step); + for (uint j = 0; j < 2; j++) { + pos_v2[j] = min_uchar[j] + ((float)data.as_u8_pair[k][j] * range_uchar[j]); + } + } + } + BLI_assert(vbo_len_capacity == GWN_vertbuf_raw_used(&pos_step)); + MEM_freeN(lines); + return GWN_batch_create_ex( + GWN_PRIM_LINES, vbo, + NULL, + GWN_BATCH_OWNS_VBO); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Init/Exit + * \{ */ + void gpu_batch_init(void) { - /* Hard coded resolution */ - sphere_low = batch_sphere(8, 16); - sphere_med = batch_sphere(16, 10); - sphere_high = batch_sphere(32, 24); - - sphere_wire_low = batch_sphere_wire(6, 8); - sphere_wire_med = batch_sphere_wire(8, 16); + gpu_batch_presets_init(); } void gpu_batch_exit(void) { - GWN_batch_discard(sphere_low); - GWN_batch_discard(sphere_med); - GWN_batch_discard(sphere_high); - GWN_batch_discard(sphere_wire_low); - GWN_batch_discard(sphere_wire_med); + gpu_batch_presets_exit(); } + +/** \} */ diff --git a/source/blender/gpu/intern/gpu_batch_presets.c b/source/blender/gpu/intern/gpu_batch_presets.c new file mode 100644 index 00000000000..9db04832a51 --- /dev/null +++ b/source/blender/gpu/intern/gpu_batch_presets.c @@ -0,0 +1,200 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2016 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Mike Erwin + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/gpu/intern/gpu_batch_presets.c + * \ingroup gpu + */ + +#include "BLI_utildefines.h" +#include "BLI_math.h" + +#include "GPU_batch.h" +#include "gpu_shader_private.h" + +/* Struct to store 3D Batches and their format */ +static struct { + struct { + Gwn_Batch *sphere_high; + Gwn_Batch *sphere_med; + Gwn_Batch *sphere_low; + Gwn_Batch *sphere_wire_low; + Gwn_Batch *sphere_wire_med; + } batch; + + Gwn_VertFormat format; + + struct { + uint pos, nor; + } attr_id; +} g_presets_3d = {0}; + +/* We may want 2D presets later. */ + +/* -------------------------------------------------------------------- */ +/** \name 3D Primitives + * \{ */ + +static void batch_sphere_lat_lon_vert( + Gwn_VertBufRaw *pos_step, Gwn_VertBufRaw *nor_step, + float lat, float lon) +{ + float pos[3]; + pos[0] = sinf(lat) * cosf(lon); + pos[1] = cosf(lat); + pos[2] = sinf(lat) * sinf(lon); + copy_v3_v3(GWN_vertbuf_raw_step(pos_step), pos); + copy_v3_v3(GWN_vertbuf_raw_step(nor_step), pos); +} + +/* Replacement for gluSphere */ +static Gwn_Batch *batch_sphere(int lat_res, int lon_res) +{ + const float lon_inc = 2 * M_PI / lon_res; + const float lat_inc = M_PI / lat_res; + float lon, lat; + + Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&g_presets_3d.format); + const uint vbo_len = (lat_res - 1) * lon_res * 6; + GWN_vertbuf_data_alloc(vbo, vbo_len); + + Gwn_VertBufRaw pos_step, nor_step; + GWN_vertbuf_attr_get_raw_data(vbo, g_presets_3d.attr_id.pos, &pos_step); + GWN_vertbuf_attr_get_raw_data(vbo, g_presets_3d.attr_id.nor, &nor_step); + + lon = 0.0f; + for (int i = 0; i < lon_res; i++, lon += lon_inc) { + lat = 0.0f; + for (int j = 0; j < lat_res; j++, lat += lat_inc) { + if (j != lat_res - 1) { /* Pole */ + batch_sphere_lat_lon_vert(&pos_step, &nor_step, lat + lat_inc, lon + lon_inc); + batch_sphere_lat_lon_vert(&pos_step, &nor_step, lat + lat_inc, lon); + batch_sphere_lat_lon_vert(&pos_step, &nor_step, lat, lon); + } + + if (j != 0) { /* Pole */ + batch_sphere_lat_lon_vert(&pos_step, &nor_step, lat, lon + lon_inc); + batch_sphere_lat_lon_vert(&pos_step, &nor_step, lat + lat_inc, lon + lon_inc); + batch_sphere_lat_lon_vert(&pos_step, &nor_step, lat, lon); + } + } + } + + BLI_assert(vbo_len == GWN_vertbuf_raw_used(&pos_step)); + BLI_assert(vbo_len == GWN_vertbuf_raw_used(&nor_step)); + + return GWN_batch_create_ex(GWN_PRIM_TRIS, vbo, NULL, GWN_BATCH_OWNS_VBO); +} + +static Gwn_Batch *batch_sphere_wire(int lat_res, int lon_res) +{ + const float lon_inc = 2 * M_PI / lon_res; + const float lat_inc = M_PI / lat_res; + float lon, lat; + + Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&g_presets_3d.format); + const uint vbo_len = (lat_res * lon_res * 2) + ((lat_res - 1) * lon_res * 2); + GWN_vertbuf_data_alloc(vbo, vbo_len); + + Gwn_VertBufRaw pos_step, nor_step; + GWN_vertbuf_attr_get_raw_data(vbo, g_presets_3d.attr_id.pos, &pos_step); + GWN_vertbuf_attr_get_raw_data(vbo, g_presets_3d.attr_id.nor, &nor_step); + + lon = 0.0f; + for (int i = 0; i < lon_res; i++, lon += lon_inc) { + lat = 0.0f; + for (int j = 0; j < lat_res; j++, lat += lat_inc) { + batch_sphere_lat_lon_vert(&pos_step, &nor_step, lat + lat_inc, lon); + batch_sphere_lat_lon_vert(&pos_step, &nor_step, lat, lon); + + if (j != lat_res - 1) { /* Pole */ + batch_sphere_lat_lon_vert(&pos_step, &nor_step, lat + lat_inc, lon + lon_inc); + batch_sphere_lat_lon_vert(&pos_step, &nor_step, lat + lat_inc, lon); + } + } + } + + BLI_assert(vbo_len == GWN_vertbuf_raw_used(&pos_step)); + BLI_assert(vbo_len == GWN_vertbuf_raw_used(&nor_step)); + + return GWN_batch_create_ex(GWN_PRIM_LINES, vbo, NULL, GWN_BATCH_OWNS_VBO); +} + +Gwn_Batch *GPU_batch_preset_sphere(int lod) +{ + BLI_assert(lod >= 0 && lod <= 2); + + if (lod == 0) { + return g_presets_3d.batch.sphere_low; + } + else if (lod == 1) { + return g_presets_3d.batch.sphere_med; + } + else { + return g_presets_3d.batch.sphere_high; + } +} + +Gwn_Batch *GPU_batch_preset_sphere_wire(int lod) +{ + BLI_assert(lod >= 0 && lod <= 1); + + if (lod == 0) { + return g_presets_3d.batch.sphere_wire_low; + } + else { + return g_presets_3d.batch.sphere_wire_med; + } +} + +/** \} */ + + +void gpu_batch_presets_init(void) +{ + if (g_presets_3d.format.attrib_ct == 0) { + Gwn_VertFormat *format = &g_presets_3d.format; + g_presets_3d.attr_id.pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT); + g_presets_3d.attr_id.nor = GWN_vertformat_attr_add(format, "nor", GWN_COMP_F32, 3, GWN_FETCH_FLOAT); + } + + /* Hard coded resolution */ + g_presets_3d.batch.sphere_low = batch_sphere(8, 16); + g_presets_3d.batch.sphere_med = batch_sphere(16, 10); + g_presets_3d.batch.sphere_high = batch_sphere(32, 24); + + g_presets_3d.batch.sphere_wire_low = batch_sphere_wire(6, 8); + g_presets_3d.batch.sphere_wire_med = batch_sphere_wire(8, 16); +} + +void gpu_batch_presets_exit(void) +{ + GWN_batch_discard(g_presets_3d.batch.sphere_low); + GWN_batch_discard(g_presets_3d.batch.sphere_med); + GWN_batch_discard(g_presets_3d.batch.sphere_high); + GWN_batch_discard(g_presets_3d.batch.sphere_wire_low); + GWN_batch_discard(g_presets_3d.batch.sphere_wire_med); +} diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c index 3a6b0a2a72d..d0efee79ab0 100644 --- a/source/blender/gpu/intern/gpu_buffers.c +++ b/source/blender/gpu/intern/gpu_buffers.c @@ -980,6 +980,8 @@ struct GPU_PBVH_Buffers { bool smooth; bool show_diffuse_color; + bool show_mask; + bool use_matcaps; float diffuse_color[4]; }; @@ -1053,10 +1055,15 @@ static void gpu_color_from_mask_quad_copy(const CCGKey *key, void GPU_pbvh_mesh_buffers_update( GPU_PBVH_Buffers *buffers, const MVert *mvert, const int *vert_indices, int totvert, const float *vmask, - const int (*face_vert_indices)[3], bool show_diffuse_color) + const int (*face_vert_indices)[3], + const int update_flags) { + const bool show_diffuse_color = (update_flags & GPU_PBVH_BUFFERS_SHOW_DIFFUSE_COLOR) != 0; + const bool show_mask = (update_flags & GPU_PBVH_BUFFERS_SHOW_MASK) != 0; + buffers->vmask = vmask; buffers->show_diffuse_color = show_diffuse_color; + buffers->show_mask = show_mask; buffers->use_matcaps = GPU_material_use_matcaps_get(); { @@ -1103,7 +1110,7 @@ void GPU_pbvh_mesh_buffers_update( const MLoopTri *lt = &buffers->looptri[buffers->face_indices[i]]; for (uint j = 0; j < 3; j++) { int vidx = face_vert_indices[i][j]; - if (vmask) { + if (vmask && show_mask) { int v_index = buffers->mloop[lt->tri[j]].v; uchar color_ub[3]; gpu_color_from_mask_copy(vmask[v_index], diffuse_color, color_ub); @@ -1142,7 +1149,7 @@ void GPU_pbvh_mesh_buffers_update( } uchar color_ub[3]; - if (vmask) { + if (vmask && show_mask) { float fmask = (vmask[vtri[0]] + vmask[vtri[1]] + vmask[vtri[2]]) / 3.0f; gpu_color_from_mask_copy(fmask, diffuse_color, color_ub); } @@ -1193,6 +1200,7 @@ GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build( #endif buffers->show_diffuse_color = false; + buffers->show_mask = true; buffers->use_matcaps = false; /* Count the number of visible triangles */ @@ -1257,11 +1265,15 @@ GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build( void GPU_pbvh_grid_buffers_update( GPU_PBVH_Buffers *buffers, CCGElem **grids, const DMFlagMat *grid_flag_mats, int *grid_indices, - int totgrid, const CCGKey *key, bool show_diffuse_color) + int totgrid, const CCGKey *key, + const int update_flags) { + const bool show_diffuse_color = (update_flags & GPU_PBVH_BUFFERS_SHOW_DIFFUSE_COLOR) != 0; + const bool show_mask = (update_flags & GPU_PBVH_BUFFERS_SHOW_MASK) != 0; int i, j, k, x, y; buffers->show_diffuse_color = show_diffuse_color; + buffers->show_mask = show_mask; buffers->use_matcaps = GPU_material_use_matcaps_get(); buffers->smooth = grid_flag_mats[grid_indices[0]].flag & ME_SMOOTH; @@ -1308,8 +1320,13 @@ void GPU_pbvh_grid_buffers_update( if (has_mask) { uchar color_ub[3]; - gpu_color_from_mask_copy(*CCG_elem_mask(key, elem), - diffuse_color, color_ub); + if (show_mask) { + gpu_color_from_mask_copy(*CCG_elem_mask(key, elem), + diffuse_color, color_ub); + } + else { + F3TOCHAR3(diffuse_color, color_ub); + } GWN_vertbuf_attr_set(buffers->vert_buf, vbo_id.col, vbo_index, color_ub); } } @@ -1341,13 +1358,18 @@ void GPU_pbvh_grid_buffers_update( if (has_mask) { uchar color_ub[3]; - gpu_color_from_mask_quad_copy(key, - elems[0], - elems[1], - elems[2], - elems[3], - diffuse_color, - color_ub); + if (show_mask) { + gpu_color_from_mask_quad_copy(key, + elems[0], + elems[1], + elems[2], + elems[3], + diffuse_color, + color_ub); + } + else { + F3TOCHAR3(diffuse_color, color_ub); + } GWN_vertbuf_attr_set(buffers->vert_buf, vbo_id.col, vbo_index, color_ub); } } @@ -1483,6 +1505,7 @@ GPU_PBVH_Buffers *GPU_pbvh_grid_buffers_build( buffers->totgrid = totgrid; buffers->show_diffuse_color = false; + buffers->show_mask = true; buffers->use_matcaps = false; /* Count the number of quads */ @@ -1544,7 +1567,8 @@ static void gpu_bmesh_vert_to_buffer_copy__gwn( const float fno[3], const float *fmask, const int cd_vert_mask_offset, - const float diffuse_color[4]) + const float diffuse_color[4], + const bool show_mask) { if (!BM_elem_flag_test(v, BM_ELEM_HIDDEN)) { @@ -1559,9 +1583,17 @@ static void gpu_bmesh_vert_to_buffer_copy__gwn( { uchar color_ub[3]; + float effective_mask; + if (show_mask) { + effective_mask = fmask ? *fmask + : BM_ELEM_CD_GET_FLOAT(v, cd_vert_mask_offset); + } + else { + effective_mask = 0.0f; + } + gpu_color_from_mask_copy( - fmask ? *fmask : - BM_ELEM_CD_GET_FLOAT(v, cd_vert_mask_offset), + effective_mask, diffuse_color, color_ub); GWN_vertbuf_attr_set(vert_buf, vbo_id->col, *v_index, color_ub); @@ -1620,8 +1652,10 @@ void GPU_pbvh_bmesh_buffers_update( GSet *bm_faces, GSet *bm_unique_verts, GSet *bm_other_verts, - bool show_diffuse_color) + const int update_flags) { + const bool show_diffuse_color = (update_flags & GPU_PBVH_BUFFERS_SHOW_DIFFUSE_COLOR) != 0; + const bool show_mask = (update_flags & GPU_PBVH_BUFFERS_SHOW_MASK) != 0; int tottri, totvert, maxvert = 0; float diffuse_color[4] = {0.8f, 0.8f, 0.8f, 1.0f}; @@ -1629,6 +1663,7 @@ void GPU_pbvh_bmesh_buffers_update( const int cd_vert_mask_offset = CustomData_get_offset(&bm->vdata, CD_PAINT_MASK); buffers->show_diffuse_color = show_diffuse_color; + buffers->show_mask = show_mask; buffers->use_matcaps = GPU_material_use_matcaps_get(); /* Count visible triangles */ @@ -1684,14 +1719,16 @@ void GPU_pbvh_bmesh_buffers_update( gpu_bmesh_vert_to_buffer_copy__gwn( BLI_gsetIterator_getKey(&gs_iter), buffers->vert_buf, &vbo_id, &v_index, NULL, NULL, - cd_vert_mask_offset, diffuse_color); + cd_vert_mask_offset, diffuse_color, + show_mask); } GSET_ITER (gs_iter, bm_other_verts) { gpu_bmesh_vert_to_buffer_copy__gwn( BLI_gsetIterator_getKey(&gs_iter), buffers->vert_buf, &vbo_id, &v_index, NULL, NULL, - cd_vert_mask_offset, diffuse_color); + cd_vert_mask_offset, diffuse_color, + show_mask); } maxvert = v_index; @@ -1724,7 +1761,8 @@ void GPU_pbvh_bmesh_buffers_update( gpu_bmesh_vert_to_buffer_copy__gwn( v[i], buffers->vert_buf, &vbo_id, &v_index, f->no, &fmask, - cd_vert_mask_offset, diffuse_color); + cd_vert_mask_offset, diffuse_color, + show_mask); } } } @@ -1796,6 +1834,7 @@ GPU_PBVH_Buffers *GPU_pbvh_bmesh_buffers_build(bool smooth_shading) buffers->use_bmesh = true; buffers->smooth = smooth_shading; buffers->show_diffuse_color = false; + buffers->show_mask = true; buffers->use_matcaps = false; return buffers; @@ -1883,6 +1922,11 @@ bool GPU_pbvh_buffers_diffuse_changed(GPU_PBVH_Buffers *buffers, GSet *bm_faces, return !equals_v3v3(diffuse_color, buffers->diffuse_color); } +bool GPU_pbvh_buffers_mask_changed(GPU_PBVH_Buffers *buffers, bool show_mask) +{ + return (buffers->show_mask != show_mask); +} + void GPU_pbvh_buffers_free(GPU_PBVH_Buffers *buffers) { if (buffers) { @@ -1892,7 +1936,7 @@ void GPU_pbvh_buffers_free(GPU_PBVH_Buffers *buffers) GWN_INDEXBUF_DISCARD_SAFE(buffers->index_buf); } GWN_INDEXBUF_DISCARD_SAFE(buffers->index_buf_fast); - GWN_vertbuf_discard(buffers->vert_buf); + GWN_VERTBUF_DISCARD_SAFE(buffers->vert_buf); #ifdef USE_BASE_ELEM if (buffers->baseelemarray) diff --git a/source/blender/gpu/intern/gpu_compositing.c b/source/blender/gpu/intern/gpu_compositing.c index 12ed67cdf4e..3de363cc76e 100644 --- a/source/blender/gpu/intern/gpu_compositing.c +++ b/source/blender/gpu/intern/gpu_compositing.c @@ -1007,7 +1007,7 @@ bool GPU_fx_do_composite_pass( glClearColor(0.0, 0.0, 0.0, 0.0); glClear(GL_COLOR_BUFFER_BIT); /* the draw call we all waited for, draw a point per pixel, scaled per circle of confusion */ - GWN_batch_draw_stupid_instanced(fx->point_batch, 0, fx->dof_downsampled_w * fx->dof_downsampled_h, 0, 0, NULL, NULL); + GWN_batch_draw_stupid_instanced(fx->point_batch, 0, fx->dof_downsampled_w * fx->dof_downsampled_h, 0, 0, 0, NULL, NULL); GPU_texture_unbind(fx->dof_half_downsampled_far); GPU_framebuffer_texture_detach(fx->dof_far_blur); @@ -1023,7 +1023,7 @@ bool GPU_fx_do_composite_pass( /* have to clear the buffer unfortunately */ glClear(GL_COLOR_BUFFER_BIT); /* the draw call we all waited for, draw a point per pixel, scaled per circle of confusion */ - GWN_batch_draw_stupid_instanced(fx->point_batch, 0, fx->dof_downsampled_w * fx->dof_downsampled_h, 0, 0, NULL, NULL); + GWN_batch_draw_stupid_instanced(fx->point_batch, 0, fx->dof_downsampled_w * fx->dof_downsampled_h, 0, 0, 0, NULL, NULL); GWN_batch_program_use_end(fx->point_batch); /* disable bindings */ diff --git a/source/blender/gpu/intern/gpu_framebuffer.c b/source/blender/gpu/intern/gpu_framebuffer.c index 6830e73cb03..09013cd29bd 100644 --- a/source/blender/gpu/intern/gpu_framebuffer.c +++ b/source/blender/gpu/intern/gpu_framebuffer.c @@ -650,7 +650,7 @@ struct GPUOffScreen { GPUTexture *depth; }; -GPUOffScreen *GPU_offscreen_create(int width, int height, int samples, char err_out[256]) +GPUOffScreen *GPU_offscreen_create(int width, int height, int samples, bool high_bitdepth, char err_out[256]) { GPUOffScreen *ofs; @@ -683,7 +683,12 @@ GPUOffScreen *GPU_offscreen_create(int width, int height, int samples, char err_ return NULL; } - ofs->color = GPU_texture_create_2D_multisample(width, height, NULL, samples, err_out); + if (high_bitdepth) { + ofs->color = GPU_texture_create_2D_custom_multisample(width, height, 4, GPU_RGBA16F, NULL, samples, err_out); + } + else { + ofs->color = GPU_texture_create_2D_multisample(width, height, NULL, samples, err_out); + } if (!ofs->color) { GPU_offscreen_free(ofs); return NULL; diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c index e2883b53047..2e6c1cbf9df 100644 --- a/source/blender/gpu/intern/gpu_material.c +++ b/source/blender/gpu/intern/gpu_material.c @@ -48,6 +48,7 @@ #include "BLI_rand.h" #include "BKE_anim.h" +#include "BKE_colorband.h" #include "BKE_colortools.h" #include "BKE_global.h" #include "BKE_image.h" @@ -55,7 +56,6 @@ #include "BKE_main.h" #include "BKE_node.h" #include "BKE_scene.h" -#include "BKE_texture.h" #include "BKE_group.h" #include "IMB_imbuf_types.h" @@ -994,7 +994,7 @@ static void ramp_blend( GPU_link(mat, names[type], fac, col1, col2, r_col); } -static void do_colorband_blend( +static void BKE_colorband_eval_blend( GPUMaterial *mat, ColorBand *coba, GPUNodeLink *fac, float rampfac, int type, GPUNodeLink *incol, GPUNodeLink **r_col) { @@ -1003,7 +1003,7 @@ static void do_colorband_blend( int size; /* do colorband */ - colorband_table_RGBA(coba, &array, &size); + BKE_colorband_evaluate_table_rgba(coba, &array, &size); GPU_link(mat, "valtorgb", fac, GPU_texture(size, array), &col, &tmp); /* use alpha in fac */ @@ -1026,7 +1026,7 @@ static void ramp_diffuse_result(GPUShadeInput *shi, GPUNodeLink **diff) GPU_link(mat, "ramp_rgbtobw", *diff, &fac); /* colorband + blend */ - do_colorband_blend(mat, ma->ramp_col, fac, ma->rampfac_col, ma->rampblend_col, *diff, diff); + BKE_colorband_eval_blend(mat, ma->ramp_col, fac, ma->rampfac_col, ma->rampblend_col, *diff, diff); } } } @@ -1063,7 +1063,7 @@ static void add_to_diffuse( } /* colorband + blend */ - do_colorband_blend(mat, ma->ramp_col, fac, ma->rampfac_col, ma->rampblend_col, shi->rgb, &addcol); + BKE_colorband_eval_blend(mat, ma->ramp_col, fac, ma->rampfac_col, ma->rampblend_col, shi->rgb, &addcol); } } else @@ -1085,7 +1085,7 @@ static void ramp_spec_result(GPUShadeInput *shi, GPUNodeLink **spec) GPU_link(mat, "ramp_rgbtobw", *spec, &fac); /* colorband + blend */ - do_colorband_blend(mat, ma->ramp_spec, fac, ma->rampfac_spec, ma->rampblend_spec, *spec, spec); + BKE_colorband_eval_blend(mat, ma->ramp_spec, fac, ma->rampfac_spec, ma->rampblend_spec, *spec, spec); } } @@ -1117,7 +1117,7 @@ static void do_specular_ramp(GPUShadeInput *shi, GPUNodeLink *is, GPUNodeLink *t } /* colorband + blend */ - do_colorband_blend(mat, ma->ramp_spec, fac, ma->rampfac_spec, ma->rampblend_spec, *spec, spec); + BKE_colorband_eval_blend(mat, ma->ramp_spec, fac, ma->rampfac_spec, ma->rampblend_spec, *spec, spec); } } diff --git a/source/blender/gpu/intern/gpu_texture.c b/source/blender/gpu/intern/gpu_texture.c index 252eede8758..d6b641af225 100644 --- a/source/blender/gpu/intern/gpu_texture.c +++ b/source/blender/gpu/intern/gpu_texture.c @@ -115,9 +115,9 @@ static GLenum gpu_texture_get_format( int components, GPUTextureFormat data_type, GLenum *format, GLenum *data_format, bool *is_depth, bool *is_stencil, unsigned int *bytesize) { - if (data_type == GPU_DEPTH_COMPONENT24 || - data_type == GPU_DEPTH_COMPONENT16 || - data_type == GPU_DEPTH_COMPONENT32F) + if (ELEM(data_type, GPU_DEPTH_COMPONENT24, + GPU_DEPTH_COMPONENT16, + GPU_DEPTH_COMPONENT32F)) { *is_depth = true; *is_stencil = false; @@ -133,14 +133,29 @@ static GLenum gpu_texture_get_format( else { *is_depth = false; *is_stencil = false; - *data_format = GL_FLOAT; - switch (components) { - case 1: *format = GL_RED; break; - case 2: *format = GL_RG; break; - case 3: *format = GL_RGB; break; - case 4: *format = GL_RGBA; break; - default: break; + /* Integer formats */ + if (ELEM(data_type, GPU_RG16I)) { + *data_format = GL_INT; + + switch (components) { + case 1: *format = GL_RED_INTEGER; break; + case 2: *format = GL_RG_INTEGER; break; + case 3: *format = GL_RGB_INTEGER; break; + case 4: *format = GL_RGBA_INTEGER; break; + default: break; + } + } + else { + *data_format = GL_FLOAT; + + switch (components) { + case 1: *format = GL_RED; break; + case 2: *format = GL_RG; break; + case 3: *format = GL_RGB; break; + case 4: *format = GL_RGBA; break; + default: break; + } } } @@ -156,6 +171,7 @@ static GLenum gpu_texture_get_format( *bytesize = 12; break; case GPU_RG16F: + case GPU_RG16I: case GPU_DEPTH24_STENCIL8: case GPU_DEPTH_COMPONENT32F: case GPU_RGBA8: @@ -188,6 +204,7 @@ static GLenum gpu_texture_get_format( case GPU_RG32F: return GL_RG32F; case GPU_RGB16F: return GL_RGB16F; case GPU_RG16F: return GL_RG16F; + case GPU_RG16I: return GL_RG16I; case GPU_RGBA8: return GL_RGBA8; case GPU_R32F: return GL_R32F; case GPU_R16F: return GL_R16F; @@ -663,6 +680,12 @@ GPUTexture *GPU_texture_create_2D_multisample(int w, int h, const float *pixels, return GPU_texture_create_nD(w, h, 0, 2, pixels, GPU_RGBA8, 4, samples, false, err_out); } +GPUTexture *GPU_texture_create_2D_custom_multisample( + int w, int h, int channels, GPUTextureFormat data_type, const float *pixels, int samples, char err_out[256]) +{ + return GPU_texture_create_nD(w, h, 0, 2, pixels, data_type, channels, samples, false, err_out); +} + GPUTexture *GPU_texture_create_2D_array_custom(int w, int h, int d, int channels, GPUTextureFormat data_type, const float *pixels, char err_out[256]) { return GPU_texture_create_nD(w, h, d, 2, pixels, data_type, channels, 0, false, err_out); diff --git a/source/blender/gpu/intern/gpu_viewport.c b/source/blender/gpu/intern/gpu_viewport.c index bd563a36f57..3ef53b3a6c3 100644 --- a/source/blender/gpu/intern/gpu_viewport.c +++ b/source/blender/gpu/intern/gpu_viewport.c @@ -84,6 +84,7 @@ struct GPUViewport { DefaultTextureList *txl; ViewportMemoryPool vmempool; /* Used for rendering data structure. */ + struct DRWInstanceDataList *idatalist; /* Used for rendering data structure. */ ListBase tex_pool; /* ViewportTempTexture list : Temporary textures shared across draw engines */ }; @@ -114,6 +115,7 @@ GPUViewport *GPU_viewport_create(void) GPUViewport *viewport = MEM_callocN(sizeof(GPUViewport), "GPUViewport"); viewport->fbl = MEM_callocN(sizeof(DefaultFramebufferList), "FramebufferList"); viewport->txl = MEM_callocN(sizeof(DefaultTextureList), "TextureList"); + viewport->idatalist = DRW_instance_data_list_create(); viewport->size[0] = viewport->size[1] = -1; @@ -210,6 +212,11 @@ ViewportMemoryPool *GPU_viewport_mempool_get(GPUViewport *viewport) return &viewport->vmempool; } +struct DRWInstanceDataList *GPU_viewport_instance_data_list_get(GPUViewport *viewport) +{ + return viewport->idatalist; +} + void *GPU_viewport_framebuffer_list_get(GPUViewport *viewport) { return viewport->fbl; @@ -583,22 +590,19 @@ void GPU_viewport_free(GPUViewport *viewport) if (viewport->vmempool.calls_generate != NULL) { BLI_mempool_destroy(viewport->vmempool.calls_generate); } - if (viewport->vmempool.calls_dynamic != NULL) { - BLI_mempool_destroy(viewport->vmempool.calls_dynamic); - } if (viewport->vmempool.shgroups != NULL) { BLI_mempool_destroy(viewport->vmempool.shgroups); } if (viewport->vmempool.uniforms != NULL) { BLI_mempool_destroy(viewport->vmempool.uniforms); } - if (viewport->vmempool.attribs != NULL) { - BLI_mempool_destroy(viewport->vmempool.attribs); - } if (viewport->vmempool.passes != NULL) { BLI_mempool_destroy(viewport->vmempool.passes); } + DRW_instance_data_list_free(viewport->idatalist); + MEM_freeN(viewport->idatalist); + GPU_viewport_debug_depth_free(viewport); } diff --git a/source/blender/gpu/shaders/gpu_shader_instance_bone_envelope_solid_vert.glsl b/source/blender/gpu/shaders/gpu_shader_instance_bone_envelope_solid_vert.glsl index 74c8f6f3103..d0f2a8dcd51 100644 --- a/source/blender/gpu/shaders/gpu_shader_instance_bone_envelope_solid_vert.glsl +++ b/source/blender/gpu/shaders/gpu_shader_instance_bone_envelope_solid_vert.glsl @@ -7,7 +7,6 @@ uniform mat4 ViewMatrix; -uniform mat4 ObjectModelMatrix; uniform mat4 ViewProjectionMatrix; @@ -38,7 +37,7 @@ void main() bone_mat[1] = normalize(bone_mat[1]); bone_mat[2] = normalize(bone_mat[2]); - mat3 nor_mat = transpose(inverse(mat3(ViewMatrix * ObjectModelMatrix) * bone_mat)); + mat3 nor_mat = transpose(inverse(mat3(ViewMatrix) * bone_mat)); /* Where does this comes from???? Don't know why, but is mandatory anyway... :/ */ const float size = 2.0f; @@ -116,7 +115,7 @@ void main() ob_pos.xyz = bone_mat * ob_pos.xyz; ob_pos.w = 1.0f; - gl_Position = ViewProjectionMatrix * ObjectModelMatrix * (ob_pos + ob_bone_origin); + gl_Position = ViewProjectionMatrix * (ob_pos + ob_bone_origin); normal = normalize(nor_mat * nor); finalColor = color; } diff --git a/source/blender/gpu/shaders/gpu_shader_instance_bone_envelope_wire_vert.glsl b/source/blender/gpu/shaders/gpu_shader_instance_bone_envelope_wire_vert.glsl index a36eb1dec77..1bdad924bd2 100644 --- a/source/blender/gpu/shaders/gpu_shader_instance_bone_envelope_wire_vert.glsl +++ b/source/blender/gpu/shaders/gpu_shader_instance_bone_envelope_wire_vert.glsl @@ -7,11 +7,8 @@ * Note that if one of head/tail radius is negative, it assumes it only works on the other end of the bone * (used to draw head/tail spheres). */ - uniform mat4 ViewMatrix; uniform mat4 ProjectionMatrix; -uniform mat4 ObjectModelMatrix; - /* ---- Instanciated Attribs ---- */ in vec4 pos; /* z encodes head (== 0.0f), tail (== 1.0f) or in-between; w encodes inner (0.0f) or outer border. */ @@ -36,7 +33,7 @@ void main() vec4 tail = bone_mat * vec4(0.0f, 1.0f, 0.0f, 1.0f); /* We generate our XY axes in object space, Y axis being aligned with bone in view space. */ - mat4 obview_mat = ViewMatrix * ObjectModelMatrix; + mat4 obview_mat = ViewMatrix; mat4 iobview_mat = inverse(obview_mat); vec4 view_bone_vec = obview_mat * normalize(tail - head); diff --git a/source/blender/gpu/shaders/gpu_shader_instance_objectspace_variying_color_vert.glsl b/source/blender/gpu/shaders/gpu_shader_instance_objectspace_variying_color_vert.glsl index 195d4849d99..9876717b297 100644 --- a/source/blender/gpu/shaders/gpu_shader_instance_objectspace_variying_color_vert.glsl +++ b/source/blender/gpu/shaders/gpu_shader_instance_objectspace_variying_color_vert.glsl @@ -1,7 +1,6 @@ uniform mat4 ViewMatrix; uniform mat4 ViewProjectionMatrix; -uniform mat4 ObjectModelMatrix; /* ---- Instanciated Attribs ---- */ in vec3 pos; @@ -16,11 +15,10 @@ flat out vec4 finalColor; void main() { - mat4 FinalModelMatrix = ObjectModelMatrix * InstanceModelMatrix; - mat4 ModelViewProjectionMatrix = ViewProjectionMatrix * FinalModelMatrix; + mat4 ModelViewProjectionMatrix = ViewProjectionMatrix * InstanceModelMatrix; /* This is slow and run per vertex, but it's still faster than * doing it per instance on CPU and sending it on via instance attrib */ - mat3 NormalMatrix = transpose(inverse(mat3(ViewMatrix * FinalModelMatrix))); + mat3 NormalMatrix = transpose(inverse(mat3(ViewMatrix * InstanceModelMatrix))); gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); normal = NormalMatrix * nor; diff --git a/source/blender/gpu/shaders/gpu_shader_material.glsl b/source/blender/gpu/shaders/gpu_shader_material.glsl index 9d22fbba65e..780f4f59fb9 100644 --- a/source/blender/gpu/shaders/gpu_shader_material.glsl +++ b/source/blender/gpu/shaders/gpu_shader_material.glsl @@ -1004,8 +1004,8 @@ void texco_orco(vec3 attorco, out vec3 orco) void texco_uv(vec2 attuv, out vec3 uv) { - /* disabled for now, works together with leaving out mtex_2d_mapping - uv = vec3(attuv * 2.0 - vec2(1.0), 0.0); */ + /* disabled for now, works together with leaving out mtex_2d_mapping */ + // uv = vec3(attuv*2.0 - vec2(1.0, 1.0), 0.0); */ uv = vec3(attuv, 0.0); } @@ -4135,9 +4135,14 @@ void node_bevel(float radius, vec3 N, out vec3 result) result = N; } +void node_displacement(float height, float dist, vec3 N, out vec3 result) +{ + result = height * dist * N; +} + /* output */ -void node_output_material(Closure surface, Closure volume, float displacement, out Closure result) +void node_output_material(Closure surface, Closure volume, vec3 displacement, out Closure result) { #ifdef VOLUMETRICS result = volume; diff --git a/source/blender/imbuf/IMB_imbuf.h b/source/blender/imbuf/IMB_imbuf.h index f1f36351e79..a7f793b5b11 100644 --- a/source/blender/imbuf/IMB_imbuf.h +++ b/source/blender/imbuf/IMB_imbuf.h @@ -583,6 +583,12 @@ bool IMB_metadata_change_field(struct ImBuf *img, const char *key, const char *f void IMB_metadata_copy(struct ImBuf *dimb, struct ImBuf *simb); /* exported for image tools in blender, to quickly allocate 32 bits rect */ +void *imb_alloc_pixels(unsigned int x, + unsigned int y, + unsigned int channels, + size_t typesize, + const char *name); + bool imb_addrectImBuf(struct ImBuf *ibuf); void imb_freerectImBuf(struct ImBuf *ibuf); diff --git a/source/blender/imbuf/intern/IMB_anim.h b/source/blender/imbuf/intern/IMB_anim.h index b10ae4f6fe9..c4c4f4405a5 100644 --- a/source/blender/imbuf/intern/IMB_anim.h +++ b/source/blender/imbuf/intern/IMB_anim.h @@ -99,8 +99,8 @@ struct anim { int curtype; int curposition; /* index 0 = 1e, 1 = 2e, enz. */ int duration; - short frs_sec; - float frs_sec_base; + int frs_sec; + double frs_sec_base; int x, y; /* for number */ diff --git a/source/blender/imbuf/intern/allocimbuf.c b/source/blender/imbuf/intern/allocimbuf.c index 6e9bfa1fc4e..7fc4a65d8d7 100644 --- a/source/blender/imbuf/intern/allocimbuf.c +++ b/source/blender/imbuf/intern/allocimbuf.c @@ -265,15 +265,11 @@ ImBuf *IMB_makeSingleUser(ImBuf *ibuf) bool addzbufImBuf(ImBuf *ibuf) { - size_t size; - if (ibuf == NULL) return false; IMB_freezbufImBuf(ibuf); - size = (size_t)ibuf->x * (size_t)ibuf->y * sizeof(unsigned int); - - if ((ibuf->zbuf = MEM_mapallocN(size, __func__))) { + if ((ibuf->zbuf = imb_alloc_pixels(ibuf->x, ibuf->y, 1, sizeof(unsigned int), __func__))) { ibuf->mall |= IB_zbuf; ibuf->flags |= IB_zbuf; return true; @@ -284,15 +280,11 @@ bool addzbufImBuf(ImBuf *ibuf) bool addzbuffloatImBuf(ImBuf *ibuf) { - size_t size; - if (ibuf == NULL) return false; IMB_freezbuffloatImBuf(ibuf); - size = (size_t)ibuf->x * (size_t)ibuf->y * sizeof(float); - - if ((ibuf->zbuf_float = MEM_mapallocN(size, __func__))) { + if ((ibuf->zbuf_float = imb_alloc_pixels(ibuf->x, ibuf->y, 1, sizeof(float), __func__))) { ibuf->mall |= IB_zbuffloat; ibuf->flags |= IB_zbuffloat; return true; @@ -361,19 +353,31 @@ bool imb_enlargeencodedbufferImBuf(ImBuf *ibuf) return true; } +void *imb_alloc_pixels(unsigned int x, + unsigned int y, + unsigned int channels, + size_t typesize, + const char *name) +{ + /* Protect against buffer overflow vulnerabilities from files specifying + * a width and height that overflow and alloc too little memory. */ + if (!((uint64_t)x * (uint64_t)y < (SIZE_MAX / (channels * typesize)))) { + return NULL; + } + + size_t size = (size_t)x * (size_t)y * (size_t)channels * typesize; + return MEM_mapallocN(size, name); +} + bool imb_addrectfloatImBuf(ImBuf *ibuf) { - size_t size; - if (ibuf == NULL) return false; if (ibuf->rect_float) imb_freerectfloatImBuf(ibuf); /* frees mipmap too, hrm */ - size = (size_t)ibuf->x * (size_t)ibuf->y * sizeof(float[4]); - ibuf->channels = 4; - if ((ibuf->rect_float = MEM_mapallocN(size, __func__))) { + if ((ibuf->rect_float = imb_alloc_pixels(ibuf->x, ibuf->y, 4, sizeof(float), __func__))) { ibuf->mall |= IB_rectfloat; ibuf->flags |= IB_rectfloat; return true; @@ -385,8 +389,6 @@ bool imb_addrectfloatImBuf(ImBuf *ibuf) /* question; why also add zbuf? */ bool imb_addrectImBuf(ImBuf *ibuf) { - size_t size; - if (ibuf == NULL) return false; /* don't call imb_freerectImBuf, it frees mipmaps, this call is used only too give float buffers display */ @@ -394,9 +396,7 @@ bool imb_addrectImBuf(ImBuf *ibuf) MEM_freeN(ibuf->rect); ibuf->rect = NULL; - size = (size_t)ibuf->x * (size_t)ibuf->y * sizeof(unsigned int); - - if ((ibuf->rect = MEM_mapallocN(size, __func__))) { + if ((ibuf->rect = imb_alloc_pixels(ibuf->x, ibuf->y, 4, sizeof(unsigned char), __func__))) { ibuf->mall |= IB_rect; ibuf->flags |= IB_rect; if (ibuf->planes > 32) { diff --git a/source/blender/imbuf/intern/anim_movie.c b/source/blender/imbuf/intern/anim_movie.c index 25b0c0d7b1a..5472cae3ef2 100644 --- a/source/blender/imbuf/intern/anim_movie.c +++ b/source/blender/imbuf/intern/anim_movie.c @@ -55,6 +55,7 @@ #include <stdlib.h> #include <stdio.h> #include <math.h> +#include <limits.h> #ifndef _WIN32 #include <dirent.h> #else @@ -1365,16 +1366,32 @@ int IMB_anim_get_duration(struct anim *anim, IMB_Timecode_Type tc) bool IMB_anim_get_fps(struct anim *anim, short *frs_sec, float *frs_sec_base, bool no_av_base) { + double frs_sec_base_double; if (anim->frs_sec) { - *frs_sec = anim->frs_sec; - *frs_sec_base = anim->frs_sec_base; + if (anim->frs_sec > SHRT_MAX) { + /* We cannot store original rational in our short/float format, + * we need to approximate it as best as we can... */ + *frs_sec = SHRT_MAX; + frs_sec_base_double = anim->frs_sec_base * (double)SHRT_MAX / (double)anim->frs_sec; + } + else { + *frs_sec = anim->frs_sec; + frs_sec_base_double = anim->frs_sec_base; + } #ifdef WITH_FFMPEG if (no_av_base) { - *frs_sec_base /= AV_TIME_BASE; + *frs_sec_base = (float)(frs_sec_base_double / AV_TIME_BASE); + } + else { + *frs_sec_base = (float)frs_sec_base_double; } #else UNUSED_VARS(no_av_base); + *frs_sec_base = (float)frs_sec_base_double; #endif + BLI_assert(*frs_sec > 0); + BLI_assert(*frs_sec_base > 0.0f); + return true; } return false; diff --git a/source/blender/imbuf/intern/bmp.c b/source/blender/imbuf/intern/bmp.c index c5694148127..e63699ea5ba 100644 --- a/source/blender/imbuf/intern/bmp.c +++ b/source/blender/imbuf/intern/bmp.c @@ -124,7 +124,7 @@ struct ImBuf *imb_bmp_decode(const unsigned char *mem, size_t size, int flags, c { struct ImBuf *ibuf = NULL; BMPINFOHEADER bmi; - int x, y, depth, ibuf_depth, skip, i, j; + int x, y, depth, ibuf_depth, skip; const unsigned char *bmp; unsigned char *rect; unsigned short col; @@ -179,13 +179,17 @@ struct ImBuf *imb_bmp_decode(const unsigned char *mem, size_t size, int flags, c } else { ibuf = IMB_allocImBuf(x, y, ibuf_depth, IB_rect); + if (!ibuf) { + return NULL; + } + rect = (unsigned char *) ibuf->rect; if (depth <= 8) { const int rowsize = (depth * x + 31) / 32 * 4; const char (*palette)[4] = (void *)(mem + skip); const int startmask = ((1 << depth) - 1) << 8; - for (i = y; i > 0; i--) { + for (size_t i = y; i > 0; i--) { int index; int bitoffs = 8; int bitmask = startmask; @@ -194,7 +198,7 @@ struct ImBuf *imb_bmp_decode(const unsigned char *mem, size_t size, int flags, c if (top_to_bottom) { rect = (unsigned char *) &ibuf->rect[(i - 1) * x]; } - for (j = x; j > 0; j--) { + for (size_t j = x; j > 0; j--) { bitoffs -= depth; bitmask >>= depth; index = (bmp[0] & bitmask) >> bitoffs; @@ -219,11 +223,11 @@ struct ImBuf *imb_bmp_decode(const unsigned char *mem, size_t size, int flags, c } } else if (depth == 16) { - for (i = y; i > 0; i--) { + for (size_t i = y; i > 0; i--) { if (top_to_bottom) { rect = (unsigned char *) &ibuf->rect[(i - 1) * x]; } - for (j = x; j > 0; j--) { + for (size_t j = x; j > 0; j--) { col = bmp[0] + (bmp[1] << 8); rect[0] = ((col >> 10) & 0x1f) << 3; rect[1] = ((col >> 5) & 0x1f) << 3; @@ -236,11 +240,11 @@ struct ImBuf *imb_bmp_decode(const unsigned char *mem, size_t size, int flags, c } else if (depth == 24) { const int x_pad = x % 4; - for (i = y; i > 0; i--) { + for (size_t i = y; i > 0; i--) { if (top_to_bottom) { rect = (unsigned char *) &ibuf->rect[(i - 1) * x]; } - for (j = x; j > 0; j--) { + for (size_t j = x; j > 0; j--) { rect[0] = bmp[2]; rect[1] = bmp[1]; rect[2] = bmp[0]; @@ -253,11 +257,11 @@ struct ImBuf *imb_bmp_decode(const unsigned char *mem, size_t size, int flags, c } } else if (depth == 32) { - for (i = y; i > 0; i--) { + for (size_t i = y; i > 0; i--) { if (top_to_bottom) { rect = (unsigned char *) &ibuf->rect[(i - 1) * x]; } - for (j = x; j > 0; j--) { + for (size_t j = x; j > 0; j--) { rect[0] = bmp[2]; rect[1] = bmp[1]; rect[2] = bmp[0]; @@ -299,7 +303,7 @@ static int putShortLSB(unsigned short us, FILE *ofile) int imb_savebmp(struct ImBuf *ibuf, const char *name, int flags) { BMPINFOHEADER infoheader; - int bytesize, extrabytes, x, y, t, ptr; + size_t bytesize, extrabytes, ptr; uchar *data; FILE *ofile; @@ -331,15 +335,15 @@ int imb_savebmp(struct ImBuf *ibuf, const char *name, int flags) putIntLSB(0, ofile); /* Need to write out padded image data in bgr format */ - for (y = 0; y < ibuf->y; y++) { - for (x = 0; x < ibuf->x; x++) { + for (size_t y = 0; y < ibuf->y; y++) { + for (size_t x = 0; x < ibuf->x; x++) { ptr = (x + y * ibuf->x) * 4; if (putc(data[ptr + 2], ofile) == EOF) return 0; if (putc(data[ptr + 1], ofile) == EOF) return 0; if (putc(data[ptr], ofile) == EOF) return 0; } /* add padding here */ - for (t = 0; t < extrabytes; t++) { + for (size_t t = 0; t < extrabytes; t++) { if (putc(0, ofile) == EOF) return 0; } } diff --git a/source/blender/imbuf/intern/cineon/cineon_dpx.c b/source/blender/imbuf/intern/cineon/cineon_dpx.c index 3e2206dc013..1d2ebf88a32 100644 --- a/source/blender/imbuf/intern/cineon/cineon_dpx.c +++ b/source/blender/imbuf/intern/cineon/cineon_dpx.c @@ -59,7 +59,7 @@ static struct ImBuf *imb_load_dpx_cineon( colorspace_set_default_role(colorspace, IM_MAX_SPACE, COLOR_ROLE_DEFAULT_FLOAT); - logImageSetVerbose((G.f & G_DEBUG) ? 1 : 0); + logImageSetVerbose((G.debug & G_DEBUG) ? 1 : 0); image = logImageOpenFromMemory(mem, size); @@ -107,7 +107,7 @@ static int imb_save_dpx_cineon(ImBuf *ibuf, const char *filename, int use_cineon return 0; } - logImageSetVerbose((G.f & G_DEBUG) ? 1 : 0); + logImageSetVerbose((G.debug & G_DEBUG) ? 1 : 0); depth = (ibuf->planes + 7) >> 3; if (depth > 4 || depth < 3) { diff --git a/source/blender/imbuf/intern/cineon/cineonlib.c b/source/blender/imbuf/intern/cineon/cineonlib.c index fbce508af17..50d0e843890 100644 --- a/source/blender/imbuf/intern/cineon/cineonlib.c +++ b/source/blender/imbuf/intern/cineon/cineonlib.c @@ -318,6 +318,7 @@ LogImageFile *cineonOpen(const unsigned char *byteStuff, int fromMemory, size_t printf("Gamma: %f\n", cineon->gamma); printf("Reference black: %f\n", cineon->referenceBlack); printf("Reference white: %f\n", cineon->referenceWhite); + printf("Orientation: %d\n", header.imageHeader.orientation); printf("----------------------------\n"); } return cineon; diff --git a/source/blender/imbuf/intern/cineon/dpxlib.c b/source/blender/imbuf/intern/cineon/dpxlib.c index 429a19936a5..d29518fc5bc 100644 --- a/source/blender/imbuf/intern/cineon/dpxlib.c +++ b/source/blender/imbuf/intern/cineon/dpxlib.c @@ -193,7 +193,8 @@ LogImageFile *dpxOpen(const unsigned char *byteStuff, int fromMemory, size_t buf dpx->srcFormat = format_DPX; dpx->numElements = swap_ushort(header.imageHeader.elements_per_image, dpx->isMSB); - if (dpx->numElements == 0) { + size_t max_elements = sizeof(header.imageHeader.element) / sizeof(header.imageHeader.element[0]); + if (dpx->numElements == 0 || dpx->numElements >= max_elements) { if (verbose) printf("DPX: Wrong number of elements: %d\n", dpx->numElements); logImageClose(dpx); return NULL; @@ -377,6 +378,7 @@ LogImageFile *dpxOpen(const unsigned char *byteStuff, int fromMemory, size_t buf printf("Gamma: %f\n", dpx->gamma); printf("Reference black: %f\n", dpx->referenceBlack); printf("Reference white: %f\n", dpx->referenceWhite); + printf("Orientation: %d\n", header.imageHeader.orientation); printf("----------------------------\n"); } return dpx; diff --git a/source/blender/imbuf/intern/cineon/logImageCore.c b/source/blender/imbuf/intern/cineon/logImageCore.c index 600642f5e44..bb72f675cb8 100644 --- a/source/blender/imbuf/intern/cineon/logImageCore.c +++ b/source/blender/imbuf/intern/cineon/logImageCore.c @@ -38,6 +38,8 @@ #include "BLI_fileops.h" #include "BLI_utildefines.h" +#include "IMB_imbuf.h" + #include "MEM_guardedalloc.h" /* @@ -162,7 +164,7 @@ void logImageGetSize(LogImageFile *logImage, int *width, int *height, int *depth * Helper */ -unsigned int getRowLength(int width, LogImageElement logElement) +size_t getRowLength(size_t width, LogImageElement logElement) { /* return the row length in bytes according to width and packing method */ switch (logElement.bitsPerSample) { @@ -201,7 +203,7 @@ int logImageSetDataRGBA(LogImageFile *logImage, float *data, int dataIsLinearRGB float *elementData; int returnValue; - elementData = (float *)MEM_mallocN(logImage->width * logImage->height * logImage->depth * sizeof(float), __func__); + elementData = (float *)imb_alloc_pixels(logImage->width, logImage->height, logImage->depth, sizeof(float), __func__); if (elementData == NULL) return 1; @@ -238,9 +240,8 @@ int logImageSetDataRGBA(LogImageFile *logImage, float *data, int dataIsLinearRGB static int logImageSetData8(LogImageFile *logImage, LogImageElement logElement, float *data) { - unsigned int rowLength = getRowLength(logImage->width, logElement); + size_t rowLength = getRowLength(logImage->width, logElement); unsigned char *row; - int x, y; row = (unsigned char *)MEM_mallocN(rowLength, __func__); if (row == NULL) { @@ -249,8 +250,8 @@ static int logImageSetData8(LogImageFile *logImage, LogImageElement logElement, } memset(row, 0, rowLength); - for (y = 0; y < logImage->height; y++) { - for (x = 0; x < logImage->width * logImage->depth; x++) + for (size_t y = 0; y < logImage->height; y++) { + for (size_t x = 0; x < logImage->width * logImage->depth; x++) row[x] = (unsigned char)float_uint(data[y * logImage->width * logImage->depth + x], 255); if (logimage_fwrite(row, rowLength, 1, logImage) == 0) { @@ -265,10 +266,9 @@ static int logImageSetData8(LogImageFile *logImage, LogImageElement logElement, static int logImageSetData10(LogImageFile *logImage, LogImageElement logElement, float *data) { - unsigned int rowLength = getRowLength(logImage->width, logElement); + size_t rowLength = getRowLength(logImage->width, logElement); unsigned int pixel, index; unsigned int *row; - int x, y, offset; row = (unsigned int *)MEM_mallocN(rowLength, __func__); if (row == NULL) { @@ -276,12 +276,12 @@ static int logImageSetData10(LogImageFile *logImage, LogImageElement logElement, return 1; } - for (y = 0; y < logImage->height; y++) { - offset = 22; + for (size_t y = 0; y < logImage->height; y++) { + int offset = 22; index = 0; pixel = 0; - for (x = 0; x < logImage->width * logImage->depth; x++) { + for (size_t x = 0; x < logImage->width * logImage->depth; x++) { pixel |= (unsigned int)float_uint(data[y * logImage->width * logImage->depth + x], 1023) << offset; offset -= 10; if (offset < 0) { @@ -308,9 +308,8 @@ static int logImageSetData10(LogImageFile *logImage, LogImageElement logElement, static int logImageSetData12(LogImageFile *logImage, LogImageElement logElement, float *data) { - unsigned int rowLength = getRowLength(logImage->width, logElement); + size_t rowLength = getRowLength(logImage->width, logElement); unsigned short *row; - int x, y; row = (unsigned short *)MEM_mallocN(rowLength, __func__); if (row == NULL) { @@ -318,8 +317,8 @@ static int logImageSetData12(LogImageFile *logImage, LogImageElement logElement, return 1; } - for (y = 0; y < logImage->height; y++) { - for (x = 0; x < logImage->width * logImage->depth; x++) + for (size_t y = 0; y < logImage->height; y++) { + for (size_t x = 0; x < logImage->width * logImage->depth; x++) row[x] = swap_ushort(((unsigned short)float_uint(data[y * logImage->width * logImage->depth + x], 4095)) << 4, logImage->isMSB); if (logimage_fwrite(row, rowLength, 1, logImage) == 0) { @@ -334,9 +333,8 @@ static int logImageSetData12(LogImageFile *logImage, LogImageElement logElement, static int logImageSetData16(LogImageFile *logImage, LogImageElement logElement, float *data) { - unsigned int rowLength = getRowLength(logImage->width, logElement); + size_t rowLength = getRowLength(logImage->width, logElement); unsigned short *row; - int x, y; row = (unsigned short *)MEM_mallocN(rowLength, __func__); if (row == NULL) { @@ -344,8 +342,8 @@ static int logImageSetData16(LogImageFile *logImage, LogImageElement logElement, return 1; } - for (y = 0; y < logImage->height; y++) { - for (x = 0; x < logImage->width * logImage->depth; x++) + for (size_t y = 0; y < logImage->height; y++) { + for (size_t x = 0; x < logImage->width * logImage->depth; x++) row[x] = swap_ushort((unsigned short)float_uint(data[y * logImage->width * logImage->depth + x], 65535), logImage->isMSB); if (logimage_fwrite(row, rowLength, 1, logImage) == 0) { @@ -382,7 +380,7 @@ int logImageGetDataRGBA(LogImageFile *logImage, float *data, int dataIsLinearRGB /* descriptor_Depth and descriptor_Composite are not supported */ if (logImage->element[i].descriptor != descriptor_Depth && logImage->element[i].descriptor != descriptor_Composite) { /* Allocate memory */ - elementData[i] = (float *)MEM_mallocN(logImage->width * logImage->height * logImage->element[i].depth * sizeof(float), __func__); + elementData[i] = imb_alloc_pixels(logImage->width, logImage->height, logImage->element[i].depth, sizeof(float), __func__); if (elementData[i] == NULL) { if (verbose) printf("DPX/Cineon: Cannot allocate memory for elementData[%d]\n.", i); for (j = 0; j < i; j++) @@ -530,7 +528,7 @@ int logImageGetDataRGBA(LogImageFile *logImage, float *data, int dataIsLinearRGB } } - mergedData = (float *)MEM_mallocN(logImage->width * logImage->height * mergedElement.depth * sizeof(float), __func__); + mergedData = (float *)imb_alloc_pixels(logImage->width, logImage->height, mergedElement.depth, sizeof(float), __func__); if (mergedData == NULL) { if (verbose) printf("DPX/Cineon: Cannot allocate mergedData.\n"); for (i = 0; i < logImage->numElements; i++) @@ -590,7 +588,6 @@ static int logImageElementGetData(LogImageFile *logImage, LogImageElement logEle static int logImageElementGetData1(LogImageFile *logImage, LogImageElement logElement, float *data) { unsigned int pixel; - int x, y, offset; /* seek at the right place */ if (logimage_fseek(logImage, logElement.dataOffset, SEEK_SET) != 0) { @@ -599,14 +596,14 @@ static int logImageElementGetData1(LogImageFile *logImage, LogImageElement logEl } /* read 1 bit data padded to 32 bits */ - for (y = 0; y < logImage->height; y++) { - for (x = 0; x < logImage->width * logElement.depth; x += 32) { + for (size_t y = 0; y < logImage->height; y++) { + for (size_t x = 0; x < logImage->width * logElement.depth; x += 32) { if (logimage_read_uint(&pixel, logImage) != 0) { if (verbose) printf("DPX/Cineon: EOF reached\n"); return 1; } pixel = swap_uint(pixel, logImage->isMSB); - for (offset = 0; offset < 32 && x + offset < logImage->width; offset++) + for (int offset = 0; offset < 32 && x + offset < logImage->width; offset++) data[y * logImage->width * logElement.depth + x + offset] = (float)((pixel >> offset) & 0x01); } } @@ -615,19 +612,18 @@ static int logImageElementGetData1(LogImageFile *logImage, LogImageElement logEl static int logImageElementGetData8(LogImageFile *logImage, LogImageElement logElement, float *data) { - unsigned int rowLength = getRowLength(logImage->width, logElement); + size_t rowLength = getRowLength(logImage->width, logElement); unsigned char pixel; - int x, y; /* extract required pixels */ - for (y = 0; y < logImage->height; y++) { + for (size_t y = 0; y < logImage->height; y++) { /* 8 bits are 32-bits padded so we need to seek at each row */ if (logimage_fseek(logImage, logElement.dataOffset + y * rowLength, SEEK_SET) != 0) { - if (verbose) printf("DPX/Cineon: Couldn't seek at %d\n", logElement.dataOffset + y * (int)rowLength); + if (verbose) printf("DPX/Cineon: Couldn't seek at %d\n", (int)(logElement.dataOffset + y * rowLength)); return 1; } - for (x = 0; x < logImage->width * logElement.depth; x++) { + for (size_t x = 0; x < logImage->width * logElement.depth; x++) { if (logimage_read_uchar(&pixel, logImage) != 0) { if (verbose) printf("DPX/Cineon: EOF reached\n"); return 1; @@ -641,7 +637,6 @@ static int logImageElementGetData8(LogImageFile *logImage, LogImageElement logEl static int logImageElementGetData10(LogImageFile *logImage, LogImageElement logElement, float *data) { unsigned int pixel; - int x, y, offset; /* seek to data */ if (logimage_fseek(logImage, logElement.dataOffset, SEEK_SET) != 0) { @@ -650,9 +645,9 @@ static int logImageElementGetData10(LogImageFile *logImage, LogImageElement logE } if (logImage->depth == 1 && logImage->srcFormat == format_DPX) { - for (y = 0; y < logImage->height; y++) { - offset = 32; - for (x = 0; x < logImage->width * logElement.depth; x++) { + for (size_t y = 0; y < logImage->height; y++) { + int offset = 32; + for (size_t x = 0; x < logImage->width * logElement.depth; x++) { /* we need to read the next long */ if (offset >= 30) { if (logElement.packing == 1) @@ -672,9 +667,9 @@ static int logImageElementGetData10(LogImageFile *logImage, LogImageElement logE } } else { - for (y = 0; y < logImage->height; y++) { - offset = -1; - for (x = 0; x < logImage->width * logElement.depth; x++) { + for (size_t y = 0; y < logImage->height; y++) { + int offset = -1; + for (size_t x = 0; x < logImage->width * logElement.depth; x++) { /* we need to read the next long */ if (offset < 0) { if (logElement.packing == 1) @@ -699,23 +694,22 @@ static int logImageElementGetData10(LogImageFile *logImage, LogImageElement logE static int logImageElementGetData10Packed(LogImageFile *logImage, LogImageElement logElement, float *data) { - unsigned int rowLength = getRowLength(logImage->width, logElement); + size_t rowLength = getRowLength(logImage->width, logElement); unsigned int pixel, oldPixel; - int offset, offset2, x, y; /* converting bytes to pixels */ - for (y = 0; y < logImage->height; y++) { + for (size_t y = 0; y < logImage->height; y++) { /* seek to data */ if (logimage_fseek(logImage, y * rowLength + logElement.dataOffset, SEEK_SET) != 0) { - if (verbose) printf("DPX/Cineon: Couldn't seek at %u\n", y * rowLength + logElement.dataOffset); + if (verbose) printf("DPX/Cineon: Couldn't seek at %u\n", (unsigned int)(y * rowLength + logElement.dataOffset)); return 1; } oldPixel = 0; - offset = 0; - offset2 = 0; + int offset = 0; + int offset2 = 0; - for (x = 0; x < logImage->width * logElement.depth; x++) { + for (size_t x = 0; x < logImage->width * logElement.depth; x++) { if (offset2 != 0) { offset = 10 - offset2; offset2 = 0; @@ -778,23 +772,22 @@ static int logImageElementGetData12(LogImageFile *logImage, LogImageElement logE static int logImageElementGetData12Packed(LogImageFile *logImage, LogImageElement logElement, float *data) { - unsigned int rowLength = getRowLength(logImage->width, logElement); + size_t rowLength = getRowLength(logImage->width, logElement); unsigned int pixel, oldPixel; - int offset, offset2, x, y; /* converting bytes to pixels */ - for (y = 0; y < logImage->height; y++) { + for (size_t y = 0; y < logImage->height; y++) { /* seek to data */ if (logimage_fseek(logImage, y * rowLength + logElement.dataOffset, SEEK_SET) != 0) { - if (verbose) printf("DPX/Cineon: Couldn't seek at %u\n", y * rowLength + logElement.dataOffset); + if (verbose) printf("DPX/Cineon: Couldn't seek at %u\n", (unsigned int)(y * rowLength + logElement.dataOffset)); return 1; } oldPixel = 0; - offset = 0; - offset2 = 0; + int offset = 0; + int offset2 = 0; - for (x = 0; x < logImage->width * logElement.depth; x++) { + for (size_t x = 0; x < logImage->width * logElement.depth; x++) { if (offset2 != 0) { offset = 12 - offset2; offset2 = 0; @@ -1020,6 +1013,7 @@ static int convertRGBA_RGB(float *src, float *dst, LogImageFile *logImage, float *dst_ptr = dst; switch (logElement.transfer) { + case transfer_Unspecified: case transfer_UserDefined: case transfer_Linear: case transfer_Logarithmic: { @@ -1054,6 +1048,7 @@ static int convertRGBA_RGB(float *src, float *dst, LogImageFile *logImage, } default: + if (verbose) printf("DPX/Cineon: Unknown transfer %d.\n", logElement.transfer); return 1; } } @@ -1066,6 +1061,7 @@ static int convertRGB_RGBA(float *src, float *dst, LogImageFile *logImage, float *dst_ptr = dst; switch (logElement.transfer) { + case transfer_Unspecified: case transfer_UserDefined: case transfer_Linear: case transfer_Logarithmic: { @@ -1100,6 +1096,7 @@ static int convertRGB_RGBA(float *src, float *dst, LogImageFile *logImage, } default: + if (verbose) printf("DPX/Cineon: Unknown transfer %d.\n", logElement.transfer); return 1; } } @@ -1115,7 +1112,7 @@ static int convertRGBA_RGBA(float *src, float *dst, LogImageFile *logImage, case transfer_UserDefined: case transfer_Linear: case transfer_Logarithmic: { - memcpy(dst, src, 4 * logImage->width * logImage->height * sizeof(float)); + memcpy(dst, src, 4 * (size_t)logImage->width * (size_t)logImage->height * sizeof(float)); return 0; } @@ -1430,11 +1427,11 @@ static int convertRGBAToLogElement(float *src, float *dst, LogImageFile *logImag if (srcIsLinearRGB != 0) { /* we need to convert src to sRGB */ - srgbSrc = (float *)MEM_mallocN(4 * logImage->width * logImage->height * sizeof(float), __func__); + srgbSrc = (float *)imb_alloc_pixels(logImage->width, logImage->height, 4, sizeof(float), __func__); if (srgbSrc == NULL) return 1; - memcpy(srgbSrc, src, 4 * logImage->width * logImage->height * sizeof(float)); + memcpy(srgbSrc, src, 4 * (size_t)logImage->width * (size_t)logImage->height * sizeof(float)); srgbSrc_ptr = srgbSrc; /* convert data from Linear RGB to sRGB via lut */ diff --git a/source/blender/imbuf/intern/cineon/logImageCore.h b/source/blender/imbuf/intern/cineon/logImageCore.h index e39df1ea096..b6f4fff73f6 100644 --- a/source/blender/imbuf/intern/cineon/logImageCore.h +++ b/source/blender/imbuf/intern/cineon/logImageCore.h @@ -196,7 +196,7 @@ LogImageFile *logImageCreate(const char *filename, int cineon, int width, int he void logImageClose(LogImageFile *logImage); /* Data handling */ -unsigned int getRowLength(int width, LogImageElement logElement); +size_t getRowLength(size_t width, LogImageElement logElement); int logImageSetDataRGBA(LogImageFile *logImage, float *data, int dataIsLinearRGB); int logImageGetDataRGBA(LogImageFile *logImage, float *data, int dataIsLinearRGB); diff --git a/source/blender/imbuf/intern/iris.c b/source/blender/imbuf/intern/iris.c index 6c0849358a5..55727ed6697 100644 --- a/source/blender/imbuf/intern/iris.c +++ b/source/blender/imbuf/intern/iris.c @@ -260,9 +260,8 @@ struct ImBuf *imb_loadiris(const uchar *mem, size_t size, int flags, char colors const uchar *mem_end = mem + size; MFileOffset _inf_data = {mem, 0}, *inf = &_inf_data; IMAGE image; - int x, y, z, tablen; int bpp, rle, cur, badorder; - ImBuf *ibuf; + ImBuf *ibuf = NULL; uchar dirty_flag = 0; if (size < HEADER_SIZE) { @@ -304,7 +303,7 @@ struct ImBuf *imb_loadiris(const uchar *mem, size_t size, int flags, char colors } if (rle) { - tablen = ysize * zsize * sizeof(int); + size_t tablen = (size_t)ysize * (size_t)zsize * sizeof(int); MFILE_SEEK(inf, HEADER_SIZE); uint *starttab = MEM_mallocN(tablen, "iris starttab"); @@ -321,8 +320,8 @@ struct ImBuf *imb_loadiris(const uchar *mem, size_t size, int flags, char colors /* check data order */ cur = 0; badorder = 0; - for (y = 0; y < ysize; y++) { - for (z = 0; z < zsize; z++) { + for (size_t y = 0; y < ysize; y++) { + for (size_t z = 0; z < zsize; z++) { if (starttab[y + z * ysize] < cur) { badorder = 1; break; @@ -336,14 +335,17 @@ struct ImBuf *imb_loadiris(const uchar *mem, size_t size, int flags, char colors if (bpp == 1) { ibuf = IMB_allocImBuf(xsize, ysize, 8 * zsize, IB_rect); + if (!ibuf) { + goto fail_rle; + } if (ibuf->planes > 32) ibuf->planes = 32; base = ibuf->rect; zbase = (uint *)ibuf->zbuf; if (badorder) { - for (z = 0; z < zsize; z++) { + for (size_t z = 0; z < zsize; z++) { lptr = base; - for (y = 0; y < ysize; y++) { + for (size_t y = 0; y < ysize; y++) { MFILE_SEEK(inf, starttab[y + z * ysize]); rledat = MFILE_DATA(inf); MFILE_STEP(inf, lengthtab[y + z * ysize]); @@ -358,12 +360,12 @@ struct ImBuf *imb_loadiris(const uchar *mem, size_t size, int flags, char colors else { lptr = base; zptr = zbase; - for (y = 0; y < ysize; y++) { + for (size_t y = 0; y < ysize; y++) { uint *lptr_next = lptr + xsize; uint *zptr_next = zptr + xsize; - for (z = 0; z < zsize; z++) { + for (size_t z = 0; z < zsize; z++) { MFILE_SEEK(inf, starttab[y + z * ysize]); rledat = MFILE_DATA(inf); MFILE_STEP(inf, lengthtab[y + z * ysize]); @@ -386,13 +388,16 @@ struct ImBuf *imb_loadiris(const uchar *mem, size_t size, int flags, char colors else { /* bpp == 2 */ ibuf = IMB_allocImBuf(xsize, ysize, 32, (flags & IB_rect) | IB_rectfloat); - + if (!ibuf) { + goto fail_rle; + } + fbase = ibuf->rect_float; if (badorder) { - for (z = 0; z < zsize; z++) { + for (size_t z = 0; z < zsize; z++) { fptr = fbase; - for (y = 0; y < ysize; y++) { + for (size_t y = 0; y < ysize; y++) { MFILE_SEEK(inf, starttab[y + z * ysize]); rledat = MFILE_DATA(inf); MFILE_STEP(inf, lengthtab[y + z * ysize]); @@ -408,9 +413,9 @@ struct ImBuf *imb_loadiris(const uchar *mem, size_t size, int flags, char colors fptr = fbase; float *fptr_next = fptr + (xsize * 4); - for (y = 0; y < ysize; y++) { + for (size_t y = 0; y < ysize; y++) { - for (z = 0; z < zsize; z++) { + for (size_t z = 0; z < zsize; z++) { MFILE_SEEK(inf, starttab[y + z * ysize]); rledat = MFILE_DATA(inf); MFILE_STEP(inf, lengthtab[y + z * ysize]); @@ -426,6 +431,10 @@ struct ImBuf *imb_loadiris(const uchar *mem, size_t size, int flags, char colors fail_rle: MEM_freeN(starttab); MEM_freeN(lengthtab); + + if (!ibuf) { + return NULL; + } } else { @@ -435,6 +444,9 @@ fail_rle: if (bpp == 1) { ibuf = IMB_allocImBuf(xsize, ysize, 8 * zsize, IB_rect); + if (!ibuf) { + goto fail_uncompressed; + } if (ibuf->planes > 32) ibuf->planes = 32; base = ibuf->rect; @@ -443,12 +455,12 @@ fail_rle: MFILE_SEEK(inf, HEADER_SIZE); rledat = MFILE_DATA(inf); - for (z = 0; z < zsize; z++) { + for (size_t z = 0; z < zsize; z++) { if (z < 4) lptr = base; else if (z < 8) lptr = zbase; - for (y = 0; y < ysize; y++) { + for (size_t y = 0; y < ysize; y++) { const uchar *rledat_next = rledat + xsize; const int z_ofs = 3 - z; MFILE_CAPACITY_AT_PTR_OK_OR_FAIL(rledat_next + z_ofs); @@ -462,17 +474,20 @@ fail_rle: else { /* bpp == 2 */ ibuf = IMB_allocImBuf(xsize, ysize, 32, (flags & IB_rect) | IB_rectfloat); + if (!ibuf) { + goto fail_uncompressed; + } fbase = ibuf->rect_float; MFILE_SEEK(inf, HEADER_SIZE); rledat = MFILE_DATA(inf); - for (z = 0; z < zsize; z++) { + for (size_t z = 0; z < zsize; z++) { fptr = fbase; - for (y = 0; y < ysize; y++) { + for (size_t y = 0; y < ysize; y++) { const uchar *rledat_next = rledat + xsize * 2; const int z_ofs = 3 - z; MFILE_CAPACITY_AT_PTR_OK_OR_FAIL(rledat_next + z_ofs); @@ -485,7 +500,9 @@ fail_rle: } #undef MFILE_CAPACITY_AT_PTR_OK_OR_FAIL fail_uncompressed: - (void)0; + if (!ibuf) { + return NULL; + } } if (bpp == 1) { @@ -493,7 +510,7 @@ fail_uncompressed: if (image.zsize == 1) { rect = (uchar *) ibuf->rect; - for (x = ibuf->x * ibuf->y; x > 0; x--) { + for (size_t x = (size_t)ibuf->x * (size_t)ibuf->y; x > 0; x--) { rect[0] = 255; rect[1] = rect[2] = rect[3]; rect += 4; @@ -502,7 +519,7 @@ fail_uncompressed: else if (image.zsize == 2) { /* grayscale with alpha */ rect = (uchar *) ibuf->rect; - for (x = ibuf->x * ibuf->y; x > 0; x--) { + for (size_t x = (size_t)ibuf->x * (size_t)ibuf->y; x > 0; x--) { rect[0] = rect[2]; rect[1] = rect[2] = rect[3]; rect += 4; @@ -511,7 +528,7 @@ fail_uncompressed: else if (image.zsize == 3) { /* add alpha */ rect = (uchar *) ibuf->rect; - for (x = ibuf->x * ibuf->y; x > 0; x--) { + for (size_t x = (size_t)ibuf->x * (size_t)ibuf->y; x > 0; x--) { rect[0] = 255; rect += 4; } @@ -522,7 +539,7 @@ fail_uncompressed: if (image.zsize == 1) { fbase = ibuf->rect_float; - for (x = ibuf->x * ibuf->y; x > 0; x--) { + for (size_t x = (size_t)ibuf->x * (size_t)ibuf->y; x > 0; x--) { fbase[0] = 1; fbase[1] = fbase[2] = fbase[3]; fbase += 4; @@ -531,7 +548,7 @@ fail_uncompressed: else if (image.zsize == 2) { /* grayscale with alpha */ fbase = ibuf->rect_float; - for (x = ibuf->x * ibuf->y; x > 0; x--) { + for (size_t x = (size_t)ibuf->x * (size_t)ibuf->y; x > 0; x--) { fbase[0] = fbase[2]; fbase[1] = fbase[2] = fbase[3]; fbase += 4; @@ -540,7 +557,7 @@ fail_uncompressed: else if (image.zsize == 3) { /* add alpha */ fbase = ibuf->rect_float; - for (x = ibuf->x * ibuf->y; x > 0; x--) { + for (size_t x = (size_t)ibuf->x * (size_t)ibuf->y; x > 0; x--) { fbase[0] = 1; fbase += 4; } diff --git a/source/blender/imbuf/intern/openexr/openexr_api.cpp b/source/blender/imbuf/intern/openexr/openexr_api.cpp index ca534e3e2a8..539b9fa45b4 100644 --- a/source/blender/imbuf/intern/openexr/openexr_api.cpp +++ b/source/blender/imbuf/intern/openexr/openexr_api.cpp @@ -1028,13 +1028,13 @@ void IMB_exr_write_channels(void *handle) for (size_t i = 0; i < num_pixels; ++i, ++cur) { *cur = rect[i * echan->xstride]; } - half *rect_to_write = current_rect_half + (data->height - 1) * data->width; + half *rect_to_write = current_rect_half + (data->height - 1L) * data->width; frameBuffer.insert(echan->name, Slice(Imf::HALF, (char *)rect_to_write, sizeof(half), -data->width * sizeof(half))); current_rect_half += num_pixels; } else { - float *rect = echan->rect + echan->xstride * (data->height - 1) * data->width; + float *rect = echan->rect + echan->xstride * (data->height - 1L) * data->width; frameBuffer.insert(echan->name, Slice(Imf::FLOAT, (char *)rect, echan->xstride * sizeof(float), -echan->ystride * sizeof(float))); } @@ -1059,11 +1059,11 @@ void IMB_exr_write_channels(void *handle) /* temporary function, used for FSA and Save Buffers */ /* called once per tile * view */ -void IMB_exrtile_write_channels(void *handle, int partx, int party, int level, const char *viewname) +void IMB_exrtile_write_channels(void *handle, int partx, int party, int level, const char *viewname, bool empty) { + /* Can write empty channels for incomplete renders. */ ExrHandle *data = (ExrHandle *)handle; FrameBuffer frameBuffer; - ExrChannel *echan; std::string view(viewname); const int view_id = imb_exr_get_multiView_id(*data->multiView, view); @@ -1071,28 +1071,32 @@ void IMB_exrtile_write_channels(void *handle, int partx, int party, int level, c exr_printf("%s %-6s %-22s \"%s\"\n", "p", "view", "name", "internal_name"); exr_printf("---------------------------------------------------------------------\n"); - for (echan = (ExrChannel *)data->channels.first; echan; echan = echan->next) { + if (!empty) { + ExrChannel *echan; + + for (echan = (ExrChannel *)data->channels.first; echan; echan = echan->next) { + + /* eventually we can make the parts' channels to include + only the current view TODO */ + if (strcmp(viewname, echan->m->view.c_str()) != 0) + continue; - /* eventually we can make the parts' channels to include - only the current view TODO */ - if (strcmp(viewname, echan->m->view.c_str()) != 0) - continue; - - exr_printf("%d %-6s %-22s \"%s\"\n", - echan->m->part_number, - echan->m->view.c_str(), - echan->m->name.c_str(), - echan->m->internal_name.c_str() - ); - - float *rect = echan->rect - echan->xstride * partx - echan->ystride * party; - frameBuffer.insert(echan->m->internal_name, - Slice(Imf::FLOAT, - (char *)rect, - echan->xstride * sizeof(float), - echan->ystride * sizeof(float) - ) - ); + exr_printf("%d %-6s %-22s \"%s\"\n", + echan->m->part_number, + echan->m->view.c_str(), + echan->m->name.c_str(), + echan->m->internal_name.c_str() + ); + + float *rect = echan->rect - echan->xstride * partx - echan->ystride * party; + frameBuffer.insert(echan->m->internal_name, + Slice(Imf::FLOAT, + (char *)rect, + echan->xstride * sizeof(float), + echan->ystride * sizeof(float) + ) + ); + } } TiledOutputPart out (*data->mpofile, view_id); diff --git a/source/blender/imbuf/intern/openexr/openexr_multi.h b/source/blender/imbuf/intern/openexr/openexr_multi.h index d9517d13cc4..d9338c888a7 100644 --- a/source/blender/imbuf/intern/openexr/openexr_multi.h +++ b/source/blender/imbuf/intern/openexr/openexr_multi.h @@ -67,7 +67,7 @@ float *IMB_exr_channel_rect(void *handle, const char *layname, const char *pass void IMB_exr_read_channels(void *handle); void IMB_exr_write_channels(void *handle); -void IMB_exrtile_write_channels(void *handle, int partx, int party, int level, const char *viewname); +void IMB_exrtile_write_channels(void *handle, int partx, int party, int level, const char *viewname, bool empty); void IMB_exr_clear_channels(void *handle); void IMB_exr_multilayer_convert( diff --git a/source/blender/imbuf/intern/openexr/openexr_stub.cpp b/source/blender/imbuf/intern/openexr/openexr_stub.cpp index 05fddcb5fa5..301e827d739 100644 --- a/source/blender/imbuf/intern/openexr/openexr_stub.cpp +++ b/source/blender/imbuf/intern/openexr/openexr_stub.cpp @@ -47,7 +47,7 @@ float *IMB_exr_channel_rect (void * /*handle*/, const char * /*layname*/ void IMB_exr_read_channels (void * /*handle*/) { } void IMB_exr_write_channels (void * /*handle*/) { } -void IMB_exrtile_write_channels (void * /*handle*/, int /*partx*/, int /*party*/, int /*level*/, const char * /*viewname*/) { } +void IMB_exrtile_write_channels (void * /*handle*/, int /*partx*/, int /*party*/, int /*level*/, const char * /*viewname*/, bool /*empty*/) { } void IMB_exr_clear_channels (void * /*handle*/) { } void IMB_exr_multilayer_convert( diff --git a/source/blender/imbuf/intern/png.c b/source/blender/imbuf/intern/png.c index dded0f7aecf..857f72e10eb 100644 --- a/source/blender/imbuf/intern/png.c +++ b/source/blender/imbuf/intern/png.c @@ -526,7 +526,7 @@ ImBuf *imb_loadpng(const unsigned char *mem, size_t size, int flags, char colors unsigned char *from, *to; unsigned short *from16; float *to_float; - int i, bytesperpixel; + unsigned int channels; if (imb_is_a_png(mem) == 0) return(NULL); @@ -571,7 +571,7 @@ ImBuf *imb_loadpng(const unsigned char *mem, size_t size, int flags, char colors png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL); - bytesperpixel = png_get_channels(png_ptr, info_ptr); + channels = png_get_channels(png_ptr, info_ptr); switch (color_type) { case PNG_COLOR_TYPE_RGB: @@ -580,10 +580,10 @@ ImBuf *imb_loadpng(const unsigned char *mem, size_t size, int flags, char colors case PNG_COLOR_TYPE_PALETTE: png_set_palette_to_rgb(png_ptr); if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { - bytesperpixel = 4; + channels = 4; } else { - bytesperpixel = 3; + channels = 3; } break; case PNG_COLOR_TYPE_GRAY: @@ -593,7 +593,7 @@ ImBuf *imb_loadpng(const unsigned char *mem, size_t size, int flags, char colors bit_depth = 8; if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { /* PNG_COLOR_TYPE_GRAY may also have alpha 'values', like with palette. */ - bytesperpixel = 2; + channels = 2; } } break; @@ -602,7 +602,7 @@ ImBuf *imb_loadpng(const unsigned char *mem, size_t size, int flags, char colors longjmp(png_jmpbuf(png_ptr), 1); } - ibuf = IMB_allocImBuf(width, height, 8 * bytesperpixel, 0); + ibuf = IMB_allocImBuf(width, height, 8 * channels, 0); if (ibuf) { ibuf->ftype = IMB_FTYPE_PNG; @@ -630,23 +630,23 @@ ImBuf *imb_loadpng(const unsigned char *mem, size_t size, int flags, char colors imb_addrectfloatImBuf(ibuf); png_set_swap(png_ptr); - pixels16 = MEM_mallocN(ibuf->x * ibuf->y * bytesperpixel * sizeof(png_uint_16), "pixels"); - if (pixels16 == NULL) { + pixels16 = imb_alloc_pixels(ibuf->x, ibuf->y, channels, sizeof(png_uint_16), "pixels"); + if (pixels16 == NULL || ibuf->rect_float == NULL) { printf("Cannot allocate pixels array\n"); longjmp(png_jmpbuf(png_ptr), 1); } /* allocate memory for an array of row-pointers */ - row_pointers = (png_bytepp) MEM_mallocN(ibuf->y * sizeof(png_uint_16p), "row_pointers"); + row_pointers = (png_bytepp) MEM_mallocN((size_t)ibuf->y * sizeof(png_uint_16p), "row_pointers"); if (row_pointers == NULL) { printf("Cannot allocate row-pointers array\n"); longjmp(png_jmpbuf(png_ptr), 1); } /* set the individual row-pointers to point at the correct offsets */ - for (i = 0; i < ibuf->y; i++) { + for (size_t i = 0; i < ibuf->y; i++) { row_pointers[ibuf->y - 1 - i] = (png_bytep) - ((png_uint_16 *)pixels16 + (i * ibuf->x) * bytesperpixel); + ((png_uint_16 *)pixels16 + (i * ibuf->x) * channels); } png_read_image(png_ptr, row_pointers); @@ -656,9 +656,9 @@ ImBuf *imb_loadpng(const unsigned char *mem, size_t size, int flags, char colors to_float = ibuf->rect_float; from16 = pixels16; - switch (bytesperpixel) { + switch (channels) { case 4: - for (i = ibuf->x * ibuf->y; i > 0; i--) { + for (size_t i = (size_t)ibuf->x * (size_t)ibuf->y; i > 0; i--) { to_float[0] = from16[0] / 65535.0; to_float[1] = from16[1] / 65535.0; to_float[2] = from16[2] / 65535.0; @@ -667,7 +667,7 @@ ImBuf *imb_loadpng(const unsigned char *mem, size_t size, int flags, char colors } break; case 3: - for (i = ibuf->x * ibuf->y; i > 0; i--) { + for (size_t i = (size_t)ibuf->x * (size_t)ibuf->y; i > 0; i--) { to_float[0] = from16[0] / 65535.0; to_float[1] = from16[1] / 65535.0; to_float[2] = from16[2] / 65535.0; @@ -676,14 +676,14 @@ ImBuf *imb_loadpng(const unsigned char *mem, size_t size, int flags, char colors } break; case 2: - for (i = ibuf->x * ibuf->y; i > 0; i--) { + for (size_t i = (size_t)ibuf->x * (size_t)ibuf->y; i > 0; i--) { to_float[0] = to_float[1] = to_float[2] = from16[0] / 65535.0; to_float[3] = from16[1] / 65535.0; to_float += 4; from16 += 2; } break; case 1: - for (i = ibuf->x * ibuf->y; i > 0; i--) { + for (size_t i = (size_t)ibuf->x * (size_t)ibuf->y; i > 0; i--) { to_float[0] = to_float[1] = to_float[2] = from16[0] / 65535.0; to_float[3] = 1.0; to_float += 4; from16++; @@ -694,23 +694,23 @@ ImBuf *imb_loadpng(const unsigned char *mem, size_t size, int flags, char colors else { imb_addrectImBuf(ibuf); - pixels = MEM_mallocN(((size_t)ibuf->x) * ibuf->y * bytesperpixel * sizeof(unsigned char), "pixels"); - if (pixels == NULL) { + pixels = imb_alloc_pixels(ibuf->x, ibuf->y, channels, sizeof(unsigned char), "pixels"); + if (pixels == NULL || ibuf->rect == NULL) { printf("Cannot allocate pixels array\n"); longjmp(png_jmpbuf(png_ptr), 1); } /* allocate memory for an array of row-pointers */ - row_pointers = (png_bytepp) MEM_mallocN(ibuf->y * sizeof(png_bytep), "row_pointers"); + row_pointers = (png_bytepp) MEM_mallocN((size_t)ibuf->y * sizeof(png_bytep), "row_pointers"); if (row_pointers == NULL) { printf("Cannot allocate row-pointers array\n"); longjmp(png_jmpbuf(png_ptr), 1); } /* set the individual row-pointers to point at the correct offsets */ - for (i = 0; i < ibuf->y; i++) { + for (int i = 0; i < ibuf->y; i++) { row_pointers[ibuf->y - 1 - i] = (png_bytep) - ((unsigned char *)pixels + (((size_t)i) * ibuf->x) * bytesperpixel * sizeof(unsigned char)); + ((unsigned char *)pixels + (((size_t)i) * ibuf->x) * channels * sizeof(unsigned char)); } png_read_image(png_ptr, row_pointers); @@ -720,9 +720,9 @@ ImBuf *imb_loadpng(const unsigned char *mem, size_t size, int flags, char colors to = (unsigned char *) ibuf->rect; from = pixels; - switch (bytesperpixel) { + switch (channels) { case 4: - for (i = ibuf->x * ibuf->y; i > 0; i--) { + for (size_t i = (size_t)ibuf->x * (size_t)ibuf->y; i > 0; i--) { to[0] = from[0]; to[1] = from[1]; to[2] = from[2]; @@ -731,7 +731,7 @@ ImBuf *imb_loadpng(const unsigned char *mem, size_t size, int flags, char colors } break; case 3: - for (i = ibuf->x * ibuf->y; i > 0; i--) { + for (size_t i = (size_t)ibuf->x * (size_t)ibuf->y; i > 0; i--) { to[0] = from[0]; to[1] = from[1]; to[2] = from[2]; @@ -740,14 +740,14 @@ ImBuf *imb_loadpng(const unsigned char *mem, size_t size, int flags, char colors } break; case 2: - for (i = ibuf->x * ibuf->y; i > 0; i--) { + for (size_t i = (size_t)ibuf->x * (size_t)ibuf->y; i > 0; i--) { to[0] = to[1] = to[2] = from[0]; to[3] = from[1]; to += 4; from += 2; } break; case 1: - for (i = ibuf->x * ibuf->y; i > 0; i--) { + for (size_t i = (size_t)ibuf->x * (size_t)ibuf->y; i > 0; i--) { to[0] = to[1] = to[2] = from[0]; to[3] = 0xff; to += 4; from++; @@ -759,7 +759,7 @@ ImBuf *imb_loadpng(const unsigned char *mem, size_t size, int flags, char colors if (flags & IB_metadata) { png_text *text_chunks; int count = png_get_text(png_ptr, info_ptr, &text_chunks, NULL); - for (i = 0; i < count; i++) { + for (int i = 0; i < count; i++) { IMB_metadata_add_field(ibuf, text_chunks[i].key, text_chunks[i].text); ibuf->flags |= IB_metadata; } diff --git a/source/blender/imbuf/intern/radiance_hdr.c b/source/blender/imbuf/intern/radiance_hdr.c index a21468e474c..8d822a314f5 100644 --- a/source/blender/imbuf/intern/radiance_hdr.c +++ b/source/blender/imbuf/intern/radiance_hdr.c @@ -71,7 +71,7 @@ typedef float fCOLOR[3]; /* read routines */ static const unsigned char *oldreadcolrs(RGBE *scan, const unsigned char *mem, int xmax, const unsigned char *mem_eof) { - int i, rshift = 0, len = xmax; + size_t i, rshift = 0, len = xmax; while (len > 0) { if (UNLIKELY(mem_eof - mem < 4)) { return NULL; @@ -99,8 +99,6 @@ static const unsigned char *oldreadcolrs(RGBE *scan, const unsigned char *mem, i static const unsigned char *freadcolrs(RGBE *scan, const unsigned char *mem, int xmax, const unsigned char *mem_eof) { - int i, j, code, val; - if (UNLIKELY(mem_eof - mem < 4)) { return NULL; } @@ -109,32 +107,32 @@ static const unsigned char *freadcolrs(RGBE *scan, const unsigned char *mem, int return oldreadcolrs(scan, mem, xmax, mem_eof); } - i = *mem++; - if (i != 2) { + int val = *mem++; + if (val != 2) { return oldreadcolrs(scan, mem - 1, xmax, mem_eof); } scan[0][GRN] = *mem++; scan[0][BLU] = *mem++; - i = *mem++; + val = *mem++; if (scan[0][GRN] != 2 || scan[0][BLU] & 128) { scan[0][RED] = 2; - scan[0][EXP] = i; + scan[0][EXP] = val; return oldreadcolrs(scan + 1, mem, xmax - 1, mem_eof); } - if (UNLIKELY(((scan[0][BLU] << 8) | i) != xmax)) { + if (UNLIKELY(((scan[0][BLU] << 8) | val) != xmax)) { return NULL; } - for (i = 0; i < 4; i++) { + for (size_t i = 0; i < 4; i++) { if (UNLIKELY(mem_eof - mem < 2)) { return NULL; } - for (j = 0; j < xmax; ) { - code = *mem++; + for (size_t j = 0; j < xmax; ) { + int code = *mem++; if (code > 128) { code &= 127; if (UNLIKELY(code + j > xmax)) { @@ -215,7 +213,6 @@ struct ImBuf *imb_loadhdr(const unsigned char *mem, size_t size, int flags, char float *rect_float; int found = 0; int width = 0, height = 0; - int x, y; const unsigned char *ptr, *mem_eof = mem + size; char oriY[80], oriX[80]; @@ -223,6 +220,7 @@ struct ImBuf *imb_loadhdr(const unsigned char *mem, size_t size, int flags, char colorspace_set_default_role(colorspace, IM_MAX_SPACE, COLOR_ROLE_DEFAULT_FLOAT); /* find empty line, next line is resolution info */ + size_t x; for (x = 1; x < size; x++) { if ((mem[x - 1] == '\n') && (mem[x] == '\n')) { found = 1; @@ -259,7 +257,7 @@ struct ImBuf *imb_loadhdr(const unsigned char *mem, size_t size, int flags, char sline = (RGBE *)MEM_mallocN(sizeof(*sline) * width, __func__); rect_float = ibuf->rect_float; - for (y = 0; y < height; y++) { + for (size_t y = 0; y < height; y++) { ptr = freadcolrs(sline, ptr, width, mem_eof); if (ptr == NULL) { printf("WARNING! HDR decode error, image may be just truncated, or completely wrong...\n"); @@ -293,7 +291,7 @@ struct ImBuf *imb_loadhdr(const unsigned char *mem, size_t size, int flags, char /* ImBuf write */ static int fwritecolrs(FILE *file, int width, int channels, unsigned char *ibufscan, float *fpscan) { - int x, i, j, beg, c2, cnt = 0; + int beg, c2, cnt = 0; fCOLOR fcol; RGBE rgbe, *rgbe_scan; @@ -304,8 +302,7 @@ static int fwritecolrs(FILE *file, int width, int channels, unsigned char *ibufs rgbe_scan = (RGBE *)MEM_mallocN(sizeof(RGBE) * width, "radhdr_write_tmpscan"); /* convert scanline */ - j = 0; - for (i = 0; i < width; i++) { + for (size_t i = 0, j = 0; i < width; i++) { if (fpscan) { fcol[RED] = fpscan[j]; fcol[GRN] = (channels >= 2) ? fpscan[j + 1] : fpscan[j]; @@ -322,7 +319,7 @@ static int fwritecolrs(FILE *file, int width, int channels, unsigned char *ibufs } if ((width < MINELEN) | (width > MAXELEN)) { /* OOBs, write out flat */ - x = fwrite((char *)rgbe_scan, sizeof(RGBE), width, file) - width; + int x = fwrite((char *)rgbe_scan, sizeof(RGBE), width, file) - width; MEM_freeN(rgbe_scan); return x; } @@ -332,8 +329,8 @@ static int fwritecolrs(FILE *file, int width, int channels, unsigned char *ibufs putc((unsigned char)(width >> 8), file); putc((unsigned char)(width & 255), file); /* put components separately */ - for (i = 0; i < 4; i++) { - for (j = 0; j < width; j += cnt) { /* find next run */ + for (size_t i = 0; i < 4; i++) { + for (size_t j = 0; j < width; j += cnt) { /* find next run */ for (beg = j; beg < width; beg += cnt) { for (cnt = 1; (cnt < 127) && ((beg + cnt) < width) && (rgbe_scan[beg + cnt][i] == rgbe_scan[beg][i]); cnt++) ; if (cnt >= MINRUN) break; /* long enough */ @@ -386,7 +383,7 @@ int imb_savehdr(struct ImBuf *ibuf, const char *name, int flags) { FILE *file = BLI_fopen(name, "wb"); float *fp = NULL; - int y, width = ibuf->x, height = ibuf->y; + size_t width = ibuf->x, height = ibuf->y; unsigned char *cp = NULL; (void)flags; /* unused */ @@ -402,7 +399,7 @@ int imb_savehdr(struct ImBuf *ibuf, const char *name, int flags) if (ibuf->rect_float) fp = ibuf->rect_float + ibuf->channels * (height - 1) * width; - for (y = height - 1; y >= 0; y--) { + for (size_t y = 0; y < height; y++) { if (fwritecolrs(file, width, ibuf->channels, cp, fp) < 0) { fclose(file); printf("HDR write error\n"); diff --git a/source/blender/imbuf/intern/tiff.c b/source/blender/imbuf/intern/tiff.c index 98aa7c5353b..afd28bb570b 100644 --- a/source/blender/imbuf/intern/tiff.c +++ b/source/blender/imbuf/intern/tiff.c @@ -376,7 +376,7 @@ static void imb_read_tiff_resolution(ImBuf *ibuf, TIFF *image) */ static int imb_read_tiff_pixels(ImBuf *ibuf, TIFF *image) { - ImBuf *tmpibuf; + ImBuf *tmpibuf = NULL; int success = 0; short bitspersample, spp, config; size_t scanline; @@ -412,16 +412,25 @@ static int imb_read_tiff_pixels(ImBuf *ibuf, TIFF *image) if (bitspersample == 32) { ib_flag = IB_rectfloat; fbuf = (float *)_TIFFmalloc(scanline); + if (!fbuf) { + goto cleanup; + } } else if (bitspersample == 16) { ib_flag = IB_rectfloat; sbuf = (unsigned short *)_TIFFmalloc(scanline); + if (!sbuf) { + goto cleanup; + } } else { ib_flag = IB_rect; } tmpibuf = IMB_allocImBuf(ibuf->x, ibuf->y, ibuf->planes, ib_flag); + if (!tmpibuf) { + goto cleanup; + } /* simple RGBA image */ if (!(bitspersample == 32 || bitspersample == 16)) { @@ -430,7 +439,7 @@ static int imb_read_tiff_pixels(ImBuf *ibuf, TIFF *image) /* contiguous channels: RGBRGBRGB */ else if (config == PLANARCONFIG_CONTIG) { for (row = 0; row < ibuf->y; row++) { - int ib_offset = ibuf->x * ibuf->y * 4 - ibuf->x * 4 * (row + 1); + size_t ib_offset = (size_t)ibuf->x * 4 * ((size_t)ibuf->y - ((size_t)row + 1)); if (bitspersample == 32) { success |= TIFFReadScanline(image, fbuf, row, 0); @@ -450,7 +459,7 @@ static int imb_read_tiff_pixels(ImBuf *ibuf, TIFF *image) * but only fill in from the TIFF scanline where necessary. */ for (chan = 0; chan < 4; chan++) { for (row = 0; row < ibuf->y; row++) { - int ib_offset = ibuf->x * ibuf->y * 4 - ibuf->x * 4 * (row + 1); + size_t ib_offset = (size_t)ibuf->x * 4 * ((size_t)ibuf->y - ((size_t)row + 1)); if (bitspersample == 32) { if (chan == 3 && spp == 3) /* fill alpha if only RGB TIFF */ @@ -475,11 +484,6 @@ static int imb_read_tiff_pixels(ImBuf *ibuf, TIFF *image) } } } - - if (bitspersample == 32) - _TIFFfree(fbuf); - else if (bitspersample == 16) - _TIFFfree(sbuf); if (success) { /* Code seems to be not needed for 16 bits tif, on PPC G5 OSX (ton) */ @@ -498,6 +502,12 @@ static int imb_read_tiff_pixels(ImBuf *ibuf, TIFF *image) tmpibuf->mall &= ~ib_flag; } +cleanup: + if (bitspersample == 32) + _TIFFfree(fbuf); + else if (bitspersample == 16) + _TIFFfree(sbuf); + IMB_freeImBuf(tmpibuf); return success; diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h index 4e1161148ea..fd8cd8b2855 100644 --- a/source/blender/makesdna/DNA_ID.h +++ b/source/blender/makesdna/DNA_ID.h @@ -211,13 +211,18 @@ typedef struct ID { int tag; int us; int icon_id; + int recalc; + int pad; IDProperty *properties; IDOverrideStatic *override_static; /* Reference linked ID which this one overrides. */ - void *py_instance; + /* Only set for datablocks which are coming from copy-on-write, points to + * the original version of it. + */ + void *orig_id; - void *pad1; + void *py_instance; } ID; /** @@ -373,6 +378,12 @@ typedef enum ID_Type { #define ID_IS_LINKED(_id) (((ID *)(_id))->lib != NULL) +#define ID_IS_STATIC_OVERRIDE(_id) (((ID *)(_id))->override_static != NULL && \ + ((ID *)(_id))->override_static->reference != NULL) + +#define ID_IS_STATIC_OVERRIDE_TEMPLATE(_id) (((ID *)(_id))->override_static != NULL && \ + ((ID *)(_id))->override_static->reference == NULL) + #ifdef GS # undef GS #endif @@ -437,22 +448,32 @@ enum { /* RESET_AFTER_USE tag existing data before linking so we know what is new. */ LIB_TAG_PRE_EXISTING = 1 << 11, - /* RESET_AFTER_USE, used by update code (depsgraph). */ - LIB_TAG_ID_RECALC = 1 << 12, - LIB_TAG_ID_RECALC_DATA = 1 << 13, - LIB_TAG_ANIM_NO_RECALC = 1 << 14, - LIB_TAG_ID_RECALC_ALL = (LIB_TAG_ID_RECALC | LIB_TAG_ID_RECALC_DATA), - /* The datablock is a copy-on-write version. */ - LIB_TAG_COPY_ON_WRITE = 1 << 15, - LIB_TAG_COPY_ON_WRITE_EVAL = 1 << 16, + LIB_TAG_COPY_ON_WRITE = 1 << 12, + LIB_TAG_COPY_ON_WRITE_EVAL = 1 << 13, /* RESET_NEVER tag datablock for freeing etc. behavior (usually set when copying real one into temp/runtime one). */ - LIB_TAG_NO_MAIN = 1 << 17, /* Datablock is not listed in Main database. */ - LIB_TAG_NO_USER_REFCOUNT = 1 << 18, /* Datablock does not refcount usages of other IDs. */ + LIB_TAG_NO_MAIN = 1 << 14, /* Datablock is not listed in Main database. */ + LIB_TAG_NO_USER_REFCOUNT = 1 << 15, /* Datablock does not refcount usages of other IDs. */ /* Datablock was not allocated by standard system (BKE_libblock_alloc), do not free its memory * (usual type-specific freeing is called though). */ - LIB_TAG_NOT_ALLOCATED = 1 << 19, + LIB_TAG_NOT_ALLOCATED = 1 << 16, +}; + +enum { + /* RESET_AFTER_USE, used by update code (depsgraph). */ + ID_RECALC_NONE = 0, + /* Generic recalc flag, when nothing else matches. */ + ID_RECALC = 1 << 0, + /* Per-component update flags. */ + ID_RECALC_ANIMATION = 1 << 1, + ID_RECALC_DRAW = 1 << 2, + ID_RECALC_DRAW_CACHE = 1 << 3, + ID_RECALC_GEOMETRY = 1 << 4, + ID_RECALC_TRANSFORM = 1 << 5, + ID_RECALC_COLLECTIONS = 1 << 6, + /* Special flag to check if SOMETHING was changed. */ + ID_RECALC_ALL = (~(int)0), }; /* To filter ID types (filter_id) */ diff --git a/source/blender/makesdna/DNA_curve_types.h b/source/blender/makesdna/DNA_curve_types.h index 261e0a5410f..48fe82b3e1a 100644 --- a/source/blender/makesdna/DNA_curve_types.h +++ b/source/blender/makesdna/DNA_curve_types.h @@ -87,9 +87,7 @@ typedef struct BevList { int charidx; int *segbevcount; float *seglen; - - /* over-alloc */ - BevPoint bevpoints[0]; + BevPoint *bevpoints; } BevList; /** diff --git a/source/blender/makesdna/DNA_layer_types.h b/source/blender/makesdna/DNA_layer_types.h index c677383cb6e..806c1ca76fc 100644 --- a/source/blender/makesdna/DNA_layer_types.h +++ b/source/blender/makesdna/DNA_layer_types.h @@ -65,7 +65,7 @@ typedef struct LayerCollection { /* TODO(sergey): Get rid of this once we've got CoW in DEG, */ short flag_evaluated; short pad[2]; - ListBase object_bases; /* (ObjectBase *)LinkData->data - synced with collection->objects and collection->filter_objects */ + ListBase object_bases; /* (ObjectBase *)LinkData->data - synced with collection->objects */ ListBase overrides; ListBase layer_collections; /* synced with collection->collections */ struct IDProperty *properties; /* overrides */ @@ -102,12 +102,10 @@ typedef struct ViewLayer { typedef struct SceneCollection { struct SceneCollection *next, *prev; char name[64]; /* MAX_NAME */ - char filter[64]; /* MAX_NAME */ int active_object_index; /* for UI */ char type; char pad[3]; ListBase objects; /* (Object *)LinkData->data */ - ListBase filter_objects; /* (Object *)LinkData->data */ ListBase scene_collections; /* nested collections */ } SceneCollection; @@ -123,9 +121,10 @@ enum { /* LayerCollection->flag */ enum { - COLLECTION_VISIBLE = (1 << 0), + COLLECTION_VIEWPORT = (1 << 0), /* Only used for group collections. */ COLLECTION_SELECTABLE = (1 << 1), COLLECTION_DISABLED = (1 << 2), + COLLECTION_RENDER = (1 << 3), /* Only used for group collections. */ }; /* ViewLayer->flag */ diff --git a/source/blender/makesdna/DNA_lightprobe_types.h b/source/blender/makesdna/DNA_lightprobe_types.h index 75705f7dd37..649df714457 100644 --- a/source/blender/makesdna/DNA_lightprobe_types.h +++ b/source/blender/makesdna/DNA_lightprobe_types.h @@ -55,7 +55,9 @@ typedef struct LightProbe { float clipsta, clipend; float vis_bias, vis_bleedbias; /* VSM visibility biases */ - float vis_blur, pad2; + float vis_blur; + + float intensity; /* Intensity multiplier */ int grid_resolution_x; /* Irradiance grid resolution */ int grid_resolution_y; diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h index 59d30d175a5..5df7e49c2f3 100644 --- a/source/blender/makesdna/DNA_modifier_types.h +++ b/source/blender/makesdna/DNA_modifier_types.h @@ -249,6 +249,7 @@ typedef struct ArrayModifierData { int flags; /* the number of duplicates to generate for MOD_ARR_FIXEDCOUNT */ int count; + float uv_offset[2]; } ArrayModifierData; /* ArrayModifierData->fit_type */ @@ -867,8 +868,8 @@ typedef struct SimpleDeformModifierData { char mode; /* deform function */ char axis; /* lock axis (for taper and strech) */ + char deform_axis; /* axis to perform the deform on (default is X, but can be overridden by origin */ char flag; - char pad; } SimpleDeformModifierData; @@ -888,6 +889,7 @@ enum { enum { MOD_SIMPLEDEFORM_LOCK_AXIS_X = (1 << 0), MOD_SIMPLEDEFORM_LOCK_AXIS_Y = (1 << 1), + MOD_SIMPLEDEFORM_LOCK_AXIS_Z = (1 << 2), }; typedef struct ShapeKeyModifierData { diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h index 78c623f6408..7c3ef5e72be 100644 --- a/source/blender/makesdna/DNA_object_types.h +++ b/source/blender/makesdna/DNA_object_types.h @@ -75,11 +75,19 @@ typedef struct bFaceMap { } bFaceMap; /* Object Runtime display data */ +struct ObjectEngineData; +typedef void (*ObjectEngineDataInitCb)(struct ObjectEngineData *engine_data); +typedef void (*ObjectEngineDataFreeCb)(struct ObjectEngineData *engine_data); + +# +# typedef struct ObjectEngineData { struct ObjectEngineData *next, *prev; struct DrawEngineType *engine_type; - void *storage; - void (*free)(void *storage); + /* Only nested data, NOT the engine data itself. */ + ObjectEngineDataFreeCb free; + /* Accumulated recalc flags, which corresponds to ID->recalc flags. */ + int recalc; } ObjectEngineData; #define MAX_VGROUP_NAME 64 @@ -154,6 +162,7 @@ typedef struct Object { bAnimVizSettings avs; /* settings for visualization of object-transform animation */ bMotionPath *mpath; /* motion path cache for this object */ + void *pad1; ListBase constraintChannels DNA_DEPRECATED; // XXX deprecated... old animation system ListBase effect DNA_DEPRECATED; // XXX deprecated... keep for readfile @@ -203,11 +212,11 @@ typedef struct Object { short nlaflag; /* used for DopeSheet filtering settings (expanded/collapsed) */ short scaflag; /* ui state for game logic */ char scavisflag; /* more display settings for game logic */ - char depsflag; + char pad; /* did last modifier stack generation need mapping support? */ char lastNeedMapping; /* bool */ - char pad; + char duplicator_visibility_flag; /* dupli-frame settings */ int dupon, dupoff, dupsta, dupend; @@ -276,8 +285,6 @@ typedef struct Object { int gameflag; int gameflag2; - struct BulletSoftBody *bsoft; /* settings for game engine bullet soft body */ - char restrictflag; /* for restricting view, select, render etc. accessible in outliner */ char pad3; short softflag; /* softbody settings */ @@ -288,6 +295,7 @@ typedef struct Object { ListBase hooks DNA_DEPRECATED; // XXX deprecated... old animation system ListBase particlesystem; /* particle systems */ + struct BulletSoftBody *bsoft; /* settings for game engine bullet soft body */ struct PartDeflect *pd; /* particle deflector/attractor/collision data */ struct SoftBody *soft; /* if exists, saved in file */ struct Group *dup_group; /* object duplicator for group */ @@ -300,6 +308,7 @@ typedef struct Object { struct FluidsimSettings *fluidsimSettings; /* if fluidsim enabled, store additional settings */ struct DerivedMesh *derivedDeform, *derivedFinal; + void *pad7; uint64_t lastDataMask; /* the custom data layer mask that was last used to calculate derivedDeform and derivedFinal */ uint64_t customdata_mask; /* (extra) custom data layer mask to use for creating derivedmesh, set by depsgraph */ unsigned int state; /* bit masks of game controllers that are active */ @@ -317,6 +326,7 @@ typedef struct Object { float ima_ofs[2]; /* offset for image empties */ ImageUser *iuser; /* must be non-null when oject is an empty image */ + void *pad4; ListBase lodlevels; /* contains data for levels of detail */ LodLevel *currentlod; @@ -326,7 +336,7 @@ typedef struct Object { struct IDProperty *base_collection_properties; /* used by depsgraph, flushed from base */ ListBase drawdata; /* runtime, ObjectEngineData */ - int pad1; + int pad6; int select_color; /* Mesh structure createrd during object evaluaiton. @@ -627,17 +637,6 @@ enum { OB_BODY_TYPE_CHARACTER = 8, }; -/* ob->depsflag */ -enum { - OB_DEPS_EXTRA_OB_RECALC = 1 << 0, - OB_DEPS_EXTRA_DATA_RECALC = 1 << 1, -}; - -/* ob->deg_update_flag */ -enum { - DEG_RUNTIME_DATA_UPDATE = 1 << 0, -}; - /* ob->scavisflag */ enum { OB_VIS_SENS = 1 << 0, @@ -706,6 +705,12 @@ enum { OB_LOCK_ROT4D = 1 << 10, }; +/* ob->duplicator_visibility_flag */ +enum { + OB_DUPLI_FLAG_VIEWPORT = 1 << 0, + OB_DUPLI_FLAG_RENDER = 1 << 1, +}; + /* ob->mode */ typedef enum eObjectMode { OB_MODE_OBJECT = 0, diff --git a/source/blender/makesdna/DNA_outliner_types.h b/source/blender/makesdna/DNA_outliner_types.h index 81575beaac8..8e48bbdde1a 100644 --- a/source/blender/makesdna/DNA_outliner_types.h +++ b/source/blender/makesdna/DNA_outliner_types.h @@ -102,8 +102,9 @@ enum { #define TSE_KEYMAP_ITEM 35 /* NO ID */ #define TSE_ID_BASE 36 /* NO ID */ #define TSE_GP_LAYER 37 /* NO ID */ -#define TSE_LAYER_COLLECTION 38 /* NO ID */ -#define TSE_SCENE_COLLECTION 39 /* NO ID */ +#define TSE_LAYER_COLLECTION 38 +#define TSE_SCENE_COLLECTION 39 +#define TSE_LAYER_COLLECTION_BASE 40 /* Check whether given TreeStoreElem should have a real ID in its ->id member. */ @@ -111,8 +112,7 @@ enum { (!ELEM((_tse)->type, TSE_NLA, TSE_NLA_TRACK, TSE_DRIVER_BASE, \ TSE_SEQUENCE, TSE_SEQ_STRIP, TSE_SEQUENCE_DUP, \ TSE_RNA_STRUCT, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM, \ - TSE_KEYMAP, TSE_KEYMAP_ITEM, TSE_ID_BASE, TSE_GP_LAYER, \ - TSE_SCENE_COLLECTION, TSE_LAYER_COLLECTION)) + TSE_KEYMAP, TSE_KEYMAP_ITEM, TSE_ID_BASE, TSE_GP_LAYER)) #endif diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index d25391ca95d..671ad1bc954 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -180,7 +180,8 @@ typedef struct SceneRenderLayer { unsigned int lay_zmask DNA_DEPRECATED; /* Converted to LayerCollection cycles holdout override. */ unsigned int lay_exclude DNA_DEPRECATED; int layflag DNA_DEPRECATED; /* Converted to ViewLayer layflag and flag. */ - + + /* pass_xor has to be after passflag */ int passflag DNA_DEPRECATED; /* pass_xor has to be after passflag */ int pass_xor DNA_DEPRECATED; /* Converted to ViewLayer passflag and flag. */ @@ -192,7 +193,7 @@ typedef struct SceneRenderLayer { struct FreestyleConfig freestyleConfig DNA_DEPRECATED; /* Converted to ViewLayer freestyleConfig. */ } SceneRenderLayer; -/* srl->layflag */ +/* SceneRenderLayer.layflag */ #define SCE_LAY_SOLID 1 #define SCE_LAY_ZTRA 2 #define SCE_LAY_HALO 4 @@ -209,7 +210,7 @@ typedef struct SceneRenderLayer { #define SCE_LAY_ZMASK 0x40000 #define SCE_LAY_NEG_ZMASK 0x80000 -/* srl->passflag */ +/* SceneRenderLayer.passflag */ typedef enum eScenePassType { SCE_PASS_COMBINED = (1 << 0), SCE_PASS_Z = (1 << 1), @@ -279,7 +280,6 @@ typedef enum eScenePassType { #define RE_PASSNAME_SUBSURFACE_INDIRECT "SubsurfaceInd" #define RE_PASSNAME_SUBSURFACE_COLOR "SubsurfaceCol" -/* note, srl->passflag is treestore element 'nr' in outliner, short still... */ /* View - MultiView */ typedef struct SceneRenderView { @@ -294,16 +294,16 @@ typedef struct SceneRenderView { } SceneRenderView; -/* srv->viewflag */ +/* SceneRenderView.viewflag */ #define SCE_VIEW_DISABLE (1<<0) -/* scene.render.views_format */ +/* RenderData.views_format */ enum { SCE_VIEWS_FORMAT_STEREO_3D = 0, SCE_VIEWS_FORMAT_MULTIVIEW = 1, }; -/* ImageFormatData.views_output */ +/* ImageFormatData.views_format (also used for Sequence.views_format) */ enum { R_IMF_VIEWS_INDIVIDUAL = 0, R_IMF_VIEWS_STEREO_3D = 1, @@ -503,7 +503,7 @@ typedef struct BakeData { char cage[64]; /* MAX_NAME */ } BakeData; -/* (char) normal_swizzle */ +/* BakeData.normal_swizzle (char) */ typedef enum eBakeNormalSwizzle { R_BAKE_POSX = 0, R_BAKE_POSY = 1, @@ -513,13 +513,13 @@ typedef enum eBakeNormalSwizzle { R_BAKE_NEGZ = 5, } eBakeNormalSwizzle; -/* (char) save_mode */ +/* BakeData.save_mode (char) */ typedef enum eBakeSaveMode { R_BAKE_SAVE_INTERNAL = 0, R_BAKE_SAVE_EXTERNAL = 1, } eBakeSaveMode; -/* bake->pass_filter */ +/* BakeData.pass_filter */ typedef enum eBakePassFilter { R_BAKE_PASS_FILTER_NONE = 0, R_BAKE_PASS_FILTER_AO = (1 << 0), @@ -801,6 +801,7 @@ typedef struct GameDome { struct Text *warptext; } GameDome; +/* GameDome.mode */ #define DOME_FISHEYE 1 #define DOME_TRUNCATED_FRONT 2 #define DOME_TRUNCATED_REAR 3 @@ -816,6 +817,7 @@ typedef struct GameFraming { char type, pad1, pad2, pad3; } GameFraming; +/* GameFraming.type */ #define SCE_GAMEFRAMING_BARS 0 #define SCE_GAMEFRAMING_EXTEND 1 #define SCE_GAMEFRAMING_SCALE 2 @@ -839,6 +841,7 @@ typedef struct RecastData { short pad2; } RecastData; +/* RecastData.partitioning */ #define RC_PARTITION_WATERSHED 0 #define RC_PARTITION_MONOTONE 1 #define RC_PARTITION_LAYERS 2 @@ -885,12 +888,15 @@ typedef struct GameData { /* Scene LoD */ short lodflag, pad2; int scehysteresis, pad5; + } GameData; +/* GameData.stereoflag */ #define STEREO_NOSTEREO 1 #define STEREO_ENABLED 2 #define STEREO_DOME 3 +/* GameData.stereomode */ //#define STEREO_NOSTEREO 1 #define STEREO_QUADBUFFERED 2 #define STEREO_ABOVEBELOW 3 @@ -901,7 +907,7 @@ typedef struct GameData { //#define STEREO_DOME 8 #define STEREO_3DTVTOPBOTTOM 9 -/* physicsEngine */ +/* GameData.physicsEngine */ #define WOPHY_NONE 0 #define WOPHY_BULLET 5 @@ -910,13 +916,13 @@ typedef struct GameData { #define OBSTSIMULATION_TOI_rays 1 #define OBSTSIMULATION_TOI_cells 2 -/* Raster storage */ +/* GameData.raster_storage */ #define RAS_STORE_AUTO 0 -#define RAS_STORE_IMMEDIATE 1 +/* #define RAS_STORE_IMMEDIATE 1 */ /* DEPRECATED */ #define RAS_STORE_VA 2 #define RAS_STORE_VBO 3 -/* vsync */ +/* GameData.vsync */ #define VSYNC_ON 0 #define VSYNC_OFF 1 #define VSYNC_ADAPTIVE 2 @@ -960,13 +966,16 @@ enum { #define SCE_LOD_USE_HYST (1 << 0) /* UV Paint */ +/* ToolSettings.uv_sculpt_settings */ #define UV_SCULPT_LOCK_BORDERS 1 #define UV_SCULPT_ALL_ISLANDS 2 +/* ToolSettings.uv_sculpt_tool */ #define UV_SCULPT_TOOL_PINCH 1 #define UV_SCULPT_TOOL_RELAX 2 #define UV_SCULPT_TOOL_GRAB 3 +/* ToolSettings.uv_relax_method */ #define UV_SCULPT_TOOL_RELAX_LAPLACIAN 1 #define UV_SCULPT_TOOL_RELAX_HC 2 @@ -976,6 +985,7 @@ enum { #define STEREO_RIGHT_SUFFIX "_R" #define STEREO_LEFT_SUFFIX "_L" +/* View3D.stereo3d_camera / View3D.multiview_eye / ImageUser.multiview_eye */ typedef enum eStereoViews { STEREO_LEFT_ID = 0, STEREO_RIGHT_ID = 1, @@ -986,7 +996,7 @@ typedef enum eStereoViews { /* *************************************************************** */ /* Markers */ -typedef struct TimeMarker { +typedef struct TimeMarker { struct TimeMarker *next, *prev; int frame; char name[64]; @@ -1064,7 +1074,7 @@ typedef struct ParticleEditSettings { short totaddkey; short brushtype; - ParticleBrushData brush[7]; /* 7 = PE_TOT_BRUSH */ + ParticleBrushData brush[7]; void *paintcursor; /* runtime */ float emitterdist, rt; @@ -1136,7 +1146,7 @@ enum { /* ------------------------------------------- */ /* GPencil Stroke Sculpting */ -/* Brush types */ +/* GP_BrushEdit_Settings.brushtype */ typedef enum eGP_EditBrush_Types { GP_EDITBRUSH_TYPE_SMOOTH = 0, GP_EDITBRUSH_TYPE_THICKNESS = 1, @@ -1154,7 +1164,7 @@ typedef enum eGP_EditBrush_Types { TOT_GP_EDITBRUSH_TYPES } eGP_EditBrush_Types; -/* Lock axis options */ +/* GP_BrushEdit_Settings.lock_axis */ typedef enum eGP_Lockaxis_Types { GP_LOCKAXIS_NONE = 0, GP_LOCKAXIS_X = 1, @@ -1192,7 +1202,7 @@ typedef struct GP_BrushEdit_Settings { int brushtype; /* eGP_EditBrush_Types */ int flag; /* eGP_BrushEdit_SettingsFlag */ - int lock_axis; /* lock drawing to one axis */ + int lock_axis; /* eGP_Lockaxis_Types lock drawing to one axis */ float alpha; /* alpha factor for selection color */ } GP_BrushEdit_Settings; @@ -1331,6 +1341,7 @@ typedef struct UnifiedPaintSettings { struct ColorSpace *colorspace; } UnifiedPaintSettings; +/* UnifiedPaintSettings.flag */ typedef enum { UNIFIED_PAINT_SIZE = (1 << 0), UNIFIED_PAINT_ALPHA = (1 << 1), @@ -1667,17 +1678,15 @@ typedef struct Scene { /* Grease Pencil */ struct bGPdata *gpd; + /* Movie Tracking */ + struct MovieClip *clip; /* active movie clip */ + /* Physics simulation settings */ struct PhysicsSettings physics_settings; - void *pad6; - uint64_t customdata_mask; /* XXX. runtime flag for drawing, actually belongs in the window, only used by BKE_object_handle_update() */ uint64_t customdata_mask_modal; /* XXX. same as above but for temp operator use (gl renders) */ - /* Movie Tracking */ - struct MovieClip *clip; /* active movie clip */ - /* Color Management */ ColorManagedViewSettings view_settings; ColorManagedDisplaySettings display_settings; @@ -1703,14 +1712,14 @@ typedef struct Scene { /* **************** RENDERDATA ********************* */ -/* flag */ +/* RenderData.flag */ /* use preview range */ #define SCER_PRV_RANGE (1<<0) #define SCER_LOCK_FRAME_SELECTION (1<<1) /* show/use subframes (for checking motion blur) */ #define SCER_SHOW_SUBFRAME (1<<3) -/* mode (int now) */ +/* RenderData.mode */ #define R_OSA 0x0001 #define R_SHADOW 0x0002 #define R_GAMMA 0x0004 @@ -1723,7 +1732,8 @@ typedef struct Scene { #define R_BORDER 0x0200 #define R_PANORAMA 0x0400 /* deprecated as scene option, still used in renderer */ #define R_CROP 0x0800 -/*#define R_COSMO 0x1000 deprecated */ + /* Disable camera switching: runtime (DURIAN_CAMERA_SWITCH) */ +#define R_NO_CAMERA_SWITCH 0x1000 #define R_ODDFIELD 0x2000 #define R_MBLUR 0x4000 /* unified was here */ @@ -1746,7 +1756,7 @@ typedef struct Scene { #define R_PERSISTENT_DATA 0x4000000 /* keep data around for re-render */ #define R_USE_WS_SHADING 0x8000000 /* use world space interpretation of lighting data */ -/* seq_flag */ +/* RenderData.seq_flag */ enum { // R_SEQ_GL_PREV = (1 << 1), // UNUSED, we just use setting from seq_prev_type now. // R_SEQ_GL_REND = (1 << 2), // UNUSED, opengl render has its own operator now. @@ -1754,15 +1764,14 @@ enum { R_SEQ_CAMERA_DOF = (1 << 4), }; -/* displaymode */ - +/* RenderData.displaymode */ #define R_OUTPUT_SCREEN 0 #define R_OUTPUT_AREA 1 #define R_OUTPUT_WINDOW 2 #define R_OUTPUT_NONE 3 /*#define R_OUTPUT_FORKED 4*/ -/* filtertype */ +/* RenderData.filtertype */ #define R_FILTER_BOX 0 #define R_FILTER_TENT 1 #define R_FILTER_QUAD 2 @@ -1772,7 +1781,7 @@ enum { #define R_FILTER_MITCH 6 #define R_FILTER_FAST_GAUSS 7 /* note, this is only used for nodes at the moment */ -/* raytrace structure */ +/* RenderData.raytrace_structure */ #define R_RAYSTRUCTURE_AUTO 0 #define R_RAYSTRUCTURE_OCTREE 1 #define R_RAYSTRUCTURE_BLIBVH 2 /* removed */ @@ -1780,11 +1789,11 @@ enum { #define R_RAYSTRUCTURE_SIMD_SVBVH 4 /* needs SIMD */ #define R_RAYSTRUCTURE_SIMD_QBVH 5 /* needs SIMD */ -/* raytrace_options */ +/* RenderData.raytrace_options */ #define R_RAYTRACE_USE_LOCAL_COORDS 0x0001 #define R_RAYTRACE_USE_INSTANCES 0x0002 -/* scemode (int now) */ +/* RenderData.scemode (int now) */ #define R_DOSEQ 0x0001 #define R_BG_RENDER 0x0002 /* passepartout is camera option now, keep this for backward compatibility */ @@ -1809,7 +1818,7 @@ enum { #define R_EXR_CACHE_FILE 0x100000 #define R_MULTIVIEW 0x200000 -/* r->stamp */ +/* RenderData.stamp */ #define R_STAMP_TIME 0x0001 #define R_STAMP_FRAME 0x0002 #define R_STAMP_DATE 0x0004 @@ -1830,19 +1839,19 @@ enum { R_STAMP_RENDERTIME|R_STAMP_CAMERALENS|R_STAMP_MEMORY| \ R_STAMP_HIDE_LABELS) -/* alphamode */ +/* RenderData.alphamode */ #define R_ADDSKY 0 #define R_ALPHAPREMUL 1 /*#define R_ALPHAKEY 2*/ /* deprecated, shouldn't be used */ -/* color_mgt_flag */ +/* RenderData.color_mgt_flag */ enum { R_COLOR_MANAGEMENT = (1 << 0), /* deprecated, should only be used in versioning code only */ /*R_COLOR_MANAGEMENT_PREDIVIDE = (1 << 1)*/ /* deprecated, shouldn't be used */ }; #ifdef DNA_DEPRECATED -/* subimtype, flag options for imtype */ +/* RenderData.subimtype flag options for imtype */ enum { R_OPENEXR_HALF = 1, /*deprecated*/ R_OPENEXR_ZBUF = 2, /*deprecated*/ @@ -1859,7 +1868,7 @@ enum { #endif /* bake_mode: same as RE_BAKE_xxx defines */ -/* bake_flag: */ +/* RenderData.bake_flag */ #define R_BAKE_CLEAR 1 #define R_BAKE_OSA 2 #define R_BAKE_TO_ACTIVE 4 @@ -1872,22 +1881,22 @@ enum { #define R_BAKE_SPLIT_MAT 512 #define R_BAKE_AUTO_NAME 1024 -/* bake_normal_space */ +/* RenderData.bake_normal_space */ #define R_BAKE_SPACE_CAMERA 0 #define R_BAKE_SPACE_WORLD 1 #define R_BAKE_SPACE_OBJECT 2 #define R_BAKE_SPACE_TANGENT 3 -/* simplify_flag */ +/* RenderData.simplify_flag */ #define R_SIMPLE_NO_TRIANGULATE 1 -/* line_thickness_mode */ +/* RenderData.line_thickness_mode */ #define R_LINE_THICKNESS_ABSOLUTE 1 #define R_LINE_THICKNESS_RELATIVE 2 /* sequencer seq_prev_type seq_rend_type */ -/* scene->r.engine (scene.c) */ +/* RenderData.engine (scene.c) */ extern const char *RE_engine_id_BLENDER_RENDER; extern const char *RE_engine_id_BLENDER_GAME; extern const char *RE_engine_id_BLENDER_CLAY; @@ -1949,9 +1958,9 @@ extern const char *RE_engine_id_CYCLES; #define TIME2FRA(a) ((((double) scene->r.frs_sec) * (double)(a)) / (double)scene->r.frs_sec_base) #define FPS (((double) scene->r.frs_sec) / (double)scene->r.frs_sec_base) -/* base->legacy_flag is in DNA_object_types.h */ +/* Base.flag is in DNA_object_types.h */ -/* toolsettings->snap_flag */ +/* ToolSettings.snap_flag */ #define SCE_SNAP 1 #define SCE_SNAP_ROTATE 2 #define SCE_SNAP_PEEL_OBJECT 4 @@ -1959,12 +1968,12 @@ extern const char *RE_engine_id_CYCLES; #define SCE_SNAP_NO_SELF 16 #define SCE_SNAP_ABS_GRID 32 -/* toolsettings->snap_target */ +/* ToolSettings.snap_target */ #define SCE_SNAP_TARGET_CLOSEST 0 #define SCE_SNAP_TARGET_CENTER 1 #define SCE_SNAP_TARGET_MEDIAN 2 #define SCE_SNAP_TARGET_ACTIVE 3 -/* toolsettings->snap_mode */ +/* ToolSettings.snap_mode */ #define SCE_SNAP_MODE_INCREMENT 0 #define SCE_SNAP_MODE_VERTEX 1 #define SCE_SNAP_MODE_EDGE 2 @@ -1975,24 +1984,24 @@ extern const char *RE_engine_id_CYCLES; #define SCE_SNAP_MODE_NODE_XY 7 #define SCE_SNAP_MODE_GRID 8 -/* toolsettings->selectmode */ +/* ToolSettings.selectmode */ #define SCE_SELECT_VERTEX 1 /* for mesh */ #define SCE_SELECT_EDGE 2 #define SCE_SELECT_FACE 4 -/* toolsettings->statvis->type */ +/* MeshStatVis.type */ #define SCE_STATVIS_OVERHANG 0 #define SCE_STATVIS_THICKNESS 1 #define SCE_STATVIS_INTERSECT 2 #define SCE_STATVIS_DISTORT 3 #define SCE_STATVIS_SHARP 4 -/* toolsettings->particle.selectmode for particles */ +/* ParticleEditSettings.selectmode for particles */ #define SCE_SELECT_PATH 1 #define SCE_SELECT_POINT 2 #define SCE_SELECT_END 4 -/* toolsettings->prop_mode (proportional falloff) */ +/* ToolSettings.prop_mode (proportional falloff) */ #define PROP_SMOOTH 0 #define PROP_SPHERE 1 #define PROP_ROOT 2 @@ -2003,21 +2012,21 @@ extern const char *RE_engine_id_CYCLES; #define PROP_INVSQUARE 7 #define PROP_MODE_MAX 8 -/* toolsettings->proportional */ +/* ToolSettings.proportional */ #define PROP_EDIT_OFF 0 #define PROP_EDIT_ON 1 #define PROP_EDIT_CONNECTED 2 #define PROP_EDIT_PROJECTED 3 -/* toolsettings->weightuser */ +/* ToolSettings.weightuser */ enum { OB_DRAW_GROUPUSER_NONE = 0, OB_DRAW_GROUPUSER_ACTIVE = 1, OB_DRAW_GROUPUSER_ALL = 2 }; -/* toolsettings->vgroupsubset */ /* object_vgroup.c */ +/* ToolSettings.vgroupsubset */ typedef enum eVGroupSelect { WT_VGROUP_ALL = 0, WT_VGROUP_ACTIVE = 1, @@ -2034,26 +2043,26 @@ typedef enum eVGroupSelect { (1 << WT_VGROUP_ALL)) -/* sce->flag */ +/* Scene.flag */ #define SCE_DS_SELECTED (1<<0) #define SCE_DS_COLLAPSED (1<<1) #define SCE_NLA_EDIT_ON (1<<2) #define SCE_FRAME_DROP (1<<3) #define SCE_KEYS_NO_SELONLY (1<<4) - /* return flag BKE_scene_base_iter_next functions */ /* #define F_ERROR -1 */ /* UNUSED */ #define F_START 0 #define F_SCENE 1 #define F_DUPLI 3 -/* audio->flag */ +/* AudioData.flag */ #define AUDIO_MUTE (1<<0) #define AUDIO_SYNC (1<<1) #define AUDIO_SCRUB (1<<2) #define AUDIO_VOLUME_ANIMATED (1<<3) +/* FFMpegCodecData.flags */ enum { #ifdef DNA_DEPRECATED FFMPEG_MULTIPLEX_AUDIO = 1, /* deprecated, you can choose none as audiocodec now */ @@ -2117,12 +2126,16 @@ typedef enum eSculptFlags { /* If set, dynamic-topology detail size will be constant in object space */ SCULPT_DYNTOPO_DETAIL_CONSTANT = (1 << 13), SCULPT_DYNTOPO_DETAIL_BRUSH = (1 << 14), + + /* Don't display mask in viewport, but still use it for strokes. */ + SCULPT_HIDE_MASK = (1 << 15), } eSculptFlags; -typedef enum eImageePaintMode { +/* ImagePaintSettings.mode */ +typedef enum eImagePaintMode { IMAGEPAINT_MODE_MATERIAL, /* detect texture paint slots from the material */ IMAGEPAINT_MODE_IMAGE, /* select texture paint image directly */ -} eImageePaintMode; +} eImagePaintMode; /* ImagePaintSettings.flag */ #define IMAGEPAINT_DRAWING 1 @@ -2130,6 +2143,7 @@ typedef enum eImageePaintMode { // #define IMAGEPAINT_DRAW_TOOL_DRAWING 4 // deprecated /* projection painting only */ +/* ImagePaintSettings.flag */ #define IMAGEPAINT_PROJECT_XRAY (1 << 4) #define IMAGEPAINT_PROJECT_BACKFACE (1 << 5) #define IMAGEPAINT_PROJECT_FLAT (1 << 6) @@ -2137,29 +2151,29 @@ typedef enum eImageePaintMode { #define IMAGEPAINT_PROJECT_LAYER_STENCIL (1 << 8) #define IMAGEPAINT_PROJECT_LAYER_STENCIL_INV (1 << 9) - +/* ImagePaintSettings.missing_data */ #define IMAGEPAINT_MISSING_UVS (1 << 0) #define IMAGEPAINT_MISSING_MATERIAL (1 << 1) #define IMAGEPAINT_MISSING_TEX (1 << 2) #define IMAGEPAINT_MISSING_STENCIL (1 << 3) -/* toolsettings->uvcalc_flag */ +/* ToolSettings.uvcalc_flag */ #define UVCALC_FILLHOLES 1 #define UVCALC_NO_ASPECT_CORRECT 2 /* would call this UVCALC_ASPECT_CORRECT, except it should be default with old file */ #define UVCALC_TRANSFORM_CORRECT 4 /* adjust UV's while transforming to avoid distortion */ #define UVCALC_USESUBSURF 8 /* Use mesh data after subsurf to compute UVs*/ -/* toolsettings->uv_flag */ +/* ToolSettings.uv_flag */ #define UV_SYNC_SELECTION 1 #define UV_SHOW_SAME_IMAGE 2 -/* toolsettings->uv_selectmode */ +/* ToolSettings.uv_selectmode */ #define UV_SELECT_VERTEX 1 #define UV_SELECT_EDGE 2 #define UV_SELECT_FACE 4 #define UV_SELECT_ISLAND 8 -/* toolsettings->edge_mode */ +/* ToolSettings.edge_mode */ #define EDGE_MODE_SELECT 0 #define EDGE_MODE_TAG_SEAM 1 #define EDGE_MODE_TAG_SHARP 2 @@ -2167,7 +2181,7 @@ typedef enum eImageePaintMode { #define EDGE_MODE_TAG_BEVEL 4 #define EDGE_MODE_TAG_FREESTYLE 5 -/* toolsettings->gpencil_flags */ +/* ToolSettings.gpencil_flags */ typedef enum eGPencil_Flags { /* "Continuous Drawing" - The drawing operator enters a mode where multiple strokes can be drawn */ GP_TOOL_FLAG_PAINTSESSIONS_ON = (1 << 0), @@ -2177,13 +2191,13 @@ typedef enum eGPencil_Flags { GP_TOOL_FLAG_PAINT_ONBACK = (1 << 2) } eGPencil_Flags; -/* toolsettings->gpencil_src */ +/* ToolSettings.gpencil_src */ typedef enum eGPencil_Source_3D { GP_TOOL_SOURCE_SCENE = 0, GP_TOOL_SOURCE_OBJECT = 1 } eGPencil_Source_3d; -/* toolsettings->gpencil_*_align - Stroke Placement mode flags */ +/* ToolSettings.gpencil_*_align - Stroke Placement mode flags */ typedef enum eGPencil_Placement_Flags { /* New strokes are added in viewport/data space (i.e. not screen space) */ GP_PROJECT_VIEWSPACE = (1 << 0), @@ -2199,7 +2213,7 @@ typedef enum eGPencil_Placement_Flags { GP_PROJECT_DEPTH_STROKE_ENDPOINTS = (1 << 4), } eGPencil_Placement_Flags; -/* toolsettings->particle flag */ +/* ToolSettings.particle flag */ #define PE_KEEP_LENGTHS 1 #define PE_LOCK_FIRST 2 #define PE_DEFLECT_EMITTER 4 @@ -2209,7 +2223,7 @@ typedef enum eGPencil_Placement_Flags { #define PE_FADE_TIME 128 #define PE_AUTO_VELOCITY 256 -/* toolsetting->particle brushtype */ +/* ParticleEditSettings.brushtype */ #define PE_BRUSH_NONE -1 #define PE_BRUSH_COMB 0 #define PE_BRUSH_CUT 1 @@ -2219,18 +2233,15 @@ typedef enum eGPencil_Placement_Flags { #define PE_BRUSH_SMOOTH 5 #define PE_BRUSH_WEIGHT 6 -/* this must equal ParticleEditSettings.brush array size */ -#define PE_TOT_BRUSH 6 - -/* ParticleBrushData->flag */ +/* ParticleBrushData.flag */ #define PE_BRUSH_DATA_PUFF_VOLUME 1 -/* tooksettings->particle edittype */ +/* ParticleBrushData.edittype */ #define PE_TYPE_PARTICLES 0 #define PE_TYPE_SOFTBODY 1 #define PE_TYPE_CLOTH 2 -/* toolsettings->skgen_options */ +/* ToolSettings.skgen_options */ #define SKGEN_FILTER_INTERNAL (1 << 0) #define SKGEN_FILTER_EXTERNAL (1 << 1) #define SKGEN_SYMMETRY (1 << 2) @@ -2252,40 +2263,40 @@ typedef enum eGPencil_Placement_Flags { #define SKGEN_SUB_CORRELATION 2 #define SKGEN_SUB_TOTAL 3 -/* toolsettings->skgen_postpro */ +/* ToolSettings.skgen_postpro */ #define SKGEN_SMOOTH 0 #define SKGEN_AVERAGE 1 #define SKGEN_SHARPEN 2 -/* toolsettings->bone_sketching */ +/* ToolSettings.bone_sketching */ #define BONE_SKETCHING 1 #define BONE_SKETCHING_QUICK 2 #define BONE_SKETCHING_ADJUST 4 -/* toolsettings->bone_sketching_convert */ +/* ToolSettings.bone_sketching_convert */ #define SK_CONVERT_CUT_FIXED 0 #define SK_CONVERT_CUT_LENGTH 1 #define SK_CONVERT_CUT_ADAPTATIVE 2 #define SK_CONVERT_RETARGET 3 -/* toolsettings->skgen_retarget_options */ +/* ToolSettings.skgen_retarget_options */ #define SK_RETARGET_AUTONAME 1 -/* toolsettings->skgen_retarget_roll */ +/* ToolSettings.skgen_retarget_roll */ #define SK_RETARGET_ROLL_NONE 0 #define SK_RETARGET_ROLL_VIEW 1 #define SK_RETARGET_ROLL_JOINT 2 -/* physics_settings->flag */ +/* PhysicsSettings.flag */ #define PHYS_GLOBAL_GRAVITY 1 /* UnitSettings */ -/* UnitSettings->system */ +/* UnitSettings.system */ #define USER_UNIT_NONE 0 #define USER_UNIT_METRIC 1 #define USER_UNIT_IMPERIAL 2 -/* UnitSettings->flag */ +/* UnitSettings.flag */ #define USER_UNIT_OPT_SPLIT 1 #define USER_UNIT_ROT_RADIANS 2 diff --git a/source/blender/makesdna/DNA_screen_types.h b/source/blender/makesdna/DNA_screen_types.h index 97792dbf0ef..fff3ec10292 100644 --- a/source/blender/makesdna/DNA_screen_types.h +++ b/source/blender/makesdna/DNA_screen_types.h @@ -45,6 +45,8 @@ struct PanelType; struct Scene; struct uiLayout; struct wmTimer; +struct wmTooltipState; + typedef struct bScreen { ID id; @@ -78,6 +80,8 @@ typedef struct bScreen { struct wmTimer *animtimer; /* if set, screen has timer handler added in window */ void *context; /* context callback */ + struct wmTooltipState *tool_tip; /* runtime */ + PreviewImage *preview; } bScreen; @@ -294,15 +298,15 @@ typedef struct ARegion { /* area->flag */ enum { HEADER_NO_PULLDOWN = (1 << 0), - AREA_FLAG_DRAWJOINTO = (1 << 1), - AREA_FLAG_DRAWJOINFROM = (1 << 2), +// AREA_FLAG_DEPRECATED_1 = (1 << 1), +// AREA_FLAG_DEPRECATED_2 = (1 << 2), #ifdef DNA_DEPRECATED_ALLOW AREA_TEMP_INFO = (1 << 3), /* versioned to make slot reusable */ #endif /* update size of regions within the area */ AREA_FLAG_REGION_SIZE_UPDATE = (1 << 3), - AREA_FLAG_DRAWSPLIT_H = (1 << 4), - AREA_FLAG_DRAWSPLIT_V = (1 << 5), +// AREA_FLAG_DEPRECATED_4 = (1 << 4), +// AREA_FLAG_DEPRECATED_5 = (1 << 5), /* used to check if we should switch back to prevspace (of a different type) */ AREA_FLAG_TEMP_TYPE = (1 << 6), /* for temporary fullscreens (file browser, image editor render) that are opened above user set fullscreens */ diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h index 27e108b82ab..40beeccf7b6 100644 --- a/source/blender/makesdna/DNA_space_types.h +++ b/source/blender/makesdna/DNA_space_types.h @@ -266,6 +266,9 @@ typedef struct SpaceOops { struct TreeStoreElem search_tse; short flag, outlinevis, storeflag, search_flags; + int filter; + char filter_state; + char pad[3]; /* pointers to treestore elements, grouped by (id, type, nr) in hashtable for faster searching */ void *treehash; @@ -281,24 +284,68 @@ typedef enum eSpaceOutliner_Flag { SO_SKIP_SORT_ALPHA = (1 << 4), } eSpaceOutliner_Flag; +/* SpaceOops->filter */ +typedef enum eSpaceOutliner_Filter { + SO_FILTER_SEARCH = (1 << 0), + SO_FILTER_ENABLE = (1 << 1), + SO_FILTER_NO_OBJECT = (1 << 2), + SO_FILTER_NO_OB_CONTENT = (1 << 3), /* Not only mesh, but modifiers, constraints, ... */ + SO_FILTER_NO_CHILDREN = (1 << 4), + + SO_FILTER_OB_TYPE = (1 << 5), + SO_FILTER_NO_OB_MESH = (1 << 6), + SO_FILTER_NO_OB_ARMATURE = (1 << 7), + SO_FILTER_NO_OB_EMPTY = (1 << 8), + SO_FILTER_NO_OB_LAMP = (1 << 9), + SO_FILTER_NO_OB_CAMERA = (1 << 10), + SO_FILTER_NO_OB_OTHERS = (1 << 11), + + SO_FILTER_OB_STATE = (1 << 12), + SO_FILTER_OB_STATE_VISIBLE = (1 << 13), /* Not set via DNA. */ + SO_FILTER_OB_STATE_SELECTED= (1 << 14), /* Not set via DNA. */ + SO_FILTER_OB_STATE_ACTIVE = (1 << 15), /* Not set via DNA. */ + SO_FILTER_NO_COLLECTION = (1 << 16), +} eSpaceOutliner_Filter; + +#define SO_FILTER_NO_OB_ALL (SO_FILTER_NO_OB_MESH | \ + SO_FILTER_NO_OB_ARMATURE | \ + SO_FILTER_NO_OB_EMPTY | \ + SO_FILTER_NO_OB_LAMP | \ + SO_FILTER_NO_OB_CAMERA | \ + SO_FILTER_NO_OB_OTHERS) + +#define SO_FILTER_ANY (SO_FILTER_NO_OBJECT | \ + SO_FILTER_NO_OB_CONTENT | \ + SO_FILTER_NO_CHILDREN | \ + SO_FILTER_OB_TYPE | \ + SO_FILTER_OB_STATE | \ + SO_FILTER_NO_COLLECTION) + +/* SpaceOops->filter_state */ +typedef enum eSpaceOutliner_StateFilter { + SO_FILTER_OB_VISIBLE = 0, + SO_FILTER_OB_SELECTED = 1, + SO_FILTER_OB_ACTIVE = 2, +} eSpaceOutliner_StateFilter; + /* SpaceOops->outlinevis */ typedef enum eSpaceOutliner_Mode { - SO_ALL_SCENES = 0, - SO_CUR_SCENE = 1, - SO_VISIBLE = 2, - SO_SELECTED = 3, - SO_ACTIVE = 4, - SO_SAME_TYPE = 5, + SO_SCENES = 0, + /* SO_CUR_SCENE = 1, */ /* deprecated! */ + /* SO_VISIBLE = 2, */ /* deprecated! */ + /* SO_SELECTED = 3, */ /* deprecated! */ + /* SO_ACTIVE = 4, */ /* deprecated! */ + /* SO_SAME_TYPE = 5, */ /* deprecated! */ SO_GROUPS = 6, SO_LIBRARIES = 7, /* SO_VERSE_SESSION = 8, */ /* deprecated! */ /* SO_VERSE_MS = 9, */ /* deprecated! */ SO_SEQUENCE = 10, SO_DATABLOCKS = 11, - SO_USERDEF = 12, + /* SO_USERDEF = 12, */ /* deprecated! */ /* SO_KEYMAP = 13, */ /* deprecated! */ SO_ID_ORPHANS = 14, - SO_ACT_LAYER = 15, + SO_VIEW_LAYER = 15, SO_COLLECTIONS = 16, } eSpaceOutliner_Mode; diff --git a/source/blender/makesdna/DNA_text_types.h b/source/blender/makesdna/DNA_text_types.h index c7969cd30e7..0a9b8c320b5 100644 --- a/source/blender/makesdna/DNA_text_types.h +++ b/source/blender/makesdna/DNA_text_types.h @@ -51,6 +51,7 @@ typedef struct Text { ID id; char *name; + void *compiled; int flags, nlines; @@ -59,10 +60,10 @@ typedef struct Text { int curc, selc; char *undo_buf; + void *pad; int undo_pos, undo_len; - + double mtime; - void *compiled; } Text; #define TXT_TABSIZE 4 diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h index 81f605b093a..38a1c3ae01c 100644 --- a/source/blender/makesdna/DNA_userdef_types.h +++ b/source/blender/makesdna/DNA_userdef_types.h @@ -472,7 +472,10 @@ typedef struct UserDef { short wheellinescroll; int uiflag; /* eUserpref_UI_Flag */ int uiflag2; /* eUserpref_UI_Flag2 */ - int language; + /* Experimental flag for app-templates to make changes to behavior + * which are outside the scope of typical preferences. */ + short app_flag; + short language; short userpref, viewzoom; int mixbufsize; @@ -503,13 +506,15 @@ typedef struct UserDef { char keyconfigstr[64]; short undosteps; - short undomemory; + short pad1; + int undomemory; + int pad3; short gp_manhattendist, gp_euclideandist, gp_eraser; short gp_settings; /* eGP_UserdefSettings */ short tb_leftmouse, tb_rightmouse; struct SolidLight light[3]; short manipulator_flag, manipulator_size; - int pad3; + int pad6; short textimeout, texcollectrate; short wmdrawmethod; /* eWM_DrawMethod */ short dragthreshold; @@ -678,15 +683,17 @@ typedef enum eUserpref_UI_Flag { USER_DRAWVIEWINFO = (1 << 4), USER_PLAINMENUS = (1 << 5), USER_LOCK_CURSOR_ADJUST = (1 << 6), - USER_UIFLAG_DEPRECATED_7 = (1 << 7), /* cleared */ + /* Avoid accidentally adjusting the layout + * (exact behavior may change based on whats considered reasonable to lock down). */ + USER_UIFLAG_DEPRECATED_7 = (1 << 7), USER_ALLWINCODECS = (1 << 8), USER_MENUOPENAUTO = (1 << 9), - USER_ZBUF_CURSOR = (1 << 10), + USER_DEPTH_CURSOR = (1 << 10), USER_AUTOPERSP = (1 << 11), USER_LOCKAROUND = (1 << 12), USER_GLOBALUNDO = (1 << 13), USER_ORBIT_SELECTION = (1 << 14), - USER_ZBUF_ORBIT = (1 << 15), + USER_DEPTH_NAVIGATE = (1 << 15), USER_HIDE_DOT = (1 << 16), USER_SHOW_ROTVIEWICON = (1 << 17), USER_SHOW_VIEWPORTNAME = (1 << 18), @@ -711,7 +718,13 @@ typedef enum eUserpref_UI_Flag2 { USER_REGION_OVERLAP = (1 << 1), USER_TRACKPAD_NATURAL = (1 << 2), } eUserpref_UI_Flag2; - + +/* UserDef.app_flag */ +typedef enum eUserpref_APP_Flag { + USER_APP_LOCK_UI_LAYOUT = (1 << 0), + USER_APP_VIEW3D_HIDE_CURSOR = (1 << 1), +} eUserpref_APP_Flag; + /* Auto-Keying mode. * UserDef.autokey_mode */ typedef enum eAutokey_Mode { @@ -818,8 +831,9 @@ typedef enum eGP_UserdefSettings { } eGP_UserdefSettings; enum { - USER_MANIPULATOR_DRAW = (1 << 0), - USER_MANIPULATOR_SHADED = (1 << 1), + USER_MANIPULATOR_DRAW = (1 << 0), + USER_MANIPULATOR_DRAW_NAVIGATE = (1 << 1), + USER_MANIPULATOR_SHADED = (1 << 8), }; /* Color Picker Types. @@ -833,7 +847,7 @@ typedef enum eColorPicker_Types { } eColorPicker_Types; /* timecode display styles - * UserDef.timecode_style */ + * UserDef.timecode_style */ typedef enum eTimecodeStyles { /* as little info as is necessary to show relevant info * with '+' to denote the frames diff --git a/source/blender/makesdna/DNA_windowmanager_types.h b/source/blender/makesdna/DNA_windowmanager_types.h index 3792873db31..4332959bd9a 100644 --- a/source/blender/makesdna/DNA_windowmanager_types.h +++ b/source/blender/makesdna/DNA_windowmanager_types.h @@ -231,6 +231,9 @@ typedef struct wmWindow { ListBase global_areas; struct Stereo3dFormat *stereo3d_format; /* properties for stereoscopic displays */ + + /* custom drawing callbacks */ + ListBase drawcalls; } wmWindow; #ifdef ime_data @@ -410,13 +413,15 @@ enum { /* low level flag so exec() operators can tell if they were invoked, use with care. * typically this shouldn't make any difference, but it rare cases its needed (see smooth-view) */ OP_IS_INVOKE = (1 << 0), + /* So we can detect if an operators exec() call is activated from an interactive repeat. */ + OP_IS_REPEAT = (1 << 1), /* When the cursor is grabbed */ - OP_IS_MODAL_GRAB_CURSOR = (1 << 1), + OP_IS_MODAL_GRAB_CURSOR = (1 << 2), /* allow modal operators to have the region under the cursor for their context * (the regiontype is maintained to prevent errors) */ - OP_IS_MODAL_CURSOR_REGION = (1 << 2), + OP_IS_MODAL_CURSOR_REGION = (1 << 3), }; #endif /* __DNA_WINDOWMANAGER_TYPES_H__ */ diff --git a/source/blender/makesdna/intern/dna_genfile.c b/source/blender/makesdna/intern/dna_genfile.c index ac932a8daaf..199bb75d099 100644 --- a/source/blender/makesdna/intern/dna_genfile.c +++ b/source/blender/makesdna/intern/dna_genfile.c @@ -173,7 +173,9 @@ void DNA_sdna_free(SDNA *sdna) MEM_freeN(sdna->structs); #ifdef WITH_DNA_GHASH - BLI_ghash_free(sdna->structs_map, NULL, NULL); + if (sdna->structs_map) { + BLI_ghash_free(sdna->structs_map, NULL, NULL); + } #endif MEM_freeN(sdna); diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h index a99541385d0..816a472559f 100644 --- a/source/blender/makesrna/RNA_access.h +++ b/source/blender/makesrna/RNA_access.h @@ -944,6 +944,7 @@ float RNA_property_float_get_default_index(PointerRNA *ptr, PropertyRNA *prop, i void RNA_property_string_get(PointerRNA *ptr, PropertyRNA *prop, char *value); char *RNA_property_string_get_alloc(PointerRNA *ptr, PropertyRNA *prop, char *fixedbuf, int fixedlen, int *r_len); void RNA_property_string_set(PointerRNA *ptr, PropertyRNA *prop, const char *value); +void RNA_property_string_set_bytes(PointerRNA *ptr, PropertyRNA *prop, const char *value, int len); int RNA_property_string_length(PointerRNA *ptr, PropertyRNA *prop); void RNA_property_string_get_default(PointerRNA *ptr, PropertyRNA *prop, char *value); char *RNA_property_string_get_default_alloc(PointerRNA *ptr, PropertyRNA *prop, char *fixedbuf, int fixedlen); @@ -1251,27 +1252,44 @@ typedef enum eRNACompareMode { RNA_EQ_COMPARE, } eRNACompareMode; -bool RNA_property_equals(struct PointerRNA *a, struct PointerRNA *b, struct PropertyRNA *prop, eRNACompareMode mode); -bool RNA_struct_equals(struct PointerRNA *a, struct PointerRNA *b, eRNACompareMode mode); +bool RNA_property_equals(struct PointerRNA *ptr_a, struct PointerRNA *ptr_b, struct PropertyRNA *prop, eRNACompareMode mode); +bool RNA_struct_equals(struct PointerRNA *ptr_a, struct PointerRNA *ptr_b, eRNACompareMode mode); /* Override. */ -bool RNA_struct_override_matches(struct PointerRNA *local, struct PointerRNA *reference, - struct IDOverrideStatic *override, const bool ignore_non_overridable, const bool ignore_overridden); +/* flags for RNA_struct_override_matches. */ +typedef enum eRNAOverrideMatch { + /* Do not compare properties that are not overridable. */ + RNA_OVERRIDE_COMPARE_IGNORE_NON_OVERRIDABLE = 1 << 0, + /* Do not compare properties that are already overridden. */ + RNA_OVERRIDE_COMPARE_IGNORE_OVERRIDDEN = 1 << 1, + + /* Create new property override if needed and possible. */ + RNA_OVERRIDE_COMPARE_CREATE = 1 << 16, + /* Restore property's value(s) to reference ones if needed and possible. */ + RNA_OVERRIDE_COMPARE_RESTORE = 1 << 17, +} eRNAOverrideMatch; + +typedef enum eRNAOverrideMatchResult { + /* Some new property overrides were created to take into account differences between local and reference. */ + RNA_OVERRIDE_MATCH_RESULT_CREATED = 1 << 0, + /* Some properties were reset to reference values. */ + RNA_OVERRIDE_MATCH_RESULT_RESTORED = 1 << 1, +} eRNAOverrideMatchResult; + +bool RNA_struct_override_matches( + struct PointerRNA *ptr_local, struct PointerRNA *ptr_reference, const char *root_path, + struct IDOverrideStatic *override, const eRNAOverrideMatch flags, + eRNAOverrideMatchResult *r_report_flags); bool RNA_struct_override_store( - struct PointerRNA *local, struct PointerRNA *reference, PointerRNA *storage, struct IDOverrideStatic *override); + struct PointerRNA *ptr_local, struct PointerRNA *ptr_reference, PointerRNA *ptr_storage, + struct IDOverrideStatic *override); -void RNA_property_override_apply( - struct PointerRNA *dst, struct PointerRNA *src, struct PointerRNA *storage, struct PropertyRNA *prop, - struct IDOverrideStaticProperty *op); void RNA_struct_override_apply( - struct PointerRNA *dst, struct PointerRNA *src, struct PointerRNA *storage, + struct PointerRNA *ptr_local, struct PointerRNA *ptr_reference, struct PointerRNA *ptr_storage, struct IDOverrideStatic *override); -bool RNA_struct_auto_override( - struct PointerRNA *local, struct PointerRNA *reference, struct IDOverrideStatic *override, const char *root_path); - struct IDOverrideStaticProperty *RNA_property_override_property_find(PointerRNA *ptr, PropertyRNA *prop); struct IDOverrideStaticProperty *RNA_property_override_property_get(PointerRNA *ptr, PropertyRNA *prop, bool *r_created); diff --git a/source/blender/makesrna/RNA_types.h b/source/blender/makesrna/RNA_types.h index 47aebbc13e7..e0824281656 100644 --- a/source/blender/makesrna/RNA_types.h +++ b/source/blender/makesrna/RNA_types.h @@ -158,7 +158,7 @@ typedef enum PropertySubType { /* Make sure enums are updated with these */ /* HIGHEST FLAG IN USE: 1 << 31 - * FREE FLAGS: 3, 7, 9, 11, 13, 14, 15, 30 */ + * FREE FLAGS: 3, 9, 11, 13, 14, 15, 30 */ typedef enum PropertyFlag { /* editable means the property is editable in the user * interface, properties are editable by default except @@ -213,6 +213,13 @@ typedef enum PropertyFlag { * but setting NULL on a mesh object is not possible. So, if its not NULL, setting NULL cant be done! */ PROP_NEVER_UNLINK = (1 << 25), + /* Pointers to data that is not owned by the struct. + * Typical example: Bone.parent, Bone.child, etc., and nearly all ID pointers. + * This is crucial information for processes that walk the whole data of an ID e.g. (like static override). + * Note that all ID pointers are enforced to this by default, this probably will need to be rechecked + * (see ugly infamous NodeTrees of mat/tex/scene/etc.). */ + PROP_PTR_NO_OWNERSHIP = (1 << 7), + /* flag contains multiple enums. * note: not to be confused with prop->enumbitflags * this exposes the flag as multiple options in python and the UI. diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c index 19f66109665..9745ca39872 100644 --- a/source/blender/makesrna/intern/makesrna.c +++ b/source/blender/makesrna/intern/makesrna.c @@ -2995,6 +2995,28 @@ static void rna_generate_property(FILE *f, StructRNA *srna, const char *nest, Pr } break; } + case PROP_POINTER: + { + PointerPropertyRNA *pprop = (PointerPropertyRNA *)prop; + + /* XXX This systematically enforces that flag on ID pointers... we'll probably have to revisit. :/ */ + StructRNA *type = rna_find_struct((const char *)pprop->type); + if (type && (type->flag & STRUCT_ID)) { + prop->flag |= PROP_PTR_NO_OWNERSHIP; + } + break; + } + case PROP_COLLECTION: + { + CollectionPropertyRNA *cprop = (CollectionPropertyRNA *)prop; + + /* XXX This systematically enforces that flag on ID pointers... we'll probably have to revisit. :/ */ + StructRNA *type = rna_find_struct((const char *)cprop->item_type); + if (type && (type->flag & STRUCT_ID)) { + prop->flag |= PROP_PTR_NO_OWNERSHIP; + } + break; + } default: break; } diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c index 44df8916796..549c1a8b30d 100644 --- a/source/blender/makesrna/intern/rna_ID.c +++ b/source/blender/makesrna/intern/rna_ID.c @@ -318,7 +318,7 @@ static ID *rna_ID_override_create(ID *id, Main *bmain) return NULL; } - return BKE_override_static_create_from(bmain, id); + return BKE_override_static_create_from_id(bmain, id); } static void rna_ID_update_tag(ID *id, ReportList *reports, int flag) @@ -772,6 +772,27 @@ static PointerRNA rna_IDPreview_get(PointerRNA *ptr) return rna_pointer_inherit_refine(ptr, &RNA_ImagePreview, prv_img); } +static int rna_ID_is_updated_get(PointerRNA *ptr) +{ + ID *id = (ID *)ptr->data; + /* TODO(sergey): Do we need to limit some of flags here? */ + return ((id->recalc & ID_RECALC_ALL) != 0); +} + +static int rna_ID_is_updated_data_get(PointerRNA *ptr) +{ + ID *id = (ID *)ptr->data; + if (GS(id->name) != ID_OB) { + return 0; + } + Object *object = (Object *)id; + ID *data = object->data; + if (data == NULL) { + return 0; + } + return ((data->recalc & ID_RECALC_ALL) != 0); +} + static PointerRNA rna_ID_override_reference_get(PointerRNA *ptr) { ID *id = (ID *)ptr->data; @@ -1023,13 +1044,13 @@ static void rna_def_ID(BlenderRNA *brna) "(initial state is undefined)"); prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "tag", LIB_TAG_ID_RECALC); RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_boolean_funcs(prop, "rna_ID_is_updated_get", NULL); RNA_def_property_ui_text(prop, "Is Updated", "Data-block is tagged for recalculation"); prop = RNA_def_property(srna, "is_updated_data", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "tag", LIB_TAG_ID_RECALC_DATA); RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_boolean_funcs(prop, "rna_ID_is_updated_data_get", NULL); RNA_def_property_ui_text(prop, "Is Updated Data", "Data-block data is tagged for recalculation"); prop = RNA_def_property(srna, "is_library_indirect", PROP_BOOLEAN, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c index 345c3d23dbe..b8dbc69f352 100644 --- a/source/blender/makesrna/intern/rna_access.c +++ b/source/blender/makesrna/intern/rna_access.c @@ -42,6 +42,10 @@ #include "BLI_ghash.h" #include "BLI_math.h" +#ifdef DEBUG_OVERRIDE_TIMEIT +# include "PIL_time_utildefines.h" +#endif + #include "BLF_api.h" #include "BLT_translation.h" @@ -425,7 +429,7 @@ static PropertyRNA *arraytypemap[IDP_NUMTYPES] = { (PropertyRNA *)&rna_PropertyGroupItem_double_array }; -IDProperty *rna_idproperty_check(PropertyRNA **prop, PointerRNA *ptr) +static void *rna_idproperty_check_ex(PropertyRNA **prop, PointerRNA *ptr, const bool return_rnaprop) { /* This is quite a hack, but avoids some complexity in the API. we * pass IDProperty structs as PropertyRNA pointers to the outside. @@ -448,7 +452,7 @@ IDProperty *rna_idproperty_check(PropertyRNA **prop, PointerRNA *ptr) return idprop; } else - return NULL; + return return_rnaprop ? *prop : NULL; } { @@ -463,6 +467,19 @@ IDProperty *rna_idproperty_check(PropertyRNA **prop, PointerRNA *ptr) } } +/* This function only returns an IDProperty, + * or NULL (in case IDProp could not be found, or prop is a real RNA property). */ +IDProperty *rna_idproperty_check(PropertyRNA **prop, PointerRNA *ptr) +{ + return rna_idproperty_check_ex(prop, ptr, false); +} + +/* This function always return the valid, real data pointer, be it a regular RNA property one, or an IDProperty one. */ +PropertyRNA *rna_ensure_property_realdata(PropertyRNA **prop, PointerRNA *ptr) +{ + return rna_idproperty_check_ex(prop, ptr, true); +} + static PropertyRNA *rna_ensure_property(PropertyRNA *prop) { /* the quick version if we don't need the idproperty */ @@ -775,7 +792,7 @@ FunctionRNA *RNA_struct_find_function(StructRNA *srna, const char *identifier) } return NULL; - /* funcitonal but slow */ + /* functional but slow */ #else PointerRNA tptr; PropertyRNA *iterprop; @@ -3026,6 +3043,42 @@ void RNA_property_string_set(PointerRNA *ptr, PropertyRNA *prop, const char *val } } +void RNA_property_string_set_bytes(PointerRNA *ptr, PropertyRNA *prop, const char *value, int len) +{ + StringPropertyRNA *sprop = (StringPropertyRNA *)prop; + IDProperty *idprop; + + BLI_assert(RNA_property_type(prop) == PROP_STRING); + BLI_assert(RNA_property_subtype(prop) == PROP_BYTESTRING); + + if ((idprop = rna_idproperty_check(&prop, ptr))) { + IDP_ResizeArray(idprop, len); + memcpy(idprop->data.pointer, value, (size_t)len); + + rna_idproperty_touch(idprop); + } + else if (sprop->set) { + /* XXX, should take length argument (currently not used). */ + sprop->set(ptr, value); /* set function needs to clamp its self */ + } + else if (sprop->set_ex) { + /* XXX, should take length argument (currently not used). */ + sprop->set_ex(ptr, prop, value); /* set function needs to clamp its self */ + } + else if (prop->flag & PROP_EDITABLE) { + IDProperty *group; + + group = RNA_struct_idprops(ptr, 1); + if (group) { + IDPropertyTemplate val = {0}; + val.string.str = value; + val.string.len = len; + val.string.subtype = IDP_STRING_SUB_BYTE; + IDP_AddToGroup(group, IDP_New(IDP_STRING, &val, prop->identifier)); + } + } +} + void RNA_property_string_get_default(PointerRNA *UNUSED(ptr), PropertyRNA *prop, char *value) { StringPropertyRNA *sprop = (StringPropertyRNA *)rna_ensure_property(prop); @@ -5767,13 +5820,10 @@ char *RNA_pointer_as_string_id(bContext *C, PointerRNA *ptr) static char *rna_pointer_as_string__bldata(PointerRNA *ptr) { - if (ptr->type == NULL) { + if (ptr->type == NULL || ptr->id.data == NULL) { return BLI_strdup("None"); } else if (RNA_struct_is_ID(ptr->type)) { - if (ptr->id.data == NULL) { - return BLI_strdup("None"); - } return RNA_path_full_ID_py(ptr->id.data); } else { @@ -6986,7 +7036,8 @@ bool RNA_property_reset(PointerRNA *ptr, PropertyRNA *prop, int index) } static bool rna_property_override_operation_apply( - PointerRNA *ptr_local, PointerRNA *ptr_reference, PointerRNA *ptr_storage, PropertyRNA *prop_local, + PointerRNA *ptr_local, PointerRNA *ptr_reference, PointerRNA *ptr_storage, + PropertyRNA *prop_local, PropertyRNA *prop_reference, PropertyRNA *prop_storage, IDOverrideStaticPropertyOperation *opop); bool RNA_property_copy(PointerRNA *ptr, PointerRNA *fromptr, PropertyRNA *prop, int index) @@ -6995,12 +7046,23 @@ bool RNA_property_copy(PointerRNA *ptr, PointerRNA *fromptr, PropertyRNA *prop, return false; } + PropertyRNA *prop_dst = prop; + PropertyRNA *prop_src = prop; + + /* Ensure we get real property data, be it an actual RNA property, or an IDProperty in disguise. */ + prop_dst = rna_ensure_property_realdata(&prop_dst, ptr); + prop_src = rna_ensure_property_realdata(&prop_src, fromptr); + + if (ELEM(NULL, prop_dst, prop_src)) { + false; + } + IDOverrideStaticPropertyOperation opop = { .operation = IDOVERRIDESTATIC_OP_REPLACE, .subitem_reference_index = index, .subitem_local_index = index }; - return rna_property_override_operation_apply(ptr, fromptr, NULL, prop, &opop); + return rna_property_override_operation_apply(ptr, fromptr, NULL, prop_dst, prop_src, NULL, &opop); } /* use RNA_warning macro which includes __func__ suffix */ @@ -7026,36 +7088,36 @@ void _RNA_warning(const char *format, ...) } static int rna_property_override_diff( - PointerRNA *a, PointerRNA *b, PropertyRNA *prop, eRNACompareMode mode, - IDOverrideStatic *override, const char *rna_path, bool *r_override_changed, const int flags); + PointerRNA *ptr_a, PointerRNA *ptr_b, PropertyRNA *prop, PropertyRNA *prop_a, PropertyRNA *prop_b, const char *rna_path, + eRNACompareMode mode, IDOverrideStatic *override, const int flags, eRNAOverrideMatchResult *r_report_flags); -bool RNA_property_equals(PointerRNA *a, PointerRNA *b, PropertyRNA *prop, eRNACompareMode mode) +bool RNA_property_equals(PointerRNA *ptr_a, PointerRNA *ptr_b, PropertyRNA *prop, eRNACompareMode mode) { BLI_assert(ELEM(mode, RNA_EQ_STRICT, RNA_EQ_UNSET_MATCH_ANY, RNA_EQ_UNSET_MATCH_NONE)); - return (rna_property_override_diff(a, b, prop, mode, NULL, NULL, NULL, 0) != 0); + return (rna_property_override_diff(ptr_a, ptr_b, prop, NULL, NULL, NULL, mode, NULL, 0, NULL) == 0); } -bool RNA_struct_equals(PointerRNA *a, PointerRNA *b, eRNACompareMode mode) +bool RNA_struct_equals(PointerRNA *ptr_a, PointerRNA *ptr_b, eRNACompareMode mode) { CollectionPropertyIterator iter; PropertyRNA *iterprop; bool equals = true; - if (a == NULL && b == NULL) + if (ptr_a == NULL && ptr_b == NULL) return true; - else if (a == NULL || b == NULL) + else if (ptr_a == NULL || ptr_b == NULL) return false; - else if (a->type != b->type) + else if (ptr_a->type != ptr_b->type) return false; - iterprop = RNA_struct_iterator_property(a->type); + iterprop = RNA_struct_iterator_property(ptr_a->type); - RNA_property_collection_begin(a, iterprop, &iter); + RNA_property_collection_begin(ptr_a, iterprop, &iter); for (; iter.valid; RNA_property_collection_next(&iter)) { PropertyRNA *prop = iter.ptr.data; - if (!RNA_property_equals(a, b, prop, mode)) { + if (!RNA_property_equals(ptr_a, ptr_b, prop, mode)) { equals = false; break; } @@ -7066,84 +7128,133 @@ bool RNA_struct_equals(PointerRNA *a, PointerRNA *b, eRNACompareMode mode) } /* Low-level functions, also used by non-override RNA API like copy or equality check. */ -#include "PIL_time_utildefines.h" + +/** Generic RNA property diff function. + * + * \note about \a prop and \a prop_a/prop_b parameters: the former is exptected to be an 'un-resolved' one, + * while the two laters are expected to be fully resolved ones (i.e. to be the IDProps when they should be, etc.). + * When \a prop is given, \a prop_a and \a prop_b should always be NULL, and vice-versa. + * This is necessary, because we cannot perform 'set/unset' checks on resolved properties + * (unset IDProps would merely be NULL then). + */ static int rna_property_override_diff( - PointerRNA *ptr_a, PointerRNA *ptr_b, PropertyRNA *prop_a, eRNACompareMode mode, - IDOverrideStatic *override, const char *rna_path, bool *r_override_changed, const int flags) + PointerRNA *ptr_a, PointerRNA *ptr_b, PropertyRNA *prop, PropertyRNA *prop_a, PropertyRNA *prop_b, const char *rna_path, + eRNACompareMode mode, IDOverrideStatic *override, const int flags, eRNAOverrideMatchResult *r_report_flags) { - int len_a, len_b; - - PropertyRNA *prop_b = prop_a; - - if (prop_a->magic != RNA_MAGIC) { - /* In case of IDProperty, we have to find the *real* idprop of ptr, - * since prop in this case is just a fake wrapper around actual IDProp data, and not a 'real' PropertyRNA. */ - /* XXX TODO this is ugly, we already get correct prop in upcalling code, whould just pass them to this func! */ - prop_a = (PropertyRNA *)rna_idproperty_find(ptr_a, ((IDProperty *)prop_a)->name); - prop_b = (PropertyRNA *)rna_idproperty_find(ptr_b, ((IDProperty *)prop_b)->name); - - if (ELEM(NULL, prop_a, prop_b)) { - return 1; - } + if (prop != NULL) { + BLI_assert(prop_a == NULL && prop_b == NULL); + prop_a = prop; + prop_b = prop; } - BLI_assert(prop_a->override_diff == prop_b->override_diff && prop_a->override_diff != NULL); + if (ELEM(NULL, prop_a, prop_b)) { + return (prop_a == prop_b) ? 0 : 1; + } if (mode == RNA_EQ_UNSET_MATCH_ANY) { /* uninitialized properties are assumed to match anything */ - if (!RNA_property_is_set(ptr_a, prop_a) || !RNA_property_is_set(ptr_b, prop_b)) + if (!RNA_property_is_set(ptr_a, prop_a) || !RNA_property_is_set(ptr_b, prop_b)) { return 0; + } } else if (mode == RNA_EQ_UNSET_MATCH_NONE) { /* unset properties never match set properties */ - if (RNA_property_is_set(ptr_a, prop_a) != RNA_property_is_set(ptr_b, prop_b)) + if (RNA_property_is_set(ptr_a, prop_a) != RNA_property_is_set(ptr_b, prop_b)) { return 1; + } } - /* get the length of the array to work with */ - len_a = RNA_property_array_length(ptr_a, prop_a); - len_b = RNA_property_array_length(ptr_b, prop_b); + if (prop != NULL) { + /* Ensure we get real property data, be it an actual RNA property, or an IDProperty in disguise. */ + prop_a = rna_ensure_property_realdata(&prop_a, ptr_a); + prop_b = rna_ensure_property_realdata(&prop_b, ptr_b); + + if (ELEM(NULL, prop_a, prop_b)) { + return (prop_a == prop_b) ? 0 : 1; + } + } + + /* Check if we are working with arrays. */ + const bool is_array_a = RNA_property_array_check(prop_a); + const bool is_array_b = RNA_property_array_check(prop_b); + + if (is_array_a != is_array_b) { + /* Should probably never happen actually... */ + BLI_assert(0); + return is_array_a ? 1 : -1; + } + + /* Get the length of the array to work with. */ + const int len_a = RNA_property_array_length(ptr_a, prop_a); + const int len_b = RNA_property_array_length(ptr_b, prop_b); if (len_a != len_b) { /* Do not handle override in that case, we do not support insertion/deletion from arrays for now. */ return len_a > len_b ? 1 : -1; } - return prop_a->override_diff( - ptr_a, ptr_b, prop_a, prop_b, len_a, len_b, mode, override, rna_path, flags, r_override_changed); + if (is_array_a && len_a == 0) { + /* Empty arrays, will happen in some case with dynamic ones. */ + return 0; + } + + RNAPropOverrideDiff override_diff = NULL; + /* Special case for IDProps, we use default callback then. */ + if (prop_a->magic != RNA_MAGIC) { + override_diff = rna_property_override_diff_default; + if (prop_b->magic == RNA_MAGIC && prop_b->override_diff != override_diff) { + override_diff = NULL; + } + } + else if (prop_b->magic != RNA_MAGIC) { + override_diff = rna_property_override_diff_default; + if (prop_a->override_diff != override_diff) { + override_diff = NULL; + } + } + else if (prop_a->override_diff == prop_b->override_diff) { + override_diff = prop_a->override_diff; + } + + if (override_diff == NULL) { +#ifndef NDEBUG + printf("'%s' gives unmatching or NULL RNA diff callbacks, should not happen (%d vs. %d).\n", + rna_path ? rna_path : (prop_a->magic != RNA_MAGIC ? ((IDProperty *)prop_a)->name : prop_a->identifier), + prop_a->magic == RNA_MAGIC, prop_b->magic == RNA_MAGIC); +#endif + BLI_assert(0); + return 1; + } + + bool override_changed = false; + int diff_flags = flags; + if ((RNA_property_flag(prop_a) & PROP_OVERRIDABLE_STATIC) == 0) { + diff_flags &= ~RNA_OVERRIDE_COMPARE_CREATE; + } + const int diff = override_diff( + ptr_a, ptr_b, prop_a, prop_b, len_a, len_b, + mode, override, rna_path, diff_flags, &override_changed); + if (override_changed && r_report_flags) { + *r_report_flags |= RNA_OVERRIDE_MATCH_RESULT_CREATED; + } + + return diff; } /* Modify local data-block to make it ready for override application (only needed for diff operations, where we use * the local data-block's data as second operand). */ static bool rna_property_override_operation_store( - PointerRNA *ptr_local, PointerRNA *ptr_reference, PointerRNA *ptr_storage, PropertyRNA *prop_local, + PointerRNA *ptr_local, PointerRNA *ptr_reference, PointerRNA *ptr_storage, + PropertyRNA *prop_local, PropertyRNA *prop_reference, PropertyRNA *prop_storage, IDOverrideStaticProperty *op) { int len_local, len_reference, len_storage = 0; - PropertyRNA *prop_reference = prop_local; - PropertyRNA *prop_storage = prop_local; bool changed = false; - if (!ptr_storage) { + if (ptr_storage == NULL) { return changed; } - if (prop_local->magic != RNA_MAGIC) { - /* In case of IDProperty, we have to find the *real* idprop of ptr, - * since prop in this case is just a fake wrapper around actual IDProp data, and not a 'real' PropertyRNA. */ - /* XXX TODO this is ugly, we already get correct prop in upcalling code, should just pass them to this func! */ - prop_local = (PropertyRNA *)rna_idproperty_find(ptr_local, ((IDProperty *)prop_local)->name); - prop_reference = (PropertyRNA *)rna_idproperty_find(ptr_reference, ((IDProperty *)prop_reference)->name); - if (ptr_storage) { - prop_storage = (PropertyRNA *)rna_idproperty_find(ptr_storage, ((IDProperty *)prop_storage)->name); - } - - /* its possible the custom-prop doesn't exist on this data-block */ - if (prop_local == NULL) { - return changed; - } - } - /* get the length of the array to work with */ len_local = RNA_property_array_length(ptr_local, prop_local); len_reference = RNA_property_array_length(ptr_reference, prop_reference); @@ -7178,12 +7289,11 @@ static bool rna_property_override_operation_store( } static bool rna_property_override_operation_apply( - PointerRNA *ptr_local, PointerRNA *ptr_reference, PointerRNA *ptr_storage, PropertyRNA *prop_local, + PointerRNA *ptr_local, PointerRNA *ptr_reference, PointerRNA *ptr_storage, + PropertyRNA *prop_local, PropertyRNA *prop_reference, PropertyRNA *prop_storage, IDOverrideStaticPropertyOperation *opop) { int len_local, len_reference, len_storage = 0; - PropertyRNA *prop_reference = prop_local; - PropertyRNA *prop_storage = prop_local; const short override_op = opop->operation; @@ -7197,25 +7307,41 @@ static bool rna_property_override_operation_apply( return false; } + if (ELEM(override_op, IDOVERRIDESTATIC_OP_ADD, IDOVERRIDESTATIC_OP_SUBTRACT, IDOVERRIDESTATIC_OP_MULTIPLY) && !prop_storage) { + /* We cannot apply 'diff' override operations without some refference storage. + * This should typically only happen at read time of .blend file... */ + return false; + } + + RNAPropOverrideApply override_apply = NULL; + /* Special case for IDProps, we use default callback then. */ if (prop_local->magic != RNA_MAGIC) { - /* In case of IDProperty, we have to find the *real* idprop of ptr, - * since prop in this case is just a fake wrapper around actual IDProp data, and not a 'real' PropertyRNA. */ - /* XXX TODO this is ugly, we already get correct prop in upcalling code, whould just pass them to this func! */ - prop_local = (PropertyRNA *)rna_idproperty_find(ptr_local, ((IDProperty *)prop_local)->name); - prop_reference = (PropertyRNA *)rna_idproperty_find(ptr_reference, ((IDProperty *)prop_reference)->name); - if (ptr_storage) { - prop_storage = (PropertyRNA *)rna_idproperty_find(ptr_storage, ((IDProperty *)prop_storage)->name); + override_apply = rna_property_override_apply_default; + if (prop_reference->magic == RNA_MAGIC && prop_reference->override_apply != override_apply) { + override_apply = NULL; } - - /* its possible the custom-prop doesn't exist on this data-block */ - if (prop_local == NULL) { - return false; + } + else if (prop_reference->magic != RNA_MAGIC) { + override_apply = rna_property_override_apply_default; + if (prop_local->override_apply != override_apply) { + override_apply = NULL; } } + else if (prop_local->override_apply == prop_reference->override_apply) { + override_apply = prop_local->override_apply; + } - if (ELEM(override_op, IDOVERRIDESTATIC_OP_ADD, IDOVERRIDESTATIC_OP_SUBTRACT, IDOVERRIDESTATIC_OP_MULTIPLY) && !prop_storage) { - /* We cannot apply 'diff' override operations without some refference storage. - * This should typically only happen at read time of .blend file... */ + if (ptr_storage && prop_storage->magic == RNA_MAGIC && prop_storage->override_apply != override_apply) { + override_apply = NULL; + } + + if (override_apply == NULL) { +#ifndef NDEBUG + printf("'%s' gives unmatching or NULL RNA copy callbacks, should not happen (%d vs. %d).\n", + prop_local->magic != RNA_MAGIC ? ((IDProperty *)prop_local)->name : prop_local->identifier, + prop_local->magic == RNA_MAGIC, prop_reference->magic == RNA_MAGIC); +#endif + BLI_assert(0); return false; } @@ -7231,71 +7357,167 @@ static bool rna_property_override_operation_apply( return false; } - BLI_assert(prop_local->override_apply == prop_reference->override_apply && - (!ptr_storage || prop_local->override_apply == prop_storage->override_apply) && - prop_local->override_apply != NULL); - /* get and set the default values as appropriate for the various types */ - return prop_local->override_apply( + return override_apply( ptr_local, ptr_reference, ptr_storage, prop_local, prop_reference, prop_storage, len_local, len_reference, len_storage, opop); } - /** * Check whether reference and local overriden data match (are the same), - * with respect to given restrictive sets of properties. */ + * with respect to given restrictive sets of properties. + * If requested, will generate needed new property overrides, and/or restore values from reference. + * + * \param r_report_flags If given, will be set with flags matching actions taken by the function on \a ptr_local. + * + * \return True if _resulting_ \a ptr_local does match \a ptr_reference. + */ bool RNA_struct_override_matches( - PointerRNA *local, PointerRNA *reference, - IDOverrideStatic *override, const bool ignore_non_overridable, const bool ignore_overridden) + PointerRNA *ptr_local, PointerRNA *ptr_reference, const char *root_path, + IDOverrideStatic *override, const eRNAOverrideMatch flags, + eRNAOverrideMatchResult *r_report_flags) { CollectionPropertyIterator iter; PropertyRNA *iterprop; - bool equals = true; + bool matching = true; - BLI_assert(local->type == reference->type); + BLI_assert(ptr_local->type == ptr_reference->type); + BLI_assert(ptr_local->id.data && ptr_reference->id.data); - iterprop = RNA_struct_iterator_property(local->type); + const bool ignore_non_overridable = (flags & RNA_OVERRIDE_COMPARE_IGNORE_NON_OVERRIDABLE) != 0; + const bool ignore_overridden = (flags & RNA_OVERRIDE_COMPARE_IGNORE_OVERRIDDEN) != 0; + const bool do_create = (flags & RNA_OVERRIDE_COMPARE_CREATE) != 0; + const bool do_restore = (flags & RNA_OVERRIDE_COMPARE_RESTORE) != 0; - RNA_property_collection_begin(local, iterprop, &iter); - for (; iter.valid; RNA_property_collection_next(&iter)) { - PropertyRNA *prop = iter.ptr.data; +#ifdef DEBUG_OVERRIDE_TIMEIT + static float _sum_time = 0.0f; + static float _num_time = 0.0f; + double _timeit_time; + if (!root_path) { + _timeit_time = PIL_check_seconds_timer(); + } +#endif + + iterprop = RNA_struct_iterator_property(ptr_local->type); + + for (RNA_property_collection_begin(ptr_local, iterprop, &iter); iter.valid; RNA_property_collection_next(&iter)) { + PropertyRNA *prop_local = iter.ptr.data; + PropertyRNA *prop_reference = iter.ptr.data; - if (ignore_non_overridable && !(prop->flag & PROP_OVERRIDABLE_STATIC)) { + /* Ensure we get real property data, be it an actual RNA property, or an IDProperty in disguise. */ + prop_local = rna_ensure_property_realdata(&prop_local, ptr_local); + prop_reference = rna_ensure_property_realdata(&prop_reference, ptr_reference); + + if (ELEM(NULL, prop_local, prop_reference)) { continue; } - if (ignore_overridden) { - /* XXX TODO this will have to be refined to handle collections insertions, and array items */ - char *rna_path = RNA_path_from_ID_to_property(local, prop); - if (BKE_override_static_property_find(override, rna_path) != NULL) { - MEM_SAFE_FREE(rna_path); - continue; - } - MEM_SAFE_FREE(rna_path); + if (ignore_non_overridable && !(prop_local->flag & PROP_OVERRIDABLE_STATIC)) { + continue; } - int flag = 0; - if (ignore_non_overridable) { - flag |= RNA_OVERRIDE_COMPARE_IGNORE_NON_OVERRIDABLE; + if (RNA_property_animated(ptr_local, prop_local)) { + /* We cannot do anything here really, animation is some kind of dynamic overrides that has + * precedence over static one... */ + continue; } - if (ignore_overridden) { - flag |= RNA_OVERRIDE_COMPARE_IGNORE_OVERRIDDEN; + + /* XXX TODO this will have to be refined to handle collections insertions, and array items */ + char *rna_path; + if (root_path) { + /* Inlined building, much much more efficient. */ + if (prop_local->magic == RNA_MAGIC) { + rna_path = BLI_sprintfN("%s.%s", root_path, RNA_property_identifier(prop_local)); + } + else { + rna_path = BLI_sprintfN("%s[\"%s\"]", root_path, RNA_property_identifier(prop_local)); + } } - if (rna_property_override_diff(local, reference, prop, RNA_EQ_STRICT, override, NULL, NULL, flag) != 0) { - equals = false; - break; + else { + rna_path = RNA_path_from_ID_to_property(ptr_local, prop_local); } + if (rna_path == NULL) { + continue; + } + + if (ignore_overridden && BKE_override_static_property_find(override, rna_path) != NULL) { + MEM_SAFE_FREE(rna_path); + continue; + } + + eRNAOverrideMatchResult report_flags = 0; + const int diff = rna_property_override_diff( + ptr_local, ptr_reference, NULL, prop_local, prop_reference, rna_path, + RNA_EQ_STRICT, override, flags, &report_flags); + + matching = matching && diff == 0; + if (r_report_flags) { + *r_report_flags |= report_flags; + } + + if (diff != 0) { + /* XXX TODO: refine this for per-item overriding of arrays... */ + IDOverrideStaticProperty *op = BKE_override_static_property_find(override, rna_path); + IDOverrideStaticPropertyOperation *opop = op ? op->operations.first : NULL; + + if (do_restore && (report_flags & RNA_OVERRIDE_MATCH_RESULT_CREATED) == 0) { + /* We are allowed to restore to reference's values. */ + if (ELEM(NULL, op, opop) || opop->operation == IDOVERRIDESTATIC_OP_NOOP) { + /* We should restore that property to its reference value */ + if (RNA_property_editable(ptr_local, prop_local)) { + IDOverrideStaticPropertyOperation opop_tmp = { + .operation = IDOVERRIDESTATIC_OP_REPLACE, + .subitem_reference_index = -1, + .subitem_local_index = -1 + }; + rna_property_override_operation_apply(ptr_local, ptr_reference, NULL, + prop_local, prop_reference, NULL, &opop_tmp); + if (r_report_flags) { + *r_report_flags |= RNA_OVERRIDE_MATCH_RESULT_RESTORED; + } + } + else { + /* Too noisy for now, this triggers on runtime props like transform matrices etc. */ + /* BLI_assert(!"We have differences between reference and overriding data on non-editable property."); */ + matching = false; + } + } + } + else if ((report_flags & RNA_OVERRIDE_MATCH_RESULT_CREATED) == 0 && ELEM(NULL, op, opop)) { + /* This property is not overridden, and differs from reference, so we have no match. */ + matching = false; + if (!(do_create || do_restore)) { + /* Since we have no 'changing' action allowed, we can break here. */ + MEM_SAFE_FREE(rna_path); + break; + } + } + } + + MEM_SAFE_FREE(rna_path); } RNA_property_collection_end(&iter); - return equals; +#ifdef DEBUG_OVERRIDE_TIMEIT + if (!root_path) { + const float _delta_time = (float)(PIL_check_seconds_timer() - _timeit_time); + _sum_time += _delta_time; + _num_time++; + printf("ID: %s\n", ((ID *)ptr_local->id.data)->name); + printf("time end (%s): %.6f\n", __func__, _delta_time); + printf("time averaged (%s): %.6f (total: %.6f, in %d runs)\n", __func__, (_sum_time / _num_time), _sum_time, (int)_num_time); + } +#endif + + return matching; } + /** Store needed second operands into \a storage data-block for differential override operations. */ -bool RNA_struct_override_store(PointerRNA *local, PointerRNA *reference, PointerRNA *storage, IDOverrideStatic *override) +bool RNA_struct_override_store( + PointerRNA *ptr_local, PointerRNA *ptr_reference, PointerRNA *ptr_storage, IDOverrideStatic *override) { bool changed = false; @@ -7304,21 +7526,23 @@ bool RNA_struct_override_store(PointerRNA *local, PointerRNA *reference, Pointer #endif for (IDOverrideStaticProperty *op = override->properties.first; op; op = op->next) { /* Simplified for now! */ - PointerRNA src_data, dst_data; - PropertyRNA *src_prop, *dst_prop; + PointerRNA data_reference, data_local; + PropertyRNA *prop_reference, *prop_local; - if (RNA_path_resolve_property(reference, op->rna_path, &src_data, &src_prop) && - RNA_path_resolve_property(local, op->rna_path, &dst_data, &dst_prop)) + if (RNA_path_resolve_property(ptr_local, op->rna_path, &data_local, &prop_local) && + RNA_path_resolve_property(ptr_reference, op->rna_path, &data_reference, &prop_reference)) { - PointerRNA storage_data; - PropertyRNA *storage_prop = NULL; + PointerRNA data_storage; + PropertyRNA *prop_storage = NULL; /* It is totally OK if this does not success, only a subset of override operations actually need storage. */ - if (storage && (storage->id.data != NULL)) { - RNA_path_resolve_property(storage, op->rna_path, &storage_data, &storage_prop); + if (ptr_storage && (ptr_storage->id.data != NULL)) { + RNA_path_resolve_property(ptr_storage, op->rna_path, &data_storage, &prop_storage); } - if (rna_property_override_operation_store(&dst_data, &src_data, &storage_data, src_prop, op)) { + if (rna_property_override_operation_store(&data_local, &data_reference, &data_storage, + prop_reference, prop_local, prop_storage, op)) + { changed = true; } } @@ -7330,46 +7554,50 @@ bool RNA_struct_override_store(PointerRNA *local, PointerRNA *reference, Pointer return changed; } -/** Apply given \a op override property operations on \a dst, using \a src as source. */ -void RNA_property_override_apply( - PointerRNA *dst, PointerRNA *src, PointerRNA *storage, PropertyRNA *prop, IDOverrideStaticProperty *op) +static void rna_property_override_apply_ex( + PointerRNA *ptr_local, PointerRNA *ptr_reference, PointerRNA *ptr_storage, + PropertyRNA *prop_local, PropertyRNA *prop_reference, PropertyRNA *prop_storage, IDOverrideStaticProperty *op) { for (IDOverrideStaticPropertyOperation *opop = op->operations.first; opop; opop = opop->next) { - if (!rna_property_override_operation_apply(dst, src, storage, prop, opop)) { + if (!rna_property_override_operation_apply(ptr_local, ptr_reference, ptr_storage, + prop_local, prop_reference, prop_storage, opop)) + { BLI_assert(0); } } } /** Apply given \a override operations on \a dst, using \a src as source. */ -void RNA_struct_override_apply(PointerRNA *dst, PointerRNA *src, PointerRNA *storage, IDOverrideStatic *override) +void RNA_struct_override_apply( + PointerRNA *ptr_local, PointerRNA *ptr_reference, PointerRNA *ptr_storage, IDOverrideStatic *override) { #ifdef DEBUG_OVERRIDE_TIMEIT TIMEIT_START_AVERAGED(RNA_struct_override_apply); #endif for (IDOverrideStaticProperty *op = override->properties.first; op; op = op->next) { /* Simplified for now! */ - PointerRNA src_data, dst_data; - PropertyRNA *src_prop, *dst_prop; + PointerRNA data_reference, data_local; + PropertyRNA *prop_reference, *prop_local; - if (RNA_path_resolve_property(src, op->rna_path, &src_data, &src_prop) && - RNA_path_resolve_property(dst, op->rna_path, &dst_data, &dst_prop)) + if (RNA_path_resolve_property(ptr_local, op->rna_path, &data_local, &prop_local) && + RNA_path_resolve_property(ptr_reference, op->rna_path, &data_reference, &prop_reference)) { - PointerRNA storage_data; - PropertyRNA *storage_prop = NULL; + PointerRNA data_storage; + PropertyRNA *prop_storage = NULL; /* It is totally OK if this does not success, only a subset of override operations actually need storage. */ - if (storage && (storage->id.data != NULL)) { - RNA_path_resolve_property(storage, op->rna_path, &storage_data, &storage_prop); + if (ptr_storage && (ptr_storage->id.data != NULL)) { + RNA_path_resolve_property(ptr_storage, op->rna_path, &data_storage, &prop_storage); } - /* Note that src and dst props are the same, unless they are IDProperties... */ - RNA_property_override_apply(&dst_data, &src_data, storage_prop ? &storage_data : NULL, src_prop, op); + rna_property_override_apply_ex( + &data_local, &data_reference, prop_storage ? &data_storage : NULL, + prop_local, prop_reference, prop_storage, op); } #ifndef NDEBUG else { printf("Failed to apply static override operation to '%s.%s' (could not resolve some properties)\n", - ((ID *)src->id.data)->name, op->rna_path); + ((ID *)ptr_reference->id.data)->name, op->rna_path); } #endif } @@ -7378,75 +7606,6 @@ void RNA_struct_override_apply(PointerRNA *dst, PointerRNA *src, PointerRNA *sto #endif } -/** Automatically define override rules by comparing \a local and \a reference RNA structs. */ -bool RNA_struct_auto_override(PointerRNA *local, PointerRNA *reference, IDOverrideStatic *override, const char *root_path) -{ - CollectionPropertyIterator iter; - PropertyRNA *iterprop; - bool changed = false; - - BLI_assert(local->type == reference->type); - BLI_assert(local->id.data && reference->id.data); - - if ((((ID *)local->id.data)->flag & LIB_OVERRIDE_STATIC_AUTO) == 0) { - return changed; - } - -#ifdef DEBUG_OVERRIDE_TIMEIT - static float _sum_time = 0.0f; - static float _num_time = 0.0f; - double _timeit_time; - if (!root_path) { - _timeit_time = PIL_check_seconds_timer(); - } -#endif - - iterprop = RNA_struct_iterator_property(local->type); - - for (RNA_property_collection_begin(local, iterprop, &iter); iter.valid; RNA_property_collection_next(&iter)) { - PropertyRNA *prop = iter.ptr.data; - - if (!(prop->flag & PROP_OVERRIDABLE_STATIC)) { - continue; - } - if (RNA_property_animated(local, prop)) { - continue; - } - - /* XXX TODO this will have to be refined to handle collections insertions, and array items */ - char *rna_path; - if (root_path) { - /* Inlined building, much much more efficient. */ - rna_path = BLI_sprintfN("%s.%s", root_path, RNA_property_identifier(prop)); - } - else { - rna_path = RNA_path_from_ID_to_property(local, prop); - } - if (rna_path == NULL) { - continue; - } - - rna_property_override_diff(local, reference, prop, RNA_EQ_STRICT, override, rna_path, &changed, - RNA_OVERRIDE_COMPARE_IGNORE_NON_OVERRIDABLE | RNA_OVERRIDE_COMPARE_IGNORE_OVERRIDDEN); - - MEM_SAFE_FREE(rna_path); - } - RNA_property_collection_end(&iter); - -#ifdef DEBUG_OVERRIDE_TIMEIT - if (!root_path) { - const float _delta_time = (float)(PIL_check_seconds_timer() - _timeit_time); - _sum_time += _delta_time; - _num_time++; - printf("ID: %s\n", ((ID *)local->id.data)->name); - printf("time end (%s): %.6f\n", __func__, _delta_time); - printf("time averaged (%s): %.6f (total: %.6f, in %d runs)\n", __func__, (_sum_time / _num_time), _sum_time, (int)_num_time); - } -#endif - - return changed; -} - IDOverrideStaticProperty *RNA_property_override_property_find(PointerRNA *ptr, PropertyRNA *prop) { ID *id = ptr->id.data; diff --git a/source/blender/makesrna/intern/rna_armature.c b/source/blender/makesrna/intern/rna_armature.c index 1ec0fd92a67..bbcb583ab39 100644 --- a/source/blender/makesrna/intern/rna_armature.c +++ b/source/blender/makesrna/intern/rna_armature.c @@ -726,6 +726,7 @@ static void rna_def_bone(BlenderRNA *brna) prop = RNA_def_property(srna, "parent", PROP_POINTER, PROP_NONE); RNA_def_property_struct_type(prop, "Bone"); RNA_def_property_pointer_sdna(prop, NULL, "parent"); + RNA_def_property_flag(prop, PROP_PTR_NO_OWNERSHIP); RNA_def_property_ui_text(prop, "Parent", "Parent bone (in same Armature)"); RNA_def_property_update(prop, 0, "rna_Armature_redraw_data"); @@ -733,6 +734,7 @@ static void rna_def_bone(BlenderRNA *brna) prop = RNA_def_property(srna, "children", PROP_COLLECTION, PROP_NONE); RNA_def_property_collection_sdna(prop, NULL, "childbase", NULL); RNA_def_property_struct_type(prop, "Bone"); + RNA_def_property_flag(prop, PROP_PTR_NO_OWNERSHIP); RNA_def_property_ui_text(prop, "Children", "Bones which are children of this bone"); rna_def_bone_common(srna, 0); diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c index 3861f4d19b9..5336a63fb76 100644 --- a/source/blender/makesrna/intern/rna_brush.c +++ b/source/blender/makesrna/intern/rna_brush.c @@ -128,7 +128,7 @@ const EnumPropertyItem rna_enum_brush_image_tool_items[] = { #include "RNA_access.h" -#include "BKE_texture.h" +#include "BKE_colorband.h" #include "BKE_brush.h" #include "BKE_icons.h" #include "BKE_paint.h" @@ -474,7 +474,7 @@ static void rna_Brush_use_gradient_set(PointerRNA *ptr, int value) else br->flag &= ~BRUSH_USE_GRADIENT; if ((br->flag & BRUSH_USE_GRADIENT) && br->gradient == NULL) - br->gradient = add_colorband(true); + br->gradient = BKE_colorband_add(true); } static void rna_Brush_set_unprojected_radius(PointerRNA *ptr, float value) diff --git a/source/blender/makesrna/intern/rna_color.c b/source/blender/makesrna/intern/rna_color.c index ad2586635c9..d9b7a58de04 100644 --- a/source/blender/makesrna/intern/rna_color.c +++ b/source/blender/makesrna/intern/rna_color.c @@ -52,12 +52,12 @@ #include "MEM_guardedalloc.h" +#include "BKE_colorband.h" #include "BKE_colortools.h" #include "BKE_image.h" #include "BKE_movieclip.h" #include "BKE_node.h" #include "BKE_sequencer.h" -#include "BKE_texture.h" #include "BKE_linestyle.h" #include "DEG_depsgraph.h" @@ -362,12 +362,12 @@ static void rna_ColorRamp_update(Main *bmain, Scene *UNUSED(scene), PointerRNA * static void rna_ColorRamp_eval(struct ColorBand *coba, float position, float color[4]) { - do_colorband(coba, position, color); + BKE_colorband_evaluate(coba, position, color); } static CBData *rna_ColorRampElement_new(struct ColorBand *coba, ReportList *reports, float position) { - CBData *element = colorband_element_add(coba, position); + CBData *element = BKE_colorband_element_add(coba, position); if (element == NULL) BKE_reportf(reports, RPT_ERROR, "Unable to add element to colorband (limit %d)", MAXCOLORBAND); @@ -379,7 +379,7 @@ static void rna_ColorRampElement_remove(struct ColorBand *coba, ReportList *repo { CBData *element = element_ptr->data; int index = (int)(element - coba->data); - if (colorband_element_remove(coba, index) == false) { + if (BKE_colorband_element_remove(coba, index) == false) { BKE_report(reports, RPT_ERROR, "Element not found in element collection or last element"); return; } diff --git a/source/blender/makesrna/intern/rna_context.c b/source/blender/makesrna/intern/rna_context.c index 3df114282fd..bcd805b0f3a 100644 --- a/source/blender/makesrna/intern/rna_context.c +++ b/source/blender/makesrna/intern/rna_context.c @@ -132,7 +132,11 @@ static PointerRNA rna_Context_scene_get(PointerRNA *ptr) static PointerRNA rna_Context_view_layer_get(PointerRNA *ptr) { bContext *C = (bContext *)ptr->data; - return rna_pointer_inherit_refine(ptr, &RNA_ViewLayer, CTX_data_view_layer(C)); + Scene *scene = CTX_data_scene(C); + PointerRNA scene_ptr; + + RNA_id_pointer_create(&scene->id, &scene_ptr); + return rna_pointer_inherit_refine(&scene_ptr, &RNA_ViewLayer, CTX_data_view_layer(C)); } static PointerRNA rna_Context_view_render_get(PointerRNA *ptr) diff --git a/source/blender/makesrna/intern/rna_depsgraph.c b/source/blender/makesrna/intern/rna_depsgraph.c index 7d520ec6abd..e6e1c714008 100644 --- a/source/blender/makesrna/intern/rna_depsgraph.c +++ b/source/blender/makesrna/intern/rna_depsgraph.c @@ -61,7 +61,7 @@ static PointerRNA rna_DepsgraphIter_object_get(PointerRNA *ptr) static PointerRNA rna_DepsgraphIter_instance_object_get(PointerRNA *ptr) { BLI_Iterator *iterator = ptr->data; - DEGOIterObjectData *deg_iter = (DEGOIterObjectData *)iterator->data; + DEGObjectIterData *deg_iter = (DEGObjectIterData *)iterator->data; Object *instance_object = NULL; if (deg_iter->dupli_object_current != NULL) { instance_object = deg_iter->dupli_object_current->ob; @@ -72,7 +72,7 @@ static PointerRNA rna_DepsgraphIter_instance_object_get(PointerRNA *ptr) static PointerRNA rna_DepsgraphIter_parent_get(PointerRNA *ptr) { BLI_Iterator *iterator = ptr->data; - DEGOIterObjectData *deg_iter = (DEGOIterObjectData *)iterator->data; + DEGObjectIterData *deg_iter = (DEGObjectIterData *)iterator->data; Object *dupli_parent = NULL; if (deg_iter->dupli_object_current != NULL) { dupli_parent = deg_iter->dupli_parent; @@ -83,7 +83,7 @@ static PointerRNA rna_DepsgraphIter_parent_get(PointerRNA *ptr) static void rna_DepsgraphIter_persistent_id_get(PointerRNA *ptr, int *persistent_id) { BLI_Iterator *iterator = ptr->data; - DEGOIterObjectData *deg_iter = (DEGOIterObjectData *)iterator->data; + DEGObjectIterData *deg_iter = (DEGObjectIterData *)iterator->data; memcpy(persistent_id, deg_iter->dupli_object_current->persistent_id, sizeof(deg_iter->dupli_object_current->persistent_id)); } @@ -91,7 +91,7 @@ static void rna_DepsgraphIter_persistent_id_get(PointerRNA *ptr, int *persistent static void rna_DepsgraphIter_orco_get(PointerRNA *ptr, float *orco) { BLI_Iterator *iterator = ptr->data; - DEGOIterObjectData *deg_iter = (DEGOIterObjectData *)iterator->data; + DEGObjectIterData *deg_iter = (DEGObjectIterData *)iterator->data; memcpy(orco, deg_iter->dupli_object_current->orco, sizeof(deg_iter->dupli_object_current->orco)); } @@ -99,14 +99,14 @@ static void rna_DepsgraphIter_orco_get(PointerRNA *ptr, float *orco) static unsigned int rna_DepsgraphIter_random_id_get(PointerRNA *ptr) { BLI_Iterator *iterator = ptr->data; - DEGOIterObjectData *deg_iter = (DEGOIterObjectData *)iterator->data; + DEGObjectIterData *deg_iter = (DEGObjectIterData *)iterator->data; return deg_iter->dupli_object_current->random_id; } static void rna_DepsgraphIter_uv_get(PointerRNA *ptr, float *uv) { BLI_Iterator *iterator = ptr->data; - DEGOIterObjectData *deg_iter = (DEGOIterObjectData *)iterator->data; + DEGObjectIterData *deg_iter = (DEGObjectIterData *)iterator->data; memcpy(uv, deg_iter->dupli_object_current->uv, sizeof(deg_iter->dupli_object_current->uv)); } @@ -114,31 +114,44 @@ static void rna_DepsgraphIter_uv_get(PointerRNA *ptr, float *uv) static int rna_DepsgraphIter_is_instance_get(PointerRNA *ptr) { BLI_Iterator *iterator = ptr->data; - DEGOIterObjectData *deg_iter = (DEGOIterObjectData *)iterator->data; + DEGObjectIterData *deg_iter = (DEGObjectIterData *)iterator->data; return (deg_iter->dupli_object_current != NULL); } /* **************** Depsgraph **************** */ -static void rna_Depsgraph_debug_graphviz(Depsgraph *graph, const char *filename) +static void rna_Depsgraph_debug_relations_graphviz(Depsgraph *depsgraph, + const char *filename) { FILE *f = fopen(filename, "w"); if (f == NULL) { return; } - DEG_debug_graphviz(graph, f, "Depsgraph", false); + DEG_debug_relations_graphviz(depsgraph, f, "Depsgraph"); fclose(f); } -static void rna_Depsgraph_debug_tag_update(Depsgraph *graph) +static void rna_Depsgraph_debug_stats_gnuplot(Depsgraph *depsgraph, + const char *filename, + const char *output_filename) { - DEG_graph_tag_relations_update(graph); + FILE *f = fopen(filename, "w"); + if (f == NULL) { + return; + } + DEG_debug_stats_gnuplot(depsgraph, f, "Timing Statistics", output_filename); + fclose(f); } -static void rna_Depsgraph_debug_stats(Depsgraph *graph, char *result) +static void rna_Depsgraph_debug_tag_update(Depsgraph *depsgraph) +{ + DEG_graph_tag_relations_update(depsgraph); +} + +static void rna_Depsgraph_debug_stats(Depsgraph *depsgraph, char *result) { size_t outer, ops, rels; - DEG_stats_simple(graph, &outer, &ops, &rels); + DEG_stats_simple(depsgraph, &outer, &ops, &rels); BLI_snprintf(result, STATS_MAX_SIZE, "Approx %lu Operations, %lu Relations, %lu Outer Nodes", ops, rels, outer); @@ -149,10 +162,13 @@ static void rna_Depsgraph_debug_stats(Depsgraph *graph, char *result) static void rna_Depsgraph_objects_begin(CollectionPropertyIterator *iter, PointerRNA *ptr) { iter->internal.custom = MEM_callocN(sizeof(BLI_Iterator), __func__); - DEGOIterObjectData *data = MEM_callocN(sizeof(DEGOIterObjectData), __func__); + DEGObjectIterData *data = MEM_callocN(sizeof(DEGObjectIterData), __func__); data->graph = (Depsgraph *)ptr->data; - data->flag = DEG_ITER_OBJECT_FLAG_SET; + data->flag = DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY | + DEG_ITER_OBJECT_FLAG_VISIBLE | + DEG_ITER_OBJECT_FLAG_LINKED_VIA_SET; + data->mode = DEG_ITER_OBJECT_MODE_RENDER; ((BLI_Iterator *)iter->internal.custom)->valid = true; DEG_iterator_objects_begin(iter->internal.custom, data); @@ -186,10 +202,14 @@ static PointerRNA rna_Depsgraph_objects_get(CollectionPropertyIterator *iter) static void rna_Depsgraph_duplis_begin(CollectionPropertyIterator *iter, PointerRNA *ptr) { iter->internal.custom = MEM_callocN(sizeof(BLI_Iterator), __func__); - DEGOIterObjectData *data = MEM_callocN(sizeof(DEGOIterObjectData), __func__); + DEGObjectIterData *data = MEM_callocN(sizeof(DEGObjectIterData), __func__); data->graph = (Depsgraph *)ptr->data; - data->flag = DEG_ITER_OBJECT_FLAG_ALL; + data->flag = DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY | + DEG_ITER_OBJECT_FLAG_LINKED_VIA_SET | + DEG_ITER_OBJECT_FLAG_VISIBLE | + DEG_ITER_OBJECT_FLAG_DUPLI; + data->mode = DEG_ITER_OBJECT_MODE_RENDER; ((BLI_Iterator *)iter->internal.custom)->valid = true; DEG_iterator_objects_begin(iter->internal.custom, data); @@ -292,10 +312,18 @@ static void rna_def_depsgraph(BlenderRNA *brna) srna = RNA_def_struct(brna, "Depsgraph", NULL); RNA_def_struct_ui_text(srna, "Dependency Graph", ""); - func = RNA_def_function(srna, "debug_graphviz", "rna_Depsgraph_debug_graphviz"); + func = RNA_def_function(srna, "debug_relations_graphviz", "rna_Depsgraph_debug_relations_graphviz"); + parm = RNA_def_string_file_path(func, "filename", NULL, FILE_MAX, "File Name", + "File in which to store graphviz debug output"); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + + func = RNA_def_function(srna, "debug_stats_gnuplot", "rna_Depsgraph_debug_stats_gnuplot"); parm = RNA_def_string_file_path(func, "filename", NULL, FILE_MAX, "File Name", "File in which to store graphviz debug output"); RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + parm = RNA_def_string_file_path(func, "output_filename", NULL, FILE_MAX, "Output File Name", + "File name where gnuplot script will save the result"); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); func = RNA_def_function(srna, "debug_tag_update", "rna_Depsgraph_debug_tag_update"); diff --git a/source/blender/makesrna/intern/rna_fluidsim.c b/source/blender/makesrna/intern/rna_fluidsim.c index 074db855c17..271ead13197 100644 --- a/source/blender/makesrna/intern/rna_fluidsim.c +++ b/source/blender/makesrna/intern/rna_fluidsim.c @@ -137,7 +137,7 @@ static void rna_FluidSettings_update_type(Main *bmain, Scene *scene, PointerRNA if (ob->type == OB_MESH && !psys) { /* add particle system */ - part = psys_new_settings("ParticleSettings", bmain); + part = BKE_particlesettings_add(bmain, "ParticleSettings"); psys = MEM_callocN(sizeof(ParticleSystem), "particle_system"); part->type = PART_FLUID; diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h index 7dffab4eefb..e987c01134f 100644 --- a/source/blender/makesrna/intern/rna_internal.h +++ b/source/blender/makesrna/intern/rna_internal.h @@ -399,6 +399,7 @@ extern StructRNA RNA_PropertyGroup; #endif struct IDProperty *rna_idproperty_check(struct PropertyRNA **prop, struct PointerRNA *ptr); +struct PropertyRNA *rna_ensure_property_realdata(struct PropertyRNA **prop, struct PointerRNA *ptr); /* Override default callbacks. */ /* Default override callbacks for all types. */ diff --git a/source/blender/makesrna/intern/rna_internal_types.h b/source/blender/makesrna/intern/rna_internal_types.h index fd0b655e41e..88efff30481 100644 --- a/source/blender/makesrna/intern/rna_internal_types.h +++ b/source/blender/makesrna/intern/rna_internal_types.h @@ -121,12 +121,6 @@ typedef int (*PropEnumGetFuncEx)(struct PointerRNA *ptr, struct PropertyRNA *pro typedef void (*PropEnumSetFuncEx)(struct PointerRNA *ptr, struct PropertyRNA *prop, int value); /* Handling override operations, and also comparison. */ -enum { - /* Do not compare properties that are not overridable. */ - RNA_OVERRIDE_COMPARE_IGNORE_NON_OVERRIDABLE = 1 << 0, - /* Do not compare properties that are already overridden. */ - RNA_OVERRIDE_COMPARE_IGNORE_OVERRIDDEN = 1 << 1, -}; /** * If \a override is NULL, merely do comparison between prop_a from ptr_a and prop_b from ptr_b, diff --git a/source/blender/makesrna/intern/rna_layer.c b/source/blender/makesrna/intern/rna_layer.c index 877d6b250c0..131378b5c49 100644 --- a/source/blender/makesrna/intern/rna_layer.c +++ b/source/blender/makesrna/intern/rna_layer.c @@ -97,16 +97,6 @@ static void rna_SceneCollection_name_set(PointerRNA *ptr, const char *value) BKE_collection_rename(scene, sc, value); } -static void rna_SceneCollection_filter_set(PointerRNA *ptr, const char *value) -{ - Scene *scene = (Scene *)ptr->id.data; - SceneCollection *sc = (SceneCollection *)ptr->data; - BLI_strncpy_utf8(sc->filter, value, sizeof(sc->filter)); - - TODO_LAYER_SYNC_FILTER; - (void)scene; -} - static PointerRNA rna_SceneCollection_objects_get(CollectionPropertyIterator *iter) { ListBaseIterator *internal = &iter->internal.listbase; @@ -350,12 +340,10 @@ RNA_LAYER_ENGINE_CLAY_GET_SET_FLOAT(hair_brightness_randomness) /* ViewLayer settings. */ RNA_LAYER_ENGINE_EEVEE_GET_SET_BOOL(gtao_enable) RNA_LAYER_ENGINE_EEVEE_GET_SET_BOOL(gtao_use_bent_normals) -RNA_LAYER_ENGINE_EEVEE_GET_SET_BOOL(gtao_denoise) RNA_LAYER_ENGINE_EEVEE_GET_SET_BOOL(gtao_bounce) RNA_LAYER_ENGINE_EEVEE_GET_SET_FLOAT(gtao_factor) RNA_LAYER_ENGINE_EEVEE_GET_SET_FLOAT(gtao_quality) RNA_LAYER_ENGINE_EEVEE_GET_SET_FLOAT(gtao_distance) -RNA_LAYER_ENGINE_EEVEE_GET_SET_INT(gtao_samples) RNA_LAYER_ENGINE_EEVEE_GET_SET_BOOL(dof_enable) RNA_LAYER_ENGINE_EEVEE_GET_SET_FLOAT(bokeh_max_size) RNA_LAYER_ENGINE_EEVEE_GET_SET_FLOAT(bokeh_threshold) @@ -387,7 +375,6 @@ RNA_LAYER_ENGINE_EEVEE_GET_SET_BOOL(sss_separate_albedo) RNA_LAYER_ENGINE_EEVEE_GET_SET_BOOL(ssr_refraction) RNA_LAYER_ENGINE_EEVEE_GET_SET_BOOL(ssr_enable) RNA_LAYER_ENGINE_EEVEE_GET_SET_BOOL(ssr_halfres) -RNA_LAYER_ENGINE_EEVEE_GET_SET_INT(ssr_ray_count) RNA_LAYER_ENGINE_EEVEE_GET_SET_FLOAT(ssr_quality) RNA_LAYER_ENGINE_EEVEE_GET_SET_FLOAT(ssr_max_roughness) RNA_LAYER_ENGINE_EEVEE_GET_SET_FLOAT(ssr_thickness) @@ -397,6 +384,7 @@ RNA_LAYER_ENGINE_EEVEE_GET_SET_INT(shadow_method) RNA_LAYER_ENGINE_EEVEE_GET_SET_INT(shadow_size) RNA_LAYER_ENGINE_EEVEE_GET_SET_BOOL(shadow_high_bitdepth) RNA_LAYER_ENGINE_EEVEE_GET_SET_INT(taa_samples) +RNA_LAYER_ENGINE_EEVEE_GET_SET_INT(taa_render_samples) RNA_LAYER_ENGINE_EEVEE_GET_SET_INT(gi_diffuse_bounces) RNA_LAYER_ENGINE_EEVEE_GET_SET_INT(gi_cubemap_resolution) RNA_LAYER_ENGINE_EEVEE_GET_SET_INT(gi_visibility_resolution) @@ -703,48 +691,6 @@ static void rna_LayerCollection_flag_update(bContext *C, PointerRNA *ptr) WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, CTX_data_scene(C)); } -static void rna_LayerCollection_enable_set( - ID *id, LayerCollection *layer_collection, Main *bmain, bContext *C, ReportList *reports, int value) -{ - ViewLayer *view_layer; - if (GS(id->name) == ID_SCE) { - Scene *scene = (Scene *)id; - view_layer = BKE_view_layer_find_from_collection(&scene->id, layer_collection); - } - else { - BLI_assert(GS(id->name) == ID_GR); - Group *group = (Group *)id; - view_layer = group->view_layer; - } - - if (layer_collection->flag & COLLECTION_DISABLED) { - if (value == 1) { - BKE_collection_enable(view_layer, layer_collection); - } - else { - BKE_reportf(reports, RPT_ERROR, "Layer collection '%s' is already disabled", - layer_collection->scene_collection->name); - return; - } - } - else { - if (value == 0) { - BKE_collection_disable(view_layer, layer_collection); - } - else { - BKE_reportf(reports, RPT_ERROR, "Layer collection '%s' is already enabled", - layer_collection->scene_collection->name); - } - } - - Scene *scene = CTX_data_scene(C); - DEG_relations_tag_update(bmain); - /* TODO(sergey): Use proper flag for tagging here. */ - DEG_id_tag_update(&scene->id, 0); - WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); - WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, scene); -} - static Group *rna_LayerCollection_create_group( ID *id, LayerCollection *layer_collection, Main *bmain, bContext *C, ReportList *reports) { @@ -912,7 +858,12 @@ static void rna_LayerObjects_selected_begin(CollectionPropertyIterator *iter, Po static void rna_ViewLayer_update_tagged(ViewLayer *UNUSED(view_layer), bContext *C) { Depsgraph *graph = CTX_data_depsgraph(C); - DEG_OBJECT_ITER(graph, ob, DEG_ITER_OBJECT_FLAG_ALL) + DEG_OBJECT_ITER(graph, ob, DEG_ITER_OBJECT_MODE_VIEWPORT, + DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY | + DEG_ITER_OBJECT_FLAG_LINKED_VIA_SET | + DEG_ITER_OBJECT_FLAG_LINKED_INDIRECTLY | + DEG_ITER_OBJECT_FLAG_VISIBLE | + DEG_ITER_OBJECT_FLAG_DUPLI) { /* Don't do anything, we just need to run the iterator to flush * the base info to the objects. */ @@ -1028,15 +979,14 @@ static void rna_def_scene_collections(BlenderRNA *brna, PropertyRNA *cprop) func = RNA_def_function(srna, "new", "rna_SceneCollection_new"); RNA_def_function_ui_description(func, "Add a collection to scene"); RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN); - parm = RNA_def_string(func, "name", "SceneCollection", 0, "", "New name for the collection (not unique)"); - RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + parm = RNA_def_string(func, "name", NULL, 0, "", "New name for the collection (not unique)"); parm = RNA_def_pointer(func, "result", "SceneCollection", "", "Newly created collection"); RNA_def_function_return(func, parm); func = RNA_def_function(srna, "remove", "rna_SceneCollection_remove"); - RNA_def_function_ui_description(func, "Remove a collection layer"); + RNA_def_function_ui_description(func, "Remove a collection and move its objects to the master collection"); RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN | FUNC_USE_REPORTS); - parm = RNA_def_pointer(func, "layer", "SceneCollection", "", "Collection to remove"); + parm = RNA_def_pointer(func, "collection", "SceneCollection", "", "Collection to remove"); RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); } @@ -1096,11 +1046,6 @@ static void rna_def_scene_collection(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Type", "Type of collection"); RNA_def_property_clear_flag(prop, PROP_EDITABLE); - prop = RNA_def_property(srna, "filter", PROP_STRING, PROP_NONE); - RNA_def_property_string_funcs(prop, NULL, NULL, "rna_SceneCollection_filter_set"); - RNA_def_property_ui_text(prop, "Filter", "Filter to dynamically include objects based on their names (e.g., CHAR_*)"); - RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, NULL); - prop = RNA_def_property(srna, "collections", PROP_COLLECTION, PROP_NONE); RNA_def_property_collection_sdna(prop, NULL, "scene_collections", NULL); RNA_def_property_struct_type(prop, "SceneCollection"); @@ -1114,12 +1059,6 @@ static void rna_def_scene_collection(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Objects", "All the objects directly added to this collection (not including sub-collection objects)"); rna_def_collection_objects(brna, prop); - prop = RNA_def_property(srna, "filters_objects", PROP_COLLECTION, PROP_NONE); - RNA_def_property_collection_sdna(prop, NULL, "filter_objects", NULL); - RNA_def_property_struct_type(prop, "Object"); - RNA_def_property_collection_funcs(prop, NULL, NULL, NULL, "rna_SceneCollection_objects_get", NULL, NULL, NULL, NULL); - RNA_def_property_ui_text(prop, "Filter Objects", "All the objects dynamically added to this collection via the filter"); - /* Functions */ func = RNA_def_function(srna, "move_above", "rna_SceneCollection_move_above"); RNA_def_function_ui_description(func, "Move collection after another"); @@ -1261,12 +1200,19 @@ static void rna_def_view_layer_engine_settings_eevee(BlenderRNA *brna) prop = RNA_def_property(srna, "taa_samples", PROP_INT, PROP_NONE); RNA_def_property_int_funcs(prop, "rna_LayerEngineSettings_Eevee_taa_samples_get", "rna_LayerEngineSettings_Eevee_taa_samples_set", NULL); - RNA_def_property_ui_text(prop, "Viewport Samples", "Number of temporal samples, unlimited if 0, " - "disabled if 1"); + RNA_def_property_ui_text(prop, "Viewport Samples", "Number of samples, unlimited if 0"); RNA_def_property_range(prop, 0, INT_MAX); RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_ViewLayerEngineSettings_update"); + prop = RNA_def_property(srna, "taa_render_samples", PROP_INT, PROP_NONE); + RNA_def_property_int_funcs(prop, "rna_LayerEngineSettings_Eevee_taa_render_samples_get", + "rna_LayerEngineSettings_Eevee_taa_render_samples_set", NULL); + RNA_def_property_ui_text(prop, "Render Samples", "Number of samples per pixels for rendering"); + RNA_def_property_range(prop, 1, INT_MAX); + RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); + RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_ViewLayerEngineSettings_update"); + /* Screen Space Subsurface Scattering */ prop = RNA_def_property(srna, "sss_enable", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_funcs(prop, "rna_LayerEngineSettings_Eevee_sss_enable_get", @@ -1337,14 +1283,6 @@ static void rna_def_view_layer_engine_settings_eevee(BlenderRNA *brna) RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_ViewLayerEngineSettings_update"); - prop = RNA_def_property(srna, "ssr_ray_count", PROP_INT, PROP_NONE); - RNA_def_property_int_funcs(prop, "rna_LayerEngineSettings_Eevee_ssr_ray_count_get", - "rna_LayerEngineSettings_Eevee_ssr_ray_count_set", NULL); - RNA_def_property_ui_text(prop, "Samples", "Number of rays to trace per pixels"); - RNA_def_property_range(prop, 1, 4); - RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); - RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_ViewLayerEngineSettings_update"); - prop = RNA_def_property(srna, "ssr_thickness", PROP_FLOAT, PROP_DISTANCE); RNA_def_property_float_funcs(prop, "rna_LayerEngineSettings_Eevee_ssr_thickness_get", "rna_LayerEngineSettings_Eevee_ssr_thickness_set", NULL); @@ -1472,13 +1410,6 @@ static void rna_def_view_layer_engine_settings_eevee(BlenderRNA *brna) RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_ViewLayerEngineSettings_update"); - prop = RNA_def_property(srna, "gtao_denoise", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_funcs(prop, "rna_LayerEngineSettings_Eevee_gtao_denoise_get", - "rna_LayerEngineSettings_Eevee_gtao_denoise_set"); - RNA_def_property_ui_text(prop, "Denoise", "Use denoising to filter the resulting occlusion and bent normal but exhibit 2x2 pixel blocks"); - RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); - RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_ViewLayerEngineSettings_update"); - prop = RNA_def_property(srna, "gtao_bounce", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_funcs(prop, "rna_LayerEngineSettings_Eevee_gtao_bounce_get", "rna_LayerEngineSettings_Eevee_gtao_bounce_set"); @@ -1510,14 +1441,6 @@ static void rna_def_view_layer_engine_settings_eevee(BlenderRNA *brna) RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); RNA_def_property_update(prop, 0, "rna_LayerCollectionEngineSettings_update"); - prop = RNA_def_property(srna, "gtao_samples", PROP_INT, PROP_UNSIGNED); - RNA_def_property_int_funcs(prop, "rna_LayerEngineSettings_Eevee_gtao_samples_get", - "rna_LayerEngineSettings_Eevee_gtao_samples_set", NULL); - RNA_def_property_ui_text(prop, "Samples", "Number of samples to take to compute occlusion"); - RNA_def_property_range(prop, 2, 32); - RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); - RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_ViewLayerEngineSettings_update"); - /* Depth of Field */ prop = RNA_def_property(srna, "dof_enable", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_funcs(prop, "rna_LayerEngineSettings_Eevee_dof_enable_get", @@ -2065,11 +1988,6 @@ static void rna_def_layer_collection(BlenderRNA *brna) parm = RNA_def_boolean(func, "result", false, "Result", "Whether the operation succeded"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "enable_set", "rna_LayerCollection_enable_set"); - RNA_def_function_ui_description(func, "Enable or disable a collection"); - parm = RNA_def_boolean(func, "value", 1, "Enable", ""); - RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN | FUNC_USE_CONTEXT | FUNC_USE_REPORTS); - func = RNA_def_function(srna, "create_group", "rna_LayerCollection_create_group"); RNA_def_function_ui_description(func, "Enable or disable a collection"); RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN | FUNC_USE_CONTEXT | FUNC_USE_REPORTS); @@ -2077,26 +1995,32 @@ static void rna_def_layer_collection(BlenderRNA *brna) RNA_def_function_return(func, parm); /* Flags */ - prop = RNA_def_property(srna, "is_enabled", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", COLLECTION_DISABLED); - RNA_def_property_clear_flag(prop, PROP_EDITABLE); - RNA_def_property_ui_text(prop, "Enabled", "Enable or disable collection from depsgraph"); + prop = RNA_def_property(srna, "selectable", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", COLLECTION_SELECTABLE); + RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); + RNA_def_property_ui_icon(prop, ICON_RESTRICT_SELECT_OFF, 1); + RNA_def_property_ui_text(prop, "Selectable", "Restrict selection"); + RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_LayerCollection_flag_update"); - prop = RNA_def_property(srna, "hide", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", COLLECTION_VISIBLE); + prop = RNA_def_property(srna, "visible_viewport", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", COLLECTION_VIEWPORT); RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); RNA_def_property_ui_icon(prop, ICON_RESTRICT_VIEW_OFF, 1); - RNA_def_property_ui_text(prop, "Hide", "Restrict visiblity"); + RNA_def_property_ui_text(prop, "Viewport Visibility", ""); RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_LayerCollection_flag_update"); - prop = RNA_def_property(srna, "hide_select", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", COLLECTION_SELECTABLE); + prop = RNA_def_property(srna, "visible_render", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", COLLECTION_RENDER); RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); - RNA_def_property_ui_icon(prop, ICON_RESTRICT_SELECT_OFF, 1); - RNA_def_property_ui_text(prop, "Hide Selectable", "Restrict selection"); + RNA_def_property_ui_icon(prop, ICON_RESTRICT_RENDER_OFF, 1); + RNA_def_property_ui_text(prop, "Render Visibility", "Control"); RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_LayerCollection_flag_update"); - /* TODO_LAYER_OVERRIDE */ + prop = RNA_def_property(srna, "enabled", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", COLLECTION_DISABLED); + RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); + RNA_def_property_ui_text(prop, "Enabled", "Enable or disable collection"); + RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_LayerCollection_flag_update"); } static void rna_def_layer_collections(BlenderRNA *brna, PropertyRNA *cprop) diff --git a/source/blender/makesrna/intern/rna_lightprobe.c b/source/blender/makesrna/intern/rna_lightprobe.c index 61dc835022b..6586b456960 100644 --- a/source/blender/makesrna/intern/rna_lightprobe.c +++ b/source/blender/makesrna/intern/rna_lightprobe.c @@ -179,6 +179,13 @@ static void rna_def_lightprobe(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Visibility Blur", "Filter size of the visibilty blur"); RNA_def_property_update(prop, NC_MATERIAL | ND_SHADING, "rna_LightProbe_recalc"); + prop = RNA_def_property(srna, "intensity", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "intensity"); + RNA_def_property_range(prop, 0.0f, FLT_MAX); + RNA_def_property_ui_range(prop, 0.0f, 3.0f, 1.0, 3); + RNA_def_property_ui_text(prop, "Intensity", "Modify the intensity of the lighting captured by this probe"); + RNA_def_property_update(prop, NC_MATERIAL | ND_SHADING, "rna_LightProbe_recalc"); + /* Data preview */ prop = RNA_def_property(srna, "show_data", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", LIGHTPROBE_FLAG_SHOW_DATA); diff --git a/source/blender/makesrna/intern/rna_main_api.c b/source/blender/makesrna/intern/rna_main_api.c index f15006fa0ed..57292b7adc3 100644 --- a/source/blender/makesrna/intern/rna_main_api.c +++ b/source/blender/makesrna/intern/rna_main_api.c @@ -454,7 +454,7 @@ static World *rna_Main_worlds_new(Main *bmain, const char *name) char safe_name[MAX_ID_NAME - 2]; rna_idname_validate(name, safe_name); - World *world = add_world(bmain, safe_name); + World *world = BKE_world_add(bmain, safe_name); id_us_min(&world->id); return world; } @@ -529,7 +529,7 @@ static bAction *rna_Main_actions_new(Main *bmain, const char *name) char safe_name[MAX_ID_NAME - 2]; rna_idname_validate(name, safe_name); - bAction *act = add_empty_action(bmain, safe_name); + bAction *act = BKE_action_add(bmain, safe_name); id_fake_user_clear(&act->id); return act; } @@ -539,7 +539,7 @@ static ParticleSettings *rna_Main_particles_new(Main *bmain, const char *name) char safe_name[MAX_ID_NAME - 2]; rna_idname_validate(name, safe_name); - ParticleSettings *part = psys_new_settings(safe_name, bmain); + ParticleSettings *part = BKE_particlesettings_add(bmain, safe_name); id_us_min(&part->id); return part; } diff --git a/source/blender/makesrna/intern/rna_material.c b/source/blender/makesrna/intern/rna_material.c index a2845b3a2f8..440af0d0e8e 100644 --- a/source/blender/makesrna/intern/rna_material.c +++ b/source/blender/makesrna/intern/rna_material.c @@ -85,6 +85,7 @@ const EnumPropertyItem rna_enum_ramp_blend_items[] = { #include "DNA_screen_types.h" #include "DNA_space_types.h" +#include "BKE_colorband.h" #include "BKE_context.h" #include "BKE_main.h" #include "BKE_material.h" @@ -323,7 +324,7 @@ static void rna_Material_use_diffuse_ramp_set(PointerRNA *ptr, int value) else ma->mode &= ~MA_RAMP_COL; if ((ma->mode & MA_RAMP_COL) && ma->ramp_col == NULL) - ma->ramp_col = add_colorband(false); + ma->ramp_col = BKE_colorband_add(false); } static void rna_Material_use_specular_ramp_set(PointerRNA *ptr, int value) @@ -334,7 +335,7 @@ static void rna_Material_use_specular_ramp_set(PointerRNA *ptr, int value) else ma->mode &= ~MA_RAMP_SPEC; if ((ma->mode & MA_RAMP_SPEC) && ma->ramp_spec == NULL) - ma->ramp_spec = add_colorband(false); + ma->ramp_spec = BKE_colorband_add(false); } static void rna_Material_use_nodes_update(bContext *C, PointerRNA *ptr) diff --git a/source/blender/makesrna/intern/rna_mesh.c b/source/blender/makesrna/intern/rna_mesh.c index 62360ea34a3..79a9d072ad2 100644 --- a/source/blender/makesrna/intern/rna_mesh.c +++ b/source/blender/makesrna/intern/rna_mesh.c @@ -1667,7 +1667,7 @@ static int rna_MeshPolygonStringPropertyLayer_data_length(PointerRNA *ptr) return me->totpoly; } -/* XXX, we dont have propper byte string support yet, so for now use the (bytes + 1) +/* XXX, we dont have proper byte string support yet, so for now use the (bytes + 1) * bmesh API exposes correct python/bytestring access */ void rna_MeshStringProperty_s_get(PointerRNA *ptr, char *value) { diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c index c443b68b209..e721a04bd2a 100644 --- a/source/blender/makesrna/intern/rna_modifier.c +++ b/source/blender/makesrna/intern/rna_modifier.c @@ -2124,6 +2124,20 @@ static void rna_def_modifier_array(BlenderRNA *brna) RNA_def_property_pointer_funcs(prop, NULL, "rna_ArrayModifier_end_cap_set", NULL, "rna_Mesh_object_poll"); RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK); RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update"); + + prop = RNA_def_property(srna, "offset_u", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_float_sdna(prop, NULL, "uv_offset[0]"); + RNA_def_property_range(prop, -1, 1); + RNA_def_property_ui_range(prop, -1, 1, 2, 4); + RNA_def_property_ui_text(prop, "U Offset", "Amount to offset array UVs on the U axis"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + prop = RNA_def_property(srna, "offset_v", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_float_sdna(prop, NULL, "uv_offset[1]"); + RNA_def_property_range(prop, -1, 1); + RNA_def_property_ui_range(prop, -1, 1, 2, 4); + RNA_def_property_ui_text(prop, "V Offset", "Amount to offset array UVs on the V axis"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); } static void rna_def_modifier_edgesplit(BlenderRNA *brna) @@ -3222,6 +3236,11 @@ static void rna_def_modifier_simpledeform(BlenderRNA *brna) RNA_def_property_string_funcs(prop, NULL, NULL, "rna_SimpleDeformModifier_vgroup_name_set"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); + prop = RNA_def_property(srna, "deform_axis", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, rna_enum_axis_xyz_items); + RNA_def_property_ui_text(prop, "Axis", "Deform around local axis"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + prop = RNA_def_property(srna, "origin", PROP_POINTER, PROP_NONE); RNA_def_property_ui_text(prop, "Origin", "Offset the origin and orientation of the deformation"); RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK); @@ -3251,12 +3270,17 @@ static void rna_def_modifier_simpledeform(BlenderRNA *brna) prop = RNA_def_property(srna, "lock_x", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "axis", MOD_SIMPLEDEFORM_LOCK_AXIS_X); - RNA_def_property_ui_text(prop, "Lock X Axis", "Do not allow deformation along the X axis"); + RNA_def_property_ui_text(prop, "X", "Do not allow deformation along the X axis"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); prop = RNA_def_property(srna, "lock_y", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "axis", MOD_SIMPLEDEFORM_LOCK_AXIS_Y); - RNA_def_property_ui_text(prop, "Lock Y Axis", "Do not allow deformation along the Y axis"); + RNA_def_property_ui_text(prop, "Y", "Do not allow deformation along the Y axis"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + prop = RNA_def_property(srna, "lock_z", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "axis", MOD_SIMPLEDEFORM_LOCK_AXIS_Z); + RNA_def_property_ui_text(prop, "Z", "Do not allow deformation along the Z axis"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); prop = RNA_def_property(srna, "invert_vertex_group", PROP_BOOLEAN, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index ab8370f77e7..2b2c6998eb4 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -5286,14 +5286,14 @@ static void def_cmp_luma_matte(StructRNA *srna) prop = RNA_def_property(srna, "limit_max", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "t1"); RNA_def_property_float_funcs(prop, NULL, "rna_Matte_t1_set", NULL); - RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_ui_range(prop, 0, 1, 0.1f, 3); RNA_def_property_ui_text(prop, "High", "Values higher than this setting are 100% opaque"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "limit_min", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "t2"); RNA_def_property_float_funcs(prop, NULL, "rna_Matte_t2_set", NULL); - RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_ui_range(prop, 0, 1, 0.1f, 3); RNA_def_property_ui_text(prop, "Low", "Values lower than this setting are 100% keyed"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } @@ -5396,14 +5396,14 @@ static void def_cmp_channel_matte(StructRNA *srna) prop = RNA_def_property(srna, "limit_max", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "t1"); RNA_def_property_float_funcs(prop, NULL, "rna_Matte_t1_set", NULL); - RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_ui_range(prop, 0, 1, 0.1f, 3); RNA_def_property_ui_text(prop, "High", "Values higher than this setting are 100% opaque"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "limit_min", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "t2"); RNA_def_property_float_funcs(prop, NULL, "rna_Matte_t2_set", NULL); - RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_ui_range(prop, 0, 1, 0.1f, 3); RNA_def_property_ui_text(prop, "Low", "Values lower than this setting are 100% keyed"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c index a153590f4ac..f2b2e95d21e 100644 --- a/source/blender/makesrna/intern/rna_object.c +++ b/source/blender/makesrna/intern/rna_object.c @@ -229,6 +229,27 @@ static void rna_Object_hide_update(Main *bmain, Scene *UNUSED(scene), PointerRNA DEG_id_type_tag(bmain, ID_OB); } +static int rna_Object_is_visible_get(PointerRNA *ptr) +{ + Object *ob = ptr->id.data; + /* The duplicators final visibility is not evaluated by depsgraph, so it's + * in ob->base_flag & VISIBLED. Instead we need to take into account whether + * we are rendering or not, and the ob->duplicator_visibility_flag. + * However for this assessor we don't know if we are rendering, so we just + * ignore the duplicator visibility + */ + return BKE_object_is_visible(ob, OB_VISIBILITY_CHECK_UNKNOWN_RENDER_MODE); +} + +static void rna_Object_collection_properties_begin(CollectionPropertyIterator *iter, PointerRNA *ptr) +{ + Object *ob = ptr->data; + + if (ob->base_collection_properties != NULL) { + rna_iterator_listbase_begin(iter, &ob->base_collection_properties->data.group, NULL); + } +} + static void rna_Object_matrix_local_get(PointerRNA *ptr, float values[16]) { Object *ob = ptr->id.data; @@ -2777,32 +2798,36 @@ static void rna_def_object(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Rigid Body Constraint", "Constraint constraining rigid bodies"); /* restrict */ - prop = RNA_def_property(srna, "hide", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "restrictflag", OB_RESTRICT_VIEW); - RNA_def_property_ui_text(prop, "Restrict View", "Restrict visibility in the viewport"); - RNA_def_property_ui_icon(prop, ICON_RESTRICT_VIEW_OFF, 1); - RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Object_hide_update"); - - prop = RNA_def_property(srna, "hide_select", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "restrictflag", OB_RESTRICT_SELECT); - RNA_def_property_ui_text(prop, "Restrict Select", "Restrict selection in the viewport"); - RNA_def_property_ui_icon(prop, ICON_RESTRICT_SELECT_OFF, 1); - RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL); - prop = RNA_def_property(srna, "hide_render", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "restrictflag", OB_RESTRICT_RENDER); RNA_def_property_ui_text(prop, "Restrict Render", "Restrict renderability"); RNA_def_property_ui_icon(prop, ICON_RESTRICT_RENDER_OFF, 1); RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Object_hide_update"); - /* Keep it in sync with BKE_object_is_visible. */ + prop = RNA_def_property(srna, "show_duplicator_for_render", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "duplicator_visibility_flag", OB_DUPLI_FLAG_RENDER); + RNA_def_property_ui_text(prop, "Render Duplicator", "Make duplicator visible when rendering"); + + prop = RNA_def_property(srna, "show_duplicator_for_viewport", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "duplicator_visibility_flag", OB_DUPLI_FLAG_VIEWPORT); + RNA_def_property_ui_text(prop, "Show Duplicator", "Make duplicator visible in the viewport"); + prop = RNA_def_property(srna, "is_visible", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "base_flag", BASE_VISIBLED); + RNA_def_property_boolean_funcs(prop, "rna_Object_is_visible_get", NULL); RNA_def_property_ui_text(prop, "Visible", "Visible to camera rays, set only on objects evaluated by depsgraph"); RNA_def_property_clear_flag(prop, PROP_EDITABLE); prop = RNA_def_property(srna, "collection_properties", PROP_COLLECTION, PROP_NONE); RNA_def_property_collection_sdna(prop, NULL, "base_collection_properties->data.group", NULL); + RNA_def_property_collection_funcs(prop, + "rna_Object_collection_properties_begin", + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL); RNA_def_property_struct_type(prop, "LayerCollectionSettings"); RNA_def_property_ui_text(prop, "Collection Settings", "Engine specific render settings to be overridden by collections"); @@ -2827,16 +2852,7 @@ static void rna_def_object(BlenderRNA *brna) RNA_def_property_range(prop, MINAFRAMEF, MAXFRAMEF); RNA_def_property_ui_text(prop, "Slow Parent Offset", "Delay in the parent relationship"); RNA_def_property_update(prop, NC_OBJECT | ND_TRANSFORM, "rna_Object_internal_update"); - - /* depsgraph hack */ - prop = RNA_def_property(srna, "use_extra_recalc_object", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "depsflag", OB_DEPS_EXTRA_OB_RECALC); - RNA_def_property_ui_text(prop, "Extra Object Update", "Refresh this object again on frame changes, dependency graph hack"); - - prop = RNA_def_property(srna, "use_extra_recalc_data", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "depsflag", OB_DEPS_EXTRA_DATA_RECALC); - RNA_def_property_ui_text(prop, "Extra Data Update", "Refresh this object's data again on frame changes, dependency graph hack"); - + /* duplicates */ prop = RNA_def_property(srna, "dupli_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_bitflag_sdna(prop, NULL, "transflag"); diff --git a/source/blender/makesrna/intern/rna_object_force.c b/source/blender/makesrna/intern/rna_object_force.c index 031b0bdec99..9265c7b62cf 100644 --- a/source/blender/makesrna/intern/rna_object_force.c +++ b/source/blender/makesrna/intern/rna_object_force.c @@ -1265,7 +1265,8 @@ static void rna_def_field(BlenderRNA *brna) prop = RNA_def_property(srna, "size", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "f_size"); - RNA_def_property_range(prop, 0.0f, 10.0f); + RNA_def_property_range(prop, 0.0f, FLT_MAX); + RNA_def_property_ui_range(prop, 0.0f, 10.0f, 1.0f, 3); RNA_def_property_ui_text(prop, "Size", "Size of the turbulence"); RNA_def_property_update(prop, 0, "rna_FieldSettings_update"); @@ -1289,7 +1290,8 @@ static void rna_def_field(BlenderRNA *brna) prop = RNA_def_property(srna, "distance_max", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "maxdist"); - RNA_def_property_range(prop, 0.0f, 1000.0f); + RNA_def_property_range(prop, 0.0f, FLT_MAX); + RNA_def_property_ui_range(prop, 0.0f, 1000.0f, 1.0f, 3); RNA_def_property_ui_text(prop, "Maximum Distance", "Maximum distance for the field to work"); RNA_def_property_update(prop, 0, "rna_FieldSettings_update"); diff --git a/source/blender/makesrna/intern/rna_particle.c b/source/blender/makesrna/intern/rna_particle.c index 67eaa22fbe4..12e56b8e926 100644 --- a/source/blender/makesrna/intern/rna_particle.c +++ b/source/blender/makesrna/intern/rna_particle.c @@ -2292,11 +2292,6 @@ static void rna_def_particle_settings(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Size", "Show particle size"); RNA_def_property_update(prop, 0, "rna_Particle_redo"); - prop = RNA_def_property(srna, "use_render_emitter", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "draw", PART_DRAW_EMITTER); - RNA_def_property_ui_text(prop, "Emitter", "Render emitter Object also"); - RNA_def_property_update(prop, 0, "rna_Particle_redo"); - prop = RNA_def_property(srna, "show_health", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "draw", PART_DRAW_HEALTH); RNA_def_property_ui_text(prop, "Health", "Draw boid health"); diff --git a/source/blender/makesrna/intern/rna_pose.c b/source/blender/makesrna/intern/rna_pose.c index baf7f5e6aa3..f50be85c446 100644 --- a/source/blender/makesrna/intern/rna_pose.c +++ b/source/blender/makesrna/intern/rna_pose.c @@ -823,16 +823,19 @@ static void rna_def_pose_channel(BlenderRNA *brna) prop = RNA_def_property(srna, "bone", PROP_POINTER, PROP_NONE); RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_struct_type(prop, "Bone"); + RNA_def_property_flag(prop, PROP_PTR_NO_OWNERSHIP); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text(prop, "Bone", "Bone associated with this PoseBone"); prop = RNA_def_property(srna, "parent", PROP_POINTER, PROP_NONE); RNA_def_property_struct_type(prop, "PoseBone"); + RNA_def_property_flag(prop, PROP_PTR_NO_OWNERSHIP); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text(prop, "Parent", "Parent of this pose bone"); prop = RNA_def_property(srna, "child", PROP_POINTER, PROP_NONE); RNA_def_property_struct_type(prop, "PoseBone"); + RNA_def_property_flag(prop, PROP_PTR_NO_OWNERSHIP); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text(prop, "Child", "Child of this pose bone"); diff --git a/source/blender/makesrna/intern/rna_rna.c b/source/blender/makesrna/intern/rna_rna.c index 24d56ef2a19..38149734bc2 100644 --- a/source/blender/makesrna/intern/rna_rna.c +++ b/source/blender/makesrna/intern/rna_rna.c @@ -337,7 +337,7 @@ static void rna_Struct_property_tags_begin(CollectionPropertyIterator *iter, Poi /* here ptr->data should always be the same as iter->parent.type */ StructRNA *srna = (StructRNA *)ptr->data; const EnumPropertyItem *tag_defines = RNA_struct_property_tag_defines(srna); - unsigned int tag_count = RNA_enum_items_count(tag_defines); + unsigned int tag_count = tag_defines ? RNA_enum_items_count(tag_defines) : 0; rna_iterator_array_begin(iter, (void *)tag_defines, sizeof(EnumPropertyItem), tag_count, 0, NULL); } @@ -1094,10 +1094,12 @@ static int rna_BlenderRNA_structs_lookup_string(PointerRNA *ptr, const char *key /* Default override (and compare) callbacks. */ /* Used for both Pointer and Collection properties. */ -static int rna_property_override_equals_propptr( - PointerRNA *propptr_a, PointerRNA *propptr_b, eRNACompareMode mode, - IDOverrideStatic *override, const char *rna_path, bool *r_override_changed, const int flags) +static int rna_property_override_diff_propptr( + PointerRNA *propptr_a, PointerRNA *propptr_b, eRNACompareMode mode, const bool no_ownership, + IDOverrideStatic *override, const char *rna_path, const int flags, bool *r_override_changed) { + const bool do_create = override != NULL && (flags & RNA_OVERRIDE_COMPARE_CREATE) != 0 && rna_path != NULL; + bool is_id = false; bool is_type_null = false; @@ -1119,46 +1121,38 @@ static int rna_property_override_equals_propptr( if (is_id) { BLI_assert(propptr_a->data == propptr_a->id.data && propptr_b->data == propptr_b->id.data); + BLI_assert(no_ownership); /* For now, once we deal with nodetrees we'll want to get rid of that one. */ } if (override) { - if (rna_path) { - if (is_type_null || is_id) { - /* In case this is an ID (or one of the pointers is NULL), do not compare structs! - * This is a quite safe path to infinite loop. - * Instead, just compare pointers themselves (we assume sub-ID structs cannot loop). */ - const int comp = (propptr_a->data != propptr_b->data); - - if (comp != 0 && rna_path) { - bool created = false; - IDOverrideStaticProperty *op = BKE_override_static_property_get(override, rna_path, &created); + if (no_ownership /* || is_id */ || is_type_null) { + /* In case this pointer prop does not own its data (or one is NULL), do not compare structs! + * This is a quite safe path to infinite loop, among other nasty issues. + * Instead, just compare pointers themselves. */ + const int comp = (propptr_a->data != propptr_b->data); - if (op != NULL && created) { /* If not yet overridden... */ - BKE_override_static_property_operation_get( - op, IDOVERRIDESTATIC_OP_REPLACE, NULL, NULL, -1, -1, true, NULL, NULL); - if (r_override_changed) { - *r_override_changed = created; - } - } - } + if (do_create && comp != 0) { + bool created = false; + IDOverrideStaticProperty *op = BKE_override_static_property_get(override, rna_path, &created); - return comp; - } - else { - const bool changed = RNA_struct_auto_override(propptr_a, propptr_b, override, rna_path); - if (r_override_changed) { - *r_override_changed = *r_override_changed || changed; + if (op != NULL && created) { /* If not yet overridden... */ + BKE_override_static_property_operation_get( + op, IDOVERRIDESTATIC_OP_REPLACE, NULL, NULL, -1, -1, true, NULL, NULL); + if (r_override_changed) { + *r_override_changed = created; + } } - /* XXX Simplification here, if no override was added we assume they are equal, - * this may not be good behavior, time will say. */ - return !changed; } + + return comp; } else { - return !RNA_struct_override_matches( - propptr_a, propptr_b, override, - flags & RNA_OVERRIDE_COMPARE_IGNORE_NON_OVERRIDABLE, - flags & RNA_OVERRIDE_COMPARE_IGNORE_OVERRIDDEN); + eRNAOverrideMatchResult report_flags = 0; + const bool match = RNA_struct_override_matches(propptr_a, propptr_b, rna_path, override, flags, &report_flags); + if (r_override_changed && (report_flags & RNA_OVERRIDE_MATCH_RESULT_CREATED) != 0) { + *r_override_changed = true; + } + return !match; } } else { @@ -1183,6 +1177,10 @@ int rna_property_override_diff_default(PointerRNA *ptr_a, PointerRNA *ptr_b, { BLI_assert(len_a == len_b); + /* Note: at this point, we are sure that when len_a is zero, we are not handling an (empty) array. */ + + const bool do_create = override != NULL && (flags & RNA_OVERRIDE_COMPARE_CREATE) != 0 && rna_path != NULL; + switch (RNA_property_type(prop_a)) { case PROP_BOOLEAN: { @@ -1198,7 +1196,7 @@ int rna_property_override_diff_default(PointerRNA *ptr_a, PointerRNA *ptr_b, const int comp = memcmp(array_a, array_b, sizeof(int) * len_a); - if (comp != 0 && rna_path) { + if (do_create && comp != 0) { /* XXX TODO this will have to be refined to handle array items */ bool created = false; IDOverrideStaticProperty *op = BKE_override_static_property_get(override, rna_path, &created); @@ -1225,7 +1223,7 @@ int rna_property_override_diff_default(PointerRNA *ptr_a, PointerRNA *ptr_b, const int value_b = RNA_property_boolean_get(ptr_b, prop_b); const int comp = (value_a < value_b) ? -1 : (value_a > value_b) ? 1 : 0; - if (comp != 0 && rna_path) { + if (do_create && comp != 0) { bool created = false; IDOverrideStaticProperty *op = BKE_override_static_property_get(override, rna_path, &created); @@ -1256,7 +1254,7 @@ int rna_property_override_diff_default(PointerRNA *ptr_a, PointerRNA *ptr_b, const int comp = memcmp(array_a, array_b, sizeof(int) * len_a); - if (comp != 0 && rna_path) { + if (do_create && comp != 0) { /* XXX TODO this will have to be refined to handle array items */ bool created = false; IDOverrideStaticProperty *op = BKE_override_static_property_get(override, rna_path, &created); @@ -1283,7 +1281,7 @@ int rna_property_override_diff_default(PointerRNA *ptr_a, PointerRNA *ptr_b, const int value_b = RNA_property_int_get(ptr_b, prop_b); const int comp = (value_a < value_b) ? -1 : (value_a > value_b) ? 1 : 0; - if (comp != 0 && rna_path) { + if (do_create && comp != 0) { bool created = false; IDOverrideStaticProperty *op = BKE_override_static_property_get(override, rna_path, &created); @@ -1315,7 +1313,7 @@ int rna_property_override_diff_default(PointerRNA *ptr_a, PointerRNA *ptr_b, const int comp = memcmp(array_a, array_b, sizeof(float) * len_a); - if (comp != 0 && rna_path) { + if (do_create && comp != 0) { /* XXX TODO this will have to be refined to handle array items */ bool created = false; IDOverrideStaticProperty *op = BKE_override_static_property_get(override, rna_path, &created); @@ -1343,7 +1341,7 @@ int rna_property_override_diff_default(PointerRNA *ptr_a, PointerRNA *ptr_b, const float value_b = RNA_property_float_get(ptr_b, prop_b); const int comp = (value_a < value_b) ? -1 : (value_a > value_b) ? 1 : 0; - if (comp != 0 && rna_path) { + if (do_create && comp != 0) { bool created = false; IDOverrideStaticProperty *op = BKE_override_static_property_get(override, rna_path, &created); @@ -1367,7 +1365,7 @@ int rna_property_override_diff_default(PointerRNA *ptr_a, PointerRNA *ptr_b, const int value_b = RNA_property_enum_get(ptr_b, prop_b); const int comp = value_a != value_b; - if (comp != 0 && rna_path) { + if (do_create && comp != 0) { bool created = false; IDOverrideStaticProperty *op = BKE_override_static_property_get(override, rna_path, &created); @@ -1391,7 +1389,7 @@ int rna_property_override_diff_default(PointerRNA *ptr_a, PointerRNA *ptr_b, char *value_b = RNA_property_string_get_alloc(ptr_b, prop_b, fixed_b, sizeof(fixed_b), &len_str_b); const int comp = strcmp(value_a, value_b); - if (comp != 0 && rna_path) { + if (do_create && comp != 0) { bool created = false; IDOverrideStaticProperty *op = BKE_override_static_property_get(override, rna_path, &created); @@ -1419,9 +1417,10 @@ int rna_property_override_diff_default(PointerRNA *ptr_a, PointerRNA *ptr_b, else { PointerRNA propptr_a = RNA_property_pointer_get(ptr_a, prop_a); PointerRNA propptr_b = RNA_property_pointer_get(ptr_b, prop_b); - return rna_property_override_equals_propptr( - &propptr_a, &propptr_b, mode, - override, rna_path, r_override_changed, flags); + const bool no_ownership = (RNA_property_flag(prop_a) & PROP_PTR_NO_OWNERSHIP) != 0; + return rna_property_override_diff_propptr( + &propptr_a, &propptr_b, mode, no_ownership, + override, rna_path, flags, r_override_changed); } break; } @@ -1468,9 +1467,10 @@ int rna_property_override_diff_default(PointerRNA *ptr_a, PointerRNA *ptr_b, } if (equals) { - const int eq = rna_property_override_equals_propptr( - &iter_a.ptr, &iter_b.ptr, mode, - override, extended_rna_path, r_override_changed, flags); + const bool no_ownership = (RNA_property_flag(prop_a) & PROP_PTR_NO_OWNERSHIP) != 0; + const int eq = rna_property_override_diff_propptr( + &iter_a.ptr, &iter_b.ptr, mode, no_ownership, + override, extended_rna_path, flags, r_override_changed); equals = equals && eq; } diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index 785f805a33e..5518b296e22 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -5676,14 +5676,16 @@ static void rna_def_scene_render_data(BlenderRNA *brna) prop = RNA_def_property(srna, "fps", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "frs_sec"); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); - RNA_def_property_range(prop, 1, 120); + RNA_def_property_range(prop, 1, SHRT_MAX); + RNA_def_property_ui_range(prop, 1, 120, 1, -1); RNA_def_property_ui_text(prop, "FPS", "Framerate, expressed in frames per second"); RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_fps_update"); prop = RNA_def_property(srna, "fps_base", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "frs_sec_base"); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); - RNA_def_property_range(prop, 0.1f, 120.0f); + RNA_def_property_range(prop, 1e-5f, 1e6f); + RNA_def_property_ui_range(prop, 0.1f, 120.0f, 2, -1); RNA_def_property_ui_text(prop, "FPS Base", "Framerate base"); RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_fps_update"); diff --git a/source/blender/makesrna/intern/rna_sculpt_paint.c b/source/blender/makesrna/intern/rna_sculpt_paint.c index ddcf525c3c8..cc447f2a028 100644 --- a/source/blender/makesrna/intern/rna_sculpt_paint.c +++ b/source/blender/makesrna/intern/rna_sculpt_paint.c @@ -297,6 +297,22 @@ static void rna_Sculpt_ShowDiffuseColor_update(bContext *C, PointerRNA *UNUSED(p } } +static void rna_Sculpt_ShowMask_update(bContext *C, PointerRNA *UNUSED(ptr)) +{ + ViewLayer *view_layer = CTX_data_view_layer(C); + Object *object = OBACT(view_layer); + if (object == NULL || object->sculpt == NULL) { + return; + } + Scene *scene = CTX_data_scene(C); + Sculpt *sd = scene->toolsettings->sculpt; + object->sculpt->show_mask = ((sd->flags & SCULPT_HIDE_MASK) == 0); + if (object->sculpt->pbvh != NULL) { + pbvh_show_mask_set(object->sculpt->pbvh, object->sculpt->show_mask); + } + WM_main_add_notifier(NC_OBJECT | ND_DRAW, object); +} + static char *rna_Sculpt_path(PointerRNA *UNUSED(ptr)) { return BLI_strdup("tool_settings.sculpt"); @@ -613,6 +629,12 @@ static void rna_def_sculpt(BlenderRNA *brna) RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Sculpt_ShowDiffuseColor_update"); + prop = RNA_def_property(srna, "show_mask", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_negative_sdna(prop, NULL, "flags", SCULPT_HIDE_MASK); + RNA_def_property_ui_text(prop, "Show Mask", "Show mask as overlay on object"); + RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); + RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Sculpt_ShowMask_update"); + prop = RNA_def_property(srna, "detail_size", PROP_FLOAT, PROP_PIXEL); RNA_def_property_ui_range(prop, 0.5, 40.0, 10, 2); RNA_def_property_ui_text(prop, "Detail Size", "Maximum edge length for dynamic topology sculpting (in pixels)"); diff --git a/source/blender/makesrna/intern/rna_smoke.c b/source/blender/makesrna/intern/rna_smoke.c index 8c2a09f1186..ac13f9d8294 100644 --- a/source/blender/makesrna/intern/rna_smoke.c +++ b/source/blender/makesrna/intern/rna_smoke.c @@ -52,9 +52,9 @@ #ifdef RNA_RUNTIME +#include "BKE_colorband.h" #include "BKE_context.h" #include "BKE_particle.h" -#include "BKE_texture.h" #include "DEG_depsgraph.h" #include "DEG_depsgraph_build.h" @@ -395,7 +395,7 @@ static void rna_Smoke_use_color_ramp_set(PointerRNA *ptr, int value) sds->use_coba = value; if (value && sds->coba == NULL) { - sds->coba = add_colorband(false); + sds->coba = BKE_colorband_add(false); } } diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index 82283019fc8..e748299a635 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -2103,23 +2103,23 @@ static void rna_def_space_outliner(BlenderRNA *brna) PropertyRNA *prop; static const EnumPropertyItem display_mode_items[] = { - {SO_ALL_SCENES, "ALL_SCENES", 0, "All Scenes", "Display data-blocks in all scenes"}, - {SO_CUR_SCENE, "CURRENT_SCENE", 0, "Current Scene", "Display data-blocks in current scene"}, - {SO_VISIBLE, "VISIBLE_LAYERS", 0, "Visible Layers", "Display data-blocks in visible layers"}, - {SO_SELECTED, "SELECTED", 0, "Selected", "Display data-blocks of selected, visible objects"}, - {SO_ACTIVE, "ACTIVE", 0, "Active", "Display data-blocks of active object"}, - {SO_SAME_TYPE, "SAME_TYPES", 0, "Same Types", - "Display data-blocks of all objects of same type as selected object"}, + {SO_VIEW_LAYER, "VIEW_LAYER", 0, "View Layer", "Display the collections of the active view layer"}, + {SO_COLLECTIONS, "COLLECTIONS", 0, "Collections", "Display all collections based on the " + "master collection hierarchy"}, + {SO_SCENES, "SCENES", 0, "Scenes", "Display composition related data in all scenes"}, {SO_GROUPS, "GROUPS", 0, "Groups", "Display groups and their data-blocks"}, {SO_SEQUENCE, "SEQUENCE", 0, "Sequence", "Display sequence data-blocks"}, {SO_LIBRARIES, "LIBRARIES", 0, "Blender File", "Display data of current file and linked libraries"}, {SO_DATABLOCKS, "DATABLOCKS", 0, "Data-Blocks", "Display all raw data-blocks"}, - {SO_USERDEF, "USER_PREFERENCES", 0, "User Preferences", "Display user preference data"}, {SO_ID_ORPHANS, "ORPHAN_DATA", 0, "Orphan Data", "Display data-blocks which are unused and/or will be lost when the file is reloaded"}, - {SO_ACT_LAYER, "ACT_LAYER", 0, "Active View Layer", "Display the collections of the active view layer"}, - {SO_COLLECTIONS, "MASTER_COLLECTION", 0, "Master Collection Tree", "Display all collections based on the " - "master collection hierarchy"}, + {0, NULL, 0, NULL, NULL} + }; + + static const EnumPropertyItem filter_state_items[] = { + {SO_FILTER_OB_VISIBLE, "VISIBLE", ICON_RESTRICT_VIEW_OFF, "Visible", "Show visible objects"}, + {SO_FILTER_OB_SELECTED, "SELECTED", ICON_RESTRICT_SELECT_OFF, "Selected", "Show selected objects"}, + {SO_FILTER_OB_ACTIVE, "ACTIVE", ICON_LAYER_ACTIVE, "Active", "Show only the active object"}, {0, NULL, 0, NULL, NULL} }; @@ -2142,22 +2142,119 @@ static void rna_def_space_outliner(BlenderRNA *brna) prop = RNA_def_property(srna, "use_filter_case_sensitive", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "search_flags", SO_FIND_CASE_SENSITIVE); RNA_def_property_ui_text(prop, "Case Sensitive Matches Only", "Only use case sensitive matches of search string"); + RNA_def_property_ui_icon(prop, ICON_SYNTAX_OFF, 0); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL); prop = RNA_def_property(srna, "use_filter_complete", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "search_flags", SO_FIND_COMPLETE); RNA_def_property_ui_text(prop, "Complete Matches Only", "Only use complete matches of search string"); + RNA_def_property_ui_icon(prop, ICON_OUTLINER_DATA_FONT, 0); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL); prop = RNA_def_property(srna, "use_sort_alpha", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SO_SKIP_SORT_ALPHA); RNA_def_property_ui_text(prop, "Sort Alphabetically", ""); + RNA_def_property_ui_icon(prop, ICON_SORTALPHA, 0); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL); prop = RNA_def_property(srna, "show_restrict_columns", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SO_HIDE_RESTRICTCOLS); RNA_def_property_ui_text(prop, "Show Restriction Columns", "Show column"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL); + + /* Filters. */ + prop = RNA_def_property(srna, "use_filter_search", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "filter", SO_FILTER_SEARCH); + RNA_def_property_ui_text(prop, "Search Name", "Filter searched elements"); + RNA_def_property_ui_icon(prop, ICON_VIEWZOOM, 0); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL); + + prop = RNA_def_property(srna, "use_filters", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "filter", SO_FILTER_ENABLE); + RNA_def_property_ui_text(prop, "Use Filters", "Use filters"); + RNA_def_property_ui_icon(prop, ICON_FILTER, 0); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL); + + prop = RNA_def_property(srna, "use_filter_object", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_negative_sdna(prop, NULL, "filter", SO_FILTER_NO_OBJECT); + RNA_def_property_ui_text(prop, "Filter Objects", "Show objects"); + RNA_def_property_ui_icon(prop, ICON_OBJECT_DATA, 0); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL); + + prop = RNA_def_property(srna, "use_filter_object_content", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_negative_sdna(prop, NULL, "filter", SO_FILTER_NO_OB_CONTENT); + RNA_def_property_ui_text(prop, "Filter Objects Contents", "Show what is inside the objects elements"); + RNA_def_property_ui_icon(prop, ICON_MODIFIER, 0); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL); + + prop = RNA_def_property(srna, "use_filter_children", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_negative_sdna(prop, NULL, "filter", SO_FILTER_NO_CHILDREN); + RNA_def_property_ui_text(prop, "Filter Objects Children", "Show children"); + RNA_def_property_ui_icon(prop, ICON_PLUS, 0); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL); + + prop = RNA_def_property(srna, "use_filter_collection", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_negative_sdna(prop, NULL, "filter", SO_FILTER_NO_COLLECTION); + RNA_def_property_ui_text(prop, "Filter Collections", "Show collections"); + RNA_def_property_ui_icon(prop, ICON_COLLAPSEMENU, 0); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL); + + /* Filters object state. */ + prop = RNA_def_property(srna, "use_filter_object_state", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "filter", SO_FILTER_OB_STATE); + RNA_def_property_ui_text(prop, "Filter Object State", "Filter objects based on their state (visible, ...)." + "This can be slow"); + RNA_def_property_ui_icon(prop, ICON_LAYER_USED, 0); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL); + + prop = RNA_def_property(srna, "filter_state", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "filter_state"); + RNA_def_property_enum_items(prop, filter_state_items); + RNA_def_property_ui_text(prop, "State Filter", ""); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL); + + /* Filters object type. */ + prop = RNA_def_property(srna, "use_filter_object_type", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "filter", SO_FILTER_OB_TYPE); + RNA_def_property_ui_text(prop, "Filter Object Type", "Show specific objects types"); + RNA_def_property_ui_icon(prop, ICON_MESH_CUBE, 0); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL); + + prop = RNA_def_property(srna, "use_filter_object_mesh", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_negative_sdna(prop, NULL, "filter", SO_FILTER_NO_OB_MESH); + RNA_def_property_ui_text(prop, "Show Meshes", "Show mesh objects"); + RNA_def_property_ui_icon(prop, ICON_OUTLINER_OB_MESH, 0); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL); + + prop = RNA_def_property(srna, "use_filter_object_armature", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_negative_sdna(prop, NULL, "filter", SO_FILTER_NO_OB_ARMATURE); + RNA_def_property_ui_text(prop, "Show Armatures", "Show armature objects"); + RNA_def_property_ui_icon(prop, ICON_OUTLINER_OB_ARMATURE, 0); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL); + + prop = RNA_def_property(srna, "use_filter_object_empty", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_negative_sdna(prop, NULL, "filter", SO_FILTER_NO_OB_EMPTY); + RNA_def_property_ui_text(prop, "Show Empties", "Show empty objects"); + RNA_def_property_ui_icon(prop, ICON_OUTLINER_OB_EMPTY, 0); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL); + + prop = RNA_def_property(srna, "use_filter_object_lamp", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_negative_sdna(prop, NULL, "filter", SO_FILTER_NO_OB_LAMP); + RNA_def_property_ui_text(prop, "Show Lamps", "Show lamps objects"); + RNA_def_property_ui_icon(prop, ICON_OUTLINER_OB_LAMP, 0); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL); + + prop = RNA_def_property(srna, "use_filter_object_camera", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_negative_sdna(prop, NULL, "filter", SO_FILTER_NO_OB_CAMERA); + RNA_def_property_ui_text(prop, "Show Cameras", "Show camera objects"); + RNA_def_property_ui_icon(prop, ICON_OUTLINER_OB_CAMERA, 0); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL); + + prop = RNA_def_property(srna, "use_filter_object_others", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_negative_sdna(prop, NULL, "filter", SO_FILTER_NO_OB_OTHERS); + RNA_def_property_ui_text(prop, "Show Other Objects", "Show curves, lattices, light probes, fonts, ..."); + RNA_def_property_ui_icon(prop, ICON_ZOOMIN, 0); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL); } static void rna_def_space_view3d(BlenderRNA *brna) diff --git a/source/blender/makesrna/intern/rna_texture.c b/source/blender/makesrna/intern/rna_texture.c index 43fe7bd3f76..42e3e2c83fb 100644 --- a/source/blender/makesrna/intern/rna_texture.c +++ b/source/blender/makesrna/intern/rna_texture.c @@ -112,6 +112,7 @@ static const EnumPropertyItem blend_type_items[] = { #include "RNA_access.h" +#include "BKE_colorband.h" #include "BKE_context.h" #include "BKE_image.h" #include "BKE_texture.h" @@ -407,7 +408,7 @@ static void rna_Texture_use_color_ramp_set(PointerRNA *ptr, int value) else tex->flag &= ~TEX_COLORBAND; if ((tex->flag & TEX_COLORBAND) && tex->coba == NULL) - tex->coba = add_colorband(false); + tex->coba = BKE_colorband_add(false); } static void rna_Texture_use_nodes_update(bContext *C, PointerRNA *ptr) diff --git a/source/blender/makesrna/intern/rna_tracking.c b/source/blender/makesrna/intern/rna_tracking.c index d23017429c1..ccc118edfb6 100644 --- a/source/blender/makesrna/intern/rna_tracking.c +++ b/source/blender/makesrna/intern/rna_tracking.c @@ -48,6 +48,9 @@ #ifdef RNA_RUNTIME +#include "DNA_anim_types.h" + +#include "BKE_animsys.h" #include "BKE_node.h" #include "DEG_depsgraph.h" @@ -56,71 +59,6 @@ #include "WM_api.h" -static MovieTrackingObject *tracking_object_from_track(MovieClip *clip, - MovieTrackingTrack *track) -{ - MovieTracking *tracking = &clip->tracking; - ListBase *tracksbase = &tracking->tracks; - /* TODO: it's a bit difficult to find list track came from knowing just - * movie clip ID and MovieTracking structure, so keep this naive - * search for a while */ - if (BLI_findindex(tracksbase, track) == -1) { - MovieTrackingObject *object = tracking->objects.first; - while (object) { - if (BLI_findindex(&object->tracks, track) != -1) { - return object; - } - object = object->next; - } - } - return NULL; -} - -static ListBase *tracking_tracksbase_from_track(MovieClip *clip, - MovieTrackingTrack *track) -{ - MovieTracking *tracking = &clip->tracking; - MovieTrackingObject *object = tracking_object_from_track(clip, track); - if (object != NULL) { - return &object->tracks; - } - return &tracking->tracks; -} - -static MovieTrackingObject *tracking_object_from_plane_track( - MovieClip *clip, - MovieTrackingPlaneTrack *plane_track) -{ - MovieTracking *tracking = &clip->tracking; - ListBase *plane_tracks_base = &tracking->plane_tracks; - /* TODO: it's a bit difficult to find list track came from knowing just - * movie clip ID and MovieTracking structure, so keep this naive - * search for a while */ - if (BLI_findindex(plane_tracks_base, plane_track) == -1) { - MovieTrackingObject *object = tracking->objects.first; - while (object) { - if (BLI_findindex(&object->plane_tracks, plane_track) != -1) { - return object; - } - object = object->next; - } - } - return NULL; -} - -static ListBase *tracking_tracksbase_from_plane_track( - MovieClip *clip, - MovieTrackingPlaneTrack *plane_track) -{ - MovieTracking *tracking = &clip->tracking; - MovieTrackingObject *object = tracking_object_from_plane_track(clip, - plane_track); - if (object != NULL) { - return &object->plane_tracks; - } - return &tracking->plane_tracks; -} - static char *rna_tracking_path(PointerRNA *UNUSED(ptr)) { return BLI_sprintfN("tracking"); @@ -150,19 +88,12 @@ static char *rna_trackingTrack_path(PointerRNA *ptr) { MovieClip *clip = (MovieClip *)ptr->id.data; MovieTrackingTrack *track = (MovieTrackingTrack *)ptr->data; - MovieTrackingObject *object = tracking_object_from_track(clip, track); - char track_name_esc[sizeof(track->name) * 2]; - BLI_strescape(track_name_esc, track->name, sizeof(track_name_esc)); - if (object == NULL) { - return BLI_sprintfN("tracking.tracks[\"%s\"]", track_name_esc); - } - else { - char object_name_esc[sizeof(object->name) * 2]; - BLI_strescape(object_name_esc, object->name, sizeof(object_name_esc)); - return BLI_sprintfN("tracking.objects[\"%s\"].tracks[\"%s\"]", - object_name_esc, - track_name_esc); - } + /* Escaped object name, escaped track name, rest of the path. */ + char rna_path[MAX_NAME * 4 + 64]; + BKE_tracking_get_rna_path_for_track(&clip->tracking, + track, + rna_path, sizeof(rna_path)); + return BLI_strdup(rna_path); } static void rna_trackingTracks_begin(CollectionPropertyIterator *iter, PointerRNA *ptr) @@ -256,9 +187,26 @@ static void rna_trackingTrack_name_set(PointerRNA *ptr, const char *value) { MovieClip *clip = (MovieClip *)ptr->id.data; MovieTrackingTrack *track = (MovieTrackingTrack *)ptr->data; - ListBase *tracksbase = tracking_tracksbase_from_track(clip, track); + ListBase *tracksbase = + BKE_tracking_find_tracks_list_for_track(&clip->tracking, track); + /* Store old name, for the animation fix later. */ + char old_name[sizeof(track->name)]; + BLI_strncpy(old_name, track->name, sizeof(track->name)); + /* Update the name, */ BLI_strncpy(track->name, value, sizeof(track->name)); BKE_tracking_track_unique_name(tracksbase, track); + /* Fix animation paths. */ + AnimData *adt = BKE_animdata_from_id(&clip->id); + if (adt != NULL) { + char rna_path[MAX_NAME * 2 + 64]; + BKE_tracking_get_rna_path_prefix_for_track(&clip->tracking, + track, + rna_path, sizeof(rna_path)); + BKE_animdata_fix_paths_rename(&clip->id, adt, NULL, + rna_path, + old_name, track->name, + 0, 0, 1); + } } static int rna_trackingTrack_select_get(PointerRNA *ptr) @@ -327,28 +275,40 @@ static char *rna_trackingPlaneTrack_path(PointerRNA *ptr) { MovieClip *clip = (MovieClip *)ptr->id.data; MovieTrackingPlaneTrack *plane_track = (MovieTrackingPlaneTrack *)ptr->data; - char track_name_esc[sizeof(plane_track->name) * 2]; - MovieTrackingObject *object = tracking_object_from_plane_track(clip, plane_track); - BLI_strescape(track_name_esc, plane_track->name, sizeof(track_name_esc)); - if (object == NULL) { - return BLI_sprintfN("tracking.plane_tracks[\"%s\"]", track_name_esc); - } - else { - char object_name_esc[sizeof(object->name) * 2]; - BLI_strescape(object_name_esc, object->name, sizeof(object_name_esc)); - return BLI_sprintfN("tracking.objects[\"%s\"].plane_tracks[\"%s\"]", - object_name_esc, - track_name_esc); - } + /* Escaped object name, escaped track name, rest of the path. */ + char rna_path[MAX_NAME * 4 + 64]; + BKE_tracking_get_rna_path_for_plane_track(&clip->tracking, + plane_track, + rna_path, sizeof(rna_path)); + return BLI_strdup(rna_path); } static void rna_trackingPlaneTrack_name_set(PointerRNA *ptr, const char *value) { MovieClip *clip = (MovieClip *)ptr->id.data; MovieTrackingPlaneTrack *plane_track = (MovieTrackingPlaneTrack *)ptr->data; - ListBase *plane_tracks_base = tracking_tracksbase_from_plane_track(clip, plane_track); + ListBase *plane_tracks_base = + BKE_tracking_find_tracks_list_for_plane_track(&clip->tracking, + plane_track); + /* Store old name, for the animation fix later. */ + char old_name[sizeof(plane_track->name)]; + BLI_strncpy(old_name, plane_track->name, sizeof(plane_track->name)); + /* Update the name, */ BLI_strncpy(plane_track->name, value, sizeof(plane_track->name)); BKE_tracking_plane_track_unique_name(plane_tracks_base, plane_track); + /* Fix animation paths. */ + AnimData *adt = BKE_animdata_from_id(&clip->id); + if (adt != NULL) { + char rna_path[MAX_NAME * 2 + 64]; + BKE_tracking_get_rna_path_prefix_for_plane_track(&clip->tracking, + plane_track, + rna_path, + sizeof(rna_path)); + BKE_animdata_fix_paths_rename(&clip->id, adt, NULL, + rna_path, + old_name, plane_track->name, + 0, 0, 1); + } } static char *rna_trackingCamera_path(PointerRNA *UNUSED(ptr)) @@ -1651,6 +1611,7 @@ static void rna_def_trackingPlaneTrack(BlenderRNA *brna) /* auto keyframing */ prop = RNA_def_property(srna, "use_auto_keying", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", PLANE_TRACK_AUTOKEY); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_ui_text(prop, "Auto Keyframe", "Automatic keyframe insertion when moving plane corners"); RNA_def_property_ui_icon(prop, ICON_REC, 0); diff --git a/source/blender/makesrna/intern/rna_ui_api.c b/source/blender/makesrna/intern/rna_ui_api.c index 51bdc0ea9ff..fbc16f01116 100644 --- a/source/blender/makesrna/intern/rna_ui_api.c +++ b/source/blender/makesrna/intern/rna_ui_api.c @@ -454,6 +454,12 @@ void RNA_api_ui_layout(StructRNA *srna) {0, NULL, 0, NULL, NULL} }; + static const EnumPropertyItem id_template_filter_items[] = { + {UI_TEMPLATE_ID_FILTER_ALL, "ALL", 0, "All", ""}, + {UI_TEMPLATE_ID_FILTER_AVAILABLE, "AVAILABLE", 0, "Available", ""}, + {0, NULL, 0, NULL, NULL} + }; + static float node_socket_color_default[] = { 0.0f, 0.0f, 0.0f, 1.0f }; /* simple layout specifiers */ @@ -549,7 +555,7 @@ void RNA_api_ui_layout(StructRNA *srna) RNA_def_boolean(func, "icon_only", false, "", "Draw only icons in buttons, no text"); RNA_def_boolean(func, "event", false, "", "Use button to input key events"); RNA_def_boolean(func, "full_event", false, "", "Use button to input full events including modifiers"); - RNA_def_boolean(func, "emboss", true, "", "Draw the button itself, just the icon/text"); + RNA_def_boolean(func, "emboss", true, "", "Draw the button itself, not just the icon/text"); RNA_def_int(func, "index", -1, -2, INT_MAX, "", "The index of this button, when set a single member of an array can be accessed, " "when set to -1 all array members are used", -2, INT_MAX); /* RNA_NO_INDEX == -1 */ @@ -582,7 +588,7 @@ void RNA_api_ui_layout(StructRNA *srna) RNA_def_function(srna, "operator_menu_hold", "rna_uiItemOMenuHold") : RNA_def_function(srna, "operator", "rna_uiItemO"); api_ui_item_op_common(func); - RNA_def_boolean(func, "emboss", true, "", "Draw the button itself, just the icon/text"); + RNA_def_boolean(func, "emboss", true, "", "Draw the button itself, not just the icon/text"); RNA_def_boolean(func, "depress", false, "", "Draw pressed in"); parm = RNA_def_property(func, "icon_value", PROP_INT, PROP_UNSIGNED); RNA_def_property_ui_text(parm, "Icon Value", "Override automatic icon of the item"); @@ -685,7 +691,9 @@ void RNA_api_ui_layout(StructRNA *srna) RNA_def_string(func, "new", NULL, 0, "", "Operator identifier to create a new ID block"); RNA_def_string(func, "open", NULL, 0, "", "Operator identifier to open a file for creating a new ID block"); RNA_def_string(func, "unlink", NULL, 0, "", "Operator identifier to unlink the ID block"); - + RNA_def_enum(func, "filter", id_template_filter_items, UI_TEMPLATE_ID_FILTER_ALL, + "", "Optionally limit the items which can be selected"); + func = RNA_def_function(srna, "template_ID_preview", "uiTemplateIDPreview"); RNA_def_function_flag(func, FUNC_USE_CONTEXT); api_ui_item_rna_common(func); @@ -694,7 +702,9 @@ void RNA_api_ui_layout(StructRNA *srna) RNA_def_string(func, "unlink", NULL, 0, "", "Operator identifier to unlink the ID block"); RNA_def_int(func, "rows", 0, 0, INT_MAX, "Number of thumbnail preview rows to display", "", 0, INT_MAX); RNA_def_int(func, "cols", 0, 0, INT_MAX, "Number of thumbnail preview columns to display", "", 0, INT_MAX); - + RNA_def_enum(func, "filter", id_template_filter_items, UI_TEMPLATE_ID_FILTER_ALL, + "", "Optionally limit the items which can be selected"); + func = RNA_def_function(srna, "template_any_ID", "rna_uiTemplateAnyID"); parm = RNA_def_pointer(func, "data", "AnyType", "", "Data from which to take property"); RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); @@ -711,6 +721,8 @@ void RNA_api_ui_layout(StructRNA *srna) RNA_def_string(func, "new", NULL, 0, "", "Operator identifier to create a new ID block"); RNA_def_string(func, "open", NULL, 0, "", "Operator identifier to open a file for creating a new ID block"); RNA_def_string(func, "unlink", NULL, 0, "", "Operator identifier to unlink the ID block"); + RNA_def_enum(func, "filter", id_template_filter_items, UI_TEMPLATE_ID_FILTER_ALL, + "", "Optionally limit the items which can be selected"); func = RNA_def_function(srna, "template_search", "uiTemplateSearch"); RNA_def_function_flag(func, FUNC_USE_CONTEXT); diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c index 1cdd43eeffc..7bd1e4bb3b2 100644 --- a/source/blender/makesrna/intern/rna_userdef.c +++ b/source/blender/makesrna/intern/rna_userdef.c @@ -24,6 +24,7 @@ * \ingroup RNA */ +#include <limits.h> #include <stdlib.h> #include "DNA_curve_types.h" @@ -34,6 +35,7 @@ #include "DNA_scene_types.h" #include "BLI_utildefines.h" +#include "BLI_math_base.h" #include "BKE_appdir.h" #include "BKE_DerivedMesh.h" @@ -145,6 +147,12 @@ static void rna_userdef_dpi_update(Main *bmain, Scene *UNUSED(scene), PointerRNA WM_main_add_notifier(NC_SCREEN | NA_EDITED, NULL); /* refresh region sizes */ } +static void rna_userdef_update_ui(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *UNUSED(ptr)) +{ + WM_main_add_notifier(NC_WINDOW, NULL); + WM_main_add_notifier(NC_SCREEN | NA_EDITED, NULL); /* refresh region sizes */ +} + static void rna_userdef_language_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *UNUSED(ptr)) { BLF_cache_clear(); @@ -638,6 +646,27 @@ static StructRNA *rna_AddonPref_refine(PointerRNA *ptr) #else +/* TODO(sergey): This technically belongs to blenlib, but we don't link + * makesrna against it. + */ + +/* Get maximum addressable memory in megabytes, */ +static size_t max_memory_in_megabytes(void) +{ + /* Maximum addressable bytes on this platform. */ + const size_t limit_bytes = (((size_t)1) << ((sizeof(size_t) * 8) - 1)); + /* Convert it to megabytes and return. */ + return (limit_bytes >> 20); +} + +/* Same as above, but clipped to int capacity. */ +static int max_memory_in_megabytes_int(void) +{ + const size_t limit_megabytes = max_memory_in_megabytes(); + /* NOTE: The result will fit into integer. */ + return (int)min_zz(limit_megabytes, (size_t)INT_MAX); +} + static void rna_def_userdef_theme_ui_font_style(BlenderRNA *brna) { StructRNA *srna; @@ -3397,12 +3426,24 @@ static void rna_def_userdef_view(BlenderRNA *brna) RNA_def_property_boolean_negative_sdna(prop, NULL, "uiflag", USER_SPLASH_DISABLE); RNA_def_property_ui_text(prop, "Show Splash", "Display splash screen on startup"); + prop = RNA_def_property(srna, "show_playback_fps", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "uiflag", USER_SHOW_FPS); RNA_def_property_ui_text(prop, "Show Playback FPS", "Show the frames per second screen refresh rate, while animation is played back"); RNA_def_property_update(prop, 0, "rna_userdef_update"); - + + /* app flags (use for app-templates) */ + prop = RNA_def_property(srna, "show_layout_ui", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_negative_sdna(prop, NULL, "app_flag", USER_APP_LOCK_UI_LAYOUT); + RNA_def_property_ui_text(prop, "Show Layout Widgets", "Show screen layout editing UI"); + RNA_def_property_update(prop, 0, "rna_userdef_update_ui"); + + prop = RNA_def_property(srna, "show_view3d_cursor", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_negative_sdna(prop, NULL, "app_flag", USER_APP_VIEW3D_HIDE_CURSOR); + RNA_def_property_ui_text(prop, "Show 3D View Cursor", ""); + RNA_def_property_update(prop, 0, "rna_userdef_update"); + /* menus */ prop = RNA_def_property(srna, "use_mouse_over_open", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "uiflag", USER_MENUOPENAUTO); @@ -3479,12 +3520,12 @@ static void rna_def_userdef_view(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Global Pivot", "Lock the same rotation/scaling pivot in all 3D Views"); prop = RNA_def_property(srna, "use_mouse_depth_navigate", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "uiflag", USER_ZBUF_ORBIT); + RNA_def_property_boolean_sdna(prop, NULL, "uiflag", USER_DEPTH_NAVIGATE); RNA_def_property_ui_text(prop, "Auto Depth", "Use the depth under the mouse to improve view pan/rotate/zoom functionality"); prop = RNA_def_property(srna, "use_mouse_depth_cursor", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "uiflag", USER_ZBUF_CURSOR); + RNA_def_property_boolean_sdna(prop, NULL, "uiflag", USER_DEPTH_CURSOR); RNA_def_property_ui_text(prop, "Cursor Depth", "Use the depth under the mouse when placing the cursor"); @@ -3552,6 +3593,11 @@ static void rna_def_userdef_view(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Manipulator", "Use 3D transform manipulator"); RNA_def_property_update(prop, 0, "rna_userdef_show_manipulator_update"); + prop = RNA_def_property(srna, "show_manipulator_navigate", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "manipulator_flag", USER_MANIPULATOR_DRAW_NAVIGATE); + RNA_def_property_ui_text(prop, "Navigate Manipulator", "Use 3D navigation manipulator"); + RNA_def_property_update(prop, 0, "rna_userdef_show_manipulator_update"); + /* TODO, expose once it's working. */ #if 0 prop = RNA_def_property(srna, "show_manipulator_shaded", PROP_BOOLEAN, PROP_NONE); @@ -3670,7 +3716,7 @@ static void rna_def_userdef_edit(BlenderRNA *brna) prop = RNA_def_property(srna, "undo_memory_limit", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "undomemory"); - RNA_def_property_range(prop, 0, 32767); + RNA_def_property_range(prop, 0, max_memory_in_megabytes_int()); RNA_def_property_ui_text(prop, "Undo Memory Size", "Maximum memory usage in megabytes (0 means unlimited)"); prop = RNA_def_property(srna, "use_global_undo", PROP_BOOLEAN, PROP_NONE); @@ -4080,7 +4126,7 @@ static void rna_def_userdef_system(BlenderRNA *brna) prop = RNA_def_property(srna, "memory_cache_limit", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "memcachelimit"); - RNA_def_property_range(prop, 0, (sizeof(void *) == 8) ? 1024 * 32 : 1024); /* 32 bit 2 GB, 64 bit 32 GB */ + RNA_def_property_range(prop, 0, max_memory_in_megabytes_int()); RNA_def_property_ui_text(prop, "Memory Cache Limit", "Memory cache limit (in megabytes)"); RNA_def_property_update(prop, 0, "rna_Userdef_memcache_update"); diff --git a/source/blender/makesrna/intern/rna_wm.c b/source/blender/makesrna/intern/rna_wm.c index 36f07db727b..bcb5bb524f0 100644 --- a/source/blender/makesrna/intern/rna_wm.c +++ b/source/blender/makesrna/intern/rna_wm.c @@ -1586,6 +1586,11 @@ static void rna_def_operator_options_runtime(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Invoke", "True when invoked (even if only the execute callbacks available)"); RNA_def_property_clear_flag(prop, PROP_EDITABLE); + prop = RNA_def_property(srna, "is_repeat", PROP_BOOLEAN, PROP_BOOLEAN); + RNA_def_property_boolean_sdna(prop, NULL, "flag", OP_IS_REPEAT); + RNA_def_property_ui_text(prop, "Repeat", "True when run from the redo panel"); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + prop = RNA_def_property(srna, "use_cursor_region", PROP_BOOLEAN, PROP_BOOLEAN); RNA_def_property_boolean_sdna(prop, NULL, "flag", OP_IS_MODAL_CURSOR_REGION); RNA_def_property_ui_text(prop, "Focus Region", "Enable to use the region under the cursor for modal execution"); @@ -1908,7 +1913,12 @@ static void rna_def_event(BlenderRNA *brna) prop = RNA_def_property(srna, "is_tablet", PROP_BOOLEAN, PROP_NONE); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_boolean_funcs(prop, "rna_Event_is_tablet_get", NULL); - RNA_def_property_ui_text(prop, "Tablet Pressure", "The pressure of the tablet or 1.0 if no tablet present"); + RNA_def_property_ui_text(prop, "Is Tablet", "The event has tablet data"); + + prop = RNA_def_property(srna, "is_mouse_absolute", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "is_motion_absolute", 1); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, "Absolute Motion", "The last motion event was an absolute input"); /* modifiers */ prop = RNA_def_property(srna, "shift", PROP_BOOLEAN, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_wm_api.c b/source/blender/makesrna/intern/rna_wm_api.c index 188b63d7d24..82077051c18 100644 --- a/source/blender/makesrna/intern/rna_wm_api.c +++ b/source/blender/makesrna/intern/rna_wm_api.c @@ -504,8 +504,11 @@ void RNA_api_wm(StructRNA *srna) /* invoke enum */ func = RNA_def_function(srna, "invoke_search_popup", "rna_Operator_enum_search_invoke"); - RNA_def_function_ui_description(func, "Operator search popup invoke (search in values of " - "operator's type 'prop' EnumProperty, and execute it on confirmation)"); + RNA_def_function_ui_description( + func, + "Operator search popup invoke which " + "searches values of the operator's :class:`bpy.types.Operator.bl_property` " + "(which must be an EnumProperty), executing it on confirmation"); rna_generic_op_invoke(func, 0); /* invoke functions, for use with python */ diff --git a/source/blender/makesrna/intern/rna_wm_manipulator.c b/source/blender/makesrna/intern/rna_wm_manipulator.c index 00705456fc7..d6de12407b0 100644 --- a/source/blender/makesrna/intern/rna_wm_manipulator.c +++ b/source/blender/makesrna/intern/rna_wm_manipulator.c @@ -401,6 +401,7 @@ RNA_MANIPULATOR_GENERIC_FLAG_RW_DEF(flag_use_draw_value, flag, WM_MANIPULATOR_DR RNA_MANIPULATOR_GENERIC_FLAG_RW_DEF(flag_use_draw_offset_scale, flag, WM_MANIPULATOR_DRAW_OFFSET_SCALE); RNA_MANIPULATOR_GENERIC_FLAG_NEG_RW_DEF(flag_use_draw_scale, flag, WM_MANIPULATOR_DRAW_OFFSET_SCALE); RNA_MANIPULATOR_GENERIC_FLAG_RW_DEF(flag_hide, flag, WM_MANIPULATOR_HIDDEN); +RNA_MANIPULATOR_GENERIC_FLAG_RW_DEF(flag_use_grab_cursor, flag, WM_MANIPULATOR_GRAB_CURSOR); /* wmManipulator.state */ RNA_MANIPULATOR_FLAG_RO_DEF(state_is_highlight, state, WM_MANIPULATOR_STATE_HIGHLIGHT); @@ -1087,6 +1088,13 @@ static void rna_def_manipulator(BlenderRNA *brna, PropertyRNA *cprop) prop, "rna_Manipulator_flag_hide_get", "rna_Manipulator_flag_hide_set"); RNA_def_property_ui_text(prop, "Hide", ""); RNA_def_property_update(prop, NC_SCREEN | NA_EDITED, NULL); + /* WM_MANIPULATOR_GRAB_CURSOR */ + prop = RNA_def_property(srna, "use_grab_cursor", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_funcs( + prop, "rna_Manipulator_flag_use_grab_cursor_get", "rna_Manipulator_flag_use_grab_cursor_set"); + RNA_def_property_ui_text(prop, "Grab Cursor", ""); + RNA_def_property_update(prop, NC_SCREEN | NA_EDITED, NULL); + /* WM_MANIPULATOR_DRAW_HOVER */ prop = RNA_def_property(srna, "use_draw_hover", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_funcs( diff --git a/source/blender/modifiers/intern/MOD_array.c b/source/blender/modifiers/intern/MOD_array.c index 81ace75f2b1..91501e539c0 100644 --- a/source/blender/modifiers/intern/MOD_array.c +++ b/source/blender/modifiers/intern/MOD_array.c @@ -177,8 +177,8 @@ static void dm_mvert_map_doubles( source_end = source_start + source_num_verts; /* build array of MVerts to be tested for merging */ - sorted_verts_target = MEM_mallocN(sizeof(SortVertsElem) * target_num_verts, __func__); - sorted_verts_source = MEM_mallocN(sizeof(SortVertsElem) * source_num_verts, __func__); + sorted_verts_target = MEM_malloc_arrayN(target_num_verts, sizeof(SortVertsElem), __func__); + sorted_verts_source = MEM_malloc_arrayN(source_num_verts, sizeof(SortVertsElem), __func__); /* Copy target vertices index and cos into SortVertsElem array */ svert_from_mvert(sorted_verts_target, mverts + target_start, target_start, target_end); @@ -491,7 +491,7 @@ static DerivedMesh *arrayModifier_doArray( if (use_merge) { /* Will need full_doubles_map for handling merge */ - full_doubles_map = MEM_mallocN(sizeof(int) * result_nverts, "mod array doubles map"); + full_doubles_map = MEM_malloc_arrayN(result_nverts, sizeof(int), "mod array doubles map"); copy_vn_i(full_doubles_map, result_nverts, -1); } @@ -608,6 +608,26 @@ static DerivedMesh *arrayModifier_doArray( } } + /* handle UVs */ + if (chunk_nloops > 0 && is_zero_v2(amd->uv_offset) == false) { + const int totuv = CustomData_number_of_layers(&result->loopData, CD_MLOOPUV); + for (i = 0; i < totuv; i++) { + MLoopUV *dmloopuv = CustomData_get_layer_n(&result->loopData, CD_MLOOPUV, i); + dmloopuv += chunk_nloops; + for (c = 1; c < count; c++) { + const float uv_offset[2] = { + amd->uv_offset[0] * (float)c, + amd->uv_offset[1] * (float)c, + }; + int l_index = chunk_nloops; + for (; l_index-- != 0; dmloopuv++) { + dmloopuv->uv[0] += uv_offset[0]; + dmloopuv->uv[1] += uv_offset[1]; + } + } + } + } + last_chunk_start = (count - 1) * chunk_nverts; last_chunk_nverts = chunk_nverts; diff --git a/source/blender/modifiers/intern/MOD_boolean.c b/source/blender/modifiers/intern/MOD_boolean.c index 5811017f745..0554fbb0317 100644 --- a/source/blender/modifiers/intern/MOD_boolean.c +++ b/source/blender/modifiers/intern/MOD_boolean.c @@ -239,7 +239,7 @@ static DerivedMesh *applyModifier_bmesh( int tottri; BMLoop *(*looptris)[3]; - looptris = MEM_mallocN(sizeof(*looptris) * looptris_tot, __func__); + looptris = MEM_malloc_arrayN(looptris_tot, sizeof(*looptris), __func__); BM_mesh_calc_tessellation_beauty(bm, looptris, &tottri); diff --git a/source/blender/modifiers/intern/MOD_build.c b/source/blender/modifiers/intern/MOD_build.c index 0a0ad11fe16..7a52ede8838 100644 --- a/source/blender/modifiers/intern/MOD_build.c +++ b/source/blender/modifiers/intern/MOD_build.c @@ -104,9 +104,9 @@ static DerivedMesh *applyModifier(ModifierData *md, const struct EvaluationConte MVert *mvert_src = dm->getVertArray(dm); - vertMap = MEM_mallocN(sizeof(*vertMap) * numVert_src, "build modifier vertMap"); - edgeMap = MEM_mallocN(sizeof(*edgeMap) * numEdge_src, "build modifier edgeMap"); - faceMap = MEM_mallocN(sizeof(*faceMap) * numPoly_src, "build modifier faceMap"); + vertMap = MEM_malloc_arrayN(numVert_src, sizeof(*vertMap), "build modifier vertMap"); + edgeMap = MEM_malloc_arrayN(numEdge_src, sizeof(*edgeMap), "build modifier edgeMap"); + faceMap = MEM_malloc_arrayN(numPoly_src, sizeof(*faceMap), "build modifier faceMap"); range_vn_i(vertMap, numVert_src, 0); range_vn_i(edgeMap, numEdge_src, 0); diff --git a/source/blender/modifiers/intern/MOD_collision.c b/source/blender/modifiers/intern/MOD_collision.c index b9a2310366a..d2ecbaeaafe 100644 --- a/source/blender/modifiers/intern/MOD_collision.c +++ b/source/blender/modifiers/intern/MOD_collision.c @@ -158,7 +158,7 @@ static void deformVerts(ModifierData *md, const struct EvaluationContext *UNUSED { const MLoop *mloop = dm->getLoopArray(dm); const MLoopTri *looptri = dm->getLoopTriArray(dm); - MVertTri *tri = MEM_mallocN(sizeof(*tri) * collmd->tri_num, __func__); + MVertTri *tri = MEM_malloc_arrayN(collmd->tri_num, sizeof(*tri), __func__); DM_verttri_from_looptri(tri, mloop, looptri, collmd->tri_num); collmd->tri = tri; } diff --git a/source/blender/modifiers/intern/MOD_correctivesmooth.c b/source/blender/modifiers/intern/MOD_correctivesmooth.c index 716b918d0f0..d95f0ae9286 100644 --- a/source/blender/modifiers/intern/MOD_correctivesmooth.c +++ b/source/blender/modifiers/intern/MOD_correctivesmooth.c @@ -156,7 +156,7 @@ static void dm_get_boundaries(DerivedMesh *dm, float *smooth_weights) mpoly_num = (unsigned int)dm->getNumPolys(dm); medge_num = (unsigned int)dm->getNumEdges(dm); - boundaries = MEM_callocN(medge_num * sizeof(*boundaries), __func__); + boundaries = MEM_calloc_arrayN(medge_num, sizeof(*boundaries), __func__); /* count the number of adjacent faces */ for (i = 0; i < mpoly_num; i++) { @@ -199,9 +199,9 @@ static void smooth_iter__simple( struct SmoothingData_Simple { float delta[3]; - } *smooth_data = MEM_callocN((size_t)numVerts * sizeof(*smooth_data), __func__); + } *smooth_data = MEM_calloc_arrayN(numVerts, sizeof(*smooth_data), __func__); - vertex_edge_count_div = MEM_callocN((size_t)numVerts * sizeof(float), __func__); + vertex_edge_count_div = MEM_calloc_arrayN(numVerts, sizeof(float), __func__); /* calculate as floats to avoid int->float conversion in #smooth_iter */ for (i = 0; i < numEdges; i++) { @@ -277,11 +277,11 @@ static void smooth_iter__length_weight( struct SmoothingData_Weighted { float delta[3]; float edge_length_sum; - } *smooth_data = MEM_callocN((size_t)numVerts * sizeof(*smooth_data), __func__); + } *smooth_data = MEM_calloc_arrayN(numVerts, sizeof(*smooth_data), __func__); /* calculate as floats to avoid int->float conversion in #smooth_iter */ - vertex_edge_count = MEM_callocN((size_t)numVerts * sizeof(float), __func__); + vertex_edge_count = MEM_calloc_arrayN(numVerts, sizeof(float), __func__); for (i = 0; i < numEdges; i++) { vertex_edge_count[edges[i].v1] += 1.0f; vertex_edge_count[edges[i].v2] += 1.0f; @@ -382,7 +382,7 @@ static void smooth_verts( if (dvert || (csmd->flag & MOD_CORRECTIVESMOOTH_PIN_BOUNDARY)) { - smooth_weights = MEM_mallocN(numVerts * sizeof(float), __func__); + smooth_weights = MEM_malloc_arrayN(numVerts, sizeof(float), __func__); if (dvert) { dm_get_weights( @@ -530,7 +530,7 @@ static void calc_deltas( float (*tangent_spaces)[3][3]; unsigned int i; - tangent_spaces = MEM_callocN((size_t)(numVerts) * sizeof(float[3][3]), __func__); + tangent_spaces = MEM_calloc_arrayN(numVerts, sizeof(float[3][3]), __func__); if (csmd->delta_cache_num != numVerts) { MEM_SAFE_FREE(csmd->delta_cache); @@ -539,7 +539,7 @@ static void calc_deltas( /* allocate deltas if they have not yet been allocated, otheriwse we will just write over them */ if (!csmd->delta_cache) { csmd->delta_cache_num = numVerts; - csmd->delta_cache = MEM_mallocN((size_t)numVerts * sizeof(float[3]), __func__); + csmd->delta_cache = MEM_malloc_arrayN(numVerts, sizeof(float[3]), __func__); } smooth_verts(csmd, dm, dvert, defgrp_index, smooth_vertex_coords, numVerts); @@ -575,7 +575,7 @@ static void correctivesmooth_modifier_do( const bool force_delta_cache_update = /* XXX, take care! if mesh data its self changes we need to forcefully recalculate deltas */ ((csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_ORCO) && - (((ID *)ob->data)->tag & LIB_TAG_ID_RECALC)); + (((ID *)ob->data)->recalc & ID_RECALC)); bool use_only_smooth = (csmd->flag & MOD_CORRECTIVESMOOTH_ONLY_SMOOTH) != 0; MDeformVert *dvert = NULL; @@ -680,7 +680,7 @@ static void correctivesmooth_modifier_do( float (*tangent_spaces)[3][3]; /* calloc, since values are accumulated */ - tangent_spaces = MEM_callocN((size_t)numVerts * sizeof(float[3][3]), __func__); + tangent_spaces = MEM_calloc_arrayN(numVerts, sizeof(float[3][3]), __func__); calc_tangent_spaces(dm, vertexCos, tangent_spaces); diff --git a/source/blender/modifiers/intern/MOD_decimate.c b/source/blender/modifiers/intern/MOD_decimate.c index 078a3085fc7..83dcd7b9b89 100644 --- a/source/blender/modifiers/intern/MOD_decimate.c +++ b/source/blender/modifiers/intern/MOD_decimate.c @@ -142,7 +142,7 @@ static DerivedMesh *applyModifier(ModifierData *md, const struct EvaluationConte const unsigned int vert_tot = dm->getNumVerts(dm); unsigned int i; - vweights = MEM_mallocN(vert_tot * sizeof(float), __func__); + vweights = MEM_malloc_arrayN(vert_tot, sizeof(float), __func__); if (dmd->flag & MOD_DECIM_FLAG_INVERT_VGROUP) { for (i = 0; i < vert_tot; i++) { diff --git a/source/blender/modifiers/intern/MOD_displace.c b/source/blender/modifiers/intern/MOD_displace.c index c9ccdc3b8c2..53a77b6fe38 100644 --- a/source/blender/modifiers/intern/MOD_displace.c +++ b/source/blender/modifiers/intern/MOD_displace.c @@ -187,7 +187,10 @@ typedef struct DisplaceUserdata { float (*vert_clnors)[3]; } DisplaceUserdata; -static void displaceModifier_do_task(void *userdata, const int iter) +static void displaceModifier_do_task( + void *__restrict userdata, + const int iter, + const ParallelRangeTLS *__restrict UNUSED(tls)) { DisplaceUserdata *data = (DisplaceUserdata *)userdata; DisplaceModifierData *dmd = data->dmd; @@ -305,7 +308,7 @@ static void displaceModifier_do( modifier_get_vgroup(ob, dm, dmd->defgrp_name, &dvert, &defgrp_index); if (dmd->texture) { - tex_co = MEM_callocN(sizeof(*tex_co) * numVerts, + tex_co = MEM_calloc_arrayN((size_t)numVerts, sizeof(*tex_co), "displaceModifier_do tex_co"); get_texture_coords((MappingInfoModifierData *)dmd, ob, dm, vertexCos, tex_co, numVerts); @@ -326,7 +329,7 @@ static void displaceModifier_do( } clnors = CustomData_get_layer(ldata, CD_NORMAL); - vert_clnors = MEM_mallocN(sizeof(*vert_clnors) * (size_t)numVerts, __func__); + vert_clnors = MEM_malloc_arrayN(numVerts, sizeof(*vert_clnors), __func__); BKE_mesh_normals_loop_to_vertex(numVerts, dm->getLoopArray(dm), dm->getNumLoops(dm), (const float (*)[3])clnors, vert_clnors); } @@ -356,7 +359,13 @@ static void displaceModifier_do( data.pool = BKE_image_pool_new(); BKE_texture_fetch_images_for_pool(dmd->texture, data.pool); } - BLI_task_parallel_range(0, numVerts, &data, displaceModifier_do_task, numVerts > 512); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = (numVerts > 512); + BLI_task_parallel_range(0, numVerts, + &data, + displaceModifier_do_task, + &settings); if (data.pool != NULL) { BKE_image_pool_free(data.pool); diff --git a/source/blender/modifiers/intern/MOD_explode.c b/source/blender/modifiers/intern/MOD_explode.c index 38785abbc19..8483da60576 100644 --- a/source/blender/modifiers/intern/MOD_explode.c +++ b/source/blender/modifiers/intern/MOD_explode.c @@ -119,9 +119,9 @@ static void createFacepa(ExplodeModifierData *emd, if (emd->facepa) MEM_freeN(emd->facepa); - facepa = emd->facepa = MEM_callocN(sizeof(int) * totface, "explode_facepa"); + facepa = emd->facepa = MEM_calloc_arrayN(totface, sizeof(int), "explode_facepa"); - vertpa = MEM_callocN(sizeof(int) * totvert, "explode_vertpa"); + vertpa = MEM_calloc_arrayN(totvert, sizeof(int), "explode_vertpa"); /* initialize all faces & verts to no particle */ for (i = 0; i < totface; i++) @@ -557,8 +557,8 @@ static DerivedMesh *cutEdges(ExplodeModifierData *emd, DerivedMesh *dm) int totvert = dm->getNumVerts(dm); int totface = dm->getNumTessFaces(dm); - int *facesplit = MEM_callocN(sizeof(int) * totface, "explode_facesplit"); - int *vertpa = MEM_callocN(sizeof(int) * totvert, "explode_vertpa2"); + int *facesplit = MEM_calloc_arrayN(totface, sizeof(int), "explode_facesplit"); + int *vertpa = MEM_calloc_arrayN(totvert, sizeof(int), "explode_vertpa2"); int *facepa = emd->facepa; int *fs, totesplit = 0, totfsplit = 0, curdupface = 0; int i, v1, v2, v3, v4, esplit, @@ -656,7 +656,7 @@ static DerivedMesh *cutEdges(ExplodeModifierData *emd, DerivedMesh *dm) * later interpreted as tri's, for this to work right I think we probably * have to stop using tessface - campbell */ - facepa = MEM_callocN(sizeof(int) * (totface + (totfsplit * 2)), "explode_facepa"); + facepa = MEM_calloc_arrayN((totface + (totfsplit * 2)), sizeof(int), "explode_facepa"); //memcpy(facepa, emd->facepa, totface*sizeof(int)); emd->facepa = facepa; diff --git a/source/blender/modifiers/intern/MOD_fluidsim_util.c b/source/blender/modifiers/intern/MOD_fluidsim_util.c index 3684e947fe0..c9f475ad228 100644 --- a/source/blender/modifiers/intern/MOD_fluidsim_util.c +++ b/source/blender/modifiers/intern/MOD_fluidsim_util.c @@ -239,7 +239,7 @@ static DerivedMesh *fluidsim_read_obj(const char *filename, const MPoly *mp_exam return NULL; } - normals = MEM_callocN(sizeof(short) * numverts * 3, "fluid_tmp_normals"); + normals = MEM_calloc_arrayN(numverts, 3 * sizeof(short), "fluid_tmp_normals"); if (!normals) { if (dm) dm->release(dm); @@ -384,7 +384,7 @@ static void fluidsim_read_vel_cache(FluidsimModifierData *fluidmd, DerivedMesh * if (fss->domainNovecgen > 0) return; - fss->meshVelocities = MEM_callocN(sizeof(FluidVertexVelocity) * dm->getNumVerts(dm), "Fluidsim_velocities"); + fss->meshVelocities = MEM_calloc_arrayN(dm->getNumVerts(dm), sizeof(FluidVertexVelocity), "Fluidsim_velocities"); fss->totvert = totvert; velarray = fss->meshVelocities; diff --git a/source/blender/modifiers/intern/MOD_laplaciandeform.c b/source/blender/modifiers/intern/MOD_laplaciandeform.c index d322b8631d2..72db3f1c132 100644 --- a/source/blender/modifiers/intern/MOD_laplaciandeform.c +++ b/source/blender/modifiers/intern/MOD_laplaciandeform.c @@ -108,12 +108,12 @@ static LaplacianSystem *initLaplacianSystem( sys->total_anchors = totalAnchors; sys->repeat = iterations; BLI_strncpy(sys->anchor_grp_name, defgrpName, sizeof(sys->anchor_grp_name)); - sys->co = MEM_mallocN(sizeof(float[3]) * totalVerts, "DeformCoordinates"); - sys->no = MEM_callocN(sizeof(float[3]) * totalVerts, "DeformNormals"); - sys->delta = MEM_callocN(sizeof(float[3]) * totalVerts, "DeformDeltas"); - sys->tris = MEM_mallocN(sizeof(int[3]) * totalTris, "DeformFaces"); - sys->index_anchors = MEM_mallocN(sizeof(int) * (totalAnchors), "DeformAnchors"); - sys->unit_verts = MEM_callocN(sizeof(int) * totalVerts, "DeformUnitVerts"); + sys->co = MEM_malloc_arrayN(totalVerts, sizeof(float[3]), "DeformCoordinates"); + sys->no = MEM_calloc_arrayN(totalVerts, sizeof(float[3]), "DeformNormals"); + sys->delta = MEM_calloc_arrayN(totalVerts, sizeof(float[3]), "DeformDeltas"); + sys->tris = MEM_malloc_arrayN(totalTris, sizeof(int[3]), "DeformFaces"); + sys->index_anchors = MEM_malloc_arrayN((totalAnchors), sizeof(int), "DeformAnchors"); + sys->unit_verts = MEM_calloc_arrayN(totalVerts, sizeof(int), "DeformUnitVerts"); return sys; } @@ -142,7 +142,7 @@ static void createFaceRingMap( { int i, j, totalr = 0; int *indices, *index_iter; - MeshElemMap *map = MEM_callocN(sizeof(MeshElemMap) * mvert_tot, "DeformRingMap"); + MeshElemMap *map = MEM_calloc_arrayN(mvert_tot, sizeof(MeshElemMap), "DeformRingMap"); const MLoopTri *mlt; for (i = 0, mlt = mlooptri; i < mtri_tot; i++, mlt++) { @@ -153,7 +153,7 @@ static void createFaceRingMap( totalr++; } } - indices = MEM_callocN(sizeof(int) * totalr, "DeformRingIndex"); + indices = MEM_calloc_arrayN(totalr, sizeof(int), "DeformRingIndex"); index_iter = indices; for (i = 0; i < mvert_tot; i++) { map[i].indices = index_iter; @@ -175,7 +175,7 @@ static void createVertRingMap( const int mvert_tot, const MEdge *medge, const int medge_tot, MeshElemMap **r_map, int **r_indices) { - MeshElemMap *map = MEM_callocN(sizeof(MeshElemMap) * mvert_tot, "DeformNeighborsMap"); + MeshElemMap *map = MEM_calloc_arrayN(mvert_tot, sizeof(MeshElemMap), "DeformNeighborsMap"); int i, vid[2], totalr = 0; int *indices, *index_iter; const MEdge *me; @@ -187,7 +187,7 @@ static void createVertRingMap( map[vid[1]].count++; totalr += 2; } - indices = MEM_callocN(sizeof(int) * totalr, "DeformNeighborsIndex"); + indices = MEM_calloc_arrayN(totalr, sizeof(int), "DeformNeighborsIndex"); index_iter = indices; for (i = 0; i < mvert_tot; i++) { map[i].indices = index_iter; @@ -521,7 +521,7 @@ static void initSystem(LaplacianDeformModifierData *lmd, Object *ob, DerivedMesh LaplacianSystem *sys; if (isValidVertexGroup(lmd, ob, dm)) { - int *index_anchors = MEM_mallocN(sizeof(int) * numVerts, __func__); /* over-alloc */ + int *index_anchors = MEM_malloc_arrayN(numVerts, sizeof(int), __func__); /* over-alloc */ const MLoopTri *mlooptri; const MLoop *mloop; @@ -547,7 +547,7 @@ static void initSystem(LaplacianDeformModifierData *lmd, Object *ob, DerivedMesh memcpy(sys->index_anchors, index_anchors, sizeof(int) * total_anchors); memcpy(sys->co, vertexCos, sizeof(float[3]) * numVerts); MEM_freeN(index_anchors); - lmd->vertexco = MEM_mallocN(sizeof(float[3]) * numVerts, "ModDeformCoordinates"); + lmd->vertexco = MEM_malloc_arrayN(numVerts, sizeof(float[3]), "ModDeformCoordinates"); memcpy(lmd->vertexco, vertexCos, sizeof(float[3]) * numVerts); lmd->total_verts = numVerts; @@ -631,7 +631,7 @@ static void LaplacianDeformModifier_do( sys = lmd->cache_system; if (sysdif) { if (sysdif == LAPDEFORM_SYSTEM_ONLY_CHANGE_ANCHORS || sysdif == LAPDEFORM_SYSTEM_ONLY_CHANGE_GROUP) { - filevertexCos = MEM_mallocN(sizeof(float[3]) * numVerts, "TempModDeformCoordinates"); + filevertexCos = MEM_malloc_arrayN(numVerts, sizeof(float[3]), "TempModDeformCoordinates"); memcpy(filevertexCos, lmd->vertexco, sizeof(float[3]) * numVerts); MEM_SAFE_FREE(lmd->vertexco); lmd->total_verts = 0; @@ -667,7 +667,7 @@ static void LaplacianDeformModifier_do( lmd->flag &= ~MOD_LAPLACIANDEFORM_BIND; } else if (lmd->total_verts > 0 && lmd->total_verts == numVerts) { - filevertexCos = MEM_mallocN(sizeof(float[3]) * numVerts, "TempDeformCoordinates"); + filevertexCos = MEM_malloc_arrayN(numVerts, sizeof(float[3]), "TempDeformCoordinates"); memcpy(filevertexCos, lmd->vertexco, sizeof(float[3]) * numVerts); MEM_SAFE_FREE(lmd->vertexco); lmd->total_verts = 0; diff --git a/source/blender/modifiers/intern/MOD_laplaciansmooth.c b/source/blender/modifiers/intern/MOD_laplaciansmooth.c index d7bc7b6c427..977b8b41cc3 100644 --- a/source/blender/modifiers/intern/MOD_laplaciansmooth.c +++ b/source/blender/modifiers/intern/MOD_laplaciansmooth.c @@ -132,14 +132,14 @@ static LaplacianSystem *init_laplacian_system(int a_numEdges, int a_numPolys, in sys->numLoops = a_numLoops; sys->numVerts = a_numVerts; - sys->eweights = MEM_callocN(sizeof(float) * sys->numEdges, __func__); - sys->fweights = MEM_callocN(sizeof(float[3]) * sys->numLoops, __func__); - sys->numNeEd = MEM_callocN(sizeof(short) * sys->numVerts, __func__); - sys->numNeFa = MEM_callocN(sizeof(short) * sys->numVerts, __func__); - sys->ring_areas = MEM_callocN(sizeof(float) * sys->numVerts, __func__); - sys->vlengths = MEM_callocN(sizeof(float) * sys->numVerts, __func__); - sys->vweights = MEM_callocN(sizeof(float) * sys->numVerts, __func__); - sys->zerola = MEM_callocN(sizeof(short) * sys->numVerts, __func__); + sys->eweights = MEM_calloc_arrayN(sys->numEdges, sizeof(float), __func__); + sys->fweights = MEM_calloc_arrayN(sys->numLoops, sizeof(float[3]), __func__); + sys->numNeEd = MEM_calloc_arrayN(sys->numVerts, sizeof(short), __func__); + sys->numNeFa = MEM_calloc_arrayN(sys->numVerts, sizeof(short), __func__); + sys->ring_areas = MEM_calloc_arrayN(sys->numVerts, sizeof(float), __func__); + sys->vlengths = MEM_calloc_arrayN(sys->numVerts, sizeof(float), __func__); + sys->vweights = MEM_calloc_arrayN(sys->numVerts, sizeof(float), __func__); + sys->zerola = MEM_calloc_arrayN(sys->numVerts, sizeof(short), __func__); return sys; } diff --git a/source/blender/modifiers/intern/MOD_mask.c b/source/blender/modifiers/intern/MOD_mask.c index d942b23b216..bcebbc40adb 100644 --- a/source/blender/modifiers/intern/MOD_mask.c +++ b/source/blender/modifiers/intern/MOD_mask.c @@ -162,7 +162,7 @@ static DerivedMesh *applyModifier(ModifierData *md, const struct EvaluationConte * - each cell is a boolean saying whether bone corresponding to the ith group is selected * - groups that don't match a bone are treated as not existing (along with the corresponding ungrouped verts) */ - bone_select_array = MEM_mallocN((size_t)defbase_tot * sizeof(char), "mask array"); + bone_select_array = MEM_malloc_arrayN((size_t)defbase_tot, sizeof(char), "mask array"); for (i = 0, def = ob->defbase.first; def; def = def->next, i++) { pchan = BKE_pose_channel_find_name(oba->pose, def->name); @@ -246,7 +246,7 @@ static DerivedMesh *applyModifier(ModifierData *md, const struct EvaluationConte mloop_src = dm->getLoopArray(dm); /* overalloc, assume all polys are seen */ - loop_mapping = MEM_mallocN(sizeof(int) * (size_t)maxPolys, "mask loopmap"); + loop_mapping = MEM_malloc_arrayN((size_t)maxPolys, sizeof(int), "mask loopmap"); /* loop over edges and faces, and do the same thing to * ensure that they only reference existing verts diff --git a/source/blender/modifiers/intern/MOD_meshcache.c b/source/blender/modifiers/intern/MOD_meshcache.c index c990951c578..5dfa1d874b2 100644 --- a/source/blender/modifiers/intern/MOD_meshcache.c +++ b/source/blender/modifiers/intern/MOD_meshcache.c @@ -94,7 +94,7 @@ static void meshcache_do( { const bool use_factor = mcmd->factor < 1.0f; float (*vertexCos_Store)[3] = (use_factor || (mcmd->deform_mode == MOD_MESHCACHE_DEFORM_INTEGRATE)) ? - MEM_mallocN(sizeof(*vertexCos_Store) * numVerts, __func__) : NULL; + MEM_malloc_arrayN(numVerts, sizeof(*vertexCos_Store), __func__) : NULL; float (*vertexCos)[3] = vertexCos_Store ? vertexCos_Store : vertexCos_Real; Scene *scene = mcmd->modifier.scene; @@ -197,8 +197,8 @@ static void meshcache_do( /* the moons align! */ int i; - float (*vertexCos_Source)[3] = MEM_mallocN(sizeof(*vertexCos_Source) * numVerts, __func__); - float (*vertexCos_New)[3] = MEM_mallocN(sizeof(*vertexCos_New) * numVerts, __func__); + float (*vertexCos_Source)[3] = MEM_malloc_arrayN(numVerts, sizeof(*vertexCos_Source), __func__); + float (*vertexCos_New)[3] = MEM_malloc_arrayN(numVerts, sizeof(*vertexCos_New), __func__); MVert *mv = me->mvert; for (i = 0; i < numVerts; i++, mv++) { diff --git a/source/blender/modifiers/intern/MOD_meshdeform.c b/source/blender/modifiers/intern/MOD_meshdeform.c index ab43204365d..da233a18d0a 100644 --- a/source/blender/modifiers/intern/MOD_meshdeform.c +++ b/source/blender/modifiers/intern/MOD_meshdeform.c @@ -215,7 +215,10 @@ typedef struct MeshdeformUserdata { float (*icagemat)[3]; } MeshdeformUserdata; -static void meshdeform_vert_task(void *userdata, const int iter) +static void meshdeform_vert_task( + void *__restrict userdata, + const int iter, + const ParallelRangeTLS *__restrict UNUSED(tls)) { MeshdeformUserdata *data = userdata; /*const*/ MeshDeformModifierData *mmd = data->mmd; @@ -358,7 +361,7 @@ static void meshdeformModifier_do( return; } - cagecos = MEM_mallocN(sizeof(*cagecos) * totcagevert, "meshdeformModifier vertCos"); + cagecos = MEM_malloc_arrayN(totcagevert, sizeof(*cagecos), "meshdeformModifier vertCos"); /* setup deformation data */ cagedm->getVertCos(cagedm, cagecos); @@ -367,7 +370,7 @@ static void meshdeformModifier_do( /* We allocate 1 element extra to make it possible to * load the values to SSE registers, which are float4. */ - dco = MEM_callocN(sizeof(*dco) * (totcagevert + 1), "MDefDco"); + dco = MEM_calloc_arrayN((totcagevert + 1), sizeof(*dco), "MDefDco"); zero_v3(dco[totcagevert]); for (a = 0; a < totcagevert; a++) { /* get cage vertex in world space with binding transform */ @@ -394,7 +397,13 @@ static void meshdeformModifier_do( data.icagemat = icagemat; /* Do deformation. */ - BLI_task_parallel_range(0, totvert, &data, meshdeform_vert_task, totvert > 1000); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.min_iter_per_thread = 16; + BLI_task_parallel_range(0, totvert, + &data, + meshdeform_vert_task, + &settings); /* release cage derivedmesh */ MEM_freeN(dco); @@ -458,8 +467,8 @@ void modifier_mdef_compact_influences(ModifierData *md) } /* allocate bind influences */ - mmd->bindinfluences = MEM_callocN(sizeof(MDefInfluence) * mmd->totinfluence, "MDefBindInfluence"); - mmd->bindoffsets = MEM_callocN(sizeof(int) * (totvert + 1), "MDefBindOffset"); + mmd->bindinfluences = MEM_calloc_arrayN(mmd->totinfluence, sizeof(MDefInfluence), "MDefBindInfluence"); + mmd->bindoffsets = MEM_calloc_arrayN((totvert + 1), sizeof(int), "MDefBindOffset"); /* write influences */ totinfluence = 0; diff --git a/source/blender/modifiers/intern/MOD_mirror.c b/source/blender/modifiers/intern/MOD_mirror.c index db06dc43b8e..1b725e335a4 100644 --- a/source/blender/modifiers/intern/MOD_mirror.c +++ b/source/blender/modifiers/intern/MOD_mirror.c @@ -167,7 +167,7 @@ static DerivedMesh *doMirrorOnAxis(MirrorModifierData *mmd, if (do_vtargetmap) { /* second half is filled with -1 */ - vtargetmap = MEM_mallocN(sizeof(int) * maxVerts * 2, "MOD_mirror tarmap"); + vtargetmap = MEM_malloc_arrayN(maxVerts, 2 * sizeof(int), "MOD_mirror tarmap"); vtmap_a = vtargetmap; vtmap_b = vtargetmap + maxVerts; diff --git a/source/blender/modifiers/intern/MOD_normal_edit.c b/source/blender/modifiers/intern/MOD_normal_edit.c index 1c7c640b971..61a5b9bb03e 100644 --- a/source/blender/modifiers/intern/MOD_normal_edit.c +++ b/source/blender/modifiers/intern/MOD_normal_edit.c @@ -117,7 +117,7 @@ static void mix_normals( int i; if (dvert) { - facs = MEM_mallocN(sizeof(*facs) * (size_t)num_loops, __func__); + facs = MEM_malloc_arrayN((size_t)num_loops, sizeof(*facs), __func__); BKE_defvert_extract_vgroup_to_loopweights( dvert, defgrp_index, num_verts, mloop, num_loops, facs, use_invert_vgroup); } @@ -195,8 +195,8 @@ static void normalEditModifier_do_radial( { int i; - float (*cos)[3] = MEM_mallocN(sizeof(*cos) * num_verts, __func__); - float (*nos)[3] = MEM_mallocN(sizeof(*nos) * num_loops, __func__); + float (*cos)[3] = MEM_malloc_arrayN((size_t)num_verts, sizeof(*cos), __func__); + float (*nos)[3] = MEM_malloc_arrayN((size_t)num_loops, sizeof(*nos), __func__); float size[3]; BLI_bitmap *done_verts = BLI_BITMAP_NEW((size_t)num_verts, __func__); @@ -294,8 +294,8 @@ static void normalEditModifier_do_directional( { const bool use_parallel_normals = (enmd->flag & MOD_NORMALEDIT_USE_DIRECTION_PARALLEL) != 0; - float (*cos)[3] = MEM_mallocN(sizeof(*cos) * num_verts, __func__); - float (*nos)[3] = MEM_mallocN(sizeof(*nos) * num_loops, __func__); + float (*cos)[3] = MEM_malloc_arrayN((size_t)num_verts, sizeof(*cos), __func__); + float (*nos)[3] = MEM_malloc_arrayN((size_t)num_loops, sizeof(*nos), __func__); float target_co[3]; int i; @@ -434,7 +434,7 @@ static DerivedMesh *normalEditModifier_do(NormalEditModifierData *enmd, Object * polynors = dm->getPolyDataArray(dm, CD_NORMAL); if (!polynors) { - polynors = MEM_mallocN(sizeof(*polynors) * num_polys, __func__); + polynors = MEM_malloc_arrayN((size_t)num_polys, sizeof(*polynors), __func__); BKE_mesh_calc_normals_poly(mvert, NULL, num_verts, mloop, mpoly, num_loops, num_polys, polynors, false); free_polynors = true; } diff --git a/source/blender/modifiers/intern/MOD_ocean.c b/source/blender/modifiers/intern/MOD_ocean.c index 189cfb8553e..b3a7ecaa138 100644 --- a/source/blender/modifiers/intern/MOD_ocean.c +++ b/source/blender/modifiers/intern/MOD_ocean.c @@ -261,7 +261,10 @@ typedef struct GenerateOceanGeometryData { float ix, iy; } GenerateOceanGeometryData; -static void generate_ocean_geometry_vertices(void *userdata, const int y) +static void generate_ocean_geometry_vertices( + void *__restrict userdata, + const int y, + const ParallelRangeTLS *__restrict UNUSED(tls)) { GenerateOceanGeometryData *gogd = userdata; int x; @@ -275,7 +278,10 @@ static void generate_ocean_geometry_vertices(void *userdata, const int y) } } -static void generate_ocean_geometry_polygons(void *userdata, const int y) +static void generate_ocean_geometry_polygons( + void *__restrict userdata, + const int y, + const ParallelRangeTLS *__restrict UNUSED(tls)) { GenerateOceanGeometryData *gogd = userdata; int x; @@ -305,7 +311,10 @@ static void generate_ocean_geometry_polygons(void *userdata, const int y) } } -static void generate_ocean_geometry_uvs(void *userdata, const int y) +static void generate_ocean_geometry_uvs( + void *__restrict userdata, + const int y, + const ParallelRangeTLS *__restrict UNUSED(tls)) { GenerateOceanGeometryData *gogd = userdata; int x; @@ -367,11 +376,15 @@ static DerivedMesh *generate_ocean_geometry(OceanModifierData *omd) gogd.origindex = CustomData_get_layer(&result->polyData, CD_ORIGINDEX); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = use_threading; + /* create vertices */ - BLI_task_parallel_range(0, gogd.res_y + 1, &gogd, generate_ocean_geometry_vertices, use_threading); + BLI_task_parallel_range(0, gogd.res_y + 1, &gogd, generate_ocean_geometry_vertices, &settings); /* create faces */ - BLI_task_parallel_range(0, gogd.res_y, &gogd, generate_ocean_geometry_polygons, use_threading); + BLI_task_parallel_range(0, gogd.res_y, &gogd, generate_ocean_geometry_polygons, &settings); CDDM_calc_edges(result); @@ -383,7 +396,7 @@ static DerivedMesh *generate_ocean_geometry(OceanModifierData *omd) gogd.ix = 1.0 / gogd.rx; gogd.iy = 1.0 / gogd.ry; - BLI_task_parallel_range(0, gogd.res_y, &gogd, generate_ocean_geometry_uvs, use_threading); + BLI_task_parallel_range(0, gogd.res_y, &gogd, generate_ocean_geometry_uvs, &settings); } } diff --git a/source/blender/modifiers/intern/MOD_particleinstance.c b/source/blender/modifiers/intern/MOD_particleinstance.c index de59635f335..09966da13a2 100644 --- a/source/blender/modifiers/intern/MOD_particleinstance.c +++ b/source/blender/modifiers/intern/MOD_particleinstance.c @@ -220,7 +220,7 @@ static DerivedMesh *applyModifier(ModifierData *md, const struct EvaluationConte if (pimd->flag & eParticleInstanceFlag_UseSize) { float *si; - si = size = MEM_callocN(totpart * sizeof(float), "particle size array"); + si = size = MEM_calloc_arrayN(totpart, sizeof(float), "particle size array"); if (pimd->flag & eParticleInstanceFlag_Parents) { for (p = 0, pa = psys->particles; p < psys->totpart; p++, pa++, si++) diff --git a/source/blender/modifiers/intern/MOD_screw.c b/source/blender/modifiers/intern/MOD_screw.c index 010bf8bf092..979dc339e4e 100644 --- a/source/blender/modifiers/intern/MOD_screw.c +++ b/source/blender/modifiers/intern/MOD_screw.c @@ -139,7 +139,7 @@ static DerivedMesh *dm_remove_doubles_on_axis( if (tot_doubles != 0) { uint tot = totvert * step_tot; - int *full_doubles_map = MEM_mallocN(sizeof(int) * tot, __func__); + int *full_doubles_map = MEM_malloc_arrayN(tot, sizeof(int), __func__); copy_vn_i(full_doubles_map, (int)tot, -1); uint tot_doubles_left = tot_doubles; @@ -448,10 +448,10 @@ static DerivedMesh *applyModifier(ModifierData *md, const struct EvaluationConte mpoly_orig = dm->getPolyArray(dm); mloop_orig = dm->getLoopArray(dm); - edge_poly_map = MEM_mallocN(sizeof(*edge_poly_map) * totedge, __func__); + edge_poly_map = MEM_malloc_arrayN(totedge, sizeof(*edge_poly_map), __func__); memset(edge_poly_map, 0xff, sizeof(*edge_poly_map) * totedge); - vert_loop_map = MEM_mallocN(sizeof(*vert_loop_map) * totvert, __func__); + vert_loop_map = MEM_malloc_arrayN(totvert, sizeof(*vert_loop_map), __func__); memset(vert_loop_map, 0xff, sizeof(*vert_loop_map) * totvert); for (i = 0, mp_orig = mpoly_orig; i < totpoly; i++, mp_orig++) { @@ -497,7 +497,7 @@ static DerivedMesh *applyModifier(ModifierData *md, const struct EvaluationConte * This makes the modifier faster with one less alloc. */ - vert_connect = MEM_mallocN(sizeof(ScrewVertConnect) * totvert, "ScrewVertConnect"); + vert_connect = MEM_malloc_arrayN(totvert, sizeof(ScrewVertConnect), "ScrewVertConnect"); //vert_connect = (ScrewVertConnect *) &medge_new[totvert]; /* skip the first slice of verts */ vc = vert_connect; diff --git a/source/blender/modifiers/intern/MOD_simpledeform.c b/source/blender/modifiers/intern/MOD_simpledeform.c index 146e882a6b6..6116e49d07d 100644 --- a/source/blender/modifiers/intern/MOD_simpledeform.c +++ b/source/blender/modifiers/intern/MOD_simpledeform.c @@ -32,7 +32,6 @@ * \ingroup modifiers */ - #include "DNA_meshdata_types.h" #include "DNA_object_types.h" @@ -48,9 +47,33 @@ #define BEND_EPS 0.000001f +/* Re-maps the indicies for X Y Z by shifting them up and wrapping, such that + * X = Y, Y = Z, Z = X (for X axis), and X = Z, Y = X, Z = Y (for Y axis). This + * exists because the deformations (excluding bend) are based on the Z axis. + * Having this helps avoid long, drawn out switches. */ +static const uint axis_map_table[3][3] = { + {1, 2, 0}, + {2, 0, 1}, + {0, 1, 2}, +}; + +BLI_INLINE void copy_v3_v3_map(float a[3], const float b[3], const uint map[3]) +{ + a[0] = b[map[0]]; + a[1] = b[map[1]]; + a[2] = b[map[2]]; +} + +BLI_INLINE void copy_v3_v3_unmap(float a[3], const float b[3], const uint map[3]) +{ + a[map[0]] = b[0]; + a[map[1]] = b[1]; + a[map[2]] = b[2]; +} + /* Clamps/Limits the given coordinate to: limits[0] <= co[axis] <= limits[1] * The amount of clamp is saved on dcut */ -static void axis_limit(int axis, const float limits[2], float co[3], float dcut[3]) +static void axis_limit(const int axis, const float limits[2], float co[3], float dcut[3]) { float val = co[axis]; if (limits[0] > val) val = limits[0]; @@ -60,7 +83,7 @@ static void axis_limit(int axis, const float limits[2], float co[3], float dcut[ co[axis] = val; } -static void simpleDeform_taper(const float factor, const float dcut[3], float r_co[3]) +static void simpleDeform_taper(const float factor, const int UNUSED(axis), const float dcut[3], float r_co[3]) { float x = r_co[0], y = r_co[1], z = r_co[2]; float scale = z * factor; @@ -69,14 +92,10 @@ static void simpleDeform_taper(const float factor, const float dcut[3], float r_ r_co[1] = y + y * scale; r_co[2] = z; - { - r_co[0] += dcut[0]; - r_co[1] += dcut[1]; - r_co[2] += dcut[2]; - } + add_v3_v3(r_co, dcut); } -static void simpleDeform_stretch(const float factor, const float dcut[3], float r_co[3]) +static void simpleDeform_stretch(const float factor, const int UNUSED(axis), const float dcut[3], float r_co[3]) { float x = r_co[0], y = r_co[1], z = r_co[2]; float scale; @@ -87,14 +106,10 @@ static void simpleDeform_stretch(const float factor, const float dcut[3], float r_co[1] = y * scale; r_co[2] = z * (1.0f + factor); - { - r_co[0] += dcut[0]; - r_co[1] += dcut[1]; - r_co[2] += dcut[2]; - } + add_v3_v3(r_co, dcut); } -static void simpleDeform_twist(const float factor, const float *dcut, float r_co[3]) +static void simpleDeform_twist(const float factor, const int UNUSED(axis), const float *dcut, float r_co[3]) { float x = r_co[0], y = r_co[1], z = r_co[2]; float theta, sint, cost; @@ -107,32 +122,58 @@ static void simpleDeform_twist(const float factor, const float *dcut, float r_co r_co[1] = x * sint + y * cost; r_co[2] = z; - { - r_co[0] += dcut[0]; - r_co[1] += dcut[1]; - r_co[2] += dcut[2]; - } + add_v3_v3(r_co, dcut); } -static void simpleDeform_bend(const float factor, const float dcut[3], float r_co[3]) +static void simpleDeform_bend(const float factor, const int axis, const float dcut[3], float r_co[3]) { float x = r_co[0], y = r_co[1], z = r_co[2]; float theta, sint, cost; BLI_assert(!(fabsf(factor) < BEND_EPS)); - theta = x * factor; + switch (axis) { + case 0: + ATTR_FALLTHROUGH; + case 1: + theta = z * factor; + break; + default: + theta = x * factor; + } sint = sinf(theta); cost = cosf(theta); - r_co[0] = -(y - 1.0f / factor) * sint; - r_co[1] = (y - 1.0f / factor) * cost + 1.0f / factor; - r_co[2] = z; - - { - r_co[0] += cost * dcut[0]; - r_co[1] += sint * dcut[0]; - r_co[2] += dcut[2]; + switch (axis) { + case 0: + r_co[0] = x; + r_co[1] = (y - 1.0f / factor) * cost + 1.0f / factor; + r_co[2] = -(y - 1.0f / factor) * sint; + { + r_co[0] += dcut[0]; + r_co[1] += sint * dcut[2]; + r_co[2] += cost * dcut[2]; + } + break; + case 1: + r_co[0] = (x - 1.0f / factor) * cost + 1.0f / factor; + r_co[1] = y; + r_co[2] = -(x - 1.0f / factor) * sint; + { + r_co[0] += sint * dcut[2]; + r_co[1] += dcut[1]; + r_co[2] += cost * dcut[2]; + } + break; + default: + r_co[0] = -(y - 1.0f / factor) * sint; + r_co[1] = (y - 1.0f / factor) * cost + 1.0f / factor; + r_co[2] = z; + { + r_co[0] += cost * dcut[0]; + r_co[1] += sint * dcut[0]; + r_co[2] += dcut[2]; + } } } @@ -142,16 +183,36 @@ static void simpleDeform_bend(const float factor, const float dcut[3], float r_c static void SimpleDeformModifier_do(SimpleDeformModifierData *smd, struct Object *ob, struct DerivedMesh *dm, float (*vertexCos)[3], int numVerts) { - static const float lock_axis[2] = {0.0f, 0.0f}; + const float base_limit[2] = {0.0f, 0.0f}; int i; - int limit_axis = 0; float smd_limit[2], smd_factor; SpaceTransform *transf = NULL, tmp_transf; - void (*simpleDeform_callback)(const float factor, const float dcut[3], float co[3]) = NULL; /* Mode callback */ + void (*simpleDeform_callback)(const float factor, const int axis, const float dcut[3], float co[3]) = NULL; /* Mode callback */ int vgroup; MDeformVert *dvert; + /* This is historically the lock axis, _not_ the deform axis as the name would imply */ + const int deform_axis = smd->deform_axis; + int lock_axis = smd->axis; + if (smd->mode == MOD_SIMPLEDEFORM_MODE_BEND) { /* Bend mode shouln't have any lock axis */ + lock_axis = 0; + } + else { + /* Don't lock axis if it is the chosen deform axis, as this flattens + * the geometry */ + if (deform_axis == 0) { + lock_axis &= ~MOD_SIMPLEDEFORM_LOCK_AXIS_X; + } + if (deform_axis == 1) { + lock_axis &= ~MOD_SIMPLEDEFORM_LOCK_AXIS_Y; + } + if (deform_axis == 2) { + lock_axis &= ~MOD_SIMPLEDEFORM_LOCK_AXIS_Z; + } + } + + /* Safe-check */ if (smd->origin == ob) smd->origin = NULL; /* No self references */ @@ -166,11 +227,21 @@ static void SimpleDeformModifier_do(SimpleDeformModifierData *smd, struct Object BLI_SPACE_TRANSFORM_SETUP(transf, ob, smd->origin); } - /* Setup vars, - * Bend limits on X.. all other modes limit on Z */ - limit_axis = (smd->mode == MOD_SIMPLEDEFORM_MODE_BEND) ? 0 : 2; - /* Update limits if needed */ + int limit_axis = deform_axis; + if (smd->mode == MOD_SIMPLEDEFORM_MODE_BEND) { + /* Bend is a special case. */ + switch (deform_axis) { + case 0: + ATTR_FALLTHROUGH; + case 1: + limit_axis = 2; + break; + default: + limit_axis = 0; + } + } + { float lower = FLT_MAX; float upper = -FLT_MAX; @@ -212,6 +283,7 @@ static void SimpleDeformModifier_do(SimpleDeformModifierData *smd, struct Object modifier_get_vgroup(ob, dm, smd->vgroup_name, &dvert, &vgroup); const bool invert_vgroup = (smd->flag & MOD_SIMPLEDEFORM_FLAG_INVERT_VGROUP) != 0; + const uint *axis_map = axis_map_table[(smd->mode != MOD_SIMPLEDEFORM_MODE_BEND) ? deform_axis : 2]; for (i = 0; i < numVerts; i++) { float weight = defvert_array_find_weight_safe(dvert, i, vgroup); @@ -229,14 +301,26 @@ static void SimpleDeformModifier_do(SimpleDeformModifierData *smd, struct Object copy_v3_v3(co, vertexCos[i]); - /* Apply axis limits */ - if (smd->mode != MOD_SIMPLEDEFORM_MODE_BEND) { /* Bend mode shoulnt have any lock axis */ - if (smd->axis & MOD_SIMPLEDEFORM_LOCK_AXIS_X) axis_limit(0, lock_axis, co, dcut); - if (smd->axis & MOD_SIMPLEDEFORM_LOCK_AXIS_Y) axis_limit(1, lock_axis, co, dcut); + /* Apply axis limits, and axis mappings */ + if (lock_axis & MOD_SIMPLEDEFORM_LOCK_AXIS_X) { + axis_limit(0, base_limit, co, dcut); + } + if (lock_axis & MOD_SIMPLEDEFORM_LOCK_AXIS_Y) { + axis_limit(1, base_limit, co, dcut); + } + if (lock_axis & MOD_SIMPLEDEFORM_LOCK_AXIS_Z) { + axis_limit(2, base_limit, co, dcut); } axis_limit(limit_axis, smd_limit, co, dcut); - simpleDeform_callback(smd_factor, dcut, co); /* apply deform */ + /* apply the deform to a mapped copy of the vertex, and then re-map it back. */ + float co_remap[3]; + float dcut_remap[3]; + copy_v3_v3_map(co_remap, co, axis_map); + copy_v3_v3_map(dcut_remap, dcut, axis_map); + simpleDeform_callback(smd_factor, deform_axis, dcut_remap, co_remap); /* apply deform */ + copy_v3_v3_unmap(co, co_remap, axis_map); + interp_v3_v3v3(vertexCos[i], vertexCos[i], co, weight); /* Use vertex weight has coef of linear interpolation */ if (transf) { @@ -254,6 +338,7 @@ static void initData(ModifierData *md) smd->mode = MOD_SIMPLEDEFORM_MODE_TWIST; smd->axis = 0; + smd->deform_axis = 0; smd->origin = NULL; smd->factor = DEG2RADF(45.0f); diff --git a/source/blender/modifiers/intern/MOD_skin.c b/source/blender/modifiers/intern/MOD_skin.c index 9d1c6913c1c..97afe6d5e87 100644 --- a/source/blender/modifiers/intern/MOD_skin.c +++ b/source/blender/modifiers/intern/MOD_skin.c @@ -419,7 +419,7 @@ static Frame **collect_hull_frames(int v, SkinNode *frames, int nbr, i; (*tothullframe) = emap[v].count; - hull_frames = MEM_callocN(sizeof(Frame *) * (*tothullframe), + hull_frames = MEM_calloc_arrayN((*tothullframe), sizeof(Frame *), "hull_from_frames.hull_frames"); i = 0; for (nbr = 0; nbr < emap[v].count; nbr++) { @@ -600,7 +600,7 @@ static SkinNode *build_frames(const MVert *mvert, int totvert, SkinNode *skin_nodes; int v; - skin_nodes = MEM_callocN(sizeof(SkinNode) * totvert, "build_frames.skin_nodes"); + skin_nodes = MEM_calloc_arrayN(totvert, sizeof(SkinNode), "build_frames.skin_nodes"); for (v = 0; v < totvert; v++) { if (emap[v].count <= 1) @@ -722,7 +722,7 @@ static EMat *build_edge_mats(const MVertSkin *vs, stack = BLI_stack_new(sizeof(stack_elem), "build_edge_mats.stack"); visited_e = BLI_BITMAP_NEW(totedge, "build_edge_mats.visited_e"); - emat = MEM_callocN(sizeof(EMat) * totedge, "build_edge_mats.emat"); + emat = MEM_calloc_arrayN(totedge, sizeof(EMat), "build_edge_mats.emat"); /* Edge matrices are built from the root nodes, add all roots with * children to the stack */ @@ -836,14 +836,14 @@ static DerivedMesh *subdivide_base(DerivedMesh *orig) totorigedge = orig->getNumEdges(orig); /* Get degree of all vertices */ - degree = MEM_callocN(sizeof(int) * totorigvert, "degree"); + degree = MEM_calloc_arrayN(totorigvert, sizeof(int), "degree"); for (i = 0; i < totorigedge; i++) { degree[origedge[i].v1]++; degree[origedge[i].v2]++; } /* Per edge, store how many subdivisions are needed */ - edge_subd = MEM_callocN(sizeof(int) * totorigedge, "edge_subd"); + edge_subd = MEM_calloc_arrayN(totorigedge, sizeof(int), "edge_subd"); for (i = 0, totsubd = 0; i < totorigedge; i++) { edge_subd[i] += calc_edge_subdivisions(origvert, orignode, &origedge[i], degree); @@ -882,7 +882,7 @@ static DerivedMesh *subdivide_base(DerivedMesh *orig) if (origdvert) { const MDeformVert *dv1 = &origdvert[e->v1]; const MDeformVert *dv2 = &origdvert[e->v2]; - vgroups = MEM_callocN(sizeof(*vgroups) * dv1->totweight, "vgroup"); + vgroups = MEM_calloc_arrayN(dv1->totweight, sizeof(*vgroups), "vgroup"); /* Only want vertex groups used by both vertices */ for (j = 0; j < dv1->totweight; j++) { diff --git a/source/blender/modifiers/intern/MOD_smooth.c b/source/blender/modifiers/intern/MOD_smooth.c index be55030e18a..91c724cd1c9 100644 --- a/source/blender/modifiers/intern/MOD_smooth.c +++ b/source/blender/modifiers/intern/MOD_smooth.c @@ -102,10 +102,10 @@ static void smoothModifier_do( unsigned char *uctmp; float *ftmp, fac, facm; - ftmp = (float *)MEM_callocN(3 * sizeof(float) * numVerts, + ftmp = (float *)MEM_calloc_arrayN(numVerts, 3 * sizeof(float), "smoothmodifier_f"); if (!ftmp) return; - uctmp = (unsigned char *)MEM_callocN(sizeof(unsigned char) * numVerts, + uctmp = (unsigned char *)MEM_calloc_arrayN(numVerts, sizeof(unsigned char), "smoothmodifier_uc"); if (!uctmp) { if (ftmp) MEM_freeN(ftmp); diff --git a/source/blender/modifiers/intern/MOD_solidify.c b/source/blender/modifiers/intern/MOD_solidify.c index 14b29855728..5635d37f100 100644 --- a/source/blender/modifiers/intern/MOD_solidify.c +++ b/source/blender/modifiers/intern/MOD_solidify.c @@ -101,7 +101,7 @@ static void dm_calc_normal(DerivedMesh *dm, float (*face_nors)[3], float (*r_ver mp = mpoly; { - EdgeFaceRef *edge_ref_array = MEM_callocN(sizeof(EdgeFaceRef) * (size_t)numEdges, "Edge Connectivity"); + EdgeFaceRef *edge_ref_array = MEM_calloc_arrayN((size_t)numEdges, sizeof(EdgeFaceRef), "Edge Connectivity"); EdgeFaceRef *edge_ref; float edge_normal[3]; @@ -235,7 +235,7 @@ static DerivedMesh *applyModifier( unsigned int *new_edge_arr = NULL; STACK_DECLARE(new_edge_arr); - unsigned int *old_vert_arr = MEM_callocN(sizeof(*old_vert_arr) * (size_t)numVerts, "old_vert_arr in solidify"); + unsigned int *old_vert_arr = MEM_calloc_arrayN(numVerts, sizeof(*old_vert_arr), "old_vert_arr in solidify"); unsigned int *edge_users = NULL; char *edge_order = NULL; @@ -270,7 +270,7 @@ static DerivedMesh *applyModifier( if (need_face_normals) { /* calculate only face normals */ - face_nors = MEM_mallocN(sizeof(*face_nors) * (size_t)numFaces, __func__); + face_nors = MEM_malloc_arrayN(numFaces, sizeof(*face_nors), __func__); BKE_mesh_calc_normals_poly( orig_mvert, NULL, (int)numVerts, orig_mloop, orig_mpoly, @@ -289,11 +289,11 @@ static DerivedMesh *applyModifier( #define INVALID_UNUSED ((unsigned int)-1) #define INVALID_PAIR ((unsigned int)-2) - new_vert_arr = MEM_mallocN(sizeof(*new_vert_arr) * (size_t)(numVerts * 2), __func__); - new_edge_arr = MEM_mallocN(sizeof(*new_edge_arr) * (size_t)((numEdges * 2) + numVerts), __func__); + new_vert_arr = MEM_malloc_arrayN(numVerts, 2 * sizeof(*new_vert_arr), __func__); + new_edge_arr = MEM_malloc_arrayN(((numEdges * 2) + numVerts), sizeof(*new_edge_arr), __func__); - edge_users = MEM_mallocN(sizeof(*edge_users) * (size_t)numEdges, "solid_mod edges"); - edge_order = MEM_mallocN(sizeof(*edge_order) * (size_t)numEdges, "solid_mod eorder"); + edge_users = MEM_malloc_arrayN(numEdges, sizeof(*edge_users), "solid_mod edges"); + edge_order = MEM_malloc_arrayN(numEdges, sizeof(*edge_order), "solid_mod eorder"); /* save doing 2 loops here... */ @@ -366,7 +366,7 @@ static DerivedMesh *applyModifier( } if (smd->flag & MOD_SOLIDIFY_NORMAL_CALC) { - vert_nors = MEM_callocN(sizeof(float) * (size_t)numVerts * 3, "mod_solid_vno_hq"); + vert_nors = MEM_calloc_arrayN(numVerts, 3 * sizeof(float), "mod_solid_vno_hq"); dm_calc_normal(dm, face_nors, vert_nors); } @@ -517,7 +517,7 @@ static DerivedMesh *applyModifier( if (do_clamp) { unsigned int i; - vert_lens = MEM_mallocN(sizeof(float) * numVerts, "vert_lens"); + vert_lens = MEM_malloc_arrayN(numVerts, sizeof(float), "vert_lens"); copy_vn_fl(vert_lens, (int)numVerts, FLT_MAX); for (i = 0; i < numEdges; i++) { const float ed_len_sq = len_squared_v3v3(mvert[medge[i].v1].co, mvert[medge[i].v2].co); @@ -596,13 +596,13 @@ static DerivedMesh *applyModifier( const bool check_non_manifold = (smd->flag & MOD_SOLIDIFY_NORMAL_CALC) != 0; #endif /* same as EM_solidify() in editmesh_lib.c */ - float *vert_angles = MEM_callocN(sizeof(float) * numVerts * 2, "mod_solid_pair"); /* 2 in 1 */ + float *vert_angles = MEM_calloc_arrayN(numVerts, 2 * sizeof(float), "mod_solid_pair"); /* 2 in 1 */ float *vert_accum = vert_angles + numVerts; unsigned int vidx; unsigned int i; if (vert_nors == NULL) { - vert_nors = MEM_mallocN(sizeof(float) * numVerts * 3, "mod_solid_vno"); + vert_nors = MEM_malloc_arrayN(numVerts, 3 * sizeof(float), "mod_solid_vno"); for (i = 0, mv = mvert; i < numVerts; i++, mv++) { normal_short_to_float_v3(vert_nors[i], mv->no); } @@ -682,7 +682,7 @@ static DerivedMesh *applyModifier( } if (do_clamp) { - float *vert_lens_sq = MEM_mallocN(sizeof(float) * numVerts, "vert_lens"); + float *vert_lens_sq = MEM_malloc_arrayN(numVerts, sizeof(float), "vert_lens"); const float offset = fabsf(smd->offset) * smd->offset_clamp; const float offset_sq = offset * offset; copy_vn_fl(vert_lens_sq, (int)numVerts, FLT_MAX); @@ -765,7 +765,7 @@ static DerivedMesh *applyModifier( #ifdef SOLIDIFY_SIDE_NORMALS const bool do_side_normals = !(result->dirty & DM_DIRTY_NORMALS); /* annoying to allocate these since we only need the edge verts, */ - float (*edge_vert_nos)[3] = do_side_normals ? MEM_callocN(sizeof(float) * numVerts * 3, __func__) : NULL; + float (*edge_vert_nos)[3] = do_side_normals ? MEM_calloc_arrayN(numVerts, 3 * sizeof(float), __func__) : NULL; float nor[3]; #endif const unsigned char crease_rim = smd->crease_rim * 255.0f; diff --git a/source/blender/modifiers/intern/MOD_surface.c b/source/blender/modifiers/intern/MOD_surface.c index c408b4fbd63..bef35ccf1fe 100644 --- a/source/blender/modifiers/intern/MOD_surface.c +++ b/source/blender/modifiers/intern/MOD_surface.c @@ -130,8 +130,8 @@ static void deformVerts(ModifierData *md, const struct EvaluationContext *UNUSED surmd->v = NULL; } - surmd->x = MEM_callocN(numverts * sizeof(MVert), "MVert"); - surmd->v = MEM_callocN(numverts * sizeof(MVert), "MVert"); + surmd->x = MEM_calloc_arrayN(numverts, sizeof(MVert), "MVert"); + surmd->v = MEM_calloc_arrayN(numverts, sizeof(MVert), "MVert"); surmd->numverts = numverts; diff --git a/source/blender/modifiers/intern/MOD_surfacedeform.c b/source/blender/modifiers/intern/MOD_surfacedeform.c index b623293ed5c..046a0ab27bf 100644 --- a/source/blender/modifiers/intern/MOD_surfacedeform.c +++ b/source/blender/modifiers/intern/MOD_surfacedeform.c @@ -314,11 +314,13 @@ BLI_INLINE int isPolyValid(const float coords[][2], const unsigned int nr) copy_v2_v2(prev_co, coords[nr - 1]); sub_v2_v2v2(prev_vec, prev_co, coords[nr - 2]); + normalize_v2(prev_vec); for (int i = 0; i < nr; i++) { sub_v2_v2v2(curr_vec, coords[i], prev_co); - if (len_squared_v2(curr_vec) < FLT_EPSILON) { + const float curr_len = normalize_v2(curr_vec); + if (curr_len < FLT_EPSILON) { return MOD_SDEF_BIND_RESULT_OVERLAP_ERR; } @@ -386,7 +388,7 @@ BLI_INLINE SDefBindWeightData *computeBindWeights(SDefBindCalcData * const data, bwdata->numpoly = data->vert_edges[nearest].num / 2; - bpoly = MEM_callocN(sizeof(*bpoly) * bwdata->numpoly, "SDefBindPoly"); + bpoly = MEM_calloc_arrayN(bwdata->numpoly, sizeof(*bpoly), "SDefBindPoly"); if (bpoly == NULL) { freeBindData(bwdata); data->success = MOD_SDEF_BIND_RESULT_MEM_ERR; @@ -429,14 +431,14 @@ BLI_INLINE SDefBindWeightData *computeBindWeights(SDefBindCalcData * const data, bpoly->numverts = poly->totloop; bpoly->loopstart = poly->loopstart; - bpoly->coords = MEM_mallocN(sizeof(*bpoly->coords) * poly->totloop, "SDefBindPolyCoords"); + bpoly->coords = MEM_malloc_arrayN(poly->totloop, sizeof(*bpoly->coords), "SDefBindPolyCoords"); if (bpoly->coords == NULL) { freeBindData(bwdata); data->success = MOD_SDEF_BIND_RESULT_MEM_ERR; return NULL; } - bpoly->coords_v2 = MEM_mallocN(sizeof(*bpoly->coords_v2) * poly->totloop, "SDefBindPolyCoords_v2"); + bpoly->coords_v2 = MEM_malloc_arrayN(poly->totloop, sizeof(*bpoly->coords_v2), "SDefBindPolyCoords_v2"); if (bpoly->coords_v2 == NULL) { freeBindData(bwdata); data->success = MOD_SDEF_BIND_RESULT_MEM_ERR; @@ -734,7 +736,10 @@ BLI_INLINE float computeNormalDisplacement(const float point_co[3], const float return normal_dist; } -static void bindVert(void *userdata, void *UNUSED(userdata_chunk), const int index, const int UNUSED(threadid)) +static void bindVert( + void *__restrict userdata, + const int index, + const ParallelRangeTLS *__restrict UNUSED(tls)) { SDefBindCalcData * const data = (SDefBindCalcData *)userdata; float point_co[3]; @@ -760,7 +765,7 @@ static void bindVert(void *userdata, void *UNUSED(userdata_chunk), const int ind return; } - sdvert->binds = MEM_callocN(sizeof(*sdvert->binds) * bwdata->numbinds, "SDefVertBindData"); + sdvert->binds = MEM_calloc_arrayN(bwdata->numbinds, sizeof(*sdvert->binds), "SDefVertBindData"); if (sdvert->binds == NULL) { data->success = MOD_SDEF_BIND_RESULT_MEM_ERR; sdvert->numbinds = 0; @@ -782,13 +787,13 @@ static void bindVert(void *userdata, void *UNUSED(userdata_chunk), const int ind sdbind->numverts = bpoly->numverts; sdbind->mode = MOD_SDEF_MODE_NGON; - sdbind->vert_weights = MEM_mallocN(sizeof(*sdbind->vert_weights) * bpoly->numverts, "SDefNgonVertWeights"); + sdbind->vert_weights = MEM_malloc_arrayN(bpoly->numverts, sizeof(*sdbind->vert_weights), "SDefNgonVertWeights"); if (sdbind->vert_weights == NULL) { data->success = MOD_SDEF_BIND_RESULT_MEM_ERR; return; } - sdbind->vert_inds = MEM_mallocN(sizeof(*sdbind->vert_inds) * bpoly->numverts, "SDefNgonVertInds"); + sdbind->vert_inds = MEM_malloc_arrayN(bpoly->numverts, sizeof(*sdbind->vert_inds), "SDefNgonVertInds"); if (sdbind->vert_inds == NULL) { data->success = MOD_SDEF_BIND_RESULT_MEM_ERR; return; @@ -818,13 +823,13 @@ static void bindVert(void *userdata, void *UNUSED(userdata_chunk), const int ind sdbind->numverts = bpoly->numverts; sdbind->mode = MOD_SDEF_MODE_CENTROID; - sdbind->vert_weights = MEM_mallocN(sizeof(*sdbind->vert_weights) * 3, "SDefCentVertWeights"); + sdbind->vert_weights = MEM_malloc_arrayN(3, sizeof(*sdbind->vert_weights), "SDefCentVertWeights"); if (sdbind->vert_weights == NULL) { data->success = MOD_SDEF_BIND_RESULT_MEM_ERR; return; } - sdbind->vert_inds = MEM_mallocN(sizeof(*sdbind->vert_inds) * bpoly->numverts, "SDefCentVertInds"); + sdbind->vert_inds = MEM_malloc_arrayN(bpoly->numverts, sizeof(*sdbind->vert_inds), "SDefCentVertInds"); if (sdbind->vert_inds == NULL) { data->success = MOD_SDEF_BIND_RESULT_MEM_ERR; return; @@ -861,13 +866,13 @@ static void bindVert(void *userdata, void *UNUSED(userdata_chunk), const int ind sdbind->numverts = bpoly->numverts; sdbind->mode = MOD_SDEF_MODE_LOOPTRI; - sdbind->vert_weights = MEM_mallocN(sizeof(*sdbind->vert_weights) * 3, "SDefTriVertWeights"); + sdbind->vert_weights = MEM_malloc_arrayN(3, sizeof(*sdbind->vert_weights), "SDefTriVertWeights"); if (sdbind->vert_weights == NULL) { data->success = MOD_SDEF_BIND_RESULT_MEM_ERR; return; } - sdbind->vert_inds = MEM_mallocN(sizeof(*sdbind->vert_inds) * bpoly->numverts, "SDefTriVertInds"); + sdbind->vert_inds = MEM_malloc_arrayN(bpoly->numverts, sizeof(*sdbind->vert_inds), "SDefTriVertInds"); if (sdbind->vert_inds == NULL) { data->success = MOD_SDEF_BIND_RESULT_MEM_ERR; return; @@ -918,20 +923,20 @@ static bool surfacedeformBind(SurfaceDeformModifierData *smd, float (*vertexCos) SDefAdjacency *adj_array; SDefEdgePolys *edge_polys; - vert_edges = MEM_callocN(sizeof(*vert_edges) * tnumverts, "SDefVertEdgeMap"); + vert_edges = MEM_calloc_arrayN(tnumverts, sizeof(*vert_edges), "SDefVertEdgeMap"); if (vert_edges == NULL) { modifier_setError((ModifierData *)smd, "Out of memory"); return false; } - adj_array = MEM_mallocN(sizeof(*adj_array) * tnumedges * 2, "SDefVertEdge"); + adj_array = MEM_malloc_arrayN(tnumedges, 2 * sizeof(*adj_array), "SDefVertEdge"); if (adj_array == NULL) { modifier_setError((ModifierData *)smd, "Out of memory"); MEM_freeN(vert_edges); return false; } - edge_polys = MEM_callocN(sizeof(*edge_polys) * tnumedges, "SDefEdgeFaceMap"); + edge_polys = MEM_calloc_arrayN(tnumedges, sizeof(*edge_polys), "SDefEdgeFaceMap"); if (edge_polys == NULL) { modifier_setError((ModifierData *)smd, "Out of memory"); MEM_freeN(vert_edges); @@ -939,7 +944,7 @@ static bool surfacedeformBind(SurfaceDeformModifierData *smd, float (*vertexCos) return false; } - smd->verts = MEM_mallocN(sizeof(*smd->verts) * numverts, "SDefBindVerts"); + smd->verts = MEM_malloc_arrayN(numverts, sizeof(*smd->verts), "SDefBindVerts"); if (smd->verts == NULL) { modifier_setError((ModifierData *)smd, "Out of memory"); freeAdjacencyMap(vert_edges, adj_array, edge_polys); @@ -976,7 +981,7 @@ static bool surfacedeformBind(SurfaceDeformModifierData *smd, float (*vertexCos) .medge = medge, .mloop = mloop, .looptri = tdm->getLoopTriArray(tdm), - .targetCos = MEM_mallocN(sizeof(float[3]) * tnumverts, "SDefTargetBindVertArray"), + .targetCos = MEM_malloc_arrayN(tnumverts, sizeof(float[3]), "SDefTargetBindVertArray"), .bind_verts = smd->verts, .vertexCos = vertexCos, .falloff = smd->falloff, @@ -994,8 +999,13 @@ static bool surfacedeformBind(SurfaceDeformModifierData *smd, float (*vertexCos) mul_v3_m4v3(data.targetCos[i], smd->mat, mvert[i].co); } - BLI_task_parallel_range_ex(0, numverts, &data, NULL, 0, bindVert, - numverts > 10000, false); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = (numverts > 10000); + BLI_task_parallel_range(0, numverts, + &data, + bindVert, + &settings); MEM_freeN(data.targetCos); @@ -1030,7 +1040,10 @@ static bool surfacedeformBind(SurfaceDeformModifierData *smd, float (*vertexCos) return data.success == 1; } -static void deformVert(void *userdata, void *UNUSED(userdata_chunk), const int index, const int UNUSED(threadid)) +static void deformVert( + void *__restrict userdata, + const int index, + const ParallelRangeTLS *__restrict UNUSED(tls)) { const SDefDeformData * const data = (SDefDeformData *)userdata; const SDefBind *sdbind = data->bind_verts[index].binds; @@ -1041,7 +1054,7 @@ static void deformVert(void *userdata, void *UNUSED(userdata_chunk), const int i for (int j = 0; j < data->bind_verts[index].numbinds; j++, sdbind++) { /* Mode-generic operations (allocate poly coordinates) */ - float (*coords)[3] = MEM_mallocN(sizeof(*coords) * sdbind->numverts, "SDefDoPolyCoords"); + float (*coords)[3] = MEM_malloc_arrayN(sdbind->numverts, sizeof(*coords), "SDefDoPolyCoords"); for (int k = 0; k < sdbind->numverts; k++) { copy_v3_v3(coords[k], data->targetCos[sdbind->vert_inds[k]]); @@ -1139,7 +1152,7 @@ static void surfacedeformModifier_do(ModifierData *md, float (*vertexCos)[3], un /* Actual vertex location update starts here */ SDefDeformData data = { .bind_verts = smd->verts, - .targetCos = MEM_mallocN(sizeof(float[3]) * tnumverts, "SDefTargetVertArray"), + .targetCos = MEM_malloc_arrayN(tnumverts, sizeof(float[3]), "SDefTargetVertArray"), .vertexCos = vertexCos, }; @@ -1151,8 +1164,13 @@ static void surfacedeformModifier_do(ModifierData *md, float (*vertexCos)[3], un mul_v3_m4v3(data.targetCos[i], smd->mat, mvert[i].co); } - BLI_task_parallel_range_ex(0, numverts, &data, NULL, 0, deformVert, - numverts > 10000, false); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = (numverts > 10000); + BLI_task_parallel_range(0, numverts, + &data, + deformVert, + &settings); if (tdm_vert_alloc) { MEM_freeN((void *)mvert); diff --git a/source/blender/modifiers/intern/MOD_util.c b/source/blender/modifiers/intern/MOD_util.c index ded1f0b77e6..5b19bcf4817 100644 --- a/source/blender/modifiers/intern/MOD_util.c +++ b/source/blender/modifiers/intern/MOD_util.c @@ -87,7 +87,7 @@ void get_texture_coords(MappingInfoModifierData *dmd, Object *ob, MPoly *mpoly = dm->getPolyArray(dm); MPoly *mp; MLoop *mloop = dm->getLoopArray(dm); - char *done = MEM_callocN(sizeof(*done) * numVerts, + char *done = MEM_calloc_arrayN(numVerts, sizeof(*done), "get_texture_coords done"); int numPolys = dm->getNumPolys(dm); char uvname[MAX_CUSTOMDATA_LAYER_NAME]; diff --git a/source/blender/modifiers/intern/MOD_uvproject.c b/source/blender/modifiers/intern/MOD_uvproject.c index c9a842621b6..498dd2486f4 100644 --- a/source/blender/modifiers/intern/MOD_uvproject.c +++ b/source/blender/modifiers/intern/MOD_uvproject.c @@ -226,7 +226,7 @@ static DerivedMesh *uvprojectModifier_do(UVProjectModifierData *umd, numVerts = dm->getNumVerts(dm); - coords = MEM_mallocN(sizeof(*coords) * numVerts, + coords = MEM_malloc_arrayN(numVerts, sizeof(*coords), "uvprojectModifier_do coords"); dm->getVertCos(dm, coords); diff --git a/source/blender/modifiers/intern/MOD_uvwarp.c b/source/blender/modifiers/intern/MOD_uvwarp.c index 3773eed26dc..32974d68d9d 100644 --- a/source/blender/modifiers/intern/MOD_uvwarp.c +++ b/source/blender/modifiers/intern/MOD_uvwarp.c @@ -110,7 +110,10 @@ typedef struct UVWarpData { int axis_v; } UVWarpData; -static void uv_warp_compute(void *userdata, const int i) +static void uv_warp_compute( + void *__restrict userdata, + const int i, + const ParallelRangeTLS *__restrict UNUSED(tls)) { const UVWarpData *data = userdata; @@ -208,7 +211,13 @@ static DerivedMesh *applyModifier(ModifierData *md, const struct EvaluationConte UVWarpData data = {.mpoly = mpoly, .mloop = mloop, .mloopuv = mloopuv, .dvert = dvert, .defgrp_index = defgrp_index, .warp_mat = warp_mat, .axis_u = axis_u, .axis_v = axis_v}; - BLI_task_parallel_range(0, numPolys, &data, uv_warp_compute, numPolys > 1000); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = (numPolys > 1000); + BLI_task_parallel_range(0, numPolys, + &data, + uv_warp_compute, + &settings); dm->dirty |= DM_DIRTY_TESS_CDLAYERS; diff --git a/source/blender/modifiers/intern/MOD_warp.c b/source/blender/modifiers/intern/MOD_warp.c index 566ee5b2d24..be0be2671b9 100644 --- a/source/blender/modifiers/intern/MOD_warp.c +++ b/source/blender/modifiers/intern/MOD_warp.c @@ -214,7 +214,7 @@ static void warpModifier_do(WarpModifierData *wmd, Object *ob, weight = strength; if (wmd->texture) { - tex_co = MEM_mallocN(sizeof(*tex_co) * numVerts, "warpModifier_do tex_co"); + tex_co = MEM_malloc_arrayN(numVerts, sizeof(*tex_co), "warpModifier_do tex_co"); get_texture_coords((MappingInfoModifierData *)wmd, ob, dm, vertexCos, tex_co, numVerts); modifier_init_texture(wmd->modifier.scene, wmd->texture); diff --git a/source/blender/modifiers/intern/MOD_wave.c b/source/blender/modifiers/intern/MOD_wave.c index c408f244afd..1271cccd719 100644 --- a/source/blender/modifiers/intern/MOD_wave.c +++ b/source/blender/modifiers/intern/MOD_wave.c @@ -206,7 +206,7 @@ static void waveModifier_do(WaveModifierData *md, } if (wmd->texture) { - tex_co = MEM_mallocN(sizeof(*tex_co) * numVerts, + tex_co = MEM_malloc_arrayN(numVerts, sizeof(*tex_co), "waveModifier_do tex_co"); get_texture_coords((MappingInfoModifierData *)wmd, ob, dm, vertexCos, tex_co, numVerts); diff --git a/source/blender/modifiers/intern/MOD_weightvg_util.c b/source/blender/modifiers/intern/MOD_weightvg_util.c index da7230ed5af..416f2964d6e 100644 --- a/source/blender/modifiers/intern/MOD_weightvg_util.c +++ b/source/blender/modifiers/intern/MOD_weightvg_util.c @@ -143,9 +143,9 @@ void weightvg_do_mask(int num, const int *indices, float *org_w, const float *ne t_map.map_object = tex_map_object; BLI_strncpy(t_map.uvlayer_name, tex_uvlayer_name, sizeof(t_map.uvlayer_name)); t_map.texmapping = tex_mapping; - v_co = MEM_mallocN(sizeof(*v_co) * numVerts, "WeightVG Modifier, TEX mode, v_co"); + v_co = MEM_malloc_arrayN(numVerts, sizeof(*v_co), "WeightVG Modifier, TEX mode, v_co"); dm->getVertCos(dm, v_co); - tex_co = MEM_callocN(sizeof(*tex_co) * numVerts, "WeightVG Modifier, TEX mode, tex_co"); + tex_co = MEM_calloc_arrayN(numVerts, sizeof(*tex_co), "WeightVG Modifier, TEX mode, tex_co"); get_texture_coords(&t_map, ob, dm, v_co, tex_co, num); MEM_freeN(v_co); diff --git a/source/blender/modifiers/intern/MOD_weightvgedit.c b/source/blender/modifiers/intern/MOD_weightvgedit.c index dbdaafaa5a7..9aa4bad1707 100644 --- a/source/blender/modifiers/intern/MOD_weightvgedit.c +++ b/source/blender/modifiers/intern/MOD_weightvgedit.c @@ -213,9 +213,9 @@ static DerivedMesh *applyModifier(ModifierData *md, } /* Get org weights, assuming 0.0 for vertices not in given vgroup. */ - org_w = MEM_mallocN(sizeof(float) * numVerts, "WeightVGEdit Modifier, org_w"); - new_w = MEM_mallocN(sizeof(float) * numVerts, "WeightVGEdit Modifier, new_w"); - dw = MEM_mallocN(sizeof(MDeformWeight *) * numVerts, "WeightVGEdit Modifier, dw"); + org_w = MEM_malloc_arrayN(numVerts, sizeof(float), "WeightVGEdit Modifier, org_w"); + new_w = MEM_malloc_arrayN(numVerts, sizeof(float), "WeightVGEdit Modifier, new_w"); + dw = MEM_malloc_arrayN(numVerts, sizeof(MDeformWeight *), "WeightVGEdit Modifier, dw"); for (i = 0; i < numVerts; i++) { dw[i] = defvert_find_index(&dvert[i], defgrp_index); if (dw[i]) { diff --git a/source/blender/modifiers/intern/MOD_weightvgmix.c b/source/blender/modifiers/intern/MOD_weightvgmix.c index 5f30d4ca72a..ab1264cc9a0 100644 --- a/source/blender/modifiers/intern/MOD_weightvgmix.c +++ b/source/blender/modifiers/intern/MOD_weightvgmix.c @@ -265,9 +265,9 @@ static DerivedMesh *applyModifier(ModifierData *md, const struct EvaluationConte return dm; } /* Find out which vertices to work on. */ - tidx = MEM_mallocN(sizeof(int) * numVerts, "WeightVGMix Modifier, tidx"); - tdw1 = MEM_mallocN(sizeof(MDeformWeight *) * numVerts, "WeightVGMix Modifier, tdw1"); - tdw2 = MEM_mallocN(sizeof(MDeformWeight *) * numVerts, "WeightVGMix Modifier, tdw2"); + tidx = MEM_malloc_arrayN(numVerts, sizeof(int), "WeightVGMix Modifier, tidx"); + tdw1 = MEM_malloc_arrayN(numVerts, sizeof(MDeformWeight *), "WeightVGMix Modifier, tdw1"); + tdw2 = MEM_malloc_arrayN(numVerts, sizeof(MDeformWeight *), "WeightVGMix Modifier, tdw2"); switch (wmd->mix_set) { case MOD_WVG_SET_A: /* All vertices in first vgroup. */ @@ -333,12 +333,12 @@ static DerivedMesh *applyModifier(ModifierData *md, const struct EvaluationConte return dm; } if (numIdx != -1) { - indices = MEM_mallocN(sizeof(int) * numIdx, "WeightVGMix Modifier, indices"); + indices = MEM_malloc_arrayN(numIdx, sizeof(int), "WeightVGMix Modifier, indices"); memcpy(indices, tidx, sizeof(int) * numIdx); - dw1 = MEM_mallocN(sizeof(MDeformWeight *) * numIdx, "WeightVGMix Modifier, dw1"); + dw1 = MEM_malloc_arrayN(numIdx, sizeof(MDeformWeight *), "WeightVGMix Modifier, dw1"); memcpy(dw1, tdw1, sizeof(MDeformWeight *) * numIdx); MEM_freeN(tdw1); - dw2 = MEM_mallocN(sizeof(MDeformWeight *) * numIdx, "WeightVGMix Modifier, dw2"); + dw2 = MEM_malloc_arrayN(numIdx, sizeof(MDeformWeight *), "WeightVGMix Modifier, dw2"); memcpy(dw2, tdw2, sizeof(MDeformWeight *) * numIdx); MEM_freeN(tdw2); } @@ -351,8 +351,8 @@ static DerivedMesh *applyModifier(ModifierData *md, const struct EvaluationConte } MEM_freeN(tidx); - org_w = MEM_mallocN(sizeof(float) * numIdx, "WeightVGMix Modifier, org_w"); - new_w = MEM_mallocN(sizeof(float) * numIdx, "WeightVGMix Modifier, new_w"); + org_w = MEM_malloc_arrayN(numIdx, sizeof(float), "WeightVGMix Modifier, org_w"); + new_w = MEM_malloc_arrayN(numIdx, sizeof(float), "WeightVGMix Modifier, new_w"); /* Mix weights. */ for (i = 0; i < numIdx; i++) { diff --git a/source/blender/modifiers/intern/MOD_weightvgproximity.c b/source/blender/modifiers/intern/MOD_weightvgproximity.c index c8bbbfe44b2..8a5d0f833a8 100644 --- a/source/blender/modifiers/intern/MOD_weightvgproximity.c +++ b/source/blender/modifiers/intern/MOD_weightvgproximity.c @@ -90,10 +90,13 @@ typedef struct Vert2GeomDataChunk { /** * Callback used by BLI_task 'for loop' helper. */ -static void vert2geom_task_cb_ex(void *userdata, void *userdata_chunk, const int iter, const int UNUSED(thread_id)) +static void vert2geom_task_cb_ex( + void *__restrict userdata, + const int iter, + const ParallelRangeTLS *__restrict tls) { Vert2GeomData *data = userdata; - Vert2GeomDataChunk *data_chunk = userdata_chunk; + Vert2GeomDataChunk *data_chunk = tls->userdata_chunk; float tmp_co[3]; int i; @@ -177,9 +180,16 @@ static void get_vert2geom_distance(int numVerts, float (*v_cos)[3], data.dist[1] = dist_e; data.dist[2] = dist_f; - BLI_task_parallel_range_ex( - 0, numVerts, &data, &data_chunk, sizeof(data_chunk), vert2geom_task_cb_ex, - numVerts > 10000, false); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = (numVerts > 10000); + settings.userdata_chunk = &data_chunk; + settings.userdata_chunk_size = sizeof(data_chunk); + BLI_task_parallel_range( + 0, numVerts, + &data, + vert2geom_task_cb_ex, + &settings); if (dist_v) free_bvhtree_from_mesh(&treeData_v); @@ -423,9 +433,9 @@ static DerivedMesh *applyModifier(ModifierData *md, const struct EvaluationConte /* Find out which vertices to work on (all vertices in vgroup), and get their relevant weight. */ - tidx = MEM_mallocN(sizeof(int) * numVerts, "WeightVGProximity Modifier, tidx"); - tw = MEM_mallocN(sizeof(float) * numVerts, "WeightVGProximity Modifier, tw"); - tdw = MEM_mallocN(sizeof(MDeformWeight *) * numVerts, "WeightVGProximity Modifier, tdw"); + tidx = MEM_malloc_arrayN(numVerts, sizeof(int), "WeightVGProximity Modifier, tidx"); + tw = MEM_malloc_arrayN(numVerts, sizeof(float), "WeightVGProximity Modifier, tw"); + tdw = MEM_malloc_arrayN(numVerts, sizeof(MDeformWeight *), "WeightVGProximity Modifier, tdw"); for (i = 0; i < numVerts; i++) { MDeformWeight *_dw = defvert_find_index(&dvert[i], defgrp_index); if (_dw) { @@ -442,11 +452,11 @@ static DerivedMesh *applyModifier(ModifierData *md, const struct EvaluationConte return dm; } if (numIdx != numVerts) { - indices = MEM_mallocN(sizeof(int) * numIdx, "WeightVGProximity Modifier, indices"); + indices = MEM_malloc_arrayN(numIdx, sizeof(int), "WeightVGProximity Modifier, indices"); memcpy(indices, tidx, sizeof(int) * numIdx); - org_w = MEM_mallocN(sizeof(float) * numIdx, "WeightVGProximity Modifier, org_w"); + org_w = MEM_malloc_arrayN(numIdx, sizeof(float), "WeightVGProximity Modifier, org_w"); memcpy(org_w, tw, sizeof(float) * numIdx); - dw = MEM_mallocN(sizeof(MDeformWeight *) * numIdx, "WeightVGProximity Modifier, dw"); + dw = MEM_malloc_arrayN(numIdx, sizeof(MDeformWeight *), "WeightVGProximity Modifier, dw"); memcpy(dw, tdw, sizeof(MDeformWeight *) * numIdx); MEM_freeN(tw); MEM_freeN(tdw); @@ -455,16 +465,16 @@ static DerivedMesh *applyModifier(ModifierData *md, const struct EvaluationConte org_w = tw; dw = tdw; } - new_w = MEM_mallocN(sizeof(float) * numIdx, "WeightVGProximity Modifier, new_w"); + new_w = MEM_malloc_arrayN(numIdx, sizeof(float), "WeightVGProximity Modifier, new_w"); MEM_freeN(tidx); /* Get our vertex coordinates. */ - v_cos = MEM_mallocN(sizeof(float[3]) * numIdx, "WeightVGProximity Modifier, v_cos"); + v_cos = MEM_malloc_arrayN(numIdx, sizeof(float[3]), "WeightVGProximity Modifier, v_cos"); if (numIdx != numVerts) { /* XXX In some situations, this code can be up to about 50 times more performant * than simply using getVertCo for each affected vertex... */ - float (*tv_cos)[3] = MEM_mallocN(sizeof(float[3]) * numVerts, "WeightVGProximity Modifier, tv_cos"); + float (*tv_cos)[3] = MEM_malloc_arrayN(numVerts, sizeof(float[3]), "WeightVGProximity Modifier, tv_cos"); dm->getVertCos(dm, tv_cos); for (i = 0; i < numIdx; i++) copy_v3_v3(v_cos[i], tv_cos[indices[i]]); @@ -503,9 +513,9 @@ static DerivedMesh *applyModifier(ModifierData *md, const struct EvaluationConte /* We must check that we do have a valid target_dm! */ if (target_dm) { SpaceTransform loc2trgt; - float *dists_v = use_trgt_verts ? MEM_mallocN(sizeof(float) * numIdx, "dists_v") : NULL; - float *dists_e = use_trgt_edges ? MEM_mallocN(sizeof(float) * numIdx, "dists_e") : NULL; - float *dists_f = use_trgt_faces ? MEM_mallocN(sizeof(float) * numIdx, "dists_f") : NULL; + float *dists_v = use_trgt_verts ? MEM_malloc_arrayN(numIdx, sizeof(float), "dists_v") : NULL; + float *dists_e = use_trgt_edges ? MEM_malloc_arrayN(numIdx, sizeof(float), "dists_e") : NULL; + float *dists_f = use_trgt_faces ? MEM_malloc_arrayN(numIdx, sizeof(float), "dists_f") : NULL; BLI_SPACE_TRANSFORM_SETUP(&loc2trgt, ob, obr); get_vert2geom_distance(numIdx, v_cos, dists_v, dists_e, dists_f, diff --git a/source/blender/modifiers/intern/MOD_wireframe.c b/source/blender/modifiers/intern/MOD_wireframe.c index 6fc1907ba0a..3cb35286114 100644 --- a/source/blender/modifiers/intern/MOD_wireframe.c +++ b/source/blender/modifiers/intern/MOD_wireframe.c @@ -52,11 +52,6 @@ static void copyData(ModifierData *md, ModifierData *target) modifier_copyData_generic(md, target); } -static bool isDisabled(ModifierData *UNUSED(md), int UNUSED(useRenderParams)) -{ - return false; -} - static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md) { WireframeModifierData *wmd = (WireframeModifierData *)md; @@ -132,8 +127,8 @@ ModifierTypeInfo modifierType_Wireframe = { /* initData */ initData, /* requiredDataMask */ requiredDataMask, /* freeData */ NULL, - /* isDisabled */ isDisabled, - /* updateDepsgraph */ NULL, + /* isDisabled */ NULL, + /* updateDepgraph */ NULL, /* dependsOnTime */ NULL, /* dependsOnNormals */ dependsOnNormals, /* foreachObjectLink */ NULL, diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt index a6e04510b03..c83daa185a8 100644 --- a/source/blender/nodes/CMakeLists.txt +++ b/source/blender/nodes/CMakeLists.txt @@ -194,6 +194,7 @@ set(SRC shader/nodes/node_shader_subsurface_scattering.c shader/nodes/node_shader_tangent.c shader/nodes/node_shader_bevel.c + shader/nodes/node_shader_displacement.c shader/nodes/node_shader_tex_brick.c shader/nodes/node_shader_tex_checker.c shader/nodes/node_shader_tex_coord.c diff --git a/source/blender/nodes/NOD_shader.h b/source/blender/nodes/NOD_shader.h index 62a92e8d084..cbdfd8d3dbf 100644 --- a/source/blender/nodes/NOD_shader.h +++ b/source/blender/nodes/NOD_shader.h @@ -79,6 +79,7 @@ void register_node_type_sh_tex_pointdensity(void); void register_node_type_sh_attribute(void); void register_node_type_sh_bevel(void); +void register_node_type_sh_displacement(void); void register_node_type_sh_geometry(void); void register_node_type_sh_light_path(void); void register_node_type_sh_light_falloff(void); diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h index a18ee154af8..e2c1fae1bde 100644 --- a/source/blender/nodes/NOD_static_types.h +++ b/source/blender/nodes/NOD_static_types.h @@ -128,6 +128,7 @@ DefNode( ShaderNode, SH_NODE_UVALONGSTROKE, def_sh_uvalongstroke, "UV DefNode( ShaderNode, SH_NODE_SEPXYZ, 0, "SEPXYZ", SeparateXYZ, "Separate XYZ", "" ) DefNode( ShaderNode, SH_NODE_COMBXYZ, 0, "COMBXYZ", CombineXYZ, "Combine XYZ", "" ) DefNode( ShaderNode, SH_NODE_BEVEL, def_sh_bevel, "BEVEL", Bevel, "Bevel", "" ) +DefNode( ShaderNode, SH_NODE_DISPLACEMENT, 0, "DISPLACEMENT", Displacement, "Displacement", "" ) DefNode( CompositorNode, CMP_NODE_VIEWER, def_cmp_viewer, "VIEWER", Viewer, "Viewer", "" ) DefNode( CompositorNode, CMP_NODE_RGB, 0, "RGB", RGB, "RGB", "" ) diff --git a/source/blender/nodes/composite/node_composite_util.h b/source/blender/nodes/composite/node_composite_util.h index 2dac0cc639a..22c5e6f9507 100644 --- a/source/blender/nodes/composite/node_composite_util.h +++ b/source/blender/nodes/composite/node_composite_util.h @@ -42,6 +42,7 @@ #include "BLT_translation.h" +#include "BKE_colorband.h" #include "BKE_colortools.h" #include "BKE_image.h" #include "BKE_texture.h" diff --git a/source/blender/nodes/composite/nodes/node_composite_hueSatVal.c b/source/blender/nodes/composite/nodes/node_composite_hueSatVal.c index 952ba78aff3..124e33d186f 100644 --- a/source/blender/nodes/composite/nodes/node_composite_hueSatVal.c +++ b/source/blender/nodes/composite/nodes/node_composite_hueSatVal.c @@ -37,8 +37,8 @@ static bNodeSocketTemplate cmp_node_hue_sat_in[] = { { SOCK_RGBA, 1, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f}, { SOCK_FLOAT, 1, N_("Hue"), 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR}, - { SOCK_FLOAT, 1, N_("Saturation"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR}, - { SOCK_FLOAT, 1, N_("Value"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR}, + { SOCK_FLOAT, 1, N_("Saturation"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 2.0f, PROP_FACTOR}, + { SOCK_FLOAT, 1, N_("Value"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 2.0f, PROP_FACTOR}, { SOCK_FLOAT, 1, N_("Fac"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR}, { -1, 0, "" } }; diff --git a/source/blender/nodes/composite/nodes/node_composite_image.c b/source/blender/nodes/composite/nodes/node_composite_image.c index bd7c4df317f..7712d7d0e71 100644 --- a/source/blender/nodes/composite/nodes/node_composite_image.c +++ b/source/blender/nodes/composite/nodes/node_composite_image.c @@ -341,6 +341,7 @@ void register_node_type_cmp_image(void) node_type_init(&ntype, node_composit_init_image); node_type_storage(&ntype, "ImageUser", node_composit_free_image, node_composit_copy_image); node_type_update(&ntype, cmp_node_image_update, NULL); + node_type_label(&ntype, node_image_label); nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/composite/nodes/node_composite_valToRgb.c b/source/blender/nodes/composite/nodes/node_composite_valToRgb.c index 32d68550cd4..707f1d22efd 100644 --- a/source/blender/nodes/composite/nodes/node_composite_valToRgb.c +++ b/source/blender/nodes/composite/nodes/node_composite_valToRgb.c @@ -46,7 +46,7 @@ static bNodeSocketTemplate cmp_node_valtorgb_out[] = { static void node_composit_init_valtorgb(bNodeTree *UNUSED(ntree), bNode *node) { - node->storage = add_colorband(true); + node->storage = BKE_colorband_add(true); } void register_node_type_cmp_valtorgb(void) diff --git a/source/blender/nodes/intern/node_socket.c b/source/blender/nodes/intern/node_socket.c index 382492707ce..e1d17003ba4 100644 --- a/source/blender/nodes/intern/node_socket.c +++ b/source/blender/nodes/intern/node_socket.c @@ -112,22 +112,21 @@ static bNodeSocket *verify_socket_template(bNodeTree *ntree, bNode *node, int in break; } if (sock) { - sock->type = stemp->type; + if (sock->type != stemp->type) { + nodeModifySocketType(ntree, node, sock, stemp->type, stemp->subtype); + } + sock->limit = (stemp->limit == 0 ? 0xFFF : stemp->limit); sock->flag |= stemp->flag; - - BLI_remlink(socklist, sock); - - return sock; } else { /* no socket for this template found, make a new one */ sock = node_add_socket_from_template(ntree, node, stemp, in_out); - /* remove the new socket from the node socket list first, - * will be added back after verification. - */ - BLI_remlink(socklist, sock); } + + /* remove the new socket from the node socket list first, + * will be added back after verification. */ + BLI_remlink(socklist, sock); return sock; } diff --git a/source/blender/nodes/intern/node_util.c b/source/blender/nodes/intern/node_util.c index dd5715891d5..43d4136d556 100644 --- a/source/blender/nodes/intern/node_util.c +++ b/source/blender/nodes/intern/node_util.c @@ -91,6 +91,12 @@ void node_blend_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int ma BLI_strncpy(label, IFACE_(name), maxlen); } +void node_image_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int maxlen) +{ + /* if there is no loaded image, return an empty string, and let nodeLabel() fill in the proper type translation. */ + BLI_strncpy(label, (node->id) ? node->id->name + 2 : "", maxlen); +} + void node_math_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int maxlen) { const char *name; diff --git a/source/blender/nodes/intern/node_util.h b/source/blender/nodes/intern/node_util.h index 2e20a8e79d4..b4437dfcb78 100644 --- a/source/blender/nodes/intern/node_util.h +++ b/source/blender/nodes/intern/node_util.h @@ -72,6 +72,7 @@ extern void *node_initexec_curves(struct bNodeExecContext *context, struct bNode /**** Labels ****/ void node_blend_label(struct bNodeTree *ntree, struct bNode *node, char *label, int maxlen); +void node_image_label(struct bNodeTree *ntree, struct bNode *node, char *label, int maxlen); void node_math_label(struct bNodeTree *ntree, struct bNode *node, char *label, int maxlen); void node_vect_math_label(struct bNodeTree *ntree, struct bNode *node, char *label, int maxlen); void node_filter_label(struct bNodeTree *ntree, struct bNode *node, char *label, int maxlen); diff --git a/source/blender/nodes/shader/node_shader_tree.c b/source/blender/nodes/shader/node_shader_tree.c index bd22a2be647..2f65188841e 100644 --- a/source/blender/nodes/shader/node_shader_tree.c +++ b/source/blender/nodes/shader/node_shader_tree.c @@ -460,6 +460,21 @@ static void ntree_shader_relink_displacement(bNodeTree *ntree, * cycles in the Cycles material :) */ nodeRemLink(ntree, displacement_link); + + /* Convert displacement vector to bump height. */ + bNode *dot_node = nodeAddStaticNode(NULL, ntree, SH_NODE_VECT_MATH); + bNode *geo_node = nodeAddStaticNode(NULL, ntree, SH_NODE_NEW_GEOMETRY); + dot_node->custom1 = 3; /* dot product */ + + nodeAddLink(ntree, + displacement_node, displacement_socket, + dot_node, dot_node->inputs.first); + nodeAddLink(ntree, + geo_node, ntree_shader_node_find_output(geo_node, "Normal"), + dot_node, dot_node->inputs.last); + displacement_node = dot_node; + displacement_socket = ntree_shader_node_find_output(dot_node, "Value"); + /* We can't connect displacement to normal directly, use bump node for that * and hope that it gives good enough approximation. */ diff --git a/source/blender/nodes/shader/node_shader_util.h b/source/blender/nodes/shader/node_shader_util.h index 148888f7693..2363addb56a 100644 --- a/source/blender/nodes/shader/node_shader_util.h +++ b/source/blender/nodes/shader/node_shader_util.h @@ -55,6 +55,7 @@ #include "BLI_threads.h" #include "BLI_utildefines.h" +#include "BKE_colorband.h" #include "BKE_colortools.h" #include "BKE_global.h" #include "BKE_image.h" diff --git a/source/blender/nodes/shader/nodes/node_shader_bump.c b/source/blender/nodes/shader/nodes/node_shader_bump.c index 15a8c47db7a..84481a50993 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bump.c +++ b/source/blender/nodes/shader/nodes/node_shader_bump.c @@ -34,7 +34,7 @@ /* **************** BUMP ******************** */ static bNodeSocketTemplate sh_node_bump_in[] = { { SOCK_FLOAT, 1, N_("Strength"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR}, - { SOCK_FLOAT, 1, N_("Distance"), 0.1f, 0.0f, 0.0f, 0.0f, 0.0f, 1000.0f}, + { SOCK_FLOAT, 1, N_("Distance"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1000.0f}, { SOCK_FLOAT, 1, N_("Height"), 1.0f, 1.0f, 1.0f, 1.0f, -1000.0f, 1000.0f, PROP_NONE, SOCK_HIDE_VALUE}, { SOCK_VECTOR, 1, N_("Normal"), 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE}, { -1, 0, "" } diff --git a/source/blender/nodes/shader/nodes/node_shader_displacement.c b/source/blender/nodes/shader/nodes/node_shader_displacement.c new file mode 100644 index 00000000000..d5c191b3966 --- /dev/null +++ b/source/blender/nodes/shader/nodes/node_shader_displacement.c @@ -0,0 +1,65 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2005 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "../node_shader_util.h" + +/* **************** OUTPUT ******************** */ + +static bNodeSocketTemplate sh_node_displacement_in[] = { + { SOCK_FLOAT, 0, N_("Height"), 0.00f, 0.0f, 0.0f, 0.0f, 0.0f, 1000.0f}, + { SOCK_FLOAT, 0, N_("Scale"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1000.0f}, + { SOCK_VECTOR, 1, N_("Normal"), 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE}, + { -1, 0, "" } +}; + +static bNodeSocketTemplate sh_node_displacement_out[] = { + { SOCK_VECTOR, 0, N_("Displacement"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; + +static int gpu_shader_displacement(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out) +{ + if (!in[2].link) { + GPU_link(mat, "direction_transform_m4v3", GPU_builtin(GPU_VIEW_NORMAL), GPU_builtin(GPU_INVERSE_VIEW_MATRIX), &in[2].link); + } + + return GPU_stack_link(mat, node, "node_displacement", in, out); +} + +/* node type definition */ +void register_node_type_sh_displacement(void) +{ + static bNodeType ntype; + + sh_node_type_base(&ntype, SH_NODE_DISPLACEMENT, "Displacement", NODE_CLASS_OP_VECTOR, 0); + node_type_compatibility(&ntype, NODE_NEW_SHADING); + node_type_socket_templates(&ntype, sh_node_displacement_in, sh_node_displacement_out); + node_type_storage(&ntype, "", NULL, NULL); + node_type_gpu(&ntype, gpu_shader_displacement); + + nodeRegisterType(&ntype); +} diff --git a/source/blender/nodes/shader/nodes/node_shader_output_material.c b/source/blender/nodes/shader/nodes/node_shader_output_material.c index 0418b039337..e901e7c4590 100644 --- a/source/blender/nodes/shader/nodes/node_shader_output_material.c +++ b/source/blender/nodes/shader/nodes/node_shader_output_material.c @@ -34,7 +34,7 @@ static bNodeSocketTemplate sh_node_output_material_in[] = { { SOCK_SHADER, 1, N_("Surface")}, { SOCK_SHADER, 1, N_("Volume")}, - { SOCK_FLOAT, 1, N_("Displacement"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE}, + { SOCK_VECTOR, 1, N_("Displacement"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE}, { -1, 0, "" } }; diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_pointdensity.c b/source/blender/nodes/shader/nodes/node_shader_tex_pointdensity.c index 8748c884a25..436eeeefb4a 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_pointdensity.c +++ b/source/blender/nodes/shader/nodes/node_shader_tex_pointdensity.c @@ -27,7 +27,6 @@ #include "../node_shader_util.h" -#include "BKE_texture.h" #include "RE_render_ext.h" diff --git a/source/blender/nodes/shader/nodes/node_shader_valToRgb.c b/source/blender/nodes/shader/nodes/node_shader_valToRgb.c index b5e32e294bf..39598eb8675 100644 --- a/source/blender/nodes/shader/nodes/node_shader_valToRgb.c +++ b/source/blender/nodes/shader/nodes/node_shader_valToRgb.c @@ -53,14 +53,14 @@ static void node_shader_exec_valtorgb(void *UNUSED(data), int UNUSED(thread), bN float fac; nodestack_get_vec(&fac, SOCK_FLOAT, in[0]); - do_colorband(node->storage, fac, out[0]->vec); + BKE_colorband_evaluate(node->storage, fac, out[0]->vec); out[1]->vec[0] = out[0]->vec[3]; } } static void node_shader_init_valtorgb(bNodeTree *UNUSED(ntree), bNode *node) { - node->storage = add_colorband(true); + node->storage = BKE_colorband_add(true); } static int gpu_shader_valtorgb(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out) @@ -68,7 +68,7 @@ static int gpu_shader_valtorgb(GPUMaterial *mat, bNode *node, bNodeExecData *UNU float *array; int size; - colorband_table_RGBA(node->storage, &array, &size); + BKE_colorband_evaluate_table_rgba(node->storage, &array, &size); return GPU_stack_link(mat, node, "valtorgb", in, out, GPU_texture(size, array)); } diff --git a/source/blender/nodes/texture/node_texture_util.h b/source/blender/nodes/texture/node_texture_util.h index 2263c271ccf..f6af5b1b6ca 100644 --- a/source/blender/nodes/texture/node_texture_util.h +++ b/source/blender/nodes/texture/node_texture_util.h @@ -53,6 +53,7 @@ #include "BLI_threads.h" #include "BLI_utildefines.h" +#include "BKE_colorband.h" #include "BKE_colortools.h" #include "BKE_global.h" #include "BKE_image.h" diff --git a/source/blender/nodes/texture/nodes/node_texture_image.c b/source/blender/nodes/texture/nodes/node_texture_image.c index 9b13589f3e1..8e9821c0fcb 100644 --- a/source/blender/nodes/texture/nodes/node_texture_image.c +++ b/source/blender/nodes/texture/nodes/node_texture_image.c @@ -106,6 +106,7 @@ void register_node_type_tex_image(void) node_type_init(&ntype, init); node_type_storage(&ntype, "ImageUser", node_free_standard_storage, node_copy_standard_storage); node_type_exec(&ntype, NULL, NULL, exec); - + node_type_label(&ntype, node_image_label); + nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/texture/nodes/node_texture_valToRgb.c b/source/blender/nodes/texture/nodes/node_texture_valToRgb.c index a49d82d27a9..8b016c5aa50 100644 --- a/source/blender/nodes/texture/nodes/node_texture_valToRgb.c +++ b/source/blender/nodes/texture/nodes/node_texture_valToRgb.c @@ -49,7 +49,7 @@ static void valtorgb_colorfn(float *out, TexParams *p, bNode *node, bNodeStack * if (node->storage) { float fac = tex_input_value(in[0], p, thread); - do_colorband(node->storage, fac, out); + BKE_colorband_evaluate(node->storage, fac, out); } } @@ -60,7 +60,7 @@ static void valtorgb_exec(void *data, int UNUSED(thread), bNode *node, bNodeExec static void valtorgb_init(bNodeTree *UNUSED(ntree), bNode *node) { - node->storage = add_colorband(true); + node->storage = BKE_colorband_add(true); } void register_node_type_tex_valtorgb(void) diff --git a/source/blender/python/bmesh/bmesh_py_utils.c b/source/blender/python/bmesh/bmesh_py_utils.c index fc0cd9e475b..224c8295a9b 100644 --- a/source/blender/python/bmesh/bmesh_py_utils.c +++ b/source/blender/python/bmesh/bmesh_py_utils.c @@ -650,7 +650,7 @@ static PyObject *bpy_bm_utils_face_join(PyObject *UNUSED(self), PyObject *args) bool do_remove = true; if (!PyArg_ParseTuple( - args, "O|i:face_join", + args, "O|O&:face_join", &py_face_array, PyC_ParseBool, &do_remove)) { diff --git a/source/blender/python/gawain/gwn_py_types.c b/source/blender/python/gawain/gwn_py_types.c index 5b602e85a12..4f6b354b7be 100644 --- a/source/blender/python/gawain/gwn_py_types.c +++ b/source/blender/python/gawain/gwn_py_types.c @@ -634,7 +634,7 @@ static PyObject *bpygwn_VertBatch_uniform_i32(BPyGwn_Batch *self, PyObject *args static PyObject *bpygwn_VertBatch_uniform_f32(BPyGwn_Batch *self, PyObject *args) { - static struct { + struct { const char *id; float values[4]; } params; @@ -648,10 +648,10 @@ static PyObject *bpygwn_VertBatch_uniform_f32(BPyGwn_Batch *self, PyObject *args } switch (PyTuple_GET_SIZE(args)) { - case 2: GWN_batch_uniform_1f(self->batch, params.id, params.values[0]); break; - case 3: GWN_batch_uniform_2fv(self->batch, params.id, params.values); break; - case 4: GWN_batch_uniform_3fv(self->batch, params.id, params.values); break; - case 5: GWN_batch_uniform_4fv(self->batch, params.id, params.values); break; + case 2: GWN_batch_uniform_1f(self->batch, params.id, params.values[0]); break; + case 3: GWN_batch_uniform_2f(self->batch, params.id, UNPACK2(params.values)); break; + case 4: GWN_batch_uniform_3f(self->batch, params.id, UNPACK3(params.values)); break; + case 5: GWN_batch_uniform_4f(self->batch, params.id, UNPACK4(params.values)); break; default: BLI_assert(0); } diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c index fdad3a7d919..e220e6559a6 100644 --- a/source/blender/python/intern/bpy_rna.c +++ b/source/blender/python/intern/bpy_rna.c @@ -1419,9 +1419,9 @@ static PyObject *pyrna_enum_to_py(PointerRNA *ptr, PropertyRNA *prop, int val) /* prefer not fail silently in case of api errors, maybe disable it later */ printf("RNA Warning: Current value \"%d\" " - "matches no enum in '%s', '%s', '%s'\n", - val, RNA_struct_identifier(ptr->type), - ptr_name, RNA_property_identifier(prop)); + "matches no enum in '%s', '%s', '%s'\n", + val, RNA_struct_identifier(ptr->type), + ptr_name, RNA_property_identifier(prop)); #if 0 /* gives python decoding errors while generating docs :( */ char error_str[256]; @@ -1751,10 +1751,8 @@ static int pyrna_py_to_prop( return -1; } else { - /* same as unicode */ - /* XXX, this is suspect but needed for function calls, need to see if theres a better way */ if (data) *((char **)data) = (char *)param; - else RNA_property_string_set(ptr, prop, param); + else RNA_property_string_set_bytes(ptr, prop, param, PyBytes_Size(value)); } } else { diff --git a/source/blender/python/intern/gpu_offscreen.c b/source/blender/python/intern/gpu_offscreen.c index 226bfcc7c21..91d407d18a8 100644 --- a/source/blender/python/intern/gpu_offscreen.c +++ b/source/blender/python/intern/gpu_offscreen.c @@ -354,7 +354,7 @@ static PyObject *pygpu_offscreen_new(PyObject *UNUSED(self), PyObject *args, PyO return NULL; } - ofs = GPU_offscreen_create(width, height, samples, err_out); + ofs = GPU_offscreen_create(width, height, samples, false, err_out); if (ofs == NULL) { PyErr_Format(PyExc_RuntimeError, diff --git a/source/blender/python/mathutils/mathutils_Matrix.c b/source/blender/python/mathutils/mathutils_Matrix.c index 2578b19d5ec..924e46a8c00 100644 --- a/source/blender/python/mathutils/mathutils_Matrix.c +++ b/source/blender/python/mathutils/mathutils_Matrix.c @@ -1641,9 +1641,9 @@ static PyObject *Matrix_rotate(MatrixObject *self, PyObject *value) PyDoc_STRVAR(Matrix_decompose_doc, ".. method:: decompose()\n" "\n" -" Return the translation, rotation and scale components of this matrix.\n" +" Return the translation, rotation, and scale components of this matrix.\n" "\n" -" :return: trans, rot, scale triple.\n" +" :return: tuple of translation, rotation, and scale\n" " :rtype: (:class:`Vector`, :class:`Quaternion`, :class:`Vector`)" ); static PyObject *Matrix_decompose(MatrixObject *self) @@ -1680,7 +1680,8 @@ static PyObject *Matrix_decompose(MatrixObject *self) PyDoc_STRVAR(Matrix_lerp_doc, ".. function:: lerp(other, factor)\n" "\n" -" Returns the interpolation of two matrices.\n" +" Returns the interpolation of two matrices. Uses polar decomposition, see" +" \"Matrix Animation and Polar Decomposition\", Shoemake and Duff, 1992.\n" "\n" " :arg other: value to interpolate with.\n" " :type other: :class:`Matrix`\n" diff --git a/source/blender/render/extern/include/RE_engine.h b/source/blender/render/extern/include/RE_engine.h index 60ffd8f42e4..f789ab702fe 100644 --- a/source/blender/render/extern/include/RE_engine.h +++ b/source/blender/render/extern/include/RE_engine.h @@ -183,6 +183,8 @@ void RE_engines_init(void); void RE_engines_exit(void); void RE_engines_register(struct Main *bmain, RenderEngineType *render_type); +bool RE_engine_is_opengl(RenderEngineType *render_type); + RenderEngineType *RE_engines_find(const char *idname); rcti* RE_engine_get_current_tiles(struct Render *re, int *r_total_tiles, bool *r_needs_free); diff --git a/source/blender/render/extern/include/RE_pipeline.h b/source/blender/render/extern/include/RE_pipeline.h index a0f3a053618..0557efccc2f 100644 --- a/source/blender/render/extern/include/RE_pipeline.h +++ b/source/blender/render/extern/include/RE_pipeline.h @@ -392,6 +392,7 @@ void RE_updateRenderInstances(Render *re, int flag); /******* defined in render_result.c *********/ bool RE_HasCombinedLayer(RenderResult *res); +bool RE_HasFloatPixels(RenderResult *res); bool RE_RenderResult_is_stereo(RenderResult *res); struct RenderView *RE_RenderViewGetById(struct RenderResult *res, const int view_id); struct RenderView *RE_RenderViewGetByName(struct RenderResult *res, const char *viewname); diff --git a/source/blender/render/intern/source/convertblender.c b/source/blender/render/intern/source/convertblender.c index 74de3fcded6..19a87784ad4 100644 --- a/source/blender/render/intern/source/convertblender.c +++ b/source/blender/render/intern/source/convertblender.c @@ -3798,12 +3798,13 @@ static GroupObject *add_render_lamp(Render *re, Object *ob) copy_v3_v3(vec, ob->obmat[2]); normalize_v3(vec); - InitSunSky(lar->sunsky, la->atm_turbidity, vec, la->horizon_brightness, - la->spread, la->sun_brightness, la->sun_size, la->backscattered_light, - la->skyblendfac, la->skyblendtype, la->sky_exposure, la->sky_colorspace); - - InitAtmosphere(lar->sunsky, la->sun_intensity, 1.0, 1.0, la->atm_inscattering_factor, la->atm_extinction_factor, - la->atm_distance_factor); + InitSunSky( + lar->sunsky, la->atm_turbidity, vec, la->horizon_brightness, + la->spread, la->sun_brightness, la->sun_size, la->backscattered_light, + la->skyblendfac, la->skyblendtype, la->sky_exposure, la->sky_colorspace); + InitAtmosphere( + lar->sunsky, la->sun_intensity, 1.0, 1.0, la->atm_inscattering_factor, la->atm_extinction_factor, + la->atm_distance_factor); } } else lar->ray_totsamp= 0; @@ -4668,9 +4669,8 @@ static void add_render_object(Render *re, Object *ob, Object *par, DupliObject * /* the emitter has to be processed first (render levels of modifiers) */ /* so here we only check if the emitter should be rendered */ if (ob->particlesystem.first) { - show_emitter= 0; + show_emitter = (ob->duplicator_visibility_flag & OB_DUPLI_FLAG_RENDER) != 0; for (psys=ob->particlesystem.first; psys; psys=psys->next) { - show_emitter += psys->part->draw & PART_DRAW_EMITTER; if (!(re->r.scemode & R_VIEWPORT_PREVIEW)) { psys_has_renderdata |= (psys->renderdata != NULL); psys_render_set(ob, psys, re->viewmat, re->winmat, re->winx, re->winy, timeoffset); diff --git a/source/blender/render/intern/source/external_engine.c b/source/blender/render/intern/source/external_engine.c index 68077d4d93b..2714e8b7685 100644 --- a/source/blender/render/intern/source/external_engine.c +++ b/source/blender/render/intern/source/external_engine.c @@ -155,6 +155,13 @@ bool RE_engine_is_external(Render *re) return (re->engine && re->engine->type && re->engine->type->render_to_image); } +bool RE_engine_is_opengl(RenderEngineType *render_type) +{ + /* TODO refine? Can we have ogl render engine without ogl render pipeline? */ + return (render_type->draw_engine != NULL) && + DRW_engine_render_support(render_type->draw_engine); +} + /* Create, Free */ RenderEngine *RE_engine_create(RenderEngineType *type) diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c index 7fdaf38a9ff..5a5c99724fe 100644 --- a/source/blender/render/intern/source/pipeline.c +++ b/source/blender/render/intern/source/pipeline.c @@ -37,6 +37,7 @@ #include <errno.h> #include "DNA_anim_types.h" +#include "DNA_group_types.h" #include "DNA_image_types.h" #include "DNA_node_types.h" #include "DNA_object_types.h" @@ -448,8 +449,6 @@ void RE_AcquireResultImage(Render *re, RenderResult *rr, const int view_id) rr->rectz = rv->rectz; rr->rect32 = rv->rect32; - rr->have_combined = (rv->rectf != NULL); - /* active layer */ rl = render_get_active_layer(re, re->result); @@ -860,7 +859,7 @@ void RE_InitState(Render *re, Render *source, RenderData *rd, re->result = MEM_callocN(sizeof(RenderResult), "new render result"); re->result->rectx = re->rectx; re->result->recty = re->recty; - render_result_view_new(re->result, "new temporary view"); + render_result_view_new(re->result, ""); } if (re->r.scemode & R_VIEWPORT_PREVIEW) @@ -2113,6 +2112,31 @@ static void tag_dependend_objects_for_render(Scene *scene, int UNUSED(renderlay) } #endif +#define DEPSGRAPH_WORKAROUND_GROUP_HACK + +#ifdef DEPSGRAPH_WORKAROUND_GROUP_HACK +/** + * Make sure the COLLECTION_VIEWPORT / COLLECTION_RENDER is considered + * for the collections visibility. + * + * This won't be needed anymore once we have depsgraph per render engine. + */ +static void tag_groups_for_render(Render *re) +{ + for (Group *group = re->main->group.first; group; group = group->id.next) { + DEG_id_tag_update(&group->id, 0); + } + +#ifdef WITH_FREESTYLE + if (re->freestyle_bmain) { + for (Group *group = re->freestyle_bmain->group.first; group; group = group->id.next) { + DEG_id_tag_update(&group->id, 0); + } + } +#endif +} +#endif + static void tag_scenes_for_render(Render *re) { bNode *node; @@ -2196,6 +2220,10 @@ static void ntree_render_scenes(Render *re) if (re->scene->nodetree == NULL) return; tag_scenes_for_render(re); + +#ifdef DEPSGRAPH_WORKAROUND_GROUP_HACK + tag_groups_for_render(re); +#endif /* now foreach render-result node tagged we do a full render */ /* results are stored in a way compisitor will find it */ @@ -2413,6 +2441,10 @@ static void do_merge_fullsample(Render *re, bNodeTree *ntree) } } +#ifdef DEPSGRAPH_WORKAROUND_GROUP_HACK + tag_groups_for_render(re); +#endif + /* composite */ if (ntree) { ntreeCompositTagRender(re->scene); @@ -2564,6 +2596,11 @@ void RE_MergeFullSample(Render *re, Main *bmain, Scene *sce, bNodeTree *ntree) #ifdef WITH_FREESTYLE free_all_freestyle_renders(); #endif + +#ifdef DEPSGRAPH_WORKAROUND_GROUP_HACK + /* Restore their visibility based on the viewport visibility flags. */ + tag_groups_for_render(re); +#endif } /* returns fully composited render-result on given time step (in RenderData) */ @@ -2662,6 +2699,11 @@ static void do_render_composite_fields_blur_3d(Render *re) free_all_freestyle_renders(); #endif +#ifdef DEPSGRAPH_WORKAROUND_GROUP_HACK + /* Restore their visibility based on the viewport visibility flags. */ + tag_groups_for_render(re); +#endif + /* weak... the display callback wants an active renderlayer pointer... */ if (re->result != NULL) { re->result->renlay = render_get_active_layer(re, re->result); @@ -3223,6 +3265,11 @@ static int render_initialize_from_main(Render *re, RenderData *rd, Main *bmain, /* check all scenes involved */ tag_scenes_for_render(re); +#ifdef DEPSGRAPH_WORKAROUND_GROUP_HACK + /* Update group collections visibility. */ + tag_groups_for_render(re); +#endif + /* * Disabled completely for now, * can be later set as render profile option @@ -3346,7 +3393,8 @@ bool RE_WriteRenderViewsImage(ReportList *reports, RenderResult *rr, Scene *scen return false; bool is_mono = BLI_listbase_count_ex(&rr->views, 2) < 2; - bool is_exr_rr = ELEM(rd->im_format.imtype, R_IMF_IMTYPE_OPENEXR, R_IMF_IMTYPE_MULTILAYER); + bool is_exr_rr = ELEM(rd->im_format.imtype, R_IMF_IMTYPE_OPENEXR, R_IMF_IMTYPE_MULTILAYER) && + RE_HasFloatPixels(rr); if (rd->im_format.views_format == R_IMF_VIEWS_MULTIVIEW && is_exr_rr) { diff --git a/source/blender/render/intern/source/pixelshading.c b/source/blender/render/intern/source/pixelshading.c index 97d6b060e0a..ddbdb35bf51 100644 --- a/source/blender/render/intern/source/pixelshading.c +++ b/source/blender/render/intern/source/pixelshading.c @@ -576,7 +576,7 @@ void shadeSunView(float col_r[3], const float view[3]) GetSkyXYZRadiancef(lar->sunsky, sview, colorxyz); xyz_to_rgb(colorxyz[0], colorxyz[1], colorxyz[2], &sun_collector[0], &sun_collector[1], &sun_collector[2], - lar->sunsky->sky_colorspace); + lar->sunsky->sky_colorspace); ramp_blend(lar->sunsky->skyblendtype, col_r, lar->sunsky->skyblendfac, sun_collector); } diff --git a/source/blender/render/intern/source/pointdensity.c b/source/blender/render/intern/source/pointdensity.c index e94a452c94a..4f300b7286c 100644 --- a/source/blender/render/intern/source/pointdensity.c +++ b/source/blender/render/intern/source/pointdensity.c @@ -48,6 +48,7 @@ #include "DNA_particle_types.h" #include "DNA_texture_types.h" +#include "BKE_colorband.h" #include "BKE_deform.h" #include "BKE_DerivedMesh.h" #include "BKE_lattice.h" @@ -55,7 +56,6 @@ #include "BKE_object.h" #include "BKE_particle.h" #include "BKE_scene.h" -#include "BKE_texture.h" #include "BKE_colortools.h" #include "DEG_depsgraph.h" @@ -786,7 +786,7 @@ static int pointdensity_color(PointDensity *pd, TexResult *texres, float age, co switch (pd->color_source) { case TEX_PD_COLOR_PARTAGE: if (pd->coba) { - if (do_colorband(pd->coba, age, rgba)) { + if (BKE_colorband_evaluate(pd->coba, age, rgba)) { texres->talpha = true; copy_v3_v3(&texres->tr, rgba); texres->tin *= rgba[3]; @@ -799,7 +799,7 @@ static int pointdensity_color(PointDensity *pd, TexResult *texres, float age, co float speed = len_v3(vec) * pd->speed_scale; if (pd->coba) { - if (do_colorband(pd->coba, speed, rgba)) { + if (BKE_colorband_evaluate(pd->coba, speed, rgba)) { texres->talpha = true; copy_v3_v3(&texres->tr, rgba); texres->tin *= rgba[3]; @@ -831,7 +831,7 @@ static int pointdensity_color(PointDensity *pd, TexResult *texres, float age, co break; case TEX_PD_COLOR_VERTWEIGHT: texres->talpha = true; - if (pd->coba && do_colorband(pd->coba, col[0], rgba)) { + if (pd->coba && BKE_colorband_evaluate(pd->coba, col[0], rgba)) { copy_v3_v3(&texres->tr, rgba); texres->tin *= rgba[3]; } @@ -1033,7 +1033,10 @@ typedef struct SampleCallbackData { float *values; } SampleCallbackData; -static void point_density_sample_func(void *data_v, const int iter) +static void point_density_sample_func( + void *__restrict data_v, + const int iter, + const ParallelRangeTLS *__restrict UNUSED(tls)) { SampleCallbackData *data = (SampleCallbackData *)data_v; @@ -1108,11 +1111,14 @@ void RE_point_density_sample( data.min = min; data.dim = dim; data.values = values; + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = (resolution > 32); BLI_task_parallel_range(0, resolution, &data, point_density_sample_func, - resolution > 32); + &settings); free_pointdensity(pd); } diff --git a/source/blender/render/intern/source/render_result.c b/source/blender/render/intern/source/render_result.c index 0e7f35fbca3..6749fedb16e 100644 --- a/source/blender/render/intern/source/render_result.c +++ b/source/blender/render/intern/source/render_result.c @@ -80,6 +80,8 @@ static void render_result_views_free(RenderResult *res) MEM_freeN(rv); } + + res->have_combined = false; } void render_result_free(RenderResult *res) @@ -1081,7 +1083,7 @@ static void save_render_result_tile(RenderResult *rr, RenderResult *rrpart, cons continue; } - IMB_exrtile_write_channels(rl->exrhandle, partx, party, 0, viewname); + IMB_exrtile_write_channels(rl->exrhandle, partx, party, 0, viewname, false); } BLI_unlock_thread(LOCK_IMAGE); @@ -1095,13 +1097,11 @@ void render_result_save_empty_result_tiles(Render *re) for (rr = re->result; rr; rr = rr->next) { for (rl = rr->layers.first; rl; rl = rl->next) { - IMB_exr_clear_channels(rl->exrhandle); - for (pa = re->parts.first; pa; pa = pa->next) { if (pa->status != PART_STATUS_MERGED) { int party = pa->disprect.ymin - re->disprect.ymin + pa->crop; int partx = pa->disprect.xmin - re->disprect.xmin + pa->crop; - IMB_exrtile_write_channels(rl->exrhandle, partx, party, 0, re->viewname); + IMB_exrtile_write_channels(rl->exrhandle, partx, party, 0, re->viewname, true); } } } @@ -1354,6 +1354,8 @@ void RE_render_result_rect_from_ibuf(RenderResult *rr, RenderData *UNUSED(rd), I RenderView *rv = RE_RenderViewGetById(rr, view_id); if (ibuf->rect_float) { + rr->have_combined = true; + if (!rv->rectf) rv->rectf = MEM_mallocN(4 * sizeof(float) * rr->rectx * rr->recty, "render_seq rectf"); @@ -1364,6 +1366,8 @@ void RE_render_result_rect_from_ibuf(RenderResult *rr, RenderData *UNUSED(rd), I MEM_SAFE_FREE(rv->rect32); } else if (ibuf->rect) { + rr->have_combined = true; + if (!rv->rect32) rv->rect32 = MEM_mallocN(sizeof(int) * rr->rectx * rr->recty, "render_seq rect"); @@ -1419,6 +1423,19 @@ bool RE_HasCombinedLayer(RenderResult *res) return (rv->rect32 || rv->rectf); } +bool RE_HasFloatPixels(RenderResult *res) +{ + RenderView *rview; + + for (rview = res->views.first; rview; rview = rview->next) { + if (rview->rect32 && !rview->rectf) { + return false; + } + } + + return true; +} + bool RE_RenderResult_is_stereo(RenderResult *res) { if (! BLI_findstring(&res->views, STEREO_LEFT_NAME, offsetof(RenderView, name))) @@ -1485,9 +1502,6 @@ static RenderView *duplicate_render_view(RenderView *rview) if (new_rview->rectf != NULL) { new_rview->rectf = MEM_dupallocN(new_rview->rectf); } - if (new_rview->rectf != NULL) { - new_rview->rectf = MEM_dupallocN(new_rview->rectf); - } if (new_rview->rectz != NULL) { new_rview->rectz = MEM_dupallocN(new_rview->rectz); } diff --git a/source/blender/render/intern/source/render_texture.c b/source/blender/render/intern/source/render_texture.c index 91d1f63a1be..4241dff96de 100644 --- a/source/blender/render/intern/source/render_texture.c +++ b/source/blender/render/intern/source/render_texture.c @@ -54,6 +54,7 @@ #include "BKE_node.h" #include "BKE_animsys.h" +#include "BKE_colorband.h" #include "BKE_DerivedMesh.h" #include "BKE_global.h" #include "BKE_main.h" @@ -161,15 +162,15 @@ static void tex_normal_derivate(Tex *tex, TexResult *texres) { if (tex->flag & TEX_COLORBAND) { float col[4]; - if (do_colorband(tex->coba, texres->tin, col)) { + if (BKE_colorband_evaluate(tex->coba, texres->tin, col)) { float fac0, fac1, fac2, fac3; fac0= (col[0]+col[1]+col[2]); - do_colorband(tex->coba, texres->nor[0], col); + BKE_colorband_evaluate(tex->coba, texres->nor[0], col); fac1= (col[0]+col[1]+col[2]); - do_colorband(tex->coba, texres->nor[1], col); + BKE_colorband_evaluate(tex->coba, texres->nor[1], col); fac2= (col[0]+col[1]+col[2]); - do_colorband(tex->coba, texres->nor[2], col); + BKE_colorband_evaluate(tex->coba, texres->nor[2], col); fac3= (col[0]+col[1]+col[2]); texres->nor[0]= (fac0 - fac1) / 3.0f; @@ -1218,7 +1219,7 @@ static int multitex(Tex *tex, if (tex->flag & TEX_COLORBAND) { float col[4]; - if (do_colorband(tex->coba, texres->tin, col)) { + if (BKE_colorband_evaluate(tex->coba, texres->tin, col)) { texres->talpha = true; texres->tr= col[0]; texres->tg= col[1]; @@ -3753,7 +3754,7 @@ Material *RE_sample_material_init(Material *orig_mat, Scene *scene) if (!orig_mat) return NULL; /* copy material */ - mat = localize_material(orig_mat); + mat = BKE_material_localize(orig_mat); /* update material anims */ BKE_animsys_evaluate_animdata(scene, &mat->id, mat->adt, BKE_scene_frame_get(scene), ADT_RECALC_ANIM); diff --git a/source/blender/render/intern/source/shadeoutput.c b/source/blender/render/intern/source/shadeoutput.c index 9279899ef66..c2d5c060530 100644 --- a/source/blender/render/intern/source/shadeoutput.c +++ b/source/blender/render/intern/source/shadeoutput.c @@ -27,7 +27,6 @@ * \ingroup render */ - #include <stdio.h> #include <float.h> #include <math.h> @@ -36,10 +35,9 @@ #include "BLI_math.h" #include "BLI_utildefines.h" +#include "BKE_colorband.h" #include "BKE_colortools.h" #include "BKE_material.h" -#include "BKE_texture.h" - #include "DNA_group_types.h" #include "DNA_lamp_types.h" @@ -942,7 +940,7 @@ static void ramp_diffuse_result(float *diff, ShadeInput *shi) if (ma->ramp_col) { if (ma->rampin_col==MA_RAMP_IN_RESULT) { float fac = IMB_colormanagement_get_luminance(diff); - do_colorband(ma->ramp_col, fac, col); + BKE_colorband_evaluate(ma->ramp_col, fac, col); /* blending method */ fac= col[3]*ma->rampfac_col; @@ -986,7 +984,7 @@ static void add_to_diffuse(float diff[3], const ShadeInput *shi, const float is, break; } - do_colorband(ma->ramp_col, fac, col); + BKE_colorband_evaluate(ma->ramp_col, fac, col); /* blending method */ fac = col[3] * ma->rampfac_col; @@ -1015,7 +1013,7 @@ static void ramp_spec_result(float spec_col[3], ShadeInput *shi) float col[4]; float fac = IMB_colormanagement_get_luminance(spec_col); - do_colorband(ma->ramp_spec, fac, col); + BKE_colorband_evaluate(ma->ramp_spec, fac, col); /* blending method */ fac= col[3]*ma->rampfac_spec; @@ -1055,7 +1053,7 @@ static void do_specular_ramp(ShadeInput *shi, float is, float t, float spec[3]) break; } - do_colorband(ma->ramp_spec, fac, col); + BKE_colorband_evaluate(ma->ramp_spec, fac, col); /* blending method */ fac= col[3]*ma->rampfac_spec; diff --git a/source/blender/windowmanager/CMakeLists.txt b/source/blender/windowmanager/CMakeLists.txt index b5784fe543c..059055daea9 100644 --- a/source/blender/windowmanager/CMakeLists.txt +++ b/source/blender/windowmanager/CMakeLists.txt @@ -73,6 +73,7 @@ set(SRC intern/wm_window.c intern/wm_stereo.c intern/wm_toolsystem.c + intern/wm_tooltip.c manipulators/intern/wm_manipulator.c manipulators/intern/wm_manipulator_group.c manipulators/intern/wm_manipulator_group_type.c diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h index 61ffbc98426..16c376888df 100644 --- a/source/blender/windowmanager/WM_api.h +++ b/source/blender/windowmanager/WM_api.h @@ -216,7 +216,6 @@ struct wmEventHandler *WM_event_add_dropbox_handler(ListBase *handlers, ListBase /* mouse */ void WM_event_add_mousemove(struct bContext *C); bool WM_event_is_modal_tweak_exit(const struct wmEvent *event, int tweak_event); -bool WM_event_is_absolute(const struct wmEvent *event); bool WM_event_is_last_mousemove(const struct wmEvent *event); #ifdef WITH_INPUT_NDOF @@ -234,11 +233,11 @@ void WM_report_banner_show(void); void WM_report(ReportType type, const char *message); void WM_reportf(ReportType type, const char *format, ...) ATTR_PRINTF_FORMAT(2, 3); -void wm_event_add_ex( +struct wmEvent *wm_event_add_ex( struct wmWindow *win, const struct wmEvent *event_to_add, const struct wmEvent *event_to_add_after) ATTR_NONNULL(1, 2); -void wm_event_add( +struct wmEvent *wm_event_add( struct wmWindow *win, const struct wmEvent *event_to_add) ATTR_NONNULL(1, 2); @@ -258,6 +257,7 @@ void WM_operator_view3d_unit_defaults(struct bContext *C, struct wmOperator *op int WM_operator_smooth_viewtx_get(const struct wmOperator *op); int WM_menu_invoke_ex(struct bContext *C, struct wmOperator *op, int opcontext); int WM_menu_invoke (struct bContext *C, struct wmOperator *op, const struct wmEvent *event); +void WM_menu_name_call(struct bContext *C, const char *menu_name, short context); int WM_enum_search_invoke_previews(struct bContext *C, struct wmOperator *op, short prv_cols, short prv_rows); int WM_enum_search_invoke(struct bContext *C, struct wmOperator *op, const struct wmEvent *event); /* invoke callback, confirm menu + exec */ @@ -541,6 +541,11 @@ void WM_progress_set(struct wmWindow *win, float progress); void WM_progress_clear(struct wmWindow *win); /* Draw (for screenshot) */ +void *WM_draw_cb_activate( + struct wmWindow *win, + void (*draw)(const struct wmWindow *, void *), + void *customdata); +void WM_draw_cb_exit(struct wmWindow *win, void *handle); void WM_redraw_windows(struct bContext *C); void WM_main_playanim(int argc, const char **argv); @@ -573,6 +578,17 @@ void WM_toolsystem_link(struct bContext *C, struct WorkSpace *workspace); void WM_toolsystem_set(struct bContext *C, const struct bToolDef *tool); void WM_toolsystem_init(struct bContext *C); +/* wm_tooltip.c */ +typedef struct ARegion *(*wmTooltipInitFn)(struct bContext *, struct ARegion *, bool *); + +void WM_tooltip_timer_init( + struct bContext *C, struct wmWindow *win, struct ARegion *ar, + wmTooltipInitFn init); +void WM_tooltip_timer_clear(struct bContext *C, struct wmWindow *win); +void WM_tooltip_clear(struct bContext *C, struct wmWindow *win); +void WM_tooltip_init(struct bContext *C, struct wmWindow *win); +void WM_tooltip_refresh(struct bContext *C, struct wmWindow *win); + #ifdef __cplusplus } #endif diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h index 27f872fc2bb..cb90029a5e7 100644 --- a/source/blender/windowmanager/WM_types.h +++ b/source/blender/windowmanager/WM_types.h @@ -474,8 +474,9 @@ typedef struct wmEvent { short keymodifier; /* rawkey modifier */ /* set in case a KM_PRESS went by unhandled */ - short check_click; - + char check_click; + char is_motion_absolute; + /* keymap item, set by handler (weak?) */ const char *keymap_idname; @@ -702,6 +703,23 @@ typedef struct wmDropBox { } wmDropBox; +/** + * Struct to store tool-tip timer and possible creation if the time is reached. + * Allows UI code to call #WM_tooltip_timer_init without each user having to handle the timer. + */ +typedef struct wmTooltipState { + /** Create tooltip on this event. */ + struct wmTimer *timer; + /** The region the tooltip is created in. */ + struct ARegion *region_from; + /** The tooltip region. */ + struct ARegion *region; + /** Create the tooltip region (assign to 'region'). */ + struct ARegion *(*init)(struct bContext *, struct ARegion *, bool *r_exit_on_event); + /** Exit on any event, not needed for buttons since their highlight state is used. */ + bool exit_on_event; +} wmTooltipState; + /* *************** migrated stuff, clean later? ************** */ typedef struct RecentFile { diff --git a/source/blender/windowmanager/intern/wm_cursors.c b/source/blender/windowmanager/intern/wm_cursors.c index d4c3928bd6c..ad5e83ceda7 100644 --- a/source/blender/windowmanager/intern/wm_cursors.c +++ b/source/blender/windowmanager/intern/wm_cursors.c @@ -213,13 +213,10 @@ void WM_cursor_grab_enable(wmWindow *win, bool wrap, bool hide, int bounds[4]) } if ((G.debug & G_DEBUG) == 0) { if (win->ghostwin) { - const GHOST_TabletData *tabletdata = GHOST_GetTabletData(win->ghostwin); - /* Note: There is no tabletdata on Windows if no tablet device is connected. */ - if (!tabletdata) - GHOST_SetCursorGrab(win->ghostwin, mode, bounds, NULL); - else if (tabletdata->Active == GHOST_kTabletModeNone) + if (win->eventstate->is_motion_absolute == false) { GHOST_SetCursorGrab(win->ghostwin, mode, bounds, NULL); + } win->grabcursor = mode; } diff --git a/source/blender/windowmanager/intern/wm_draw.c b/source/blender/windowmanager/intern/wm_draw.c index 5650c16ee0e..30197537e14 100644 --- a/source/blender/windowmanager/intern/wm_draw.c +++ b/source/blender/windowmanager/intern/wm_draw.c @@ -50,6 +50,8 @@ #include "BKE_context.h" #include "BKE_image.h" +#include "BKE_scene.h" +#include "BKE_workspace.h" #include "GHOST_C-api.h" @@ -133,7 +135,8 @@ static bool wm_area_test_invalid_backbuf(ScrArea *sa) return true; } -static void wm_region_test_render_do_draw(const Scene *scene, ScrArea *sa, ARegion *ar) +static void wm_region_test_render_do_draw(const Scene *scene, const struct Depsgraph *depsgraph, + ScrArea *sa, ARegion *ar) { /* tag region for redraw from render engine preview running inside of it */ if (sa->spacetype == SPACE_VIEW3D) { @@ -146,7 +149,7 @@ static void wm_region_test_render_do_draw(const Scene *scene, ScrArea *sa, ARegi rcti border_rect; /* do partial redraw when possible */ - if (ED_view3d_calc_render_border(scene, v3d, ar, &border_rect)) + if (ED_view3d_calc_render_border(scene, depsgraph, v3d, ar, &border_rect)) ED_region_tag_redraw_partial(ar, &border_rect); else ED_region_tag_redraw(ar); @@ -170,6 +173,46 @@ static void wm_draw_region(bContext *C, ARegion *ar) /********************** draw all **************************/ /* - reference method, draw all each time */ +typedef struct WindowDrawCB { + struct WindowDrawCB *next, *prev; + + void(*draw)(const struct wmWindow *, void *); + void *customdata; + +} WindowDrawCB; + +void *WM_draw_cb_activate( + wmWindow *win, + void(*draw)(const struct wmWindow *, void *), + void *customdata) +{ + WindowDrawCB *wdc = MEM_callocN(sizeof(*wdc), "WindowDrawCB"); + + BLI_addtail(&win->drawcalls, wdc); + wdc->draw = draw; + wdc->customdata = customdata; + + return wdc; +} + +void WM_draw_cb_exit(wmWindow *win, void *handle) +{ + for (WindowDrawCB *wdc = win->drawcalls.first; wdc; wdc = wdc->next) { + if (wdc == (WindowDrawCB *)handle) { + BLI_remlink(&win->drawcalls, wdc); + MEM_freeN(wdc); + return; + } + } +} + +static void wm_draw_callbacks(wmWindow *win) +{ + for (WindowDrawCB *wdc = win->drawcalls.first; wdc; wdc = wdc->next) { + wdc->draw(win, wdc->customdata); + } +} + static void wm_method_draw_full(bContext *C, wmWindow *win) { bScreen *screen = WM_window_get_active_screen(win); @@ -193,8 +236,9 @@ static void wm_method_draw_full(bContext *C, wmWindow *win) CTX_wm_area_set(C, NULL); } - ED_screen_draw(win); + ED_screen_draw_edges(win); screen->do_draw = false; + wm_draw_callbacks(win); /* draw overlapping regions */ for (ar = screen->regionbase.first; ar; ar = ar->next) { @@ -330,17 +374,19 @@ static void wm_method_draw_overlap_all(bContext *C, wmWindow *win, int exchange) /* after area regions so we can do area 'overlay' drawing */ if (screen->do_draw) { - ED_screen_draw(win); + ED_screen_draw_edges(win); screen->do_draw = false; + wm_draw_callbacks(win); if (exchange) screen->swap = WIN_FRONT_OK; } else if (exchange) { if (screen->swap == WIN_FRONT_OK) { - ED_screen_draw(win); + ED_screen_draw_edges(win); screen->do_draw = false; screen->swap = WIN_BOTH_OK; + wm_draw_callbacks(win); } else if (screen->swap == WIN_BACK_OK) screen->swap = WIN_FRONT_OK; @@ -626,8 +672,9 @@ static void wm_method_draw_triple(bContext *C, wmWindow *win) } /* after area regions so we can do area 'overlay' drawing */ - ED_screen_draw(win); + ED_screen_draw_edges(win); WM_window_get_active_screen(win)->do_draw = false; + wm_draw_callbacks(win); /* draw floating regions (menus) */ for (ar = screen->regionbase.first; ar; ar = ar->next) { @@ -800,10 +847,12 @@ static void wm_method_draw_triple_multiview(bContext *C, wmWindow *win, eStereoV } /* after area regions so we can do area 'overlay' drawing */ - ED_screen_draw(win); + ED_screen_draw_edges(win); if (sview == STEREO_RIGHT_ID) screen->do_draw = false; + wm_draw_callbacks(win); + /* draw floating regions (menus) */ for (ar = screen->regionbase.first; ar; ar = ar->next) { if (ar->swinid) { @@ -834,7 +883,10 @@ static void wm_method_draw_triple_multiview(bContext *C, wmWindow *win, eStereoV /* quick test to prevent changing window drawable */ static bool wm_draw_update_test_window(wmWindow *win) { - const Scene *scene = WM_window_get_active_scene(win); + /*const*/ struct WorkSpace *workspace = WM_window_get_active_workspace(win); + /*const*/ Scene *scene = WM_window_get_active_scene(win); + /*const*/ ViewLayer *view_layer = BKE_workspace_view_layer_get(workspace, scene); + struct Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer, true); const bScreen *screen = WM_window_get_active_screen(win); ARegion *ar; bool do_draw = false; @@ -850,7 +902,7 @@ static bool wm_draw_update_test_window(wmWindow *win) ED_screen_areas_iter(win, screen, sa) { for (ar = sa->regionbase.first; ar; ar = ar->next) { - wm_region_test_render_do_draw(scene, sa, ar); + wm_region_test_render_do_draw(scene, depsgraph, sa, ar); if (ar->swinid && ar->do_draw) do_draw = true; diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index 02cf9981a3a..e66e7728d31 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -97,7 +97,7 @@ static int wm_operator_call_internal(bContext *C, wmOperatorType *ot, PointerRNA /* ************ event management ************** */ -void wm_event_add_ex(wmWindow *win, const wmEvent *event_to_add, const wmEvent *event_to_add_after) +wmEvent *wm_event_add_ex(wmWindow *win, const wmEvent *event_to_add, const wmEvent *event_to_add_after) { wmEvent *event = MEM_mallocN(sizeof(wmEvent), "wmEvent"); @@ -105,6 +105,13 @@ void wm_event_add_ex(wmWindow *win, const wmEvent *event_to_add, const wmEvent * update_tablet_data(win, event); + if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) { + /* We could have a preference to support relative tablet motion (we can't detect that). */ + event->is_motion_absolute = ( + (event->tablet_data != NULL) && + (event->tablet_data->Active != GHOST_kTabletModeNone)); + } + if (event_to_add_after == NULL) { BLI_addtail(&win->queue, event); } @@ -112,11 +119,12 @@ void wm_event_add_ex(wmWindow *win, const wmEvent *event_to_add, const wmEvent * /* note, strictly speaking this breaks const-correctness, however we're only changing 'next' member */ BLI_insertlinkafter(&win->queue, (void *)event_to_add_after, event); } + return event; } -void wm_event_add(wmWindow *win, const wmEvent *event_to_add) +wmEvent *wm_event_add(wmWindow *win, const wmEvent *event_to_add) { - wm_event_add_ex(win, event_to_add, NULL); + return wm_event_add_ex(win, event_to_add, NULL); } void wm_event_free(wmEvent *event) @@ -695,11 +703,6 @@ void WM_report_banner_show(void) wm_reports->reporttimer->customdata = rti; } -bool WM_event_is_absolute(const wmEvent *event) -{ - return (event->tablet_data != NULL); -} - bool WM_event_is_last_mousemove(const wmEvent *event) { while ((event = event->next)) { @@ -870,14 +873,22 @@ static int wm_operator_exec(bContext *C, wmOperator *op, const bool repeat, cons return retval; if (op->type->exec) { - if (op->type->flag & OPTYPE_UNDO) + if (op->type->flag & OPTYPE_UNDO) { wm->op_undo_depth++; + } + if (repeat) { + op->flag |= OP_IS_REPEAT; + } retval = op->type->exec(C, op); OPERATOR_RETVAL_CHECK(retval); + if (repeat) { + op->flag &= ~OP_IS_REPEAT; + } - if (op->type->flag & OPTYPE_UNDO && CTX_wm_manager(C) == wm) + if (op->type->flag & OPTYPE_UNDO && CTX_wm_manager(C) == wm) { wm->op_undo_depth--; + } } /* XXX Disabled the repeat check to address part 2 of #31840. @@ -1472,6 +1483,19 @@ int WM_operator_name_call(bContext *C, const char *opstring, short context, Poin } /** + * Call an existent menu. The menu can be created in C or Python. + */ +void WM_menu_name_call(bContext *C, const char *menu_name, short context) +{ + wmOperatorType *ot = WM_operatortype_find("WM_OT_call_menu", false); + PointerRNA ptr; + WM_operator_properties_create_ptr(&ptr, ot); + RNA_string_set(&ptr, "name", menu_name); + WM_operator_name_call_ptr(C, ot, context, &ptr); + WM_operator_properties_free(&ptr); +} + +/** * Similar to #WM_operator_name_call called with #WM_OP_EXEC_DEFAULT context. * * - #wmOperatorType is used instead of operator name since python already has the operator type. @@ -2274,8 +2298,10 @@ static int wm_handlers_do_intern(bContext *C, wmEvent *event, ListBase *handlers int part; mpr = wm_manipulatormap_highlight_find(mmap, C, event, &part); wm_manipulatormap_highlight_set(mmap, C, mpr, part); + if (mpr != NULL) { + WM_tooltip_timer_init(C, CTX_wm_window(C), region, WM_manipulatormap_tooltip_init); + } } - /* handle user configurable manipulator-map keymap */ else { /* Either we operate on a single highlighted item * or groups attached to the selected manipulators. @@ -2712,6 +2738,13 @@ void wm_event_do_handlers(bContext *C) CTX_wm_window_set(C, win); + /* Clear tool-tip on mouse move. */ + if (screen->tool_tip && screen->tool_tip->exit_on_event) { + if (ISMOUSE(event->type)) { + WM_tooltip_clear(C, win); + } + } + /* we let modal handlers get active area/region, also wm_paintcursor_test needs it */ CTX_wm_area_set(C, area_event_inside(C, &event->x)); CTX_wm_region_set(C, region_event_inside(C, &event->x)); @@ -2728,7 +2761,16 @@ void wm_event_do_handlers(bContext *C) /* fileread case */ if (CTX_wm_window(C) == NULL) return; - + + /* check for a tooltip */ + if (screen == WM_window_get_active_screen(win)) { + if (screen->tool_tip && screen->tool_tip->timer) { + if ((event->type == TIMER) && (event->customdata == screen->tool_tip->timer)) { + WM_tooltip_init(C, win); + } + } + } + /* check dragging, creates new event or frees, adds draw tag */ wm_event_drag_test(wm, win, event); @@ -3512,7 +3554,7 @@ static bool wm_event_is_double_click(wmEvent *event, const wmEvent *event_state) return false; } -static void wm_event_add_mousemove(wmWindow *win, const wmEvent *event) +static wmEvent *wm_event_add_mousemove(wmWindow *win, const wmEvent *event) { wmEvent *event_last = win->queue.last; @@ -3522,16 +3564,13 @@ static void wm_event_add_mousemove(wmWindow *win, const wmEvent *event) if (event_last && event_last->type == MOUSEMOVE) event_last->type = INBETWEEN_MOUSEMOVE; - wm_event_add(win, event); - - { - wmEvent *event_new = win->queue.last; - if (event_last == NULL) { - event_last = win->eventstate; - } - - copy_v2_v2_int(&event_new->prevx, &event_last->x); + wmEvent *event_new = wm_event_add(win, event); + if (event_last == NULL) { + event_last = win->eventstate; } + + copy_v2_v2_int(&event_new->prevx, &event_last->x); + return event_new; } /* windows store own event queues, no bContext here */ @@ -3561,8 +3600,11 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int U wm_stereo3d_mouse_offset_apply(win, &event.x); event.type = MOUSEMOVE; - wm_event_add_mousemove(win, &event); - copy_v2_v2_int(&evt->x, &event.x); + { + wmEvent *event_new = wm_event_add_mousemove(win, &event); + copy_v2_v2_int(&evt->x, &event_new->x); + evt->is_motion_absolute = event_new->is_motion_absolute; + } /* also add to other window if event is there, this makes overdraws disappear nicely */ /* it remaps mousecoord to other window in event */ @@ -3574,8 +3616,11 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int U copy_v2_v2_int(&oevent.x, &event.x); oevent.type = MOUSEMOVE; - wm_event_add_mousemove(owin, &oevent); - copy_v2_v2_int(&oevt->x, &oevent.x); + { + wmEvent *event_new = wm_event_add_mousemove(owin, &oevent); + copy_v2_v2_int(&oevt->x, &event_new->x); + oevt->is_motion_absolute = event_new->is_motion_absolute; + } } break; diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c index 7c8059fcda9..6a86644da17 100644 --- a/source/blender/windowmanager/intern/wm_files.c +++ b/source/blender/windowmanager/intern/wm_files.c @@ -1043,7 +1043,7 @@ static ImBuf *blend_file_thumb(const bContext *C, Scene *scene, ViewLayer *view_ ibuf = ED_view3d_draw_offscreen_imbuf_simple( &eval_ctx, scene, view_layer, scene->camera, BLEN_THUMB_SIZE * 2, BLEN_THUMB_SIZE * 2, - IB_rect, OB_SOLID, V3D_OFSDRAW_NONE, R_ALPHAPREMUL, 0, NULL, + IB_rect, V3D_OFSDRAW_NONE, OB_SOLID, R_ALPHAPREMUL, 0, NULL, NULL, NULL, err_out); } else { diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c index 96cb11f11ab..8980c4acf26 100644 --- a/source/blender/windowmanager/intern/wm_operators.c +++ b/source/blender/windowmanager/intern/wm_operators.c @@ -1953,7 +1953,7 @@ static uiBlock *wm_block_create_splash(bContext *C, ARegion *ar, void *UNUSED(ar ibuf_template = IMB_loadiffname(splash_filepath, IB_rect, NULL); if (ibuf_template) { const int x_expect = ibuf->x; - const int y_expect = 230 * (int)U.pixelsize; + const int y_expect = 282 * (int)U.pixelsize; /* don't cover the header text */ if (ibuf_template->x == x_expect && ibuf_template->y == y_expect) { memcpy(ibuf->rect, ibuf_template->rect, ibuf_template->x * ibuf_template->y * sizeof(char[4])); diff --git a/source/blender/windowmanager/intern/wm_stereo.c b/source/blender/windowmanager/intern/wm_stereo.c index c0800705b28..84b739a692e 100644 --- a/source/blender/windowmanager/intern/wm_stereo.c +++ b/source/blender/windowmanager/intern/wm_stereo.c @@ -397,7 +397,7 @@ bool WM_stereo3d_enabled(wmWindow *win, bool skip_stereo3d_check) /** * If needed, this adjusts \a r_mouse_xy so that drawn cursor and handled mouse position are matching visually. -*/ + */ void wm_stereo3d_mouse_offset_apply(wmWindow *win, int *r_mouse_xy) { if (!WM_stereo3d_enabled(win, false)) diff --git a/source/blender/windowmanager/intern/wm_tooltip.c b/source/blender/windowmanager/intern/wm_tooltip.c new file mode 100644 index 00000000000..83d620d1522 --- /dev/null +++ b/source/blender/windowmanager/intern/wm_tooltip.c @@ -0,0 +1,106 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/windowmanager/intern/wm_tooltip.c + * \ingroup wm + * + * Manages a per-window tool-tip. + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_utildefines.h" + +#include "BKE_context.h" + +#include "ED_screen.h" + +#include "UI_interface.h" + +#include "WM_api.h" +#include "WM_types.h" + +void WM_tooltip_timer_init( + bContext *C, wmWindow *win, ARegion *ar, + wmTooltipInitFn init) +{ + bScreen *screen = WM_window_get_active_screen(win); + wmWindowManager *wm = CTX_wm_manager(C); + if (screen->tool_tip == NULL) { + screen->tool_tip = MEM_callocN(sizeof(*screen->tool_tip), __func__); + } + screen->tool_tip->region_from = ar; + screen->tool_tip->timer = WM_event_add_timer(wm, win, TIMER, UI_TOOLTIP_DELAY); + screen->tool_tip->init = init; +} + +void WM_tooltip_timer_clear(bContext *C, wmWindow *win) +{ + wmWindowManager *wm = CTX_wm_manager(C); + bScreen *screen = WM_window_get_active_screen(win); + if (screen->tool_tip != NULL) { + if (screen->tool_tip->timer != NULL) { + WM_event_remove_timer(wm, win, screen->tool_tip->timer); + screen->tool_tip->timer = NULL; + } + } +} + +void WM_tooltip_clear(bContext *C, wmWindow *win) +{ + WM_tooltip_timer_clear(C, win); + bScreen *screen = WM_window_get_active_screen(win); + if (screen->tool_tip != NULL) { + if (screen->tool_tip->region) { + UI_tooltip_free(C, screen, screen->tool_tip->region); + screen->tool_tip->region = NULL; + } + MEM_freeN(screen->tool_tip); + screen->tool_tip = NULL; + } +} + +void WM_tooltip_init(bContext *C, wmWindow *win) +{ + WM_tooltip_timer_clear(C, win); + bScreen *screen = WM_window_get_active_screen(win); + if (screen->tool_tip->region) { + UI_tooltip_free(C, screen, screen->tool_tip->region); + screen->tool_tip->region = NULL; + } + screen->tool_tip->region = screen->tool_tip->init( + C, screen->tool_tip->region_from, &screen->tool_tip->exit_on_event); + if (screen->tool_tip->region == NULL) { + WM_tooltip_clear(C, win); + } +} + +void WM_tooltip_refresh(bContext *C, wmWindow *win) +{ + WM_tooltip_timer_clear(C, win); + bScreen *screen = WM_window_get_active_screen(win); + if (screen->tool_tip != NULL) { + if (screen->tool_tip->region) { + UI_tooltip_free(C, screen, screen->tool_tip->region); + screen->tool_tip->region = NULL; + } + WM_tooltip_init(C, win); + } +} diff --git a/source/blender/windowmanager/manipulators/WM_manipulator_api.h b/source/blender/windowmanager/manipulators/WM_manipulator_api.h index 9214bccb6a0..53bee9c6775 100644 --- a/source/blender/windowmanager/manipulators/WM_manipulator_api.h +++ b/source/blender/windowmanager/manipulators/WM_manipulator_api.h @@ -259,6 +259,9 @@ bool WM_manipulatormap_minmax( const struct wmManipulatorMap *mmap, bool use_hidden, bool use_select, float r_min[3], float r_max[3]); +struct ARegion *WM_manipulatormap_tooltip_init( + struct bContext *C, struct ARegion *ar, bool *r_exit_on_event); + /* -------------------------------------------------------------------- */ /* wmManipulatorMapType */ @@ -326,6 +329,6 @@ void WM_manipulator_group_type_unlink_delayed_ptr( void WM_manipulator_group_type_unlink_delayed(const char *idname); /* Utilities */ -void WM_manipulator_group_type_is_any_selected(const char *idname); +bool WM_manipulator_context_check_drawstep(const struct bContext *C, eWM_ManipulatorMapDrawStep step); #endif /* __WM_MANIPULATOR_API_H__ */ diff --git a/source/blender/windowmanager/manipulators/WM_manipulator_types.h b/source/blender/windowmanager/manipulators/WM_manipulator_types.h index 5fa89b8d35f..6d83f411db1 100644 --- a/source/blender/windowmanager/manipulators/WM_manipulator_types.h +++ b/source/blender/windowmanager/manipulators/WM_manipulator_types.h @@ -80,6 +80,10 @@ typedef enum eWM_ManipulatorFlag { * This simply skips scale when calculating the final matrix. * Needed when the manipulator needs to align with the interface underneath it. */ WM_MANIPULATOR_DRAW_NO_SCALE = (1 << 5), + /** + * Hide the cursor and lock it's position while interacting with this manipulator. + */ + WM_MANIPULATOR_GRAB_CURSOR = (1 << 6), } eWM_ManipulatorFlag; /** @@ -178,6 +182,8 @@ struct wmManipulator { /* Optional ID for highlighting different parts of this manipulator. * -1 when unset, otherwise a valid index. (Used as index to 'op_data'). */ int highlight_part; + /* For single click button manipulators, use a different part as a fallback, -1 when unused. */ + int drag_part; /* Transformation of the manipulator in 2d or 3d space. * - Matrix axis are expected to be unit length (scale is applied after). @@ -307,6 +313,9 @@ typedef struct wmManipulatorType { /* called when manipulator selection state changes */ wmManipulatorFnSelectRefresh select_refresh; + /* Free data (not the manipulator it's self), use when the manipulator allocates it's own members. */ + wmManipulatorFnFree free; + /* RNA for properties */ struct StructRNA *srna; diff --git a/source/blender/windowmanager/manipulators/intern/wm_manipulator.c b/source/blender/windowmanager/manipulators/intern/wm_manipulator.c index 7ca1f8fd5f2..3a78dd32f94 100644 --- a/source/blender/windowmanager/manipulators/intern/wm_manipulator.c +++ b/source/blender/windowmanager/manipulators/intern/wm_manipulator.c @@ -98,6 +98,8 @@ static wmManipulator *wm_manipulator_create( unit_m4(mpr->matrix_basis); unit_m4(mpr->matrix_offset); + mpr->drag_part = -1; + return mpr; } @@ -164,6 +166,10 @@ static void wm_manipulator_register(wmManipulatorGroup *mgroup, wmManipulator *m */ void WM_manipulator_free(wmManipulator *mpr) { + if (mpr->type->free != NULL) { + mpr->type->free(mpr); + } + #ifdef WITH_PYTHON if (mpr->py_instance) { /* do this first in case there are any __del__ functions or @@ -729,3 +735,28 @@ void WM_manipulator_properties_free(PointerRNA *ptr) } /** \} */ + +/** \name General Utilities + * + * \{ */ + +bool WM_manipulator_context_check_drawstep(const struct bContext *C, eWM_ManipulatorMapDrawStep step) +{ + switch (step) { + case WM_MANIPULATORMAP_DRAWSTEP_2D: + { + break; + } + case WM_MANIPULATORMAP_DRAWSTEP_3D: + { + wmWindowManager *wm = CTX_wm_manager(C); + if (ED_screen_animation_playing(wm)) { + return false; + } + break; + } + } + return true; +} + +/** \} */ diff --git a/source/blender/windowmanager/manipulators/intern/wm_manipulator_group.c b/source/blender/windowmanager/manipulators/intern/wm_manipulator_group.c index d62aac8cd87..0e63f3d6ffe 100644 --- a/source/blender/windowmanager/manipulators/intern/wm_manipulator_group.c +++ b/source/blender/windowmanager/manipulators/intern/wm_manipulator_group.c @@ -39,6 +39,7 @@ #include "BLI_listbase.h" #include "BLI_string.h" +#include "BLI_math.h" #include "BKE_context.h" #include "BKE_main.h" @@ -61,6 +62,10 @@ # include "BPY_extern.h" #endif +/* Allow manipulator part's to be single click only, + * dragging falls back to activating their 'drag_part' action. */ +#define USE_DRAG_DETECT + /* -------------------------------------------------------------------- */ /** \name wmManipulatorGroup * @@ -140,7 +145,7 @@ void wm_manipulatorgroup_manipulator_register(wmManipulatorGroup *mgroup, wmMani mpr->parent_mgroup = mgroup; } -wmManipulator *wm_manipulatorgroup_find_intersected_mainpulator( +wmManipulator *wm_manipulatorgroup_find_intersected_manipulator( const wmManipulatorGroup *mgroup, bContext *C, const wmEvent *event, int *r_part) { @@ -303,19 +308,81 @@ void MANIPULATORGROUP_OT_manipulator_select(wmOperatorType *ot) typedef struct ManipulatorTweakData { wmManipulatorMap *mmap; + wmManipulatorGroup *mgroup; wmManipulator *mpr_modal; int init_event; /* initial event type */ int flag; /* tweak flags */ + +#ifdef USE_DRAG_DETECT + /* True until the mouse is moved (only use when the operator has no modal). + * this allows some manipulators to be click-only. */ + enum { + /* Don't detect dragging. */ + DRAG_NOP = 0, + /* Detect dragging (wait until a drag or click is detected). */ + DRAG_DETECT, + /* Drag has started, idle until there is no active modal operator. + * This is needed because finishing the modal operator also exits + * the modal manipulator state (un-grabbs the cursor). + * Ideally this workaround could be removed later. */ + DRAG_IDLE, + } drag_state; +#endif + } ManipulatorTweakData; -static void manipulator_tweak_finish(bContext *C, wmOperator *op, const bool cancel) +static bool manipulator_tweak_start( + bContext *C, wmManipulatorMap *mmap, wmManipulator *mpr, const wmEvent *event) +{ + /* activate highlighted manipulator */ + wm_manipulatormap_modal_set(mmap, C, mpr, event, true); + + return (mpr->state & WM_MANIPULATOR_STATE_MODAL); +} + +static bool manipulator_tweak_start_and_finish( + bContext *C, wmManipulatorMap *mmap, wmManipulator *mpr, const wmEvent *event, bool *r_is_modal) +{ + wmManipulatorOpElem *mpop = WM_manipulator_operator_get(mpr, mpr->highlight_part); + if (r_is_modal) { + *r_is_modal = false; + } + if (mpop && mpop->type) { + /* XXX temporary workaround for modal manipulator operator + * conflicting with modal operator attached to manipulator */ + if (mpop->type->modal) { + /* activate highlighted manipulator */ + wm_manipulatormap_modal_set(mmap, C, mpr, event, true); + if (r_is_modal) { + *r_is_modal = true; + } + } + else { + /* Allow for 'button' manipulators, single click to run an action. */ + WM_operator_name_call_ptr(C, mpop->type, WM_OP_INVOKE_DEFAULT, &mpop->ptr); + } + return true; + } + else { + return false; + } +} + +static void manipulator_tweak_finish(bContext *C, wmOperator *op, const bool cancel, bool clear_modal) { ManipulatorTweakData *mtweak = op->customdata; if (mtweak->mpr_modal->type->exit) { mtweak->mpr_modal->type->exit(C, mtweak->mpr_modal, cancel); } - wm_manipulatormap_modal_set(mtweak->mmap, C, mtweak->mpr_modal, NULL, false); + if (clear_modal) { + /* The manipulator may have been removed. */ + if ((BLI_findindex(&mtweak->mmap->groups, mtweak->mgroup) != -1) && + (BLI_findindex(&mtweak->mgroup->manipulators, mtweak->mpr_modal) != -1)) + { + wm_manipulatormap_modal_set(mtweak->mmap, C, mtweak->mpr_modal, NULL, false); + } + } MEM_freeN(mtweak); } @@ -323,27 +390,68 @@ static int manipulator_tweak_modal(bContext *C, wmOperator *op, const wmEvent *e { ManipulatorTweakData *mtweak = op->customdata; wmManipulator *mpr = mtweak->mpr_modal; + int retval = OPERATOR_PASS_THROUGH; + bool clear_modal = true; if (mpr == NULL) { BLI_assert(0); return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH); } - if (event->type == mtweak->init_event && event->val == KM_RELEASE) { - manipulator_tweak_finish(C, op, false); - return OPERATOR_FINISHED; - } +#ifdef USE_DRAG_DETECT + wmManipulatorMap *mmap = mtweak->mmap; + if (mtweak->drag_state == DRAG_DETECT) { + if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) { + if (len_manhattan_v2v2_int(&event->x, mmap->mmap_context.event_xy) > 2) { + mtweak->drag_state = DRAG_IDLE; + mpr->highlight_part = mpr->drag_part; + } + } + else if (event->type == mtweak->init_event && event->val == KM_RELEASE) { + mtweak->drag_state = DRAG_NOP; + retval = OPERATOR_FINISHED; + } + if (mtweak->drag_state != DRAG_DETECT) { + /* Follow logic in 'manipulator_tweak_invoke' */ + bool is_modal = false; + if (manipulator_tweak_start_and_finish(C, mmap, mpr, event, &is_modal)) { + if (is_modal) { + clear_modal = false; + } + } + else { + if (!manipulator_tweak_start(C, mmap, mpr, event)) { + retval = OPERATOR_FINISHED; + } + } + } + } + if (mtweak->drag_state == DRAG_IDLE) { + if (mmap->mmap_context.modal != NULL) { + return OPERATOR_PASS_THROUGH; + } + else { + manipulator_tweak_finish(C, op, false, false); + return OPERATOR_FINISHED; + } + } +#endif /* USE_DRAG_DETECT */ - if (event->type == EVT_MODAL_MAP) { + if (retval == OPERATOR_FINISHED) { + /* pass */ + } + else if (event->type == mtweak->init_event && event->val == KM_RELEASE) { + retval = OPERATOR_FINISHED; + } + else if (event->type == EVT_MODAL_MAP) { switch (event->val) { case TWEAK_MODAL_CANCEL: - manipulator_tweak_finish(C, op, true); - return OPERATOR_CANCELLED; + retval = OPERATOR_CANCELLED; + break; case TWEAK_MODAL_CONFIRM: - manipulator_tweak_finish(C, op, false); - return OPERATOR_FINISHED; - + retval = OPERATOR_FINISHED; + break; case TWEAK_MODAL_PRECISION_ON: mtweak->flag |= WM_MANIPULATOR_TWEAK_PRECISE; break; @@ -360,20 +468,28 @@ static int manipulator_tweak_modal(bContext *C, wmOperator *op, const wmEvent *e } } + if (retval != OPERATOR_PASS_THROUGH) { + manipulator_tweak_finish(C, op, retval != OPERATOR_FINISHED, clear_modal); + return retval; + } + /* handle manipulator */ wmManipulatorFnModal modal_fn = mpr->custom_modal ? mpr->custom_modal : mpr->type->modal; - int retval = modal_fn(C, mpr, event, mtweak->flag); + if (modal_fn) { + int modal_retval = modal_fn(C, mpr, event, mtweak->flag); - if ((retval & OPERATOR_RUNNING_MODAL) == 0) { - manipulator_tweak_finish(C, op, (retval & OPERATOR_CANCELLED) != 0); - return OPERATOR_FINISHED; - } + if ((modal_retval & OPERATOR_RUNNING_MODAL) == 0) { + manipulator_tweak_finish(C, op, (modal_retval & OPERATOR_CANCELLED) != 0, true); + return OPERATOR_FINISHED; + } - /* Ugly hack to send manipulator events */ - ((wmEvent *)event)->type = EVT_MANIPULATOR_UPDATE; + /* Ugly hack to send manipulator events */ + ((wmEvent *)event)->type = EVT_MANIPULATOR_UPDATE; + } /* always return PASS_THROUGH so modal handlers * with manipulators attached can update */ + BLI_assert(retval == OPERATOR_PASS_THROUGH); return OPERATOR_PASS_THROUGH; } @@ -383,37 +499,58 @@ static int manipulator_tweak_invoke(bContext *C, wmOperator *op, const wmEvent * wmManipulatorMap *mmap = ar->manipulator_map; wmManipulator *mpr = mmap->mmap_context.highlight; + /* Needed for single click actions which don't enter modal state. */ + WM_tooltip_clear(C, CTX_wm_window(C)); + if (!mpr) { /* wm_handlers_do_intern shouldn't let this happen */ BLI_assert(0); return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH); } + bool use_drag_fallback = false; - /* activate highlighted manipulator */ - wm_manipulatormap_modal_set(mmap, C, mpr, event, true); +#ifdef USE_DRAG_DETECT + use_drag_fallback = !ELEM(mpr->drag_part, -1, mpr->highlight_part); +#endif - /* XXX temporary workaround for modal manipulator operator - * conflicting with modal operator attached to manipulator */ - wmManipulatorOpElem *mpop = WM_manipulator_operator_get(mpr, mpr->highlight_part); - if (mpop && mpop->type) { - if (mpop->type->modal) { + if (use_drag_fallback == false) { + if (manipulator_tweak_start_and_finish(C, mmap, mpr, event, NULL)) { return OPERATOR_FINISHED; } } - /* Couldn't start the manipulator. */ - if ((mpr->state & WM_MANIPULATOR_STATE_MODAL) == 0) { - return OPERATOR_PASS_THROUGH; + bool use_drag_detect = false; +#ifdef USE_DRAG_DETECT + if (use_drag_fallback) { + wmManipulatorOpElem *mpop = WM_manipulator_operator_get(mpr, mpr->highlight_part); + if (mpop && mpop->type) { + if (mpop->type->modal == NULL) { + use_drag_detect = true; + } + } + } +#endif + + if (use_drag_detect == false) { + if (!manipulator_tweak_start(C, mmap, mpr, event)) { + /* failed to start */ + return OPERATOR_PASS_THROUGH; + } } ManipulatorTweakData *mtweak = MEM_mallocN(sizeof(ManipulatorTweakData), __func__); mtweak->init_event = WM_userdef_event_type_from_keymap_type(event->type); mtweak->mpr_modal = mmap->mmap_context.highlight; + mtweak->mgroup = mtweak->mpr_modal->parent_mgroup; mtweak->mmap = mmap; mtweak->flag = 0; +#ifdef USE_DRAG_DETECT + mtweak->drag_state = use_drag_detect ? DRAG_DETECT : DRAG_NOP; +#endif + op->customdata = mtweak; WM_event_add_modal_handler(C, op); diff --git a/source/blender/windowmanager/manipulators/intern/wm_manipulator_intern.h b/source/blender/windowmanager/manipulators/intern/wm_manipulator_intern.h index bf5c38b9e39..b7982cf00df 100644 --- a/source/blender/windowmanager/manipulators/intern/wm_manipulator_intern.h +++ b/source/blender/windowmanager/manipulators/intern/wm_manipulator_intern.h @@ -69,7 +69,7 @@ struct wmManipulatorGroup *wm_manipulatorgroup_new_from_type( struct wmManipulatorMap *mmap, struct wmManipulatorGroupType *wgt); void wm_manipulatorgroup_free(bContext *C, struct wmManipulatorGroup *mgroup); void wm_manipulatorgroup_manipulator_register(struct wmManipulatorGroup *mgroup, struct wmManipulator *mpr); -struct wmManipulator *wm_manipulatorgroup_find_intersected_mainpulator( +struct wmManipulator *wm_manipulatorgroup_find_intersected_manipulator( const struct wmManipulatorGroup *mgroup, struct bContext *C, const struct wmEvent *event, int *r_part); void wm_manipulatorgroup_intersectable_manipulators_to_list( @@ -112,6 +112,9 @@ struct wmManipulatorMap { struct wmManipulator *modal; /* array for all selected manipulators */ struct wmManipulatorMapSelectState select; + /* cursor location at point of entering modal (see: WM_MANIPULATOR_GRAB_CURSOR) */ + int event_xy[2]; + short event_grabcursor; } mmap_context; }; diff --git a/source/blender/windowmanager/manipulators/intern/wm_manipulator_map.c b/source/blender/windowmanager/manipulators/intern/wm_manipulator_map.c index 5d9810272cc..a9875020fbb 100644 --- a/source/blender/windowmanager/manipulators/intern/wm_manipulator_map.c +++ b/source/blender/windowmanager/manipulators/intern/wm_manipulator_map.c @@ -51,6 +51,9 @@ #include "WM_types.h" #include "wm_event_system.h" +/* for tool-tips */ +#include "UI_interface.h" + #include "DEG_depsgraph.h" /* own includes */ @@ -442,6 +445,10 @@ void WM_manipulatormap_draw( wmManipulatorMap *mmap, const bContext *C, const eWM_ManipulatorMapDrawStep drawstep) { + if (!WM_manipulator_context_check_drawstep(C, drawstep)) { + return; + } + ListBase draw_manipulators = {NULL}; manipulatormap_prepare_drawing(mmap, C, &draw_manipulators, drawstep); @@ -547,6 +554,7 @@ static wmManipulator *manipulator_find_intersected_3d( }; *r_part = 0; + /* set up view matrices */ view3d_operator_needs_opengl(C); @@ -585,6 +593,11 @@ wmManipulator *wm_manipulatormap_highlight_find( { wmManipulator *mpr = NULL; ListBase visible_3d_manipulators = {NULL}; + bool do_step[WM_MANIPULATORMAP_DRAWSTEP_MAX]; + + for (int i = 0; i < ARRAY_SIZE(do_step); i++) { + do_step[i] = WM_manipulator_context_check_drawstep(C, i); + } for (wmManipulatorGroup *mgroup = mmap->groups.first; mgroup; mgroup = mgroup->next) { @@ -596,25 +609,28 @@ wmManipulator *wm_manipulatormap_highlight_find( } if (wm_manipulatorgroup_is_visible(mgroup, C)) { + eWM_ManipulatorMapDrawStep step; if (mgroup->type->flag & WM_MANIPULATORGROUPTYPE_3D) { - if ((mmap->update_flag[WM_MANIPULATORMAP_DRAWSTEP_3D] & MANIPULATORMAP_IS_REFRESH_CALLBACK) && - mgroup->type->refresh) - { - mgroup->type->refresh(C, mgroup); - /* cleared below */ - } - wm_manipulatorgroup_intersectable_manipulators_to_list(mgroup, &visible_3d_manipulators); + step = WM_MANIPULATORMAP_DRAWSTEP_3D; } else { - if ((mmap->update_flag[WM_MANIPULATORMAP_DRAWSTEP_2D] & MANIPULATORMAP_IS_REFRESH_CALLBACK) && - mgroup->type->refresh) + step = WM_MANIPULATORMAP_DRAWSTEP_2D; + } + + if (do_step[step]) { + if ((mmap->update_flag[step] & MANIPULATORMAP_IS_REFRESH_CALLBACK) && + (mgroup->type->refresh != NULL)) { mgroup->type->refresh(C, mgroup); /* cleared below */ } - - if ((mpr = wm_manipulatorgroup_find_intersected_mainpulator(mgroup, C, event, r_part))) { - break; + if (step == WM_MANIPULATORMAP_DRAWSTEP_3D) { + wm_manipulatorgroup_intersectable_manipulators_to_list(mgroup, &visible_3d_manipulators); + } + else if (step == WM_MANIPULATORMAP_DRAWSTEP_2D) { + if ((mpr = wm_manipulatorgroup_find_intersected_manipulator(mgroup, C, event, r_part))) { + break; + } } } } @@ -886,27 +902,39 @@ void wm_manipulatormap_modal_set( { if (enable) { BLI_assert(mmap->mmap_context.modal == NULL); + wmWindow *win = CTX_wm_window(C); - /* For now only grab cursor for 3D manipulators. */ - bool grab_cursor = (mpr->parent_mgroup->type->flag & WM_MANIPULATORGROUPTYPE_3D) != 0; - int retval = OPERATOR_RUNNING_MODAL; + WM_tooltip_clear(C, win); if (mpr->type->invoke && (mpr->type->modal || mpr->custom_modal)) { - retval = mpr->type->invoke(C, mpr, event); - } - - if ((retval & OPERATOR_RUNNING_MODAL) == 0) { - return; + const int retval = mpr->type->invoke(C, mpr, event); + if ((retval & OPERATOR_RUNNING_MODAL) == 0) { + return; + } } mpr->state |= WM_MANIPULATOR_STATE_MODAL; mmap->mmap_context.modal = mpr; + if ((mpr->flag & WM_MANIPULATOR_GRAB_CURSOR) && + (event->is_motion_absolute == false)) + { + WM_cursor_grab_enable(win, true, true, NULL); + copy_v2_v2_int(mmap->mmap_context.event_xy, &event->x); + mmap->mmap_context.event_grabcursor = win->grabcursor; + } + else { + mmap->mmap_context.event_xy[0] = INT_MAX; + } + struct wmManipulatorOpElem *mpop = WM_manipulator_operator_get(mpr, mpr->highlight_part); if (mpop && mpop->type) { - WM_operator_name_call_ptr(C, mpop->type, WM_OP_INVOKE_DEFAULT, &mpop->ptr); + const int retval = WM_operator_name_call_ptr(C, mpop->type, WM_OP_INVOKE_DEFAULT, &mpop->ptr); + if ((retval & OPERATOR_RUNNING_MODAL) == 0) { + wm_manipulatormap_modal_set(mmap, C, mpr, event, false); + } /* we failed to hook the manipulator to the operator handler or operator was cancelled, return */ if (!mmap->mmap_context.modal) { @@ -915,10 +943,6 @@ void wm_manipulatormap_modal_set( } return; } - - if (grab_cursor) { - WM_cursor_grab_enable(CTX_wm_window(C), true, true, NULL); - } } else { BLI_assert(ELEM(mmap->mmap_context.modal, NULL, mpr)); @@ -931,10 +955,23 @@ void wm_manipulatormap_modal_set( mmap->mmap_context.modal = NULL; if (C) { - WM_cursor_grab_disable(CTX_wm_window(C), NULL); + wmWindow *win = CTX_wm_window(C); + if (mmap->mmap_context.event_xy[0] != INT_MAX) { + /* Check if some other part of Blender (typically operators) + * have adjusted the grab mode since it was set. + * If so: warp, so we have a predictable outcome. */ + if (mmap->mmap_context.event_grabcursor == win->grabcursor) { + WM_cursor_grab_disable(win, mmap->mmap_context.event_xy); + } + else { + WM_cursor_warp(win, UNPACK2(mmap->mmap_context.event_xy)); + } + } ED_region_tag_redraw(CTX_wm_region(C)); WM_event_add_mousemove(C); } + + mmap->mmap_context.event_xy[0] = INT_MAX; } } @@ -977,6 +1014,27 @@ void WM_manipulatormap_message_subscribe( /* -------------------------------------------------------------------- */ +/** \name Tooltip Handling + * + * \{ */ + +struct ARegion *WM_manipulatormap_tooltip_init( + struct bContext *C, struct ARegion *ar, bool *r_exit_on_event) +{ + wmManipulatorMap *mmap = ar->manipulator_map; + *r_exit_on_event = true; + if (mmap) { + wmManipulator *mpr = mmap->mmap_context.highlight; + if (mpr) { + return UI_tooltip_create_from_manipulator(C, mpr); + } + } + return NULL; +} + +/** \} */ /* wmManipulatorMapType */ + +/* -------------------------------------------------------------------- */ /** \name wmManipulatorMapType * * \{ */ diff --git a/source/blender/windowmanager/manipulators/wm_manipulator_fn.h b/source/blender/windowmanager/manipulators/wm_manipulator_fn.h index 7e163f8a785..305d04eab68 100644 --- a/source/blender/windowmanager/manipulators/wm_manipulator_fn.h +++ b/source/blender/windowmanager/manipulators/wm_manipulator_fn.h @@ -59,6 +59,7 @@ typedef int (*wmManipulatorFnInvoke)(struct bContext *, struct wmManipulator typedef void (*wmManipulatorFnExit)(struct bContext *, struct wmManipulator *, const bool); typedef int (*wmManipulatorFnCursorGet)(struct wmManipulator *); typedef void (*wmManipulatorFnSelectRefresh)(struct wmManipulator *); +typedef void (*wmManipulatorFnFree)(struct wmManipulator *); /* wmManipulatorProperty ('value' type defined by 'wmManipulatorProperty.data_type') */ typedef void (*wmManipulatorPropertyFnGet)( |