diff options
82 files changed, 1445 insertions, 1940 deletions
diff --git a/extern/mantaflow/CMakeLists.txt b/extern/mantaflow/CMakeLists.txt index bbf75039782..9f66b42c6bf 100644 --- a/extern/mantaflow/CMakeLists.txt +++ b/extern/mantaflow/CMakeLists.txt @@ -35,15 +35,28 @@ set(MANTAVERSION "0.13") add_definitions(-DWITH_FLUID=1) -set(MANTA_DEP - dependencies -) +# Compile Mantaflow dependencies too (e.g. cnpy for numpy file IO). +# Make sure that dependencies exist before enabling this option by updating the source files in extern/ +set(WITH_MANTA_DEPENDENCIES 0) + +# Enable Mantaflow numpy support +set(WITH_MANTA_NUMPY 0) + +if(NOT WITH_MANTA_DEPENDENCIES) + add_definitions(-DNO_CNPY=1) +endif() + set(MANTA_HLP helper ) set(MANTA_PP preprocessed ) +if(WITH_MANTA_DEPENDENCIES) + set(MANTA_DEP + dependencies + ) +endif() if(WITH_TBB) add_definitions(-DTBB=1) @@ -62,6 +75,10 @@ if(WIN32) add_definitions(-D_USE_MATH_DEFINES) endif() +if(WITH_MANTA_NUMPY AND WITH_PYTHON_INSTALL_NUMPY) + add_definitions(-DNUMPY=1) +endif() + set(INC ${MANTA_PP} ${MANTA_PP}/fileio @@ -69,14 +86,25 @@ set(INC ${MANTA_PP}/plugin ${MANTA_HLP}/pwrapper ${MANTA_HLP}/util - ${MANTA_DEP}/cnpy ) +if(WITH_MANTA_DEPENDENCIES) + list(APPEND INC + ${MANTA_DEP}/cnpy + ) +endif() + set(INC_SYS ${PYTHON_INCLUDE_DIRS} ${ZLIB_INCLUDE_DIRS} ) +if(WITH_MANTA_NUMPY AND WITH_PYTHON_INSTALL_NUMPY) + list(APPEND INC_SYS + ${PYTHON_NUMPY_INCLUDE_DIRS} + ) +endif() + if(WITH_TBB) list(APPEND INC_SYS ${TBB_INCLUDE_DIRS} @@ -96,9 +124,6 @@ if(WITH_OPENVDB) endif() set(SRC - ${MANTA_DEP}/cnpy/cnpy.cpp - ${MANTA_DEP}/cnpy/cnpy.h - ${MANTA_PP}/commonkernels.h ${MANTA_PP}/commonkernels.h.reg.cpp ${MANTA_PP}/conjugategrad.cpp @@ -161,14 +186,10 @@ set(SRC ${MANTA_PP}/plugin/initplugins.cpp ${MANTA_PP}/plugin/kepsilon.cpp ${MANTA_PP}/plugin/meshplugins.cpp -# TODO (sebbas): add numpy to libraries -# ${MANTA_PP}/plugin/numpyconvert.cpp ${MANTA_PP}/plugin/pressure.cpp ${MANTA_PP}/plugin/ptsplugins.cpp ${MANTA_PP}/plugin/secondaryparticles.cpp ${MANTA_PP}/plugin/surfaceturbulence.cpp -# TODO (sebbas): add numpy to libraries -# ${MANTA_PP}/plugin/tfplugins.cpp ${MANTA_PP}/plugin/vortexplugins.cpp ${MANTA_PP}/plugin/waveletturbulence.cpp ${MANTA_PP}/plugin/waves.cpp @@ -193,9 +214,6 @@ set(SRC ${MANTA_PP}/vortexsheet.h.reg.cpp ${MANTA_HLP}/pwrapper/manta.h -# TODO (sebbas): add numpy to libraries -# ${MANTA_HLP}/pwrapper/numpyWrap.cpp -# ${MANTA_HLP}/pwrapper/numpyWrap.h ${MANTA_HLP}/pwrapper/pclass.cpp ${MANTA_HLP}/pwrapper/pclass.h ${MANTA_HLP}/pwrapper/pconvert.cpp @@ -221,6 +239,22 @@ set(SRC ${MANTA_HLP}/util/vectorbase.h ) +if(WITH_MANTA_DEPENDENCIES) + list(APPEND SRC + ${MANTA_DEP}/cnpy/cnpy.cpp + ${MANTA_DEP}/cnpy/cnpy.h + ) +endif() + +if(WITH_MANTA_NUMPY AND WITH_PYTHON_INSTALL_NUMPY) + list(APPEND SRC + ${MANTA_PP}/plugin/numpyconvert.cpp + ${MANTA_PP}/plugin/tfplugins.cpp + ${MANTA_HLP}/pwrapper/numpyWrap.cpp + ${MANTA_HLP}/pwrapper/numpyWrap.h + ) +endif() + set(LIB ${PYTHON_LINKFLAGS} ${PYTHON_LIBRARIES} diff --git a/extern/mantaflow/UPDATE.sh b/extern/mantaflow/UPDATE.sh index 3feb1ba9226..aed4e2a9b71 100644 --- a/extern/mantaflow/UPDATE.sh +++ b/extern/mantaflow/UPDATE.sh @@ -13,6 +13,12 @@ BLENDER_INSTALLATION=/Users/sebbas/Developer/Blender/fluid-mantaflow # Try to check out Mantaflow repository before building? CLEAN_REPOSITORY=0 +# Skip copying dependency files? +WITH_DEPENDENCIES=0 + +# Build with numpy support? +USE_NUMPY=0 + # Choose which multithreading platform to use for Mantaflow preprocessing USE_OMP=0 USE_TBB=1 @@ -50,17 +56,21 @@ fi MANTA_BUILD_PATH=$MANTA_INSTALLATION/build_blender/ mkdir -p $MANTA_BUILD_PATH cd $MANTA_BUILD_PATH -cmake ../mantaflowgit -DGUI=OFF -DOPENMP=$USE_OMP -DTBB=$USE_TBB -DBLENDER=ON -DPREPDEBUG=ON && make -j8 +cmake ../mantaflowgit -DGUI=0 -DOPENMP=$USE_OMP -DTBB=$USE_TBB -DBLENDER=1 -DPREPDEBUG=1 -DNUMPY=$USE_NUMPY && make -j8 # ==================== 3) COPY MANTAFLOW FILES TO BLENDER ROOT =========================== -mkdir -p $BLENDER_INSTALLATION/blender/tmp/dependencies/ && cp -Rf $MANTA_INSTALLATION/mantaflowgit/dependencies/cnpy "$_" +if [[ "$WITH_DEPENDENCIES" -eq "1" ]]; then + mkdir -p $BLENDER_INSTALLATION/blender/tmp/dependencies/ && cp -Rf $MANTA_INSTALLATION/mantaflowgit/dependencies/cnpy "$_" +fi mkdir -p $BLENDER_INSTALLATION/blender/tmp/helper/ && cp -Rf $MANTA_INSTALLATION/mantaflowgit/source/util "$_" mkdir -p $BLENDER_INSTALLATION/blender/tmp/helper/ && cp -Rf $MANTA_INSTALLATION/mantaflowgit/source/pwrapper "$_" mkdir -p $BLENDER_INSTALLATION/blender/tmp/preprocessed/ && cp -Rf $MANTA_INSTALLATION/build_blender/pp/source/. "$_" # Remove some files that are not need in Blender -rm $BLENDER_INSTALLATION/blender/tmp/dependencies/cnpy/example1.cpp +if [[ "$WITH_DEPENDENCIES" -eq "1" ]]; then + rm $BLENDER_INSTALLATION/blender/tmp/dependencies/cnpy/example1.cpp +fi rm $BLENDER_INSTALLATION/blender/tmp/helper/pwrapper/pymain.cpp rm $BLENDER_INSTALLATION/blender/tmp/preprocessed/*.reg rm $BLENDER_INSTALLATION/blender/tmp/preprocessed/python/*.reg @@ -82,8 +92,13 @@ BLENDER_TMP_DEP=$BLENDER_TMP/dependencies BLENDER_TMP_HLP=$BLENDER_TMP/helper BLENDER_TMP_PP=$BLENDER_TMP/preprocessed +# Before moving new files, delete all existing file in the Blender repository +rm -Rf $BLENDER_MANTA_EXTERN/dependencies $BLENDER_MANTA_EXTERN/helper $BLENDER_MANTA_EXTERN/preprocessed + # Move files from tmp dir to extern/ -cp -Rf $BLENDER_TMP_DEP $BLENDER_MANTA_EXTERN +if [[ "$WITH_DEPENDENCIES" -eq "1" ]]; then + cp -Rf $BLENDER_TMP_DEP $BLENDER_MANTA_EXTERN +fi cp -Rf $BLENDER_TMP_HLP $BLENDER_MANTA_EXTERN cp -Rf $BLENDER_TMP_PP $BLENDER_MANTA_EXTERN diff --git a/extern/mantaflow/dependencies/cnpy/LICENSE b/extern/mantaflow/dependencies/cnpy/LICENSE deleted file mode 100644 index e60eadbccb3..00000000000 --- a/extern/mantaflow/dependencies/cnpy/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License - -Copyright (c) Carl Rogers, 2011 - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/extern/mantaflow/dependencies/cnpy/cnpy.cpp b/extern/mantaflow/dependencies/cnpy/cnpy.cpp deleted file mode 100644 index 7f0ce21ece8..00000000000 --- a/extern/mantaflow/dependencies/cnpy/cnpy.cpp +++ /dev/null @@ -1,385 +0,0 @@ -// Copyright (C) 2011 Carl Rogers -// Released under MIT License -// license available in LICENSE file, or at http://www.opensource.org/licenses/mit-license.php - -#include "cnpy.h" -#include <complex> -#include <cstdlib> -#include <algorithm> -#include <cstring> -#include <iomanip> -#include <stdint.h> -#include <stdexcept> -#include <regex> - -char cnpy::BigEndianTest() -{ - int x = 1; - return (((char *)&x)[0]) ? '<' : '>'; -} - -char cnpy::map_type(const std::type_info &t) -{ - if (t == typeid(float)) - return 'f'; - if (t == typeid(double)) - return 'f'; - if (t == typeid(long double)) - return 'f'; - - if (t == typeid(int)) - return 'i'; - if (t == typeid(char)) - return 'i'; - if (t == typeid(short)) - return 'i'; - if (t == typeid(long)) - return 'i'; - if (t == typeid(long long)) - return 'i'; - - if (t == typeid(unsigned char)) - return 'u'; - if (t == typeid(unsigned short)) - return 'u'; - if (t == typeid(unsigned long)) - return 'u'; - if (t == typeid(unsigned long long)) - return 'u'; - if (t == typeid(unsigned int)) - return 'u'; - - if (t == typeid(bool)) - return 'b'; - - if (t == typeid(std::complex<float>)) - return 'c'; - if (t == typeid(std::complex<double>)) - return 'c'; - if (t == typeid(std::complex<long double>)) - return 'c'; - - else - return '?'; -} - -template<> std::vector<char> &cnpy::operator+=(std::vector<char> &lhs, const std::string rhs) -{ - lhs.insert(lhs.end(), rhs.begin(), rhs.end()); - return lhs; -} - -template<> std::vector<char> &cnpy::operator+=(std::vector<char> &lhs, const char *rhs) -{ - // write in little endian - size_t len = strlen(rhs); - lhs.reserve(len); - for (size_t byte = 0; byte < len; byte++) { - lhs.push_back(rhs[byte]); - } - return lhs; -} - -void cnpy::parse_npy_header(unsigned char *buffer, - size_t &word_size, - std::vector<size_t> &shape, - bool &fortran_order) -{ - // std::string magic_string(buffer,6); - uint8_t major_version = *reinterpret_cast<uint8_t *>(buffer + 6); - uint8_t minor_version = *reinterpret_cast<uint8_t *>(buffer + 7); - uint16_t header_len = *reinterpret_cast<uint16_t *>(buffer + 8); - std::string header(reinterpret_cast<char *>(buffer + 9), header_len); - - size_t loc1, loc2; - - // fortran order - loc1 = header.find("fortran_order") + 16; - fortran_order = (header.substr(loc1, 4) == "True" ? true : false); - - // shape - loc1 = header.find("("); - loc2 = header.find(")"); - - std::regex num_regex("[0-9][0-9]*"); - std::smatch sm; - shape.clear(); - - std::string str_shape = header.substr(loc1 + 1, loc2 - loc1 - 1); - while (std::regex_search(str_shape, sm, num_regex)) { - shape.push_back(std::stoi(sm[0].str())); - str_shape = sm.suffix().str(); - } - - // endian, word size, data type - // byte order code | stands for not applicable. - // not sure when this applies except for byte array - loc1 = header.find("descr") + 9; - bool littleEndian = (header[loc1] == '<' || header[loc1] == '|' ? true : false); - assert(littleEndian); - - // char type = header[loc1+1]; - // assert(type == map_type(T)); - - std::string str_ws = header.substr(loc1 + 2); - loc2 = str_ws.find("'"); - word_size = atoi(str_ws.substr(0, loc2).c_str()); -} - -void cnpy::parse_npy_header(FILE *fp, - size_t &word_size, - std::vector<size_t> &shape, - bool &fortran_order) -{ - char buffer[256]; - size_t res = fread(buffer, sizeof(char), 11, fp); - if (res != 11) - throw std::runtime_error("parse_npy_header: failed fread"); - std::string header = fgets(buffer, 256, fp); - assert(header[header.size() - 1] == '\n'); - - size_t loc1, loc2; - - // fortran order - loc1 = header.find("fortran_order"); - if (loc1 == std::string::npos) - throw std::runtime_error("parse_npy_header: failed to find header keyword: 'fortran_order'"); - loc1 += 16; - fortran_order = (header.substr(loc1, 4) == "True" ? true : false); - - // shape - loc1 = header.find("("); - loc2 = header.find(")"); - if (loc1 == std::string::npos || loc2 == std::string::npos) - throw std::runtime_error("parse_npy_header: failed to find header keyword: '(' or ')'"); - - std::regex num_regex("[0-9][0-9]*"); - std::smatch sm; - shape.clear(); - - std::string str_shape = header.substr(loc1 + 1, loc2 - loc1 - 1); - while (std::regex_search(str_shape, sm, num_regex)) { - shape.push_back(std::stoi(sm[0].str())); - str_shape = sm.suffix().str(); - } - - // endian, word size, data type - // byte order code | stands for not applicable. - // not sure when this applies except for byte array - loc1 = header.find("descr"); - if (loc1 == std::string::npos) - throw std::runtime_error("parse_npy_header: failed to find header keyword: 'descr'"); - loc1 += 9; - bool littleEndian = (header[loc1] == '<' || header[loc1] == '|' ? true : false); - assert(littleEndian); - - // char type = header[loc1+1]; - // assert(type == map_type(T)); - - std::string str_ws = header.substr(loc1 + 2); - loc2 = str_ws.find("'"); - word_size = atoi(str_ws.substr(0, loc2).c_str()); -} - -void cnpy::parse_zip_footer(FILE *fp, - uint16_t &nrecs, - size_t &global_header_size, - size_t &global_header_offset) -{ - std::vector<char> footer(22); - fseek(fp, -22, SEEK_END); - size_t res = fread(&footer[0], sizeof(char), 22, fp); - if (res != 22) - throw std::runtime_error("parse_zip_footer: failed fread"); - - uint16_t disk_no, disk_start, nrecs_on_disk, comment_len; - disk_no = *(uint16_t *)&footer[4]; - disk_start = *(uint16_t *)&footer[6]; - nrecs_on_disk = *(uint16_t *)&footer[8]; - nrecs = *(uint16_t *)&footer[10]; - global_header_size = *(uint32_t *)&footer[12]; - global_header_offset = *(uint32_t *)&footer[16]; - comment_len = *(uint16_t *)&footer[20]; - - assert(disk_no == 0); - assert(disk_start == 0); - assert(nrecs_on_disk == nrecs); - assert(comment_len == 0); -} - -cnpy::NpyArray load_the_npy_file(FILE *fp) -{ - std::vector<size_t> shape; - size_t word_size; - bool fortran_order; - cnpy::parse_npy_header(fp, word_size, shape, fortran_order); - - cnpy::NpyArray arr(shape, word_size, fortran_order); - size_t nread = fread(arr.data<char>(), 1, arr.num_bytes(), fp); - if (nread != arr.num_bytes()) - throw std::runtime_error("load_the_npy_file: failed fread"); - return arr; -} - -cnpy::NpyArray load_the_npz_array(FILE *fp, uint32_t compr_bytes, uint32_t uncompr_bytes) -{ - - std::vector<unsigned char> buffer_compr(compr_bytes); - std::vector<unsigned char> buffer_uncompr(uncompr_bytes); - size_t nread = fread(&buffer_compr[0], 1, compr_bytes, fp); - if (nread != compr_bytes) - throw std::runtime_error("load_the_npy_file: failed fread"); - - int err; - z_stream d_stream; - - d_stream.zalloc = Z_NULL; - d_stream.zfree = Z_NULL; - d_stream.opaque = Z_NULL; - d_stream.avail_in = 0; - d_stream.next_in = Z_NULL; - err = inflateInit2(&d_stream, -MAX_WBITS); - - d_stream.avail_in = compr_bytes; - d_stream.next_in = &buffer_compr[0]; - d_stream.avail_out = uncompr_bytes; - d_stream.next_out = &buffer_uncompr[0]; - - err = inflate(&d_stream, Z_FINISH); - err = inflateEnd(&d_stream); - - std::vector<size_t> shape; - size_t word_size; - bool fortran_order; - cnpy::parse_npy_header(&buffer_uncompr[0], word_size, shape, fortran_order); - - cnpy::NpyArray array(shape, word_size, fortran_order); - - size_t offset = uncompr_bytes - array.num_bytes(); - memcpy(array.data<unsigned char>(), &buffer_uncompr[0] + offset, array.num_bytes()); - - return array; -} - -cnpy::npz_t cnpy::npz_load(std::string fname) -{ - FILE *fp = fopen(fname.c_str(), "rb"); - - if (!fp) { - throw std::runtime_error("npz_load: Error! Unable to open file " + fname + "!"); - } - - cnpy::npz_t arrays; - - while (1) { - std::vector<char> local_header(30); - size_t headerres = fread(&local_header[0], sizeof(char), 30, fp); - if (headerres != 30) - throw std::runtime_error("npz_load: failed fread"); - - // if we've reached the global header, stop reading - if (local_header[2] != 0x03 || local_header[3] != 0x04) - break; - - // read in the variable name - uint16_t name_len = *(uint16_t *)&local_header[26]; - std::string varname(name_len, ' '); - size_t vname_res = fread(&varname[0], sizeof(char), name_len, fp); - if (vname_res != name_len) - throw std::runtime_error("npz_load: failed fread"); - - // erase the lagging .npy - varname.erase(varname.end() - 4, varname.end()); - - // read in the extra field - uint16_t extra_field_len = *(uint16_t *)&local_header[28]; - if (extra_field_len > 0) { - std::vector<char> buff(extra_field_len); - size_t efield_res = fread(&buff[0], sizeof(char), extra_field_len, fp); - if (efield_res != extra_field_len) - throw std::runtime_error("npz_load: failed fread"); - } - - uint16_t compr_method = *reinterpret_cast<uint16_t *>(&local_header[0] + 8); - uint32_t compr_bytes = *reinterpret_cast<uint32_t *>(&local_header[0] + 18); - uint32_t uncompr_bytes = *reinterpret_cast<uint32_t *>(&local_header[0] + 22); - - if (compr_method == 0) { - arrays[varname] = load_the_npy_file(fp); - } - else { - arrays[varname] = load_the_npz_array(fp, compr_bytes, uncompr_bytes); - } - } - - fclose(fp); - return arrays; -} - -cnpy::NpyArray cnpy::npz_load(std::string fname, std::string varname) -{ - FILE *fp = fopen(fname.c_str(), "rb"); - - if (!fp) - throw std::runtime_error("npz_load: Unable to open file " + fname); - - while (1) { - std::vector<char> local_header(30); - size_t header_res = fread(&local_header[0], sizeof(char), 30, fp); - if (header_res != 30) - throw std::runtime_error("npz_load: failed fread"); - - // if we've reached the global header, stop reading - if (local_header[2] != 0x03 || local_header[3] != 0x04) - break; - - // read in the variable name - uint16_t name_len = *(uint16_t *)&local_header[26]; - std::string vname(name_len, ' '); - size_t vname_res = fread(&vname[0], sizeof(char), name_len, fp); - if (vname_res != name_len) - throw std::runtime_error("npz_load: failed fread"); - vname.erase(vname.end() - 4, vname.end()); // erase the lagging .npy - - // read in the extra field - uint16_t extra_field_len = *(uint16_t *)&local_header[28]; - fseek(fp, extra_field_len, SEEK_CUR); // skip past the extra field - - uint16_t compr_method = *reinterpret_cast<uint16_t *>(&local_header[0] + 8); - uint32_t compr_bytes = *reinterpret_cast<uint32_t *>(&local_header[0] + 18); - uint32_t uncompr_bytes = *reinterpret_cast<uint32_t *>(&local_header[0] + 22); - - if (vname == varname) { - NpyArray array = (compr_method == 0) ? load_the_npy_file(fp) : - load_the_npz_array(fp, compr_bytes, uncompr_bytes); - fclose(fp); - return array; - } - else { - // skip past the data - // uint32_t size = *(uint32_t*) &local_header[22]; - uint32_t size = *(uint32_t *)&local_header[18]; // using index 18 instead of 22 enables - // support for compressed data - fseek(fp, size, SEEK_CUR); - } - } - - fclose(fp); - - // if we get here, we haven't found the variable in the file - throw std::runtime_error("npz_load: Variable name " + varname + " not found in " + fname); -} - -cnpy::NpyArray cnpy::npy_load(std::string fname) -{ - - FILE *fp = fopen(fname.c_str(), "rb"); - - if (!fp) - throw std::runtime_error("npy_load: Unable to open file " + fname); - - NpyArray arr = load_the_npy_file(fp); - - fclose(fp); - return arr; -} diff --git a/extern/mantaflow/dependencies/cnpy/cnpy.h b/extern/mantaflow/dependencies/cnpy/cnpy.h deleted file mode 100644 index e4b6365cb6f..00000000000 --- a/extern/mantaflow/dependencies/cnpy/cnpy.h +++ /dev/null @@ -1,310 +0,0 @@ -// Copyright (C) 2011 Carl Rogers -// Released under MIT License -// license available in LICENSE file, or at http://www.opensource.org/licenses/mit-license.php - -#ifndef LIBCNPY_H_ -#define LIBCNPY_H_ - -#include <string> -#include <stdexcept> -#include <sstream> -#include <vector> -#include <cstdio> -#include <typeinfo> -#include <iostream> -#include <cassert> -#include <zlib.h> -#include <map> -#include <memory> -#include <stdint.h> -#include <numeric> - -namespace cnpy { - -struct NpyArray { - NpyArray(const std::vector<size_t> &_shape, size_t _word_size, bool _fortran_order) - : shape(_shape), word_size(_word_size), fortran_order(_fortran_order) - { - num_vals = 1; - for (size_t i = 0; i < shape.size(); i++) - num_vals *= shape[i]; - data_holder = std::shared_ptr<std::vector<char>>(new std::vector<char>(num_vals * word_size)); - } - - NpyArray() : shape(0), word_size(0), fortran_order(0), num_vals(0) - { - } - - template<typename T> T *data() - { - return reinterpret_cast<T *>(&(*data_holder)[0]); - } - - template<typename T> const T *data() const - { - return reinterpret_cast<T *>(&(*data_holder)[0]); - } - - template<typename T> std::vector<T> as_vec() const - { - const T *p = data<T>(); - return std::vector<T>(p, p + num_vals); - } - - size_t num_bytes() const - { - return data_holder->size(); - } - - std::shared_ptr<std::vector<char>> data_holder; - std::vector<size_t> shape; - size_t word_size; - bool fortran_order; - size_t num_vals; -}; - -using npz_t = std::map<std::string, NpyArray>; - -char BigEndianTest(); -char map_type(const std::type_info &t); -template<typename T> std::vector<char> create_npy_header(const std::vector<size_t> &shape); -void parse_npy_header(FILE *fp, - size_t &word_size, - std::vector<size_t> &shape, - bool &fortran_order); -void parse_npy_header(unsigned char *buffer, - size_t &word_size, - std::vector<size_t> &shape, - bool &fortran_order); -void parse_zip_footer(FILE *fp, - uint16_t &nrecs, - size_t &global_header_size, - size_t &global_header_offset); -npz_t npz_load(std::string fname); -NpyArray npz_load(std::string fname, std::string varname); -NpyArray npy_load(std::string fname); - -template<typename T> std::vector<char> &operator+=(std::vector<char> &lhs, const T rhs) -{ - // write in little endian - for (size_t byte = 0; byte < sizeof(T); byte++) { - char val = *((char *)&rhs + byte); - lhs.push_back(val); - } - return lhs; -} - -template<> std::vector<char> &operator+=(std::vector<char> &lhs, const std::string rhs); -template<> std::vector<char> &operator+=(std::vector<char> &lhs, const char *rhs); - -template<typename T> -void npy_save(std::string fname, - const T *data, - const std::vector<size_t> shape, - std::string mode = "w") -{ - FILE *fp = NULL; - std::vector<size_t> true_data_shape; // if appending, the shape of existing + new data - - if (mode == "a") - fp = fopen(fname.c_str(), "r+b"); - - if (fp) { - // file exists. we need to append to it. read the header, modify the array size - size_t word_size; - bool fortran_order; - parse_npy_header(fp, word_size, true_data_shape, fortran_order); - assert(!fortran_order); - - if (word_size != sizeof(T)) { - std::cout << "libnpy error: " << fname << " has word size " << word_size - << " but npy_save appending data sized " << sizeof(T) << "\n"; - assert(word_size == sizeof(T)); - } - if (true_data_shape.size() != shape.size()) { - std::cout << "libnpy error: npy_save attempting to append misdimensioned data to " << fname - << "\n"; - assert(true_data_shape.size() != shape.size()); - } - - for (size_t i = 1; i < shape.size(); i++) { - if (shape[i] != true_data_shape[i]) { - std::cout << "libnpy error: npy_save attempting to append misshaped data to " << fname - << "\n"; - assert(shape[i] == true_data_shape[i]); - } - } - true_data_shape[0] += shape[0]; - } - else { - fp = fopen(fname.c_str(), "wb"); - true_data_shape = shape; - } - - std::vector<char> header = create_npy_header<T>(true_data_shape); - size_t nels = std::accumulate(shape.begin(), shape.end(), 1, std::multiplies<size_t>()); - - fseek(fp, 0, SEEK_SET); - fwrite(&header[0], sizeof(char), header.size(), fp); - fseek(fp, 0, SEEK_END); - fwrite(data, sizeof(T), nels, fp); - fclose(fp); -} - -template<typename T> -void npz_save(std::string zipname, - std::string fname, - const T *data, - const std::vector<size_t> &shape, - std::string mode = "w") -{ - // first, append a .npy to the fname - fname += ".npy"; - - // now, on with the show - FILE *fp = NULL; - uint16_t nrecs = 0; - size_t global_header_offset = 0; - std::vector<char> global_header; - - if (mode == "a") - fp = fopen(zipname.c_str(), "r+b"); - - if (fp) { - // zip file exists. we need to add a new npy file to it. - // first read the footer. this gives us the offset and size of the global header - // then read and store the global header. - // below, we will write the the new data at the start of the global header then append the - // global header and footer below it - size_t global_header_size; - parse_zip_footer(fp, nrecs, global_header_size, global_header_offset); - fseek(fp, global_header_offset, SEEK_SET); - global_header.resize(global_header_size); - size_t res = fread(&global_header[0], sizeof(char), global_header_size, fp); - if (res != global_header_size) { - throw std::runtime_error("npz_save: header read error while adding to existing zip"); - } - fseek(fp, global_header_offset, SEEK_SET); - } - else { - fp = fopen(zipname.c_str(), "wb"); - } - - std::vector<char> npy_header = create_npy_header<T>(shape); - - size_t nels = std::accumulate(shape.begin(), shape.end(), 1, std::multiplies<size_t>()); - size_t nbytes = nels * sizeof(T) + npy_header.size(); - - // get the CRC of the data to be added - uint32_t crc = crc32(0L, (uint8_t *)&npy_header[0], npy_header.size()); - crc = crc32(crc, (uint8_t *)data, nels * sizeof(T)); - - // build the local header - std::vector<char> local_header; - local_header += "PK"; // first part of sig - local_header += (uint16_t)0x0403; // second part of sig - local_header += (uint16_t)20; // min version to extract - local_header += (uint16_t)0; // general purpose bit flag - local_header += (uint16_t)0; // compression method - local_header += (uint16_t)0; // file last mod time - local_header += (uint16_t)0; // file last mod date - local_header += (uint32_t)crc; // crc - local_header += (uint32_t)nbytes; // compressed size - local_header += (uint32_t)nbytes; // uncompressed size - local_header += (uint16_t)fname.size(); // fname length - local_header += (uint16_t)0; // extra field length - local_header += fname; - - // build global header - global_header += "PK"; // first part of sig - global_header += (uint16_t)0x0201; // second part of sig - global_header += (uint16_t)20; // version made by - global_header.insert(global_header.end(), local_header.begin() + 4, local_header.begin() + 30); - global_header += (uint16_t)0; // file comment length - global_header += (uint16_t)0; // disk number where file starts - global_header += (uint16_t)0; // internal file attributes - global_header += (uint32_t)0; // external file attributes - global_header += (uint32_t) - global_header_offset; // relative offset of local file header, since it begins where the - // global header used to begin - global_header += fname; - - // build footer - std::vector<char> footer; - footer += "PK"; // first part of sig - footer += (uint16_t)0x0605; // second part of sig - footer += (uint16_t)0; // number of this disk - footer += (uint16_t)0; // disk where footer starts - footer += (uint16_t)(nrecs + 1); // number of records on this disk - footer += (uint16_t)(nrecs + 1); // total number of records - footer += (uint32_t)global_header.size(); // nbytes of global headers - footer += (uint32_t)(global_header_offset + nbytes + - local_header.size()); // offset of start of global headers, since global - // header now starts after newly written array - footer += (uint16_t)0; // zip file comment length - - // write everything - fwrite(&local_header[0], sizeof(char), local_header.size(), fp); - fwrite(&npy_header[0], sizeof(char), npy_header.size(), fp); - fwrite(data, sizeof(T), nels, fp); - fwrite(&global_header[0], sizeof(char), global_header.size(), fp); - fwrite(&footer[0], sizeof(char), footer.size(), fp); - fclose(fp); -} - -template<typename T> -void npy_save(std::string fname, const std::vector<T> data, std::string mode = "w") -{ - std::vector<size_t> shape; - shape.push_back(data.size()); - npy_save(fname, &data[0], shape, mode); -} - -template<typename T> -void npz_save(std::string zipname, - std::string fname, - const std::vector<T> data, - std::string mode = "w") -{ - std::vector<size_t> shape; - shape.push_back(data.size()); - npz_save(zipname, fname, &data[0], shape, mode); -} - -template<typename T> std::vector<char> create_npy_header(const std::vector<size_t> &shape) -{ - - std::vector<char> dict; - dict += "{'descr': '"; - dict += BigEndianTest(); - dict += map_type(typeid(T)); - dict += std::to_string(sizeof(T)); - dict += "', 'fortran_order': False, 'shape': ("; - dict += std::to_string(shape[0]); - for (size_t i = 1; i < shape.size(); i++) { - dict += ", "; - dict += std::to_string(shape[i]); - } - if (shape.size() == 1) - dict += ","; - dict += "), }"; - // pad with spaces so that preamble+dict is modulo 16 bytes. preamble is 10 bytes. dict needs to - // end with \n - int remainder = 16 - (10 + dict.size()) % 16; - dict.insert(dict.end(), remainder, ' '); - dict.back() = '\n'; - - std::vector<char> header; - header += (char)0x93; - header += "NUMPY"; - header += (char)0x01; // major version of numpy format - header += (char)0x00; // minor version of numpy format - header += (uint16_t)dict.size(); - header.insert(header.end(), dict.begin(), dict.end()); - - return header; -} - -} // namespace cnpy - -#endif diff --git a/extern/mantaflow/preprocessed/fileio/iogrids.cpp b/extern/mantaflow/preprocessed/fileio/iogrids.cpp index e2550d6db8b..825ce0ae8b5 100644 --- a/extern/mantaflow/preprocessed/fileio/iogrids.cpp +++ b/extern/mantaflow/preprocessed/fileio/iogrids.cpp @@ -27,7 +27,10 @@ extern "C" { } #endif -#include "cnpy.h" +#if NO_CNPY != 1 +# include "cnpy.h" +#endif + #include "mantaio.h" #include "grid.h" #include "vector4d.h" @@ -965,12 +968,16 @@ int readGrid4dUni( }; void readGrid4dUniCleanup(void **fileHandle) { +#if NO_ZLIB != 1 gzFile gzf = NULL; if (fileHandle) { gzf = (gzFile)(*fileHandle); gzclose(gzf); *fileHandle = NULL; } +#else + debMsg("file format not supported without zlib", 1); +#endif } template<class T> int writeGrid4dRaw(const string &name, Grid4d<T> *grid) @@ -1021,15 +1028,13 @@ template<class T> int readGrid4dRaw(const string &name, Grid4d<T> *grid) template<class T> int writeGridNumpy(const string &name, Grid<T> *grid) { -#if NO_ZLIB == 1 - debMsg("file format not supported without zlib", 1); - return 0; -#endif + #if FLOATINGPOINT_PRECISION != 1 errMsg("writeGridNumpy: Double precision not yet supported"); return 0; #endif +#if NO_CNPY != 1 // find suffix to differentiate between npy <-> npz , TODO: check for actual "npy" string std::string::size_type idx; bool bUseNpz = false; @@ -1075,19 +1080,21 @@ template<class T> int writeGridNumpy(const string &name, Grid<T> *grid) cnpy::npy_save(name, &grid[0], shape, "w"); } return 1; -}; +#else + debMsg("file format not supported without cnpy", 1); + return 0; +#endif +} template<class T> int readGridNumpy(const string &name, Grid<T> *grid) { -#if NO_ZLIB == 1 - debMsg("file format not supported without zlib", 1); - return 0; -#endif + #if FLOATINGPOINT_PRECISION != 1 errMsg("readGridNumpy: Double precision not yet supported"); return 0; #endif +#if NO_CNPY != 1 // find suffix to differentiate between npy <-> npz std::string::size_type idx; bool bUseNpz = false; @@ -1144,7 +1151,11 @@ template<class T> int readGridNumpy(const string &name, Grid<T> *grid) gridArr.data<T>(), sizeof(T) * grid->getSizeX() * grid->getSizeY() * grid->getSizeZ()); return 1; -}; +#else + debMsg("file format not supported without cnpy", 1); + return 0; +#endif +} int writeGridsNumpy(const string &name, std::vector<PbClass *> *grids) { @@ -1163,13 +1174,12 @@ void getNpzFileSize( const string &name, int &x, int &y, int &z, int *t = NULL, std::string *info = NULL) { x = y = z = 0; -#if NO_ZLIB != 1 - debMsg("file format not supported without zlib", 1); - return; -#endif + #if FLOATINGPOINT_PRECISION != 1 errMsg("getNpzFileSize: Double precision not yet supported"); #endif + +#if NO_CNPY != 1 // find suffix to differentiate between npy <-> npz cnpy::NpyArray gridArr; cnpy::npz_t fNpz = cnpy::npz_load(name); @@ -1180,6 +1190,9 @@ void getNpzFileSize( x = gridArr.shape[2]; if (t) (*t) = 0; // unused for now +#else + debMsg("file format not supported without cnpy", 1); +#endif } Vec3 getNpzFileSize(const string &name) { diff --git a/extern/mantaflow/preprocessed/fileio/ioutil.cpp b/extern/mantaflow/preprocessed/fileio/ioutil.cpp index cc63cf87ac1..cf40d71fcc4 100644 --- a/extern/mantaflow/preprocessed/fileio/ioutil.cpp +++ b/extern/mantaflow/preprocessed/fileio/ioutil.cpp @@ -26,17 +26,18 @@ extern "C" { # include <zlib.h> } +#endif -# if defined(WIN32) || defined(_WIN32) -# include <windows.h> -# include <string> -# endif +#if defined(WIN32) || defined(_WIN32) +# include <windows.h> +# include <string> +#endif using namespace std; namespace Manta { -# if defined(WIN32) || defined(_WIN32) +#if defined(WIN32) || defined(_WIN32) static wstring stringToWstring(const char *str) { const int length_wc = MultiByteToWideChar(CP_UTF8, 0, str, strlen(str), NULL, 0); @@ -44,10 +45,11 @@ static wstring stringToWstring(const char *str) MultiByteToWideChar(CP_UTF8, 0, str, strlen(str), &strWide[0], length_wc); return strWide; } -# endif // WIN32==1 +#endif // WIN32==1 void *safeGzopen(const char *filename, const char *mode) { +#if NO_ZLIB != 1 gzFile gzfile; # if defined(WIN32) || defined(_WIN32) @@ -58,8 +60,11 @@ void *safeGzopen(const char *filename, const char *mode) # endif return gzfile; -} +#else + debMsg("safeGzopen not supported without zlib", 1); + return nullptr; #endif // NO_ZLIB != 1 +} #if defined(OPENVDB) // Convert from OpenVDB value to Manta value. @@ -109,4 +114,4 @@ template<> void convertTo(openvdb::Vec3s *out, Vec3 &in) } #endif // OPENVDB==1 -} // namespace +} // namespace Manta diff --git a/extern/mantaflow/preprocessed/gitinfo.h b/extern/mantaflow/preprocessed/gitinfo.h index 67cede606da..5763d31f7fb 100644 --- a/extern/mantaflow/preprocessed/gitinfo.h +++ b/extern/mantaflow/preprocessed/gitinfo.h @@ -1,3 +1,3 @@ -#define MANTA_GIT_VERSION "commit 1881a368ed10797e84b470645d7c738ef75ad6d8" +#define MANTA_GIT_VERSION "commit 78ecf1940765e45d8fc15b3304a622785a84939e" diff --git a/extern/mantaflow/preprocessed/mesh.cpp b/extern/mantaflow/preprocessed/mesh.cpp index c99d621d2bd..7a27b88ece7 100644 --- a/extern/mantaflow/preprocessed/mesh.cpp +++ b/extern/mantaflow/preprocessed/mesh.cpp @@ -1371,11 +1371,11 @@ void Mesh::updateDataFields() for (size_t i = 0; i < mNodes.size(); ++i) { Vec3 pos = mNodes[i].pos; for (IndexInt md = 0; md < (IndexInt)mMdataReal.size(); ++md) - mMdataReal[md]->initNewValue(i, mNodes[i].pos); + mMdataReal[md]->initNewValue(i, pos); for (IndexInt md = 0; md < (IndexInt)mMdataVec3.size(); ++md) - mMdataVec3[md]->initNewValue(i, mNodes[i].pos); + mMdataVec3[md]->initNewValue(i, pos); for (IndexInt md = 0; md < (IndexInt)mMdataInt.size(); ++md) - mMdataInt[md]->initNewValue(i, mNodes[i].pos); + mMdataInt[md]->initNewValue(i, pos); } } diff --git a/release/scripts/modules/addon_utils.py b/release/scripts/modules/addon_utils.py index 8a074d23db9..af6d4b1cd29 100644 --- a/release/scripts/modules/addon_utils.py +++ b/release/scripts/modules/addon_utils.py @@ -367,7 +367,7 @@ def enable(module_name, *, default_set=False, persistent=False, handle_error=Non if mod.bl_info.get("blender", (0, 0, 0)) < (2, 80, 0): if _bpy.app.debug: - print(f"Warning: Add-on '{module_name:s}' was not upgraded for 2.80, ignoring") + print("Warning: Add-on '%s' was not upgraded for 2.80, ignoring" % module_name) return None # 2) Try register collected modules. diff --git a/release/scripts/modules/bpy/utils/__init__.py b/release/scripts/modules/bpy/utils/__init__.py index 19450bb38ec..8a67a598ccd 100644 --- a/release/scripts/modules/bpy/utils/__init__.py +++ b/release/scripts/modules/bpy/utils/__init__.py @@ -789,7 +789,7 @@ def register_tool(tool_cls, *, after=None, separator=False, group=False): cls = ToolSelectPanelHelper._tool_class_from_space_type(space_type) if cls is None: - raise Exception(f"Space type {space_type!r} has no toolbar") + raise Exception("Space type %r has no toolbar" % space_type) tools = cls._tools[context_mode] # First sanity check @@ -799,9 +799,9 @@ def register_tool(tool_cls, *, after=None, separator=False, group=False): if item is not None } if not issubclass(tool_cls, WorkSpaceTool): - raise Exception(f"Expected WorkSpaceTool subclass, not {type(tool_cls)!r}") + raise Exception("Expected WorkSpaceTool subclass, not %r" % type(tool_cls)) if tool_cls.bl_idname in tools_id: - raise Exception(f"Tool {tool_cls.bl_idname!r} already exists!") + raise Exception("Tool %r already exists!" % tool_cls.bl_idname) del tools_id, WorkSpaceTool # Convert the class into a ToolDef. @@ -900,7 +900,7 @@ def unregister_tool(tool_cls): from bl_ui.space_toolsystem_common import ToolSelectPanelHelper cls = ToolSelectPanelHelper._tool_class_from_space_type(space_type) if cls is None: - raise Exception(f"Space type {space_type!r} has no toolbar") + raise Exception("Space type %r has no toolbar" % space_type) tools = cls._tools[context_mode] tool_def = tool_cls._bl_tool @@ -952,7 +952,7 @@ def unregister_tool(tool_cls): break if not changed: - raise Exception(f"Unable to remove {tool_cls!r}") + raise Exception("Unable to remove %r" % tool_cls) del tool_cls._bl_tool keymap_data = tool_def.keymap @@ -963,7 +963,7 @@ def unregister_tool(tool_cls): for kc in (keyconfigs.default, keyconfigs.addon): km = kc.keymaps.get(keymap_data[0]) if km is None: - print(f"Warning keymap {keymap_data[0]!r} not found in {kc.name!r}!") + print("Warning keymap %r not found in %r!" % (keymap_data[0], kc.name)) else: kc.keymaps.remove(km) diff --git a/release/scripts/modules/bpy/utils/previews.py b/release/scripts/modules/bpy/utils/previews.py index 7f337677635..511df853d66 100644 --- a/release/scripts/modules/bpy/utils/previews.py +++ b/release/scripts/modules/bpy/utils/previews.py @@ -85,7 +85,7 @@ class ImagePreviewCollection(dict): def new(self, name): if name in self: - raise KeyError(f"key {name!r} already exists") + raise KeyError("key %r already exists" % name) p = self[name] = _utils_previews.new( self._gen_key(name)) return p @@ -93,7 +93,7 @@ class ImagePreviewCollection(dict): def load(self, name, path, path_type, force_reload=False): if name in self: - raise KeyError(f"key {name!r} already exists") + raise KeyError("key %r already exists" % name) p = self[name] = _utils_previews.load( self._gen_key(name), path, path_type, force_reload) return p diff --git a/release/scripts/presets/keyconfig/keymap_data/blender_default.py b/release/scripts/presets/keyconfig/keymap_data/blender_default.py index 8a9d3052a2e..b8f6ca0a5a0 100644 --- a/release/scripts/presets/keyconfig/keymap_data/blender_default.py +++ b/release/scripts/presets/keyconfig/keymap_data/blender_default.py @@ -749,6 +749,9 @@ def km_property_editor(_params): # ShaderFX panels ("object.shaderfx_remove", {"type": 'X', "value": 'PRESS'}, {"properties": [("report", True)]}), ("object.shaderfx_remove", {"type": 'DEL', "value": 'PRESS'}, {"properties": [("report", True)]}), + # Constraint panels + ("constraint.delete", {"type": 'X', "value": 'PRESS'}, {"properties": [("report", True)]}), + ("constraint.delete", {"type": 'DEL', "value": 'PRESS'}, {"properties": [("report", True)]}), ]) return keymap diff --git a/release/scripts/startup/bl_operators/screen_play_rendered_anim.py b/release/scripts/startup/bl_operators/screen_play_rendered_anim.py index 255852d3b26..6c29c07c62e 100644 --- a/release/scripts/startup/bl_operators/screen_play_rendered_anim.py +++ b/release/scripts/startup/bl_operators/screen_play_rendered_anim.py @@ -143,10 +143,10 @@ class PlayRenderedAnim(Operator): ] cmd.extend(opts) elif preset == 'FRAMECYCLER': - opts = [file, f"{scene.frame_start:d}-{scene.frame_end:d}"] + opts = [file, "%d-%d" % (scene.frame_start, scene.frame_end)] cmd.extend(opts) elif preset == 'RV': - opts = ["-fps", str(rd.fps), "-play", f"[ {file:s} ]"] + opts = ["-fps", str(rd.fps), "-play", "[ %s ]" % file] cmd.extend(opts) elif preset == 'MPLAYER': opts = [] @@ -156,7 +156,7 @@ class PlayRenderedAnim(Operator): opts += [ ("mf://" + file.replace("#", "?")), "-mf", - f"fps={fps_final:4f}" + "fps=%.4f" % fps_final, ] opts += ["-loop", "0", "-really-quiet", "-fs"] diff --git a/release/scripts/startup/bl_ui/space_clip.py b/release/scripts/startup/bl_ui/space_clip.py index 032a4a612c8..43883ff0f3a 100644 --- a/release/scripts/startup/bl_ui/space_clip.py +++ b/release/scripts/startup/bl_ui/space_clip.py @@ -1238,7 +1238,7 @@ class CLIP_MT_view_zoom(Menu): layout.operator( "clip.view_zoom_ratio", - text=iface_(f"Zoom {a:d}:{b:d}"), + text=iface_("Zoom %d:%d") % (a, b), translate=False, ).ratio = a / b diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py index 5392ed9cc25..66c98b81e0e 100644 --- a/release/scripts/startup/bl_ui/space_userpref.py +++ b/release/scripts/startup/bl_ui/space_userpref.py @@ -994,7 +994,7 @@ class USERPREF_PT_theme_bone_color_sets(ThemePanel, CenterAlignMixIn, Panel): layout.use_property_split = True for i, ui in enumerate(theme.bone_color_sets, 1): - layout.label(text=iface_(f"Color Set {i:d}"), translate=False) + layout.label(text=iface_("Color Set %d") % i, translate=False) flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False) diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py index fe80a0c1c36..749e92bdcf7 100644 --- a/release/scripts/startup/bl_ui/space_view3d.py +++ b/release/scripts/startup/bl_ui/space_view3d.py @@ -1100,7 +1100,7 @@ class VIEW3D_MT_mirror(Menu): for (space_name, space_id) in (("Global", 'GLOBAL'), ("Local", 'LOCAL')): for axis_index, axis_name in enumerate("XYZ"): - props = layout.operator("transform.mirror", text=f"{axis_name!s} {space_name!s}") + props = layout.operator("transform.mirror", text="%s %s" % (axis_name, space_name)) props.constraint_axis[axis_index] = True props.orient_type = space_id diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index acd4c75befd..1d01436c7e4 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -106,18 +106,18 @@ typedef struct bNodeSocketTemplate { * However, achieving this requires quite a few changes currently. */ #ifdef __cplusplus namespace blender { -namespace bke { +namespace nodes { class SocketMFNetworkBuilder; class NodeMFNetworkBuilder; -} // namespace bke +} // namespace nodes namespace fn { class MFDataType; } } // namespace blender -using NodeExpandInMFNetworkFunction = void (*)(blender::bke::NodeMFNetworkBuilder &builder); +using NodeExpandInMFNetworkFunction = void (*)(blender::nodes::NodeMFNetworkBuilder &builder); using SocketGetMFDataTypeFunction = blender::fn::MFDataType (*)(); -using SocketExpandInMFNetworkFunction = void (*)(blender::bke::SocketMFNetworkBuilder &builder); +using SocketExpandInMFNetworkFunction = void (*)(blender::nodes::SocketMFNetworkBuilder &builder); #else typedef void *NodeExpandInMFNetworkFunction; diff --git a/source/blender/blenkernel/BKE_simulation.h b/source/blender/blenkernel/BKE_simulation.h index ff6aaa5e30e..36f4122f4dc 100644 --- a/source/blender/blenkernel/BKE_simulation.h +++ b/source/blender/blenkernel/BKE_simulation.h @@ -17,13 +17,15 @@ #ifndef __BKE_SIMULATION_H__ #define __BKE_SIMULATION_H__ +#include "DNA_simulation_types.h" + #ifdef __cplusplus extern "C" { #endif struct Depsgraph; struct Main; -struct Simulation; +struct Scene; void *BKE_simulation_add(struct Main *bmain, const char *name); @@ -31,6 +33,12 @@ void BKE_simulation_data_update(struct Depsgraph *depsgraph, struct Scene *scene, struct Simulation *simulation); +SimulationState *BKE_simulation_state_add(Simulation *simulation, + eSimulationStateType type, + const char *name); +void BKE_simulation_state_remove(Simulation *simulation, SimulationState *state); +void BKE_simulation_state_remove_all(Simulation *simulation); + #ifdef __cplusplus } #endif diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index 30e6baf1a9d..800fa7d18ee 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -107,7 +107,6 @@ set(SRC intern/customdata_file.c intern/data_transfer.c intern/deform.c - intern/derived_node_tree.cc intern/displist.c intern/displist_tangent.c intern/dynamicpaint.c @@ -188,8 +187,6 @@ set(SRC intern/multires_unsubdivide.c intern/nla.c intern/node.c - intern/node_tree_multi_function.cc - intern/node_tree_ref.cc intern/object.c intern/object_deform.c intern/object_dupli.c @@ -298,7 +295,6 @@ set(SRC BKE_customdata_file.h BKE_data_transfer.h BKE_deform.h - BKE_derived_node_tree.hh BKE_displist.h BKE_displist_tangent.h BKE_duplilist.h @@ -359,8 +355,6 @@ set(SRC BKE_multires.h BKE_nla.h BKE_node.h - BKE_node_tree_multi_function.hh - BKE_node_tree_ref.hh BKE_object.h BKE_object_deform.h BKE_object_facemap.h @@ -443,7 +437,7 @@ set(LIB bf_intern_opensubdiv # Uses stub when disabled. bf_modifiers bf_nodes - bf_physics + bf_simulation bf_rna bf_shader_fx ) diff --git a/source/blender/blenkernel/intern/simulation.cc b/source/blender/blenkernel/intern/simulation.cc index 831de084500..1ac987d130d 100644 --- a/source/blender/blenkernel/intern/simulation.cc +++ b/source/blender/blenkernel/intern/simulation.cc @@ -45,25 +45,22 @@ #include "BKE_lib_remap.h" #include "BKE_main.h" #include "BKE_node.h" -#include "BKE_node_tree_multi_function.hh" #include "BKE_pointcache.h" #include "BKE_simulation.h" +#include "NOD_node_tree_multi_function.hh" #include "NOD_simulation.h" #include "BLT_translation.h" #include "FN_attributes_ref.hh" -#include "FN_cpp_types.hh" #include "FN_multi_function_network_evaluation.hh" #include "FN_multi_function_network_optimization.hh" #include "DEG_depsgraph.h" #include "DEG_depsgraph_query.h" -extern "C" { -void WM_clipboard_text_set(const char *buf, bool selection); -} +#include "SIM_simulation_update.hh" static void simulation_init_data(ID *id) { @@ -107,6 +104,58 @@ static void free_particle_simulation_state(ParticleSimulationState *state) MEM_freeN(state); } +SimulationState *BKE_simulation_state_add(Simulation *simulation, + eSimulationStateType type, + const char *name) +{ + BLI_assert(simulation != nullptr); + BLI_assert(name != nullptr); + + bool is_cow_simulation = DEG_is_evaluated_id(&simulation->id); + + switch (type) { + case SIM_STATE_TYPE_PARTICLES: { + ParticleSimulationState *state = (ParticleSimulationState *)MEM_callocN(sizeof(*state), AT); + state->head.type = SIM_STATE_TYPE_PARTICLES; + state->head.name = BLI_strdup(name); + CustomData_reset(&state->attributes); + + if (!is_cow_simulation) { + state->point_cache = BKE_ptcache_add(&state->ptcaches); + } + + BLI_addtail(&simulation->states, state); + return &state->head; + } + } + + BLI_assert(false); + return nullptr; +} + +void BKE_simulation_state_remove(Simulation *simulation, SimulationState *state) +{ + BLI_assert(simulation != nullptr); + BLI_assert(state != nullptr); + BLI_assert(BLI_findindex(&simulation->states, state) >= 0); + + BLI_remlink(&simulation->states, state); + switch ((eSimulationStateType)state->type) { + case SIM_STATE_TYPE_PARTICLES: { + free_particle_simulation_state((ParticleSimulationState *)state); + break; + } + } +} + +void BKE_simulation_state_remove_all(Simulation *simulation) +{ + BLI_assert(simulation != nullptr); + while (!BLI_listbase_is_empty(&simulation->states)) { + BKE_simulation_state_remove(simulation, (SimulationState *)simulation->states.first); + } +} + static void simulation_free_data(ID *id) { Simulation *simulation = (Simulation *)id; @@ -119,14 +168,7 @@ static void simulation_free_data(ID *id) simulation->nodetree = nullptr; } - LISTBASE_FOREACH_MUTABLE (SimulationState *, state, &simulation->states) { - switch ((eSimulationStateType)state->type) { - case SIM_STATE_TYPE_PARTICLES: { - free_particle_simulation_state((ParticleSimulationState *)state); - break; - } - } - } + BKE_simulation_state_remove_all(simulation); } static void simulation_foreach_id(ID *id, LibraryForeachIDData *data) @@ -164,651 +206,7 @@ void *BKE_simulation_add(Main *bmain, const char *name) return simulation; } -namespace blender::bke { - -static void ensure_attributes_exist(ParticleSimulationState *state) -{ - if (CustomData_get_layer_named(&state->attributes, CD_PROP_FLOAT3, "Position") == nullptr) { - CustomData_add_layer_named( - &state->attributes, CD_PROP_FLOAT3, CD_CALLOC, nullptr, state->tot_particles, "Position"); - } - if (CustomData_get_layer_named(&state->attributes, CD_PROP_FLOAT3, "Velocity") == nullptr) { - CustomData_add_layer_named( - &state->attributes, CD_PROP_FLOAT3, CD_CALLOC, nullptr, state->tot_particles, "Velocity"); - } - if (CustomData_get_layer_named(&state->attributes, CD_PROP_INT32, "ID") == nullptr) { - CustomData_add_layer_named( - &state->attributes, CD_PROP_INT32, CD_CALLOC, nullptr, state->tot_particles, "ID"); - } -} - -static void copy_states_to_cow(Simulation *simulation_orig, Simulation *simulation_cow) -{ - LISTBASE_FOREACH_MUTABLE (SimulationState *, state_cow, &simulation_cow->states) { - switch ((eSimulationStateType)state_cow->type) { - case SIM_STATE_TYPE_PARTICLES: { - BLI_remlink(&simulation_cow->states, state_cow); - free_particle_simulation_state((ParticleSimulationState *)state_cow); - break; - } - } - } - simulation_cow->current_frame = simulation_orig->current_frame; - - LISTBASE_FOREACH (SimulationState *, state_orig, &simulation_orig->states) { - switch ((eSimulationStateType)state_orig->type) { - case SIM_STATE_TYPE_PARTICLES: { - ParticleSimulationState *particle_state_orig = (ParticleSimulationState *)state_orig; - ParticleSimulationState *particle_state_cow = (ParticleSimulationState *)MEM_callocN( - sizeof(*particle_state_cow), AT); - particle_state_cow->tot_particles = particle_state_orig->tot_particles; - particle_state_cow->head.name = BLI_strdup(state_orig->name); - CustomData_copy(&particle_state_orig->attributes, - &particle_state_cow->attributes, - CD_MASK_ALL, - CD_DUPLICATE, - particle_state_orig->tot_particles); - BLI_addtail(&simulation_cow->states, particle_state_cow); - break; - } - } - } -} - -static Map<const fn::MFOutputSocket *, std::string> deduplicate_attribute_nodes( - fn::MFNetwork &network, MFNetworkTreeMap &network_map, const DerivedNodeTree &tree) -{ - Span<const DNode *> attribute_dnodes = tree.nodes_by_type("SimulationNodeParticleAttribute"); - uint amount = attribute_dnodes.size(); - if (amount == 0) { - return {}; - } - - Vector<fn::MFInputSocket *> name_sockets; - for (const DNode *dnode : attribute_dnodes) { - fn::MFInputSocket &name_socket = network_map.lookup_dummy(dnode->input(0)); - name_sockets.append(&name_socket); - } - - fn::MFNetworkEvaluator network_fn{{}, name_sockets.as_span()}; - - fn::MFParamsBuilder params{network_fn, 1}; - - Array<std::string> attribute_names{amount, NoInitialization()}; - for (uint i : IndexRange(amount)) { - params.add_uninitialized_single_output( - fn::GMutableSpan(fn::CPPType_string, attribute_names.data() + i, 1)); - } - - fn::MFContextBuilder context; - /* Todo: Check that the names don't depend on dummy nodes. */ - network_fn.call({0}, params, context); - - Map<std::pair<std::string, fn::MFDataType>, Vector<fn::MFNode *>> - attribute_nodes_by_name_and_type; - for (uint i : IndexRange(amount)) { - attribute_nodes_by_name_and_type - .lookup_or_add_default({attribute_names[i], name_sockets[i]->node().output(0).data_type()}) - .append(&name_sockets[i]->node()); - } - - Map<const fn::MFOutputSocket *, std::string> attribute_inputs; - for (auto item : attribute_nodes_by_name_and_type.items()) { - StringRef attribute_name = item.key.first; - fn::MFDataType data_type = item.key.second; - Span<fn::MFNode *> nodes = item.value; - - fn::MFOutputSocket &new_attribute_socket = network.add_input( - "Attribute '" + attribute_name + "'", data_type); - for (fn::MFNode *node : nodes) { - network.relink(node->output(0), new_attribute_socket); - } - network.remove(nodes); - - attribute_inputs.add_new(&new_attribute_socket, attribute_name); - } - - return attribute_inputs; -} - -class CustomDataAttributesRef { - private: - Vector<void *> buffers_; - uint size_; - std::unique_ptr<fn::AttributesInfo> info_; - - public: - CustomDataAttributesRef(CustomData &custom_data, uint size) - { - fn::AttributesInfoBuilder builder; - for (const CustomDataLayer &layer : Span(custom_data.layers, custom_data.totlayer)) { - buffers_.append(layer.data); - switch (layer.type) { - case CD_PROP_INT32: { - builder.add<int32_t>(layer.name, 0); - break; - } - case CD_PROP_FLOAT3: { - builder.add<float3>(layer.name, {0, 0, 0}); - break; - } - } - } - info_ = std::make_unique<fn::AttributesInfo>(builder); - size_ = size; - } - - operator fn::MutableAttributesRef() - { - return fn::MutableAttributesRef(*info_, buffers_, size_); - } - - operator fn::AttributesRef() const - { - return fn::AttributesRef(*info_, buffers_, size_); - } -}; - -static std::string dnode_to_path(const DNode &dnode) -{ - std::string path; - for (const DParentNode *parent = dnode.parent(); parent; parent = parent->parent()) { - path = parent->node_ref().name() + "/" + path; - } - path = path + dnode.name(); - return path; -} - -static void remove_unused_states(Simulation *simulation, const VectorSet<std::string> &state_names) -{ - LISTBASE_FOREACH_MUTABLE (SimulationState *, state, &simulation->states) { - if (!state_names.contains(state->name)) { - BLI_remlink(&simulation->states, state); - free_particle_simulation_state((ParticleSimulationState *)state); - } - } -} - -static void reset_states(Simulation *simulation) -{ - LISTBASE_FOREACH (SimulationState *, state, &simulation->states) { - switch ((eSimulationStateType)state->type) { - case SIM_STATE_TYPE_PARTICLES: { - ParticleSimulationState *particle_state = (ParticleSimulationState *)state; - CustomData_free(&particle_state->attributes, particle_state->tot_particles); - particle_state->tot_particles = 0; - break; - } - } - } -} - -static SimulationState *try_find_state_by_name(Simulation *simulation, StringRef name) -{ - LISTBASE_FOREACH (SimulationState *, state, &simulation->states) { - if (state->name == name) { - return state; - } - } - return nullptr; -} - -static void add_missing_particle_states(Simulation *simulation, Span<std::string> state_names) -{ - for (StringRefNull name : state_names) { - SimulationState *state = try_find_state_by_name(simulation, name); - if (state != nullptr) { - BLI_assert(state->type == SIM_STATE_TYPE_PARTICLES); - continue; - } - - ParticleSimulationState *particle_state = (ParticleSimulationState *)MEM_callocN( - sizeof(*particle_state), AT); - particle_state->head.type = SIM_STATE_TYPE_PARTICLES; - particle_state->head.name = BLI_strdup(name.data()); - CustomData_reset(&particle_state->attributes); - particle_state->point_cache = BKE_ptcache_add(&particle_state->ptcaches); - BLI_addtail(&simulation->states, particle_state); - } -} - -static void reinitialize_empty_simulation_states(Simulation *simulation, - const DerivedNodeTree &tree) -{ - VectorSet<std::string> state_names; - for (const DNode *dnode : tree.nodes_by_type("SimulationNodeParticleSimulation")) { - state_names.add(dnode_to_path(*dnode)); - } - - remove_unused_states(simulation, state_names); - reset_states(simulation); - add_missing_particle_states(simulation, state_names); -} - -static void update_simulation_state_list(Simulation *simulation, const DerivedNodeTree &tree) -{ - VectorSet<std::string> state_names; - for (const DNode *dnode : tree.nodes_by_type("SimulationNodeParticleSimulation")) { - state_names.add(dnode_to_path(*dnode)); - } - - remove_unused_states(simulation, state_names); - add_missing_particle_states(simulation, state_names); -} - -class ParticleFunctionInput { - public: - virtual ~ParticleFunctionInput() = default; - virtual void add_input(fn::AttributesRef attributes, - fn::MFParamsBuilder ¶ms, - ResourceCollector &resources) const = 0; -}; - -class ParticleFunction { - private: - const fn::MultiFunction *global_fn_; - const fn::MultiFunction *per_particle_fn_; - Array<const ParticleFunctionInput *> global_inputs_; - Array<const ParticleFunctionInput *> per_particle_inputs_; - Array<bool> output_is_global_; - Vector<uint> global_output_indices_; - Vector<uint> per_particle_output_indices_; - Vector<fn::MFDataType> output_types_; - Vector<StringRefNull> output_names_; - - friend class ParticleFunctionEvaluator; - - public: - ParticleFunction(const fn::MultiFunction *global_fn, - const fn::MultiFunction *per_particle_fn, - Span<const ParticleFunctionInput *> global_inputs, - Span<const ParticleFunctionInput *> per_particle_inputs, - Span<bool> output_is_global) - : global_fn_(global_fn), - per_particle_fn_(per_particle_fn), - global_inputs_(global_inputs), - per_particle_inputs_(per_particle_inputs), - output_is_global_(output_is_global) - { - for (uint i : output_is_global_.index_range()) { - if (output_is_global_[i]) { - uint param_index = global_inputs_.size() + global_output_indices_.size(); - fn::MFParamType param_type = global_fn_->param_type(param_index); - BLI_assert(param_type.is_output()); - output_types_.append(param_type.data_type()); - output_names_.append(global_fn_->param_name(param_index)); - global_output_indices_.append(i); - } - else { - uint param_index = per_particle_inputs_.size() + per_particle_output_indices_.size(); - fn::MFParamType param_type = per_particle_fn_->param_type(param_index); - BLI_assert(param_type.is_output()); - output_types_.append(param_type.data_type()); - output_names_.append(per_particle_fn_->param_name(param_index)); - per_particle_output_indices_.append(i); - } - } - } -}; - -class ParticleFunctionEvaluator { - private: - ResourceCollector resources_; - const ParticleFunction &particle_fn_; - IndexMask mask_; - fn::MFContextBuilder global_context_; - fn::MFContextBuilder per_particle_context_; - fn::AttributesRef particle_attributes_; - Vector<void *> outputs_; - bool is_computed_ = false; - - public: - ParticleFunctionEvaluator(const ParticleFunction &particle_fn, - IndexMask mask, - fn::AttributesRef particle_attributes) - : particle_fn_(particle_fn), - mask_(mask), - particle_attributes_(particle_attributes), - outputs_(particle_fn_.output_types_.size(), nullptr) - { - } - - ~ParticleFunctionEvaluator() - { - for (uint output_index : outputs_.index_range()) { - void *buffer = outputs_[output_index]; - fn::MFDataType data_type = particle_fn_.output_types_[output_index]; - BLI_assert(data_type.is_single()); /* For now. */ - const fn::CPPType &type = data_type.single_type(); - - if (particle_fn_.output_is_global_[output_index]) { - type.destruct(buffer); - } - else { - type.destruct_indices(outputs_[0], mask_); - } - } - } - - void compute() - { - BLI_assert(!is_computed_); - this->compute_globals(); - this->compute_per_particle(); - is_computed_ = true; - } - - template<typename T> fn::VSpan<T> get(uint output_index, StringRef expected_name) const - { - return this->get(output_index, expected_name).typed<T>(); - } - - fn::GVSpan get(uint output_index, StringRef expected_name) const - { -#ifdef DEBUG - StringRef real_name = particle_fn_.output_names_[output_index]; - BLI_assert(expected_name == real_name); - BLI_assert(is_computed_); -#endif - UNUSED_VARS_NDEBUG(expected_name); - const void *buffer = outputs_[output_index]; - const fn::CPPType &type = particle_fn_.output_types_[output_index].single_type(); - if (particle_fn_.output_is_global_[output_index]) { - return fn::GVSpan::FromSingleWithMaxSize(type, buffer); - } - else { - return fn::GVSpan(fn::GSpan(type, buffer, mask_.min_array_size())); - } - } - - private: - void compute_globals() - { - if (particle_fn_.global_fn_ == nullptr) { - return; - } - - fn::MFParamsBuilder params(*particle_fn_.global_fn_, mask_.min_array_size()); - - /* Add input parameters. */ - for (const ParticleFunctionInput *input : particle_fn_.global_inputs_) { - input->add_input(particle_attributes_, params, resources_); - } - - /* Add output parameters. */ - for (uint output_index : particle_fn_.global_output_indices_) { - fn::MFDataType data_type = particle_fn_.output_types_[output_index]; - BLI_assert(data_type.is_single()); /* For now. */ - - const fn::CPPType &type = data_type.single_type(); - void *buffer = resources_.linear_allocator().allocate(type.size(), type.alignment()); - params.add_uninitialized_single_output(fn::GMutableSpan(type, buffer, 1)); - outputs_[output_index] = buffer; - } - - particle_fn_.global_fn_->call({0}, params, global_context_); - } - - void compute_per_particle() - { - if (particle_fn_.per_particle_fn_ == nullptr) { - return; - } - - fn::MFParamsBuilder params(*particle_fn_.per_particle_fn_, mask_.min_array_size()); - - /* Add input parameters. */ - for (const ParticleFunctionInput *input : particle_fn_.per_particle_inputs_) { - input->add_input(particle_attributes_, params, resources_); - } - - /* Add output parameters. */ - for (uint output_index : particle_fn_.per_particle_output_indices_) { - fn::MFDataType data_type = particle_fn_.output_types_[output_index]; - BLI_assert(data_type.is_single()); /* For now. */ - - const fn::CPPType &type = data_type.single_type(); - void *buffer = resources_.linear_allocator().allocate(type.size() * mask_.min_array_size(), - type.alignment()); - params.add_uninitialized_single_output( - fn::GMutableSpan(type, buffer, mask_.min_array_size())); - outputs_[output_index] = buffer; - } - - particle_fn_.per_particle_fn_->call(mask_, params, global_context_); - } -}; - -class ParticleAttributeInput : public ParticleFunctionInput { - private: - std::string attribute_name_; - const fn::CPPType &attribute_type_; - - public: - ParticleAttributeInput(std::string attribute_name, const fn::CPPType &attribute_type) - : attribute_name_(std::move(attribute_name)), attribute_type_(attribute_type) - { - } - - void add_input(fn::AttributesRef attributes, - fn::MFParamsBuilder ¶ms, - ResourceCollector &UNUSED(resources)) const override - { - std::optional<fn::GSpan> span = attributes.try_get(attribute_name_, attribute_type_); - if (span.has_value()) { - params.add_readonly_single_input(*span); - } - else { - params.add_readonly_single_input(fn::GVSpan::FromDefault(attribute_type_)); - } - } -}; - -static const ParticleFunction *create_particle_function_for_inputs( - Span<const fn::MFInputSocket *> sockets_to_compute, - ResourceCollector &resources, - const Map<const fn::MFOutputSocket *, std::string> &attribute_inputs) -{ - BLI_assert(sockets_to_compute.size() >= 1); - const fn::MFNetwork &network = sockets_to_compute[0]->node().network(); - - VectorSet<const fn::MFOutputSocket *> dummy_deps; - VectorSet<const fn::MFInputSocket *> unlinked_input_deps; - network.find_dependencies(sockets_to_compute, dummy_deps, unlinked_input_deps); - BLI_assert(unlinked_input_deps.size() == 0); - - Vector<const ParticleFunctionInput *> per_particle_inputs; - for (const fn::MFOutputSocket *socket : dummy_deps) { - const std::string *attribute_name = attribute_inputs.lookup_ptr(socket); - if (attribute_name == nullptr) { - return nullptr; - } - per_particle_inputs.append(&resources.construct<ParticleAttributeInput>( - AT, *attribute_name, socket->data_type().single_type())); - } - - const fn::MultiFunction &per_particle_fn = resources.construct<fn::MFNetworkEvaluator>( - AT, dummy_deps.as_span(), sockets_to_compute); - - Array<bool> output_is_global(sockets_to_compute.size(), false); - - const ParticleFunction &particle_fn = resources.construct<ParticleFunction>( - AT, - nullptr, - &per_particle_fn, - Span<const ParticleFunctionInput *>(), - per_particle_inputs.as_span(), - output_is_global.as_span()); - - return &particle_fn; -} - -class ParticleForce { - public: - virtual ~ParticleForce() = default; - virtual void add_force(fn::AttributesRef attributes, - MutableSpan<float3> r_combined_force) const = 0; -}; - -class ParticleFunctionForce : public ParticleForce { - private: - const ParticleFunction &particle_fn_; - - public: - ParticleFunctionForce(const ParticleFunction &particle_fn) : particle_fn_(particle_fn) - { - } - - void add_force(fn::AttributesRef attributes, MutableSpan<float3> r_combined_force) const override - { - IndexMask mask = IndexRange(attributes.size()); - ParticleFunctionEvaluator evaluator{particle_fn_, mask, attributes}; - evaluator.compute(); - fn::VSpan<float3> forces = evaluator.get<float3>(0, "Force"); - for (uint i : mask) { - r_combined_force[i] += forces[i]; - } - } -}; - -static Vector<const ParticleForce *> create_forces_for_particle_simulation( - const DNode &simulation_node, - MFNetworkTreeMap &network_map, - ResourceCollector &resources, - const Map<const fn::MFOutputSocket *, std::string> &attribute_inputs) -{ - Vector<const ParticleForce *> forces; - for (const DOutputSocket *origin_socket : simulation_node.input(2, "Forces").linked_sockets()) { - const DNode &origin_node = origin_socket->node(); - if (origin_node.idname() != "SimulationNodeForce") { - continue; - } - - const fn::MFInputSocket &force_socket = network_map.lookup_dummy( - origin_node.input(0, "Force")); - - const ParticleFunction *particle_fn = create_particle_function_for_inputs( - {&force_socket}, resources, attribute_inputs); - - if (particle_fn == nullptr) { - continue; - } - - const ParticleForce &force = resources.construct<ParticleFunctionForce>(AT, *particle_fn); - forces.append(&force); - } - return forces; -} - -static Map<std::string, Vector<const ParticleForce *>> collect_forces( - MFNetworkTreeMap &network_map, - ResourceCollector &resources, - const Map<const fn::MFOutputSocket *, std::string> &attribute_inputs) -{ - Map<std::string, Vector<const ParticleForce *>> forces_by_simulation; - for (const DNode *dnode : network_map.tree().nodes_by_type("SimulationNodeParticleSimulation")) { - std::string name = dnode_to_path(*dnode); - Vector<const ParticleForce *> forces = create_forces_for_particle_simulation( - *dnode, network_map, resources, attribute_inputs); - forces_by_simulation.add_new(std::move(name), std::move(forces)); - } - return forces_by_simulation; -} - -static void simulation_data_update(Depsgraph *depsgraph, Scene *scene, Simulation *simulation_cow) -{ - int current_frame = scene->r.cfra; - if (simulation_cow->current_frame == current_frame) { - return; - } - - /* Below we modify the original state/cache. Only the active depsgraph is allowed to do that. */ - if (!DEG_is_active(depsgraph)) { - return; - } - - Simulation *simulation_orig = (Simulation *)DEG_get_original_id(&simulation_cow->id); - - NodeTreeRefMap tree_refs; - /* TODO: Use simulation_cow, but need to add depsgraph relations before that. */ - const DerivedNodeTree tree{simulation_orig->nodetree, tree_refs}; - fn::MFNetwork network; - ResourceCollector resources; - MFNetworkTreeMap network_map = insert_node_tree_into_mf_network(network, tree, resources); - Map<const fn::MFOutputSocket *, std::string> attribute_inputs = deduplicate_attribute_nodes( - network, network_map, tree); - fn::mf_network_optimization::constant_folding(network, resources); - fn::mf_network_optimization::common_subnetwork_elimination(network); - fn::mf_network_optimization::dead_node_removal(network); - // WM_clipboard_text_set(network.to_dot().c_str(), false); - - Map<std::string, Vector<const ParticleForce *>> forces_by_simulation = collect_forces( - network_map, resources, attribute_inputs); - - if (current_frame == 1) { - reinitialize_empty_simulation_states(simulation_orig, tree); - - RNG *rng = BLI_rng_new(0); - - simulation_orig->current_frame = 1; - LISTBASE_FOREACH (ParticleSimulationState *, state, &simulation_orig->states) { - state->tot_particles = 1000; - CustomData_realloc(&state->attributes, state->tot_particles); - ensure_attributes_exist(state); - - CustomDataAttributesRef custom_data_attributes{state->attributes, - (uint)state->tot_particles}; - - fn::MutableAttributesRef attributes = custom_data_attributes; - MutableSpan<float3> positions = attributes.get<float3>("Position"); - MutableSpan<float3> velocities = attributes.get<float3>("Velocity"); - MutableSpan<int32_t> ids = attributes.get<int32_t>("ID"); - - for (uint i : positions.index_range()) { - positions[i] = {i / 100.0f, 0, 0}; - velocities[i] = {0, BLI_rng_get_float(rng) - 0.5f, BLI_rng_get_float(rng) - 0.5f}; - ids[i] = i; - } - } - - BLI_rng_free(rng); - - copy_states_to_cow(simulation_orig, simulation_cow); - } - else if (current_frame == simulation_orig->current_frame + 1) { - update_simulation_state_list(simulation_orig, tree); - float time_step = 1.0f / 24.0f; - simulation_orig->current_frame = current_frame; - - LISTBASE_FOREACH (ParticleSimulationState *, state, &simulation_orig->states) { - ensure_attributes_exist(state); - - CustomDataAttributesRef custom_data_attributes{state->attributes, - (uint)state->tot_particles}; - - fn::MutableAttributesRef attributes = custom_data_attributes; - MutableSpan<float3> positions = attributes.get<float3>("Position"); - MutableSpan<float3> velocities = attributes.get<float3>("Velocity"); - - Array<float3> force_vectors{(uint)state->tot_particles, {0, 0, 0}}; - Span<const ParticleForce *> forces = forces_by_simulation.lookup_as(state->head.name); - for (const ParticleForce *force : forces) { - force->add_force(attributes, force_vectors); - } - - for (uint i : positions.index_range()) { - velocities[i] += force_vectors[i] * time_step; - positions[i] += velocities[i] * time_step; - } - } - - copy_states_to_cow(simulation_orig, simulation_cow); - } -} - -} // namespace blender::bke - void BKE_simulation_data_update(Depsgraph *depsgraph, Scene *scene, Simulation *simulation) { - blender::bke::simulation_data_update(depsgraph, scene, simulation); + blender::sim::update_simulation_in_depsgraph(depsgraph, scene, simulation); } diff --git a/source/blender/blenlib/BLI_string_ref.hh b/source/blender/blenlib/BLI_string_ref.hh index bcf2d20338e..5b555b8cd1d 100644 --- a/source/blender/blenlib/BLI_string_ref.hh +++ b/source/blender/blenlib/BLI_string_ref.hh @@ -187,7 +187,7 @@ class StringRefNull : public StringRefBase { * Reference a std::string. Remember that when the std::string is destructed, the StringRefNull * will point to uninitialized memory. */ - StringRefNull(const std::string &str) : StringRefNull(str.data()) + StringRefNull(const std::string &str) : StringRefNull(str.c_str()) { } @@ -200,6 +200,16 @@ class StringRefNull : public StringRefBase { BLI_assert(index <= size_); return data_[index]; } + + /** + * Returns the beginning of a null-terminated char array. + * + * This is like ->data(), but can only be called on a StringRefNull. + */ + const char *c_str() const + { + return data_; + } }; /** diff --git a/source/blender/draw/intern/draw_cache_extract.h b/source/blender/draw/intern/draw_cache_extract.h index f05e8e2f9d6..4156e2e79d8 100644 --- a/source/blender/draw/intern/draw_cache_extract.h +++ b/source/blender/draw/intern/draw_cache_extract.h @@ -170,8 +170,7 @@ typedef enum DRWBatchFlag { MBC_WIRE_EDGES = (1 << 23), MBC_WIRE_LOOPS = (1 << 24), MBC_WIRE_LOOPS_UVS = (1 << 25), - MBC_SURF_PER_MAT = (1 << 26), - MBC_SKIN_ROOTS = (1 << 27), + MBC_SKIN_ROOTS = (1 << 26), } DRWBatchFlag; #define MBC_EDITUV \ diff --git a/source/blender/draw/intern/draw_cache_extract_mesh.c b/source/blender/draw/intern/draw_cache_extract_mesh.c index a27ee90b148..1737f8b2ff9 100644 --- a/source/blender/draw/intern/draw_cache_extract_mesh.c +++ b/source/blender/draw/intern/draw_cache_extract_mesh.c @@ -890,12 +890,13 @@ static void extract_tris_finish(const MeshRenderData *mr, void *ibo, void *_data MeshExtract_Tri_Data *data = _data; GPU_indexbuf_build_in_place(&data->elb, ibo); /* HACK: Create ibo sub-ranges and assign them to each #GPUBatch. */ - if (mr->use_final_mesh && mr->cache->surface_per_mat && mr->cache->surface_per_mat[0]) { - BLI_assert(mr->cache->surface_per_mat[0]->elem == ibo); + if (mr->use_final_mesh) { for (int i = 0; i < mr->mat_len; i++) { /* Multiply by 3 because these are triangle indices. */ - const int start = data->tri_mat_start[i] * 3; - const int len = data->tri_mat_end[i] * 3 - data->tri_mat_start[i] * 3; + const int mat_start = data->tri_mat_start[i]; + const int mat_end = data->tri_mat_end[i]; + const int start = mat_start * 3; + const int len = (mat_end - mat_start) * 3; GPUIndexBuf *sub_ibo = GPU_indexbuf_create_subrange(ibo, start, len); /* WARNING: We modify the #GPUBatch here! */ GPU_batch_elembuf_set(mr->cache->surface_per_mat[i], sub_ibo, true); diff --git a/source/blender/draw/intern/draw_cache_impl_mesh.c b/source/blender/draw/intern/draw_cache_impl_mesh.c index e69fb795948..410d59b557b 100644 --- a/source/blender/draw/intern/draw_cache_impl_mesh.c +++ b/source/blender/draw/intern/draw_cache_impl_mesh.c @@ -527,14 +527,26 @@ static void mesh_batch_cache_check_vertex_group(MeshBatchCache *cache, } } -static void mesh_batch_cache_discard_shaded_batches(MeshBatchCache *cache) +static void mesh_batch_cache_request_surface_batches(MeshBatchCache *cache) { + mesh_batch_cache_add_request(cache, MBC_SURFACE); + DRW_batch_request(&cache->batch.surface); + if (cache->surface_per_mat) { + for (int i = 0; i < cache->mat_len; i++) { + DRW_batch_request(&cache->surface_per_mat[i]); + } + } +} + +static void mesh_batch_cache_discard_surface_batches(MeshBatchCache *cache) +{ + GPU_BATCH_DISCARD_SAFE(cache->batch.surface); if (cache->surface_per_mat) { for (int i = 0; i < cache->mat_len; i++) { GPU_BATCH_DISCARD_SAFE(cache->surface_per_mat[i]); } } - cache->batch_ready &= ~MBC_SURF_PER_MAT; + cache->batch_ready &= ~MBC_SURFACE; } static void mesh_batch_cache_discard_shaded_tri(MeshBatchCache *cache) @@ -546,7 +558,7 @@ static void mesh_batch_cache_discard_shaded_tri(MeshBatchCache *cache) GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.vcol); GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.orco); } - mesh_batch_cache_discard_shaded_batches(cache); + mesh_batch_cache_discard_surface_batches(cache); mesh_cd_layers_type_clear(&cache->cd_used); MEM_SAFE_FREE(cache->surface_per_mat); @@ -586,10 +598,7 @@ static void mesh_batch_cache_discard_uvedit(MeshBatchCache *cache) cache->cd_used.edit_uv = 0; /* Discard other batches that uses vbo.uv */ - mesh_batch_cache_discard_shaded_batches(cache); - - GPU_BATCH_DISCARD_SAFE(cache->batch.surface); - cache->batch_ready &= ~MBC_SURFACE; + mesh_batch_cache_discard_surface_batches(cache); } static void mesh_batch_cache_discard_uvedit_select(MeshBatchCache *cache) @@ -651,12 +660,8 @@ void DRW_mesh_batch_cache_dirty_tag(Mesh *me, int mode) GPU_BATCH_DISCARD_SAFE(cache->batch.surface); GPU_BATCH_DISCARD_SAFE(cache->batch.wire_loops); GPU_BATCH_DISCARD_SAFE(cache->batch.wire_edges); - if (cache->surface_per_mat) { - for (int i = 0; i < cache->mat_len; i++) { - GPU_BATCH_DISCARD_SAFE(cache->surface_per_mat[i]); - } - } - cache->batch_ready &= ~(MBC_SURFACE | MBC_WIRE_EDGES | MBC_WIRE_LOOPS | MBC_SURF_PER_MAT); + mesh_batch_cache_discard_surface_batches(cache); + cache->batch_ready &= ~(MBC_SURFACE | MBC_WIRE_EDGES | MBC_WIRE_LOOPS); break; case BKE_MESH_BATCH_DIRTY_ALL: cache->is_dirty = true; @@ -782,8 +787,8 @@ GPUBatch *DRW_mesh_batch_cache_get_all_edges(Mesh *me) GPUBatch *DRW_mesh_batch_cache_get_surface(Mesh *me) { MeshBatchCache *cache = mesh_batch_cache_get(me); - mesh_batch_cache_add_request(cache, MBC_SURFACE); - return DRW_batch_request(&cache->batch.surface); + mesh_batch_cache_request_surface_batches(cache); + return cache->batch.surface; } GPUBatch *DRW_mesh_batch_cache_get_loose_edges(Mesh *me) @@ -841,23 +846,15 @@ GPUBatch **DRW_mesh_batch_cache_get_surface_shaded(Mesh *me, BLI_assert(gpumat_array_len == cache->mat_len); mesh_cd_layers_type_merge(&cache->cd_needed, cd_needed); - - mesh_batch_cache_add_request(cache, MBC_SURF_PER_MAT); - - for (int i = 0; i < cache->mat_len; i++) { - DRW_batch_request(&cache->surface_per_mat[i]); - } + mesh_batch_cache_request_surface_batches(cache); return cache->surface_per_mat; } GPUBatch **DRW_mesh_batch_cache_get_surface_texpaint(Mesh *me) { MeshBatchCache *cache = mesh_batch_cache_get(me); - mesh_batch_cache_add_request(cache, MBC_SURF_PER_MAT); texpaint_request_active_uv(cache, me); - for (int i = 0; i < cache->mat_len; i++) { - DRW_batch_request(&cache->surface_per_mat[i]); - } + mesh_batch_cache_request_surface_batches(cache); return cache->surface_per_mat; } @@ -865,24 +862,24 @@ GPUBatch *DRW_mesh_batch_cache_get_surface_texpaint_single(Mesh *me) { MeshBatchCache *cache = mesh_batch_cache_get(me); texpaint_request_active_uv(cache, me); - mesh_batch_cache_add_request(cache, MBC_SURFACE); - return DRW_batch_request(&cache->batch.surface); + mesh_batch_cache_request_surface_batches(cache); + return cache->batch.surface; } GPUBatch *DRW_mesh_batch_cache_get_surface_vertpaint(Mesh *me) { MeshBatchCache *cache = mesh_batch_cache_get(me); texpaint_request_active_vcol(cache, me); - mesh_batch_cache_add_request(cache, MBC_SURFACE); - return DRW_batch_request(&cache->batch.surface); + mesh_batch_cache_request_surface_batches(cache); + return cache->batch.surface; } GPUBatch *DRW_mesh_batch_cache_get_surface_sculpt(Mesh *me) { MeshBatchCache *cache = mesh_batch_cache_get(me); sculpt_request_active_vcol(cache, me); - mesh_batch_cache_add_request(cache, MBC_SURFACE); - return DRW_batch_request(&cache->batch.surface); + mesh_batch_cache_request_surface_batches(cache); + return cache->batch.surface; } int DRW_mesh_material_count_get(Mesh *me) @@ -900,8 +897,7 @@ GPUVertBuf *DRW_mesh_batch_cache_pos_vertbuf_get(Mesh *me) { MeshBatchCache *cache = mesh_batch_cache_get(me); /* Request surface to trigger the vbo filling. Otherwise it may do nothing. */ - mesh_batch_cache_add_request(cache, MBC_SURFACE); - DRW_batch_request(&cache->batch.surface); + mesh_batch_cache_request_surface_batches(cache); DRW_vbo_request(NULL, &cache->final.vbo.pos_nor); return cache->final.vbo.pos_nor; @@ -1122,6 +1118,40 @@ void DRW_mesh_batch_cache_free_old(Mesh *me, int ctime) mesh_cd_layers_type_clear(&cache->cd_used_over_time); } +#ifdef DEBUG +/* Sanity check function to test if all requested batches are available. */ +static void drw_mesh_batch_cache_check_available(struct TaskGraph *task_graph, Mesh *me) +{ + MeshBatchCache *cache = mesh_batch_cache_get(me); + /* Make sure all requested batches have been setup. */ + /* Note: The next line creates a different scheduling than during release builds what can lead to + * some issues (See T77867 where we needed to disable this function in order to debug what was + * happening in release builds). */ + BLI_task_graph_work_and_wait(task_graph); + for (int i = 0; i < sizeof(cache->batch) / sizeof(void *); i++) { + BLI_assert(!DRW_batch_requested(((GPUBatch **)&cache->batch)[i], 0)); + } + for (int i = 0; i < sizeof(cache->final.vbo) / sizeof(void *); i++) { + BLI_assert(!DRW_vbo_requested(((GPUVertBuf **)&cache->final.vbo)[i])); + } + for (int i = 0; i < sizeof(cache->final.ibo) / sizeof(void *); i++) { + BLI_assert(!DRW_ibo_requested(((GPUIndexBuf **)&cache->final.ibo)[i])); + } + for (int i = 0; i < sizeof(cache->cage.vbo) / sizeof(void *); i++) { + BLI_assert(!DRW_vbo_requested(((GPUVertBuf **)&cache->cage.vbo)[i])); + } + for (int i = 0; i < sizeof(cache->cage.ibo) / sizeof(void *); i++) { + BLI_assert(!DRW_ibo_requested(((GPUIndexBuf **)&cache->cage.ibo)[i])); + } + for (int i = 0; i < sizeof(cache->uv_cage.vbo) / sizeof(void *); i++) { + BLI_assert(!DRW_vbo_requested(((GPUVertBuf **)&cache->uv_cage.vbo)[i])); + } + for (int i = 0; i < sizeof(cache->uv_cage.ibo) / sizeof(void *); i++) { + BLI_assert(!DRW_ibo_requested(((GPUIndexBuf **)&cache->uv_cage.ibo)[i])); + } +} +#endif + /* Can be called for any surface type. Mesh *me is the final mesh. */ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph, Object *ob, @@ -1142,10 +1172,9 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph, /* Early out */ if (cache->batch_requested == 0) { #ifdef DEBUG - goto check; -#else - return; + drw_mesh_batch_cache_check_available(task_graph, me); #endif + return; } /* Sanity check. */ @@ -1170,30 +1199,8 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph, } } - /* HACK: if MBC_SURF_PER_MAT is requested and ibo.tris is already available, it won't have it's - * index ranges initialized. So discard ibo.tris in order to recreate it. - * This needs to happen before saved_elem_ranges is populated. */ - if ((batch_requested & MBC_SURF_PER_MAT) != 0 && (cache->batch_ready & MBC_SURF_PER_MAT) == 0) { - FOREACH_MESH_BUFFER_CACHE (cache, mbuffercache) { - GPU_INDEXBUF_DISCARD_SAFE(mbuffercache->ibo.tris); - } - /* Clear all batches that reference ibo.tris. */ - GPU_BATCH_CLEAR_SAFE(cache->batch.surface); - GPU_BATCH_CLEAR_SAFE(cache->batch.surface_weights); - GPU_BATCH_CLEAR_SAFE(cache->batch.edit_mesh_analysis); - GPU_BATCH_CLEAR_SAFE(cache->batch.edit_triangles); - GPU_BATCH_CLEAR_SAFE(cache->batch.edit_lnor); - GPU_BATCH_CLEAR_SAFE(cache->batch.edit_selection_faces); - for (int i = 0; i < cache->mat_len; i++) { - GPU_BATCH_CLEAR_SAFE(cache->surface_per_mat[i]); - } - - cache->batch_ready &= ~(MBC_SURFACE | MBC_SURFACE_WEIGHTS | MBC_EDIT_MESH_ANALYSIS | - MBC_EDIT_TRIANGLES | MBC_EDIT_LNOR | MBC_EDIT_SELECTION_FACES); - } - if (batch_requested & - (MBC_SURFACE | MBC_SURF_PER_MAT | MBC_WIRE_LOOPS_UVS | MBC_EDITUV_FACES_STRETCH_AREA | + (MBC_SURFACE | MBC_WIRE_LOOPS_UVS | MBC_EDITUV_FACES_STRETCH_AREA | MBC_EDITUV_FACES_STRETCH_ANGLE | MBC_EDITUV_FACES | MBC_EDITUV_EDGES | MBC_EDITUV_VERTS)) { /* Modifiers will only generate an orco layer if the mesh is deformed. */ if (cache->cd_needed.orco != 0) { @@ -1246,7 +1253,7 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph, GPU_BATCH_CLEAR_SAFE(cache->surface_per_mat[i]); } GPU_BATCH_CLEAR_SAFE(cache->batch.surface); - cache->batch_ready &= ~(MBC_SURFACE | MBC_SURF_PER_MAT); + cache->batch_ready &= ~(MBC_SURFACE); mesh_cd_layers_type_merge(&cache->cd_used, cache->cd_needed); } @@ -1282,10 +1289,9 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph, /* Second chance to early out */ if ((batch_requested & ~cache->batch_ready) == 0) { #ifdef DEBUG - goto check; -#else - return; + drw_mesh_batch_cache_check_available(task_graph, me); #endif + return; } cache->batch_ready |= batch_requested; @@ -1537,32 +1543,7 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph, ts, use_hide); #ifdef DEBUG -check: - /* Make sure all requested batches have been setup. */ - /* TODO(jbakker): we should move this to the draw_manager but that needs refactoring and - * additional looping.*/ - BLI_task_graph_work_and_wait(task_graph); - for (int i = 0; i < sizeof(cache->batch) / sizeof(void *); i++) { - BLI_assert(!DRW_batch_requested(((GPUBatch **)&cache->batch)[i], 0)); - } - for (int i = 0; i < sizeof(cache->final.vbo) / sizeof(void *); i++) { - BLI_assert(!DRW_vbo_requested(((GPUVertBuf **)&cache->final.vbo)[i])); - } - for (int i = 0; i < sizeof(cache->final.ibo) / sizeof(void *); i++) { - BLI_assert(!DRW_ibo_requested(((GPUIndexBuf **)&cache->final.ibo)[i])); - } - for (int i = 0; i < sizeof(cache->cage.vbo) / sizeof(void *); i++) { - BLI_assert(!DRW_vbo_requested(((GPUVertBuf **)&cache->cage.vbo)[i])); - } - for (int i = 0; i < sizeof(cache->cage.ibo) / sizeof(void *); i++) { - BLI_assert(!DRW_ibo_requested(((GPUIndexBuf **)&cache->cage.ibo)[i])); - } - for (int i = 0; i < sizeof(cache->uv_cage.vbo) / sizeof(void *); i++) { - BLI_assert(!DRW_vbo_requested(((GPUVertBuf **)&cache->uv_cage.vbo)[i])); - } - for (int i = 0; i < sizeof(cache->uv_cage.ibo) / sizeof(void *); i++) { - BLI_assert(!DRW_ibo_requested(((GPUIndexBuf **)&cache->uv_cage.ibo)[i])); - } + drw_mesh_batch_cache_check_available(task_graph, me); #endif } diff --git a/source/blender/draw/intern/draw_cache_impl_pointcloud.c b/source/blender/draw/intern/draw_cache_impl_pointcloud.c index 5977c60335f..17902f27513 100644 --- a/source/blender/draw/intern/draw_cache_impl_pointcloud.c +++ b/source/blender/draw/intern/draw_cache_impl_pointcloud.c @@ -270,6 +270,7 @@ GPUBatch **DRW_cache_pointcloud_surface_shaded_get(Object *ob, PointCloud *pointcloud = ob->data; PointCloudBatchCache *cache = pointcloud_batch_cache_get(pointcloud); BLI_assert(cache->mat_len == gpumat_array_len); + UNUSED_VARS(gpumat_array_len); if (cache->surface_per_mat[0] == NULL) { pointcloud_batch_cache_ensure_pos(ob, cache); diff --git a/source/blender/editors/include/ED_uvedit.h b/source/blender/editors/include/ED_uvedit.h index ec41e785714..1b87fae1bb4 100644 --- a/source/blender/editors/include/ED_uvedit.h +++ b/source/blender/editors/include/ED_uvedit.h @@ -115,51 +115,51 @@ bool uvedit_uv_select_test(const struct Scene *scene, struct BMLoop *l, const int cd_loop_uv_offset); /* uv face */ -bool uvedit_face_select_set(const struct Scene *scene, +void uvedit_face_select_set(const struct Scene *scene, struct BMEditMesh *em, struct BMFace *efa, const bool select, const bool do_history, const int cd_loop_uv_offset); -bool uvedit_face_select_enable(const struct Scene *scene, +void uvedit_face_select_enable(const struct Scene *scene, struct BMEditMesh *em, struct BMFace *efa, const bool do_history, const int cd_loop_uv_offset); -bool uvedit_face_select_disable(const struct Scene *scene, +void uvedit_face_select_disable(const struct Scene *scene, struct BMEditMesh *em, struct BMFace *efa, const int cd_loop_uv_offset); /* uv edge */ -void uvedit_edge_select_set(struct BMEditMesh *em, - const struct Scene *scene, +void uvedit_edge_select_set(const struct Scene *scene, + struct BMEditMesh *em, struct BMLoop *l, const bool select, const bool do_history, const int cd_loop_uv_offset); -void uvedit_edge_select_enable(struct BMEditMesh *em, - const struct Scene *scene, +void uvedit_edge_select_enable(const struct Scene *scene, + struct BMEditMesh *em, struct BMLoop *l, const bool do_history, const int cd_loop_uv_offset); -void uvedit_edge_select_disable(struct BMEditMesh *em, - const struct Scene *scene, +void uvedit_edge_select_disable(const struct Scene *scene, + struct BMEditMesh *em, struct BMLoop *l, const int cd_loop_uv_offset); /* uv vert */ -void uvedit_uv_select_set(struct BMEditMesh *em, - const struct Scene *scene, +void uvedit_uv_select_set(const struct Scene *scene, + struct BMEditMesh *em, struct BMLoop *l, const bool select, const bool do_history, const int cd_loop_uv_offset); -void uvedit_uv_select_enable(struct BMEditMesh *em, - const struct Scene *scene, +void uvedit_uv_select_enable(const struct Scene *scene, + struct BMEditMesh *em, struct BMLoop *l, const bool do_history, const int cd_loop_uv_offset); -void uvedit_uv_select_disable(struct BMEditMesh *em, - const struct Scene *scene, +void uvedit_uv_select_disable(const struct Scene *scene, + struct BMEditMesh *em, struct BMLoop *l, const int cd_loop_uv_offset); diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index 3c0b5bd3027..21696b9c1ab 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -2027,6 +2027,7 @@ void uiTemplateConstraints(uiLayout *UNUSED(layout), bContext *C, bool use_bone_ ScrArea *sa = CTX_wm_area(C); ARegion *region = CTX_wm_region(C); + Object *ob = ED_object_active_context(C); ListBase *constraints = get_constraints(C, use_bone_constraints); /* Switch between the bone panel ID function and the object panel ID function. */ @@ -2042,11 +2043,15 @@ void uiTemplateConstraints(uiLayout *UNUSED(layout), bContext *C, bool use_bone_ char panel_idname[MAX_NAME]; panel_id_func(con, panel_idname); + /* Create custom data RNA pointer. */ + PointerRNA *con_ptr = MEM_mallocN(sizeof(PointerRNA), "panel customdata"); + RNA_pointer_create(&ob->id, &RNA_Constraint, con, con_ptr); + Panel *new_panel = UI_panel_add_instanced( - sa, region, ®ion->panels, panel_idname, i, NULL); + sa, region, ®ion->panels, panel_idname, i, con_ptr); + if (new_panel) { - /* Set the list panel functionality function pointers since we don't do it with - * python. */ + /* Set the list panel functionality function pointers since we don't do it with python. */ new_panel->type->set_list_data_expand_flag = set_constraint_expand_flag; new_panel->type->get_list_data_expand_flag = get_constraint_expand_flag; new_panel->type->reorder = constraint_reorder; @@ -2062,6 +2067,22 @@ void uiTemplateConstraints(uiLayout *UNUSED(layout), bContext *C, bool use_bone_ UI_panel_set_expand_from_list_data(C, panel); } } + + /* Assuming there's only one group of instanced panels, update the custom data pointers. */ + Panel *panel = region->panels.first; + LISTBASE_FOREACH (bConstraint *, con, constraints) { + /* Move to the next instanced panel corresponding to the next constraint. */ + while ((panel->type == NULL) || !(panel->type->flag & PNL_INSTANCED)) { + panel = panel->next; + BLI_assert(panel != NULL); /* There shouldn't be fewer panels than constraint panels. */ + } + + PointerRNA *con_ptr = MEM_mallocN(sizeof(PointerRNA), "constraint panel customdata"); + RNA_pointer_create(&ob->id, &RNA_Constraint, con, con_ptr); + UI_panel_custom_data_set(panel, con_ptr); + + panel = panel->next; + } } } diff --git a/source/blender/editors/object/object_constraint.c b/source/blender/editors/object/object_constraint.c index 90ea71ae5c5..bcb1b8afbdd 100644 --- a/source/blender/editors/object/object_constraint.c +++ b/source/blender/editors/object/object_constraint.c @@ -702,7 +702,17 @@ static void edit_constraint_properties(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_HIDDEN); } -static bool edit_constraint_invoke_properties(bContext *C, wmOperator *op) +static void edit_constraint_report_property(wmOperatorType *ot) +{ + PropertyRNA *prop = RNA_def_boolean( + ot->srna, "report", false, "Report", "Create a notification after the operation"); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); +} + +static bool edit_constraint_invoke_properties(bContext *C, + wmOperator *op, + const wmEvent *event, + int *r_retval) { PointerRNA ptr = CTX_data_pointer_get_type(C, "constraint", &RNA_Constraint); Object *ob = (ptr.owner_id) ? (Object *)ptr.owner_id : ED_object_active_context(C); @@ -730,6 +740,31 @@ static bool edit_constraint_invoke_properties(bContext *C, wmOperator *op) return true; } + /* Check the custom data of panels under the mouse for a modifier. */ + if (event != NULL) { + PointerRNA *panel_ptr = UI_region_panel_custom_data_under_cursor(C, event); + + if (!(panel_ptr == NULL || RNA_pointer_is_null(panel_ptr))) { + if (RNA_struct_is_a(panel_ptr->type, &RNA_Constraint)) { + con = panel_ptr->data; + RNA_string_set(op->ptr, "constraint", con->name); + list = ED_object_constraint_list_from_constraint(ob, con, NULL); + RNA_enum_set(op->ptr, + "owner", + (&ob->constraints == list) ? EDIT_CONSTRAINT_OWNER_OBJECT : + EDIT_CONSTRAINT_OWNER_BONE); + + return true; + } + + BLI_assert(r_retval != NULL); /* We need the return value in this case. */ + if (r_retval != NULL) { + *r_retval = (OPERATOR_PASS_THROUGH | OPERATOR_CANCELLED); + } + return false; + } + } + return false; } @@ -813,7 +848,7 @@ static int stretchto_reset_exec(bContext *C, wmOperator *op) static int stretchto_reset_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - if (edit_constraint_invoke_properties(C, op)) { + if (edit_constraint_invoke_properties(C, op, NULL, NULL)) { return stretchto_reset_exec(C, op); } return OPERATOR_CANCELLED; @@ -868,7 +903,7 @@ static int limitdistance_reset_exec(bContext *C, wmOperator *op) static int limitdistance_reset_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - if (edit_constraint_invoke_properties(C, op)) { + if (edit_constraint_invoke_properties(C, op, NULL, NULL)) { return limitdistance_reset_exec(C, op); } return OPERATOR_CANCELLED; @@ -946,7 +981,7 @@ static int childof_set_inverse_exec(bContext *C, wmOperator *op) static int childof_set_inverse_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - if (edit_constraint_invoke_properties(C, op)) { + if (edit_constraint_invoke_properties(C, op, NULL, NULL)) { return childof_set_inverse_exec(C, op); } return OPERATOR_CANCELLED; @@ -995,7 +1030,7 @@ static int childof_clear_inverse_exec(bContext *C, wmOperator *op) static int childof_clear_inverse_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - if (edit_constraint_invoke_properties(C, op)) { + if (edit_constraint_invoke_properties(C, op, NULL, NULL)) { return childof_clear_inverse_exec(C, op); } return OPERATOR_CANCELLED; @@ -1120,7 +1155,7 @@ static int followpath_path_animate_invoke(bContext *C, const wmEvent *UNUSED(event)) { /* hook up invoke properties for figuring out which constraint we're dealing with */ - if (edit_constraint_invoke_properties(C, op)) { + if (edit_constraint_invoke_properties(C, op, NULL, NULL)) { return followpath_path_animate_exec(C, op); } return OPERATOR_CANCELLED; @@ -1201,7 +1236,7 @@ static int objectsolver_set_inverse_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - if (edit_constraint_invoke_properties(C, op)) { + if (edit_constraint_invoke_properties(C, op, NULL, NULL)) { return objectsolver_set_inverse_exec(C, op); } return OPERATOR_CANCELLED; @@ -1257,7 +1292,7 @@ static int objectsolver_clear_inverse_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - if (edit_constraint_invoke_properties(C, op)) { + if (edit_constraint_invoke_properties(C, op, NULL, NULL)) { return objectsolver_clear_inverse_exec(C, op); } return OPERATOR_CANCELLED; @@ -1374,26 +1409,23 @@ void ED_object_constraint_dependency_tag_update(Main *bmain, Object *ob, bConstr DEG_relations_tag_update(bmain); } -static bool constraint_poll(bContext *C) -{ - PointerRNA ptr = CTX_data_pointer_get_type(C, "constraint", &RNA_Constraint); - return (ptr.owner_id && ptr.data); -} - /** \} */ /* ------------------------------------------------------------------- */ /** \name Delete Constraint Operator * \{ */ -static int constraint_delete_exec(bContext *C, wmOperator *UNUSED(op)) +static int constraint_delete_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); - PointerRNA ptr = CTX_data_pointer_get_type(C, "constraint", &RNA_Constraint); - Object *ob = (Object *)ptr.owner_id; - bConstraint *con = ptr.data; + Object *ob = ED_object_active_context(C); + bConstraint *con = edit_constraint_property_get(op, ob, 0); ListBase *lb = ED_object_constraint_list_from_constraint(ob, con, NULL); + /* Store name temporarily for report. */ + char name[MAX_NAME]; + strcpy(name, con->name); + /* free the constraint */ if (BKE_constraint_remove_ex(lb, ob, con, true)) { /* there's no active constraint now, so make sure this is the case */ @@ -1407,12 +1439,25 @@ static int constraint_delete_exec(bContext *C, wmOperator *UNUSED(op)) /* notifiers */ WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT | NA_REMOVED, ob); + if (RNA_boolean_get(op->ptr, "report")) { + BKE_reportf(op->reports, RPT_INFO, "Removed constraint: %s", name); + } + return OPERATOR_FINISHED; } /* couldn't remove due to some invalid data */ return OPERATOR_CANCELLED; } +static int constraint_delete_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + int retval; + if (edit_constraint_invoke_properties(C, op, event, &retval)) { + return constraint_delete_exec(C, op); + } + return OPERATOR_CANCELLED; +} + void CONSTRAINT_OT_delete(wmOperatorType *ot) { /* identifiers */ @@ -1421,11 +1466,14 @@ void CONSTRAINT_OT_delete(wmOperatorType *ot) ot->description = "Remove constraint from constraint stack"; /* callbacks */ + ot->invoke = constraint_delete_invoke; ot->exec = constraint_delete_exec; - ot->poll = constraint_poll; + ot->poll = edit_constraint_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + edit_constraint_properties(ot); + edit_constraint_report_property(ot); } /** \} */ @@ -1455,12 +1503,13 @@ static int constraint_move_down_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } -static int constraint_move_down_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +static int constraint_move_down_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - if (edit_constraint_invoke_properties(C, op)) { + int retval; + if (edit_constraint_invoke_properties(C, op, event, &retval)) { return constraint_move_down_exec(C, op); } - return OPERATOR_CANCELLED; + return retval; } void CONSTRAINT_OT_move_down(wmOperatorType *ot) @@ -1509,12 +1558,13 @@ static int constraint_move_up_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } -static int constraint_move_up_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +static int constraint_move_up_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - if (edit_constraint_invoke_properties(C, op)) { + int retval; + if (edit_constraint_invoke_properties(C, op, event, &retval)) { return constraint_move_up_exec(C, op); } - return OPERATOR_CANCELLED; + return retval; } void CONSTRAINT_OT_move_up(wmOperatorType *ot) @@ -1565,14 +1615,13 @@ static int constraint_move_to_index_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } -static int constraint_move_to_index_invoke(bContext *C, - wmOperator *op, - const wmEvent *UNUSED(event)) +static int constraint_move_to_index_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - if (edit_constraint_invoke_properties(C, op)) { + int retval; + if (edit_constraint_invoke_properties(C, op, event, &retval)) { return constraint_move_to_index_exec(C, op); } - return OPERATOR_CANCELLED; + return retval; } void CONSTRAINT_OT_move_to_index(wmOperatorType *ot) diff --git a/source/blender/editors/uvedit/uvedit_rip.c b/source/blender/editors/uvedit/uvedit_rip.c index 562f0ce84c1..07bec2da1ae 100644 --- a/source/blender/editors/uvedit/uvedit_rip.c +++ b/source/blender/editors/uvedit/uvedit_rip.c @@ -857,7 +857,7 @@ static bool uv_rip_object(Scene *scene, Object *obedit, const float co[2], const BMLoop *l_iter = BLI_gsetIterator_getKey(&gs_iter); ULData *ul = UL(l_iter); if (ul->side == side_from_cursor) { - uvedit_uv_select_disable(em, scene, l_iter, cd_loop_uv_offset); + uvedit_uv_select_disable(scene, em, l_iter, cd_loop_uv_offset); changed = true; } /* Ensure we don't operate on these again. */ @@ -875,7 +875,7 @@ static bool uv_rip_object(Scene *scene, Object *obedit, const float co[2], const BMLoop *l_iter = BLI_gsetIterator_getKey(&gs_iter); ULData *ul = UL(l_iter); if (ul->side == side_from_cursor) { - uvedit_uv_select_disable(em, scene, l_iter, cd_loop_uv_offset); + uvedit_uv_select_disable(scene, em, l_iter, cd_loop_uv_offset); changed = true; } /* Ensure we don't operate on these again. */ diff --git a/source/blender/editors/uvedit/uvedit_select.c b/source/blender/editors/uvedit/uvedit_select.c index ddb276a663a..12b2207b62b 100644 --- a/source/blender/editors/uvedit/uvedit_select.c +++ b/source/blender/editors/uvedit/uvedit_select.c @@ -161,7 +161,7 @@ static void uvedit_vertex_select_tagged(BMEditMesh *em, BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { if (BM_elem_flag_test(l->v, BM_ELEM_TAG)) { - uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); + uvedit_uv_select_set(scene, em, l, select, false, cd_loop_uv_offset); } } } @@ -202,7 +202,7 @@ bool uvedit_face_select_test(const Scene *scene, BMFace *efa, const int cd_loop_ return uvedit_face_select_test_ex(scene->toolsettings, efa, cd_loop_uv_offset); } -bool uvedit_face_select_set(const struct Scene *scene, +void uvedit_face_select_set(const struct Scene *scene, struct BMEditMesh *em, struct BMFace *efa, const bool select, @@ -210,12 +210,14 @@ bool uvedit_face_select_set(const struct Scene *scene, const int cd_loop_uv_offset) { if (select) { - return uvedit_face_select_enable(scene, em, efa, do_history, cd_loop_uv_offset); + uvedit_face_select_enable(scene, em, efa, do_history, cd_loop_uv_offset); + } + else { + uvedit_face_select_disable(scene, em, efa, cd_loop_uv_offset); } - return uvedit_face_select_disable(scene, em, efa, cd_loop_uv_offset); } -bool uvedit_face_select_enable(const Scene *scene, +void uvedit_face_select_enable(const Scene *scene, BMEditMesh *em, BMFace *efa, const bool do_history, @@ -238,14 +240,10 @@ bool uvedit_face_select_enable(const Scene *scene, luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); luv->flag |= MLOOPUV_VERTSEL; } - - return true; } - - return false; } -bool uvedit_face_select_disable(const Scene *scene, +void uvedit_face_select_disable(const Scene *scene, BMEditMesh *em, BMFace *efa, const int cd_loop_uv_offset) @@ -264,11 +262,7 @@ bool uvedit_face_select_disable(const Scene *scene, luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); luv->flag &= ~MLOOPUV_VERTSEL; } - - return true; } - - return false; } bool uvedit_edge_select_test_ex(const ToolSettings *ts, BMLoop *l, const int cd_loop_uv_offset) @@ -296,8 +290,8 @@ bool uvedit_edge_select_test(const Scene *scene, BMLoop *l, const int cd_loop_uv return uvedit_edge_select_test_ex(scene->toolsettings, l, cd_loop_uv_offset); } -void uvedit_edge_select_set(BMEditMesh *em, - const Scene *scene, +void uvedit_edge_select_set(const Scene *scene, + BMEditMesh *em, BMLoop *l, const bool select, const bool do_history, @@ -305,15 +299,15 @@ void uvedit_edge_select_set(BMEditMesh *em, { if (select) { - uvedit_edge_select_enable(em, scene, l, do_history, cd_loop_uv_offset); + uvedit_edge_select_enable(scene, em, l, do_history, cd_loop_uv_offset); } else { - uvedit_edge_select_disable(em, scene, l, cd_loop_uv_offset); + uvedit_edge_select_disable(scene, em, l, cd_loop_uv_offset); } } -void uvedit_edge_select_enable(BMEditMesh *em, - const Scene *scene, +void uvedit_edge_select_enable(const Scene *scene, + BMEditMesh *em, BMLoop *l, const bool do_history, const int cd_loop_uv_offset) @@ -348,8 +342,8 @@ void uvedit_edge_select_enable(BMEditMesh *em, } } -void uvedit_edge_select_disable(BMEditMesh *em, - const Scene *scene, +void uvedit_edge_select_disable(const Scene *scene, + BMEditMesh *em, BMLoop *l, const int cd_loop_uv_offset) @@ -396,23 +390,23 @@ bool uvedit_uv_select_test(const Scene *scene, BMLoop *l, const int cd_loop_uv_o return uvedit_uv_select_test_ex(scene->toolsettings, l, cd_loop_uv_offset); } -void uvedit_uv_select_set(BMEditMesh *em, - const Scene *scene, +void uvedit_uv_select_set(const Scene *scene, + BMEditMesh *em, BMLoop *l, const bool select, const bool do_history, const int cd_loop_uv_offset) { if (select) { - uvedit_uv_select_enable(em, scene, l, do_history, cd_loop_uv_offset); + uvedit_uv_select_enable(scene, em, l, do_history, cd_loop_uv_offset); } else { - uvedit_uv_select_disable(em, scene, l, cd_loop_uv_offset); + uvedit_uv_select_disable(scene, em, l, cd_loop_uv_offset); } } -void uvedit_uv_select_enable(BMEditMesh *em, - const Scene *scene, +void uvedit_uv_select_enable(const Scene *scene, + BMEditMesh *em, BMLoop *l, const bool do_history, const int cd_loop_uv_offset) @@ -437,8 +431,8 @@ void uvedit_uv_select_enable(BMEditMesh *em, } } -void uvedit_uv_select_disable(BMEditMesh *em, - const Scene *scene, +void uvedit_uv_select_disable(const Scene *scene, + BMEditMesh *em, BMLoop *l, const int cd_loop_uv_offset) { @@ -921,7 +915,7 @@ static int uv_select_edgeloop( iterv_curr = uv_select_edgeloop_vertex_map_get(vmap, efa, l); if (iterv_curr->flag) { - uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); + uvedit_uv_select_set(scene, em, l, select, false, cd_loop_uv_offset); } } } @@ -1476,18 +1470,21 @@ void UV_OT_select_all(wmOperatorType *ot) /** \name Mouse Select Operator * \{ */ -static bool uv_sticky_select( - const float *limit, const int hitv[], int v, float *hituv[], float *uv, int sticky, int hitlen) +static bool uv_sticky_select(const float limit[2], + const int hitv[], + int v, + float *hituv[], + const float uv[2], + int sticky, + int hitlen) { - int i; - - /* this function test if some vertex needs to selected + /* This function test if some vertex needs to selected * in addition to the existing ones due to sticky select */ if (sticky == SI_STICKY_DISABLE) { return false; } - for (i = 0; i < hitlen; i++) { + for (int i = 0; i < hitlen; i++) { if (hitv[i] == v) { if (sticky == SI_STICKY_LOC) { if (fabsf(hituv[i][0] - uv[0]) < limit[0] && fabsf(hituv[i][1] - uv[1]) < limit[1]) { @@ -1684,13 +1681,13 @@ static int uv_mouse_select_multi(bContext *C, if (selectmode == UV_SELECT_VERTEX) { /* (de)select uv vertex */ select = !uvedit_uv_select_test(scene, hit.l, cd_loop_uv_offset); - uvedit_uv_select_set(em, scene, hit.l, select, true, cd_loop_uv_offset); + uvedit_uv_select_set(scene, em, hit.l, select, true, cd_loop_uv_offset); flush = 1; } else if (selectmode == UV_SELECT_EDGE) { /* (de)select edge */ select = !(uvedit_edge_select_test(scene, hit.l, cd_loop_uv_offset)); - uvedit_edge_select_set(em, scene, hit.l, select, true, cd_loop_uv_offset); + uvedit_edge_select_set(scene, em, hit.l, select, true, cd_loop_uv_offset); flush = 1; } else if (selectmode == UV_SELECT_FACE) { @@ -1721,7 +1718,7 @@ static int uv_mouse_select_multi(bContext *C, luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); if (uv_sticky_select( limit, hitv, BM_elem_index_get(l->v), hituv, luv->uv, sticky, hitlen)) { - uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); + uvedit_uv_select_set(scene, em, l, select, false, cd_loop_uv_offset); } } } @@ -1735,12 +1732,12 @@ static int uv_mouse_select_multi(bContext *C, if (selectmode == UV_SELECT_VERTEX) { /* select vertex */ - uvedit_uv_select_enable(em, scene, hit.l, true, cd_loop_uv_offset); + uvedit_uv_select_enable(scene, em, hit.l, true, cd_loop_uv_offset); flush = 1; } else if (selectmode == UV_SELECT_EDGE) { /* select edge */ - uvedit_edge_select_enable(em, scene, hit.l, true, cd_loop_uv_offset); + uvedit_edge_select_enable(scene, em, hit.l, true, cd_loop_uv_offset); flush = 1; } else if (selectmode == UV_SELECT_FACE) { @@ -1763,7 +1760,7 @@ static int uv_mouse_select_multi(bContext *C, if (uv_sticky_select( limit, hitv, BM_elem_index_get(l->v), hituv, luv->uv, sticky, hitlen)) { - uvedit_uv_select_enable(em, scene, l, false, cd_loop_uv_offset); + uvedit_uv_select_enable(scene, em, l, false, cd_loop_uv_offset); } flush = 1; @@ -2269,7 +2266,7 @@ static void uv_select_flush_from_tag_sticky_loc_internal(Scene *scene, UvMapVert *start_vlist = NULL, *vlist_iter; BMFace *efa_vlist; - uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); + uvedit_uv_select_set(scene, em, l, select, false, cd_loop_uv_offset); vlist_iter = BM_uv_vert_map_at_index(vmap, BM_elem_index_get(l->v)); @@ -2300,7 +2297,7 @@ static void uv_select_flush_from_tag_sticky_loc_internal(Scene *scene, l_other = BM_iter_at_index( em->bm, BM_LOOPS_OF_FACE, efa_vlist, vlist_iter->loop_of_poly_index); - uvedit_uv_select_set(em, scene, l_other, select, false, cd_loop_uv_offset); + uvedit_uv_select_set(scene, em, l_other, select, false, cd_loop_uv_offset); } vlist_iter = vlist_iter->next; } @@ -2353,7 +2350,7 @@ static void uv_select_flush_from_tag_face(SpaceImage *sima, BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { if (BM_elem_flag_test(l->v, BM_ELEM_TAG)) { - uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); + uvedit_uv_select_set(scene, em, l, select, false, cd_loop_uv_offset); } } } @@ -2440,7 +2437,7 @@ static void uv_select_flush_from_tag_loop(SpaceImage *sima, BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { if (BM_elem_flag_test(l->v, BM_ELEM_TAG)) { - uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); + uvedit_uv_select_set(scene, em, l, select, false, cd_loop_uv_offset); } } } @@ -2474,7 +2471,7 @@ static void uv_select_flush_from_tag_loop(SpaceImage *sima, BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { if (BM_elem_flag_test(l, BM_ELEM_TAG)) { - uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); + uvedit_uv_select_set(scene, em, l, select, false, cd_loop_uv_offset); } } } @@ -2582,8 +2579,8 @@ static int uv_box_select_exec(bContext *C, wmOperator *op) if ((select != luv_select) || (select != luv_select_prev)) { if (BLI_rctf_isect_pt_v(&rectf, luv->uv) && BLI_rctf_isect_pt_v(&rectf, luv_prev->uv)) { - uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); - uvedit_uv_select_set(em, scene, l_prev, select, false, cd_loop_uv_offset); + uvedit_uv_select_set(scene, em, l, select, false, cd_loop_uv_offset); + uvedit_uv_select_set(scene, em, l_prev, select, false, cd_loop_uv_offset); BM_elem_flag_enable(l->v, BM_ELEM_TAG); BM_elem_flag_enable(l_prev->v, BM_ELEM_TAG); } @@ -2614,14 +2611,14 @@ static int uv_box_select_exec(bContext *C, wmOperator *op) if (!pinned || (ts->uv_flag & UV_SYNC_SELECTION)) { /* UV_SYNC_SELECTION - can't do pinned selection */ if (BLI_rctf_isect_pt_v(&rectf, luv->uv)) { - uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); + uvedit_uv_select_set(scene, em, l, select, false, cd_loop_uv_offset); BM_elem_flag_enable(l->v, BM_ELEM_TAG); has_selected = true; } } else if (pinned) { if ((luv->flag & MLOOPUV_PINNED) && BLI_rctf_isect_pt_v(&rectf, luv->uv)) { - uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); + uvedit_uv_select_set(scene, em, l, select, false, cd_loop_uv_offset); BM_elem_flag_enable(l->v, BM_ELEM_TAG); } } @@ -2815,8 +2812,8 @@ static int uv_circle_select_exec(bContext *C, wmOperator *op) if ((select != luv_select) || (select != luv_select_prev)) { if (uv_circle_select_is_edge_inside(luv->uv, luv_prev->uv, offset, ellipse)) { changed = true; - uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); - uvedit_uv_select_set(em, scene, l_prev, select, false, cd_loop_uv_offset); + uvedit_uv_select_set(scene, em, l, select, false, cd_loop_uv_offset); + uvedit_uv_select_set(scene, em, l_prev, select, false, cd_loop_uv_offset); BM_elem_flag_enable(l->v, BM_ELEM_TAG); BM_elem_flag_enable(l_prev->v, BM_ELEM_TAG); } @@ -2844,7 +2841,7 @@ static int uv_circle_select_exec(bContext *C, wmOperator *op) luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); if (uv_circle_select_is_point_inside(luv->uv, offset, ellipse)) { changed = true; - uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); + uvedit_uv_select_set(scene, em, l, select, false, cd_loop_uv_offset); BM_elem_flag_enable(l->v, BM_ELEM_TAG); has_selected = true; } @@ -3012,8 +3009,8 @@ static bool do_lasso_select_mesh_uv(bContext *C, region, &rect, mcoords, mcoords_len, luv->uv) && do_lasso_select_mesh_uv_is_point_inside( region, &rect, mcoords, mcoords_len, luv_prev->uv)) { - uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); - uvedit_uv_select_set(em, scene, l_prev, select, false, cd_loop_uv_offset); + uvedit_uv_select_set(scene, em, l, select, false, cd_loop_uv_offset); + uvedit_uv_select_set(scene, em, l_prev, select, false, cd_loop_uv_offset); changed = true; BM_elem_flag_enable(l->v, BM_ELEM_TAG); BM_elem_flag_enable(l_prev->v, BM_ELEM_TAG); @@ -3042,7 +3039,7 @@ static bool do_lasso_select_mesh_uv(bContext *C, MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); if (do_lasso_select_mesh_uv_is_point_inside( region, &rect, mcoords, mcoords_len, luv->uv)) { - uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); + uvedit_uv_select_set(scene, em, l, select, false, cd_loop_uv_offset); changed = true; BM_elem_flag_enable(l->v, BM_ELEM_TAG); has_selected = true; @@ -3149,7 +3146,7 @@ static int uv_select_pinned_exec(bContext *C, wmOperator *UNUSED(op)) luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); if (luv->flag & MLOOPUV_PINNED) { - uvedit_uv_select_enable(em, scene, l, false, cd_loop_uv_offset); + uvedit_uv_select_enable(scene, em, l, false, cd_loop_uv_offset); changed = true; } } diff --git a/source/blender/editors/uvedit/uvedit_smart_stitch.c b/source/blender/editors/uvedit/uvedit_smart_stitch.c index 29e10f03e3c..f649ee528d4 100644 --- a/source/blender/editors/uvedit/uvedit_smart_stitch.c +++ b/source/blender/editors/uvedit/uvedit_smart_stitch.c @@ -981,7 +981,7 @@ static void stitch_propagate_uv_final_position(Scene *scene, if (final) { copy_v2_v2(luv->uv, final_position[index].uv); - uvedit_uv_select_enable(state->em, scene, l, false, cd_loop_uv_offset); + uvedit_uv_select_enable(scene, state->em, l, false, cd_loop_uv_offset); } else { int face_preview_pos = diff --git a/source/blender/functions/CMakeLists.txt b/source/blender/functions/CMakeLists.txt index 0ec531dea0d..2686275e898 100644 --- a/source/blender/functions/CMakeLists.txt +++ b/source/blender/functions/CMakeLists.txt @@ -38,7 +38,6 @@ set(SRC FN_array_spans.hh FN_attributes_ref.hh FN_cpp_type.hh - FN_cpp_types.hh FN_generic_vector_array.hh FN_multi_function.hh FN_multi_function_builder.hh diff --git a/source/blender/functions/FN_cpp_type.hh b/source/blender/functions/FN_cpp_type.hh index 7ec60809194..ce02bfd05be 100644 --- a/source/blender/functions/FN_cpp_type.hh +++ b/source/blender/functions/FN_cpp_type.hh @@ -788,15 +788,12 @@ inline std::unique_ptr<const CPPType> create_cpp_type(StringRef name, const T &d } // namespace blender::fn #define MAKE_CPP_TYPE(IDENTIFIER, TYPE_NAME) \ - static TYPE_NAME default_value_##IDENTIFIER; \ - static std::unique_ptr<const blender::fn::CPPType> CPPTYPE_##IDENTIFIER##_owner = \ - blender::fn::create_cpp_type<TYPE_NAME>(STRINGIFY(IDENTIFIER), default_value_##IDENTIFIER); \ - const blender::fn::CPPType &CPPType_##IDENTIFIER = *CPPTYPE_##IDENTIFIER##_owner; \ template<> const blender::fn::CPPType &blender::fn::CPPType::get<TYPE_NAME>() \ { \ - /* This can happen when trying to access a CPPType during static storage initialization. */ \ - BLI_assert(CPPTYPE_##IDENTIFIER##_owner.get() != nullptr); \ - return CPPType_##IDENTIFIER; \ + static TYPE_NAME default_value; \ + static std::unique_ptr<const CPPType> cpp_type = blender::fn::create_cpp_type<TYPE_NAME>( \ + STRINGIFY(IDENTIFIER), default_value); \ + return *cpp_type; \ } #endif /* __FN_CPP_TYPE_HH__ */ diff --git a/source/blender/functions/intern/cpp_types.cc b/source/blender/functions/intern/cpp_types.cc index 052278afd65..3bf4683d815 100644 --- a/source/blender/functions/intern/cpp_types.cc +++ b/source/blender/functions/intern/cpp_types.cc @@ -14,7 +14,7 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include "FN_cpp_types.hh" +#include "FN_cpp_type.hh" #include "BLI_color.hh" #include "BLI_float2.hh" diff --git a/source/blender/gpu/intern/gpu_framebuffer.c b/source/blender/gpu/intern/gpu_framebuffer.c index 366a1d17d69..40c1e6f59b2 100644 --- a/source/blender/gpu/intern/gpu_framebuffer.c +++ b/source/blender/gpu/intern/gpu_framebuffer.c @@ -683,6 +683,10 @@ static void gpu_framebuffer_read_color_ex( { GLenum type = gpu_get_gl_channel_type(channels); GLenum gl_format = gpu_get_gl_datatype(format); + /* TODO: needed for selection buffers to work properly, this should be handled better. */ + if (type == GL_RED && gl_format == GL_UNSIGNED_INT) { + type = GL_RED_INTEGER; + } glReadBuffer(readfb); glReadPixels(x, y, w, h, type, gl_format, data); } @@ -1075,4 +1079,4 @@ void GPU_frontbuffer_read_pixels( { glReadBuffer(GL_FRONT); gpu_framebuffer_read_color_ex(x, y, w, h, channels, GL_FRONT, format, data); -}
\ No newline at end of file +} diff --git a/source/blender/io/common/CMakeLists.txt b/source/blender/io/common/CMakeLists.txt index 708f24ca0e2..a6975863413 100644 --- a/source/blender/io/common/CMakeLists.txt +++ b/source/blender/io/common/CMakeLists.txt @@ -48,3 +48,16 @@ set(LIB blender_add_lib(bf_io_common "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") target_link_libraries(bf_io_common INTERFACE) + +if(WITH_GTESTS) + set(TEST_SRC + intern/abstract_hierarchy_iterator_test.cc + intern/hierarchy_context_order_test.cc + intern/object_identifier_test.cc + ) + set(TEST_LIB + bf_blenloader_test + ) + include(GTestTesting) + blender_add_test_lib(bf_io_common_tests "${TEST_SRC}" "${INC};${TEST_INC}" "${INC_SYS}" "${LIB};${TEST_LIB}") +endif() diff --git a/tests/gtests/usd/abstract_hierarchy_iterator_test.cc b/source/blender/io/common/intern/abstract_hierarchy_iterator_test.cc index d9148a7b289..266c865ee52 100644 --- a/tests/gtests/usd/abstract_hierarchy_iterator_test.cc +++ b/source/blender/io/common/intern/abstract_hierarchy_iterator_test.cc @@ -19,21 +19,21 @@ #include "IO_abstract_hierarchy_iterator.h" #include "blenloader/blendfile_loading_base_test.h" -extern "C" { #include "BLI_math.h" #include "DEG_depsgraph.h" #include "DNA_object_types.h" -} #include <map> #include <set> +namespace blender::io { + +namespace { + /* Mapping from ID.name to set of export hierarchy path. Duplicated objects can be exported * multiple times with different export paths, hence the set. */ typedef std::map<std::string, std::set<std::string>> used_writers; -using namespace blender::io; - class TestHierarchyWriter : public AbstractHierarchyWriter { public: std::string writer_type; @@ -57,16 +57,7 @@ class TestHierarchyWriter : public AbstractHierarchyWriter { } }; -void debug_print_writers(const char *label, const used_writers &writers_map) -{ - printf("%s:\n", label); - for (auto idname_writers : writers_map) { - printf(" %s:\n", idname_writers.first.c_str()); - for (const std::string &export_path : idname_writers.second) { - printf(" - %s\n", export_path.c_str()); - } - } -} +} // namespace class TestingHierarchyIterator : public AbstractHierarchyIterator { public: /* Public so that the test cases can directly inspect the created writers. */ @@ -75,7 +66,6 @@ class TestingHierarchyIterator : public AbstractHierarchyIterator { used_writers hair_writers; used_writers particle_writers; - public: explicit TestingHierarchyIterator(Depsgraph *depsgraph) : AbstractHierarchyIterator(depsgraph) { } @@ -84,19 +74,19 @@ class TestingHierarchyIterator : public AbstractHierarchyIterator { } protected: - AbstractHierarchyWriter *create_transform_writer(const HierarchyContext *context) override + AbstractHierarchyWriter *create_transform_writer(const HierarchyContext * /*context*/) override { return new TestHierarchyWriter("transform", transform_writers); } - AbstractHierarchyWriter *create_data_writer(const HierarchyContext *context) override + AbstractHierarchyWriter *create_data_writer(const HierarchyContext * /*context*/) override { return new TestHierarchyWriter("data", data_writers); } - AbstractHierarchyWriter *create_hair_writer(const HierarchyContext *context) override + AbstractHierarchyWriter *create_hair_writer(const HierarchyContext * /*context*/) override { return new TestHierarchyWriter("hair", hair_writers); } - AbstractHierarchyWriter *create_particle_writer(const HierarchyContext *context) override + AbstractHierarchyWriter *create_particle_writer(const HierarchyContext * /*context*/) override { return new TestHierarchyWriter("particle", particle_writers); } @@ -325,3 +315,4 @@ TEST_F(USDHierarchyIteratorTest, ExportSubsetTest) EXPECT_EQ(expected_transforms, iterator->transform_writers); EXPECT_EQ(expected_data, iterator->data_writers); } +} // namespace blender::io diff --git a/tests/gtests/usd/hierarchy_context_order_test.cc b/source/blender/io/common/intern/hierarchy_context_order_test.cc index 25cda6d8670..7273b92c479 100644 --- a/tests/gtests/usd/hierarchy_context_order_test.cc +++ b/source/blender/io/common/intern/hierarchy_context_order_test.cc @@ -24,16 +24,20 @@ extern "C" { #include "BLI_utildefines.h" } -using namespace blender::io; +namespace blender::io { -class HierarchyContextOrderTest : public testing::Test { -}; +namespace { -static Object *fake_pointer(int value) +Object *fake_pointer(int value) { return static_cast<Object *>(POINTER_FROM_INT(value)); } +} // namespace + +class HierarchyContextOrderTest : public testing::Test { +}; + TEST_F(HierarchyContextOrderTest, ObjectPointerTest) { HierarchyContext ctx_a = {0}; @@ -121,3 +125,5 @@ TEST_F(HierarchyContextOrderTest, TransitiveTest) EXPECT_FALSE(ctx_d < ctx_b); EXPECT_FALSE(ctx_d < ctx_c); } + +} // namespace blender::io diff --git a/tests/gtests/usd/object_identifier_test.cc b/source/blender/io/common/intern/object_identifier_test.cc index 810d4470260..2b565876f22 100644 --- a/tests/gtests/usd/object_identifier_test.cc +++ b/source/blender/io/common/intern/object_identifier_test.cc @@ -24,8 +24,7 @@ #include <climits> -namespace blender { -namespace io { +namespace blender::io { namespace { @@ -232,5 +231,4 @@ TEST_F(PersistentIDTest, as_object_name_suffix) EXPECT_EQ("-3--2--1", TestPersistentID(-1, -2, -3).as_object_name_suffix()); } -} // namespace io -} // namespace blender +} // namespace blender::io diff --git a/source/blender/io/usd/CMakeLists.txt b/source/blender/io/usd/CMakeLists.txt index 19e16a5b328..79b15c60b94 100644 --- a/source/blender/io/usd/CMakeLists.txt +++ b/source/blender/io/usd/CMakeLists.txt @@ -109,3 +109,15 @@ else() endif() target_link_libraries(bf_usd INTERFACE ${TBB_LIBRARIES}) + +if(WITH_GTESTS) + set(TEST_SRC + tests/usd_stage_creation_test.cc + ) + set(TEST_INC + ) + set(TEST_LIB + ) + include(GTestTesting) + blender_add_test_lib(bf_io_usd_tests "${TEST_SRC}" "${INC};${TEST_INC}" "${INC_SYS}" "${LIB};${TEST_LIB}") +endif() diff --git a/tests/gtests/usd/usd_stage_creation_test.cc b/source/blender/io/usd/tests/usd_stage_creation_test.cc index b262e21f053..d41ae6c4f26 100644 --- a/tests/gtests/usd/usd_stage_creation_test.cc +++ b/source/blender/io/usd/tests/usd_stage_creation_test.cc @@ -21,28 +21,32 @@ #include <string> -extern "C" { #include "BLI_path_util.h" #include "BLI_utildefines.h" #include "BKE_appdir.h" +extern "C" { /* Workaround to make it possible to pass a path at runtime to USD. See creator.c. */ void usd_initialise_plugin_path(const char *datafiles_usd_path); } -DEFINE_string(test_usd_datafiles_dir, "", "The bin/{BLENDER_VERSION}/datafiles/usd directory."); +namespace blender::io::usd { class USDStageCreationTest : public testing::Test { }; TEST_F(USDStageCreationTest, JSONFileLoadingTest) { - if (FLAGS_test_usd_datafiles_dir.empty()) { - FAIL() << "Pass the --test-usd-datafiles-dir flag"; + const std::string &release_dir = blender::tests::flags_test_release_dir(); + if (release_dir.empty()) { + FAIL(); } - usd_initialise_plugin_path(FLAGS_test_usd_datafiles_dir.c_str()); + char usd_datafiles_dir[FILE_MAX]; + BLI_path_join(usd_datafiles_dir, FILE_MAX, release_dir.c_str(), "datafiles", "usd", nullptr); + + usd_initialise_plugin_path(usd_datafiles_dir); /* Simply the ability to create a USD Stage for a specific filename means that the extension * has been recognised by the USD library, and that a USD plugin has been loaded to write such @@ -60,3 +64,5 @@ TEST_F(USDStageCreationTest, JSONFileLoadingTest) FAIL() << "unable to find suitable USD plugin to write " << filename; } } + +} // namespace blender::io::usd diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt index 9106eacb31a..b3cb8163f2a 100644 --- a/source/blender/nodes/CMakeLists.txt +++ b/source/blender/nodes/CMakeLists.txt @@ -273,9 +273,12 @@ set(SRC texture/node_texture_tree.c texture/node_texture_util.c + intern/derived_node_tree.cc intern/node_common.c intern/node_exec.c intern/node_socket.cc + intern/node_tree_multi_function.cc + intern/node_tree_ref.cc intern/node_util.c composite/node_composite_util.h @@ -286,7 +289,10 @@ set(SRC NOD_common.h NOD_composite.h + NOD_derived_node_tree.hh NOD_function.h + NOD_node_tree_multi_function.hh + NOD_node_tree_ref.hh NOD_shader.h NOD_simulation.h NOD_socket.h diff --git a/source/blender/blenkernel/BKE_derived_node_tree.hh b/source/blender/nodes/NOD_derived_node_tree.hh index 083057835a5..84370dcd399 100644 --- a/source/blender/blenkernel/BKE_derived_node_tree.hh +++ b/source/blender/nodes/NOD_derived_node_tree.hh @@ -14,11 +14,11 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifndef __BKE_DERIVED_NODE_TREE_HH__ -#define __BKE_DERIVED_NODE_TREE_HH__ +#ifndef __NOD_DERIVED_NODE_TREE_HH__ +#define __NOD_DERIVED_NODE_TREE_HH__ /** \file - * \ingroup bke + * \ingroup nodes * * DerivedNodeTree provides a flattened view on a bNodeTree, i.e. node groups are inlined. It * builds on top of NodeTreeRef and supports similar queries efficiently. @@ -30,9 +30,9 @@ * There is a dot graph exporter for debugging purposes. */ -#include "BKE_node_tree_ref.hh" +#include "NOD_node_tree_ref.hh" -namespace blender::bke { +namespace blender::nodes { class DSocket; class DInputSocket; @@ -477,7 +477,7 @@ inline Span<const DNode *> DerivedNodeTree::nodes() const inline Span<const DNode *> DerivedNodeTree::nodes_by_type(StringRefNull idname) const { - const bNodeType *nodetype = nodeTypeFind(idname.data()); + const bNodeType *nodetype = nodeTypeFind(idname.c_str()); return this->nodes_by_type(nodetype); } @@ -512,6 +512,6 @@ inline Span<const DGroupInput *> DerivedNodeTree::group_inputs() const return group_inputs_; } -} // namespace blender::bke +} // namespace blender::nodes -#endif /* __BKE_DERIVED_NODE_TREE_HH__ */ +#endif /* __NOD_DERIVED_NODE_TREE_HH__ */ diff --git a/source/blender/blenkernel/BKE_node_tree_multi_function.hh b/source/blender/nodes/NOD_node_tree_multi_function.hh index 7219eb1726a..f7a1fbb114d 100644 --- a/source/blender/blenkernel/BKE_node_tree_multi_function.hh +++ b/source/blender/nodes/NOD_node_tree_multi_function.hh @@ -14,11 +14,11 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifndef __BKE_NODE_TREE_FUNCTION_HH__ -#define __BKE_NODE_TREE_FUNCTION_HH__ +#ifndef __NOD_NODE_TREE_FUNCTION_HH__ +#define __NOD_NODE_TREE_FUNCTION_HH__ /** \file - * \ingroup bke + * \ingroup nodes * * This file allows you to generate a multi-function network from a user-generated node tree. */ @@ -26,12 +26,11 @@ #include "FN_multi_function_builder.hh" #include "FN_multi_function_network.hh" -#include "BKE_derived_node_tree.hh" +#include "NOD_derived_node_tree.hh" #include "BLI_resource_collector.hh" -namespace blender { -namespace bke { +namespace blender::nodes { /* Maybe this should be moved to BKE_node.h. */ inline bool is_multi_function_data_socket(const bNodeSocket *bsocket) @@ -44,7 +43,7 @@ inline bool is_multi_function_data_socket(const bNodeSocket *bsocket) } /** - * A MFNetworkTreeMap maps various components of a bke::DerivedNodeTree to components of a + * A MFNetworkTreeMap maps various components of a DerivedNodeTree to components of a * fn::MFNetwork. This is necessary for further processing of a multi-function network that has * been generated from a node tree. */ @@ -241,7 +240,7 @@ class MFNetworkBuilderBase { BLI_STATIC_ASSERT((std::is_base_of_v<fn::MultiFunction, T>), ""); void *buffer = common_.resources.linear_allocator().allocate(sizeof(T), alignof(T)); T *fn = new (buffer) T(std::forward<Args>(args)...); - common_.resources.add(destruct_ptr<T>(fn), fn->name().data()); + common_.resources.add(destruct_ptr<T>(fn), fn->name().c_str()); return *fn; } }; @@ -384,7 +383,6 @@ MFNetworkTreeMap insert_node_tree_into_mf_network(fn::MFNetwork &network, const DerivedNodeTree &tree, ResourceCollector &resources); -} // namespace bke -} // namespace blender +} // namespace blender::nodes -#endif /* __BKE_NODE_TREE_FUNCTION_HH__ */ +#endif /* __NOD_NODE_TREE_FUNCTION_HH__ */ diff --git a/source/blender/blenkernel/BKE_node_tree_ref.hh b/source/blender/nodes/NOD_node_tree_ref.hh index b1e8904d718..907184125b8 100644 --- a/source/blender/blenkernel/BKE_node_tree_ref.hh +++ b/source/blender/nodes/NOD_node_tree_ref.hh @@ -14,11 +14,11 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifndef __BKE_NODE_TREE_REF_HH__ -#define __BKE_NODE_TREE_REF_HH__ +#ifndef __NOD_NODE_TREE_REF_HH__ +#define __NOD_NODE_TREE_REF_HH__ /** \file - * \ingroup bke + * \ingroup nodes * * NodeTreeRef makes querying information about a bNodeTree more efficient. It is an immutable data * structure. It should not be used after anymore, after the underlying node tree changed. @@ -58,7 +58,7 @@ #include "RNA_access.h" -namespace blender::bke { +namespace blender::nodes { class SocketRef; class InputSocketRef; @@ -405,7 +405,7 @@ inline Span<const NodeRef *> NodeTreeRef::nodes() const inline Span<const NodeRef *> NodeTreeRef::nodes_by_type(StringRefNull idname) const { - const bNodeType *nodetype = nodeTypeFind(idname.data()); + const bNodeType *nodetype = nodeTypeFind(idname.c_str()); return this->nodes_by_type(nodetype); } @@ -440,6 +440,6 @@ inline bNodeTree *NodeTreeRef::btree() const return btree_; } -} // namespace blender::bke +} // namespace blender::nodes -#endif /* __BKE_NODE_TREE_REF_HH__ */ +#endif /* __NOD_NODE_TREE_REF_HH__ */ diff --git a/source/blender/nodes/function/node_function_util.hh b/source/blender/nodes/function/node_function_util.hh index 938cb5dd593..8e09ab0f24f 100644 --- a/source/blender/nodes/function/node_function_util.hh +++ b/source/blender/nodes/function/node_function_util.hh @@ -27,11 +27,11 @@ #include "DNA_node_types.h" #include "BKE_node.h" -#include "BKE_node_tree_multi_function.hh" #include "BLT_translation.h" #include "NOD_function.h" +#include "NOD_node_tree_multi_function.hh" #include "node_util.h" diff --git a/source/blender/nodes/function/nodes/node_fn_boolean_math.cc b/source/blender/nodes/function/nodes/node_fn_boolean_math.cc index 3a145311a08..231771abbfa 100644 --- a/source/blender/nodes/function/nodes/node_fn_boolean_math.cc +++ b/source/blender/nodes/function/nodes/node_fn_boolean_math.cc @@ -71,7 +71,7 @@ static const blender::fn::MultiFunction &get_multi_function(bNode &bnode) return blender::fn::dummy_multi_function; } -static void node_boolean_expand_in_mf_network(blender::bke::NodeMFNetworkBuilder &builder) +static void node_boolean_expand_in_mf_network(blender::nodes::NodeMFNetworkBuilder &builder) { const blender::fn::MultiFunction &fn = get_multi_function(builder.bnode()); builder.set_matching_fn(fn); diff --git a/source/blender/nodes/function/nodes/node_fn_combine_strings.cc b/source/blender/nodes/function/nodes/node_fn_combine_strings.cc index a880933bc12..a545c4f0749 100644 --- a/source/blender/nodes/function/nodes/node_fn_combine_strings.cc +++ b/source/blender/nodes/function/nodes/node_fn_combine_strings.cc @@ -28,7 +28,7 @@ static bNodeSocketTemplate fn_node_combine_strings_out[] = { }; static void fn_node_combine_strings_expand_in_mf_network( - blender::bke::NodeMFNetworkBuilder &builder) + blender::nodes::NodeMFNetworkBuilder &builder) { static blender::fn::CustomMF_SI_SI_SO<std::string, std::string, std::string> combine_fn{ "Combine Strings", [](const std::string &a, const std::string &b) { return a + b; }}; diff --git a/source/blender/nodes/function/nodes/node_fn_float_compare.cc b/source/blender/nodes/function/nodes/node_fn_float_compare.cc index fb2c4d88caf..f8bd9a30940 100644 --- a/source/blender/nodes/function/nodes/node_fn_float_compare.cc +++ b/source/blender/nodes/function/nodes/node_fn_float_compare.cc @@ -90,7 +90,7 @@ static const blender::fn::MultiFunction &get_multi_function(bNode &node) return blender::fn::dummy_multi_function; } -static void node_float_compare_expand_in_mf_network(blender::bke::NodeMFNetworkBuilder &builder) +static void node_float_compare_expand_in_mf_network(blender::nodes::NodeMFNetworkBuilder &builder) { const blender::fn::MultiFunction &fn = get_multi_function(builder.bnode()); builder.set_matching_fn(fn); diff --git a/source/blender/nodes/function/nodes/node_fn_group_instance_id.cc b/source/blender/nodes/function/nodes/node_fn_group_instance_id.cc index c61c941ee0d..1e22cde721d 100644 --- a/source/blender/nodes/function/nodes/node_fn_group_instance_id.cc +++ b/source/blender/nodes/function/nodes/node_fn_group_instance_id.cc @@ -22,11 +22,11 @@ static bNodeSocketTemplate fn_node_group_instance_id_out[] = { }; static void fn_node_group_instance_id_expand_in_mf_network( - blender::bke::NodeMFNetworkBuilder &builder) + blender::nodes::NodeMFNetworkBuilder &builder) { - const blender::bke::DNode &node = builder.dnode(); + const blender::nodes::DNode &node = builder.dnode(); std::string id = "/"; - for (const blender::bke::DParentNode *parent = node.parent(); parent; + for (const blender::nodes::DParentNode *parent = node.parent(); parent; parent = parent->parent()) { id = "/" + parent->node_ref().name() + id; } diff --git a/source/blender/blenkernel/intern/derived_node_tree.cc b/source/blender/nodes/intern/derived_node_tree.cc index 01317eeb5ce..daec67b53a9 100644 --- a/source/blender/blenkernel/intern/derived_node_tree.cc +++ b/source/blender/nodes/intern/derived_node_tree.cc @@ -14,13 +14,13 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include "BKE_derived_node_tree.hh" +#include "NOD_derived_node_tree.hh" #include "BLI_dot_export.hh" #define UNINITIALIZED_ID UINT32_MAX -namespace blender::bke { +namespace blender::nodes { static const NodeTreeRef &get_tree_ref(NodeTreeRefMap &node_tree_refs, bNodeTree *btree) { @@ -438,4 +438,4 @@ std::string DerivedNodeTree::to_dot() const return digraph.to_dot_string(); } -} // namespace blender::bke +} // namespace blender::nodes diff --git a/source/blender/nodes/intern/node_socket.cc b/source/blender/nodes/intern/node_socket.cc index 02124465dda..3a82438a211 100644 --- a/source/blender/nodes/intern/node_socket.cc +++ b/source/blender/nodes/intern/node_socket.cc @@ -34,13 +34,13 @@ #include "BKE_lib_id.h" #include "BKE_node.h" -#include "BKE_node_tree_multi_function.hh" #include "RNA_access.h" #include "RNA_types.h" #include "MEM_guardedalloc.h" +#include "NOD_node_tree_multi_function.hh" #include "NOD_socket.h" struct bNodeSocket *node_add_socket_from_template(struct bNodeTree *ntree, @@ -517,7 +517,7 @@ static bNodeSocketType *make_socket_type_bool() { bNodeSocketType *socktype = make_standard_socket_type(SOCK_BOOLEAN, PROP_NONE); socktype->get_mf_data_type = []() { return blender::fn::MFDataType::ForSingle<bool>(); }; - socktype->expand_in_mf_network = [](blender::bke::SocketMFNetworkBuilder &builder) { + socktype->expand_in_mf_network = [](blender::nodes::SocketMFNetworkBuilder &builder) { bool value = builder.socket_default_value<bNodeSocketValueBoolean>()->value; builder.set_constant_value(value); }; @@ -528,7 +528,7 @@ static bNodeSocketType *make_socket_type_float(PropertySubType subtype) { bNodeSocketType *socktype = make_standard_socket_type(SOCK_FLOAT, subtype); socktype->get_mf_data_type = []() { return blender::fn::MFDataType::ForSingle<float>(); }; - socktype->expand_in_mf_network = [](blender::bke::SocketMFNetworkBuilder &builder) { + socktype->expand_in_mf_network = [](blender::nodes::SocketMFNetworkBuilder &builder) { float value = builder.socket_default_value<bNodeSocketValueFloat>()->value; builder.set_constant_value(value); }; @@ -539,7 +539,7 @@ static bNodeSocketType *make_socket_type_int(PropertySubType subtype) { bNodeSocketType *socktype = make_standard_socket_type(SOCK_INT, subtype); socktype->get_mf_data_type = []() { return blender::fn::MFDataType::ForSingle<int>(); }; - socktype->expand_in_mf_network = [](blender::bke::SocketMFNetworkBuilder &builder) { + socktype->expand_in_mf_network = [](blender::nodes::SocketMFNetworkBuilder &builder) { int value = builder.socket_default_value<bNodeSocketValueInt>()->value; builder.set_constant_value(value); }; @@ -552,7 +552,7 @@ static bNodeSocketType *make_socket_type_vector(PropertySubType subtype) socktype->get_mf_data_type = []() { return blender::fn::MFDataType::ForSingle<blender::float3>(); }; - socktype->expand_in_mf_network = [](blender::bke::SocketMFNetworkBuilder &builder) { + socktype->expand_in_mf_network = [](blender::nodes::SocketMFNetworkBuilder &builder) { blender::float3 value = builder.socket_default_value<bNodeSocketValueVector>()->value; builder.set_constant_value(value); }; @@ -565,7 +565,7 @@ static bNodeSocketType *make_socket_type_rgba() socktype->get_mf_data_type = []() { return blender::fn::MFDataType::ForSingle<blender::Color4f>(); }; - socktype->expand_in_mf_network = [](blender::bke::SocketMFNetworkBuilder &builder) { + socktype->expand_in_mf_network = [](blender::nodes::SocketMFNetworkBuilder &builder) { blender::Color4f value = builder.socket_default_value<bNodeSocketValueRGBA>()->value; builder.set_constant_value(value); }; @@ -576,7 +576,7 @@ static bNodeSocketType *make_socket_type_string() { bNodeSocketType *socktype = make_standard_socket_type(SOCK_STRING, PROP_NONE); socktype->get_mf_data_type = []() { return blender::fn::MFDataType::ForSingle<std::string>(); }; - socktype->expand_in_mf_network = [](blender::bke::SocketMFNetworkBuilder &builder) { + socktype->expand_in_mf_network = [](blender::nodes::SocketMFNetworkBuilder &builder) { std::string value = builder.socket_default_value<bNodeSocketValueString>()->value; builder.set_constant_value(value); }; diff --git a/source/blender/blenkernel/intern/node_tree_multi_function.cc b/source/blender/nodes/intern/node_tree_multi_function.cc index 537ec056126..f77b19354a4 100644 --- a/source/blender/blenkernel/intern/node_tree_multi_function.cc +++ b/source/blender/nodes/intern/node_tree_multi_function.cc @@ -14,13 +14,12 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include "BKE_node_tree_multi_function.hh" +#include "NOD_node_tree_multi_function.hh" #include "BLI_color.hh" #include "BLI_float3.hh" -namespace blender { -namespace bke { +namespace blender::nodes { /* Maybe this should be moved to BKE_node.h. */ static std::optional<fn::MFDataType> try_get_multi_function_data_type_of_socket( @@ -342,5 +341,4 @@ MFNetworkTreeMap insert_node_tree_into_mf_network(fn::MFNetwork &network, return network_map; } -} // namespace bke -} // namespace blender +} // namespace blender::nodes diff --git a/source/blender/blenkernel/intern/node_tree_ref.cc b/source/blender/nodes/intern/node_tree_ref.cc index 5c998a06cb5..186ca750f10 100644 --- a/source/blender/blenkernel/intern/node_tree_ref.cc +++ b/source/blender/nodes/intern/node_tree_ref.cc @@ -14,11 +14,11 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include "BKE_node_tree_ref.hh" +#include "NOD_node_tree_ref.hh" #include "BLI_dot_export.hh" -namespace blender::bke { +namespace blender::nodes { NodeTreeRef::NodeTreeRef(bNodeTree *btree) : btree_(btree) { @@ -174,4 +174,4 @@ std::string NodeTreeRef::to_dot() const return digraph.to_dot_string(); } -} // namespace blender::bke +} // namespace blender::nodes diff --git a/source/blender/nodes/shader/node_shader_util.h b/source/blender/nodes/shader/node_shader_util.h index 2aed485c8bc..b0ba1ea194f 100644 --- a/source/blender/nodes/shader/node_shader_util.h +++ b/source/blender/nodes/shader/node_shader_util.h @@ -73,7 +73,7 @@ #ifdef __cplusplus # include "FN_multi_function_builder.hh" -# include "BKE_node_tree_multi_function.hh" +# include "NOD_node_tree_multi_function.hh" # include "BLI_color.hh" # include "BLI_float3.hh" diff --git a/source/blender/nodes/shader/nodes/node_shader_map_range.cc b/source/blender/nodes/shader/nodes/node_shader_map_range.cc index 3f8a516c175..b026499ec4b 100644 --- a/source/blender/nodes/shader/nodes/node_shader_map_range.cc +++ b/source/blender/nodes/shader/nodes/node_shader_map_range.cc @@ -128,7 +128,7 @@ class MapRangeFunction : public blender::fn::MultiFunction { } }; -static void sh_node_map_range_expand_in_mf_network(blender::bke::NodeMFNetworkBuilder &builder) +static void sh_node_map_range_expand_in_mf_network(blender::nodes::NodeMFNetworkBuilder &builder) { bNode &bnode = builder.bnode(); bool clamp = bnode.custom1 != 0; diff --git a/source/blender/nodes/shader/nodes/node_shader_math.cc b/source/blender/nodes/shader/nodes/node_shader_math.cc index c6762f17919..c7035da8c70 100644 --- a/source/blender/nodes/shader/nodes/node_shader_math.cc +++ b/source/blender/nodes/shader/nodes/node_shader_math.cc @@ -147,7 +147,7 @@ static int gpu_shader_math(GPUMaterial *mat, } static const blender::fn::MultiFunction &get_base_multi_function( - blender::bke::NodeMFNetworkBuilder &builder) + blender::nodes::NodeMFNetworkBuilder &builder) { const int mode = builder.bnode().custom1; switch (mode) { @@ -347,11 +347,11 @@ static const blender::fn::MultiFunction &get_base_multi_function( } } -static void sh_node_math_expand_in_mf_network(blender::bke::NodeMFNetworkBuilder &builder) +static void sh_node_math_expand_in_mf_network(blender::nodes::NodeMFNetworkBuilder &builder) { const blender::fn::MultiFunction &base_function = get_base_multi_function(builder); - const blender::bke::DNode &dnode = builder.dnode(); + const blender::nodes::DNode &dnode = builder.dnode(); blender::fn::MFNetwork &network = builder.network(); blender::fn::MFFunctionNode &base_node = network.add_function(base_function); diff --git a/source/blender/nodes/shader/nodes/node_shader_sepcombRGB.cc b/source/blender/nodes/shader/nodes/node_shader_sepcombRGB.cc index 8cab115c0b5..4b4b80ea1ad 100644 --- a/source/blender/nodes/shader/nodes/node_shader_sepcombRGB.cc +++ b/source/blender/nodes/shader/nodes/node_shader_sepcombRGB.cc @@ -89,7 +89,7 @@ class SeparateRGBFunction : public blender::fn::MultiFunction { } }; -static void sh_node_seprgb_expand_in_mf_network(blender::bke::NodeMFNetworkBuilder &builder) +static void sh_node_seprgb_expand_in_mf_network(blender::nodes::NodeMFNetworkBuilder &builder) { static SeparateRGBFunction fn; builder.set_matching_fn(fn); @@ -146,7 +146,7 @@ static int gpu_shader_combrgb(GPUMaterial *mat, return GPU_stack_link(mat, node, "combine_rgb", in, out); } -static void sh_node_combrgb_expand_in_mf_network(blender::bke::NodeMFNetworkBuilder &builder) +static void sh_node_combrgb_expand_in_mf_network(blender::nodes::NodeMFNetworkBuilder &builder) { static blender::fn::CustomMF_SI_SI_SI_SO<float, float, float, blender::Color4f> fn{ "Combine RGB", [](float r, float g, float b) { return blender::Color4f(r, g, b, 1.0f); }}; diff --git a/source/blender/nodes/shader/nodes/node_shader_sepcombXYZ.cc b/source/blender/nodes/shader/nodes/node_shader_sepcombXYZ.cc index d9af37ab46b..03e18acc245 100644 --- a/source/blender/nodes/shader/nodes/node_shader_sepcombXYZ.cc +++ b/source/blender/nodes/shader/nodes/node_shader_sepcombXYZ.cc @@ -74,7 +74,7 @@ class MF_SeparateXYZ : public blender::fn::MultiFunction { } }; -static void sh_node_sepxyz_expand_in_mf_network(blender::bke::NodeMFNetworkBuilder &builder) +static void sh_node_sepxyz_expand_in_mf_network(blender::nodes::NodeMFNetworkBuilder &builder) { static MF_SeparateXYZ separate_fn; builder.set_matching_fn(separate_fn); @@ -113,7 +113,7 @@ static int gpu_shader_combxyz(GPUMaterial *mat, return GPU_stack_link(mat, node, "combine_xyz", in, out); } -static void sh_node_combxyz_expand_in_mf_network(blender::bke::NodeMFNetworkBuilder &builder) +static void sh_node_combxyz_expand_in_mf_network(blender::nodes::NodeMFNetworkBuilder &builder) { static blender::fn::CustomMF_SI_SI_SI_SO<float, float, float, blender::float3> fn{ "Combine Vector", [](float x, float y, float z) { return blender::float3(x, y, z); }}; diff --git a/source/blender/nodes/shader/nodes/node_shader_valToRgb.cc b/source/blender/nodes/shader/nodes/node_shader_valToRgb.cc index 76409c836d8..21f15bcf6f4 100644 --- a/source/blender/nodes/shader/nodes/node_shader_valToRgb.cc +++ b/source/blender/nodes/shader/nodes/node_shader_valToRgb.cc @@ -157,7 +157,7 @@ class ColorBandFunction : public blender::fn::MultiFunction { } }; -static void sh_node_valtorgb_expand_in_mf_network(blender::bke::NodeMFNetworkBuilder &builder) +static void sh_node_valtorgb_expand_in_mf_network(blender::nodes::NodeMFNetworkBuilder &builder) { bNode &bnode = builder.bnode(); const ColorBand *color_band = (const ColorBand *)bnode.storage; diff --git a/source/blender/nodes/shader/nodes/node_shader_value.cc b/source/blender/nodes/shader/nodes/node_shader_value.cc index 64701018d63..1d7c3f47233 100644 --- a/source/blender/nodes/shader/nodes/node_shader_value.cc +++ b/source/blender/nodes/shader/nodes/node_shader_value.cc @@ -39,7 +39,7 @@ static int gpu_shader_value(GPUMaterial *mat, return GPU_stack_link(mat, node, "set_value", in, out, link); } -static void sh_node_value_expand_in_mf_network(blender::bke::NodeMFNetworkBuilder &builder) +static void sh_node_value_expand_in_mf_network(blender::nodes::NodeMFNetworkBuilder &builder) { const bNodeSocket *bsocket = builder.dnode().output(0).bsocket(); const bNodeSocketValueFloat *value = (const bNodeSocketValueFloat *)bsocket->default_value; diff --git a/source/blender/nodes/shader/nodes/node_shader_vector_math.cc b/source/blender/nodes/shader/nodes/node_shader_vector_math.cc index 8301ab4d855..c18ad8bb244 100644 --- a/source/blender/nodes/shader/nodes/node_shader_vector_math.cc +++ b/source/blender/nodes/shader/nodes/node_shader_vector_math.cc @@ -161,7 +161,7 @@ static void node_shader_update_vector_math(bNodeTree *UNUSED(ntree), bNode *node } static const blender::fn::MultiFunction &get_multi_function( - blender::bke::NodeMFNetworkBuilder &builder) + blender::nodes::NodeMFNetworkBuilder &builder) { using blender::float3; @@ -271,7 +271,7 @@ static const blender::fn::MultiFunction &get_multi_function( }; } -static void sh_node_vector_math_expand_in_mf_network(blender::bke::NodeMFNetworkBuilder &builder) +static void sh_node_vector_math_expand_in_mf_network(blender::nodes::NodeMFNetworkBuilder &builder) { const blender::fn::MultiFunction &fn = get_multi_function(builder); builder.set_matching_fn(fn); diff --git a/source/blender/simulation/CMakeLists.txt b/source/blender/simulation/CMakeLists.txt index aced9664f51..fa4838b0875 100644 --- a/source/blender/simulation/CMakeLists.txt +++ b/source/blender/simulation/CMakeLists.txt @@ -24,8 +24,11 @@ set(INC ../blenkernel ../blenlib ../depsgraph + ../functions ../imbuf ../makesdna + ../makesrna + ../nodes ../../../intern/guardedalloc ) @@ -41,11 +44,17 @@ set(SRC intern/implicit.h intern/implicit_blender.c intern/implicit_eigen.cpp + intern/particle_function.cc + intern/simulation_update.cc SIM_mass_spring.h + SIM_particle_function.hh + SIM_simulation_update.hh ) set(LIB + bf_blenkernel + bf_nodes ) if(WITH_OPENMP_STATIC) @@ -54,4 +63,4 @@ if(WITH_OPENMP_STATIC) ) endif() -blender_add_lib(bf_physics "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") +blender_add_lib(bf_simulation "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") diff --git a/source/blender/simulation/SIM_particle_function.hh b/source/blender/simulation/SIM_particle_function.hh new file mode 100644 index 00000000000..eae61b1ae11 --- /dev/null +++ b/source/blender/simulation/SIM_particle_function.hh @@ -0,0 +1,89 @@ +/* + * 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. + */ + +#ifndef __SIM_PARTICLE_FUNCTION_HH__ +#define __SIM_PARTICLE_FUNCTION_HH__ + +#include "FN_attributes_ref.hh" +#include "FN_multi_function.hh" + +#include "BLI_resource_collector.hh" + +namespace blender::sim { + +class ParticleFunctionInput { + public: + virtual ~ParticleFunctionInput() = default; + virtual void add_input(fn::AttributesRef attributes, + fn::MFParamsBuilder ¶ms, + ResourceCollector &resources) const = 0; +}; + +class ParticleFunction { + private: + const fn::MultiFunction *global_fn_; + const fn::MultiFunction *per_particle_fn_; + Array<const ParticleFunctionInput *> global_inputs_; + Array<const ParticleFunctionInput *> per_particle_inputs_; + Array<bool> output_is_global_; + Vector<uint> global_output_indices_; + Vector<uint> per_particle_output_indices_; + Vector<fn::MFDataType> output_types_; + Vector<StringRefNull> output_names_; + + friend class ParticleFunctionEvaluator; + + public: + ParticleFunction(const fn::MultiFunction *global_fn, + const fn::MultiFunction *per_particle_fn, + Span<const ParticleFunctionInput *> global_inputs, + Span<const ParticleFunctionInput *> per_particle_inputs, + Span<bool> output_is_global); +}; + +class ParticleFunctionEvaluator { + private: + ResourceCollector resources_; + const ParticleFunction &particle_fn_; + IndexMask mask_; + fn::MFContextBuilder global_context_; + fn::MFContextBuilder per_particle_context_; + fn::AttributesRef particle_attributes_; + Vector<void *> outputs_; + bool is_computed_ = false; + + public: + ParticleFunctionEvaluator(const ParticleFunction &particle_fn, + IndexMask mask, + fn::AttributesRef particle_attributes); + ~ParticleFunctionEvaluator(); + + void compute(); + fn::GVSpan get(uint output_index, StringRef expected_name) const; + + template<typename T> fn::VSpan<T> get(uint output_index, StringRef expected_name) const + { + return this->get(output_index, expected_name).typed<T>(); + } + + private: + void compute_globals(); + void compute_per_particle(); +}; + +} // namespace blender::sim + +#endif /* __SIM_PARTICLE_FUNCTION_HH__ */ diff --git a/source/blender/functions/FN_cpp_types.hh b/source/blender/simulation/SIM_simulation_update.hh index 63f6b49885f..40b62bfb58a 100644 --- a/source/blender/functions/FN_cpp_types.hh +++ b/source/blender/simulation/SIM_simulation_update.hh @@ -14,35 +14,19 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifndef __FN_CPP_TYPES_HH__ -#define __FN_CPP_TYPES_HH__ +#ifndef __SIM_SIMULATION_UPDATE_HH__ +#define __SIM_SIMULATION_UPDATE_HH__ -/** \file - * \ingroup fn - * - * This header provides convenient access to CPPType instances for some core types like integer - * types. - */ - -#include "FN_cpp_type.hh" - -namespace blender::fn { - -extern const CPPType &CPPType_bool; - -extern const CPPType &CPPType_float; -extern const CPPType &CPPType_float3; -extern const CPPType &CPPType_float4x4; - -extern const CPPType &CPPType_int32; -extern const CPPType &CPPType_uint32; -extern const CPPType &CPPType_uint8; +struct Depsgraph; +struct Scene; +struct Simulation; -extern const CPPType &CPPType_Color4f; -extern const CPPType &CPPType_Color4b; +namespace blender::sim { -extern const CPPType &CPPType_string; +void update_simulation_in_depsgraph(Depsgraph *depsgraph, + Scene *scene_cow, + Simulation *simulation_cow); -} // namespace blender::fn +} -#endif /* __FN_CPP_TYPES_HH__ */ +#endif /* __SIM_SIMULATION_UPDATE_HH__ */ diff --git a/source/blender/simulation/intern/particle_function.cc b/source/blender/simulation/intern/particle_function.cc new file mode 100644 index 00000000000..7a0c9ccdb13 --- /dev/null +++ b/source/blender/simulation/intern/particle_function.cc @@ -0,0 +1,160 @@ +/* + * 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. + */ + +#include "SIM_particle_function.hh" + +namespace blender::sim { + +ParticleFunction::ParticleFunction(const fn::MultiFunction *global_fn, + const fn::MultiFunction *per_particle_fn, + Span<const ParticleFunctionInput *> global_inputs, + Span<const ParticleFunctionInput *> per_particle_inputs, + Span<bool> output_is_global) + : global_fn_(global_fn), + per_particle_fn_(per_particle_fn), + global_inputs_(global_inputs), + per_particle_inputs_(per_particle_inputs), + output_is_global_(output_is_global) +{ + for (uint i : output_is_global_.index_range()) { + if (output_is_global_[i]) { + uint param_index = global_inputs_.size() + global_output_indices_.size(); + fn::MFParamType param_type = global_fn_->param_type(param_index); + BLI_assert(param_type.is_output()); + output_types_.append(param_type.data_type()); + output_names_.append(global_fn_->param_name(param_index)); + global_output_indices_.append(i); + } + else { + uint param_index = per_particle_inputs_.size() + per_particle_output_indices_.size(); + fn::MFParamType param_type = per_particle_fn_->param_type(param_index); + BLI_assert(param_type.is_output()); + output_types_.append(param_type.data_type()); + output_names_.append(per_particle_fn_->param_name(param_index)); + per_particle_output_indices_.append(i); + } + } +} + +ParticleFunctionEvaluator::ParticleFunctionEvaluator(const ParticleFunction &particle_fn, + IndexMask mask, + fn::AttributesRef particle_attributes) + : particle_fn_(particle_fn), + mask_(mask), + particle_attributes_(particle_attributes), + outputs_(particle_fn_.output_types_.size(), nullptr) +{ +} + +ParticleFunctionEvaluator::~ParticleFunctionEvaluator() +{ + for (uint output_index : outputs_.index_range()) { + void *buffer = outputs_[output_index]; + fn::MFDataType data_type = particle_fn_.output_types_[output_index]; + BLI_assert(data_type.is_single()); /* For now. */ + const fn::CPPType &type = data_type.single_type(); + + if (particle_fn_.output_is_global_[output_index]) { + type.destruct(buffer); + } + else { + type.destruct_indices(outputs_[0], mask_); + } + } +} + +void ParticleFunctionEvaluator::compute() +{ + BLI_assert(!is_computed_); + this->compute_globals(); + this->compute_per_particle(); + is_computed_ = true; +} + +fn::GVSpan ParticleFunctionEvaluator::get(uint output_index, StringRef expected_name) const +{ +#ifdef DEBUG + StringRef real_name = particle_fn_.output_names_[output_index]; + BLI_assert(expected_name == real_name); + BLI_assert(is_computed_); +#endif + UNUSED_VARS_NDEBUG(expected_name); + const void *buffer = outputs_[output_index]; + const fn::CPPType &type = particle_fn_.output_types_[output_index].single_type(); + if (particle_fn_.output_is_global_[output_index]) { + return fn::GVSpan::FromSingleWithMaxSize(type, buffer); + } + else { + return fn::GVSpan(fn::GSpan(type, buffer, mask_.min_array_size())); + } +} + +void ParticleFunctionEvaluator::compute_globals() +{ + if (particle_fn_.global_fn_ == nullptr) { + return; + } + + fn::MFParamsBuilder params(*particle_fn_.global_fn_, mask_.min_array_size()); + + /* Add input parameters. */ + for (const ParticleFunctionInput *input : particle_fn_.global_inputs_) { + input->add_input(particle_attributes_, params, resources_); + } + + /* Add output parameters. */ + for (uint output_index : particle_fn_.global_output_indices_) { + fn::MFDataType data_type = particle_fn_.output_types_[output_index]; + BLI_assert(data_type.is_single()); /* For now. */ + + const fn::CPPType &type = data_type.single_type(); + void *buffer = resources_.linear_allocator().allocate(type.size(), type.alignment()); + params.add_uninitialized_single_output(fn::GMutableSpan(type, buffer, 1)); + outputs_[output_index] = buffer; + } + + particle_fn_.global_fn_->call({0}, params, global_context_); +} + +void ParticleFunctionEvaluator::compute_per_particle() +{ + if (particle_fn_.per_particle_fn_ == nullptr) { + return; + } + + fn::MFParamsBuilder params(*particle_fn_.per_particle_fn_, mask_.min_array_size()); + + /* Add input parameters. */ + for (const ParticleFunctionInput *input : particle_fn_.per_particle_inputs_) { + input->add_input(particle_attributes_, params, resources_); + } + + /* Add output parameters. */ + for (uint output_index : particle_fn_.per_particle_output_indices_) { + fn::MFDataType data_type = particle_fn_.output_types_[output_index]; + BLI_assert(data_type.is_single()); /* For now. */ + + const fn::CPPType &type = data_type.single_type(); + void *buffer = resources_.linear_allocator().allocate(type.size() * mask_.min_array_size(), + type.alignment()); + params.add_uninitialized_single_output(fn::GMutableSpan(type, buffer, mask_.min_array_size())); + outputs_[output_index] = buffer; + } + + particle_fn_.per_particle_fn_->call(mask_, params, global_context_); +} + +} // namespace blender::sim diff --git a/source/blender/simulation/intern/simulation_update.cc b/source/blender/simulation/intern/simulation_update.cc new file mode 100644 index 00000000000..d682b018b11 --- /dev/null +++ b/source/blender/simulation/intern/simulation_update.cc @@ -0,0 +1,495 @@ +/* + * 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. + */ + +#include "SIM_particle_function.hh" +#include "SIM_simulation_update.hh" + +#include "BKE_customdata.h" +#include "BKE_simulation.h" + +#include "DNA_scene_types.h" +#include "DNA_simulation_types.h" + +#include "DEG_depsgraph_query.h" + +#include "BLI_array.hh" +#include "BLI_float3.hh" +#include "BLI_listbase.h" +#include "BLI_map.hh" +#include "BLI_rand.h" +#include "BLI_vector.hh" + +#include "NOD_node_tree_multi_function.hh" + +#include "FN_attributes_ref.hh" +#include "FN_multi_function_network_evaluation.hh" +#include "FN_multi_function_network_optimization.hh" + +extern "C" { +void WM_clipboard_text_set(const char *buf, bool selection); +} + +namespace blender::sim { + +static void ensure_attributes_exist(ParticleSimulationState *state) +{ + if (CustomData_get_layer_named(&state->attributes, CD_PROP_FLOAT3, "Position") == nullptr) { + CustomData_add_layer_named( + &state->attributes, CD_PROP_FLOAT3, CD_CALLOC, nullptr, state->tot_particles, "Position"); + } + if (CustomData_get_layer_named(&state->attributes, CD_PROP_FLOAT3, "Velocity") == nullptr) { + CustomData_add_layer_named( + &state->attributes, CD_PROP_FLOAT3, CD_CALLOC, nullptr, state->tot_particles, "Velocity"); + } + if (CustomData_get_layer_named(&state->attributes, CD_PROP_INT32, "ID") == nullptr) { + CustomData_add_layer_named( + &state->attributes, CD_PROP_INT32, CD_CALLOC, nullptr, state->tot_particles, "ID"); + } +} + +static void copy_states_to_cow(Simulation *simulation_orig, Simulation *simulation_cow) +{ + BKE_simulation_state_remove_all(simulation_cow); + simulation_cow->current_frame = simulation_orig->current_frame; + + LISTBASE_FOREACH (SimulationState *, state_orig, &simulation_orig->states) { + switch ((eSimulationStateType)state_orig->type) { + case SIM_STATE_TYPE_PARTICLES: { + ParticleSimulationState *particle_state_orig = (ParticleSimulationState *)state_orig; + ParticleSimulationState *particle_state_cow = (ParticleSimulationState *) + BKE_simulation_state_add(simulation_cow, SIM_STATE_TYPE_PARTICLES, state_orig->name); + particle_state_cow->tot_particles = particle_state_orig->tot_particles; + CustomData_copy(&particle_state_orig->attributes, + &particle_state_cow->attributes, + CD_MASK_ALL, + CD_DUPLICATE, + particle_state_orig->tot_particles); + break; + } + } + } +} + +static Map<const fn::MFOutputSocket *, std::string> deduplicate_attribute_nodes( + fn::MFNetwork &network, + nodes::MFNetworkTreeMap &network_map, + const nodes::DerivedNodeTree &tree) +{ + Span<const nodes::DNode *> attribute_dnodes = tree.nodes_by_type( + "SimulationNodeParticleAttribute"); + uint amount = attribute_dnodes.size(); + if (amount == 0) { + return {}; + } + + Vector<fn::MFInputSocket *> name_sockets; + for (const nodes::DNode *dnode : attribute_dnodes) { + fn::MFInputSocket &name_socket = network_map.lookup_dummy(dnode->input(0)); + name_sockets.append(&name_socket); + } + + fn::MFNetworkEvaluator network_fn{{}, name_sockets.as_span()}; + + fn::MFParamsBuilder params{network_fn, 1}; + + Array<std::string> attribute_names{amount, NoInitialization()}; + for (uint i : IndexRange(amount)) { + params.add_uninitialized_single_output( + fn::GMutableSpan(fn::CPPType::get<std::string>(), attribute_names.data() + i, 1)); + } + + fn::MFContextBuilder context; + /* Todo: Check that the names don't depend on dummy nodes. */ + network_fn.call({0}, params, context); + + Map<std::pair<std::string, fn::MFDataType>, Vector<fn::MFNode *>> + attribute_nodes_by_name_and_type; + for (uint i : IndexRange(amount)) { + attribute_nodes_by_name_and_type + .lookup_or_add_default({attribute_names[i], name_sockets[i]->node().output(0).data_type()}) + .append(&name_sockets[i]->node()); + } + + Map<const fn::MFOutputSocket *, std::string> attribute_inputs; + for (auto item : attribute_nodes_by_name_and_type.items()) { + StringRef attribute_name = item.key.first; + fn::MFDataType data_type = item.key.second; + Span<fn::MFNode *> nodes = item.value; + + fn::MFOutputSocket &new_attribute_socket = network.add_input( + "Attribute '" + attribute_name + "'", data_type); + for (fn::MFNode *node : nodes) { + network.relink(node->output(0), new_attribute_socket); + } + network.remove(nodes); + + attribute_inputs.add_new(&new_attribute_socket, attribute_name); + } + + return attribute_inputs; +} + +class CustomDataAttributesRef { + private: + Vector<void *> buffers_; + uint size_; + std::unique_ptr<fn::AttributesInfo> info_; + + public: + CustomDataAttributesRef(CustomData &custom_data, uint size) + { + fn::AttributesInfoBuilder builder; + for (const CustomDataLayer &layer : Span(custom_data.layers, custom_data.totlayer)) { + buffers_.append(layer.data); + switch (layer.type) { + case CD_PROP_INT32: { + builder.add<int32_t>(layer.name, 0); + break; + } + case CD_PROP_FLOAT3: { + builder.add<float3>(layer.name, {0, 0, 0}); + break; + } + } + } + info_ = std::make_unique<fn::AttributesInfo>(builder); + size_ = size; + } + + operator fn::MutableAttributesRef() + { + return fn::MutableAttributesRef(*info_, buffers_, size_); + } + + operator fn::AttributesRef() const + { + return fn::AttributesRef(*info_, buffers_, size_); + } +}; + +static std::string dnode_to_path(const nodes::DNode &dnode) +{ + std::string path; + for (const nodes::DParentNode *parent = dnode.parent(); parent; parent = parent->parent()) { + path = parent->node_ref().name() + "/" + path; + } + path = path + dnode.name(); + return path; +} + +static void remove_unused_states(Simulation *simulation, const VectorSet<std::string> &state_names) +{ + LISTBASE_FOREACH_MUTABLE (SimulationState *, state, &simulation->states) { + if (!state_names.contains(state->name)) { + BKE_simulation_state_remove(simulation, state); + } + } +} + +static void reset_states(Simulation *simulation) +{ + LISTBASE_FOREACH (SimulationState *, state, &simulation->states) { + switch ((eSimulationStateType)state->type) { + case SIM_STATE_TYPE_PARTICLES: { + ParticleSimulationState *particle_state = (ParticleSimulationState *)state; + CustomData_free(&particle_state->attributes, particle_state->tot_particles); + particle_state->tot_particles = 0; + break; + } + } + } +} + +static SimulationState *try_find_state_by_name(Simulation *simulation, StringRef name) +{ + LISTBASE_FOREACH (SimulationState *, state, &simulation->states) { + if (state->name == name) { + return state; + } + } + return nullptr; +} + +static void add_missing_particle_states(Simulation *simulation, Span<std::string> state_names) +{ + for (StringRefNull name : state_names) { + SimulationState *state = try_find_state_by_name(simulation, name); + if (state != nullptr) { + BLI_assert(state->type == SIM_STATE_TYPE_PARTICLES); + continue; + } + + BKE_simulation_state_add(simulation, SIM_STATE_TYPE_PARTICLES, name.c_str()); + } +} + +static void reinitialize_empty_simulation_states(Simulation *simulation, + const nodes::DerivedNodeTree &tree) +{ + VectorSet<std::string> state_names; + for (const nodes::DNode *dnode : tree.nodes_by_type("SimulationNodeParticleSimulation")) { + state_names.add(dnode_to_path(*dnode)); + } + + remove_unused_states(simulation, state_names); + reset_states(simulation); + add_missing_particle_states(simulation, state_names); +} + +static void update_simulation_state_list(Simulation *simulation, + const nodes::DerivedNodeTree &tree) +{ + VectorSet<std::string> state_names; + for (const nodes::DNode *dnode : tree.nodes_by_type("SimulationNodeParticleSimulation")) { + state_names.add(dnode_to_path(*dnode)); + } + + remove_unused_states(simulation, state_names); + add_missing_particle_states(simulation, state_names); +} + +class ParticleAttributeInput : public ParticleFunctionInput { + private: + std::string attribute_name_; + const fn::CPPType &attribute_type_; + + public: + ParticleAttributeInput(std::string attribute_name, const fn::CPPType &attribute_type) + : attribute_name_(std::move(attribute_name)), attribute_type_(attribute_type) + { + } + + void add_input(fn::AttributesRef attributes, + fn::MFParamsBuilder ¶ms, + ResourceCollector &UNUSED(resources)) const override + { + std::optional<fn::GSpan> span = attributes.try_get(attribute_name_, attribute_type_); + if (span.has_value()) { + params.add_readonly_single_input(*span); + } + else { + params.add_readonly_single_input(fn::GVSpan::FromDefault(attribute_type_)); + } + } +}; + +static const ParticleFunction *create_particle_function_for_inputs( + Span<const fn::MFInputSocket *> sockets_to_compute, + ResourceCollector &resources, + const Map<const fn::MFOutputSocket *, std::string> &attribute_inputs) +{ + BLI_assert(sockets_to_compute.size() >= 1); + const fn::MFNetwork &network = sockets_to_compute[0]->node().network(); + + VectorSet<const fn::MFOutputSocket *> dummy_deps; + VectorSet<const fn::MFInputSocket *> unlinked_input_deps; + network.find_dependencies(sockets_to_compute, dummy_deps, unlinked_input_deps); + BLI_assert(unlinked_input_deps.size() == 0); + + Vector<const ParticleFunctionInput *> per_particle_inputs; + for (const fn::MFOutputSocket *socket : dummy_deps) { + const std::string *attribute_name = attribute_inputs.lookup_ptr(socket); + if (attribute_name == nullptr) { + return nullptr; + } + per_particle_inputs.append(&resources.construct<ParticleAttributeInput>( + AT, *attribute_name, socket->data_type().single_type())); + } + + const fn::MultiFunction &per_particle_fn = resources.construct<fn::MFNetworkEvaluator>( + AT, dummy_deps.as_span(), sockets_to_compute); + + Array<bool> output_is_global(sockets_to_compute.size(), false); + + const ParticleFunction &particle_fn = resources.construct<ParticleFunction>( + AT, + nullptr, + &per_particle_fn, + Span<const ParticleFunctionInput *>(), + per_particle_inputs.as_span(), + output_is_global.as_span()); + + return &particle_fn; +} + +class ParticleForce { + public: + virtual ~ParticleForce() = default; + virtual void add_force(fn::AttributesRef attributes, + MutableSpan<float3> r_combined_force) const = 0; +}; + +class ParticleFunctionForce : public ParticleForce { + private: + const ParticleFunction &particle_fn_; + + public: + ParticleFunctionForce(const ParticleFunction &particle_fn) : particle_fn_(particle_fn) + { + } + + void add_force(fn::AttributesRef attributes, MutableSpan<float3> r_combined_force) const override + { + IndexMask mask = IndexRange(attributes.size()); + ParticleFunctionEvaluator evaluator{particle_fn_, mask, attributes}; + evaluator.compute(); + fn::VSpan<float3> forces = evaluator.get<float3>(0, "Force"); + for (uint i : mask) { + r_combined_force[i] += forces[i]; + } + } +}; + +static Vector<const ParticleForce *> create_forces_for_particle_simulation( + const nodes::DNode &simulation_node, + nodes::MFNetworkTreeMap &network_map, + ResourceCollector &resources, + const Map<const fn::MFOutputSocket *, std::string> &attribute_inputs) +{ + Vector<const ParticleForce *> forces; + for (const nodes::DOutputSocket *origin_socket : + simulation_node.input(2, "Forces").linked_sockets()) { + const nodes::DNode &origin_node = origin_socket->node(); + if (origin_node.idname() != "SimulationNodeForce") { + continue; + } + + const fn::MFInputSocket &force_socket = network_map.lookup_dummy( + origin_node.input(0, "Force")); + + const ParticleFunction *particle_fn = create_particle_function_for_inputs( + {&force_socket}, resources, attribute_inputs); + + if (particle_fn == nullptr) { + continue; + } + + const ParticleForce &force = resources.construct<ParticleFunctionForce>(AT, *particle_fn); + forces.append(&force); + } + return forces; +} + +static Map<std::string, Vector<const ParticleForce *>> collect_forces( + nodes::MFNetworkTreeMap &network_map, + ResourceCollector &resources, + const Map<const fn::MFOutputSocket *, std::string> &attribute_inputs) +{ + Map<std::string, Vector<const ParticleForce *>> forces_by_simulation; + for (const nodes::DNode *dnode : + network_map.tree().nodes_by_type("SimulationNodeParticleSimulation")) { + std::string name = dnode_to_path(*dnode); + Vector<const ParticleForce *> forces = create_forces_for_particle_simulation( + *dnode, network_map, resources, attribute_inputs); + forces_by_simulation.add_new(std::move(name), std::move(forces)); + } + return forces_by_simulation; +} + +void update_simulation_in_depsgraph(Depsgraph *depsgraph, + Scene *scene_cow, + Simulation *simulation_cow) +{ + int current_frame = scene_cow->r.cfra; + if (simulation_cow->current_frame == current_frame) { + return; + } + + /* Below we modify the original state/cache. Only the active depsgraph is allowed to do that. */ + if (!DEG_is_active(depsgraph)) { + return; + } + + Simulation *simulation_orig = (Simulation *)DEG_get_original_id(&simulation_cow->id); + + nodes::NodeTreeRefMap tree_refs; + /* TODO: Use simulation_cow, but need to add depsgraph relations before that. */ + const nodes::DerivedNodeTree tree{simulation_orig->nodetree, tree_refs}; + fn::MFNetwork network; + ResourceCollector resources; + nodes::MFNetworkTreeMap network_map = insert_node_tree_into_mf_network(network, tree, resources); + Map<const fn::MFOutputSocket *, std::string> attribute_inputs = deduplicate_attribute_nodes( + network, network_map, tree); + fn::mf_network_optimization::constant_folding(network, resources); + fn::mf_network_optimization::common_subnetwork_elimination(network); + fn::mf_network_optimization::dead_node_removal(network); + // WM_clipboard_text_set(network.to_dot().c_str(), false); + + Map<std::string, Vector<const ParticleForce *>> forces_by_simulation = collect_forces( + network_map, resources, attribute_inputs); + + if (current_frame == 1) { + reinitialize_empty_simulation_states(simulation_orig, tree); + + RNG *rng = BLI_rng_new(0); + + simulation_orig->current_frame = 1; + LISTBASE_FOREACH (ParticleSimulationState *, state, &simulation_orig->states) { + state->tot_particles = 1000; + CustomData_realloc(&state->attributes, state->tot_particles); + ensure_attributes_exist(state); + + CustomDataAttributesRef custom_data_attributes{state->attributes, + (uint)state->tot_particles}; + + fn::MutableAttributesRef attributes = custom_data_attributes; + MutableSpan<float3> positions = attributes.get<float3>("Position"); + MutableSpan<float3> velocities = attributes.get<float3>("Velocity"); + MutableSpan<int32_t> ids = attributes.get<int32_t>("ID"); + + for (uint i : positions.index_range()) { + positions[i] = {i / 100.0f, 0, 0}; + velocities[i] = {0, BLI_rng_get_float(rng) - 0.5f, BLI_rng_get_float(rng) - 0.5f}; + ids[i] = i; + } + } + + BLI_rng_free(rng); + + copy_states_to_cow(simulation_orig, simulation_cow); + } + else if (current_frame == simulation_orig->current_frame + 1) { + update_simulation_state_list(simulation_orig, tree); + float time_step = 1.0f / 24.0f; + simulation_orig->current_frame = current_frame; + + LISTBASE_FOREACH (ParticleSimulationState *, state, &simulation_orig->states) { + ensure_attributes_exist(state); + + CustomDataAttributesRef custom_data_attributes{state->attributes, + (uint)state->tot_particles}; + + fn::MutableAttributesRef attributes = custom_data_attributes; + MutableSpan<float3> positions = attributes.get<float3>("Position"); + MutableSpan<float3> velocities = attributes.get<float3>("Velocity"); + + Array<float3> force_vectors{(uint)state->tot_particles, {0, 0, 0}}; + Span<const ParticleForce *> forces = forces_by_simulation.lookup_as(state->head.name); + for (const ParticleForce *force : forces) { + force->add_force(attributes, force_vectors); + } + + for (uint i : positions.index_range()) { + velocities[i] += force_vectors[i] * time_step; + positions[i] += velocities[i] * time_step; + } + } + + copy_states_to_cow(simulation_orig, simulation_cow); + } +} + +} // namespace blender::sim diff --git a/tests/gtests/CMakeLists.txt b/tests/gtests/CMakeLists.txt index 4ce68a6f4c0..282eb9080f5 100644 --- a/tests/gtests/CMakeLists.txt +++ b/tests/gtests/CMakeLists.txt @@ -19,7 +19,4 @@ if(WITH_GTESTS) if(WITH_ALEMBIC) add_subdirectory(alembic) endif() - if(WITH_USD) - add_subdirectory(usd) - endif() endif() diff --git a/tests/gtests/blenloader/blendfile_loading_base_test.cc b/tests/gtests/blenloader/blendfile_loading_base_test.cc index 62befae90cd..f15ae615e8a 100644 --- a/tests/gtests/blenloader/blendfile_loading_base_test.cc +++ b/tests/gtests/blenloader/blendfile_loading_base_test.cc @@ -50,8 +50,6 @@ extern "C" { #include "wm.h" } -DEFINE_string(test_assets_dir, "", "lib/tests directory from SVN containing the test assets."); - BlendfileLoadingBaseTest::~BlendfileLoadingBaseTest() { } @@ -125,19 +123,18 @@ void BlendfileLoadingBaseTest::TearDown() bool BlendfileLoadingBaseTest::blendfile_load(const char *filepath) { - if (FLAGS_test_assets_dir.empty()) { - ADD_FAILURE() - << "Pass the flag --test-assets-dir and point to the lib/tests directory from SVN."; + const std::string &test_assets_dir = blender::tests::flags_test_asset_dir(); + if (test_assets_dir.empty()) { return false; } char abspath[FILENAME_MAX]; - BLI_path_join(abspath, sizeof(abspath), FLAGS_test_assets_dir.c_str(), filepath, NULL); + BLI_path_join(abspath, sizeof(abspath), test_assets_dir.c_str(), filepath, NULL); bfile = BLO_read_from_file(abspath, BLO_READ_SKIP_NONE, NULL /* reports */); if (bfile == nullptr) { ADD_FAILURE() << "Unable to load file '" << filepath << "' from test assets dir '" - << FLAGS_test_assets_dir << "'"; + << test_assets_dir << "'"; return false; } return true; diff --git a/tests/gtests/functions/FN_array_spans_test.cc b/tests/gtests/functions/FN_array_spans_test.cc index 988d48fa452..6912a62ff17 100644 --- a/tests/gtests/functions/FN_array_spans_test.cc +++ b/tests/gtests/functions/FN_array_spans_test.cc @@ -3,7 +3,6 @@ #include "testing/testing.h" #include "FN_array_spans.hh" -#include "FN_cpp_types.hh" #include "FN_generic_vector_array.hh" #include "BLI_array.hh" @@ -77,7 +76,7 @@ TEST(virtual_array_span, MultipleArrayConstructor) TEST(generic_virtual_array_span, TypeConstructor) { - GVArraySpan span{CPPType_int32}; + GVArraySpan span{CPPType::get<int32_t>()}; EXPECT_EQ(span.size(), 0); EXPECT_TRUE(span.is_empty()); @@ -88,7 +87,7 @@ TEST(generic_virtual_array_span, TypeConstructor) TEST(generic_virtual_array_span, GSpanConstructor) { std::array<std::string, 3> values = {"hello", "world", "test"}; - GVArraySpan span{GSpan(CPPType_string, values.data(), 3), 5}; + GVArraySpan span{GSpan(CPPType::get<std::string>(), values.data(), 3), 5}; EXPECT_EQ(span.size(), 5); EXPECT_FALSE(span.is_empty()); EXPECT_EQ(span[0][0], values.data()); @@ -119,7 +118,7 @@ TEST(generic_virtual_array_span, IsSingleArray1) TEST(generic_virtual_array_span, IsSingleArray2) { - GVectorArray vectors{CPPType_int32, 3}; + GVectorArray vectors{CPPType::get<int32_t>(), 3}; GVectorArrayRef<int> vectors_ref = vectors; vectors_ref.append(1, 4); diff --git a/tests/gtests/functions/FN_attributes_ref_test.cc b/tests/gtests/functions/FN_attributes_ref_test.cc index 1c05bb930db..0b0afdc210f 100644 --- a/tests/gtests/functions/FN_attributes_ref_test.cc +++ b/tests/gtests/functions/FN_attributes_ref_test.cc @@ -2,7 +2,6 @@ #include "BLI_float3.hh" #include "FN_attributes_ref.hh" -#include "FN_cpp_types.hh" #include "testing/testing.h" diff --git a/tests/gtests/functions/FN_cpp_type_test.cc b/tests/gtests/functions/FN_cpp_type_test.cc index da5ce3416ce..78731f9c987 100644 --- a/tests/gtests/functions/FN_cpp_type_test.cc +++ b/tests/gtests/functions/FN_cpp_type_test.cc @@ -3,7 +3,6 @@ #include "testing/testing.h" #include "FN_cpp_type.hh" -#include "FN_cpp_types.hh" namespace blender::fn { @@ -76,6 +75,8 @@ struct TestType { MAKE_CPP_TYPE(TestType, TestType) +const CPPType &CPPType_TestType = CPPType::get<TestType>(); + TEST(cpp_type, Size) { EXPECT_EQ(CPPType_TestType.size(), sizeof(TestType)); @@ -312,7 +313,7 @@ TEST(cpp_type, DebugPrint) { int value = 42; std::stringstream ss; - CPPType_int32.debug_print((void *)&value, ss); + CPPType::get<int32_t>().debug_print((void *)&value, ss); std::string text = ss.str(); EXPECT_EQ(text, "42"); } diff --git a/tests/gtests/functions/FN_generic_vector_array_test.cc b/tests/gtests/functions/FN_generic_vector_array_test.cc index 7ce7b543218..cfca678ad27 100644 --- a/tests/gtests/functions/FN_generic_vector_array_test.cc +++ b/tests/gtests/functions/FN_generic_vector_array_test.cc @@ -1,6 +1,5 @@ /* Apache License, Version 2.0 */ -#include "FN_cpp_types.hh" #include "FN_generic_vector_array.hh" #include "testing/testing.h" @@ -9,19 +8,19 @@ namespace blender::fn { TEST(generic_vector_array, Constructor) { - GVectorArray vectors{CPPType_int32, 3}; + GVectorArray vectors{CPPType::get<int32_t>(), 3}; EXPECT_EQ(vectors.size(), 3); EXPECT_EQ(vectors.lengths().size(), 3); EXPECT_EQ(vectors.starts().size(), 3); EXPECT_EQ(vectors.lengths()[0], 0); EXPECT_EQ(vectors.lengths()[1], 0); EXPECT_EQ(vectors.lengths()[2], 0); - EXPECT_EQ(vectors.type(), CPPType_int32); + EXPECT_EQ(vectors.type(), CPPType::get<int32_t>()); } TEST(generic_vector_array, Append) { - GVectorArray vectors{CPPType_string, 3}; + GVectorArray vectors{CPPType::get<std::string>(), 3}; std::string value = "hello"; vectors.append(0, &value); value = "world"; @@ -39,7 +38,7 @@ TEST(generic_vector_array, Append) TEST(generic_vector_array, AsArraySpan) { - GVectorArray vectors{CPPType_int32, 3}; + GVectorArray vectors{CPPType::get<int32_t>(), 3}; int value = 3; vectors.append(0, &value); vectors.append(0, &value); @@ -49,7 +48,7 @@ TEST(generic_vector_array, AsArraySpan) vectors.append(2, &value); GVArraySpan span = vectors; - EXPECT_EQ(span.type(), CPPType_int32); + EXPECT_EQ(span.type(), CPPType::get<int32_t>()); EXPECT_EQ(span.size(), 3); EXPECT_EQ(span[0].size(), 2); EXPECT_EQ(span[1].size(), 0); @@ -60,7 +59,7 @@ TEST(generic_vector_array, AsArraySpan) TEST(generic_vector_array, TypedRef) { - GVectorArray vectors{CPPType_int32, 4}; + GVectorArray vectors{CPPType::get<int32_t>(), 4}; GVectorArrayRef<int> ref = vectors.typed<int>(); ref.append(0, 2); ref.append(0, 6); @@ -84,7 +83,7 @@ TEST(generic_vector_array, TypedRef) TEST(generic_vector_array, Extend) { - GVectorArray vectors{CPPType_int32, 3}; + GVectorArray vectors{CPPType::get<int32_t>(), 3}; GVectorArrayRef<int> ref = vectors; ref.extend(1, {5, 6, 7}); diff --git a/tests/gtests/functions/FN_multi_function_network_test.cc b/tests/gtests/functions/FN_multi_function_network_test.cc index 5507733c8be..35af8300cfa 100644 --- a/tests/gtests/functions/FN_multi_function_network_test.cc +++ b/tests/gtests/functions/FN_multi_function_network_test.cc @@ -2,7 +2,6 @@ #include "testing/testing.h" -#include "FN_cpp_types.hh" #include "FN_multi_function_builder.hh" #include "FN_multi_function_network.hh" #include "FN_multi_function_network_evaluation.hh" @@ -195,7 +194,7 @@ TEST(multi_function_network, Test2) Array<int> input_value_1 = {3, 6}; int input_value_2 = 4; - GVectorArray output_value_1(CPPType_int32, 5); + GVectorArray output_value_1(CPPType::get<int32_t>(), 5); Array<int> output_value_2(5, -1); MFParamsBuilder params(network_fn, 5); @@ -221,14 +220,14 @@ TEST(multi_function_network, Test2) EXPECT_EQ(output_value_2[4], 39); } { - GVectorArray input_value_1(CPPType_int32, 3); + GVectorArray input_value_1(CPPType::get<int32_t>(), 3); GVectorArrayRef<int> input_value_ref_1 = input_value_1; input_value_ref_1.extend(0, {3, 4, 5}); input_value_ref_1.extend(1, {1, 2}); Array<int> input_value_2 = {4, 2, 3}; - GVectorArray output_value_1(CPPType_int32, 3); + GVectorArray output_value_1(CPPType::get<int32_t>(), 3); Array<int> output_value_2(3, -1); MFParamsBuilder params(network_fn, 3); diff --git a/tests/gtests/functions/FN_multi_function_test.cc b/tests/gtests/functions/FN_multi_function_test.cc index 8cc8f91a300..66039e463ed 100644 --- a/tests/gtests/functions/FN_multi_function_test.cc +++ b/tests/gtests/functions/FN_multi_function_test.cc @@ -2,7 +2,6 @@ #include "testing/testing.h" -#include "FN_cpp_types.hh" #include "FN_multi_function.hh" #include "FN_multi_function_builder.hh" @@ -126,7 +125,7 @@ TEST(multi_function, CreateRangeFunction) { CreateRangeFunction fn; - GVectorArray ranges(CPPType_uint32, 5); + GVectorArray ranges(CPPType::get<int32_t>(), 5); GVectorArrayRef<uint> ranges_ref(ranges); Array<uint> sizes = {3, 0, 6, 1, 4}; @@ -173,9 +172,9 @@ class GenericAppendFunction : public MultiFunction { TEST(multi_function, GenericAppendFunction) { - GenericAppendFunction fn(CPPType_int32); + GenericAppendFunction fn(CPPType::get<int32_t>()); - GVectorArray vectors(CPPType_int32, 4); + GVectorArray vectors(CPPType::get<int32_t>(), 4); GVectorArrayRef<int> vectors_ref(vectors); vectors_ref.append(0, 1); vectors_ref.append(0, 2); @@ -318,7 +317,7 @@ TEST(multi_function, CustomMF_Constant) TEST(multi_function, CustomMF_GenericConstant) { int value = 42; - CustomMF_GenericConstant fn{CPPType_int32, (const void *)&value}; + CustomMF_GenericConstant fn{CPPType::get<int32_t>(), (const void *)&value}; EXPECT_EQ(fn.param_name(0), "42"); Array<int> outputs(4, 0); @@ -342,7 +341,7 @@ TEST(multi_function, CustomMF_GenericConstantArray) CustomMF_GenericConstantArray fn{GSpan(Span(values))}; EXPECT_EQ(fn.param_name(0), "[3, 4, 5, 6, ]"); - GVectorArray g_vector_array{CPPType_int32, 4}; + GVectorArray g_vector_array{CPPType::get<int32_t>(), 4}; GVectorArrayRef<int> vector_array = g_vector_array; MFParamsBuilder params(fn, g_vector_array.size()); diff --git a/tests/gtests/functions/FN_spans_test.cc b/tests/gtests/functions/FN_spans_test.cc index 8968d49c082..3172cdc7170 100644 --- a/tests/gtests/functions/FN_spans_test.cc +++ b/tests/gtests/functions/FN_spans_test.cc @@ -2,14 +2,13 @@ #include "testing/testing.h" -#include "FN_cpp_types.hh" #include "FN_spans.hh" namespace blender::fn { TEST(generic_span, TypeConstructor) { - GSpan span(CPPType_float); + GSpan span(CPPType::get<float>()); EXPECT_EQ(span.size(), 0); EXPECT_EQ(span.typed<float>().size(), 0); EXPECT_TRUE(span.is_empty()); @@ -19,7 +18,7 @@ TEST(generic_span, BufferAndSizeConstructor) { int values[4] = {6, 7, 3, 2}; void *buffer = (void *)values; - GSpan span(CPPType_int32, buffer, 4); + GSpan span(CPPType::get<int32_t>(), buffer, 4); EXPECT_EQ(span.size(), 4); EXPECT_FALSE(span.is_empty()); EXPECT_EQ(span.typed<int>().size(), 4); @@ -31,7 +30,7 @@ TEST(generic_span, BufferAndSizeConstructor) TEST(generic_mutable_span, TypeConstructor) { - GMutableSpan span(CPPType_int32); + GMutableSpan span(CPPType::get<int32_t>()); EXPECT_EQ(span.size(), 0); EXPECT_TRUE(span.is_empty()); } @@ -40,7 +39,7 @@ TEST(generic_mutable_span, BufferAndSizeConstructor) { int values[4] = {4, 7, 3, 5}; void *buffer = (void *)values; - GMutableSpan span(CPPType_int32, buffer, 4); + GMutableSpan span(CPPType::get<int32_t>(), buffer, 4); EXPECT_EQ(span.size(), 4); EXPECT_FALSE(span.is_empty()); EXPECT_EQ(span.typed<int>().size(), 4); @@ -127,7 +126,7 @@ TEST(virtual_span, SingleConstructor) TEST(generic_virtual_span, TypeConstructor) { - GVSpan span(CPPType_int32); + GVSpan span(CPPType::get<int32_t>()); EXPECT_EQ(span.size(), 0); EXPECT_TRUE(span.is_empty()); EXPECT_FALSE(span.is_single_element()); @@ -139,7 +138,7 @@ TEST(generic_virtual_span, TypeConstructor) TEST(generic_virtual_span, GenericSpanConstructor) { int values[4] = {3, 4, 5, 6}; - GVSpan span{GSpan(CPPType_int32, values, 4)}; + GVSpan span{GSpan(CPPType::get<int32_t>(), values, 4)}; EXPECT_EQ(span.size(), 4); EXPECT_FALSE(span.is_empty()); EXPECT_EQ(span[0], &values[0]); @@ -167,7 +166,7 @@ TEST(generic_virtual_span, SpanConstructor) { std::array<int, 3> values = {6, 7, 8}; GVSpan span{Span<int>(values)}; - EXPECT_EQ(span.type(), CPPType_int32); + EXPECT_EQ(span.type(), CPPType::get<int32_t>()); EXPECT_EQ(span.size(), 3); EXPECT_EQ(span[0], &values[0]); EXPECT_EQ(span[1], &values[1]); @@ -190,7 +189,7 @@ TEST(generic_virtual_span, SpanConstructor) TEST(generic_virtual_span, SingleConstructor) { int value = 5; - GVSpan span = GVSpan::FromSingle(CPPType_int32, &value, 3); + GVSpan span = GVSpan::FromSingle(CPPType::get<int32_t>(), &value, 3); EXPECT_EQ(span.size(), 3); EXPECT_FALSE(span.is_empty()); EXPECT_EQ(span[0], &value); diff --git a/tests/gtests/runner/BlenderAddTests.cmake b/tests/gtests/runner/BlenderAddTests.cmake new file mode 100644 index 00000000000..c4f5c8aba8a --- /dev/null +++ b/tests/gtests/runner/BlenderAddTests.cmake @@ -0,0 +1,3 @@ +# Disable ASAN leak detection when trying to discover tests. +set(ENV{ASAN_OPTIONS} "detect_leaks=0") +include(GoogleTestAddTests) diff --git a/tests/gtests/runner/CMakeLists.txt b/tests/gtests/runner/CMakeLists.txt index e7cbabfe7c6..4da0bce09a4 100644 --- a/tests/gtests/runner/CMakeLists.txt +++ b/tests/gtests/runner/CMakeLists.txt @@ -60,4 +60,14 @@ setup_liblinks(blender_test) # exposes those tests individually to the ctest runner. # See https://cmake.org/cmake/help/v3.18/module/GoogleTest.html include(GoogleTest) -gtest_discover_tests(blender_test) + +set(_GOOGLETEST_DISCOVER_TESTS_SCRIPT + ${CMAKE_CURRENT_LIST_DIR}/BlenderAddTests.cmake +) + +gtest_discover_tests(blender_test + # So that unit tests know where to find files: + EXTRA_ARGS + --test-assets-dir "${CMAKE_SOURCE_DIR}/../lib/tests" + --test-release-dir "$<TARGET_FILE_DIR:blender>/${BLENDER_VERSION}" +) diff --git a/tests/gtests/testing/testing.h b/tests/gtests/testing/testing.h index 32cb6e7f18a..34928035b7d 100644 --- a/tests/gtests/testing/testing.h +++ b/tests/gtests/testing/testing.h @@ -7,6 +7,15 @@ #include "glog/logging.h" #include "gtest/gtest.h" +namespace blender::tests { + +/* These strings are passed on the CLI with the --test-asset-dir and --test-release-dir arguments. + * The arguments are added automatically when invoking tests via `ctest`. */ +const std::string &flags_test_asset_dir(); /* ../lib/tests in the SVN directory. */ +const std::string &flags_test_release_dir(); /* bin/{blender version} in the build directory. */ + +} // namespace blender::tests + #define EXPECT_V3_NEAR(a, b, eps) \ { \ EXPECT_NEAR(a[0], b[0], eps); \ diff --git a/tests/gtests/testing/testing_main.cc b/tests/gtests/testing/testing_main.cc index 6b3a8e5515d..0acdcf3a8a5 100644 --- a/tests/gtests/testing/testing_main.cc +++ b/tests/gtests/testing/testing_main.cc @@ -19,6 +19,31 @@ #include "testing/testing.h" +DEFINE_string(test_assets_dir, "", "lib/tests directory from SVN containing the test assets."); +DEFINE_string(test_release_dir, "", "bin/{blender version} directory of the current build."); + +namespace blender::tests { + +const std::string &flags_test_asset_dir() +{ + if (FLAGS_test_assets_dir.empty()) { + ADD_FAILURE() + << "Pass the flag --test-assets-dir and point to the lib/tests directory from SVN."; + } + return FLAGS_test_assets_dir; +} + +const std::string &flags_test_release_dir() +{ + if (FLAGS_test_release_dir.empty()) { + ADD_FAILURE() + << "Pass the flag --test-release-dir and point to the bin/{blender version} directory."; + } + return FLAGS_test_release_dir; +} + +} // namespace blender::tests + int main(int argc, char **argv) { testing::InitGoogleTest(&argc, argv); diff --git a/tests/gtests/usd/CMakeLists.txt b/tests/gtests/usd/CMakeLists.txt deleted file mode 100644 index 0caa2fac155..00000000000 --- a/tests/gtests/usd/CMakeLists.txt +++ /dev/null @@ -1,109 +0,0 @@ -# ***** 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) 2019, Blender Foundation -# All rights reserved. -# ***** END GPL LICENSE BLOCK ***** - -# This suppresses the warning "This file includes at least one deprecated or antiquated -# header which may be removed without further notice at a future date", which is caused -# by the USD library including <ext/hash_set> on Linux. This has been reported at: -# https://github.com/PixarAnimationStudios/USD/issues/1057. -if(UNIX AND NOT APPLE) - add_definitions(-D_GLIBCXX_PERMIT_BACKWARD_HASH) -endif() -if(WIN32) - add_definitions(-DNOMINMAX) -endif() -add_definitions(-DPXR_STATIC) - -set(INC - . - .. - ../../../source/blender/blenlib - ../../../source/blender/blenkernel - ../../../source/blender/io/common - ../../../source/blender/io/usd - ../../../source/blender/makesdna - ../../../source/blender/depsgraph - ${USD_INCLUDE_DIRS} - ${BOOST_INCLUDE_DIR} - ${TBB_INCLUDE_DIR} -) - -set(LIB - bf_blenloader_test - bf_blenloader - - # Should not be needed but gives windows linker errors if the ocio libs are linked before this: - bf_intern_opencolorio - bf_gpu - - bf_usd - bf_io_common - - ${BOOST_LIBRARIES} - ${TBB_LIBRARIES} -) - -include_directories(${INC}) - -setup_libdirs() -get_property(BLENDER_SORTED_LIBS GLOBAL PROPERTY BLENDER_SORTED_LIBS_PROP) - -set(SRC - abstract_hierarchy_iterator_test.cc - hierarchy_context_order_test.cc - object_identifier_test.cc -) - -# TODO(Sybren): re-enable this unit test. -# if(NOT APPLE) -# # TODO(Sybren): This unit test has only been tested on Linux, and should possibly be -# # restructured to support other platforms as well. -# list(APPEND SRC usd_stage_creation_test.cc) -# endif() - - -if(WITH_BUILDINFO) - list(APPEND SRC - "$<TARGET_OBJECTS:buildinfoobj>" - ) -endif() - -# get_cmake_property(_variableNames VARIABLES) -# list(SORT _variableNames) -# foreach(_variableName ${_variableNames}) -# message(STATUS "${_variableName}=${${_variableName}}") -# endforeach() - -# Works on Linux, not on Windows: -# set(_usd_DATAFILES_DIR "${CMAKE_INSTALL_PREFIX}/${BLENDER_VERSION}/datafiles/usd") -set(_usd_DATAFILES_DIR "$<TARGET_FILE_DIR:blender>/${BLENDER_VERSION}/datafiles/usd") - -BLENDER_SRC_GTEST_EX( - NAME usd - SRC "${SRC}" - EXTRA_LIBS "${LIB}" - COMMAND_ARGS - --test-assets-dir "${CMAKE_SOURCE_DIR}/../lib/tests" -) -# TODO(Sybren): add the below CLI argument to the test when the usd_stage_creation_test.cc -# test is reenabled. -# --test-usd-datafiles-dir "${_usd_DATAFILES_DIR}" -unset(_usd_DATAFILES_DIR) - -setup_liblinks(usd_test) |