diff options
author | Lukas Tönne <lukas.toenne@gmail.com> | 2018-06-09 08:43:15 +0300 |
---|---|---|
committer | Lukas Tönne <lukas.toenne@gmail.com> | 2018-06-09 08:43:15 +0300 |
commit | b7b6f72cb57af13f0a0637c515a06e3831989909 (patch) | |
tree | 424fccbc7cf4701ffe37d8930b1ca10972991adb | |
parent | 4f2532e88cca35a3aaad753cbb27cb93d13dbb7a (diff) | |
parent | 86660aa29468d6902e2da9dda2789eb2f973df48 (diff) |
Merge branch 'blender2.8' into hair_guides
732 files changed, 47740 insertions, 7564 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 43820159456..69d0abe1e25 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -817,18 +817,20 @@ set(PLATFORM_LINKLIBS "") set(PLATFORM_LINKFLAGS "") set(PLATFORM_LINKFLAGS_DEBUG "") -if(WITH_COMPILER_ASAN) - set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} ${COMPILER_ASAN_CFLAGS}") - set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} ${COMPILER_ASAN_CFLAGS}") - - set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${COMPILER_ASAN_CXXFLAGS}") - set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} ${COMPILER_ASAN_CXXFLAGS}") - if(MSVC) - set(COMPILER_ASAN_LINKER_FLAGS "/FUNCTIONPADMIN:6") +if (NOT CMAKE_BUILD_TYPE MATCHES "Release") + if(WITH_COMPILER_ASAN) + set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} ${COMPILER_ASAN_CFLAGS}") + set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} ${COMPILER_ASAN_CFLAGS}") + + set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${COMPILER_ASAN_CXXFLAGS}") + set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} ${COMPILER_ASAN_CXXFLAGS}") + if(MSVC) + set(COMPILER_ASAN_LINKER_FLAGS "/FUNCTIONPADMIN:6") + endif() + set(PLATFORM_LINKLIBS "${PLATFORM_LINKLIBS};${COMPILER_ASAN_LIBRARY}") + set(PLATFORM_LINKFLAGS "${COMPILER_ASAN_LIBRARY} ${COMPILER_ASAN_LINKER_FLAGS}") + set(PLATFORM_LINKFLAGS_DEBUG "${COMPILER_ASAN_LIBRARY} ${COMPILER_ASAN_LINKER_FLAGS}") endif() - set(PLATFORM_LINKLIBS "${PLATFORM_LINKLIBS};${COMPILER_ASAN_LIBRARY}") - set(PLATFORM_LINKFLAGS "${COMPILER_ASAN_LIBRARY} ${COMPILER_ASAN_LINKER_FLAGS}") - set(PLATFORM_LINKFLAGS_DEBUG "${COMPILER_ASAN_LIBRARY} ${COMPILER_ASAN_LINKER_FLAGS}") endif() #----------------------------------------------------------------------------- diff --git a/build_files/cmake/platform/platform_win32.cmake b/build_files/cmake/platform/platform_win32.cmake index f55178b89e2..0ee0845be33 100644 --- a/build_files/cmake/platform/platform_win32.cmake +++ b/build_files/cmake/platform/platform_win32.cmake @@ -31,7 +31,8 @@ endif() if(CMAKE_C_COMPILER_ID MATCHES "Clang") set(MSVC_CLANG On) - set(MSVC_REDIST_DIR $ENV{VCToolsRedistDir}) + set(VC_TOOLS_DIR $ENV{VCToolsRedistDir} CACHE STRING "Location of the msvc redistributables") + set(MSVC_REDIST_DIR ${VC_TOOLS_DIR}) if (DEFINED MSVC_REDIST_DIR) file(TO_CMAKE_PATH ${MSVC_REDIST_DIR} MSVC_REDIST_DIR) else() diff --git a/build_files/windows/configure_msbuild.cmd b/build_files/windows/configure_msbuild.cmd index eee21f568be..f8c2a87de8e 100644 --- a/build_files/windows/configure_msbuild.cmd +++ b/build_files/windows/configure_msbuild.cmd @@ -1,5 +1,3 @@ -set BUILD_CMAKE_ARGS=%BUILD_CMAKE_ARGS% -G "Visual Studio %BUILD_VS_VER% %BUILD_VS_YEAR%%WINDOWS_ARCH%" %TESTS_CMAKE_ARGS% - if "%BUILD_ARCH%"=="x64" ( set MSBUILD_PLATFORM=x64 ) else if "%BUILD_ARCH%"=="x86" ( @@ -11,9 +9,9 @@ if "%BUILD_ARCH%"=="x64" ( ) if "%WITH_CLANG%"=="1" ( - set BUILD_CMAKE_ARGS=%BUILD_CMAKE_ARGS% -T"LLVM-vs2017" + set CLANG_CMAKE_ARGS=-T"LLVM-vs2017" if "%WITH_ASAN%"=="1" ( - set BUILD_CMAKE_ARGS=%BUILD_CMAKE_ARGS% -DWITH_COMPILER_ASAN=On + set ASAN_CMAKE_ARGS=-DWITH_COMPILER_ASAN=On ) ) else ( if "%WITH_ASAN%"=="1" ( @@ -21,6 +19,7 @@ if "%WITH_CLANG%"=="1" ( exit /b 1 ) ) +set BUILD_CMAKE_ARGS=%BUILD_CMAKE_ARGS% -G "Visual Studio %BUILD_VS_VER% %BUILD_VS_YEAR%%WINDOWS_ARCH%" %TESTS_CMAKE_ARGS% %CLANG_CMAKE_ARGS% %ASAN_CMAKE_ARGS% if NOT EXIST %BUILD_DIR%\nul ( mkdir %BUILD_DIR% diff --git a/build_files/windows/configure_ninja.cmd b/build_files/windows/configure_ninja.cmd index d3b002e9a24..224d761adf6 100644 --- a/build_files/windows/configure_ninja.cmd +++ b/build_files/windows/configure_ninja.cmd @@ -1,3 +1,9 @@ +ninja --version 1>NUL 2>&1 +if %ERRORLEVEL% NEQ 0 ( + echo "Ninja not detected in the path" + exit /b 1 + ) + set BUILD_CMAKE_ARGS=%BUILD_CMAKE_ARGS% -G "Ninja" %TESTS_CMAKE_ARGS% -DCMAKE_BUILD_TYPE=%BUILD_TYPE% if "%WITH_CLANG%" == "1" ( diff --git a/build_files/windows/detect_msvc2017.cmd b/build_files/windows/detect_msvc2017.cmd index 90fad8744b5..060e9f88617 100644 --- a/build_files/windows/detect_msvc2017.cmd +++ b/build_files/windows/detect_msvc2017.cmd @@ -12,7 +12,12 @@ if not exist "%vs_where%" ( goto FAIL ) ) -for /f "usebackq tokens=1* delims=: " %%i in (`"%vs_where%" -products * -latest %VSWHERE_ARGS% -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64`) do ( + +if NOT "%verbose%" == "" ( + echo "%vs_where%" -latest %VSWHERE_ARGS% -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64` + ) + +for /f "usebackq tokens=1* delims=: " %%i in (`"%vs_where%" -latest %VSWHERE_ARGS% -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64`) do ( if /i "%%i"=="installationPath" set VS_InstallDir=%%j ) diff --git a/build_files/windows/parse_arguments.cmd b/build_files/windows/parse_arguments.cmd index 2cc0acfd243..8a6d743978d 100644 --- a/build_files/windows/parse_arguments.cmd +++ b/build_files/windows/parse_arguments.cmd @@ -53,6 +53,10 @@ if NOT "%1" == "" ( ) else if "%1" == "2017pre" ( set BUILD_VS_YEAR=2017 set VSWHERE_ARGS=-prerelease + set BUILD_VS_YEAR=2017 + ) else if "%1" == "2017b" ( + set BUILD_VS_YEAR=2017 + set VSWHERE_ARGS=-products Microsoft.VisualStudio.Product.BuildTools ) else if "%1" == "2015" ( set BUILD_VS_YEAR=2015 ) else if "%1" == "2013" ( diff --git a/build_files/windows/reset_variables.cmd b/build_files/windows/reset_variables.cmd index f933729b91c..a522ed7407f 100644 --- a/build_files/windows/reset_variables.cmd +++ b/build_files/windows/reset_variables.cmd @@ -22,4 +22,6 @@ set BUILD_SHOW_HASHES= set SHOW_HELP= set BUILD_WITH_NINJA= set WITH_CLANG= -set WITH_ASAN=
\ No newline at end of file +set WITH_ASAN= +set CLANG_CMAKE_ARGS= +set ASAN_CMAKE_ARGS= diff --git a/build_files/windows/show_help.cmd b/build_files/windows/show_help.cmd index 0524e8a84fc..2b297120f4b 100644 --- a/build_files/windows/show_help.cmd +++ b/build_files/windows/show_help.cmd @@ -23,7 +23,13 @@ echo - buildir [newdir] ^(override default build folder^) echo - x86 ^(override host auto-detect and build 32 bit code^) echo - x64 ^(override host auto-detect and build 64 bit code^) echo - 2013 ^(build with visual studio 2013^) -echo - 2015 ^(build with visual studio 2015^) [EXPERIMENTAL] -echo - 2017 ^(build with visual studio 2017^) [EXPERIMENTAL] -echo - 2017pre ^(build with visual studio 2017 pre-release^) [EXPERIMENTAL] +echo. +echo Experimental options +echo - 2015 ^(build with visual studio 2015^) +echo - 2017 ^(build with visual studio 2017^) +echo - 2017pre ^(build with visual studio 2017 pre-release^) +echo - 2017b ^(build with visual studio 2017 Build Tools^) +echo - clang ^(enable building with clang^) +echo - asan ^(enable asan when building with clang^) +echo - ninja ^(enable building with ninja instead of msbuild^) echo. diff --git a/extern/audaspace/plugins/ffmpeg/FFMPEG.cpp b/extern/audaspace/plugins/ffmpeg/FFMPEG.cpp index 7f9b762f816..3ffe963b2b9 100644 --- a/extern/audaspace/plugins/ffmpeg/FFMPEG.cpp +++ b/extern/audaspace/plugins/ffmpeg/FFMPEG.cpp @@ -23,7 +23,9 @@ AUD_NAMESPACE_BEGIN FFMPEG::FFMPEG() { +#if LIBAVCODEC_VERSION_MAJOR < 58 av_register_all(); +#endif } void FFMPEG::registerPlugin() diff --git a/extern/audaspace/plugins/ffmpeg/FFMPEGReader.cpp b/extern/audaspace/plugins/ffmpeg/FFMPEGReader.cpp index 6b79cc5abfd..2da84ce0d4c 100644 --- a/extern/audaspace/plugins/ffmpeg/FFMPEGReader.cpp +++ b/extern/audaspace/plugins/ffmpeg/FFMPEGReader.cpp @@ -22,37 +22,37 @@ extern "C" { #include <libavcodec/avcodec.h> #include <libavformat/avio.h> +#include <libavutil/avutil.h> } AUD_NAMESPACE_BEGIN +#if LIBAVCODEC_VERSION_MAJOR < 58 +#define FFMPEG_OLD_CODE +#endif + int FFMPEGReader::decode(AVPacket& packet, Buffer& buffer) { - AVFrame* frame = nullptr; + int buf_size = buffer.getSize(); + int buf_pos = 0; + +#ifdef FFMPEG_OLD_CODE int got_frame; int read_length; uint8_t* orig_data = packet.data; int orig_size = packet.size; - int buf_size = buffer.getSize(); - int buf_pos = 0; - while(packet.size > 0) { got_frame = 0; - if(!frame) - frame = av_frame_alloc(); - else - av_frame_unref(frame); - - read_length = avcodec_decode_audio4(m_codecCtx, frame, &got_frame, &packet); + read_length = avcodec_decode_audio4(m_codecCtx, m_frame, &got_frame, &packet); if(read_length < 0) break; if(got_frame) { - int data_size = av_samples_get_buffer_size(nullptr, m_codecCtx->channels, frame->nb_samples, m_codecCtx->sample_fmt, 1); + int data_size = av_samples_get_buffer_size(nullptr, m_codecCtx->channels, m_frame->nb_samples, m_codecCtx->sample_fmt, 1); if(buf_size - buf_pos < data_size) { @@ -62,18 +62,18 @@ int FFMPEGReader::decode(AVPacket& packet, Buffer& buffer) if(m_tointerleave) { - int single_size = data_size / m_codecCtx->channels / frame->nb_samples; + int single_size = data_size / m_codecCtx->channels / m_frame->nb_samples; for(int channel = 0; channel < m_codecCtx->channels; channel++) { - for(int i = 0; i < frame->nb_samples; i++) + for(int i = 0; i < m_frame->nb_samples; i++) { std::memcpy(((data_t*)buffer.getBuffer()) + buf_pos + ((m_codecCtx->channels * i) + channel) * single_size, - frame->data[channel] + i * single_size, single_size); + m_frame->data[channel] + i * single_size, single_size); } } } else - std::memcpy(((data_t*)buffer.getBuffer()) + buf_pos, frame->data[0], data_size); + std::memcpy(((data_t*)buffer.getBuffer()) + buf_pos, m_frame->data[0], data_size); buf_pos += data_size; } @@ -83,7 +83,42 @@ int FFMPEGReader::decode(AVPacket& packet, Buffer& buffer) packet.data = orig_data; packet.size = orig_size; - av_free(frame); +#else + avcodec_send_packet(m_codecCtx, &packet); + + while(true) + { + auto ret = avcodec_receive_frame(m_codecCtx, m_frame); + + if(ret != 0) + break; + + int data_size = av_samples_get_buffer_size(nullptr, m_codecCtx->channels, m_frame->nb_samples, m_codecCtx->sample_fmt, 1); + + if(buf_size - buf_pos < data_size) + { + buffer.resize(buf_size + data_size, true); + buf_size += data_size; + } + + if(m_tointerleave) + { + int single_size = data_size / m_codecCtx->channels / m_frame->nb_samples; + for(int channel = 0; channel < m_codecCtx->channels; channel++) + { + for(int i = 0; i < m_frame->nb_samples; i++) + { + std::memcpy(((data_t*)buffer.getBuffer()) + buf_pos + ((m_codecCtx->channels * i) + channel) * single_size, + m_frame->data[channel] + i * single_size, single_size); + } + } + } + else + std::memcpy(((data_t*)buffer.getBuffer()) + buf_pos, m_frame->data[0], data_size); + + buf_pos += data_size; + } +#endif return buf_pos; } @@ -101,7 +136,11 @@ void FFMPEGReader::init() for(unsigned int i = 0; i < m_formatCtx->nb_streams; i++) { +#ifdef FFMPEG_OLD_CODE if((m_formatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO) +#else + if((m_formatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) +#endif && (m_stream < 0)) { m_stream=i; @@ -112,12 +151,34 @@ void FFMPEGReader::init() if(m_stream == -1) AUD_THROW(FileException, "File couldn't be read, no audio stream found by ffmpeg."); - m_codecCtx = m_formatCtx->streams[m_stream]->codec; - // get a decoder and open it - AVCodec* aCodec = avcodec_find_decoder(m_codecCtx->codec_id); +#ifndef FFMPEG_OLD_CODE + AVCodec* aCodec = avcodec_find_decoder(m_formatCtx->streams[m_stream]->codecpar->codec_id); + if(!aCodec) AUD_THROW(FileException, "File couldn't be read, no decoder found with ffmpeg."); +#endif + + m_frame = av_frame_alloc(); + + if(!m_frame) + AUD_THROW(FileException, "File couldn't be read, ffmpeg frame couldn't be allocated."); + +#ifdef FFMPEG_OLD_CODE + m_codecCtx = m_formatCtx->streams[m_stream]->codec; + + AVCodec* aCodec = avcodec_find_decoder(m_codecCtx->codec_id); +#else + m_codecCtx = avcodec_alloc_context3(aCodec); +#endif + + if(!m_codecCtx) + AUD_THROW(FileException, "File couldn't be read, ffmpeg context couldn't be allocated."); + +#ifndef FFMPEG_OLD_CODE + if(avcodec_parameters_to_context(m_codecCtx, m_formatCtx->streams[m_stream]->codecpar) < 0) + AUD_THROW(FileException, "File couldn't be read, ffmpeg decoder parameters couldn't be copied to decoder context."); +#endif if(avcodec_open2(m_codecCtx, aCodec, nullptr) < 0) AUD_THROW(FileException, "File couldn't be read, ffmpeg codec couldn't be opened."); @@ -157,6 +218,8 @@ void FFMPEGReader::init() FFMPEGReader::FFMPEGReader(std::string filename) : m_pkgbuf(), m_formatCtx(nullptr), + m_codecCtx(nullptr), + m_frame(nullptr), m_aviocontext(nullptr), m_membuf(nullptr) { @@ -177,12 +240,14 @@ FFMPEGReader::FFMPEGReader(std::string filename) : FFMPEGReader::FFMPEGReader(std::shared_ptr<Buffer> buffer) : m_pkgbuf(), + m_codecCtx(nullptr), + m_frame(nullptr), m_membuffer(buffer), m_membufferpos(0) { - m_membuf = reinterpret_cast<data_t*>(av_malloc(FF_MIN_BUFFER_SIZE + FF_INPUT_BUFFER_PADDING_SIZE)); + m_membuf = reinterpret_cast<data_t*>(av_malloc(AV_INPUT_BUFFER_MIN_SIZE + AV_INPUT_BUFFER_PADDING_SIZE)); - m_aviocontext = avio_alloc_context(m_membuf, FF_MIN_BUFFER_SIZE, 0, this, read_packet, nullptr, seek_packet); + m_aviocontext = avio_alloc_context(m_membuf, AV_INPUT_BUFFER_MIN_SIZE, 0, this, read_packet, nullptr, seek_packet); if(!m_aviocontext) { @@ -212,7 +277,14 @@ FFMPEGReader::FFMPEGReader(std::shared_ptr<Buffer> buffer) : FFMPEGReader::~FFMPEGReader() { + if(m_frame) + av_frame_free(&m_frame); +#ifdef FFMPEG_OLD_CODE avcodec_close(m_codecCtx); +#else + if(m_codecCtx) + avcodec_free_context(&m_codecCtx); +#endif avformat_close_input(&m_formatCtx); } @@ -312,7 +384,7 @@ void FFMPEGReader::seek(int position) } } } - av_free_packet(&packet); + av_packet_unref(&packet); } } else @@ -343,7 +415,7 @@ Specs FFMPEGReader::getSpecs() const void FFMPEGReader::read(int& length, bool& eos, sample_t* buffer) { // read packages and decode them - AVPacket packet; + AVPacket packet = {}; int data_size = 0; int pkgbuf_pos; int left = length; @@ -359,7 +431,7 @@ void FFMPEGReader::read(int& length, bool& eos, sample_t* buffer) data_size = std::min(pkgbuf_pos, left * sample_size); m_convert((data_t*) buf, (data_t*) m_pkgbuf.getBuffer(), data_size / AUD_FORMAT_SIZE(m_specs.format)); buf += data_size / AUD_FORMAT_SIZE(m_specs.format); - left -= data_size/sample_size; + left -= data_size / sample_size; } // for each frame read as long as there isn't enough data already @@ -375,9 +447,9 @@ void FFMPEGReader::read(int& length, bool& eos, sample_t* buffer) data_size = std::min(pkgbuf_pos, left * sample_size); m_convert((data_t*) buf, (data_t*) m_pkgbuf.getBuffer(), data_size / AUD_FORMAT_SIZE(m_specs.format)); buf += data_size / AUD_FORMAT_SIZE(m_specs.format); - left -= data_size/sample_size; + left -= data_size / sample_size; } - av_free_packet(&packet); + av_packet_unref(&packet); } // read more data than necessary? if(pkgbuf_pos > data_size) diff --git a/extern/audaspace/plugins/ffmpeg/FFMPEGReader.h b/extern/audaspace/plugins/ffmpeg/FFMPEGReader.h index e2ae959912d..a69ac7709c8 100644 --- a/extern/audaspace/plugins/ffmpeg/FFMPEGReader.h +++ b/extern/audaspace/plugins/ffmpeg/FFMPEGReader.h @@ -80,6 +80,11 @@ private: AVCodecContext* m_codecCtx; /** + * The AVFrame structure for using ffmpeg. + */ + AVFrame* m_frame; + + /** * The AVIOContext to read the data from. */ AVIOContext* m_aviocontext; diff --git a/extern/audaspace/plugins/ffmpeg/FFMPEGWriter.cpp b/extern/audaspace/plugins/ffmpeg/FFMPEGWriter.cpp index f79f0f7fc6b..09b70897c31 100644 --- a/extern/audaspace/plugins/ffmpeg/FFMPEGWriter.cpp +++ b/extern/audaspace/plugins/ffmpeg/FFMPEGWriter.cpp @@ -27,6 +27,10 @@ extern "C" { AUD_NAMESPACE_BEGIN +#if LIBAVCODEC_VERSION_MAJOR < 58 +#define FFMPEG_OLD_CODE +#endif + void FFMPEGWriter::encode() { sample_t* data = m_input_buffer.getBuffer(); @@ -58,82 +62,106 @@ void FFMPEGWriter::encode() if(m_input_size) m_convert(reinterpret_cast<data_t*>(data), reinterpret_cast<data_t*>(data), m_input_samples * m_specs.channels); - AVPacket packet; - - packet.data = nullptr; - packet.size = 0; +#ifdef FFMPEG_OLD_CODE + m_packet->data = nullptr; + m_packet->size = 0; - av_init_packet(&packet); + av_init_packet(m_packet); - AVFrame* frame = av_frame_alloc(); - av_frame_unref(frame); + av_frame_unref(m_frame); int got_packet; +#endif - frame->nb_samples = m_input_samples; - frame->format = m_codecCtx->sample_fmt; - frame->channel_layout = m_codecCtx->channel_layout; + m_frame->nb_samples = m_input_samples; + m_frame->format = m_codecCtx->sample_fmt; + m_frame->channel_layout = m_codecCtx->channel_layout; - if(avcodec_fill_audio_frame(frame, m_specs.channels, m_codecCtx->sample_fmt, reinterpret_cast<data_t*>(data), m_input_buffer.getSize(), 0) < 0) + if(avcodec_fill_audio_frame(m_frame, m_specs.channels, m_codecCtx->sample_fmt, reinterpret_cast<data_t*>(data), m_input_buffer.getSize(), 0) < 0) AUD_THROW(FileException, "File couldn't be written, filling the audio frame failed with ffmpeg."); AVRational sample_time = { 1, static_cast<int>(m_specs.rate) }; - frame->pts = av_rescale_q(m_position - m_input_samples, m_codecCtx->time_base, sample_time); + m_frame->pts = av_rescale_q(m_position - m_input_samples, m_codecCtx->time_base, sample_time); - if(avcodec_encode_audio2(m_codecCtx, &packet, frame, &got_packet)) +#ifdef FFMPEG_OLD_CODE + if(avcodec_encode_audio2(m_codecCtx, m_packet, m_frame, &got_packet)) { - av_frame_free(&frame); AUD_THROW(FileException, "File couldn't be written, audio encoding failed with ffmpeg."); } if(got_packet) { - packet.flags |= AV_PKT_FLAG_KEY; - packet.stream_index = m_stream->index; - if(av_write_frame(m_formatCtx, &packet) < 0) + m_packet->flags |= AV_PKT_FLAG_KEY; + m_packet->stream_index = m_stream->index; + if(av_write_frame(m_formatCtx, m_packet) < 0) { - av_free_packet(&packet); - av_frame_free(&frame); + av_free_packet(m_packet); AUD_THROW(FileException, "Frame couldn't be writen to the file with ffmpeg."); } - av_free_packet(&packet); + av_free_packet(m_packet); } +#else + if(avcodec_send_frame(m_codecCtx, m_frame) < 0) + AUD_THROW(FileException, "File couldn't be written, audio encoding failed with ffmpeg."); + + while(avcodec_receive_packet(m_codecCtx, m_packet) == 0) + { + m_packet->stream_index = m_stream->index; - av_frame_free(&frame); + if(av_write_frame(m_formatCtx, m_packet) < 0) + AUD_THROW(FileException, "Frame couldn't be writen to the file with ffmpeg."); + } +#endif } void FFMPEGWriter::close() { +#ifdef FFMPEG_OLD_CODE int got_packet = true; while(got_packet) { - AVPacket packet; + m_packet->data = nullptr; + m_packet->size = 0; - packet.data = nullptr; - packet.size = 0; + av_init_packet(m_packet); - av_init_packet(&packet); - - if(avcodec_encode_audio2(m_codecCtx, &packet, nullptr, &got_packet)) + if(avcodec_encode_audio2(m_codecCtx, m_packet, nullptr, &got_packet)) AUD_THROW(FileException, "File end couldn't be written, audio encoding failed with ffmpeg."); if(got_packet) { - packet.flags |= AV_PKT_FLAG_KEY; - packet.stream_index = m_stream->index; - if(av_write_frame(m_formatCtx, &packet)) + m_packet->flags |= AV_PKT_FLAG_KEY; + m_packet->stream_index = m_stream->index; + if(av_write_frame(m_formatCtx, m_packet)) { - av_free_packet(&packet); + av_free_packet(m_packet); AUD_THROW(FileException, "Final frames couldn't be writen to the file with ffmpeg."); } - av_free_packet(&packet); + av_free_packet(m_packet); } } +#else + if(avcodec_send_frame(m_codecCtx, nullptr) < 0) + AUD_THROW(FileException, "File couldn't be written, audio encoding failed with ffmpeg."); + + while(avcodec_receive_packet(m_codecCtx, m_packet) == 0) + { + m_packet->stream_index = m_stream->index; + + if(av_write_frame(m_formatCtx, m_packet) < 0) + AUD_THROW(FileException, "Frame couldn't be writen to the file with ffmpeg."); + } +#endif } FFMPEGWriter::FFMPEGWriter(std::string filename, DeviceSpecs specs, Container format, Codec codec, unsigned int bitrate) : m_position(0), m_specs(specs), + m_formatCtx(nullptr), + m_codecCtx(nullptr), + m_stream(nullptr), + m_packet(nullptr), + m_frame(nullptr), m_input_samples(0), m_deinterleave(false) { @@ -142,75 +170,105 @@ FFMPEGWriter::FFMPEGWriter(std::string filename, DeviceSpecs specs, Container fo if(avformat_alloc_output_context2(&m_formatCtx, nullptr, formats[format], filename.c_str()) < 0) AUD_THROW(FileException, "File couldn't be written, format couldn't be found with ffmpeg."); - m_outputFmt = m_formatCtx->oformat; + AVOutputFormat* outputFmt = m_formatCtx->oformat; - if(!m_outputFmt) { + if(!outputFmt) { avformat_free_context(m_formatCtx); AUD_THROW(FileException, "File couldn't be written, output format couldn't be found with ffmpeg."); } - m_outputFmt->audio_codec = AV_CODEC_ID_NONE; + outputFmt->audio_codec = AV_CODEC_ID_NONE; switch(codec) { case CODEC_AAC: - m_outputFmt->audio_codec = AV_CODEC_ID_AAC; + outputFmt->audio_codec = AV_CODEC_ID_AAC; break; case CODEC_AC3: - m_outputFmt->audio_codec = AV_CODEC_ID_AC3; + outputFmt->audio_codec = AV_CODEC_ID_AC3; break; case CODEC_FLAC: - m_outputFmt->audio_codec = AV_CODEC_ID_FLAC; + outputFmt->audio_codec = AV_CODEC_ID_FLAC; break; case CODEC_MP2: - m_outputFmt->audio_codec = AV_CODEC_ID_MP2; + outputFmt->audio_codec = AV_CODEC_ID_MP2; break; case CODEC_MP3: - m_outputFmt->audio_codec = AV_CODEC_ID_MP3; + outputFmt->audio_codec = AV_CODEC_ID_MP3; break; case CODEC_OPUS: - m_outputFmt->audio_codec = AV_CODEC_ID_OPUS; + outputFmt->audio_codec = AV_CODEC_ID_OPUS; break; case CODEC_PCM: switch(specs.format) { case FORMAT_U8: - m_outputFmt->audio_codec = AV_CODEC_ID_PCM_U8; + outputFmt->audio_codec = AV_CODEC_ID_PCM_U8; break; case FORMAT_S16: - m_outputFmt->audio_codec = AV_CODEC_ID_PCM_S16LE; + outputFmt->audio_codec = AV_CODEC_ID_PCM_S16LE; break; case FORMAT_S24: - m_outputFmt->audio_codec = AV_CODEC_ID_PCM_S24LE; + outputFmt->audio_codec = AV_CODEC_ID_PCM_S24LE; break; case FORMAT_S32: - m_outputFmt->audio_codec = AV_CODEC_ID_PCM_S32LE; + outputFmt->audio_codec = AV_CODEC_ID_PCM_S32LE; break; case FORMAT_FLOAT32: - m_outputFmt->audio_codec = AV_CODEC_ID_PCM_F32LE; + outputFmt->audio_codec = AV_CODEC_ID_PCM_F32LE; break; case FORMAT_FLOAT64: - m_outputFmt->audio_codec = AV_CODEC_ID_PCM_F64LE; + outputFmt->audio_codec = AV_CODEC_ID_PCM_F64LE; break; default: - m_outputFmt->audio_codec = AV_CODEC_ID_NONE; + outputFmt->audio_codec = AV_CODEC_ID_NONE; break; } break; case CODEC_VORBIS: - m_outputFmt->audio_codec = AV_CODEC_ID_VORBIS; + outputFmt->audio_codec = AV_CODEC_ID_VORBIS; break; default: - m_outputFmt->audio_codec = AV_CODEC_ID_NONE; + outputFmt->audio_codec = AV_CODEC_ID_NONE; + break; + } + + uint64_t channel_layout = 0; + + switch(m_specs.channels) + { + case CHANNELS_MONO: + channel_layout = AV_CH_LAYOUT_MONO; + break; + case CHANNELS_STEREO: + channel_layout = AV_CH_LAYOUT_STEREO; + break; + case CHANNELS_STEREO_LFE: + channel_layout = AV_CH_LAYOUT_2POINT1; + break; + case CHANNELS_SURROUND4: + channel_layout = AV_CH_LAYOUT_QUAD; + break; + case CHANNELS_SURROUND5: + channel_layout = AV_CH_LAYOUT_5POINT0_BACK; + break; + case CHANNELS_SURROUND51: + channel_layout = AV_CH_LAYOUT_5POINT1_BACK; + break; + case CHANNELS_SURROUND61: + channel_layout = AV_CH_LAYOUT_6POINT1_BACK; + break; + case CHANNELS_SURROUND71: + channel_layout = AV_CH_LAYOUT_7POINT1; break; } try { - if(m_outputFmt->audio_codec == AV_CODEC_ID_NONE) + if(outputFmt->audio_codec == AV_CODEC_ID_NONE) AUD_THROW(FileException, "File couldn't be written, audio codec not found with ffmpeg."); - AVCodec* codec = avcodec_find_encoder(m_outputFmt->audio_codec); + AVCodec* codec = avcodec_find_encoder(outputFmt->audio_codec); if(!codec) AUD_THROW(FileException, "File couldn't be written, audio encoder couldn't be found with ffmpeg."); @@ -220,7 +278,14 @@ FFMPEGWriter::FFMPEGWriter(std::string filename, DeviceSpecs specs, Container fo m_stream->id = m_formatCtx->nb_streams - 1; +#ifdef FFMPEG_OLD_CODE m_codecCtx = m_stream->codec; +#else + m_codecCtx = avcodec_alloc_context3(codec); +#endif + + if(!m_codecCtx) + AUD_THROW(FileException, "File couldn't be written, context creation failed with ffmpeg."); switch(m_specs.format) { @@ -247,7 +312,7 @@ FFMPEGWriter::FFMPEGWriter(std::string filename, DeviceSpecs specs, Container fo } if(m_formatCtx->oformat->flags & AVFMT_GLOBALHEADER) - m_codecCtx->flags |= CODEC_FLAG_GLOBAL_HEADER; + m_codecCtx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; bool format_supported = false; @@ -328,9 +393,13 @@ FFMPEGWriter::FFMPEGWriter(std::string filename, DeviceSpecs specs, Container fo m_specs.rate = m_codecCtx->sample_rate; - m_codecCtx->codec_id = m_outputFmt->audio_codec; +#ifdef FFMPEG_OLD_CODE + m_codecCtx->codec_id = outputFmt->audio_codec; +#endif + m_codecCtx->codec_type = AVMEDIA_TYPE_AUDIO; m_codecCtx->bit_rate = bitrate; + m_codecCtx->channel_layout = channel_layout; m_codecCtx->channels = m_specs.channels; m_stream->time_base.num = m_codecCtx->time_base.num = 1; m_stream->time_base.den = m_codecCtx->time_base.den = m_codecCtx->sample_rate; @@ -338,6 +407,11 @@ FFMPEGWriter::FFMPEGWriter(std::string filename, DeviceSpecs specs, Container fo if(avcodec_open2(m_codecCtx, codec, nullptr) < 0) AUD_THROW(FileException, "File couldn't be written, encoder couldn't be opened with ffmpeg."); +#ifndef FFMPEG_OLD_CODE + if(avcodec_parameters_from_context(m_stream->codecpar, m_codecCtx) < 0) + AUD_THROW(FileException, "File couldn't be written, codec parameters couldn't be copied to the context."); +#endif + int samplesize = std::max(int(AUD_SAMPLE_SIZE(m_specs)), AUD_DEVICE_SAMPLE_SIZE(m_specs)); if((m_input_size = m_codecCtx->frame_size)) @@ -346,13 +420,26 @@ FFMPEGWriter::FFMPEGWriter(std::string filename, DeviceSpecs specs, Container fo if(avio_open(&m_formatCtx->pb, filename.c_str(), AVIO_FLAG_WRITE)) AUD_THROW(FileException, "File couldn't be written, file opening failed with ffmpeg."); - avformat_write_header(m_formatCtx, nullptr); + if(avformat_write_header(m_formatCtx, nullptr) < 0) + AUD_THROW(FileException, "File couldn't be written, writing the header failed."); } catch(Exception&) { +#ifndef FFMPEG_OLD_CODE + if(m_codecCtx) + avcodec_free_context(&m_codecCtx); +#endif avformat_free_context(m_formatCtx); throw; } + +#ifdef FFMPEG_OLD_CODE + m_packet = new AVPacket({}); +#else + m_packet = av_packet_alloc(); +#endif + + m_frame = av_frame_alloc(); } FFMPEGWriter::~FFMPEGWriter() @@ -365,9 +452,26 @@ FFMPEGWriter::~FFMPEGWriter() av_write_trailer(m_formatCtx); + if(m_frame) + av_frame_free(&m_frame); + + if(m_packet) + { +#ifdef FFMPEG_OLD_CODE + delete m_packet; +#else + av_packet_free(&m_packet); +#endif + } + +#ifdef FFMPEG_OLD_CODE avcodec_close(m_codecCtx); +#else + if(m_codecCtx) + avcodec_free_context(&m_codecCtx); +#endif - avio_close(m_formatCtx->pb); + avio_closep(&m_formatCtx->pb); avformat_free_context(m_formatCtx); } diff --git a/extern/audaspace/plugins/ffmpeg/FFMPEGWriter.h b/extern/audaspace/plugins/ffmpeg/FFMPEGWriter.h index 690185deb64..c22f479d83c 100644 --- a/extern/audaspace/plugins/ffmpeg/FFMPEGWriter.h +++ b/extern/audaspace/plugins/ffmpeg/FFMPEGWriter.h @@ -66,14 +66,19 @@ private: AVCodecContext* m_codecCtx; /** - * The AVOutputFormat structure for using ffmpeg. + * The AVStream structure for using ffmpeg. */ - AVOutputFormat* m_outputFmt; + AVStream* m_stream; /** - * The AVStream structure for using ffmpeg. + * The AVPacket structure for using ffmpeg. */ - AVStream* m_stream; + AVPacket* m_packet; + + /** + * The AVFrame structure for using ffmpeg. + */ + AVFrame* m_frame; /** * The input buffer for the format converted data before encoding. diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py index 5c68115cd86..721b395e596 100644 --- a/intern/cycles/blender/addon/ui.py +++ b/intern/cycles/blender/addon/ui.py @@ -1480,26 +1480,6 @@ class CYCLES_MATERIAL_PT_settings_surface(CyclesButtonsPanel, Panel): col = layout.column() col.prop(cmat, "sample_as_light", text="Multiple Importance") col.prop(cmat, "use_transparent_shadow") - - -class CYCLES_MATERIAL_PT_settings_geometry(CyclesButtonsPanel, Panel): - bl_label = "Geometry" - bl_parent_id = "CYCLES_MATERIAL_PT_settings" - bl_context = "material" - - @classmethod - def poll(cls, context): - return context.material and CyclesButtonsPanel.poll(context) - - def draw(self, context): - layout = self.layout - layout.use_property_split = True - - mat = context.material - cmat = mat.cycles - - col = layout.column() - col.prop(cmat, "displacement_method", text="Displacement Method") @@ -1674,29 +1654,7 @@ class CYCLES_SCENE_PT_simplify(CyclesButtonsPanel, Panel): self.layout.prop(rd, "use_simplify", text="") def draw(self, context): - layout = self.layout - layout.use_property_split = True - - scene = context.scene - rd = scene.render - cscene = scene.cycles - - layout.active = rd.use_simplify - - col = layout.column() - col.prop(cscene, "use_camera_cull") - sub = col.column() - sub.active = cscene.use_camera_cull - sub.prop(cscene, "camera_cull_margin") - - layout.separator() - - col = layout.column() - - col.prop(cscene, "use_distance_cull") - sub = col.column() - sub.active = cscene.use_distance_cull - sub.prop(cscene, "distance_cull_margin", text="Distance") + pass class CYCLES_SCENE_PT_simplify_viewport(CyclesButtonsPanel, Panel): @@ -1746,6 +1704,36 @@ class CYCLES_SCENE_PT_simplify_render(CyclesButtonsPanel, Panel): col.prop(cscene, "ao_bounces_render", text="AO Bounces") +class CYCLES_SCENE_PT_simplify_culling(CyclesButtonsPanel, Panel): + bl_label = "Culling" + bl_context = "scene" + bl_parent_id = "CYCLES_SCENE_PT_simplify" + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'CYCLES'} + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + + scene = context.scene + rd = scene.render + cscene = scene.cycles + + layout.active = rd.use_simplify + + col = layout.column() + col.prop(cscene, "use_camera_cull") + sub = col.column() + sub.active = cscene.use_camera_cull + sub.prop(cscene, "camera_cull_margin") + + col = layout.column() + col.prop(cscene, "use_distance_cull") + sub = col.column() + sub.active = cscene.use_distance_cull + sub.prop(cscene, "distance_cull_margin", text="Distance") + + def draw_device(self, context): scene = context.scene layout = self.layout @@ -1847,13 +1835,13 @@ classes = ( CYCLES_MATERIAL_PT_displacement, CYCLES_MATERIAL_PT_settings, CYCLES_MATERIAL_PT_settings_surface, - CYCLES_MATERIAL_PT_settings_geometry, CYCLES_MATERIAL_PT_settings_volume, CYCLES_RENDER_PT_bake, CYCLES_RENDER_PT_debug, CYCLES_SCENE_PT_simplify, CYCLES_SCENE_PT_simplify_viewport, CYCLES_SCENE_PT_simplify_render, + CYCLES_SCENE_PT_simplify_culling, ) diff --git a/intern/cycles/blender/blender_object.cpp b/intern/cycles/blender/blender_object.cpp index 3c38c7a4584..8ed3eafb488 100644 --- a/intern/cycles/blender/blender_object.cpp +++ b/intern/cycles/blender/blender_object.cpp @@ -482,7 +482,8 @@ static bool object_render_hide_original(BL::Object::type_enum ob_type, static bool object_render_hide(BL::Object& b_ob, bool top_level, bool parent_hide, - bool& hide_triangles) + bool& hide_triangles, + BL::Depsgraph::mode_enum depsgraph_mode) { /* check if we should render or hide particle emitter */ BL::Object::particle_systems_iterator b_psys; @@ -501,11 +502,16 @@ static bool object_render_hide(BL::Object& b_ob, has_particles = true; } + /* Both mode_PREVIEW and mode_VIEWPORT are treated the same here.*/ + const bool show_duplicator = depsgraph_mode == BL::Depsgraph::mode_RENDER + ? b_ob.show_duplicator_for_render() + : b_ob.show_duplicator_for_viewport(); + if(has_particles) { - show_emitter = b_ob.show_duplicator_for_render(); + show_emitter = show_duplicator; hide_emitter = !show_emitter; } else if(b_ob.is_duplicator()) { - if(top_level || b_ob.show_duplicator_for_render()) { + if(top_level || show_duplicator) { hide_as_dupli_parent = true; } } @@ -563,6 +569,8 @@ void BlenderSync::sync_objects(BL::Depsgraph& b_depsgraph, float motion_time) bool cancel = false; bool use_portal = false; + BL::Depsgraph::mode_enum depsgraph_mode = b_depsgraph.mode(); + BL::Depsgraph::object_instances_iterator b_instance_iter; for(b_depsgraph.object_instances.begin(b_instance_iter); b_instance_iter != b_depsgraph.object_instances.end() && !cancel; @@ -582,7 +590,7 @@ void BlenderSync::sync_objects(BL::Depsgraph& b_depsgraph, float motion_time) /* test if object needs to be hidden */ bool hide_tris; - if(!object_render_hide(b_ob, true, true, hide_tris)) { + if(!object_render_hide(b_ob, true, true, hide_tris, depsgraph_mode)) { /* object itself */ sync_object(b_depsgraph, b_instance, diff --git a/intern/cycles/kernel/bvh/bvh.h b/intern/cycles/kernel/bvh/bvh.h index c0a5bb434ea..d3e0b25a200 100644 --- a/intern/cycles/kernel/bvh/bvh.h +++ b/intern/cycles/kernel/bvh/bvh.h @@ -212,21 +212,20 @@ ccl_device_intersect void scene_intersect_local(KernelGlobals *kg, { #ifdef __OBJECT_MOTION__ if(kernel_data.bvh.have_motion) { - bvh_intersect_local_motion(kg, - &ray, - local_isect, - local_object, - lcg_state, - max_hits); - return; + return bvh_intersect_local_motion(kg, + &ray, + local_isect, + local_object, + lcg_state, + max_hits); } #endif /* __OBJECT_MOTION__ */ - bvh_intersect_local(kg, - &ray, - local_isect, - local_object, - lcg_state, - max_hits); + return bvh_intersect_local(kg, + &ray, + local_isect, + local_object, + lcg_state, + max_hits); } #endif diff --git a/intern/cycles/kernel/bvh/bvh_local.h b/intern/cycles/kernel/bvh/bvh_local.h index 605d4166819..9292cc76a5c 100644 --- a/intern/cycles/kernel/bvh/bvh_local.h +++ b/intern/cycles/kernel/bvh/bvh_local.h @@ -246,22 +246,20 @@ ccl_device_inline void BVH_FUNCTION_NAME(KernelGlobals *kg, switch(kernel_data.bvh.bvh_layout) { #ifdef __QBVH__ case BVH_LAYOUT_BVH4: - BVH_FUNCTION_FULL_NAME(QBVH)(kg, - ray, - local_isect, - local_object, - lcg_state, - max_hits); - break; + return BVH_FUNCTION_FULL_NAME(QBVH)(kg, + ray, + local_isect, + local_object, + lcg_state, + max_hits); #endif case BVH_LAYOUT_BVH2: - BVH_FUNCTION_FULL_NAME(BVH)(kg, - ray, - local_isect, - local_object, - lcg_state, - max_hits); - break; + return BVH_FUNCTION_FULL_NAME(BVH)(kg, + ray, + local_isect, + local_object, + lcg_state, + max_hits); } kernel_assert(!"Should not happen"); } diff --git a/intern/gawain/gawain/gwn_common.h b/intern/gawain/gawain/gwn_common.h index dc0a52ca096..f1512bf4466 100644 --- a/intern/gawain/gawain/gwn_common.h +++ b/intern/gawain/gawain/gwn_common.h @@ -33,4 +33,4 @@ # define GWN_INLINE static __forceinline #else # define GWN_INLINE static inline __attribute__((always_inline)) __attribute__((__unused__)) -#endif
\ No newline at end of file +#endif diff --git a/intern/gawain/src/gwn_batch.c b/intern/gawain/src/gwn_batch.c index 2e3a4eff0f0..64d5d146578 100644 --- a/intern/gawain/src/gwn_batch.c +++ b/intern/gawain/src/gwn_batch.c @@ -179,7 +179,7 @@ int GWN_batch_vertbuf_add_ex( return v; } } - + // we only make it this far if there is no room for another Gwn_VertBuf #if TRUST_NO_ONE assert(false); diff --git a/intern/gawain/src/gwn_immediate.c b/intern/gawain/src/gwn_immediate.c index 006af0abe01..b0b587d1b8c 100644 --- a/intern/gawain/src/gwn_immediate.c +++ b/intern/gawain/src/gwn_immediate.c @@ -47,7 +47,7 @@ typedef struct { GLuint vbo_id; GLuint vao_id; - + GLuint bound_program; const Gwn_ShaderInterface* shader_interface; Gwn_AttrBinding attrib_binding; diff --git a/intern/ghost/CMakeLists.txt b/intern/ghost/CMakeLists.txt index e4b74ae24af..d8330d43c16 100644 --- a/intern/ghost/CMakeLists.txt +++ b/intern/ghost/CMakeLists.txt @@ -280,7 +280,7 @@ elseif(WIN32) if(NOT WITH_GL_EGL) list(APPEND SRC intern/GHOST_ContextWGL.cpp - + intern/GHOST_ContextWGL.h ) endif() @@ -307,7 +307,7 @@ endif() if(WITH_GL_EGL AND NOT (WITH_HEADLESS OR WITH_GHOST_SDL)) list(APPEND SRC intern/GHOST_ContextEGL.cpp - + intern/GHOST_ContextEGL.h ) endif() diff --git a/intern/ghost/GHOST_C-api.h b/intern/ghost/GHOST_C-api.h index 071474e57dc..a911c4560e4 100644 --- a/intern/ghost/GHOST_C-api.h +++ b/intern/ghost/GHOST_C-api.h @@ -36,7 +36,7 @@ #include "GHOST_Types.h" #ifdef __cplusplus -extern "C" { +extern "C" { #endif /** @@ -103,7 +103,7 @@ extern GHOST_TUns64 GHOST_GetMilliSeconds(GHOST_SystemHandle systemhandle); /** * Installs a timer. - * Note that, on most operating systems, messages need to be processed in order + * Note that, on most operating systems, messages need to be processed in order * for the timer callbacks to be invoked. * \param systemhandle The handle to the system * \param delay The time to wait for the first call to the timerProc (in milliseconds) @@ -165,7 +165,7 @@ extern void GHOST_GetAllDisplayDimensions(GHOST_SystemHandle systemhandle, /** * Create a new window. - * The new window is added to the list of windows managed. + * The new window is added to the list of windows managed. * Never explicitly delete the window, use disposeWindow() instead. * \param systemhandle The handle to the system * \param title The name of the window (displayed in the title bar of the window if the OS supports it). @@ -218,7 +218,7 @@ extern GHOST_TUserDataPtr GHOST_GetWindowUserData(GHOST_WindowHandle windowhandl * \param windowhandle The handle to the window * \param userdata The window user data. */ -extern void GHOST_SetWindowUserData(GHOST_WindowHandle windowhandle, +extern void GHOST_SetWindowUserData(GHOST_WindowHandle windowhandle, GHOST_TUserDataPtr userdata); /** @@ -488,7 +488,7 @@ extern GHOST_TEventType GHOST_GetEventType(GHOST_EventHandle eventhandle); extern GHOST_TUns64 GHOST_GetEventTime(GHOST_EventHandle eventhandle); /** - * Returns the window this event was generated on, + * Returns the window this event was generated on, * or NULL if it is a 'system' event. * \param eventhandle The handle to the event * \return The generating window. @@ -566,7 +566,7 @@ extern void GHOST_SetTitle(GHOST_WindowHandle windowhandle, /** * Returns the title displayed in the title bar. The title * should be free'd with free(). - * + * * \param windowhandle The handle to the window * \return The title, free with free(). */ diff --git a/intern/ghost/GHOST_IEvent.h b/intern/ghost/GHOST_IEvent.h index ba5d9ee33b9..83273716950 100644 --- a/intern/ghost/GHOST_IEvent.h +++ b/intern/ghost/GHOST_IEvent.h @@ -42,8 +42,8 @@ class GHOST_IWindow; * Interface class for events received from GHOST. * You should not need to inherit this class. The system will pass these events * to the GHOST_IEventConsumer::processEvent() method of event consumers.<br> - * Use the getType() method to retrieve the type of event and the getData() - * method to get the event data out. Using the event type you can cast the + * Use the getType() method to retrieve the type of event and the getData() + * method to get the event data out. Using the event type you can cast the * event data to the correct event dat structure. * \see GHOST_IEventConsumer#processEvent * \see GHOST_TEventType @@ -73,18 +73,18 @@ public: virtual GHOST_TUns64 getTime() = 0; /** - * Returns the window this event was generated on, + * Returns the window this event was generated on, * or NULL if it is a 'system' event. * \return The generating window. */ virtual GHOST_IWindow *getWindow() = 0; - + /** * Returns the event data. * \return The event data. */ virtual GHOST_TEventDataPtr getData() = 0; - + #ifdef WITH_CXX_GUARDEDALLOC MEM_CXX_CLASS_ALLOC_FUNCS("GHOST:GHOST_IEvent") #endif diff --git a/intern/ghost/GHOST_ISystem.h b/intern/ghost/GHOST_ISystem.h index 25b7fb26e0e..1a6c0f9a1bf 100644 --- a/intern/ghost/GHOST_ISystem.h +++ b/intern/ghost/GHOST_ISystem.h @@ -315,7 +315,7 @@ public: * \return The current status. */ virtual bool getFullScreen(void) = 0; - + /** * Native pixel size support (MacBook 'retina'). */ diff --git a/intern/ghost/GHOST_ISystemPaths.h b/intern/ghost/GHOST_ISystemPaths.h index 8f81a226f94..14b1183af2c 100644 --- a/intern/ghost/GHOST_ISystemPaths.h +++ b/intern/ghost/GHOST_ISystemPaths.h @@ -4,7 +4,7 @@ * 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. + * 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 @@ -18,7 +18,7 @@ * The Original Code is Copyright (C) 2009 Blender Foundation. * All rights reserved. * - * + * * Contributor(s): Blender Foundation * * ***** END GPL LICENSE BLOCK ***** diff --git a/intern/ghost/GHOST_ITimerTask.h b/intern/ghost/GHOST_ITimerTask.h index 9bea697cbc8..dd3db5623cc 100644 --- a/intern/ghost/GHOST_ITimerTask.h +++ b/intern/ghost/GHOST_ITimerTask.h @@ -39,11 +39,11 @@ /** * Interface for a timer task. * Timer tasks are created by the system and can be installed by the system. - * After installation, the timer callback-procedure or "timerProc" will be called + * After installation, the timer callback-procedure or "timerProc" will be called * periodically. You should not need to inherit this class. It is passed to the * application in the timer-callback.<br> * <br> - * Note that GHOST processes timers in the UI thread. You should ask GHOST + * Note that GHOST processes timers in the UI thread. You should ask GHOST * process messages in order for the timer-callbacks to be called. * \see GHOST_ISystem#installTimer * \see GHOST_TimerProcPtr @@ -77,7 +77,7 @@ public: * \return The timer user data. */ virtual GHOST_TUserDataPtr getUserData() const = 0; - + /** * Changes the time user data. * \param userData: The timer user data. diff --git a/intern/ghost/GHOST_IWindow.h b/intern/ghost/GHOST_IWindow.h index 4a4d6be5ced..5a3403bcbd3 100644 --- a/intern/ghost/GHOST_IWindow.h +++ b/intern/ghost/GHOST_IWindow.h @@ -361,7 +361,7 @@ public: */ virtual void endIME() = 0; #endif /* WITH_INPUT_IME */ - + #ifdef WITH_CXX_GUARDEDALLOC MEM_CXX_CLASS_ALLOC_FUNCS("GHOST:GHOST_IWindow") #endif diff --git a/intern/ghost/GHOST_Path-api.h b/intern/ghost/GHOST_Path-api.h index 5af3adaa570..9a4d065d2ad 100644 --- a/intern/ghost/GHOST_Path-api.h +++ b/intern/ghost/GHOST_Path-api.h @@ -36,7 +36,7 @@ #include "GHOST_Types.h" #ifdef __cplusplus -extern "C" { +extern "C" { #endif GHOST_DECLARE_HANDLE(GHOST_SystemPathsHandle); @@ -79,7 +79,7 @@ extern const GHOST_TUns8 *GHOST_getBinaryDir(void); extern void GHOST_addToSystemRecentFiles(const char *filename); #ifdef __cplusplus -} +} #endif #endif diff --git a/intern/ghost/GHOST_Types.h b/intern/ghost/GHOST_Types.h index 02b5063e515..b206bb677a7 100644 --- a/intern/ghost/GHOST_Types.h +++ b/intern/ghost/GHOST_Types.h @@ -77,7 +77,7 @@ typedef enum { GHOST_kSuccess } GHOST_TSuccess; -/* Xtilt and Ytilt represent how much the pen is tilted away from +/* Xtilt and Ytilt represent how much the pen is tilted away from * vertically upright in either the X or Y direction, with X and Y the * axes of the tablet surface. * In other words, Xtilt and Ytilt are components of a vector created by projecting @@ -190,12 +190,12 @@ typedef enum { GHOST_kEventWindowSize, GHOST_kEventWindowMove, GHOST_kEventWindowDPIHintChanged, - + GHOST_kEventDraggingEntered, GHOST_kEventDraggingUpdated, GHOST_kEventDraggingExited, GHOST_kEventDraggingDropDone, - + GHOST_kEventOpenMainFile, // Needed for Cocoa to open double-clicked .blend file at startup GHOST_kEventNativeResolutionChange, // Needed for Cocoa when window moves to other display @@ -214,9 +214,9 @@ typedef enum { GHOST_kStandardCursorDefault = 0, GHOST_kStandardCursorRightArrow, GHOST_kStandardCursorLeftArrow, - GHOST_kStandardCursorInfo, + GHOST_kStandardCursorInfo, GHOST_kStandardCursorDestroy, - GHOST_kStandardCursorHelp, + GHOST_kStandardCursorHelp, GHOST_kStandardCursorCycle, GHOST_kStandardCursorSpray, GHOST_kStandardCursorWait, @@ -233,7 +233,7 @@ typedef enum { GHOST_kStandardCursorBottomRightCorner, GHOST_kStandardCursorBottomLeftCorner, GHOST_kStandardCursorCopy, - GHOST_kStandardCursorCustom, + GHOST_kStandardCursorCustom, GHOST_kStandardCursorPencil, GHOST_kStandardCursorNumCursors @@ -247,7 +247,7 @@ typedef enum { GHOST_kKeyLinefeed, GHOST_kKeyClear, GHOST_kKeyEnter = 0x0D, - + GHOST_kKeyEsc = 0x1B, GHOST_kKeySpace = ' ', GHOST_kKeyQuote = 0x27, @@ -305,7 +305,7 @@ typedef enum { GHOST_kKeyBackslash = 0x5C, GHOST_kKeyAccentGrave = '`', - + GHOST_kKeyLeftShift = 0x100, GHOST_kKeyRightShift, GHOST_kKeyLeftControl, @@ -377,7 +377,7 @@ typedef enum { GHOST_kKeyF22, GHOST_kKeyF23, GHOST_kKeyF24, - + // Multimedia keypad buttons GHOST_kKeyMediaPlay, GHOST_kKeyMediaStop, @@ -418,7 +418,7 @@ typedef enum { GHOST_kTrackpadEventSwipe, /* Reserved, not used for now */ GHOST_kTrackpadEventMagnify } GHOST_TTrackpadEventSubTypes; - + typedef struct { /** The event subtype */ diff --git a/intern/ghost/intern/GHOST_Buttons.h b/intern/ghost/intern/GHOST_Buttons.h index 0aa93a2fad0..aed9a3cc81f 100644 --- a/intern/ghost/intern/GHOST_Buttons.h +++ b/intern/ghost/intern/GHOST_Buttons.h @@ -38,7 +38,7 @@ /** * This struct stores the state of the mouse buttons. - * Buttons can be set using button masks. + * Buttons can be set using button masks. * \author Maarten Gribnau * \date May 15, 2001 */ diff --git a/intern/ghost/intern/GHOST_C-api.cpp b/intern/ghost/intern/GHOST_C-api.cpp index c89ef49de33..90956cf541a 100644 --- a/intern/ghost/intern/GHOST_C-api.cpp +++ b/intern/ghost/intern/GHOST_C-api.cpp @@ -119,7 +119,7 @@ void GHOST_GetMainDisplayDimensions(GHOST_SystemHandle systemhandle, GHOST_TUns32 *height) { GHOST_ISystem *system = (GHOST_ISystem *) systemhandle; - + system->getMainDisplayDimensions(*width, *height); } @@ -182,7 +182,7 @@ GHOST_TSuccess GHOST_DisposeWindow(GHOST_SystemHandle systemhandle, { GHOST_ISystem *system = (GHOST_ISystem *) systemhandle; GHOST_IWindow *window = (GHOST_IWindow *) windowhandle; - + return system->disposeWindow(window); } @@ -193,7 +193,7 @@ int GHOST_ValidWindow(GHOST_SystemHandle systemhandle, { GHOST_ISystem *system = (GHOST_ISystem *) systemhandle; GHOST_IWindow *window = (GHOST_IWindow *) windowhandle; - + return (int) system->validWindow(window); } @@ -211,7 +211,7 @@ GHOST_WindowHandle GHOST_BeginFullScreen(GHOST_SystemHandle systemhandle, bstereoVisual = true; else bstereoVisual = false; - + system->beginFullScreen(*setting, &window, bstereoVisual); return (GHOST_WindowHandle)window; @@ -240,7 +240,7 @@ int GHOST_GetFullScreen(GHOST_SystemHandle systemhandle) int GHOST_ProcessEvents(GHOST_SystemHandle systemhandle, int waitForEvent) { GHOST_ISystem *system = (GHOST_ISystem *) systemhandle; - + return (int) system->processEvents(waitForEvent ? true : false); } @@ -249,7 +249,7 @@ int GHOST_ProcessEvents(GHOST_SystemHandle systemhandle, int waitForEvent) void GHOST_DispatchEvents(GHOST_SystemHandle systemhandle) { GHOST_ISystem *system = (GHOST_ISystem *) systemhandle; - + system->dispatchEvents(); } @@ -257,7 +257,7 @@ void GHOST_DispatchEvents(GHOST_SystemHandle systemhandle) GHOST_TSuccess GHOST_AddEventConsumer(GHOST_SystemHandle systemhandle, GHOST_EventConsumerHandle consumerhandle) { GHOST_ISystem *system = (GHOST_ISystem *) systemhandle; - + return system->addEventConsumer((GHOST_CallbackEventConsumer *)consumerhandle); } @@ -353,7 +353,7 @@ GHOST_TSuccess GHOST_GetCursorPosition(GHOST_SystemHandle systemhandle, GHOST_TInt32 *y) { GHOST_ISystem *system = (GHOST_ISystem *) systemhandle; - + return system->getCursorPosition(*x, *y); } @@ -364,7 +364,7 @@ GHOST_TSuccess GHOST_SetCursorPosition(GHOST_SystemHandle systemhandle, GHOST_TInt32 y) { GHOST_ISystem *system = (GHOST_ISystem *) systemhandle; - + return system->setCursorPosition(x, y); } @@ -398,7 +398,7 @@ GHOST_TSuccess GHOST_GetModifierKeyState(GHOST_SystemHandle systemhandle, GHOST_ISystem *system = (GHOST_ISystem *) systemhandle; GHOST_TSuccess result; bool isdown = false; - + result = system->getModifierKeyState(mask, isdown); *isDown = (int) isdown; @@ -414,7 +414,7 @@ GHOST_TSuccess GHOST_GetButtonState(GHOST_SystemHandle systemhandle, GHOST_ISystem *system = (GHOST_ISystem *) systemhandle; GHOST_TSuccess result; bool isdown = false; - + result = system->getButtonState(mask, isdown); *isDown = (int) isdown; @@ -441,7 +441,7 @@ void GHOST_setAcceptDragOperation(GHOST_WindowHandle windowhandle, GHOST_TInt8 c GHOST_TEventType GHOST_GetEventType(GHOST_EventHandle eventhandle) { GHOST_IEvent *event = (GHOST_IEvent *) eventhandle; - + return event->getType(); } @@ -466,7 +466,7 @@ GHOST_WindowHandle GHOST_GetEventWindow(GHOST_EventHandle eventhandle) GHOST_TEventDataPtr GHOST_GetEventData(GHOST_EventHandle eventhandle) { GHOST_IEvent *event = (GHOST_IEvent *) eventhandle; - + return event->getData(); } @@ -475,7 +475,7 @@ GHOST_TEventDataPtr GHOST_GetEventData(GHOST_EventHandle eventhandle) GHOST_TimerProcPtr GHOST_GetTimerProc(GHOST_TimerTaskHandle timertaskhandle) { GHOST_ITimerTask *timertask = (GHOST_ITimerTask *) timertaskhandle; - + return timertask->getTimerProc(); } @@ -485,7 +485,7 @@ void GHOST_SetTimerProc(GHOST_TimerTaskHandle timertaskhandle, GHOST_TimerProcPtr timerproc) { GHOST_ITimerTask *timertask = (GHOST_ITimerTask *) timertaskhandle; - + timertask->setTimerProc(timerproc); } @@ -504,13 +504,13 @@ void GHOST_SetTimerTaskUserData(GHOST_TimerTaskHandle timertaskhandle, GHOST_TUserDataPtr userdata) { GHOST_ITimerTask *timertask = (GHOST_ITimerTask *) timertaskhandle; - + timertask->setUserData(userdata); } -int GHOST_GetValid(GHOST_WindowHandle windowhandle) +int GHOST_GetValid(GHOST_WindowHandle windowhandle) { GHOST_IWindow *window = (GHOST_IWindow *) windowhandle; @@ -542,7 +542,7 @@ void GHOST_SetTitle(GHOST_WindowHandle windowhandle, const char *title) { GHOST_IWindow *window = (GHOST_IWindow *) windowhandle; - + window->setTitle(title); } @@ -567,7 +567,7 @@ char *GHOST_GetTitle(GHOST_WindowHandle windowhandle) -GHOST_RectangleHandle GHOST_GetWindowBounds(GHOST_WindowHandle windowhandle) +GHOST_RectangleHandle GHOST_GetWindowBounds(GHOST_WindowHandle windowhandle) { GHOST_IWindow *window = (GHOST_IWindow *) windowhandle; GHOST_Rect *rectangle = NULL; @@ -580,7 +580,7 @@ GHOST_RectangleHandle GHOST_GetWindowBounds(GHOST_WindowHandle windowhandle) -GHOST_RectangleHandle GHOST_GetClientBounds(GHOST_WindowHandle windowhandle) +GHOST_RectangleHandle GHOST_GetClientBounds(GHOST_WindowHandle windowhandle) { GHOST_IWindow *window = (GHOST_IWindow *) windowhandle; GHOST_Rect *rectangle = NULL; @@ -678,16 +678,16 @@ GHOST_TSuccess GHOST_SetWindowState(GHOST_WindowHandle windowhandle, GHOST_TSuccess GHOST_SetWindowModifiedState(GHOST_WindowHandle windowhandle, GHOST_TUns8 isUnsavedChanges) { GHOST_IWindow *window = (GHOST_IWindow *) windowhandle; - + return window->setModifiedState(isUnsavedChanges); -} +} GHOST_TSuccess GHOST_SetWindowOrder(GHOST_WindowHandle windowhandle, GHOST_TWindowOrder order) { GHOST_IWindow *window = (GHOST_IWindow *) windowhandle; - + return window->setOrder(order); } @@ -725,7 +725,7 @@ GHOST_TUns16 GHOST_GetNumOfAASamples(GHOST_WindowHandle windowhandle) GHOST_TSuccess GHOST_ActivateWindowDrawingContext(GHOST_WindowHandle windowhandle) { GHOST_IWindow *window = (GHOST_IWindow *) windowhandle; - + return window->activateDrawingContext(); } diff --git a/intern/ghost/intern/GHOST_ContextWGL.h b/intern/ghost/intern/GHOST_ContextWGL.h index 6f575db73c6..be9575844c9 100644 --- a/intern/ghost/intern/GHOST_ContextWGL.h +++ b/intern/ghost/intern/GHOST_ContextWGL.h @@ -158,7 +158,7 @@ private: const int m_contextResetNotificationStrategy; HGLRC m_hGLRC; - + #ifndef NDEBUG const char *m_dummyVendor; const char *m_dummyRenderer; diff --git a/intern/ghost/intern/GHOST_Debug.h b/intern/ghost/intern/GHOST_Debug.h index db49627b378..658c9bf5d2c 100644 --- a/intern/ghost/intern/GHOST_Debug.h +++ b/intern/ghost/intern/GHOST_Debug.h @@ -40,9 +40,9 @@ # endif // DEBUG #endif // _MSC_VER -#ifdef WITH_GHOST_DEBUG +#ifdef WITH_GHOST_DEBUG # define GHOST_DEBUG // spit ghost events to stdout -#endif // WITH_GHOST_DEBUG +#endif // WITH_GHOST_DEBUG #ifdef GHOST_DEBUG # include <iostream> diff --git a/intern/ghost/intern/GHOST_DisplayManager.cpp b/intern/ghost/intern/GHOST_DisplayManager.cpp index 9f0b32148f6..2f8240e826b 100644 --- a/intern/ghost/intern/GHOST_DisplayManager.cpp +++ b/intern/ghost/intern/GHOST_DisplayManager.cpp @@ -179,9 +179,9 @@ GHOST_DisplayManager::findMatch( best = score; } } - + match = m_settings[display][found]; - + GHOST_PRINT("GHOST_DisplayManager::findMatch(): settings of match:\n"); GHOST_PRINT(" setting.xPixels=" << match.xPixels << "\n"); GHOST_PRINT(" setting.yPixels=" << match.yPixels << "\n"); diff --git a/intern/ghost/intern/GHOST_DisplayManager.h b/intern/ghost/intern/GHOST_DisplayManager.h index afdb11543e9..02a742a54db 100644 --- a/intern/ghost/intern/GHOST_DisplayManager.h +++ b/intern/ghost/intern/GHOST_DisplayManager.h @@ -50,7 +50,7 @@ public: * Constructor. */ GHOST_DisplayManager(void); - + /** * Destructor. */ @@ -79,7 +79,7 @@ public: GHOST_TInt32& numSettings) const; /** - * Returns the current setting for this display device. + * Returns the current setting for this display device. * \param display The index of the display to query with 0 <= display < getNumDisplays(). * \param index The setting index to be returned. * \param setting The setting of the display device with this index. @@ -90,7 +90,7 @@ public: GHOST_DisplaySetting& setting) const; /** - * Returns the current setting for this display device. + * Returns the current setting for this display device. * \param display The index of the display to query with 0 <= display < getNumDisplays(). * \param setting The current setting of the display device with this index. * \return Indication of success. @@ -128,7 +128,7 @@ protected: * \return Indication of success. */ GHOST_TSuccess initializeSettings(void); - + /** Tells whether the list of display modes has been stored already. */ bool m_settingsInitialized; /** The list with display settings for the main display. */ diff --git a/intern/ghost/intern/GHOST_DisplayManagerCocoa.h b/intern/ghost/intern/GHOST_DisplayManagerCocoa.h index f580820d8f6..3ce0b4e2239 100644 --- a/intern/ghost/intern/GHOST_DisplayManagerCocoa.h +++ b/intern/ghost/intern/GHOST_DisplayManagerCocoa.h @@ -69,7 +69,7 @@ public: GHOST_TSuccess getNumDisplaySettings(GHOST_TUns8 display, GHOST_TInt32& numSettings) const; /** - * Returns the current setting for this display device. + * Returns the current setting for this display device. * \param display The index of the display to query with 0 <= display < getNumDisplays(). * \param index The setting index to be returned. * \param setting The setting of the display device with this index. @@ -78,7 +78,7 @@ public: GHOST_TSuccess getDisplaySetting(GHOST_TUns8 display, GHOST_TInt32 index, GHOST_DisplaySetting& setting) const; /** - * Returns the current setting for this display device. + * Returns the current setting for this display device. * \param display The index of the display to query with 0 <= display < getNumDisplays(). * \param setting The current setting of the display device with this index. * \return Indication of success. @@ -86,14 +86,14 @@ public: GHOST_TSuccess getCurrentDisplaySetting(GHOST_TUns8 display, GHOST_DisplaySetting& setting) const; /** - * Changes the current setting for this display device. + * Changes the current setting for this display device. * \param display The index of the display to query with 0 <= display < getNumDisplays(). * \param setting The current setting of the display device with this index. * \return Indication of success. */ GHOST_TSuccess setCurrentDisplaySetting(GHOST_TUns8 display, const GHOST_DisplaySetting& setting); -protected: +protected: //Do not cache values as OS X supports screen hot plug /** Cached number of displays. */ //CGDisplayCount m_numDisplays; diff --git a/intern/ghost/intern/GHOST_DisplayManagerWin32.cpp b/intern/ghost/intern/GHOST_DisplayManagerWin32.cpp index 7b9a897fe57..f5f6de330a9 100644 --- a/intern/ghost/intern/GHOST_DisplayManagerWin32.cpp +++ b/intern/ghost/intern/GHOST_DisplayManagerWin32.cpp @@ -62,11 +62,11 @@ static BOOL get_dd(DWORD d, DISPLAY_DEVICE *dd) } /* - * When you call EnumDisplaySettings with iModeNum set to zero, the operating system - * initializes and caches information about the display device. When you call - * EnumDisplaySettings with iModeNum set to a non-zero value, the function returns + * When you call EnumDisplaySettings with iModeNum set to zero, the operating system + * initializes and caches information about the display device. When you call + * EnumDisplaySettings with iModeNum set to a non-zero value, the function returns * the information that was cached the last time the function was called with iModeNum - * set to zero. + * set to zero. */ GHOST_TSuccess GHOST_DisplayManagerWin32::getNumDisplaySettings(GHOST_TUns8 display, GHOST_TInt32& numSettings) const { @@ -98,9 +98,9 @@ GHOST_TSuccess GHOST_DisplayManagerWin32::getDisplaySetting(GHOST_TUns8 display, setting.bpp = dm.dmBitsPerPel; /* When you call the EnumDisplaySettings function, the dmDisplayFrequency member * may return with the value 0 or 1. These values represent the display hardware's - * default refresh rate. This default rate is typically set by switches on a display - * card or computer motherboard, or by a configuration program that does not use - * Win32 display functions such as ChangeDisplaySettings. + * default refresh rate. This default rate is typically set by switches on a display + * card or computer motherboard, or by a configuration program that does not use + * Win32 display functions such as ChangeDisplaySettings. */ /* First, we tried to explicitly set the frequency to 60 if EnumDisplaySettings * returned 0 or 1 but this doesn't work since later on an exact match will diff --git a/intern/ghost/intern/GHOST_DisplayManagerWin32.h b/intern/ghost/intern/GHOST_DisplayManagerWin32.h index ff8849f03c9..f0d6d62083c 100644 --- a/intern/ghost/intern/GHOST_DisplayManagerWin32.h +++ b/intern/ghost/intern/GHOST_DisplayManagerWin32.h @@ -69,7 +69,7 @@ public: GHOST_TSuccess getNumDisplaySettings(GHOST_TUns8 display, GHOST_TInt32& numSettings) const; /** - * Returns the current setting for this display device. + * Returns the current setting for this display device. * \param display The index of the display to query with 0 <= display < getNumDisplays(). * \param index The setting index to be returned. * \param setting The setting of the display device with this index. @@ -78,7 +78,7 @@ public: GHOST_TSuccess getDisplaySetting(GHOST_TUns8 display, GHOST_TInt32 index, GHOST_DisplaySetting& setting) const; /** - * Returns the current setting for this display device. + * Returns the current setting for this display device. * \param display The index of the display to query with 0 <= display < getNumDisplays(). * \param setting The current setting of the display device with this index. * \return Indication of success. @@ -86,7 +86,7 @@ public: GHOST_TSuccess getCurrentDisplaySetting(GHOST_TUns8 display, GHOST_DisplaySetting& setting) const; /** - * Changes the current setting for this display device. + * Changes the current setting for this display device. * \param display The index of the display to query with 0 <= display < getNumDisplays(). * \param setting The current setting of the display device with this index. * \return Indication of success. diff --git a/intern/ghost/intern/GHOST_DisplayManagerX11.cpp b/intern/ghost/intern/GHOST_DisplayManagerX11.cpp index b3e6f2e53fa..8a629b2bf18 100644 --- a/intern/ghost/intern/GHOST_DisplayManagerX11.cpp +++ b/intern/ghost/intern/GHOST_DisplayManagerX11.cpp @@ -158,7 +158,7 @@ getDisplaySetting( return GHOST_kSuccess; } - + GHOST_TSuccess GHOST_DisplayManagerX11:: getCurrentDisplaySetting( diff --git a/intern/ghost/intern/GHOST_DisplayManagerX11.h b/intern/ghost/intern/GHOST_DisplayManagerX11.h index b54c53c67bd..857a8a5fce8 100644 --- a/intern/ghost/intern/GHOST_DisplayManagerX11.h +++ b/intern/ghost/intern/GHOST_DisplayManagerX11.h @@ -76,7 +76,7 @@ public: ) const; /** - * Returns the current setting for this display device. + * Returns the current setting for this display device. * \param display The index of the display to query with 0 <= display < getNumDisplays(). * \param index The setting index to be returned. * \param setting The setting of the display device with this index. @@ -90,7 +90,7 @@ public: ) const; /** - * Returns the current setting for this display device. + * Returns the current setting for this display device. * \param display The index of the display to query with 0 <= display < getNumDisplays(). * \param setting The current setting of the display device with this index. * \return Indication of success. @@ -102,7 +102,7 @@ public: ) const; /** - * Changes the current setting for this display device. + * Changes the current setting for this display device. * \param display The index of the display to query with 0 <= display < getNumDisplays(). * \param setting The current setting of the display device with this index. * \return Indication of success. @@ -119,5 +119,5 @@ private: }; -#endif // +#endif // diff --git a/intern/ghost/intern/GHOST_DropTargetWin32.cpp b/intern/ghost/intern/GHOST_DropTargetWin32.cpp index cbf37bf1b16..79d7a2d48b4 100644 --- a/intern/ghost/intern/GHOST_DropTargetWin32.cpp +++ b/intern/ghost/intern/GHOST_DropTargetWin32.cpp @@ -29,7 +29,7 @@ * \ingroup GHOST */ - + #include "GHOST_Debug.h" #include "GHOST_DropTargetWin32.h" #include <shellapi.h> @@ -59,7 +59,7 @@ GHOST_DropTargetWin32::~GHOST_DropTargetWin32() } -/* +/* * IUnknown::QueryInterface */ HRESULT __stdcall GHOST_DropTargetWin32::QueryInterface(REFIID riid, void **ppvObj) @@ -81,8 +81,8 @@ HRESULT __stdcall GHOST_DropTargetWin32::QueryInterface(REFIID riid, void **ppvO } -/* - * IUnknown::AddRef +/* + * IUnknown::AddRef */ ULONG __stdcall GHOST_DropTargetWin32::AddRef(void) @@ -90,13 +90,13 @@ ULONG __stdcall GHOST_DropTargetWin32::AddRef(void) return ::InterlockedIncrement(&m_cRef); } -/* +/* * IUnknown::Release */ ULONG __stdcall GHOST_DropTargetWin32::Release(void) { ULONG refs = ::InterlockedDecrement(&m_cRef); - + if (refs == 0) { delete this; return 0; @@ -106,7 +106,7 @@ ULONG __stdcall GHOST_DropTargetWin32::Release(void) } } -/* +/* * Implementation of IDropTarget::DragEnter */ HRESULT __stdcall GHOST_DropTargetWin32::DragEnter(IDataObject *pDataObject, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect) @@ -114,13 +114,13 @@ HRESULT __stdcall GHOST_DropTargetWin32::DragEnter(IDataObject *pDataObject, DWO // we accept all drop by default m_window->setAcceptDragOperation(true); *pdwEffect = DROPEFFECT_NONE; - + m_draggedObjectType = getGhostType(pDataObject); m_system->pushDragDropEvent(GHOST_kEventDraggingEntered, m_draggedObjectType, m_window, pt.x, pt.y, NULL); return S_OK; } -/* +/* * Implementation of IDropTarget::DragOver */ HRESULT __stdcall GHOST_DropTargetWin32::DragOver(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect) @@ -136,7 +136,7 @@ HRESULT __stdcall GHOST_DropTargetWin32::DragOver(DWORD grfKeyState, POINTL pt, return S_OK; } -/* +/* * Implementation of IDropTarget::DragLeave */ HRESULT __stdcall GHOST_DropTargetWin32::DragLeave(void) @@ -147,7 +147,7 @@ HRESULT __stdcall GHOST_DropTargetWin32::DragLeave(void) } /* Implementation of IDropTarget::Drop - * This function will not be called if pdwEffect is set to DROPEFFECT_NONE in + * This function will not be called if pdwEffect is set to DROPEFFECT_NONE in * the implementation of IDropTarget::DragOver */ HRESULT __stdcall GHOST_DropTargetWin32::Drop(IDataObject *pDataObject, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect) @@ -162,15 +162,15 @@ HRESULT __stdcall GHOST_DropTargetWin32::Drop(IDataObject *pDataObject, DWORD gr } if (data) m_system->pushDragDropEvent(GHOST_kEventDraggingDropDone, m_draggedObjectType, m_window, pt.x, pt.y, data); - + m_draggedObjectType = GHOST_kDragnDropTypeUnknown; return S_OK; } -/* +/* * Helpers */ - + DWORD GHOST_DropTargetWin32::allowedDropEffect(DWORD dwAllowed) { DWORD dwEffect = DROPEFFECT_NONE; @@ -264,7 +264,7 @@ void *GHOST_DropTargetWin32::getDropDataAsFilenames(IDataObject *pDataObject) // Free up memory. ::GlobalUnlock(stgmed.hGlobal); ::ReleaseStgMedium(&stgmed); - + return strArray; } } @@ -301,7 +301,7 @@ void *GHOST_DropTargetWin32::getDropDataAsString(IDataObject *pDataObject) if (pDataObject->QueryGetData(&fmtetc) == S_OK) { if (pDataObject->GetData(&fmtetc, &stgmed) == S_OK) { char *str = (char *)::GlobalLock(stgmed.hGlobal); - + tmp_string = (char *)::malloc(::strlen(str) + 1); if (!tmp_string) { ::GlobalUnlock(stgmed.hGlobal); @@ -320,7 +320,7 @@ void *GHOST_DropTargetWin32::getDropDataAsString(IDataObject *pDataObject) return tmp_string; } } - + return NULL; } @@ -338,7 +338,7 @@ int GHOST_DropTargetWin32::WideCharToANSI(LPCWSTR in, char * &out) 0, NULL, NULL ); - + if (!size) { #ifdef GHOST_DEBUG ::printLastError(); diff --git a/intern/ghost/intern/GHOST_DropTargetWin32.h b/intern/ghost/intern/GHOST_DropTargetWin32.h index 56bae1fd1b2..3d7be45799f 100644 --- a/intern/ghost/intern/GHOST_DropTargetWin32.h +++ b/intern/ghost/intern/GHOST_DropTargetWin32.h @@ -41,11 +41,11 @@ class GHOST_DropTargetWin32 : public IDropTarget { public: /* IUnknownd implementation. - * Enables clients to get pointers to other interfaces on a given object + * Enables clients to get pointers to other interfaces on a given object * through the QueryInterface method, and manage the existence of the object - * through the AddRef and Release methods. All other COM interfaces are - * inherited, directly or indirectly, from IUnknown. Therefore, the three - * methods in IUnknown are the first entries in the VTable for every interface. + * through the AddRef and Release methods. All other COM interfaces are + * inherited, directly or indirectly, from IUnknown. Therefore, the three + * methods in IUnknown are the first entries in the VTable for every interface. */ HRESULT __stdcall QueryInterface(REFIID riid, void **ppvObj); ULONG __stdcall AddRef(void); @@ -56,20 +56,20 @@ public: * provide drag-and-drop operations in your application. It contains methods * used in any application that can be a target for data during a * drag-and-drop operation. A drop-target application is responsible for: - * + * * - Determining the effect of the drop on the target application. * - Incorporating any valid dropped data when the drop occurs. * - Communicating target feedback to the source so the source application * can provide appropriate visual feedback such as setting the cursor. * - Implementing drag scrolling. * - Registering and revoking its application windows as drop targets. - * - * The IDropTarget interface contains methods that handle all these - * responsibilities except registering and revoking the application window - * as a drop target, for which you must call the RegisterDragDrop and the + * + * The IDropTarget interface contains methods that handle all these + * responsibilities except registering and revoking the application window + * as a drop target, for which you must call the RegisterDragDrop and the * RevokeDragDrop functions. */ - + HRESULT __stdcall DragEnter(IDataObject *pDataObject, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect); HRESULT __stdcall DragOver(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect); HRESULT __stdcall DragLeave(void); @@ -133,7 +133,7 @@ private: /** * Convert Unicode to ANSI, replacing unconvertable chars with '?'. - * The ANSI codepage is the system default codepage, + * The ANSI codepage is the system default codepage, * and can change from system to system. * \param in LPCWSTR. * \param out char *. Is set to NULL on failure. diff --git a/intern/ghost/intern/GHOST_Event.h b/intern/ghost/intern/GHOST_Event.h index 6a715498b87..278870738c2 100644 --- a/intern/ghost/intern/GHOST_Event.h +++ b/intern/ghost/intern/GHOST_Event.h @@ -60,7 +60,7 @@ public: * \return The event type. */ GHOST_TEventType getType() - { + { return m_type; } @@ -74,7 +74,7 @@ public: } /** - * Returns the window this event was generated on, + * Returns the window this event was generated on, * or NULL if it is a 'system' event. * \return The generating window. */ diff --git a/intern/ghost/intern/GHOST_EventDragnDrop.h b/intern/ghost/intern/GHOST_EventDragnDrop.h index b7bf37c99d8..c9f4f08b53c 100644 --- a/intern/ghost/intern/GHOST_EventDragnDrop.h +++ b/intern/ghost/intern/GHOST_EventDragnDrop.h @@ -41,9 +41,9 @@ extern "C" { /** * Drag & drop event - * + * * The dragging sequence is performed in four phases: - * + * * <li> Start sequence (GHOST_kEventDraggingEntered) that tells a drag'n'drop operation has started. * Already gives the object data type, and the entering mouse location * @@ -93,13 +93,13 @@ public: m_dragnDropEventData.data = data; m_data = &m_dragnDropEventData; } - + ~GHOST_EventDragnDrop() { //Free the dropped object data if (m_dragnDropEventData.data == NULL) return; - + switch (m_dragnDropEventData.dataType) { case GHOST_kDragnDropTypeBitmap: IMB_freeImBuf((ImBuf *)m_dragnDropEventData.data); @@ -108,10 +108,10 @@ public: { GHOST_TStringArray *strArray = (GHOST_TStringArray *)m_dragnDropEventData.data; int i; - + for (i = 0; i < strArray->count; i++) free(strArray->strings[i]); - + free(strArray->strings); free(strArray); } @@ -124,8 +124,8 @@ public: break; } } - - + + protected: /** The x,y-coordinates of the cursor position. */ diff --git a/intern/ghost/intern/GHOST_EventKey.h b/intern/ghost/intern/GHOST_EventKey.h index 54e38c00d05..7e867596503 100644 --- a/intern/ghost/intern/GHOST_EventKey.h +++ b/intern/ghost/intern/GHOST_EventKey.h @@ -60,7 +60,7 @@ public: m_keyEventData.utf8_buf[0] = '\0'; m_data = &m_keyEventData; } - + /** * Constructor. * \param msec The time this event was generated. @@ -82,7 +82,7 @@ public: else m_keyEventData.utf8_buf[0] = '\0'; m_data = &m_keyEventData; } - + protected: /** The key event data. */ GHOST_TEventKeyData m_keyEventData; diff --git a/intern/ghost/intern/GHOST_EventManager.cpp b/intern/ghost/intern/GHOST_EventManager.cpp index 0675ac734ed..bf92fa4517b 100644 --- a/intern/ghost/intern/GHOST_EventManager.cpp +++ b/intern/ghost/intern/GHOST_EventManager.cpp @@ -127,7 +127,7 @@ GHOST_TSuccess GHOST_EventManager::addConsumer(GHOST_IEventConsumer *consumer) { GHOST_TSuccess success; GHOST_ASSERT(consumer, "invalid consumer"); - + // Check to see whether the consumer is already in our list TConsumerVector::const_iterator iter = std::find(m_consumers.begin(), m_consumers.end(), consumer); diff --git a/intern/ghost/intern/GHOST_EventManager.h b/intern/ghost/intern/GHOST_EventManager.h index ae2971ea1a8..efad19616ad 100644 --- a/intern/ghost/intern/GHOST_EventManager.h +++ b/intern/ghost/intern/GHOST_EventManager.h @@ -143,7 +143,7 @@ protected: /** A stack with events. */ typedef std::deque<GHOST_IEvent *> TEventStack; - + /** The event stack. */ std::deque<GHOST_IEvent *> m_events; std::deque<GHOST_IEvent *> m_handled_events; diff --git a/intern/ghost/intern/GHOST_EventNDOF.h b/intern/ghost/intern/GHOST_EventNDOF.h index 754e1091860..b81f74becee 100644 --- a/intern/ghost/intern/GHOST_EventNDOF.h +++ b/intern/ghost/intern/GHOST_EventNDOF.h @@ -4,7 +4,7 @@ * 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. + * 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 diff --git a/intern/ghost/intern/GHOST_EventPrinter.cpp b/intern/ghost/intern/GHOST_EventPrinter.cpp index a6adba12152..221b85b80ba 100644 --- a/intern/ghost/intern/GHOST_EventPrinter.cpp +++ b/intern/ghost/intern/GHOST_EventPrinter.cpp @@ -41,7 +41,7 @@ bool GHOST_EventPrinter::processEvent(GHOST_IEvent *event) { bool handled = true; - + GHOST_ASSERT(event, "event==0"); if (event->getType() == GHOST_kEventWindowUpdate) return false; @@ -95,7 +95,7 @@ bool GHOST_EventPrinter::processEvent(GHOST_IEvent *event) std::cout << "GHOST_kEventKeyDown, key: " << str; } break; - + case GHOST_kEventDraggingEntered: { GHOST_TEventDragnDropData *dragnDropData = (GHOST_TEventDragnDropData *)((GHOST_IEvent *)event)->getData(); @@ -103,7 +103,7 @@ bool GHOST_EventPrinter::processEvent(GHOST_IEvent *event) std::cout << " mouse at x=" << dragnDropData->x << " y=" << dragnDropData->y; } break; - + case GHOST_kEventDraggingUpdated: { GHOST_TEventDragnDropData *dragnDropData = (GHOST_TEventDragnDropData *)((GHOST_IEvent *)event)->getData(); @@ -118,7 +118,7 @@ bool GHOST_EventPrinter::processEvent(GHOST_IEvent *event) std::cout << "GHOST_kEventDraggingExited, dragged object type : " << dragnDropData->dataType; } break; - + case GHOST_kEventDraggingDropDone: { GHOST_TEventDragnDropData *dragnDropData = (GHOST_TEventDragnDropData *)((GHOST_IEvent *)event)->getData(); @@ -148,14 +148,14 @@ bool GHOST_EventPrinter::processEvent(GHOST_IEvent *event) case GHOST_kEventOpenMainFile: { GHOST_TEventDataPtr eventData = ((GHOST_IEvent *)event)->getData(); - + if (eventData) std::cout << "GHOST_kEventOpenMainFile for path : " << (char *)eventData; else std::cout << "GHOST_kEventOpenMainFile with no path specified!!"; } break; - + case GHOST_kEventQuit: std::cout << "GHOST_kEventQuit"; break; diff --git a/intern/ghost/intern/GHOST_ISystemPaths.cpp b/intern/ghost/intern/GHOST_ISystemPaths.cpp index 93ca0bc3880..8bd7fbe4f9b 100644 --- a/intern/ghost/intern/GHOST_ISystemPaths.cpp +++ b/intern/ghost/intern/GHOST_ISystemPaths.cpp @@ -67,7 +67,7 @@ GHOST_TSuccess GHOST_ISystemPaths::create() # else m_systemPaths = new GHOST_SystemPathsUnix(); # endif -#endif +#endif success = m_systemPaths != NULL ? GHOST_kSuccess : GHOST_kFailure; } else { diff --git a/intern/ghost/intern/GHOST_NDOFManager.cpp b/intern/ghost/intern/GHOST_NDOFManager.cpp index cab9bf45b80..1f2af73b743 100644 --- a/intern/ghost/intern/GHOST_NDOFManager.cpp +++ b/intern/ghost/intern/GHOST_NDOFManager.cpp @@ -4,7 +4,7 @@ * 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. + * 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 diff --git a/intern/ghost/intern/GHOST_NDOFManager.h b/intern/ghost/intern/GHOST_NDOFManager.h index 0c0b945d548..78f24e07a6e 100644 --- a/intern/ghost/intern/GHOST_NDOFManager.h +++ b/intern/ghost/intern/GHOST_NDOFManager.h @@ -4,7 +4,7 @@ * 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. + * 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 diff --git a/intern/ghost/intern/GHOST_NDOFManagerCocoa.h b/intern/ghost/intern/GHOST_NDOFManagerCocoa.h index 3f1bfcf57fc..6e676faba1e 100644 --- a/intern/ghost/intern/GHOST_NDOFManagerCocoa.h +++ b/intern/ghost/intern/GHOST_NDOFManagerCocoa.h @@ -4,7 +4,7 @@ * 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. + * 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 diff --git a/intern/ghost/intern/GHOST_NDOFManagerUnix.cpp b/intern/ghost/intern/GHOST_NDOFManagerUnix.cpp index fff5aba6f9e..624d39b6347 100644 --- a/intern/ghost/intern/GHOST_NDOFManagerUnix.cpp +++ b/intern/ghost/intern/GHOST_NDOFManagerUnix.cpp @@ -4,7 +4,7 @@ * 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. + * 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 diff --git a/intern/ghost/intern/GHOST_NDOFManagerUnix.h b/intern/ghost/intern/GHOST_NDOFManagerUnix.h index 3fd171d9e76..8d83ac7b670 100644 --- a/intern/ghost/intern/GHOST_NDOFManagerUnix.h +++ b/intern/ghost/intern/GHOST_NDOFManagerUnix.h @@ -4,7 +4,7 @@ * 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. + * 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 @@ -20,7 +20,7 @@ * * ***** END GPL LICENSE BLOCK ***** */ - + #ifndef __GHOST_NDOFMANAGERUNIX_H__ #define __GHOST_NDOFMANAGERUNIX_H__ diff --git a/intern/ghost/intern/GHOST_NDOFManagerWin32.cpp b/intern/ghost/intern/GHOST_NDOFManagerWin32.cpp index 0023ee7e1d0..fbdac249eb0 100644 --- a/intern/ghost/intern/GHOST_NDOFManagerWin32.cpp +++ b/intern/ghost/intern/GHOST_NDOFManagerWin32.cpp @@ -1,11 +1,11 @@ /* - * + * * ***** 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. + * 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 diff --git a/intern/ghost/intern/GHOST_NDOFManagerWin32.h b/intern/ghost/intern/GHOST_NDOFManagerWin32.h index 2f7bc9ee732..522a79ffc0c 100644 --- a/intern/ghost/intern/GHOST_NDOFManagerWin32.h +++ b/intern/ghost/intern/GHOST_NDOFManagerWin32.h @@ -4,7 +4,7 @@ * 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. + * 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 diff --git a/intern/ghost/intern/GHOST_Rect.cpp b/intern/ghost/intern/GHOST_Rect.cpp index 9af4f30ebc1..646dae9f242 100644 --- a/intern/ghost/intern/GHOST_Rect.cpp +++ b/intern/ghost/intern/GHOST_Rect.cpp @@ -108,7 +108,7 @@ void GHOST_Rect::setCenter(GHOST_TInt32 cx, GHOST_TInt32 cy) void GHOST_Rect::setCenter(GHOST_TInt32 cx, GHOST_TInt32 cy, GHOST_TInt32 w, GHOST_TInt32 h) { long w_2, h_2; - + w_2 = w >> 1; h_2 = h >> 1; m_l = cx - w_2; diff --git a/intern/ghost/intern/GHOST_System.cpp b/intern/ghost/intern/GHOST_System.cpp index 4db2f0616d7..f849993ae6d 100644 --- a/intern/ghost/intern/GHOST_System.cpp +++ b/intern/ghost/intern/GHOST_System.cpp @@ -113,7 +113,7 @@ GHOST_TSuccess GHOST_System::disposeWindow(GHOST_IWindow *window) /* * Remove all pending events for the window. - */ + */ if (m_windowManager->getWindowFound(window)) { m_eventManager->removeWindowEvents(window); } @@ -272,7 +272,7 @@ GHOST_TSuccess GHOST_System::pushEvent(GHOST_IEvent *event) GHOST_TSuccess GHOST_System::getModifierKeyState(GHOST_TModifierKeyMask mask, bool& isDown) const { GHOST_ModifierKeys keys; - // Get the state of all modifier keys + // Get the state of all modifier keys GHOST_TSuccess success = getModifierKeys(keys); if (success) { // Isolate the state of the key requested @@ -306,7 +306,7 @@ GHOST_TSuccess GHOST_System::init() m_timerManager = new GHOST_TimerManager(); m_windowManager = new GHOST_WindowManager(); m_eventManager = new GHOST_EventManager(); - + #ifdef GHOST_DEBUG if (m_eventManager) { m_eventPrinter = new GHOST_EventPrinter(); diff --git a/intern/ghost/intern/GHOST_System.h b/intern/ghost/intern/GHOST_System.h index 50c893b1113..6831b3d07d9 100644 --- a/intern/ghost/intern/GHOST_System.h +++ b/intern/ghost/intern/GHOST_System.h @@ -91,7 +91,7 @@ public: /** * Installs a timer. - * Note that, on most operating systems, messages need to be processed in order + * Note that, on most operating systems, messages need to be processed in order * for the timer callbacks to be invoked. * \param delay The time to wait for the first call to the timerProc (in milliseconds) * \param interval The interval between calls to the timerProc @@ -114,7 +114,7 @@ public: /*************************************************************************************** * Display/window management functionality ***************************************************************************************/ - + /** * Inherited from GHOST_ISystem but left pure virtual * @@ -169,7 +169,7 @@ public: */ bool getFullScreen(void); - + /** * Native pixel size support (MacBook 'retina'). * \return The pixel size in float. @@ -237,7 +237,7 @@ public: * \return Indication of success. */ GHOST_TSuccess getButtonState(GHOST_TButtonMask mask, bool& isDown) const; - + #ifdef WITH_INPUT_NDOF /*************************************************************************************** * Access to 3D mouse. @@ -305,7 +305,7 @@ public: * */ virtual GHOST_TUns8 *getClipboard(bool selection) const = 0; - + /** * Put data to the Clipboard * \param buffer The buffer to copy to the clipboard @@ -324,7 +324,7 @@ public: */ virtual bool supportsNativeDialogs(void); - + protected: /** * Initialize the system. @@ -362,7 +362,7 @@ protected: /** The N-degree of freedom device manager */ GHOST_NDOFManager *m_ndofManager; #endif - + /** Prints all the events. */ #ifdef GHOST_DEBUG GHOST_EventPrinter *m_eventPrinter; @@ -370,7 +370,7 @@ protected: /** Settings of the display before the display went fullscreen. */ GHOST_DisplaySetting m_preFullScreenSetting; - + }; inline GHOST_TimerManager *GHOST_System::getTimerManager() const diff --git a/intern/ghost/intern/GHOST_SystemCocoa.h b/intern/ghost/intern/GHOST_SystemCocoa.h index 8586c91b615..f0702737b46 100644 --- a/intern/ghost/intern/GHOST_SystemCocoa.h +++ b/intern/ghost/intern/GHOST_SystemCocoa.h @@ -88,7 +88,7 @@ public: * \return The dimension of the main display. */ void getMainDisplayDimensions(GHOST_TUns32& width, GHOST_TUns32& height) const; - + /** Returns the combine dimensions of all monitors. * \return The dimension of the workspace. */ @@ -122,7 +122,7 @@ public: const bool exclusive = false, const GHOST_TEmbedderWindowID parentWindow = 0 ); - + /** * Create a new offscreen context. * Never explicitly delete the context, use disposeContext() instead. @@ -152,19 +152,19 @@ public: * \return Indication of the presence of events. */ bool processEvents(bool waitForEvent); - + /** * Handle User request to quit, from Menu bar Quit, and Cmd+Q * Display alert panel if changes performed since last save */ GHOST_TUns8 handleQuitRequest(); - + /** * Handle Cocoa openFile event * Display confirmation request panel if changes performed since last save */ bool handleOpenDocumentRequest(void *filepathStr); - + /** * Handles a drag'n'drop destination event. Called by GHOST_WindowCocoa window subclass * \param eventType The type of drag'n'drop event @@ -176,7 +176,7 @@ public: */ GHOST_TSuccess handleDraggingEvent(GHOST_TEventType eventType, GHOST_TDragnDropTypes draggedObjectType, GHOST_WindowCocoa *window, int mouseX, int mouseY, void *data); - + /*************************************************************************************** * Cursor management functionality ***************************************************************************************/ @@ -196,7 +196,7 @@ public: * \return Indication of success. */ GHOST_TSuccess setCursorPosition(GHOST_TInt32 x, GHOST_TInt32 y); - + /*************************************************************************************** * Access to mouse button and keyboard states. ***************************************************************************************/ @@ -221,7 +221,7 @@ public: * \return Returns the selected buffer */ GHOST_TUns8 *getClipboard(bool selection) const; - + /** * Puts buffer to system clipboard * \param buffer The buffer to be copied @@ -236,7 +236,7 @@ public: * \return Indication whether the event was handled. */ GHOST_TSuccess handleWindowEvent(GHOST_TEventType eventType, GHOST_WindowCocoa *window); - + /** * Handles the Cocoa event telling the application has become active (again) * \return Indication whether the event was handled. @@ -254,7 +254,7 @@ public: int toggleConsole(int action) { return 0; } - + /** * Handles a tablet event. * \param eventPtr An NSEvent pointer (casted to void* to enable compilation in standard C++) @@ -279,7 +279,7 @@ public: * \return Indication whether the event was handled. */ GHOST_TSuccess handleKeyEvent(void *eventPtr); - + /** * Informs if the system provides native dialogs (eg. confirm quit) */ @@ -303,19 +303,19 @@ protected: /** Start time at initialization. */ GHOST_TUns64 m_start_time; - + /** Event has been processed directly by Cocoa (or NDOF manager) and has sent a ghost event to be dispatched */ bool m_outsideLoopEventProcessed; - + /** Raised window is not yet known by the window manager, so delay application become active event handling */ bool m_needDelayedApplicationBecomeActiveEventProcessing; - + /** State of the modifiers. */ GHOST_TUns32 m_modifierMask; /** Ignores window size messages (when window is dragged). */ bool m_ignoreWindowSizedMessages; - + /** Temporarily ignore momentum scroll events */ bool m_ignoreMomentumScroll; /** Is the scroll wheel event generated by a multitouch trackpad or mouse? */ diff --git a/intern/ghost/intern/GHOST_SystemPaths.h b/intern/ghost/intern/GHOST_SystemPaths.h index 22879c71e1e..fbaa8ad8ba5 100644 --- a/intern/ghost/intern/GHOST_SystemPaths.h +++ b/intern/ghost/intern/GHOST_SystemPaths.h @@ -4,7 +4,7 @@ * 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. + * 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 @@ -18,7 +18,7 @@ * The Original Code is Copyright (C) 2009 Blender Foundation. * All rights reserved. * - * + * * Contributor(s): Blender Foundation * * ***** END GPL LICENSE BLOCK ***** diff --git a/intern/ghost/intern/GHOST_SystemPathsCocoa.h b/intern/ghost/intern/GHOST_SystemPathsCocoa.h index 1c76284857c..3a1f3e1aacf 100644 --- a/intern/ghost/intern/GHOST_SystemPathsCocoa.h +++ b/intern/ghost/intern/GHOST_SystemPathsCocoa.h @@ -4,7 +4,7 @@ * 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. + * 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 @@ -18,7 +18,7 @@ * The Original Code is Copyright (C) 2010 Blender Foundation. * All rights reserved. * - * + * * Contributor(s): Damien Plisson 2010 * * ***** END GPL LICENSE BLOCK ***** diff --git a/intern/ghost/intern/GHOST_SystemPathsUnix.cpp b/intern/ghost/intern/GHOST_SystemPathsUnix.cpp index 8738b8dd0fe..b4e1259d824 100644 --- a/intern/ghost/intern/GHOST_SystemPathsUnix.cpp +++ b/intern/ghost/intern/GHOST_SystemPathsUnix.cpp @@ -4,7 +4,7 @@ * 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. + * 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 @@ -18,7 +18,7 @@ * The Original Code is Copyright (C) 2010 Blender Foundation. * All rights reserved. * - * + * * Contributor(s): Blender Foundation * * ***** END GPL LICENSE BLOCK ***** diff --git a/intern/ghost/intern/GHOST_SystemPathsUnix.h b/intern/ghost/intern/GHOST_SystemPathsUnix.h index 1502160c8d6..69c37c00ce0 100644 --- a/intern/ghost/intern/GHOST_SystemPathsUnix.h +++ b/intern/ghost/intern/GHOST_SystemPathsUnix.h @@ -4,7 +4,7 @@ * 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. + * 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 @@ -18,7 +18,7 @@ * The Original Code is Copyright (C) 2010 Blender Foundation. * All rights reserved. * - * + * * Contributor(s): Blender Foundation * * ***** END GPL LICENSE BLOCK ***** @@ -44,7 +44,7 @@ public: * this class should only be instanciated by GHOST_ISystem. */ GHOST_SystemPathsUnix(); - + /** * Destructor. */ diff --git a/intern/ghost/intern/GHOST_SystemPathsWin32.cpp b/intern/ghost/intern/GHOST_SystemPathsWin32.cpp index 8056bc76edb..d122d3dd51f 100644 --- a/intern/ghost/intern/GHOST_SystemPathsWin32.cpp +++ b/intern/ghost/intern/GHOST_SystemPathsWin32.cpp @@ -17,7 +17,7 @@ * * The Original Code is Copyright (C) 2011 Blender Foundation. * All rights reserved. - * + * * Contributor(s): Blender Foundation * Andrea Weikert * diff --git a/intern/ghost/intern/GHOST_SystemWin32.cpp b/intern/ghost/intern/GHOST_SystemWin32.cpp index ccc90e363b7..625a34aa142 100644 --- a/intern/ghost/intern/GHOST_SystemWin32.cpp +++ b/intern/ghost/intern/GHOST_SystemWin32.cpp @@ -240,7 +240,7 @@ GHOST_TUns64 GHOST_SystemWin32::getMilliSeconds() const __int64 delta = 1000 * (count - m_start); GHOST_TUns64 t = (GHOST_TUns64)(delta / m_freq); - return t; + return t; } @@ -407,7 +407,7 @@ bool GHOST_SystemWin32::processEvents(bool waitForEvent) #else GHOST_TUns64 next = timerMgr->nextFireTime(); GHOST_TInt64 maxSleep = next - getMilliSeconds(); - + if (next == GHOST_kFireTimeNever) { ::WaitMessage(); } @@ -469,17 +469,17 @@ GHOST_TSuccess GHOST_SystemWin32::getModifierKeys(GHOST_ModifierKeys &keys) cons keys.set(GHOST_kModifierKeyLeftShift, down); down = HIBYTE(::GetKeyState(VK_RSHIFT)) != 0; keys.set(GHOST_kModifierKeyRightShift, down); - + down = HIBYTE(::GetKeyState(VK_LMENU)) != 0; keys.set(GHOST_kModifierKeyLeftAlt, down); down = HIBYTE(::GetKeyState(VK_RMENU)) != 0; keys.set(GHOST_kModifierKeyRightAlt, down); - + down = HIBYTE(::GetKeyState(VK_LCONTROL)) != 0; keys.set(GHOST_kModifierKeyLeftControl, down); down = HIBYTE(::GetKeyState(VK_RCONTROL)) != 0; keys.set(GHOST_kModifierKeyRightControl, down); - + bool lwindown = HIBYTE(::GetKeyState(VK_LWIN)) != 0; bool rwindown = HIBYTE(::GetKeyState(VK_RWIN)) != 0; if (lwindown || rwindown) @@ -512,7 +512,7 @@ GHOST_TSuccess GHOST_SystemWin32::getButtons(GHOST_Buttons &buttons) const GHOST_TSuccess GHOST_SystemWin32::init() { GHOST_TSuccess success = GHOST_System::init(); - + /* Disable scaling on high DPI displays on Vista */ HMODULE user32 = ::LoadLibraryA("user32.dll"); @@ -542,12 +542,12 @@ GHOST_TSuccess GHOST_SystemWin32::init() wc.cbWndExtra = 0; wc.hInstance = ::GetModuleHandle(0); wc.hIcon = ::LoadIcon(wc.hInstance, "APPICON"); - + if (!wc.hIcon) { ::LoadIcon(NULL, IDI_APPLICATION); } wc.hCursor = ::LoadCursor(0, IDC_ARROW); - wc.hbrBackground = + wc.hbrBackground = #ifdef INW32_COMPISITING (HBRUSH)CreateSolidBrush #endif @@ -560,7 +560,7 @@ GHOST_TSuccess GHOST_SystemWin32::init() success = GHOST_kFailure; } } - + return success; } @@ -583,7 +583,7 @@ GHOST_TKey GHOST_SystemWin32::hardKey(RAWINPUT const &raw, int *keyDown, char *v *keyDown = !(raw.data.keyboard.Flags & RI_KEY_BREAK) && msg != WM_KEYUP && msg != WM_SYSKEYUP; key = this->convertKey(raw.data.keyboard.VKey, raw.data.keyboard.MakeCode, (raw.data.keyboard.Flags & (RI_KEY_E1 | RI_KEY_E0))); - + // extra handling of modifier keys: don't send repeats out from GHOST if (key >= GHOST_kKeyLeftShift && key <= GHOST_kKeyRightAlt) { bool changed = false; @@ -628,7 +628,7 @@ GHOST_TKey GHOST_SystemWin32::hardKey(RAWINPUT const &raw, int *keyDown, char *v default: break; } - + if (changed) { modifiers.set(modifier, (bool)*keyDown); system->storeModifierKeys(modifiers); @@ -637,7 +637,7 @@ GHOST_TKey GHOST_SystemWin32::hardKey(RAWINPUT const &raw, int *keyDown, char *v key = GHOST_kKeyUnknown; } } - + if (vk) *vk = raw.data.keyboard.VKey; @@ -682,7 +682,7 @@ GHOST_TKey GHOST_SystemWin32::convertKey(short vKey, short scanCode, short exten switch (vKey) { case VK_RETURN: key = (extend) ? GHOST_kKeyNumpadEnter : GHOST_kKeyEnter; break; - + case VK_BACK: key = GHOST_kKeyBackSpace; break; case VK_TAB: key = GHOST_kKeyTab; break; case VK_ESCAPE: key = GHOST_kKeyEsc; break; @@ -782,7 +782,7 @@ GHOST_TKey GHOST_SystemWin32::convertKey(short vKey, short scanCode, short exten break; } } - + return key; } @@ -799,7 +799,7 @@ GHOST_EventCursor *GHOST_SystemWin32::processCursorEvent(GHOST_TEventType type, { GHOST_TInt32 x_screen, y_screen; GHOST_SystemWin32 *system = (GHOST_SystemWin32 *) getSystem(); - + system->getCursorPosition(x_screen, y_screen); /* TODO: CHECK IF THIS IS A TABLET EVENT */ @@ -856,7 +856,7 @@ void GHOST_SystemWin32::processWheelEvent(GHOST_WindowWin32 *window, WPARAM wPar int acc = system->m_wheelDeltaAccum; int delta = GET_WHEEL_DELTA_WPARAM(wParam); - + if (acc * delta < 0) { // scroll direction reversed. acc = 0; @@ -864,7 +864,7 @@ void GHOST_SystemWin32::processWheelEvent(GHOST_WindowWin32 *window, WPARAM wPar acc += delta; int direction = (acc >= 0) ? 1 : -1; acc = abs(acc); - + while (acc >= WHEEL_DELTA) { system->pushEvent(new GHOST_EventWheel(system->getMilliSeconds(), window, direction)); acc -= WHEEL_DELTA; @@ -1178,10 +1178,10 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam, */ case WM_DEADCHAR: /* The WM_DEADCHAR message is posted to the window with the keyboard focus when a - * WM_KEYUP message is translated by the TranslateMessage function. WM_DEADCHAR - * specifies a character code generated by a dead key. A dead key is a key that - * generates a character, such as the umlaut (double-dot), that is combined with - * another character to form a composite character. For example, the umlaut-O + * WM_KEYUP message is translated by the TranslateMessage function. WM_DEADCHAR + * specifies a character code generated by a dead key. A dead key is a key that + * generates a character, such as the umlaut (double-dot), that is combined with + * another character to form a composite character. For example, the umlaut-O * character (Ö) is generated by typing the dead key for the umlaut character, and * then typing the O key. */ @@ -1193,16 +1193,16 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam, * a dead key that is pressed while holding down the alt key. */ case WM_SYSCHAR: - /* The WM_SYSCHAR message is sent to the window with the keyboard focus when - * a WM_SYSCHAR message is translated by the TranslateMessage function. - * WM_SYSCHAR specifies the character code of a dead key - that is, + /* The WM_SYSCHAR message is sent to the window with the keyboard focus when + * a WM_SYSCHAR message is translated by the TranslateMessage function. + * WM_SYSCHAR specifies the character code of a dead key - that is, * a dead key that is pressed while holding down the alt key. * To prevent the sound, DefWindowProc must be avoided by return */ break; case WM_SYSCOMMAND: - /* The WM_SYSCHAR message is sent to the window when system commands such as - * maximize, minimize or close the window are triggered. Also it is sent when ALT + /* The WM_SYSCHAR message is sent to the window when system commands such as + * maximize, minimize or close the window are triggered. Also it is sent when ALT * button is press for menu. To prevent this we must return preventing DefWindowProc. */ if (wParam == SC_KEYMENU) { @@ -1269,11 +1269,11 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam, break; case WM_MOUSEWHEEL: { - /* The WM_MOUSEWHEEL message is sent to the focus window - * when the mouse wheel is rotated. The DefWindowProc + /* The WM_MOUSEWHEEL message is sent to the focus window + * when the mouse wheel is rotated. The DefWindowProc * function propagates the message to the window's parent. - * There should be no internal forwarding of the message, - * since DefWindowProc propagates it up the parent chain + * There should be no internal forwarding of the message, + * since DefWindowProc propagates it up the parent chain * until it finds a window that processes it. */ @@ -1281,7 +1281,7 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam, POINT mouse_pos = {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)}; HWND mouse_hwnd = ChildWindowFromPoint(HWND_DESKTOP, mouse_pos); GHOST_WindowWin32 *mouse_window = (GHOST_WindowWin32 *)::GetWindowLongPtr(mouse_hwnd, GWLP_USERDATA); - + processWheelEvent(mouse_window ? mouse_window : window , wParam, lParam); eventHandled = true; #ifdef BROKEN_PEEK_TOUCHPAD @@ -1293,7 +1293,7 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam, /* The WM_SETCURSOR message is sent to a window if the mouse causes the cursor * to move within a window and mouse input is not captured. * This means we have to set the cursor shape every time the mouse moves! - * The DefWindowProc function uses this message to set the cursor to an + * The DefWindowProc function uses this message to set the cursor to an * arrow if it is not in the client area. */ if (LOWORD(lParam) == HTCLIENT) { @@ -1301,7 +1301,7 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam, window->loadCursor(window->getCursorVisibility(), window->getCursorShape()); // Bypass call to DefWindowProc return 0; - } + } else { // Outside of client area show standard cursor window->loadCursor(true, GHOST_kStandardCursorDefault); @@ -1317,10 +1317,10 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam, * that contains the cursor. If a window has captured the mouse, this message is not posted. */ case WM_NCHITTEST: - /* The WM_NCHITTEST message is sent to a window when the cursor moves, or - * when a mouse button is pressed or released. If the mouse is not captured, - * the message is sent to the window beneath the cursor. Otherwise, the message - * is sent to the window that has captured the mouse. + /* The WM_NCHITTEST message is sent to a window when the cursor moves, or + * when a mouse button is pressed or released. If the mouse is not captured, + * the message is sent to the window beneath the cursor. Otherwise, the message + * is sent to the window that has captured the mouse. */ break; @@ -1332,11 +1332,11 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam, event = processWindowEvent(GHOST_kEventWindowClose, window); break; case WM_ACTIVATE: - /* The WM_ACTIVATE message is sent to both the window being activated and the window being - * deactivated. If the windows use the same input queue, the message is sent synchronously, + /* The WM_ACTIVATE message is sent to both the window being activated and the window being + * deactivated. If the windows use the same input queue, the message is sent synchronously, * first to the window procedure of the top-level window being deactivated, then to the window * procedure of the top-level window being activated. If the windows use different input queues, - * the message is sent asynchronously, so the window is activated immediately. + * the message is sent asynchronously, so the window is activated immediately. */ { GHOST_ModifierKeys modifiers; @@ -1353,12 +1353,12 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam, break; } case WM_ENTERSIZEMOVE: - /* The WM_ENTERSIZEMOVE message is sent one time to a window after it enters the moving - * or sizing modal loop. The window enters the moving or sizing modal loop when the user - * clicks the window's title bar or sizing border, or when the window passes the - * WM_SYSCOMMAND message to the DefWindowProc function and the wParam parameter of the - * message specifies the SC_MOVE or SC_SIZE value. The operation is complete when - * DefWindowProc returns. + /* The WM_ENTERSIZEMOVE message is sent one time to a window after it enters the moving + * or sizing modal loop. The window enters the moving or sizing modal loop when the user + * clicks the window's title bar or sizing border, or when the window passes the + * WM_SYSCOMMAND message to the DefWindowProc function and the wParam parameter of the + * message specifies the SC_MOVE or SC_SIZE value. The operation is complete when + * DefWindowProc returns. */ window->m_inLiveResize = 1; break; @@ -1366,11 +1366,11 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam, window->m_inLiveResize = 0; break; case WM_PAINT: - /* An application sends the WM_PAINT message when the system or another application + /* An application sends the WM_PAINT message when the system or another application * makes a request to paint a portion of an application's window. The message is sent - * when the UpdateWindow or RedrawWindow function is called, or by the DispatchMessage - * function when the application obtains a WM_PAINT message by using the GetMessage or - * PeekMessage function. + * when the UpdateWindow or RedrawWindow function is called, or by the DispatchMessage + * function when the application obtains a WM_PAINT message by using the GetMessage or + * PeekMessage function. */ if (!window->m_inLiveResize) { event = processWindowEvent(GHOST_kEventWindowUpdate, window); @@ -1381,10 +1381,10 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam, } break; case WM_GETMINMAXINFO: - /* The WM_GETMINMAXINFO message is sent to a window when the size or - * position of the window is about to change. An application can use - * this message to override the window's default maximized size and - * position, or its default minimum or maximum tracking size. + /* The WM_GETMINMAXINFO message is sent to a window when the size or + * position of the window is about to change. An application can use + * this message to override the window's default maximized size and + * position, or its default minimum or maximum tracking size. */ processMinMaxInfo((MINMAXINFO *) lParam); /* Let DefWindowProc handle it. */ @@ -1392,9 +1392,9 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam, case WM_SIZING: case WM_SIZE: /* The WM_SIZE message is sent to a window after its size has changed. - * The WM_SIZE and WM_MOVE messages are not sent if an application handles the + * The WM_SIZE and WM_MOVE messages are not sent if an application handles the * WM_WINDOWPOSCHANGED message without calling DefWindowProc. It is more efficient - * to perform any move or size change processing during the WM_WINDOWPOSCHANGED + * to perform any move or size change processing during the WM_WINDOWPOSCHANGED * message without calling DefWindowProc. */ /* we get first WM_SIZE before we fully init. So, do not dispatch before we continiously resizng */ @@ -1415,10 +1415,10 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam, * and, if needed, change its size or position. */ case WM_MOVE: - /* The WM_SIZE and WM_MOVE messages are not sent if an application handles the + /* The WM_SIZE and WM_MOVE messages are not sent if an application handles the * WM_WINDOWPOSCHANGED message without calling DefWindowProc. It is more efficient - * to perform any move or size change processing during the WM_WINDOWPOSCHANGED - * message without calling DefWindowProc. + * to perform any move or size change processing during the WM_WINDOWPOSCHANGED + * message without calling DefWindowProc. */ /* see WM_SIZE comment*/ if (window->m_inLiveResize) { @@ -1487,13 +1487,13 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam, * that all child windows still exist. */ case WM_NCDESTROY: - /* The WM_NCDESTROY message informs a window that its nonclient area is being destroyed. The + /* The WM_NCDESTROY message informs a window that its nonclient area is being destroyed. The * DestroyWindow function sends the WM_NCDESTROY message to the window following the WM_DESTROY - * message. WM_DESTROY is used to free the allocated memory object associated with the window. + * message. WM_DESTROY is used to free the allocated memory object associated with the window. */ break; case WM_KILLFOCUS: - /* The WM_KILLFOCUS message is sent to a window immediately before it loses the keyboard focus. + /* The WM_KILLFOCUS message is sent to a window immediately before it loses the keyboard focus. * We want to prevent this if a window is still active and it loses focus to nowhere*/ if (!wParam && hwnd == ::GetActiveWindow()) ::SetFocus(hwnd); @@ -1526,7 +1526,7 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam, * when a timer expires. You can process the message by providing a WM_TIMER * case in the window procedure. Otherwise, the default window procedure will * call the TimerProc callback function specified in the call to the SetTimer - * function used to install the timer. + * function used to install the timer. * * In GHOST, we let DefWindowProc call the timer callback. */ @@ -1565,7 +1565,7 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam, GHOST_TUns8 *GHOST_SystemWin32::getClipboard(bool selection) const { char *temp_buff; - + if (IsClipboardFormatAvailable(CF_UNICODETEXT) && OpenClipboard(NULL) ) { wchar_t *buffer; HANDLE hData = GetClipboardData(CF_UNICODETEXT); @@ -1578,14 +1578,14 @@ GHOST_TUns8 *GHOST_SystemWin32::getClipboard(bool selection) const CloseClipboard(); return NULL; } - + temp_buff = alloc_utf_8_from_16(buffer, 0); - + /* Buffer mustn't be accessed after CloseClipboard * it would like accessing free-d memory */ GlobalUnlock(hData); CloseClipboard(); - + return (GHOST_TUns8 *)temp_buff; } else if (IsClipboardFormatAvailable(CF_TEXT) && OpenClipboard(NULL) ) { @@ -1601,17 +1601,17 @@ GHOST_TUns8 *GHOST_SystemWin32::getClipboard(bool selection) const CloseClipboard(); return NULL; } - + len = strlen(buffer); temp_buff = (char *) malloc(len + 1); strncpy(temp_buff, buffer, len); temp_buff[len] = '\0'; - + /* Buffer mustn't be accessed after CloseClipboard * it would like accessing free-d memory */ GlobalUnlock(hData); CloseClipboard(); - + return (GHOST_TUns8 *)temp_buff; } else { @@ -1626,11 +1626,11 @@ void GHOST_SystemWin32::putClipboard(GHOST_TInt8 *buffer, bool selection) const if (OpenClipboard(NULL)) { HLOCAL clipbuffer; wchar_t *data; - + if (buffer) { size_t len = count_utf_16_from_8(buffer); EmptyClipboard(); - + clipbuffer = LocalAlloc(LMEM_FIXED, sizeof(wchar_t) * len); data = (wchar_t *)GlobalLock(clipbuffer); @@ -1686,7 +1686,7 @@ static bool getProcessName(int pid, char *buffer, int max_len) static bool isStartedFromCommandPrompt() { HWND hwnd = GetConsoleWindow(); - + if (hwnd) { DWORD pid = (DWORD)-1; DWORD ppid = GetParentProcessID(); diff --git a/intern/ghost/intern/GHOST_SystemWin32.h b/intern/ghost/intern/GHOST_SystemWin32.h index 0f15f9180ae..e1fd82ec239 100644 --- a/intern/ghost/intern/GHOST_SystemWin32.h +++ b/intern/ghost/intern/GHOST_SystemWin32.h @@ -110,7 +110,7 @@ public: /** * Create a new window. - * The new window is added to the list of windows managed. + * The new window is added to the list of windows managed. * Never explicitly delete the window, use disposeWindow() instead. * \param title The name of the window (displayed in the title bar of the window if the OS supports it). * \param left The coordinate of the left edge of the window. @@ -157,7 +157,7 @@ public: * \return Indication of the presence of events. */ bool processEvents(bool waitForEvent); - + /*************************************************************************************** ** Cursor management functionality @@ -203,7 +203,7 @@ public: * \return Returns the Clipboard */ GHOST_TUns8 *getClipboard(bool selection) const; - + /** * Puts buffer to system clipboard * \param selection Used by X11 only @@ -212,7 +212,7 @@ public: void putClipboard(GHOST_TInt8 *buffer, bool selection) const; /** - * Creates a drag'n'drop event and pushes it immediately onto the event queue. + * Creates a drag'n'drop event and pushes it immediately onto the event queue. * Called by GHOST_DropTargetWin32 class. * \param eventType The type of drag'n'drop event * \param draggedObjectType The type object concerned (currently array of file names, string, ?bitmap) @@ -222,7 +222,7 @@ public: * \return Indication whether the event was handled. */ static GHOST_TSuccess pushDragDropEvent(GHOST_TEventType eventType, GHOST_TDragnDropTypes draggedObjectType, GHOST_WindowWin32 *window, int mouseX, int mouseY, void *data); - + /** * Confirms quitting he program when there is just one window left open * in the application @@ -242,7 +242,7 @@ protected: * \return A success value. */ GHOST_TSuccess exit(); - + /** * Converts raw WIN32 key codes from the wndproc to GHOST keys. * \param vKey The virtual key from hardKey @@ -303,7 +303,7 @@ protected: */ GHOST_TKey processSpecialKey(short vKey, short scanCode) const; - /** + /** * Creates a window event. * \param type The type of event to create. * \param window The window receiving the event (the active window). @@ -351,7 +351,7 @@ protected: * param keys The new state of the modifier keys. */ inline void storeModifierKeys(const GHOST_ModifierKeys& keys); - + /** * Check current key layout for AltGr */ @@ -373,7 +373,7 @@ protected: * \return current status (1 -visible, 0 - hidden) */ int toggleConsole(int action); - + /** The current state of the modifier keys. */ GHOST_ModifierKeys m_modifierKeys; /** State variable set at initialization. */ diff --git a/intern/ghost/intern/GHOST_SystemX11.cpp b/intern/ghost/intern/GHOST_SystemX11.cpp index 69aa3a09977..b7bd0be017d 100644 --- a/intern/ghost/intern/GHOST_SystemX11.cpp +++ b/intern/ghost/intern/GHOST_SystemX11.cpp @@ -121,7 +121,7 @@ GHOST_SystemX11( { XInitThreads(); m_display = XOpenDisplay(NULL); - + if (!m_display) { std::cerr << "Unable to open a display" << std::endl; abort(); /* was return before, but this would just mean it will crash later */ @@ -179,16 +179,16 @@ GHOST_SystemX11( if (gettimeofday(&tv, NULL) == -1) { GHOST_ASSERT(false, "Could not instantiate timer!"); } - + /* Taking care not to overflow the tv.tv_sec * 1000 */ m_start_time = GHOST_TUns64(tv.tv_sec) * 1000 + tv.tv_usec / 1000; - - + + /* use detectable autorepeate, mac and windows also do this */ int use_xkb; int xkb_opcode, xkb_event, xkb_error; int xkb_major = XkbMajorVersion, xkb_minor = XkbMinorVersion; - + use_xkb = XkbQueryExtension(m_display, &xkb_opcode, &xkb_event, &xkb_error, &xkb_major, &xkb_minor); if (use_xkb) { XkbSetDetectableAutoRepeat(m_display, true, NULL); @@ -244,7 +244,7 @@ GHOST_SystemX11:: /* close tablet devices */ if (m_xtablet.StylusDevice) XCloseDevice(m_display, m_xtablet.StylusDevice); - + if (m_xtablet.EraserDevice) XCloseDevice(m_display, m_xtablet.EraserDevice); #endif /* WITH_X11_XINPUT */ @@ -285,7 +285,7 @@ getMilliSeconds() const /* Taking care not to overflow the tv.tv_sec * 1000 */ return GHOST_TUns64(tv.tv_sec) * 1000 + tv.tv_usec / 1000 - m_start_time; } - + GHOST_TUns8 GHOST_SystemX11:: getNumDisplays() const @@ -358,9 +358,9 @@ createWindow(const STR_String& title, const GHOST_TEmbedderWindowID parentWindow) { GHOST_WindowX11 *window = NULL; - + if (!m_display) return 0; - + window = new GHOST_WindowX11(this, m_display, title, left, top, width, height, state, parentWindow, type, @@ -386,7 +386,7 @@ createWindow(const STR_String& title, return window; } -bool GHOST_SystemX11::supportsNativeDialogs(void) +bool GHOST_SystemX11::supportsNativeDialogs(void) { return false; } @@ -516,7 +516,7 @@ GHOST_SystemX11:: findGhostWindow( Window xwind) const { - + if (xwind == 0) return NULL; /* It is not entirely safe to do this as the backptr may point @@ -528,7 +528,7 @@ findGhostWindow( vector<GHOST_IWindow *>::iterator win_it = win_vec.begin(); vector<GHOST_IWindow *>::const_iterator win_end = win_vec.end(); - + for (; win_it != win_end; ++win_it) { GHOST_WindowX11 *window = static_cast<GHOST_WindowX11 *>(*win_it); if (window->getXWindow() == xwind) { @@ -536,14 +536,14 @@ findGhostWindow( } } return NULL; - + } static void SleepTillEvent(Display *display, GHOST_TInt64 maxSleep) { int fd = ConnectionNumber(display); fd_set fds; - + FD_ZERO(&fds); FD_SET(fd, &fds); @@ -555,7 +555,7 @@ static void SleepTillEvent(Display *display, GHOST_TInt64 maxSleep) tv.tv_sec = maxSleep / 1000; tv.tv_usec = (maxSleep - tv.tv_sec * 1000) * 1000; - + select(fd + 1, &fds, NULL, NULL, &tv); } } @@ -618,15 +618,15 @@ processEvents( { /* Get all the current events -- translate them into * ghost events and call base class pushEvent() method. */ - + bool anyProcessed = false; - + do { GHOST_TimerManager *timerMgr = getTimerManager(); - + if (waitForEvent && m_dirty_windows.empty() && !XPending(m_display)) { GHOST_TUns64 next = timerMgr->nextFireTime(); - + if (next == GHOST_kFireTimeNever) { SleepTillEvent(m_display, -1); } @@ -637,11 +637,11 @@ processEvents( SleepTillEvent(m_display, next - getMilliSeconds()); } } - + if (timerMgr->fireTimers(getMilliSeconds())) { anyProcessed = true; } - + while (XPending(m_display)) { XEvent xevent; XNextEvent(m_display, &xevent); @@ -669,10 +669,8 @@ processEvents( } /* dispatch event to XIM server */ - if ((XFilterEvent(&xevent, (Window)NULL) == True) && (xevent.type != KeyRelease)) { - /* do nothing now, the event is consumed by XIM. - * however, KeyRelease event should be processed - * here, otherwise modifiers remain activated. */ + if ((XFilterEvent(&xevent, (Window)NULL) == True)) { + /* do nothing now, the event is consumed by XIM. */ continue; } #endif @@ -738,7 +736,7 @@ processEvents( #endif /* USE_UNITY_WORKAROUND */ } - + if (generateWindowExposeEvents()) { anyProcessed = true; } @@ -748,9 +746,9 @@ processEvents( anyProcessed = true; } #endif - + } while (waitForEvent && !anyProcessed); - + return anyProcessed; } @@ -971,7 +969,7 @@ GHOST_SystemX11::processEvent(XEvent *xe) #else char *utf8_buf = NULL; #endif - + GHOST_TEventType type = (xke->type == KeyPress) ? GHOST_kEventKeyDown : GHOST_kEventKeyUp; GHOST_TKey gkey; @@ -1084,7 +1082,7 @@ GHOST_SystemX11::processEvent(XEvent *xe) } gkey = convertXKey(key_sym); - + if (!XLookupString(xke, &ascii, 1, NULL, NULL)) { ascii = '\0'; } @@ -1178,7 +1176,7 @@ GHOST_SystemX11::processEvent(XEvent *xe) if (utf8_buf != utf8_array) free(utf8_buf); #endif - + break; } @@ -1187,7 +1185,7 @@ GHOST_SystemX11::processEvent(XEvent *xe) { XButtonEvent & xbe = xe->xbutton; GHOST_TButtonMask gbmask = GHOST_kButtonMaskLeft; - GHOST_TEventType type = (xbe.type == ButtonPress) ? + GHOST_TEventType type = (xbe.type == ButtonPress) ? GHOST_kEventButtonDown : GHOST_kEventButtonUp; /* process wheel mouse events and break, only pass on press events */ @@ -1201,7 +1199,7 @@ GHOST_SystemX11::processEvent(XEvent *xe) g_event = new GHOST_EventWheel(getMilliSeconds(), window, -1); break; } - + /* process rest of normal mouse buttons */ if (xbe.button == Button1) gbmask = GHOST_kButtonMaskLeft; @@ -1233,13 +1231,13 @@ GHOST_SystemX11::processEvent(XEvent *xe) ); break; } - + /* change of size, border, layer etc. */ case ConfigureNotify: { /* XConfigureEvent & xce = xe->xconfigure; */ - g_event = new + g_event = new GHOST_Event( getMilliSeconds(), GHOST_kEventWindowSize, @@ -1255,10 +1253,10 @@ GHOST_SystemX11::processEvent(XEvent *xe) /* TODO: make sure this is the correct place for activate/deactivate */ // printf("X: focus %s for window %d\n", xfe.type == FocusIn ? "in" : "out", (int) xfe.window); - + /* May have to look at the type of event and filter some out. */ - GHOST_TEventType gtype = (xfe.type == FocusIn) ? + GHOST_TEventType gtype = (xfe.type == FocusIn) ? GHOST_kEventWindowActivate : GHOST_kEventWindowDeactivate; #if defined(WITH_X11_XINPUT) && defined(X_HAVE_UTF8_STRING) @@ -1271,7 +1269,7 @@ GHOST_SystemX11::processEvent(XEvent *xe) } #endif - g_event = new + g_event = new GHOST_Event( getMilliSeconds(), gtype, @@ -1285,7 +1283,7 @@ GHOST_SystemX11::processEvent(XEvent *xe) XClientMessageEvent & xcme = xe->xclient; if (((Atom)xcme.data.l[0]) == m_atom.WM_DELETE_WINDOW) { - g_event = new + g_event = new GHOST_Event( getMilliSeconds(), GHOST_kEventWindowClose, @@ -1329,14 +1327,14 @@ GHOST_SystemX11::processEvent(XEvent *xe) break; } - + case DestroyNotify: ::exit(-1); /* We're not interested in the following things.(yet...) */ case NoExpose: case GraphicsExpose: break; - + case EnterNotify: case LeaveNotify: { @@ -1349,7 +1347,7 @@ GHOST_SystemX11::processEvent(XEvent *xe) */ XCrossingEvent &xce = xe->xcrossing; if (xce.mode == NotifyNormal) { - g_event = new + g_event = new GHOST_EventCursor( getMilliSeconds(), GHOST_kEventCursorMove, @@ -1397,18 +1395,18 @@ GHOST_SystemX11::processEvent(XEvent *xe) XEvent nxe; Atom target, utf8_string, string, compound_text, c_string; XSelectionRequestEvent *xse = &xe->xselectionrequest; - + target = XInternAtom(m_display, "TARGETS", False); utf8_string = XInternAtom(m_display, "UTF8_STRING", False); string = XInternAtom(m_display, "STRING", False); compound_text = XInternAtom(m_display, "COMPOUND_TEXT", False); c_string = XInternAtom(m_display, "C_STRING", False); - + /* support obsolete clients */ if (xse->property == None) { xse->property = xse->target; } - + nxe.xselection.type = SelectionNotify; nxe.xselection.requestor = xse->requestor; nxe.xselection.property = xse->property; @@ -1416,7 +1414,7 @@ GHOST_SystemX11::processEvent(XEvent *xe) nxe.xselection.selection = xse->selection; nxe.xselection.target = xse->target; nxe.xselection.time = xse->time; - + /* Check to see if the requestor is asking for String */ if (xse->target == utf8_string || xse->target == string || @@ -1447,13 +1445,13 @@ GHOST_SystemX11::processEvent(XEvent *xe) /* Change property to None because we do not support anything but STRING */ nxe.xselection.property = None; } - + /* Send the event to the client 0 0 == False, SelectionNotify */ XSendEvent(m_display, xse->requestor, 0, 0, &nxe); XFlush(m_display); break; } - + default: { #ifdef WITH_X11_XINPUT @@ -1584,7 +1582,7 @@ getButtons( } else { return GHOST_kFailure; - } + } return GHOST_kSuccess; } @@ -1688,7 +1686,7 @@ setCursorPosition( #endif XSync(m_display, 0); /* Sync to process all requests */ - + return GHOST_kSuccess; } @@ -1699,7 +1697,7 @@ addDirtyWindow( GHOST_WindowX11 *bad_wind) { GHOST_ASSERT((bad_wind != NULL), "addDirtyWindow() NULL ptr trapped (window)"); - + m_dirty_windows.push_back(bad_wind); } @@ -1711,7 +1709,7 @@ generateWindowExposeEvents() vector<GHOST_WindowX11 *>::iterator w_start = m_dirty_windows.begin(); vector<GHOST_WindowX11 *>::const_iterator w_end = m_dirty_windows.end(); bool anyProcessed = false; - + for (; w_start != w_end; ++w_start) { GHOST_Event *g_event = new GHOST_Event( @@ -1721,7 +1719,7 @@ generateWindowExposeEvents() ); (*w_start)->validate(); - + if (g_event) { pushEvent(g_event); anyProcessed = true; @@ -1843,7 +1841,15 @@ convertXKey(KeySym key) GXMAP(type, XF86XK_AudioForward, GHOST_kKeyMediaLast); #endif #endif + /* Non US keyboard layouts: avoid 'UnknownKey' - TODO(campbell): lookup scan-codes. */ + GXMAP(type, XK_dead_circumflex, GHOST_kKeyAccentGrave); /* 'de' */ + GXMAP(type, XK_masculine, GHOST_kKeyAccentGrave); /* 'es' */ + GXMAP(type, XK_onehalf, GHOST_kKeyAccentGrave); /* 'dk' */ + GXMAP(type, XK_twosuperior, GHOST_kKeyAccentGrave); /* 'fr' */ default: +#ifdef GHOST_DEBUG + printf("%s: unknown key: %lu / 0x%lx\n", __func__, key, key); +#endif type = GHOST_kKeyUnknown; break; } @@ -2110,12 +2116,12 @@ GHOST_TUns8 *GHOST_SystemX11::getClipboard(bool selection) const unsigned char *tmp_data = (unsigned char *) malloc(sel_len + 1); memcpy((char *)tmp_data, (char *)sel_buf, sel_len); tmp_data[sel_len] = '\0'; - + if (sseln == m_atom.STRING) XFree(sel_buf); else free(sel_buf); - + return tmp_data; } return(NULL); @@ -2156,7 +2162,7 @@ void GHOST_SystemX11::putClipboard(GHOST_TInt8 *buffer, bool selection) const } #ifdef WITH_XDND -GHOST_TSuccess GHOST_SystemX11::pushDragDropEvent(GHOST_TEventType eventType, +GHOST_TSuccess GHOST_SystemX11::pushDragDropEvent(GHOST_TEventType eventType, GHOST_TDragnDropTypes draggedObjectType, GHOST_IWindow *window, int mouseX, int mouseY, @@ -2322,7 +2328,7 @@ void GHOST_SystemX11::refreshXInputDevices() for (int i = 0; i < device_count; ++i) { char *device_type = device_info[i].type ? XGetAtomName(m_display, device_info[i].type) : NULL; - + // printf("Tablet type:'%s', name:'%s', index:%d\n", device_type, device_info[i].name, i); @@ -2355,7 +2361,7 @@ void GHOST_SystemX11::refreshXInputDevices() break; } - + ici = (XAnyClassPtr)(((char *)ici) + ici->length); } } diff --git a/intern/ghost/intern/GHOST_SystemX11.h b/intern/ghost/intern/GHOST_SystemX11.h index b910589a1ad..f279cf53dcd 100644 --- a/intern/ghost/intern/GHOST_SystemX11.h +++ b/intern/ghost/intern/GHOST_SystemX11.h @@ -86,7 +86,7 @@ public: GHOST_SystemX11( ); - + /** * Destructor. */ @@ -114,7 +114,7 @@ public: GHOST_TUns64 getMilliSeconds( ) const; - + /** * Returns the number of displays on this system. @@ -146,7 +146,7 @@ public: /** * Create a new window. - * The new window is added to the list of windows managed. + * The new window is added to the list of windows managed. * Never explicitly delete the window, use disposeWindow() instead. * \param title The name of the window (displayed in the title bar of the window if the OS supports it). * \param left The coordinate of the left edge of the window. @@ -210,7 +210,7 @@ public: GHOST_TInt32& x, GHOST_TInt32& y ) const; - + GHOST_TSuccess setCursorPosition( GHOST_TInt32 x, @@ -239,15 +239,15 @@ public: /** * Flag a window as dirty. This will - * generate a GHOST window update event on a call to processEvents() + * generate a GHOST window update event on a call to processEvents() */ void addDirtyWindow( GHOST_WindowX11 *bad_wind ); - - + + /** * return a pointer to the X11 display structure */ @@ -256,7 +256,7 @@ public: getXDisplay( ) { return m_display; - } + } #if defined(WITH_X11_XINPUT) && defined(X_HAVE_UTF8_STRING) XIM @@ -277,7 +277,7 @@ public: * \return Returns the Clipboard indicated by Flag */ GHOST_TUns8 *getClipboard(bool selection) const; - + /** * Puts buffer to system clipboard * \param buffer The buffer to copy to the clipboard @@ -287,14 +287,14 @@ public: #ifdef WITH_XDND /** - * Creates a drag'n'drop event and pushes it immediately onto the event queue. + * Creates a drag'n'drop event and pushes it immediately onto the event queue. * Called by GHOST_DropTargetX11 class. * \param eventType The type of drag'n'drop event * \param draggedObjectType The type object concerned (currently array of file names, string, ?bitmap) * \param mouseX x mouse coordinate (in window coordinates) * \param mouseY y mouse coordinate * \param window The window on which the event occurred - * \return Indication whether the event was handled. + * \return Indication whether the event was handled. */ static GHOST_TSuccess pushDragDropEvent(GHOST_TEventType eventType, GHOST_TDragnDropTypes draggedObjectType, GHOST_IWindow *window, int mouseX, int mouseY, void *data); #endif diff --git a/intern/ghost/intern/GHOST_TaskbarWin32.h b/intern/ghost/intern/GHOST_TaskbarWin32.h index 0ef71754717..f65207af706 100644 --- a/intern/ghost/intern/GHOST_TaskbarWin32.h +++ b/intern/ghost/intern/GHOST_TaskbarWin32.h @@ -87,7 +87,7 @@ typedef enum TBPFLAG { TBPF_PAUSED = 0x8, } TBPFLAG; -#define THBN_CLICKED 0x1800 +#define THBN_CLICKED 0x1800 extern "C" { const GUID IID_ITaskList3 = {0xEA1AFB91, 0x9E28, 0x4B86, {0x90, 0xE9, 0x9E, 0x9F, 0x8A, 0x5E, 0xEF, 0xAF}}; diff --git a/intern/ghost/intern/GHOST_TaskbarX11.cpp b/intern/ghost/intern/GHOST_TaskbarX11.cpp index b47068df39f..2ef82dc6636 100644 --- a/intern/ghost/intern/GHOST_TaskbarX11.cpp +++ b/intern/ghost/intern/GHOST_TaskbarX11.cpp @@ -127,4 +127,4 @@ void GHOST_TaskBarX11::set_progress_enabled(bool enabled) assert(is_valid()); unity_set_progress_visible(handle, enabled ? 1 : 0); unity_event_loop(NULL, 0); -}
\ No newline at end of file +} diff --git a/intern/ghost/intern/GHOST_TimerManager.cpp b/intern/ghost/intern/GHOST_TimerManager.cpp index f6ec9d3febe..1918fc26151 100644 --- a/intern/ghost/intern/GHOST_TimerManager.cpp +++ b/intern/ghost/intern/GHOST_TimerManager.cpp @@ -102,14 +102,14 @@ GHOST_TUns64 GHOST_TimerManager::nextFireTime() { GHOST_TUns64 smallest = GHOST_kFireTimeNever; TTimerVector::iterator iter; - + for (iter = m_timers.begin(); iter != m_timers.end(); ++iter) { GHOST_TUns64 next = (*iter)->getNext(); - + if (next < smallest) smallest = next; } - + return smallest; } diff --git a/intern/ghost/intern/GHOST_TimerManager.h b/intern/ghost/intern/GHOST_TimerManager.h index 6cf4bcf40eb..78026a743eb 100644 --- a/intern/ghost/intern/GHOST_TimerManager.h +++ b/intern/ghost/intern/GHOST_TimerManager.h @@ -90,11 +90,11 @@ public: /** * Finds the soonest time the next timer would fire. - * \return The soonest time the next timer would fire, + * \return The soonest time the next timer would fire, * or GHOST_kFireTimeNever if no timers exist. */ GHOST_TUns64 nextFireTime(); - + /** * Checks all timer tasks to see if they are expired and fires them if needed. * \param time The current time. diff --git a/intern/ghost/intern/GHOST_TimerTask.h b/intern/ghost/intern/GHOST_TimerTask.h index 45aa66e4630..fa35fd134f5 100644 --- a/intern/ghost/intern/GHOST_TimerTask.h +++ b/intern/ghost/intern/GHOST_TimerTask.h @@ -78,7 +78,7 @@ public: * \param start The timer start time. */ void setStart(GHOST_TUns64 start) - { + { m_start = start; } @@ -96,7 +96,7 @@ public: * \param interval The timer interval. */ void setInterval(GHOST_TUns64 interval) - { + { m_interval = interval; } @@ -114,7 +114,7 @@ public: * \param next The time the timerProc will be called. */ void setNext(GHOST_TUns64 next) - { + { m_next = next; } @@ -144,7 +144,7 @@ public: { return m_userData; } - + /** * Changes the time user data. * \param userData: The timer user data. @@ -168,7 +168,7 @@ public: * \param auxData The auxiliary storage room. */ void setAuxData(GHOST_TUns32 auxData) - { + { m_auxData = auxData; } diff --git a/intern/ghost/intern/GHOST_Window.cpp b/intern/ghost/intern/GHOST_Window.cpp index 71fa260f0f2..6596028d5a1 100644 --- a/intern/ghost/intern/GHOST_Window.cpp +++ b/intern/ghost/intern/GHOST_Window.cpp @@ -58,12 +58,12 @@ GHOST_Window::GHOST_Window( { m_isUnsavedChanges = false; m_canAcceptDragOperation = false; - + m_progressBarVisible = false; - + m_cursorGrabAccumPos[0] = 0; m_cursorGrabAccumPos[1] = 0; - + m_nativePixelSize = 1.0f; m_fullScreen = state == GHOST_kWindowStateFullScreen; @@ -208,7 +208,7 @@ GHOST_TSuccess GHOST_Window::setCustomCursorShape(GHOST_TUns8 bitmap[16][2], GHO 16, 16, hotX, hotY, 0, 1); } -GHOST_TSuccess GHOST_Window::setCustomCursorShape(GHOST_TUns8 *bitmap, GHOST_TUns8 *mask, +GHOST_TSuccess GHOST_Window::setCustomCursorShape(GHOST_TUns8 *bitmap, GHOST_TUns8 *mask, int sizex, int sizey, int hotX, int hotY, int fg_color, int bg_color) { @@ -234,7 +234,7 @@ bool GHOST_Window::canAcceptDragOperation() const GHOST_TSuccess GHOST_Window::setModifiedState(bool isUnsavedChanges) { m_isUnsavedChanges = isUnsavedChanges; - + return GHOST_kSuccess; } diff --git a/intern/ghost/intern/GHOST_Window.h b/intern/ghost/intern/GHOST_Window.h index 2798bdf72f3..413a3315225 100644 --- a/intern/ghost/intern/GHOST_Window.h +++ b/intern/ghost/intern/GHOST_Window.h @@ -40,7 +40,7 @@ class GHOST_Context; /** * Platform independent implementation of GHOST_IWindow. - * Dimensions are given in screen coordinates that are relative to the + * Dimensions are given in screen coordinates that are relative to the * upper-left corner of the screen. * Implements part of the GHOST_IWindow interface and adds some methods to * be implemented by childs of this class. @@ -94,7 +94,7 @@ public: * virtual GHOST_TSuccess activateDrawingContext() = 0; * virtual GHOST_TSuccess invalidate() = 0; */ - + /** * Destructor. * Closes the window and disposes resources allocated. @@ -105,7 +105,7 @@ public: * Returns indication as to whether the window is valid. * \return The validity of the window. */ - virtual bool getValid() const { + virtual bool getValid() const { return m_context != NULL; } @@ -114,7 +114,7 @@ public: * \return The associated OS object/handle */ virtual void *getOSWindow() const; - + /** * Returns the current cursor shape. * \return The current cursor shape. @@ -185,14 +185,14 @@ public: virtual GHOST_TSuccess setProgressBar(float /*progress*/) { return GHOST_kFailure; } - + /** * Hides the progress bar in the icon */ virtual GHOST_TSuccess endProgressBar() { return GHOST_kFailure; } - + /** * Sets the swap interval for swapBuffers. * \param interval The swap interval to use. @@ -216,26 +216,26 @@ public: * Tells if the ongoing drag'n'drop object can be accepted upon mouse drop */ void setAcceptDragOperation(bool canAccept); - + /** * Returns acceptance of the dropped object * Usually called by the "object dropped" event handling function */ bool canAcceptDragOperation() const; - + /** * Sets the window "modified" status, indicating unsaved changes * \param isUnsavedChanges Unsaved changes or not * \return Indication of success. */ virtual GHOST_TSuccess setModifiedState(bool isUnsavedChanges); - + /** * Gets the window "modified" status, indicating unsaved changes * \return True if there are unsaved changes */ virtual bool getModifiedState(); - + /** * Returns the type of drawing context used in this window. * \return The current type of drawing context. @@ -278,7 +278,7 @@ public: { return m_userData; } - + /** * Changes the window user data. * \param userData: The window user data. @@ -287,7 +287,7 @@ public: { m_userData = userData; } - + float getNativePixelSize(void) { if (m_nativePixelSize > 0.0f) @@ -341,7 +341,7 @@ protected: virtual GHOST_TSuccess setWindowCursorGrab(GHOST_TGrabCursorMode /*mode*/) { return GHOST_kSuccess; } - + /** * Sets the cursor shape on the window using * native window system calls. @@ -355,15 +355,15 @@ protected: virtual GHOST_TSuccess setWindowCustomCursorShape(GHOST_TUns8 bitmap[16][2], GHOST_TUns8 mask[16][2], int hotX, int hotY) = 0; - - virtual GHOST_TSuccess setWindowCustomCursorShape(GHOST_TUns8 *bitmap, GHOST_TUns8 *mask, + + virtual GHOST_TSuccess setWindowCustomCursorShape(GHOST_TUns8 *bitmap, GHOST_TUns8 *mask, int szx, int szy, int hotX, int hotY, int fg, int bg) = 0; GHOST_TSuccess releaseNativeHandles(); /** The drawing context installed in this window. */ GHOST_TDrawingContextType m_drawingContextType; - + /** The window user data */ GHOST_TUserDataPtr m_userData; @@ -384,16 +384,16 @@ protected: /** The current shape of the cursor */ GHOST_TStandardCursor m_cursorShape; - + /** The presence of progress indicator with the application icon */ bool m_progressBarVisible; - + /** The acceptance of the "drop candidate" of the current drag'n'drop operation */ bool m_canAcceptDragOperation; - + /** Modified state : are there unsaved changes */ bool m_isUnsavedChanges; - + /** Stores whether this is a full screen window. */ bool m_fullScreen; @@ -407,7 +407,7 @@ protected: GHOST_TUns32 m_fullScreenWidth; /** Full-screen height */ GHOST_TUns32 m_fullScreenHeight; - + /* OSX only, retina screens */ float m_nativePixelSize; diff --git a/intern/ghost/intern/GHOST_WindowCocoa.h b/intern/ghost/intern/GHOST_WindowCocoa.h index 9dbc85d91e2..54ecd2b44c8 100644 --- a/intern/ghost/intern/GHOST_WindowCocoa.h +++ b/intern/ghost/intern/GHOST_WindowCocoa.h @@ -89,7 +89,7 @@ public: * \return The validity of the window. */ bool getValid() const; - + /** * Returns the associated NSWindow object * \return The associated NSWindow object @@ -110,11 +110,11 @@ public: /** * Returns the window rectangle dimensions. - * The dimensions are given in screen coordinates that are relative to the upper-left corner of the screen. + * The dimensions are given in screen coordinates that are relative to the upper-left corner of the screen. * \param bounds The bounding rectangle of the window. */ void getWindowBounds(GHOST_Rect& bounds) const; - + /** * Returns the client rectangle dimensions. * The left and top members of the rectangle are always zero. @@ -153,7 +153,7 @@ public: * \return Indication of success. */ GHOST_TSuccess setModifiedState(bool isUnsavedChanges); - + /** * Converts a point in screen coordinates to client rectangle coordinates * \param inX The x-coordinate on the screen. @@ -197,7 +197,7 @@ public: * \return The NSScreen object */ NSScreen *getScreen(); - + /** * Sets the state of the window (normal, minimized, maximized). * \param state The state of the window. @@ -213,7 +213,7 @@ public: GHOST_TSuccess setOrder(GHOST_TWindowOrder order); void loadCursor(bool visible, GHOST_TStandardCursor cursor) const; - + const GHOST_TabletData *GetTabletData() { return &m_tablet; @@ -223,32 +223,32 @@ public: { return m_tablet; } - + /** * Sets the progress bar value displayed in the window/application icon * \param progress The progress % (0.0 to 1.0) */ GHOST_TSuccess setProgressBar(float progress); - + /** * Hides the progress bar icon */ GHOST_TSuccess endProgressBar(); - - + + void setNativePixelSize(void); GHOST_TSuccess beginFullScreen() const {return GHOST_kFailure;} GHOST_TSuccess endFullScreen() const {return GHOST_kFailure;} - + /** public function to get the window containing the OpenGL view */ CocoaWindow *getCocoaWindow() const {return m_window;}; /* Internal value to ensure proper redraws during animations */ void setImmediateDraw(bool value) { m_immediateDraw = value; } bool getImmediateDraw(void) const { return m_immediateDraw; } - + protected: /** @@ -268,13 +268,13 @@ protected: * native window system calls. */ GHOST_TSuccess setWindowCursorVisibility(bool visible); - + /** * Sets the cursor grab on the window using * native window system calls. */ GHOST_TSuccess setWindowCursorGrab(GHOST_TGrabCursorMode mode); - + /** * Sets the cursor shape on the window using * native window system calls. @@ -287,14 +287,14 @@ protected: */ GHOST_TSuccess setWindowCustomCursorShape(GHOST_TUns8 *bitmap, GHOST_TUns8 *mask, int sizex, int sizey, int hotX, int hotY, int fg_color, int bg_color); - + GHOST_TSuccess setWindowCustomCursorShape(GHOST_TUns8 bitmap[16][2], GHOST_TUns8 mask[16][2], int hotX, int hotY); /** The window containing the OpenGL view */ CocoaWindow *m_window; - + /** The openGL view */ - CocoaOpenGLView *m_openGLView; + CocoaOpenGLView *m_openGLView; /** The mother SystemCocoa class to send events */ GHOST_SystemCocoa *m_systemCocoa; diff --git a/intern/ghost/intern/GHOST_WindowManager.cpp b/intern/ghost/intern/GHOST_WindowManager.cpp index 790c73deca5..31e1b0401f1 100644 --- a/intern/ghost/intern/GHOST_WindowManager.cpp +++ b/intern/ghost/intern/GHOST_WindowManager.cpp @@ -42,7 +42,7 @@ #include "GHOST_Window.h" -GHOST_WindowManager::GHOST_WindowManager() : +GHOST_WindowManager::GHOST_WindowManager() : m_fullScreenWindow(0), m_activeWindow(0), m_activeWindowBeforeFullScreen(0) @@ -61,7 +61,7 @@ GHOST_TSuccess GHOST_WindowManager::addWindow(GHOST_IWindow *window) GHOST_TSuccess success = GHOST_kFailure; if (window) { if (!getWindowFound(window)) { - // Store the pointer to the window + // Store the pointer to the window m_windows.push_back(window); success = GHOST_kSuccess; } @@ -170,7 +170,7 @@ GHOST_TSuccess GHOST_WindowManager::setActiveWindow(GHOST_IWindow *window) } return success; } - + GHOST_IWindow *GHOST_WindowManager::getActiveWindow(void) const { @@ -200,7 +200,7 @@ GHOST_IWindow *GHOST_WindowManager::getWindowAssociatedWithOSWindow(void *osWind if ((*iter)->getOSWindow() == osWindow) return *iter; } - + return NULL; } @@ -208,7 +208,7 @@ bool GHOST_WindowManager::getAnyModifiedState() { bool isAnyModified = false; std::vector<GHOST_IWindow *>::iterator iter; - + for (iter = m_windows.begin(); iter != m_windows.end(); ++iter) { if ((*iter)->getModifiedState()) isAnyModified = true; diff --git a/intern/ghost/intern/GHOST_WindowManager.h b/intern/ghost/intern/GHOST_WindowManager.h index e868a9b0416..a7dde2af39c 100644 --- a/intern/ghost/intern/GHOST_WindowManager.h +++ b/intern/ghost/intern/GHOST_WindowManager.h @@ -110,38 +110,38 @@ public: * \param window The new active window. */ GHOST_TSuccess setActiveWindow(GHOST_IWindow *window); - + /** * Returns the active window (the window receiving events). * There can be only one window active which should be in the current window list. * \return window The active window (or NULL if there is none). */ GHOST_IWindow *getActiveWindow(void) const; - + /** * Set this window to be inactive (not receiving events). * \param window The window to deactivate. */ void setWindowInactive(const GHOST_IWindow *window); - + /** - * Return a vector of the windows currently managed by this - * class. + * Return a vector of the windows currently managed by this + * class. * \warning It is very dangerous to mess with the contents of - * this vector. Please do not destroy or add windows use the + * this vector. Please do not destroy or add windows use the * interface above for this, */ std::vector<GHOST_IWindow *> & getWindows(); - + /** * Finds the window associated with an OS window object/handle * \param osWindow The OS window object/handle * \return The associated window, null if none corresponds */ GHOST_IWindow *getWindowAssociatedWithOSWindow(void *osWindow); - + /** * Return true if any windows has a modified status * \return True if any window has unsaved changes @@ -164,7 +164,7 @@ protected: #ifdef WITH_CXX_GUARDEDALLOC MEM_CXX_CLASS_ALLOC_FUNCS("GHOST:GHOST_WindowManager") #endif - + }; #endif // __GHOST_WINDOWMANAGER_H__ diff --git a/intern/ghost/intern/GHOST_WindowWin32.cpp b/intern/ghost/intern/GHOST_WindowWin32.cpp index 3c9c7c415bb..676a29f28d4 100644 --- a/intern/ghost/intern/GHOST_WindowWin32.cpp +++ b/intern/ghost/intern/GHOST_WindowWin32.cpp @@ -99,7 +99,7 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system, if (state != GHOST_kWindowStateFullScreen) { RECT rect; MONITORINFO monitor; - GHOST_TUns32 tw, th; + GHOST_TUns32 tw, th; #ifndef _MSC_VER int cxsizeframe = GetSystemMetrics(SM_CXSIZEFRAME); @@ -158,7 +158,7 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system, width = rect.right - rect.left; height = rect.bottom - rect.top; } - + wchar_t *title_16 = alloc_utf16_from_8((char *)(const char *)title, 0); m_hWnd = ::CreateWindowW( s_windowClassName, // pointer to registered class name @@ -225,7 +225,7 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system, ::ShowWindow(m_hWnd, nCmdShow); #ifdef WIN32_COMPOSITING if (alphaBackground && parentwindowhwnd == 0) { - + HRESULT hr = S_OK; // Create and populate the Blur Behind structure @@ -817,7 +817,7 @@ GHOST_TSuccess GHOST_WindowWin32::setWindowCursorGrab(GHOST_TGrabCursorMode mode m_cursorGrabBounds.m_l = m_cursorGrabBounds.m_r = -1; /* disable */ registerMouseClickEvent(3); } - + return GHOST_kSuccess; } @@ -1041,7 +1041,7 @@ GHOST_TSuccess GHOST_WindowWin32::setWindowCustomCursorShape( GHOST_TSuccess GHOST_WindowWin32::setProgressBar(float progress) -{ +{ /*SetProgressValue sets state to TBPF_NORMAL automaticly*/ if (m_Bar && S_OK == m_Bar->SetProgressValue(m_hWnd, 10000 * progress, 10000)) return GHOST_kSuccess; diff --git a/intern/ghost/intern/GHOST_WindowWin32.h b/intern/ghost/intern/GHOST_WindowWin32.h index 75a33951ff4..d998e86c9b1 100644 --- a/intern/ghost/intern/GHOST_WindowWin32.h +++ b/intern/ghost/intern/GHOST_WindowWin32.h @@ -132,11 +132,11 @@ public: /** * Returns the window rectangle dimensions. - * The dimensions are given in screen coordinates that are relative to the upper-left corner of the screen. + * The dimensions are given in screen coordinates that are relative to the upper-left corner of the screen. * \param bounds The bounding rectangle of the window. */ void getWindowBounds(GHOST_Rect& bounds) const; - + /** * Returns the client rectangle dimensions. * The left and top members of the rectangle are always zero. @@ -211,19 +211,19 @@ public: * \param progress The progress % */ GHOST_TSuccess setProgressBar(float progress); - + /** * Hides the progress bar in the icon */ GHOST_TSuccess endProgressBar(); - + /** - * Register a mouse click event (should be called + * Register a mouse click event (should be called * for any real button press, controls mouse * capturing). * - * \param press + * \param press * 0 - mouse pressed * 1 - mouse released * 2 - operator grab @@ -286,14 +286,14 @@ private: * native window system calls. */ GHOST_TSuccess setWindowCursorVisibility(bool visible); - + /** * Sets the cursor grab on the window using native window system calls. * Using registerMouseClickEvent. * \param mode GHOST_TGrabCursorMode. */ GHOST_TSuccess setWindowCursorGrab(GHOST_TGrabCursorMode mode); - + /** * Sets the cursor shape on the window using * native window system calls. @@ -318,7 +318,7 @@ private: int fg_color, int bg_color ); - + /** Pointer to system */ GHOST_SystemWin32 *m_system; /** Pointer to COM IDropTarget implementor */ @@ -330,7 +330,7 @@ private: /** Flag for if window has captured the mouse */ bool m_hasMouseCaptured; - /** Flag if an operator grabs the mouse with WM_cursor_grab_enable/ungrab() + /** Flag if an operator grabs the mouse with WM_cursor_grab_enable/ungrab() * Multiple grabs must be released with a single ungrab */ bool m_hasGrabMouse; /** Count of number of pressed buttons */ diff --git a/intern/ghost/intern/GHOST_WindowX11.cpp b/intern/ghost/intern/GHOST_WindowX11.cpp index 3c291bd5ec6..ade4799a52d 100644 --- a/intern/ghost/intern/GHOST_WindowX11.cpp +++ b/intern/ghost/intern/GHOST_WindowX11.cpp @@ -204,7 +204,7 @@ static XVisualInfo *x11_visualinfo_from_glx( numOfAASamples = 0; actualSamples = 0; } - + #ifdef WITH_X11_ALPHA if ( needAlpha && glx_version >= 103 @@ -276,7 +276,7 @@ static XVisualInfo *x11_visualinfo_from_glx( /* legacy, don't use extension */ for (;;) { GHOST_X11_GL_GetAttributes(glx_attribs, 64, actualSamples, stereoVisual, needAlpha, false); - + visual = glXChooseVisual(display, DefaultScreen(display), glx_attribs); /* Any sample level or even zero, which means oversampling disabled, is good @@ -408,7 +408,7 @@ GHOST_WindowX11(GHOST_SystemX11 *system, Window root_return; int x_return, y_return; unsigned int w_return, h_return, border_w_return, depth_return; - + XGetGeometry(m_display, parentWindow, &root_return, &x_return, &y_return, &w_return, &h_return, &border_w_return, &depth_return); @@ -430,8 +430,8 @@ GHOST_WindowX11(GHOST_SystemX11 *system, &xattributes); XSelectInput(m_display, parentWindow, SubstructureNotifyMask); - - } + + } #ifdef WITH_XDND /* initialize drop target for newly created window */ @@ -717,12 +717,12 @@ getTitle( STR_String& title) const { char *name = NULL; - + XFetchName(m_display, m_window, &name); title = name ? name : "untitled"; XFree(name); } - + void GHOST_WindowX11:: getWindowBounds( @@ -742,12 +742,12 @@ getClientBounds( int x_return, y_return; unsigned int w_return, h_return, border_w_return, depth_return; GHOST_TInt32 screen_x, screen_y; - + XGetGeometry(m_display, m_window, &root_return, &x_return, &y_return, &w_return, &h_return, &border_w_return, &depth_return); clientToScreen(0, 0, screen_x, screen_y); - + bounds.m_l = screen_x; bounds.m_r = bounds.m_l + w_return; bounds.m_t = screen_y; @@ -794,7 +794,7 @@ setClientSize( XConfigureWindow(m_display, m_window, value_mask, &values); return GHOST_kSuccess; -} +} void GHOST_WindowX11:: @@ -818,7 +818,7 @@ screenToClient( outX = ax; outY = ay; } - + void GHOST_WindowX11:: clientToScreen( @@ -1159,7 +1159,7 @@ setOrder( GHOST_TWindowOrder order) { if (order == GHOST_kWindowOrderTop) { - XWindowAttributes attr; + XWindowAttributes attr; Atom atom; /* We use both XRaiseWindow and _NET_ACTIVE_WINDOW, since some @@ -1209,7 +1209,7 @@ setOrder( else { return GHOST_kFailure; } - + return GHOST_kSuccess; } @@ -1233,8 +1233,8 @@ invalidate() if (m_invalid_window == false) { m_system->addDirtyWindow(this); m_invalid_window = true; - } - + } + return GHOST_kSuccess; } @@ -1242,15 +1242,15 @@ invalidate() * called by the X11 system implementation when expose events * for the window have been pushed onto the GHOST queue */ - + void GHOST_WindowX11:: validate() { m_invalid_window = false; -} - - +} + + /** * Destructor. * Closes the window and disposes resources allocated. @@ -1289,7 +1289,7 @@ GHOST_WindowX11:: XSetSelectionOwner(m_display, Clipboard_atom, None, CurrentTime); } } - + if (m_visualInfo) { XFree(m_visualInfo); } @@ -1425,13 +1425,13 @@ getStandardCursor( if (xcursor_id) { Cursor xcursor = m_standard_cursors[xcursor_id]; - + if (!xcursor) { xcursor = XCreateFontCursor(m_display, xcursor_id); m_standard_cursors[xcursor_id] = xcursor; } - + return xcursor; } else { @@ -1447,7 +1447,7 @@ getEmptyCursor( Pixmap blank; XColor dummy = {0}; char data[1] = {0}; - + /* make a blank cursor */ blank = XCreateBitmapFromData( m_display, @@ -1468,7 +1468,7 @@ setWindowCursorVisibility( bool visible) { Cursor xcursor; - + if (visible) { if (m_visible_cursor) xcursor = m_visible_cursor; @@ -1481,7 +1481,7 @@ setWindowCursorVisibility( XDefineCursor(m_display, m_window, xcursor); XFlush(m_display); - + return GHOST_kSuccess; } @@ -1544,7 +1544,7 @@ setWindowCursorGrab( } XFlush(m_display); - + return GHOST_kSuccess; } @@ -1556,7 +1556,7 @@ setWindowCursorShape( Cursor xcursor = getStandardCursor(shape); m_visible_cursor = xcursor; - + XDefineCursor(m_display, m_window, xcursor); XFlush(m_display); @@ -1578,7 +1578,7 @@ setWindowCustomCursorShape( GHOST_TSuccess GHOST_WindowX11:: -setWindowCustomCursorShape( +setWindowCustomCursorShape( GHOST_TUns8 *bitmap, GHOST_TUns8 *mask, int sizex, @@ -1591,7 +1591,7 @@ setWindowCustomCursorShape( Colormap colormap = DefaultColormap(m_display, m_visualInfo->screen); Pixmap bitmap_pix, mask_pix; XColor fg, bg; - + if (XAllocNamedColor(m_display, colormap, "White", &fg, &fg) == 0) return GHOST_kFailure; if (XAllocNamedColor(m_display, colormap, "Black", &bg, &bg) == 0) return GHOST_kFailure; @@ -1601,13 +1601,13 @@ setWindowCustomCursorShape( bitmap_pix = XCreateBitmapFromData(m_display, m_window, (char *) bitmap, sizex, sizey); mask_pix = XCreateBitmapFromData(m_display, m_window, (char *) mask, sizex, sizey); - + m_custom_cursor = XCreatePixmapCursor(m_display, bitmap_pix, mask_pix, &fg, &bg, hotX, hotY); XDefineCursor(m_display, m_window, m_custom_cursor); XFlush(m_display); m_visible_cursor = m_custom_cursor; - + XFreePixmap(m_display, bitmap_pix); XFreePixmap(m_display, mask_pix); diff --git a/intern/ghost/intern/GHOST_WindowX11.h b/intern/ghost/intern/GHOST_WindowX11.h index 236fe0b76b0..bf2497ee6d6 100644 --- a/intern/ghost/intern/GHOST_WindowX11.h +++ b/intern/ghost/intern/GHOST_WindowX11.h @@ -54,7 +54,7 @@ class GHOST_DropTargetX11; /** * X11 implementation of GHOST_IWindow. - * Dimensions are given in screen coordinates that are relative to the upper-left corner of the screen. + * Dimensions are given in screen coordinates that are relative to the upper-left corner of the screen. * \author Laurence Bourn * \date October 26, 2001 */ @@ -112,7 +112,7 @@ public: getWindowBounds( GHOST_Rect& bounds ) const; - + void getClientBounds( GHOST_Rect& bounds @@ -149,7 +149,7 @@ public: GHOST_TInt32& outX, GHOST_TInt32& outY ) const; - + GHOST_TWindowState getState( ) const; @@ -158,12 +158,12 @@ public: setState( GHOST_TWindowState state ); - + GHOST_TSuccess setOrder( GHOST_TWindowOrder order ); - + GHOST_TSuccess invalidate( ); @@ -191,7 +191,7 @@ public: validate( ); - /** + /** * Return a handle to the x11 window type. */ Window @@ -257,7 +257,7 @@ protected: setWindowCursorVisibility( bool visible ); - + /** * Sets the cursor grab on the window using * native window system calls. @@ -290,7 +290,7 @@ protected: int hotX, int hotY ); - + /** * Sets the cursor shape on the window using * native window system calls (Arbitrary size/color). @@ -310,7 +310,7 @@ protected: private: /// Force use of public constructor. - + GHOST_WindowX11( ); @@ -322,11 +322,11 @@ private: getStandardCursor( GHOST_TStandardCursor g_cursor ); - + Cursor getEmptyCursor( ); - + Window m_window; Display *m_display; XVisualInfo *m_visualInfo; @@ -342,13 +342,13 @@ private: /** XCursor structure of an empty (blank) cursor */ Cursor m_empty_cursor; - + /** XCursor structure of the custom cursor */ Cursor m_custom_cursor; /** XCursor to show when cursor is visible */ Cursor m_visible_cursor; - + /** Cache of XC_* ID's to XCursor structures */ std::map<unsigned int, Cursor> m_standard_cursors; diff --git a/intern/ghost/test/CMakeLists.txt b/intern/ghost/test/CMakeLists.txt index 0cec217630c..9f714ae4fba 100644 --- a/intern/ghost/test/CMakeLists.txt +++ b/intern/ghost/test/CMakeLists.txt @@ -103,7 +103,7 @@ suffix_relpaths(SRC_NEW "${SRC}" "../../guardedalloc/") include_directories(${INC_NEW}) add_library(guardedalloc_lib ${SRC_NEW}) -# blenfont +# blenfont include(${CMAKE_SOURCE_DIR}/../../../source/blender/blenfont/CMakeLists.txt) suffix_relpaths(INC_NEW "${INC}" "../../../source/blender/blenfont/") suffix_relpaths(SRC_NEW "${SRC}" "../../../source/blender/blenfont/") @@ -128,7 +128,7 @@ add_library(glewmx_lib ${SRC_NEW}) include_directories( "../../../source/blender/blenlib" ) -add_library(bli_lib +add_library(bli_lib "../../../source/blender/blenlib/intern/fileops.c" "../../../source/blender/blenlib/intern/gsqueue.c" "../../../source/blender/blenlib/intern/rct.c" diff --git a/intern/ghost/test/gears/GHOST_C-Test.c b/intern/ghost/test/gears/GHOST_C-Test.c index c635ab9be5b..abaa6258122 100644 --- a/intern/ghost/test/gears/GHOST_C-Test.c +++ b/intern/ghost/test/gears/GHOST_C-Test.c @@ -84,16 +84,16 @@ static void gearGL(GLfloat inner_radius, GLfloat outer_radius, GLfloat width, GL GLfloat angle, da; GLfloat u, v, len; const double pi = 3.14159264; - + r0 = inner_radius; r1 = (float)(outer_radius - tooth_depth / 2.0); r2 = (float)(outer_radius + tooth_depth / 2.0); - + da = (float)(2.0 * pi / teeth / 4.0); - + glShadeModel(GL_FLAT); glNormal3f(0.0, 0.0, 1.0); - + /* draw front face */ glBegin(GL_QUAD_STRIP); for (i = 0; i <= teeth; i++) { @@ -104,7 +104,7 @@ static void gearGL(GLfloat inner_radius, GLfloat outer_radius, GLfloat width, GL glVertex3f((float)(r1 * cos(angle + 3 * da)), (float)(r1 * sin(angle + 3 * da)), (float)(width * 0.5)); } glEnd(); - + /* draw front sides of teeth */ glBegin(GL_QUADS); da = (float)(2.0 * pi / teeth / 4.0); @@ -116,9 +116,9 @@ static void gearGL(GLfloat inner_radius, GLfloat outer_radius, GLfloat width, GL glVertex3f((float)(r1 * cos(angle + 3 * da)), (float)(r1 * sin(angle + 3 * da)), (float)(width * 0.5)); } glEnd(); - + glNormal3f(0.0, 0.0, -1.0); - + /* draw back face */ glBegin(GL_QUAD_STRIP); for (i = 0; i <= teeth; i++) { @@ -129,7 +129,7 @@ static void gearGL(GLfloat inner_radius, GLfloat outer_radius, GLfloat width, GL glVertex3f((float)(r0 * cos(angle)), (float)(r0 * sin(angle)), (float)(-width * 0.5)); } glEnd(); - + /* draw back sides of teeth */ glBegin(GL_QUADS); da = (float)(2.0 * pi / teeth / 4.0); @@ -141,7 +141,7 @@ static void gearGL(GLfloat inner_radius, GLfloat outer_radius, GLfloat width, GL glVertex3f((float)(r1 * cos(angle)), (float)(r1 * sin(angle)), (float)(-width * 0.5)); } glEnd(); - + /* draw outward faces of teeth */ glBegin(GL_QUAD_STRIP); for (i = 0; i < teeth; i++) { @@ -169,9 +169,9 @@ static void gearGL(GLfloat inner_radius, GLfloat outer_radius, GLfloat width, GL glVertex3f((float)(r1 * cos(0.0)), (float)(r1 * sin(0.0)), (float)(width * 0.5)); glVertex3f((float)(r1 * cos(0.0)), (float)(r1 * sin(0.0)), (float)(-width * 0.5)); glEnd(); - + glShadeModel(GL_SMOOTH); - + /* draw inside radius cylinder */ glBegin(GL_QUAD_STRIP); for (i = 0; i <= teeth; i++) { @@ -191,13 +191,13 @@ static void drawGearGL(int id) static GLfloat ared[4] = { 0.8f, 0.1f, 0.0f, 1.0f }; static GLfloat agreen[4] = { 0.0f, 0.8f, 0.2f, 1.0f }; static GLfloat ablue[4] = { 0.2f, 0.2f, 1.0f, 1.0f }; - + glLightfv(GL_LIGHT0, GL_POSITION, pos); glEnable(GL_CULL_FACE); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glEnable(GL_DEPTH_TEST); - + switch (id) { case 1: @@ -222,32 +222,32 @@ static void drawGearGL(int id) static void drawGL(void) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - + glPushMatrix(); - + glRotatef(view_rotx, 1.0, 0.0, 0.0); glRotatef(view_roty, 0.0, 1.0, 0.0); glRotatef(view_rotz, 0.0, 0.0, 1.0); - + glPushMatrix(); glTranslatef(-3.0, -2.0, 0.0); glRotatef(fAngle, 0.0, 0.0, 1.0); drawGearGL(1); glPopMatrix(); - + glPushMatrix(); glTranslatef(3.1f, -2.0f, 0.0f); glRotatef((float)(-2.0 * fAngle - 9.0), 0.0, 0.0, 1.0); drawGearGL(2); glPopMatrix(); - + glPushMatrix(); glTranslatef(-3.1f, 2.2f, -1.8f); glRotatef(90.0f, 1.0f, 0.0f, 0.0f); glRotatef((float)(2.0 * fAngle - 2.0), 0.0, 0.0, 1.0); drawGearGL(3); glPopMatrix(); - + glPopMatrix(); } @@ -256,13 +256,13 @@ static void setViewPortGL(GHOST_WindowHandle hWindow) { GHOST_RectangleHandle hRect = NULL; GLfloat w, h; - + GHOST_ActivateWindowDrawingContext(hWindow); hRect = GHOST_GetClientBounds(hWindow); - + w = (float)GHOST_GetWidthRectangle(hRect) / (float)GHOST_GetHeightRectangle(hRect); h = 1.0; - + glViewport(0, 0, GHOST_GetWidthRectangle(hRect), GHOST_GetHeightRectangle(hRect)); glMatrixMode(GL_PROJECTION); @@ -272,7 +272,7 @@ static void setViewPortGL(GHOST_WindowHandle hWindow) glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glTranslatef(0.0, 0.0, -40.0); - + glClearColor(.2f, 0.0f, 0.0f, 0.0f); glClear(GL_COLOR_BUFFER_BIT); @@ -290,7 +290,7 @@ int processEvent(GHOST_EventHandle hEvent, GHOST_TUserDataPtr userData) GHOST_TEventWheelData *wheelData = NULL; GHOST_DisplaySetting setting; GHOST_WindowHandle window = GHOST_GetEventWindow(hEvent); - + switch (GHOST_GetEventType(hEvent)) { #if 0 @@ -316,7 +316,7 @@ int processEvent(GHOST_EventHandle hEvent, GHOST_TUserDataPtr userData) case GHOST_kEventKeyUp: break; - + case GHOST_kEventKeyDown: { keyData = (GHOST_TEventKeyData *)GHOST_GetEventData(hEvent); @@ -391,7 +391,7 @@ int processEvent(GHOST_EventHandle hEvent, GHOST_TUserDataPtr userData) sprintf(ntitle, "%s-", title); GHOST_SetTitle(sMainWindow, ntitle); - + free(ntitle); free(title); } @@ -402,7 +402,7 @@ int processEvent(GHOST_EventHandle hEvent, GHOST_TUserDataPtr userData) } } break; - + case GHOST_kEventWindowClose: { GHOST_WindowHandle window2 = GHOST_GetEventWindow(hEvent); @@ -420,7 +420,7 @@ int processEvent(GHOST_EventHandle hEvent, GHOST_TUserDataPtr userData) } } break; - + case GHOST_kEventWindowActivate: handled = 0; break; @@ -437,7 +437,7 @@ int processEvent(GHOST_EventHandle hEvent, GHOST_TUserDataPtr userData) GHOST_SwapWindowBuffers(window2); } break; - + default: handled = 0; break; @@ -456,7 +456,7 @@ int main(int argc, char **argv) /* Create the system */ shSystem = GHOST_CreateSystem(); GHOST_AddEventConsumer(shSystem, consumer); - + if (shSystem) { /* Create the main window */ @@ -471,7 +471,7 @@ int main(int argc, char **argv) printf("could not create main window\n"); exit(-1); } - + /* Create a secondary window */ sSecondaryWindow = GHOST_CreateWindow( shSystem, @@ -485,7 +485,7 @@ int main(int argc, char **argv) printf("could not create secondary window\n"); exit(-1); } - + /* Install a timer to have the gears running */ sGearsTimer = GHOST_InstallTimer(shSystem, 0, @@ -496,7 +496,7 @@ int main(int argc, char **argv) /* Enter main loop */ while (!sExitRequested) { - if (!GHOST_ProcessEvents(shSystem, 0)) + if (!GHOST_ProcessEvents(shSystem, 0)) { #ifdef WIN32 /* If there were no events, be nice to other applications */ @@ -519,7 +519,7 @@ int main(int argc, char **argv) /* Dispose the system */ GHOST_DisposeSystem(shSystem); - + return 0; } diff --git a/intern/ghost/test/gears/GHOST_Test.cpp b/intern/ghost/test/gears/GHOST_Test.cpp index f58a220055f..8c4d93fcbc4 100644 --- a/intern/ghost/test/gears/GHOST_Test.cpp +++ b/intern/ghost/test/gears/GHOST_Test.cpp @@ -273,7 +273,7 @@ static void View(GHOST_IWindow *window, bool stereo, int eye = 0) if (stereo) { if (nVidiaWindows) - { + { // handled by nVidia driver so act as normal (explicitly put here since // it -is- stereo) glViewport(0, 0, bnds.getWidth(), bnds.getHeight()); @@ -666,7 +666,7 @@ bool Application::processEvent(GHOST_IEvent *event) window2->swapBuffers(); } break; - + default: handled = false; break; diff --git a/intern/ghost/test/multitest/Basic.h b/intern/ghost/test/multitest/Basic.h index c8f61d40c57..86d68ef06cb 100644 --- a/intern/ghost/test/multitest/Basic.h +++ b/intern/ghost/test/multitest/Basic.h @@ -28,11 +28,11 @@ int min_i (int a, int b); int max_i (int a, int b); -int clamp_i (int val, int min, int max); +int clamp_i (int val, int min, int max); -float min_f (float a, float b); -float max_f (float a, float b); -float clamp_f (float val, float min, float max); +float min_f (float a, float b); +float max_f (float a, float b); +float clamp_f (float val, float min, float max); void rect_copy (int dst[2][2], int src[2][2]); int rect_contains_pt (int rect[2][2], int pt[2]); diff --git a/intern/ghost/test/multitest/EventToBuf.c b/intern/ghost/test/multitest/EventToBuf.c index 49255de5e64..7401ab83dbf 100644 --- a/intern/ghost/test/multitest/EventToBuf.c +++ b/intern/ghost/test/multitest/EventToBuf.c @@ -47,7 +47,7 @@ char *eventtype_to_string(GHOST_TEventType type) case GHOST_kEventQuit: return "Quit"; case GHOST_kEventWindowClose: return "WindowClose"; - case GHOST_kEventWindowActivate: return "WindowActivate"; + case GHOST_kEventWindowActivate: return "WindowActivate"; case GHOST_kEventWindowDeactivate: return "WindowDeactivate"; case GHOST_kEventWindowUpdate: return "WindowUpdate"; case GHOST_kEventWindowSize: return "WindowSize"; @@ -188,7 +188,7 @@ static char *keytype_to_string(GHOST_TKey key) K(KeyF22); K(KeyF23); K(KeyF24); - + default: return "KeyUnknown"; } diff --git a/intern/ghost/test/multitest/MultiTest.c b/intern/ghost/test/multitest/MultiTest.c index 833b5c720a1..8cd31c3137e 100644 --- a/intern/ghost/test/multitest/MultiTest.c +++ b/intern/ghost/test/multitest/MultiTest.c @@ -79,7 +79,7 @@ void rect_bevel_side(int rect[2][2], int side, float *lt, float *dk, const float int ltidx = (side / 2) % 4; int dkidx = (ltidx + 1 + (side & 1)) % 4; int i, corner; - + glBegin(GL_LINES); for (i = 0; i < width; i++) { float ltf = pow(lt[i], 1.0 / 2.2), dkf = pow(dk[i], 1.0 / 2.2); @@ -102,7 +102,7 @@ void rect_bevel_side(int rect[2][2], int side, float *lt, float *dk, const float } } glEnd(); - + glColor3fv(col); glRecti(rect[0][0] + width, rect[0][1] + width, rect[1][0] - width, rect[1][1] - width); } @@ -113,17 +113,17 @@ void rect_bevel_smooth(int rect[2][2], int width) float *dk = malloc(sizeof(*dk) * width); float col[4]; int i; - + for (i = 0; i < width; i++) { float v = width - 1 ? ((float) i / (width - 1)) : 0; lt[i] = 1.2 + (1.0 - 1.2) * v; dk[i] = 0.2 + (1.0 - 0.2) * v; } - + glGetFloatv(GL_CURRENT_COLOR, col); - + rect_bevel_side(rect, 3, lt, dk, col, width); - + free(lt); free(dk); } @@ -136,11 +136,11 @@ typedef struct { MultiTestApp *app; GHOST_WindowHandle win; - + int size[2]; - + int lmouse[2], lmbut[3]; - + int tmouse[2]; } MainWindow; @@ -152,18 +152,18 @@ static void mainwindow_log(MainWindow *mw, char *str) static void mainwindow_do_draw(MainWindow *mw) { GHOST_ActivateWindowDrawingContext(mw->win); - + if (mw->lmbut[0]) { glClearColor(0.5, 0.5, 0.5, 1); } else { glClearColor(1, 1, 1, 1); - } + } glClear(GL_COLOR_BUFFER_BIT); - + glColor3f(0.5, 0.6, 0.8); glRecti(mw->tmouse[0] - 5, mw->tmouse[1] - 5, mw->tmouse[0] + 5, mw->tmouse[1] + 5); - + GHOST_SwapWindowBuffers(mw->win); } @@ -175,7 +175,7 @@ static void mainwindow_do_reshape(MainWindow *mw) mw->size[0] = GHOST_GetWidthRectangle(bounds); mw->size[1] = GHOST_GetHeightRectangle(bounds); - + glViewport(0, 0, mw->size[0], mw->size[1]); glMatrixMode(GL_PROJECTION); @@ -234,7 +234,7 @@ static void mainwindow_do_key(MainWindow *mw, GHOST_TKey key, int press) static void mainwindow_do_move(MainWindow *mw, int x, int y) { mw->lmouse[0] = x, mw->lmouse[1] = y; - + if (mw->lmbut[0]) { mw->tmouse[0] = x, mw->tmouse[1] = y; GHOST_InvalidateWindow(mw->win); @@ -261,10 +261,10 @@ static void mainwindow_handle(void *priv, GHOST_EventHandle evt) MainWindow *mw = priv; GHOST_TEventType type = GHOST_GetEventType(evt); char buf[256]; - + event_to_buf(evt, buf); mainwindow_log(mw, buf); - + switch (type) { case GHOST_kEventCursorMove: { @@ -304,7 +304,7 @@ static void mainwindow_timer_proc(GHOST_TimerTaskHandle task, GHOST_TUns64 time) { MainWindow *mw = GHOST_GetTimerTaskUserData(task); char buf[64]; - + sprintf(buf, "timer: %6.2f", (double) ((GHOST_TInt64) time) / 1000); mainwindow_log(mw, buf); } @@ -314,23 +314,23 @@ MainWindow *mainwindow_new(MultiTestApp *app) GHOST_SystemHandle sys = multitestapp_get_system(app); GHOST_WindowHandle win; GHOST_GLSettings glSettings = {0}; - + win = GHOST_CreateWindow( sys, "MultiTest:Main", 40, 40, 400, 400, GHOST_kWindowStateNormal, GHOST_kDrawingContextTypeOpenGL, glSettings); - + if (win) { MainWindow *mw = MEM_callocN(sizeof(*mw), "mainwindow_new"); mw->app = app; mw->win = win; - + GHOST_SetWindowUserData(mw->win, windowdata_new(mw, mainwindow_handle)); - + GHOST_InstallTimer(sys, 1000, 10000, mainwindow_timer_proc, mw); - + return mw; } else { @@ -356,23 +356,23 @@ struct _LoggerWindow { GHOST_WindowHandle win; -#ifdef USE_BMF +#ifdef USE_BMF BMF_Font *font; #else int font; #endif int fonttexid; int fontheight; - + int size[2]; - + int ndisplines; int textarea[2][2]; ScrollBar *scroll; - + char **loglines; int nloglines, logsize; - + int lmbut[3]; int lmouse[2]; }; @@ -383,7 +383,7 @@ struct _LoggerWindow { static void loggerwindow_recalc_regions(LoggerWindow *lw) { int nscroll[2][2]; - + nscroll[0][0] = SCROLLBAR_PAD; nscroll[0][1] = SCROLLBAR_PAD; nscroll[1][0] = nscroll[0][0] + SCROLLBAR_WIDTH; @@ -418,10 +418,10 @@ static void loggerwindow_do_reshape(LoggerWindow *lw) GHOST_RectangleHandle bounds = GHOST_GetClientBounds(lw->win); GHOST_ActivateWindowDrawingContext(lw->win); - + lw->size[0] = GHOST_GetWidthRectangle(bounds); lw->size[1] = GHOST_GetHeightRectangle(bounds); - + loggerwindow_recalc_regions(lw); loggerwindow_setup_window_gl(lw); } @@ -430,21 +430,21 @@ static void loggerwindow_do_draw(LoggerWindow *lw) { int i, ndisplines, startline; int sb_rect[2][2], sb_thumb[2][2]; - + GHOST_ActivateWindowDrawingContext(lw->win); - + glClearColor(1, 1, 1, 1); glClear(GL_COLOR_BUFFER_BIT); glColor3f(0.8, 0.8, 0.8); rect_bevel_smooth(lw->textarea, 4); - + scrollbar_get_rect(lw->scroll, sb_rect); scrollbar_get_thumb(lw->scroll, sb_thumb); - + glColor3f(0.6, 0.6, 0.6); rect_bevel_smooth(sb_rect, 1); - + if (scrollbar_is_scrolling(lw->scroll)) { glColor3f(0.6, 0.7, 0.5); } @@ -452,16 +452,16 @@ static void loggerwindow_do_draw(LoggerWindow *lw) glColor3f(0.9, 0.9, 0.92); } rect_bevel_smooth(sb_thumb, 1); - + startline = scrollbar_get_thumbpos(lw->scroll) * (lw->nloglines - 1); ndisplines = min_i(lw->ndisplines, lw->nloglines - startline); if (lw->fonttexid != -1) { glBindTexture(GL_TEXTURE_2D, lw->fonttexid); - + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_BLEND); - glEnable(GL_TEXTURE_2D); + glEnable(GL_TEXTURE_2D); } glColor3f(0, 0, 0); for (i = 0; i < ndisplines; i++) { @@ -470,7 +470,7 @@ static void loggerwindow_do_draw(LoggerWindow *lw) int x_pos = lw->textarea[0][0] + 4; int y_pos = lw->textarea[0][1] + 4 + i * lw->fontheight; -#ifdef USE_BMF +#ifdef USE_BMF if (lw->fonttexid == -1) { glRasterPos2i(x_pos, y_pos); BMF_DrawString(lw->font, line); @@ -486,7 +486,7 @@ static void loggerwindow_do_draw(LoggerWindow *lw) #ifdef USE_BMF if (lw->fonttexid != -1) { - glDisable(GL_TEXTURE_2D); + glDisable(GL_TEXTURE_2D); glDisable(GL_BLEND); } #endif @@ -497,7 +497,7 @@ static void loggerwindow_do_draw(LoggerWindow *lw) static void loggerwindow_do_move(LoggerWindow *lw, int x, int y) { lw->lmouse[0] = x, lw->lmouse[1] = y; - + if (scrollbar_is_scrolling(lw->scroll)) { scrollbar_keep_scrolling(lw->scroll, y); GHOST_InvalidateWindow(lw->win); @@ -508,10 +508,10 @@ static void loggerwindow_do_button(LoggerWindow *lw, int which, int press) { if (which == GHOST_kButtonMaskLeft) { lw->lmbut[0] = press; - + if (press) { if (scrollbar_contains_pt(lw->scroll, lw->lmouse)) { - scrollbar_start_scrolling(lw->scroll, lw->lmouse[1]); + scrollbar_start_scrolling(lw->scroll, lw->lmouse[1]); GHOST_SetCursorShape(lw->win, GHOST_kStandardCursorUpDown); GHOST_InvalidateWindow(lw->win); } @@ -546,7 +546,7 @@ static void loggerwindow_handle(void *priv, GHOST_EventHandle evt) { LoggerWindow *lw = priv; GHOST_TEventType type = GHOST_GetEventType(evt); - + switch (type) { case GHOST_kEventCursorMove: { @@ -588,7 +588,7 @@ LoggerWindow *loggerwindow_new(MultiTestApp *app) GHOST_SystemHandle sys = multitestapp_get_system(app); GHOST_TUns32 screensize[2]; GHOST_WindowHandle win; - + GHOST_GetMainDisplayDimensions(sys, &screensize[0], &screensize[1]); win = GHOST_CreateWindow( sys, "MultiTest:Logger", @@ -596,7 +596,7 @@ LoggerWindow *loggerwindow_new(MultiTestApp *app) GHOST_kWindowStateNormal, GHOST_kDrawingContextTypeOpenGL, glSettings); - + if (win) { LoggerWindow *lw = MEM_callocN(sizeof(*lw), "loggerwindow_new"); int bbox[2][2]; @@ -614,12 +614,12 @@ LoggerWindow *loggerwindow_new(MultiTestApp *app) BLF_size(lw->font, 11, 72); lw->fontheight = BLF_height(lw->font, "A_", 2); #endif - + lw->nloglines = lw->logsize = 0; lw->loglines = MEM_mallocN(sizeof(*lw->loglines) * lw->nloglines, "loglines"); - + lw->scroll = scrollbar_new(2, 40); - + GHOST_SetWindowUserData(lw->win, windowdata_new(lw, loggerwindow_handle)); loggerwindow_do_reshape(lw); @@ -636,10 +636,10 @@ void loggerwindow_log(LoggerWindow *lw, char *line) if (lw->nloglines == lw->logsize) { lw->loglines = memdbl(lw->loglines, &lw->logsize, sizeof(*lw->loglines)); } - + lw->loglines[lw->nloglines++] = string_dup(line); scrollbar_set_thumbpct(lw->scroll, (float) lw->ndisplines / lw->nloglines); - + GHOST_InvalidateWindow(lw->win); } @@ -652,7 +652,7 @@ void loggerwindow_free(LoggerWindow *lw) MEM_freeN(lw->loglines[i]); } MEM_freeN(lw->loglines); - + windowdata_free(GHOST_GetWindowUserData(lw->win)); GHOST_DisposeWindow(sys, lw->win); MEM_freeN(lw); @@ -667,7 +667,7 @@ typedef struct { MultiTestApp *app; GHOST_WindowHandle win; - + int size[2]; } ExtraWindow; @@ -677,10 +677,10 @@ static void extrawindow_do_draw(ExtraWindow *ew) glClearColor(1, 1, 1, 1); glClear(GL_COLOR_BUFFER_BIT); - + glColor3f(0.8, 0.8, 0.8); glRecti(10, 10, ew->size[0] - 10, ew->size[1] - 10); - + GHOST_SwapWindowBuffers(ew->win); } @@ -692,7 +692,7 @@ static void extrawindow_do_reshape(ExtraWindow *ew) ew->size[0] = GHOST_GetWidthRectangle(bounds); ew->size[1] = GHOST_GetHeightRectangle(bounds); - + glViewport(0, 0, ew->size[0], ew->size[1]); glMatrixMode(GL_PROJECTION); @@ -721,15 +721,15 @@ static void extrawindow_spin_cursor(ExtraWindow *ew, GHOST_TUns64 time) double ftime = (double) ((GHOST_TInt64) time) / 1000; float angle = fmod(ftime, 1.0) * 3.1415 * 2; int i; - + memset(&bitmap, 0, sizeof(bitmap)); memset(&mask, 0, sizeof(mask)); - + bitmap[0][0] |= mask[0][0] |= 0xF; bitmap[1][0] |= mask[1][0] |= 0xF; bitmap[2][0] |= mask[2][0] |= 0xF; bitmap[3][0] |= mask[3][0] |= 0xF; - + for (i = 0; i < 7; i++) { int x = 7 + cos(angle) * i; int y = 7 + sin(angle) * i; @@ -740,10 +740,10 @@ static void extrawindow_spin_cursor(ExtraWindow *ew, GHOST_TUns64 time) float v = (i / 63.0) * 3.1415 * 2; int x = 7 + cos(v) * 7; int y = 7 + sin(v) * 7; - + mask[y][x / 8] |= (1 << (x % 8)); } - + GHOST_SetCustomCursorShape(ew->win, bitmap, mask, 0, 0); } @@ -752,10 +752,10 @@ static void extrawindow_handle(void *priv, GHOST_EventHandle evt) ExtraWindow *ew = priv; GHOST_TEventType type = GHOST_GetEventType(evt); char buf[256]; - + event_to_buf(evt, buf); loggerwindow_log(multitestapp_get_logger(ew->app), buf); - + switch (type) { case GHOST_kEventKeyDown: case GHOST_kEventKeyUp: @@ -790,21 +790,21 @@ ExtraWindow *extrawindow_new(MultiTestApp *app) GHOST_GLSettings glSettings = {0}; GHOST_SystemHandle sys = multitestapp_get_system(app); GHOST_WindowHandle win; - + win = GHOST_CreateWindow( sys, "MultiTest:Extra", 500, 40, 400, 400, GHOST_kWindowStateNormal, GHOST_kDrawingContextTypeOpenGL, glSettings); - + if (win) { ExtraWindow *ew = MEM_callocN(sizeof(*ew), "mainwindow_new"); ew->app = app; ew->win = win; - + GHOST_SetWindowUserData(ew->win, windowdata_new(ew, extrawindow_handle)); - + return ew; } else { @@ -824,13 +824,13 @@ void extrawindow_free(ExtraWindow *ew) /* * MultiTestApp */ - + struct _MultiTestApp { GHOST_SystemHandle sys; MainWindow *main; LoggerWindow *logger; ExtraWindow *extra; - + int exit; }; @@ -838,21 +838,21 @@ static int multitest_event_handler(GHOST_EventHandle evt, GHOST_TUserDataPtr dat { MultiTestApp *app = data; GHOST_WindowHandle win; - + win = GHOST_GetEventWindow(evt); if (win && !GHOST_ValidWindow(app->sys, win)) { loggerwindow_log(app->logger, "WARNING: bad event, non-valid window\n"); return 1; } - + if (win) { WindowData *wb = GHOST_GetWindowUserData(win); - + windowdata_handle(wb, evt); } else { GHOST_TEventType type = GHOST_GetEventType(evt); - + /* GHOST_kEventQuit are the only 'system' events, * that is, events without a window. */ @@ -866,7 +866,7 @@ static int multitest_event_handler(GHOST_EventHandle evt, GHOST_TUserDataPtr dat break; } } - + return 1; } @@ -880,25 +880,25 @@ MultiTestApp *multitestapp_new(void) { if (!app->sys) fatal("Unable to create ghost system"); - if (!GHOST_AddEventConsumer(app->sys, consumer)) + if (!GHOST_AddEventConsumer(app->sys, consumer)) fatal("Unable to add multitest event consumer "); - + app->main = mainwindow_new(app); - if (!app->main) + if (!app->main) fatal("Unable to create main window"); - + app->logger = loggerwindow_new(app); if (!app->logger) fatal("Unable to create logger window"); app->extra = NULL; app->exit = 0; - + return app; } LoggerWindow *multitestapp_get_logger(MultiTestApp *app) { - return app->logger; + return app->logger; } GHOST_SystemHandle multitestapp_get_system(MultiTestApp *app) { @@ -943,7 +943,7 @@ void multitestapp_free(MultiTestApp *app) } /***/ - + int main(int argc, char **argv) { MultiTestApp *app; @@ -953,9 +953,9 @@ int main(int argc, char **argv) #endif app = multitestapp_new(); - + multitestapp_run(app); multitestapp_free(app); - + return 0; } diff --git a/intern/ghost/test/multitest/ScrollBar.c b/intern/ghost/test/multitest/ScrollBar.c index 8964d304920..2a363f3ce5d 100644 --- a/intern/ghost/test/multitest/ScrollBar.c +++ b/intern/ghost/test/multitest/ScrollBar.c @@ -37,7 +37,7 @@ struct _ScrollBar { int rect[2][2]; float thumbpos, thumbpct; - + int inset; int minthumb; @@ -48,7 +48,7 @@ struct _ScrollBar { static int scrollbar_get_thumbH(ScrollBar *sb) { int scrollable_h = rect_height(sb->rect) - 2 * sb->inset; - + return clamp_i(sb->thumbpct * scrollable_h, sb->minthumb, scrollable_h); } @@ -56,7 +56,7 @@ static int scrollbar_get_thumbableH(ScrollBar *sb) { int scrollable_h = rect_height(sb->rect) - 2 * sb->inset; int thumb_h = scrollbar_get_thumbH(sb); - + return scrollable_h - thumb_h; } @@ -76,7 +76,7 @@ ScrollBar *scrollbar_new(int inset, int minthumb) ScrollBar *sb = MEM_callocN(sizeof(*sb), "scrollbar_new"); sb->inset = inset; sb->minthumb = minthumb; - + return sb; } diff --git a/intern/ghost/test/multitest/ScrollBar.h b/intern/ghost/test/multitest/ScrollBar.h index 8c8d02d197e..dd737539bf2 100644 --- a/intern/ghost/test/multitest/ScrollBar.h +++ b/intern/ghost/test/multitest/ScrollBar.h @@ -29,7 +29,7 @@ typedef struct _ScrollBar ScrollBar; /***/ - + ScrollBar* scrollbar_new (int inset, int minthumb); int scrollbar_is_scrolling (ScrollBar *sb); diff --git a/intern/ghost/test/multitest/Util.c b/intern/ghost/test/multitest/Util.c index bacd0a313d4..9ac7ae0263d 100644 --- a/intern/ghost/test/multitest/Util.c +++ b/intern/ghost/test/multitest/Util.c @@ -40,10 +40,10 @@ void *memdbl(void *mem, int *size_pr, int item_size) int cur_size = *size_pr; int new_size = cur_size ? (cur_size * 2) : 1; void *nmem = MEM_mallocN(new_size * item_size, "memdbl"); - + memcpy(nmem, mem, cur_size * item_size); MEM_freeN(mem); - + *size_pr = new_size; return nmem; } @@ -54,19 +54,19 @@ char *string_dup(char *str) char *nstr = MEM_mallocN(len + 1, "string_dup"); memcpy(nstr, str, len + 1); - + return nstr; } void fatal(char *fmt, ...) { va_list ap; - + fprintf(stderr, "FATAL: "); va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap); fprintf(stderr, "\n"); - + exit(1); } diff --git a/intern/ghost/test/multitest/WindowData.c b/intern/ghost/test/multitest/WindowData.c index de4992ab2a0..07078cd9238 100644 --- a/intern/ghost/test/multitest/WindowData.c +++ b/intern/ghost/test/multitest/WindowData.c @@ -43,7 +43,7 @@ WindowData *windowdata_new(void *data, WindowDataHandler handler) WindowData *wb = MEM_mallocN(sizeof(*wb), "windowdata_new"); wb->data = data; wb->handler = handler; - + return wb; } diff --git a/intern/ghost/test/multitest/WindowData.h b/intern/ghost/test/multitest/WindowData.h index f8198101b8d..0e6c7518843 100644 --- a/intern/ghost/test/multitest/WindowData.h +++ b/intern/ghost/test/multitest/WindowData.h @@ -27,9 +27,9 @@ typedef void (*WindowDataHandler)(void *priv, GHOST_EventHandle evt); typedef struct _WindowData WindowData; - + /***/ - + WindowData* windowdata_new (void *data, WindowDataHandler handler); void windowdata_handle (WindowData *wb, GHOST_EventHandle evt); void windowdata_free (WindowData *wb); diff --git a/release/datafiles/studiolights/matcap/license.txt b/release/datafiles/studiolights/matcap/license.txt new file mode 100644 index 00000000000..358c8dcd832 --- /dev/null +++ b/release/datafiles/studiolights/matcap/license.txt @@ -0,0 +1,3 @@ +These matcap images are licensed as GNU GPL 2 or later, like the rest of Blender's code. + +Thanks to Kent Trammell, Aidy Burrows, John Herreno , Terry Wallwork and David Silverman for making the pictures. diff --git a/release/datafiles/studiolights/matcap/mc01.jpg b/release/datafiles/studiolights/matcap/mc01.jpg Binary files differnew file mode 100644 index 00000000000..8c7aef287ee --- /dev/null +++ b/release/datafiles/studiolights/matcap/mc01.jpg diff --git a/release/datafiles/studiolights/matcap/mc02.jpg b/release/datafiles/studiolights/matcap/mc02.jpg Binary files differnew file mode 100644 index 00000000000..11deddfeaed --- /dev/null +++ b/release/datafiles/studiolights/matcap/mc02.jpg diff --git a/release/datafiles/studiolights/matcap/mc03.jpg b/release/datafiles/studiolights/matcap/mc03.jpg Binary files differnew file mode 100644 index 00000000000..64d992fb61a --- /dev/null +++ b/release/datafiles/studiolights/matcap/mc03.jpg diff --git a/release/datafiles/studiolights/matcap/mc04.jpg b/release/datafiles/studiolights/matcap/mc04.jpg Binary files differnew file mode 100644 index 00000000000..42be580ee93 --- /dev/null +++ b/release/datafiles/studiolights/matcap/mc04.jpg diff --git a/release/datafiles/studiolights/matcap/mc05.jpg b/release/datafiles/studiolights/matcap/mc05.jpg Binary files differnew file mode 100644 index 00000000000..586d233ef31 --- /dev/null +++ b/release/datafiles/studiolights/matcap/mc05.jpg diff --git a/release/datafiles/studiolights/matcap/mc06.jpg b/release/datafiles/studiolights/matcap/mc06.jpg Binary files differnew file mode 100644 index 00000000000..657883d0866 --- /dev/null +++ b/release/datafiles/studiolights/matcap/mc06.jpg diff --git a/release/datafiles/studiolights/matcap/mc07.jpg b/release/datafiles/studiolights/matcap/mc07.jpg Binary files differnew file mode 100644 index 00000000000..372caf7e87c --- /dev/null +++ b/release/datafiles/studiolights/matcap/mc07.jpg diff --git a/release/datafiles/studiolights/matcap/mc08.jpg b/release/datafiles/studiolights/matcap/mc08.jpg Binary files differnew file mode 100644 index 00000000000..50eec402812 --- /dev/null +++ b/release/datafiles/studiolights/matcap/mc08.jpg diff --git a/release/datafiles/studiolights/matcap/mc09.jpg b/release/datafiles/studiolights/matcap/mc09.jpg Binary files differnew file mode 100644 index 00000000000..e05d441aaf9 --- /dev/null +++ b/release/datafiles/studiolights/matcap/mc09.jpg diff --git a/release/datafiles/studiolights/matcap/mc10.jpg b/release/datafiles/studiolights/matcap/mc10.jpg Binary files differnew file mode 100644 index 00000000000..ab82f17bb93 --- /dev/null +++ b/release/datafiles/studiolights/matcap/mc10.jpg diff --git a/release/datafiles/studiolights/matcap/mc11.jpg b/release/datafiles/studiolights/matcap/mc11.jpg Binary files differnew file mode 100644 index 00000000000..053550f082c --- /dev/null +++ b/release/datafiles/studiolights/matcap/mc11.jpg diff --git a/release/datafiles/studiolights/matcap/mc12.jpg b/release/datafiles/studiolights/matcap/mc12.jpg Binary files differnew file mode 100644 index 00000000000..beb16f3742e --- /dev/null +++ b/release/datafiles/studiolights/matcap/mc12.jpg diff --git a/release/datafiles/studiolights/matcap/mc13.jpg b/release/datafiles/studiolights/matcap/mc13.jpg Binary files differnew file mode 100644 index 00000000000..7fb8fa58e8f --- /dev/null +++ b/release/datafiles/studiolights/matcap/mc13.jpg diff --git a/release/datafiles/studiolights/matcap/mc14.jpg b/release/datafiles/studiolights/matcap/mc14.jpg Binary files differnew file mode 100644 index 00000000000..ba868d2f95a --- /dev/null +++ b/release/datafiles/studiolights/matcap/mc14.jpg diff --git a/release/datafiles/studiolights/matcap/mc15.jpg b/release/datafiles/studiolights/matcap/mc15.jpg Binary files differnew file mode 100644 index 00000000000..b10ea326a42 --- /dev/null +++ b/release/datafiles/studiolights/matcap/mc15.jpg diff --git a/release/datafiles/studiolights/matcap/mc16.jpg b/release/datafiles/studiolights/matcap/mc16.jpg Binary files differnew file mode 100644 index 00000000000..c6ce02d59df --- /dev/null +++ b/release/datafiles/studiolights/matcap/mc16.jpg diff --git a/release/datafiles/studiolights/matcap/mc17.jpg b/release/datafiles/studiolights/matcap/mc17.jpg Binary files differnew file mode 100644 index 00000000000..14f15f70460 --- /dev/null +++ b/release/datafiles/studiolights/matcap/mc17.jpg diff --git a/release/datafiles/studiolights/matcap/mc18.jpg b/release/datafiles/studiolights/matcap/mc18.jpg Binary files differnew file mode 100644 index 00000000000..db572856b07 --- /dev/null +++ b/release/datafiles/studiolights/matcap/mc18.jpg diff --git a/release/datafiles/studiolights/matcap/mc19.jpg b/release/datafiles/studiolights/matcap/mc19.jpg Binary files differnew file mode 100644 index 00000000000..56d2efb1734 --- /dev/null +++ b/release/datafiles/studiolights/matcap/mc19.jpg diff --git a/release/datafiles/studiolights/matcap/mc20.jpg b/release/datafiles/studiolights/matcap/mc20.jpg Binary files differnew file mode 100644 index 00000000000..002a0910dd9 --- /dev/null +++ b/release/datafiles/studiolights/matcap/mc20.jpg diff --git a/release/datafiles/studiolights/matcap/mc21.jpg b/release/datafiles/studiolights/matcap/mc21.jpg Binary files differnew file mode 100644 index 00000000000..cb2fea573b8 --- /dev/null +++ b/release/datafiles/studiolights/matcap/mc21.jpg diff --git a/release/datafiles/studiolights/matcap/mc22.jpg b/release/datafiles/studiolights/matcap/mc22.jpg Binary files differnew file mode 100644 index 00000000000..2fc71b98c5a --- /dev/null +++ b/release/datafiles/studiolights/matcap/mc22.jpg diff --git a/release/datafiles/studiolights/matcap/mc23.jpg b/release/datafiles/studiolights/matcap/mc23.jpg Binary files differnew file mode 100644 index 00000000000..3793c0fcaa5 --- /dev/null +++ b/release/datafiles/studiolights/matcap/mc23.jpg diff --git a/release/datafiles/studiolights/matcap/mc24.jpg b/release/datafiles/studiolights/matcap/mc24.jpg Binary files differnew file mode 100644 index 00000000000..2a9618d8fe1 --- /dev/null +++ b/release/datafiles/studiolights/matcap/mc24.jpg diff --git a/release/scripts/addons b/release/scripts/addons -Subproject 4b91309b122bcdcddd1854b1137407b2c4f55c7 +Subproject ebd058d7a6438d137522063bb3286c8acc325ca diff --git a/release/scripts/addons_contrib b/release/scripts/addons_contrib -Subproject cd57934bd04c174fc3402888d01a74e6e6653b2 +Subproject 474702157831f1a58bb50f5240ab8b1b02b6ba3 diff --git a/release/scripts/startup/bl_operators/wm.py b/release/scripts/startup/bl_operators/wm.py index ee101bb3cc6..b0a5e19d269 100644 --- a/release/scripts/startup/bl_operators/wm.py +++ b/release/scripts/startup/bl_operators/wm.py @@ -19,13 +19,17 @@ # <pep8 compliant> import bpy -from bpy.types import Operator +from bpy.types import ( + Operator, + OperatorFileListElement +) from bpy.props import ( BoolProperty, EnumProperty, FloatProperty, IntProperty, StringProperty, + CollectionProperty, ) from bpy.app.translations import pgettext_tip as tip_ @@ -2394,12 +2398,126 @@ class WM_OT_toolbar(Operator): def draw_menu(popover, context): layout = popover.layout - cls.draw_cls(layout, context, detect_layout=False) + cls.draw_cls(layout, context, detect_layout=False, scale_y=1.0) wm.popover(draw_menu, keymap=keymap) return {'FINISHED'} +# Studio Light operations +class WM_OT_studiolight_install(Operator): + """Install a user defined studio light""" + bl_idname = "wm.studiolight_install" + bl_label = "Install Custom Studio Light" + + files = CollectionProperty( + name="File Path", + type=OperatorFileListElement, + ) + directory = StringProperty( + subtype='DIR_PATH', + ) + filter_folder = BoolProperty( + name="Filter folders", + default=True, + options={'HIDDEN'}, + ) + filter_glob = StringProperty( + default="*.png;*.jpg;*.hdr;*.exr", + options={'HIDDEN'}, + ) + orientation = EnumProperty( + items=( + ("MATCAP", "MatCap", ""), + ("WORLD", "World", ""), + ("CAMERA", "Camera", ""), + ) + ) + + def execute(self, context): + import traceback + import shutil + import pathlib + userpref = context.user_preferences + + filepaths = [pathlib.Path(self.directory, e.name) for e in self.files] + path_studiolights = bpy.utils.user_resource('DATAFILES') + + if not path_studiolights: + self.report({'ERROR'}, "Failed to get Studio Light path") + return {'CANCELLED'} + + path_studiolights = pathlib.Path(path_studiolights, "studiolights", self.orientation.lower()) + if not path_studiolights.exists(): + try: + path_studiolights.mkdir(parents=True, exist_ok=True) + except: + traceback.print_exc() + + for filepath in filepaths: + shutil.copy(str(filepath), str(path_studiolights)) + userpref.studio_lights_refresh() + + # print message + msg = ( + tip_("StudioLight Installed %r into %r") % + (", ".join(str(x.name) for x in self.files), str(path_studiolights)) + ) + print(msg) + self.report({'INFO'}, msg) + return {'FINISHED'} + + def invoke(self, context, event): + wm = context.window_manager + wm.fileselect_add(self) + return {'RUNNING_MODAL'} + + +class WM_OT_studiolight_uninstall(Operator): + bl_idname = 'wm.studiolight_uninstall' + bl_label = "Uninstall Studio Light" + index = bpy.props.IntProperty() + + def execute(self, context): + import pathlib + userpref = context.user_preferences + for studio_light in userpref.studio_lights: + if studio_light.index == self.index: + path = pathlib.Path(studio_light.path) + if path.exists(): + path.unlink() + userpref.studio_lights_refresh() + return {'FINISHED'} + return {'CANCELLED'} + + +class WM_OT_studiolight_expand(Operator): + bl_idname = "wm.studiolight_expand" + bl_label = "Expand Studio Light" + index = bpy.props.IntProperty() + + def execute(self, context): + userpref = context.user_preferences + for studio_light in userpref.studio_lights: + if studio_light.index == self.index: + studio_light.show_expanded = not studio_light.show_expanded + break + + return {'FINISHED'} + + +class WM_OT_studiolight_userpref_show(Operator): + """Show light user preferences""" + bl_idname = "wm.studiolight_userpref_show" + bl_label = "" + bl_options = {'INTERNAL'} + + def execute(self, context): + context.user_preferences.active_section = 'LIGHTS' + bpy.ops.screen.userpref_show('INVOKE_DEFAULT') + return {'FINISHED'} + + classes = ( BRUSH_OT_active_index_set, WM_OT_addon_disable, @@ -2454,6 +2572,10 @@ classes = ( WM_OT_owner_disable, WM_OT_owner_enable, WM_OT_url_open, + WM_OT_studiolight_expand, + WM_OT_studiolight_install, + WM_OT_studiolight_uninstall, + WM_OT_studiolight_userpref_show, WM_OT_tool_set_by_name, WM_OT_toolbar, ) diff --git a/release/scripts/startup/bl_ui/__init__.py b/release/scripts/startup/bl_ui/__init__.py index b4ec29330c5..1518119eadc 100644 --- a/release/scripts/startup/bl_ui/__init__.py +++ b/release/scripts/startup/bl_ui/__init__.py @@ -89,7 +89,7 @@ _modules = [ "space_userpref", "space_view3d", "space_view3d_toolbar", - ] +] import bpy @@ -168,6 +168,8 @@ def unregister(): # Define a default UIList, when a list does not need any custom drawing... # Keep in sync with its #defined name in UI_interface.h + + class UI_UL_list(bpy.types.UIList): # These are common filtering or ordering operations (same as the default C ones!). @staticmethod diff --git a/release/scripts/startup/bl_ui/properties_constraint.py b/release/scripts/startup/bl_ui/properties_constraint.py index 9b61101778f..b7880e605b3 100644 --- a/release/scripts/startup/bl_ui/properties_constraint.py +++ b/release/scripts/startup/bl_ui/properties_constraint.py @@ -941,6 +941,7 @@ class BONE_PT_constraints(ConstraintButtonsPanel, Panel): for con in context.pose_bone.constraints: self.draw_constraint(context, con) + classes = ( OBJECT_PT_constraints, BONE_PT_constraints, diff --git a/release/scripts/startup/bl_ui/properties_data_curve.py b/release/scripts/startup/bl_ui/properties_data_curve.py index 057a7233206..47c53d6ffb5 100644 --- a/release/scripts/startup/bl_ui/properties_data_curve.py +++ b/release/scripts/startup/bl_ui/properties_data_curve.py @@ -180,6 +180,7 @@ class DATA_PT_geometry_curve(CurveButtonsPanelCurve, Panel): sub.active = curve.taper_object is not None sub.prop(curve, "use_map_taper") + class DATA_PT_geometry_curve_bevel(CurveButtonsPanelCurve, Panel): bl_label = "Bevel" bl_parent_id = "DATA_PT_geometry_curve" @@ -348,6 +349,7 @@ class DATA_PT_font(CurveButtonsPanelText, Panel): row.prop(char, "use_underline", toggle=True) row.prop(char, "use_small_caps", toggle=True) + class DATA_PT_font_transform(CurveButtonsPanelText, Panel): bl_label = "Transform" bl_parent_id = "DATA_PT_font" @@ -404,7 +406,6 @@ class DATA_PT_paragraph_alignment(CurveButtonsPanelText, Panel): layout.row().prop(text, "align_y", expand=True) - class DATA_PT_paragraph_spacing(CurveButtonsPanelText, Panel): bl_parent_id = "DATA_PT_paragraph" bl_label = "Spacing" diff --git a/release/scripts/startup/bl_ui/properties_data_lamp.py b/release/scripts/startup/bl_ui/properties_data_lamp.py index e5dd1bbd771..2727c84e820 100644 --- a/release/scripts/startup/bl_ui/properties_data_lamp.py +++ b/release/scripts/startup/bl_ui/properties_data_lamp.py @@ -182,7 +182,6 @@ class DATA_PT_EEVEE_shadow(DataButtonsPanel, Panel): col.prop(lamp, "shadow_buffer_bleed_bias", text="Bleed Bias") - class DATA_PT_EEVEE_shadow_cascaded_shadow_map(DataButtonsPanel, Panel): bl_label = "Cascaded Shadow Map" bl_parent_id = "DATA_PT_EEVEE_shadow" diff --git a/release/scripts/startup/bl_ui/properties_freestyle.py b/release/scripts/startup/bl_ui/properties_freestyle.py index a9c9d512335..12ecbeb3e6b 100644 --- a/release/scripts/startup/bl_ui/properties_freestyle.py +++ b/release/scripts/startup/bl_ui/properties_freestyle.py @@ -629,7 +629,7 @@ class VIEWLAYER_PT_freestyle_linestyle(ViewLayerFreestyleEditorButtonsPanel, Pan row = layout.row(align=True) row.prop(linestyle, "panel", expand=True) if linestyle.panel == 'STROKES': - ## Chaining + # Chaining layout.prop(linestyle, "use_chaining", text="Chaining:") split = layout.split(align=True) split.active = linestyle.use_chaining @@ -643,7 +643,7 @@ class VIEWLAYER_PT_freestyle_linestyle(ViewLayerFreestyleEditorButtonsPanel, Pan col = split.column() col.prop(linestyle, "use_same_object") - ## Splitting + # Splitting layout.label(text="Splitting:") split = layout.split(align=True) # First column @@ -679,7 +679,7 @@ class VIEWLAYER_PT_freestyle_linestyle(ViewLayerFreestyleEditorButtonsPanel, Pan sub.prop(linestyle, "split_dash3", text="D3") sub.prop(linestyle, "split_gap3", text="G3") - ## Sorting + # Sorting layout.prop(linestyle, "use_sorting", text="Sorting:") col = layout.column() col.active = linestyle.use_sorting @@ -693,7 +693,7 @@ class VIEWLAYER_PT_freestyle_linestyle(ViewLayerFreestyleEditorButtonsPanel, Pan row = col.row(align=True) row.prop(linestyle, "sort_order", expand=True) - ## Selection + # Selection layout.label(text="Selection:") split = layout.split(align=True) # First column @@ -716,12 +716,12 @@ class VIEWLAYER_PT_freestyle_linestyle(ViewLayerFreestyleEditorButtonsPanel, Pan sub.active = linestyle.use_chain_count sub.prop(linestyle, "chain_count") - ## Caps + # Caps layout.label(text="Caps:") row = layout.row(align=True) row.prop(linestyle, "caps", expand=True) - ## Dashed lines + # Dashed lines layout.prop(linestyle, "use_dashed_line", text="Dashed Line:") row = layout.row(align=True) row.active = linestyle.use_dashed_line @@ -786,9 +786,10 @@ class VIEWLAYER_PT_freestyle_linestyle(ViewLayerFreestyleEditorButtonsPanel, Pan row = layout.row() props = row.operator( - "wm.properties_context_change", - text="Go to Linestyle Textures Properties", - icon='TEXTURE') + "wm.properties_context_change", + text="Go to Linestyle Textures Properties", + icon='TEXTURE', + ) props.context = 'TEXTURE' elif linestyle.panel == 'MISC': diff --git a/release/scripts/startup/bl_ui/properties_grease_pencil_common.py b/release/scripts/startup/bl_ui/properties_grease_pencil_common.py index decbbff5d60..a2ccfb4f1b8 100644 --- a/release/scripts/startup/bl_ui/properties_grease_pencil_common.py +++ b/release/scripts/startup/bl_ui/properties_grease_pencil_common.py @@ -242,7 +242,6 @@ class GreasePencilStrokeEditPanel: if is_3d_view: layout.separator() - layout.separator() col = layout.column(align=True) col.operator("gpencil.stroke_subdivide", text="Subdivide") @@ -1100,11 +1099,11 @@ class GreasePencilPaletteColorPanel: row = layout.row() sub = row.row(align=True) - sub.label(text="Isolate:") # based on active color only + sub.label(text="Isolate:") # based on active color only sub.operator("gpencil.palettecolor_isolate", icon='LOCKED', text="").affect_visibility = False sub.operator("gpencil.palettecolor_isolate", icon='RESTRICT_VIEW_OFF', text="").affect_visibility = True sub = row.row(align=True) - sub.label(text="Lock:") # based on other stuff... + sub.label(text="Lock:") # based on other stuff... sub.operator("gpencil.stroke_lock_color", icon='BORDER_RECT', text="") sub.operator("gpencil.palette_lock_layer", icon='COLOR', text="") diff --git a/release/scripts/startup/bl_ui/properties_mask_common.py b/release/scripts/startup/bl_ui/properties_mask_common.py index a7a67130f2f..450ca80bbc2 100644 --- a/release/scripts/startup/bl_ui/properties_mask_common.py +++ b/release/scripts/startup/bl_ui/properties_mask_common.py @@ -43,8 +43,8 @@ class MASK_UL_layers(UIList): class MASK_PT_mask: # subclasses must define... - #~ bl_space_type = 'CLIP_EDITOR' - #~ bl_region_type = 'UI' + # ~ bl_space_type = 'CLIP_EDITOR' + # ~ bl_region_type = 'UI' bl_label = "Mask Settings" bl_options = {'DEFAULT_CLOSED'} @@ -66,8 +66,8 @@ class MASK_PT_mask: class MASK_PT_layers: # subclasses must define... - #~ bl_space_type = 'CLIP_EDITOR' - #~ bl_region_type = 'UI' + # ~ bl_space_type = 'CLIP_EDITOR' + # ~ bl_region_type = 'UI' bl_label = "Mask Layers" @classmethod @@ -114,8 +114,8 @@ class MASK_PT_layers: class MASK_PT_spline: # subclasses must define... - #~ bl_space_type = 'CLIP_EDITOR' - #~ bl_region_type = 'UI' + # ~ bl_space_type = 'CLIP_EDITOR' + # ~ bl_region_type = 'UI' bl_label = "Active Spline" @classmethod @@ -148,8 +148,8 @@ class MASK_PT_spline: class MASK_PT_point: # subclasses must define... - #~ bl_space_type = 'CLIP_EDITOR' - #~ bl_region_type = 'UI' + # ~ bl_space_type = 'CLIP_EDITOR' + # ~ bl_region_type = 'UI' bl_label = "Active Point" @classmethod @@ -203,8 +203,8 @@ class MASK_PT_point: class MASK_PT_display: # subclasses must define... - #~ bl_space_type = 'CLIP_EDITOR' - #~ bl_region_type = 'UI' + # ~ bl_space_type = 'CLIP_EDITOR' + # ~ bl_region_type = 'UI' bl_label = "Mask Display" bl_options = {'DEFAULT_CLOSED'} @@ -229,8 +229,8 @@ class MASK_PT_display: class MASK_PT_transforms: # subclasses must define... - #~ bl_space_type = 'CLIP_EDITOR' - #~ bl_region_type = 'TOOLS' + # ~ bl_space_type = 'CLIP_EDITOR' + # ~ bl_region_type = 'TOOLS' bl_label = "Transforms" bl_category = "Mask" bl_options = {'DEFAULT_CLOSED'} @@ -253,8 +253,8 @@ class MASK_PT_transforms: class MASK_PT_tools: # subclasses must define... - #~ bl_space_type = 'CLIP_EDITOR' - #~ bl_region_type = 'TOOLS' + # ~ bl_space_type = 'CLIP_EDITOR' + # ~ bl_region_type = 'TOOLS' bl_label = "Mask Tools" bl_category = "Mask" @@ -291,8 +291,8 @@ class MASK_PT_tools: class MASK_PT_add: # subclasses must define... - #~ bl_space_type = 'CLIP_EDITOR' - #~ bl_region_type = 'TOOLS' + # ~ bl_space_type = 'CLIP_EDITOR' + # ~ bl_region_type = 'TOOLS' bl_label = "Add" bl_category = "Mask" diff --git a/release/scripts/startup/bl_ui/properties_paint_common.py b/release/scripts/startup/bl_ui/properties_paint_common.py index bc8bc523e12..f1e5102f061 100644 --- a/release/scripts/startup/bl_ui/properties_paint_common.py +++ b/release/scripts/startup/bl_ui/properties_paint_common.py @@ -126,7 +126,7 @@ def brush_texpaint_common(panel, context, layout, brush, settings, projpaint=Fal col.prop(brush, "gradient_stroke_mode", text="Mode") if brush.gradient_stroke_mode in {'SPACING_REPEAT', 'SPACING_CLAMP'}: col.prop(brush, "grad_spacing") - else: # if brush.image_tool == 'FILL': + else: # if brush.image_tool == 'FILL': col.prop(brush, "gradient_fill_mode") else: row = col.row(align=True) diff --git a/release/scripts/startup/bl_ui/properties_particle.py b/release/scripts/startup/bl_ui/properties_particle.py index 9ffc9e983bb..00eb13dd222 100644 --- a/release/scripts/startup/bl_ui/properties_particle.py +++ b/release/scripts/startup/bl_ui/properties_particle.py @@ -404,7 +404,7 @@ class PARTICLE_PT_hair_dynamics_structure(ParticleButtonsPanel, Panel): @classmethod def poll(cls, context): - return context.particle_system.cloth != None + return context.particle_system.cloth is not None def draw(self, context): layout = self.layout @@ -436,7 +436,7 @@ class PARTICLE_PT_hair_dynamics_volume(ParticleButtonsPanel, Panel): @classmethod def poll(cls, context): - return context.particle_system.cloth != None + return context.particle_system.cloth is not None def draw(self, context): layout = self.layout @@ -591,6 +591,7 @@ class PARTICLE_PT_rotation(ParticleButtonsPanel, Panel): if part.type != 'HAIR': col.prop(part, "use_dynamic_rotation") + class PARTICLE_PT_rotation_angular_velocity(ParticleButtonsPanel, Panel): bl_label = "Angular Velocity" bl_parent_id = "PARTICLE_PT_rotation" @@ -812,6 +813,7 @@ class PARTICLE_PT_physics(ParticleButtonsPanel, Panel): sub.prop(key, "object", text="") sub.prop(key, "system", text="System") + class PARTICLE_PT_physics_deflection(ParticleButtonsPanel, Panel): bl_label = "Deflection" bl_parent_id = "PARTICLE_PT_physics" @@ -820,8 +822,8 @@ class PARTICLE_PT_physics_deflection(ParticleButtonsPanel, Panel): @classmethod def poll(cls, context): - part = particle_get_settings(context) - return part.physics_type in {'NEWTON', 'FLUID'} + part = particle_get_settings(context) + return part.physics_type in {'NEWTON', 'FLUID'} def draw(self, context): layout = self.layout @@ -846,8 +848,8 @@ class PARTICLE_PT_physics_forces(ParticleButtonsPanel, Panel): @classmethod def poll(cls, context): - part = particle_get_settings(context) - return part.physics_type == 'NEWTON' + part = particle_get_settings(context) + return part.physics_type == 'NEWTON' def draw(self, context): layout = self.layout @@ -873,8 +875,8 @@ class PARTICLE_PT_physics_integration(ParticleButtonsPanel, Panel): @classmethod def poll(cls, context): - part = particle_get_settings(context) - return part.physics_type == 'NEWTON' + part = particle_get_settings(context) + return part.physics_type == 'NEWTON' def draw(self, context): layout = self.layout @@ -924,7 +926,7 @@ class PARTICLE_PT_boidbrain(ParticleButtonsPanel, Panel): # Currently boids can only use the first state so these are commented out for now. #row = layout.row() - #row.template_list("UI_UL_list", "particle_boids", boids, "states", + # row.template_list("UI_UL_list", "particle_boids", boids, "states", # boids, "active_boid_state_index", compact="True") #col = row.row() #sub = col.row(align=True) @@ -1039,6 +1041,7 @@ class PARTICLE_PT_render(ParticleButtonsPanel, Panel): col.prop(part, "material_slot", text="Material") col.prop(psys, "parent", text="Coordinate System") + class PARTICLE_PT_render_extra(ParticleButtonsPanel, Panel): bl_label = "Extra" bl_parent_id = "PARTICLE_PT_render" @@ -1058,7 +1061,7 @@ class PARTICLE_PT_render_extra(ParticleButtonsPanel, Panel): ob = context.object part = particle_get_settings(context) - col=layout.column() + col = layout.column() col = layout.column() col.prop(part, "use_parent_particles", text="Parent Particles") @@ -1066,7 +1069,6 @@ class PARTICLE_PT_render_extra(ParticleButtonsPanel, Panel): col.prop(part, "use_dead", text="Dead") - class PARTICLE_PT_render_line(ParticleButtonsPanel, Panel): bl_label = "Line" bl_parent_id = "PARTICLE_PT_render" @@ -1086,7 +1088,7 @@ class PARTICLE_PT_render_line(ParticleButtonsPanel, Panel): ob = context.object part = particle_get_settings(context) - col=layout.column() + col = layout.column() col.separator() sub = col.column(align=True) @@ -1094,6 +1096,7 @@ class PARTICLE_PT_render_line(ParticleButtonsPanel, Panel): sub.prop(part, "line_length_head", text="Head") col.prop(part, "use_velocity_length", text="Velocity Length") + class PARTICLE_PT_render_path(ParticleButtonsPanel, Panel): bl_label = "Path" bl_parent_id = "PARTICLE_PT_render" @@ -1113,7 +1116,7 @@ class PARTICLE_PT_render_path(ParticleButtonsPanel, Panel): ob = context.object part = particle_get_settings(context) - col=layout.column() + col = layout.column() col.prop(part, "use_strand_primitive") sub = col.column() @@ -1148,7 +1151,7 @@ class PARTICLE_PT_render_path_timing(ParticleButtonsPanel, Panel): ob = context.object part = particle_get_settings(context) - col=layout.column() + col = layout.column() col.prop(part, "use_absolute_path_time") @@ -1160,6 +1163,7 @@ class PARTICLE_PT_render_path_timing(ParticleButtonsPanel, Panel): col.prop(part, "path_end", text="End", slider=not part.use_absolute_path_time) col.prop(part, "length_random", text="Random", slider=True) + class PARTICLE_PT_render_object(ParticleButtonsPanel, Panel): bl_label = "Object" bl_parent_id = "PARTICLE_PT_render" @@ -1179,7 +1183,7 @@ class PARTICLE_PT_render_object(ParticleButtonsPanel, Panel): ob = context.object part = particle_get_settings(context) - col=layout.column() + col = layout.column() col.prop(part, "dupli_object", text="Instance Object") sub = col.column() @@ -1207,7 +1211,7 @@ class PARTICLE_PT_render_collection(ParticleButtonsPanel, Panel): ob = context.object part = particle_get_settings(context) - col=layout.column() + col = layout.column() col.prop(part, "dupli_group") @@ -1219,6 +1223,7 @@ class PARTICLE_PT_render_collection(ParticleButtonsPanel, Panel): sub.prop(part, "use_rotation_dupli", text="Object Rotation") sub.prop(part, "use_scale_dupli", text="Object Scale") + class PARTICLE_PT_render_collection_use_count(ParticleButtonsPanel, Panel): bl_label = "Use Count" bl_parent_id = "PARTICLE_PT_render_collection" @@ -1246,13 +1251,13 @@ class PARTICLE_PT_render_collection_use_count(ParticleButtonsPanel, Panel): ob = context.object part = particle_get_settings(context) - col=layout.column() + col = layout.column() layout.active = part.use_group_count and not part.use_whole_group row = layout.row() row.template_list("UI_UL_list", "particle_dupli_weights", part, "dupli_weights", - part, "active_dupliweight_index") + part, "active_dupliweight_index") col = row.column() sub = col.row() @@ -1267,6 +1272,7 @@ class PARTICLE_PT_render_collection_use_count(ParticleButtonsPanel, Panel): row = layout.row() row.prop(weight, "count") + class PARTICLE_PT_render_billboards_alignment(ParticleButtonsPanel, Panel): bl_label = "Billboard Alignment" bl_parent_id = "PARTICLE_PT_render" @@ -1286,12 +1292,13 @@ class PARTICLE_PT_render_billboards_alignment(ParticleButtonsPanel, Panel): ob = context.object part = particle_get_settings(context) - col=layout.column() + col = layout.column() col.prop(part, "billboard_align", text="Align To") col.prop(part, "lock_billboard", text="Lock Axis") col.prop(part, "billboard_object") + class PARTICLE_PT_render_billboards_tilt(ParticleButtonsPanel, Panel): bl_label = "Billboard Tilt" bl_parent_id = "PARTICLE_PT_render" @@ -1311,7 +1318,7 @@ class PARTICLE_PT_render_billboards_tilt(ParticleButtonsPanel, Panel): ob = context.object part = particle_get_settings(context) - col=layout.column() + col = layout.column() sub = col.column(align=True) sub.prop(part, "billboard_tilt", text="Angle", slider=True) @@ -1325,6 +1332,7 @@ class PARTICLE_PT_render_billboards_tilt(ParticleButtonsPanel, Panel): col.prop(part, "billboard_velocity_head", text="Velocity ScaleHead") col.prop(part, "billboard_velocity_tail", text="Tail") + class PARTICLE_PT_render_billboards_uv(ParticleButtonsPanel, Panel): bl_label = "Billboard UVs" bl_parent_id = "PARTICLE_PT_render" @@ -1344,7 +1352,7 @@ class PARTICLE_PT_render_billboards_uv(ParticleButtonsPanel, Panel): ob = context.object part = particle_get_settings(context) - col=layout.column() + col = layout.column() if psys: col.prop_search(psys, "billboard_normal_uv", ob.data, "uv_layers") @@ -1361,7 +1369,6 @@ class PARTICLE_PT_render_billboards_uv(ParticleButtonsPanel, Panel): sub.prop(part, "billboard_offset_split") - class PARTICLE_PT_render_trails(ParticleButtonsPanel, Panel): bl_label = "Trails" bl_parent_id = "PARTICLE_PT_render" @@ -1380,7 +1387,7 @@ class PARTICLE_PT_render_trails(ParticleButtonsPanel, Panel): psys = context.particle_system part = particle_get_settings(context) - col=layout.column() + col = layout.column() col.prop(part, "trail_count") @@ -1532,6 +1539,7 @@ class PARTICLE_PT_children_parting(ParticleButtonsPanel, Panel): col.prop(part, "child_parting_min", text="Min") col.prop(part, "child_parting_max", text="Max") + class PARTICLE_PT_children_clumping(ParticleButtonsPanel, Panel): bl_label = "Clumping" bl_parent_id = "PARTICLE_PT_children" @@ -1573,6 +1581,7 @@ class PARTICLE_PT_children_clumping(ParticleButtonsPanel, Panel): if part.use_twist_curve: sub.template_curve_mapping(part, "twist_curve") + class PARTICLE_PT_children_roughness(ParticleButtonsPanel, Panel): bl_label = "Roughness" bl_parent_id = "PARTICLE_PT_children" diff --git a/release/scripts/startup/bl_ui/properties_physics_cloth.py b/release/scripts/startup/bl_ui/properties_physics_cloth.py index e0d0327324b..f450bc61635 100644 --- a/release/scripts/startup/bl_ui/properties_physics_cloth.py +++ b/release/scripts/startup/bl_ui/properties_physics_cloth.py @@ -257,6 +257,7 @@ class PHYSICS_PT_cloth_field_weights(PhysicButtonsPanel, Panel): cloth = context.cloth.settings effector_weights_ui(self, context, cloth.effector_weights, 'CLOTH') + classes = ( CLOTH_MT_presets, PHYSICS_PT_cloth, diff --git a/release/scripts/startup/bl_ui/properties_physics_common.py b/release/scripts/startup/bl_ui/properties_physics_common.py index 3615f8be48c..05c72bf47ee 100644 --- a/release/scripts/startup/bl_ui/properties_physics_common.py +++ b/release/scripts/startup/bl_ui/properties_physics_common.py @@ -274,7 +274,7 @@ def basic_force_field_settings_ui(self, context, field): elif field.type == 'HARMONIC': col.prop(field, "use_multiple_springs") if field.type == 'FORCE': - col.prop(field, "use_gravity_falloff", text="Gravitation") + col.prop(field, "use_gravity_falloff", text="Gravitation") split = layout.split() diff --git a/release/scripts/startup/bl_ui/properties_physics_rigidbody.py b/release/scripts/startup/bl_ui/properties_physics_rigidbody.py index 817b0ab76ed..3cb9026fd02 100644 --- a/release/scripts/startup/bl_ui/properties_physics_rigidbody.py +++ b/release/scripts/startup/bl_ui/properties_physics_rigidbody.py @@ -117,7 +117,7 @@ class PHYSICS_PT_rigid_body_dynamics(PHYSICS_PT_rigidbody_panel, Panel): rbo = ob.rigid_body #col = layout.column(align=1) - #col.label(text="Activation:") + # col.label(text="Activation:") # XXX: settings such as activate on collison/etc. split = layout.split() diff --git a/release/scripts/startup/bl_ui/properties_render.py b/release/scripts/startup/bl_ui/properties_render.py index d75d3b61f1e..7cb0ce55be3 100644 --- a/release/scripts/startup/bl_ui/properties_render.py +++ b/release/scripts/startup/bl_ui/properties_render.py @@ -152,7 +152,7 @@ class RENDER_PT_dimensions(RenderButtonsPanel, Panel): sub.prop(rd, "use_crop_to_border", text="Crop") col = layout.column(align=True) - col.prop(scene, "frame_start", text="Frame Range Start") + col.prop(scene, "frame_start", text="Frame Start") col.prop(scene, "frame_end", text="End") col.prop(scene, "frame_step", text="Step") @@ -161,8 +161,21 @@ class RENDER_PT_dimensions(RenderButtonsPanel, Panel): col.label(text="Frame Rate") self.draw_framerate(col, rd) + +class RENDER_PT_frame_remapping(RenderButtonsPanel, Panel): + bl_label = "Time Remapping" + bl_parent_id = "RENDER_PT_dimensions" + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'} + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + + rd = context.scene.render + col = layout.column(align=True) - col.prop(rd, "frame_map_old", text="Time Remapping Old") + col.prop(rd, "frame_map_old", text="Old") col.prop(rd, "frame_map_new", text="New") @@ -222,6 +235,7 @@ class RENDER_PT_stamp(RenderButtonsPanel, Panel): sub.active = rd.use_stamp_note sub.prop(rd, "stamp_note_text", text="") + class RENDER_PT_stamp_burn(RenderButtonsPanel, Panel): bl_label = "Burn Into Image" bl_parent_id = "RENDER_PT_stamp" @@ -773,6 +787,7 @@ classes = ( RENDER_MT_framerate_presets, RENDER_PT_context, RENDER_PT_dimensions, + RENDER_PT_frame_remapping, RENDER_PT_post_processing, RENDER_PT_output, RENDER_PT_encoding, diff --git a/release/scripts/startup/bl_ui/properties_scene.py b/release/scripts/startup/bl_ui/properties_scene.py index 380ee57962c..4c5b1a86235 100644 --- a/release/scripts/startup/bl_ui/properties_scene.py +++ b/release/scripts/startup/bl_ui/properties_scene.py @@ -296,9 +296,7 @@ class SCENE_PT_color_management_curves(SceneButtonsPanel, Panel): layout.use_property_split = False layout.enabled = view.use_curve_mapping - layout.template_curve_mapping(view, "curve_mapping", levels = True) - - + layout.template_curve_mapping(view, "curve_mapping", levels=True) class SCENE_PT_audio(SceneButtonsPanel, Panel): @@ -478,6 +476,24 @@ class SCENE_PT_viewport_display(SceneButtonsPanel, Panel): col.prop(scene.display, "shadow_shift") +class SCENE_PT_viewport_display_ssao(SceneButtonsPanel, Panel): + bl_label = "Screen Space Ambient Occlusion" + bl_parent_id = "SCENE_PT_viewport_display" + + @classmethod + def poll(cls, context): + return True + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + scene = context.scene + col = layout.column() + col.prop(scene.display, "matcap_ssao_samples") + col.prop(scene.display, "matcap_ssao_distance") + col.prop(scene.display, "matcap_ssao_attenuation") + + class SCENE_PT_custom_props(SceneButtonsPanel, PropertyPanel, Panel): COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_CLAY', 'BLENDER_EEVEE'} _context_path = "scene" @@ -494,6 +510,7 @@ classes = ( SCENE_PT_color_management, SCENE_PT_color_management_curves, SCENE_PT_viewport_display, + SCENE_PT_viewport_display_ssao, SCENE_PT_audio, SCENE_PT_physics, SCENE_PT_rigid_body_world, diff --git a/release/scripts/startup/bl_ui/properties_texture.py b/release/scripts/startup/bl_ui/properties_texture.py index aa3227e0b72..e5bf2c910a0 100644 --- a/release/scripts/startup/bl_ui/properties_texture.py +++ b/release/scripts/startup/bl_ui/properties_texture.py @@ -59,6 +59,7 @@ class TEXTURE_UL_texslots(UIList): layout.alignment = 'CENTER' layout.label(text="", icon_value=icon) + def context_tex_datablock(context): idblock = context.brush if idblock: @@ -106,6 +107,7 @@ class TEXTURE_PT_preview(TextureButtonsPanel, Panel): if isinstance(idblock, Brush): layout.prop(tex, "use_preview_alpha") + class TEXTURE_PT_context(TextureButtonsPanel, Panel): bl_label = "" bl_context = "texture" diff --git a/release/scripts/startup/bl_ui/properties_view_layer.py b/release/scripts/startup/bl_ui/properties_view_layer.py index 3c8552c3407..013fac3c099 100644 --- a/release/scripts/startup/bl_ui/properties_view_layer.py +++ b/release/scripts/startup/bl_ui/properties_view_layer.py @@ -43,7 +43,7 @@ class VIEWLAYER_PT_layer(ViewLayerButtonsPanel, Panel): rd = scene.render layer = bpy.context.view_layer - layout.prop(layer, "use", text="Use for Rendering"); + layout.prop(layer, "use", text="Use for Rendering") layout.prop(rd, "use_single_layer", text="Render Single Layer") diff --git a/release/scripts/startup/bl_ui/space_clip.py b/release/scripts/startup/bl_ui/space_clip.py index a3dc401b484..40009090231 100644 --- a/release/scripts/startup/bl_ui/space_clip.py +++ b/release/scripts/startup/bl_ui/space_clip.py @@ -1018,9 +1018,11 @@ class CLIP_PT_proxy(CLIP_PT_clip_view_panel, Panel): if clip.use_proxy_custom_directory: col.prop(clip.proxy, "directory") - col.operator("clip.rebuild_proxy", - text="Build Proxy / Timecode" if clip.source == 'MOVIE' - else "Build Proxy") + col.operator( + "clip.rebuild_proxy", + text="Build Proxy / Timecode" if clip.source == 'MOVIE' + else "Build Proxy" + ) if clip.source == 'MOVIE': col2 = col.column() @@ -1189,6 +1191,7 @@ class CLIP_PT_tools_grease_pencil_brush(GreasePencilBrushPanel, Panel): class CLIP_PT_tools_grease_pencil_brushcurves(GreasePencilBrushCurvesPanel, Panel): bl_space_type = 'CLIP_EDITOR' + class CLIP_MT_view(Menu): bl_label = "View" diff --git a/release/scripts/startup/bl_ui/space_dopesheet.py b/release/scripts/startup/bl_ui/space_dopesheet.py index 3fedf8bc08c..0dbb3f53332 100644 --- a/release/scripts/startup/bl_ui/space_dopesheet.py +++ b/release/scripts/startup/bl_ui/space_dopesheet.py @@ -425,11 +425,11 @@ class DOPESHEET_MT_gpencil_channel(Menu): layout.operator("anim.channels_editable_toggle") # XXX: to be enabled when these are ready for use! - #layout.separator() - #layout.operator("anim.channels_expand") - #layout.operator("anim.channels_collapse") + # layout.separator() + # layout.operator("anim.channels_expand") + # layout.operator("anim.channels_collapse") - #layout.separator() + # layout.separator() #layout.operator_menu_enum("anim.channels_move", "direction", text="Move...") @@ -450,9 +450,9 @@ class DOPESHEET_MT_gpencil_frame(Menu): layout.separator() layout.operator("action.keyframe_type") - #layout.separator() - #layout.operator("action.copy") - #layout.operator("action.paste") + # layout.separator() + # layout.operator("action.copy") + # layout.operator("action.paste") class DOPESHEET_MT_delete(Menu): @@ -469,6 +469,66 @@ class DOPESHEET_MT_delete(Menu): layout.operator("action.clean", text="Clean Channels").channels = True +class DOPESHEET_MT_specials(Menu): + bl_label = "Dope Sheet Context Menu" + + def draw(self, context): + layout = self.layout + + layout.operator("action.copy", text="Copy") + layout.operator("action.paste", text="Paste") + layout.operator("action.paste", text="Paste Flipped").flipped = True + + layout.separator() + + layout.operator_menu_enum("action.handle_type", "type", text="Handle Type") + layout.operator_menu_enum("action.interpolation_type", "type", text="Interpolation Mode") + layout.operator_menu_enum("action.easing_type", "type", text="Easing Type") + + layout.separator() + + layout.operator("action.keyframe_insert").type = 'SEL' + layout.operator("action.duplicate_move") + layout.operator("action.delete") + + layout.separator() + + layout.operator_menu_enum("action.mirror", "type", text="Mirror") + layout.operator_menu_enum("action.snap", "type", text="Snap") + + +class DOPESHEET_MT_channel_specials(Menu): + bl_label = "Dope Sheet Channel Context Menu" + + def draw(self, context): + layout = self.layout + + layout.operator("anim.channels_setting_enable", text="Mute Channels").type = 'MUTE' + layout.operator("anim.channels_setting_disable", text="Unmute Channels").type = 'MUTE' + layout.separator() + layout.operator("anim.channels_setting_enable", text="Protect Channels").type = 'PROTECT' + layout.operator("anim.channels_setting_disable", text="Unprotect Channels").type = 'PROTECT' + + layout.separator() + layout.operator("anim.channels_group") + layout.operator("anim.channels_ungroup") + + layout.separator() + layout.operator("anim.channels_editable_toggle") + layout.operator_menu_enum("action.extrapolation_type", "type", text="Extrapolation Mode") + + layout.separator() + layout.operator("anim.channels_expand") + layout.operator("anim.channels_collapse") + + layout.separator() + layout.operator_menu_enum("anim.channels_move", "direction", text="Move...") + + layout.separator() + + layout.operator("anim.channels_delete") + + classes = ( DOPESHEET_HT_header, DOPESHEET_HT_editor_buttons, @@ -482,6 +542,8 @@ classes = ( DOPESHEET_MT_gpencil_channel, DOPESHEET_MT_gpencil_frame, DOPESHEET_MT_delete, + DOPESHEET_MT_specials, + DOPESHEET_MT_channel_specials, ) if __name__ == "__main__": # only for live edit. diff --git a/release/scripts/startup/bl_ui/space_graph.py b/release/scripts/startup/bl_ui/space_graph.py index 7e927bb6385..6e809c4e86a 100644 --- a/release/scripts/startup/bl_ui/space_graph.py +++ b/release/scripts/startup/bl_ui/space_graph.py @@ -299,6 +299,76 @@ class GRAPH_MT_delete(Menu): layout.operator("graph.clean").channels = False layout.operator("graph.clean", text="Clean Channels").channels = True + +class GRAPH_MT_specials(Menu): + bl_label = "F-Curve Context Menu" + + def draw(self, context): + layout = self.layout + + layout.operator("graph.copy", text="Copy") + layout.operator("graph.paste", text="Paste") + layout.operator("graph.paste", text="Paste Flipped").flipped = True + + layout.separator() + + layout.operator_menu_enum("graph.handle_type", "type", text="Handle Type") + layout.operator_menu_enum("graph.interpolation_type", "type", text="Interpolation Mode") + layout.operator_menu_enum("graph.easing_type", "type", text="Easing Type") + + layout.separator() + + layout.operator("graph.keyframe_insert").type = 'SEL' + layout.operator("graph.duplicate_move") + layout.operator("graph.delete") + + layout.separator() + + layout.operator_menu_enum("graph.mirror", "type", text="Mirror") + layout.operator_menu_enum("graph.snap", "type", text="Snap") + + +class GRAPH_MT_channel_specials(Menu): + bl_label = "F-Curve Channel Context Menu" + + def draw(self, context): + layout = self.layout + st = context.space_data + + layout.separator() + layout.operator("anim.channels_setting_enable", text="Mute Channels").type = 'MUTE' + layout.operator("anim.channels_setting_disable", text="Unmute Channels").type = 'MUTE' + layout.separator() + layout.operator("anim.channels_setting_enable", text="Protect Channels").type = 'PROTECT' + layout.operator("anim.channels_setting_disable", text="Unprotect Channels").type = 'PROTECT' + + layout.separator() + layout.operator("anim.channels_group") + layout.operator("anim.channels_ungroup") + + layout.separator() + layout.operator("anim.channels_editable_toggle") + layout.operator_menu_enum("graph.extrapolation_type", "type", text="Extrapolation Mode") + + layout.separator() + layout.operator("graph.hide", text="Hide Selected Curves").unselected = False + layout.operator("graph.hide", text="Hide Unselected Curves").unselected = True + layout.operator("graph.reveal") + + layout.separator() + layout.operator("anim.channels_expand") + layout.operator("anim.channels_collapse") + + layout.separator() + layout.operator_menu_enum("anim.channels_move", "direction", text="Move...") + + layout.separator() + + layout.operator("anim.channels_delete") + if st.mode == 'DRIVERS': + layout.operator("graph.driver_delete_invalid") + + classes = ( GRAPH_HT_header, GRAPH_MT_editor_menus, @@ -309,6 +379,8 @@ classes = ( GRAPH_MT_key, GRAPH_MT_key_transform, GRAPH_MT_delete, + GRAPH_MT_specials, + GRAPH_MT_channel_specials, ) if __name__ == "__main__": # only for live edit. diff --git a/release/scripts/startup/bl_ui/space_image.py b/release/scripts/startup/bl_ui/space_image.py index b1ff1618d09..4b533d2f045 100644 --- a/release/scripts/startup/bl_ui/space_image.py +++ b/release/scripts/startup/bl_ui/space_image.py @@ -422,6 +422,43 @@ class IMAGE_MT_uvs_select_mode(Menu): props.data_path = "tool_settings.uv_select_mode" +class IMAGE_MT_specials(Menu): + bl_label = "UV Context Menu" + + def draw(self, context): + layout = self.layout + + sima = context.space_data + + # UV Edit Mode + if sima.show_uvedit: + layout.operator("uv.unwrap") + layout.operator("uv.follow_active_quads") + + layout.separator() + + layout.operator("uv.pin").clear = False + layout.operator("uv.pin", text="Unpin").clear = True + + layout.separator() + + layout.operator("uv.weld") + layout.operator("uv.stitch") + + layout.separator() + + layout.operator_enum("uv.align", "axis") # W, 2/3/4 + + layout.separator() + + layout.operator("transform.mirror", text="Mirror X").constraint_axis[0] = True + layout.operator("transform.mirror", text="Mirror Y").constraint_axis[1] = True + + layout.separator() + + layout.menu("IMAGE_MT_uvs_snap") + + class IMAGE_HT_header(Header): bl_space_type = 'IMAGE_EDITOR' @@ -584,6 +621,7 @@ class IMAGE_PT_tools_mask(MASK_PT_tools, Panel): bl_region_type = 'TOOLS' bl_category = 'Mask' + class IMAGE_PT_tools_mask_add(MASK_PT_add, Panel): bl_space_type = 'IMAGE_EDITOR' bl_region_type = 'TOOLS' @@ -1127,8 +1165,6 @@ class IMAGE_PT_uv_sculpt(Panel, ImagePaintPanel): col.prop(uvsculpt, "show_brush") - - class IMAGE_PT_options_uvs(Panel, UVToolsPanel): bl_label = "UV Options" bl_category = "Options" @@ -1308,6 +1344,7 @@ classes = ( IMAGE_MT_uvs_mirror, IMAGE_MT_uvs_weldalign, IMAGE_MT_uvs_select_mode, + IMAGE_MT_specials, IMAGE_HT_header, MASK_MT_editor_menus, IMAGE_PT_mask, diff --git a/release/scripts/startup/bl_ui/space_node.py b/release/scripts/startup/bl_ui/space_node.py index 0963613af5c..bf3fa64a852 100644 --- a/release/scripts/startup/bl_ui/space_node.py +++ b/release/scripts/startup/bl_ui/space_node.py @@ -290,6 +290,41 @@ class NODE_MT_node_color_specials(Menu): layout.operator("node.node_copy_color", icon='COPY_ID') +class NODE_MT_specials(Menu): + bl_label = "Node Context Menu" + + def draw(self, context): + layout = self.layout + + layout.operator_context = 'INVOKE_DEFAULT' + layout.operator("node.duplicate_move") + layout.operator("node.delete") + layout.operator_context = 'EXEC_DEFAULT' + + layout.operator("node.delete_reconnect") + + layout.separator() + + layout.operator("node.link_make").replace = False + layout.operator("node.link_make", text="Make and Replace Links").replace = True + layout.operator("node.links_detach") + + layout.separator() + + layout.operator("node.group_make", text="Group") + layout.operator("node.group_ungroup", text="Ungroup") + layout.operator("node.group_edit").exit = False + + layout.separator() + + layout.operator("node.hide_toggle") + layout.operator("node.mute_toggle") + layout.operator("node.preview_toggle") + layout.operator("node.hide_socket_toggle") + layout.operator("node.options_toggle") + layout.operator("node.collapse_hide_unused_toggle") + + class NODE_PT_active_node_generic(Panel): bl_space_type = 'NODE_EDITOR' bl_region_type = 'UI' @@ -507,11 +542,15 @@ class NODE_PT_tools_grease_pencil_sculpt(GreasePencilStrokeSculptPanel, Panel): bl_region_type = 'TOOLS' # Grease Pencil drawing brushes + + class NODE_PT_tools_grease_pencil_brush(GreasePencilBrushPanel, Panel): bl_space_type = 'NODE_EDITOR' bl_region_type = 'TOOLS' # Grease Pencil drawing curves + + class NODE_PT_tools_grease_pencil_brushcurves(GreasePencilBrushCurvesPanel, Panel): bl_space_type = 'NODE_EDITOR' bl_region_type = 'TOOLS' @@ -522,6 +561,7 @@ class NODE_PT_tools_grease_pencil_brushcurves(GreasePencilBrushCurvesPanel, Pane def node_draw_tree_view(layout, context): pass + classes = ( NODE_HT_header, NODE_MT_editor_menus, @@ -531,6 +571,7 @@ classes = ( NODE_MT_node, NODE_MT_node_color_presets, NODE_MT_node_color_specials, + NODE_MT_specials, NODE_PT_active_node_generic, NODE_PT_active_node_color, NODE_PT_active_node_properties, diff --git a/release/scripts/startup/bl_ui/space_outliner.py b/release/scripts/startup/bl_ui/space_outliner.py index 8b8526cf9f2..12cff72b61a 100644 --- a/release/scripts/startup/bl_ui/space_outliner.py +++ b/release/scripts/startup/bl_ui/space_outliner.py @@ -179,7 +179,7 @@ class OUTLINER_MT_collection(Menu): layout.operator("outliner.collection_instance", text="Instance to Scene") if space.display_mode != 'VIEW_LAYER': layout.operator("outliner.collection_link", text="Link to Scene") - layout.operator("outliner.id_operation", text="Unlink").type='UNLINK' + layout.operator("outliner.id_operation", text="Unlink").type = 'UNLINK' if space.display_mode == 'VIEW_LAYER': layout.separator() @@ -206,20 +206,20 @@ class OUTLINER_MT_object(Menu): space = context.space_data - layout.operator("outliner.object_operation", text="Delete").type='DELETE' + layout.operator("outliner.object_operation", text="Delete").type = 'DELETE' if space.display_mode == 'VIEW_LAYER' and not space.use_filter_collection: - layout.operator("outliner.object_operation", text="Delete Hierarchy").type='DELETE_HIERARCHY' + layout.operator("outliner.object_operation", text="Delete Hierarchy").type = 'DELETE_HIERARCHY' layout.separator() - layout.operator("outliner.object_operation", text="Select").type='SELECT' - layout.operator("outliner.object_operation", text="Select Hierarchy").type='SELECT_HIERARCHY' - layout.operator("outliner.object_operation", text="Deselect").type='DESELECT' + layout.operator("outliner.object_operation", text="Select").type = 'SELECT' + layout.operator("outliner.object_operation", text="Select Hierarchy").type = 'SELECT_HIERARCHY' + layout.operator("outliner.object_operation", text="Deselect").type = 'DESELECT' layout.separator() if not (space.display_mode == 'VIEW_LAYER' and not space.use_filter_collection): - layout.operator("outliner.id_operation", text="Unlink").type='UNLINK' + layout.operator("outliner.id_operation", text="Unlink").type = 'UNLINK' layout.separator() layout.operator_menu_enum("outliner.id_operation", 'type', text="ID Data") diff --git a/release/scripts/startup/bl_ui/space_properties.py b/release/scripts/startup/bl_ui/space_properties.py index cd7137e0254..2d1725b2087 100644 --- a/release/scripts/startup/bl_ui/space_properties.py +++ b/release/scripts/startup/bl_ui/space_properties.py @@ -32,8 +32,7 @@ class PROPERTIES_HT_header(Header): row = layout.row() row.template_header() - if view.mode == 'DATA_PROPERTIES': - row.prop(view, "context", expand=True, icon_only=True) + row.prop(view, "context", expand=True, icon_only=True) classes = ( diff --git a/release/scripts/startup/bl_ui/space_statusbar.py b/release/scripts/startup/bl_ui/space_statusbar.py index 983b474d18b..3a6fc4925d8 100644 --- a/release/scripts/startup/bl_ui/space_statusbar.py +++ b/release/scripts/startup/bl_ui/space_statusbar.py @@ -73,7 +73,6 @@ class STATUSBAR_HT_header(Header): return - classes = ( STATUSBAR_HT_header, ) diff --git a/release/scripts/startup/bl_ui/space_time.py b/release/scripts/startup/bl_ui/space_time.py index d5609e219e3..7c584b3177b 100644 --- a/release/scripts/startup/bl_ui/space_time.py +++ b/release/scripts/startup/bl_ui/space_time.py @@ -117,6 +117,7 @@ class TIME_MT_editor_menus(Menu): panel_type="TIME_PT_keyframing_settings", text="Keying") + class TIME_MT_marker(Menu): bl_label = "Marker" @@ -217,6 +218,7 @@ def marker_menu_generic(layout): ################################### + class TimelinePanelButtons: bl_space_type = 'DOPESHEET_EDITOR' bl_region_type = 'UI' diff --git a/release/scripts/startup/bl_ui/space_toolsystem_common.py b/release/scripts/startup/bl_ui/space_toolsystem_common.py index cb6d3851d02..2b9d4207272 100644 --- a/release/scripts/startup/bl_ui/space_toolsystem_common.py +++ b/release/scripts/startup/bl_ui/space_toolsystem_common.py @@ -339,9 +339,7 @@ class ToolSelectPanelHelper: # - None: Signal to finish (complete any final operations, e.g. add padding). @staticmethod - def _layout_generator_single_column(layout): - scale_y = 2.0 - + def _layout_generator_single_column(layout, scale_y): col = layout.column(align=True) col.scale_y = scale_y is_sep = False @@ -355,9 +353,8 @@ class ToolSelectPanelHelper: is_sep = yield col @staticmethod - def _layout_generator_multi_columns(layout, column_count): - scale_y = 2.0 - scale_x = 2.2 + def _layout_generator_multi_columns(layout, column_count, scale_y): + scale_x = scale_y * 1.1 column_last = column_count - 1 col = layout.column(align=True) @@ -394,7 +391,7 @@ class ToolSelectPanelHelper: column_index += 1 @staticmethod - def _layout_generator_detect_from_region(layout, region): + def _layout_generator_detect_from_region(layout, region, scale_y): """ Choose an appropriate layout for the toolbar. """ @@ -421,15 +418,14 @@ class ToolSelectPanelHelper: column_count = 1 if column_count == 1: - ui_gen = ToolSelectPanelHelper._layout_generator_single_column(layout) + ui_gen = ToolSelectPanelHelper._layout_generator_single_column(layout, scale_y=scale_y) else: - ui_gen = ToolSelectPanelHelper._layout_generator_multi_columns(layout, column_count=column_count) + ui_gen = ToolSelectPanelHelper._layout_generator_multi_columns(layout, column_count=column_count, scale_y=scale_y) return ui_gen, show_text - @classmethod - def draw_cls(cls, layout, context, detect_layout=True): + def draw_cls(cls, layout, context, detect_layout=True, scale_y=2.0): # Use a classmethod so it can be called outside of a panel context. # XXX, this UI isn't very nice. @@ -445,9 +441,9 @@ class ToolSelectPanelHelper: ) if detect_layout: - ui_gen, show_text = cls._layout_generator_detect_from_region(layout, context.region) + ui_gen, show_text = cls._layout_generator_detect_from_region(layout, context.region, scale_y) else: - ui_gen = ToolSelectPanelHelper._layout_generator_single_column(layout) + ui_gen = ToolSelectPanelHelper._layout_generator_single_column(layout, scale_y) show_text = True # Start iteration @@ -676,6 +672,7 @@ def keymap_from_context(context, space_type): wm.keyconfigs.update() return keymap + classes = ( WM_MT_toolsystem_submenu, ) diff --git a/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py index 42fac9e03a4..da86c1c03bc 100644 --- a/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py +++ b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py @@ -91,7 +91,7 @@ class _defs_view3d_generic: ("transform.translate", dict(release_confirm=True, cursor_transform=True), dict(type='EVT_TWEAK_A', value='ANY'), - ), + ), ), ) @@ -292,7 +292,6 @@ class _defs_edit_armature: class _defs_edit_mesh: - @ToolDef.from_fn def cube_add(): return dict( diff --git a/release/scripts/startup/bl_ui/space_topbar.py b/release/scripts/startup/bl_ui/space_topbar.py index 7beb97f31b6..c231d05ecdb 100644 --- a/release/scripts/startup/bl_ui/space_topbar.py +++ b/release/scripts/startup/bl_ui/space_topbar.py @@ -141,7 +141,7 @@ class TOPBAR_HT_lower_bar(Header): elif mode == 'POSE': pass elif mode == 'PARTICLE': - pass + layout.popover_group(space_type='PROPERTIES', region_type='WINDOW', context=".paint_common", category="") def draw_right(self, context): layout = self.layout diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py index 1e090884fd1..a480fa433e1 100644 --- a/release/scripts/startup/bl_ui/space_userpref.py +++ b/release/scripts/startup/bl_ui/space_userpref.py @@ -22,6 +22,7 @@ from bpy.types import ( Header, Menu, Panel, + Operator, ) from bpy.app.translations import pgettext_iface as iface_ from bpy.app.translations import contexts as i18n_contexts @@ -71,6 +72,10 @@ class USERPREF_HT_header(Header): layout.operator("wm.addon_install", icon='FILESEL') layout.operator("wm.addon_refresh", icon='FILE_REFRESH') layout.menu("USERPREF_MT_addons_online_resources") + elif userpref.active_section == 'LIGHTS': + layout.operator('wm.studiolight_install', text="Install MatCap").orientation='MATCAP' + layout.operator('wm.studiolight_install', text="Install World HDRI").orientation='WORLD' + layout.operator('wm.studiolight_install', text="Install Camera HDRI").orientation='CAMERA' elif userpref.active_section == 'THEMES': layout.operator("ui.reset_default_theme") layout.operator("wm.theme_install") @@ -141,7 +146,6 @@ class USERPREF_MT_app_templates(Menu): layout.operator_context = 'INVOKE_DEFAULT' props = layout.operator("wm.app_template_install") - def draw(self, context): self.draw_ex(context, use_splash=False, use_default=True, use_install=True) @@ -282,14 +286,14 @@ class USERPREF_PT_interface(Panel): row.separator() col = row.column() - #Toolbox doesn't exist yet - #col.label(text="Toolbox:") + # Toolbox doesn't exist yet + # col.label(text="Toolbox:") #col.prop(view, "show_column_layout") #col.label(text="Open Toolbox Delay:") #col.prop(view, "open_left_mouse_delay", text="Hold LMB") #col.prop(view, "open_right_mouse_delay", text="Hold RMB") col.prop(view, "show_manipulator") - ## Currently not working + # Currently not working # col.prop(view, "show_manipulator_shaded") sub = col.column() sub.active = view.show_manipulator @@ -328,7 +332,6 @@ class USERPREF_PT_interface(Panel): col.prop(view, "show_view3d_cursor") - class USERPREF_PT_edit(Panel): bl_space_type = 'USER_PREFERENCES' bl_label = "Edit" @@ -412,7 +415,7 @@ class USERPREF_PT_edit(Panel): sub = col.column() - #~ sub.active = edit.use_keyframe_insert_auto # incorrect, time-line can enable + # ~ sub.active = edit.use_keyframe_insert_auto # incorrect, time-line can enable sub.prop(edit, "use_keyframe_insert_available", text="Only Insert Available") col.separator() @@ -1217,7 +1220,7 @@ class USERPREF_PT_input(Panel): #sub.prop(inputs, "use_mouse_mmb_paste") - #col.separator() + # col.separator() sub = col.column() sub.prop(inputs, "invert_zoom_wheel", text="Invert Wheel Zoom Direction") @@ -1332,7 +1335,7 @@ class USERPREF_PT_addons(Panel): 'OFFICIAL': 'FILE_BLEND', 'COMMUNITY': 'POSE_DATA', 'TESTING': 'MOD_EXPLODE', - } + } @classmethod def poll(cls, context): @@ -1410,7 +1413,6 @@ class USERPREF_PT_addons(Panel): sub_col.label(" " + addon_file) sub_col.label(" " + addon_path) - if addon_utils.error_encoding: self.draw_error( col, @@ -1435,11 +1437,11 @@ class USERPREF_PT_addons(Panel): # check if addon should be visible with current filters if ((filter == "All") or - (filter == info["category"]) or - (filter == "Enabled" and is_enabled) or - (filter == "Disabled" and not is_enabled) or - (filter == "User" and (mod.__file__.startswith((scripts_addons_folder, userpref_addons_folder)))) - ): + (filter == info["category"]) or + (filter == "Enabled" and is_enabled) or + (filter == "Disabled" and not is_enabled) or + (filter == "User" and (mod.__file__.startswith((scripts_addons_folder, userpref_addons_folder)))) + ): if search and search not in info["name"].lower(): if info["author"]: if search not in info["author"].lower(): @@ -1573,6 +1575,60 @@ class USERPREF_PT_addons(Panel): row.label(text=module_name, translate=False) +class StudioLightPanelMixin(): + bl_space_type = 'USER_PREFERENCES' + bl_region_type = 'WINDOW' + + @classmethod + def poll(cls, context): + userpref = context.user_preferences + return (userpref.active_section == 'LIGHTS') + + def _get_lights(self, userpref): + return [light for light in userpref.studio_lights if light.is_user_defined and light.orientation == self.sl_orientation] + + def draw_header(self, context): + layout = self.layout + row = layout.row() + userpref = context.user_preferences + lights = self._get_lights(userpref) + row.label("({})".format(len(lights))) + + def draw(self, context): + layout = self.layout + userpref = context.user_preferences + lights = self._get_lights(userpref) + if lights: + flow = layout.column_flow(4) + for studio_light in lights: + self.draw_studio_light(flow, studio_light) + else: + layout.label("No custom {} configured".format(self.bl_label)) + + def draw_studio_light(self, layout, studio_light): + box = layout.box() + row = box.row() + + row.template_icon_view(studio_light, "icon_id") + op = row.operator('wm.studiolight_uninstall', text="", icon='ZOOMOUT') + op.index = studio_light.index + + +class USERPREF_PT_studiolight_matcaps(Panel, StudioLightPanelMixin): + bl_label = "MatCaps" + sl_orientation = 'MATCAP' + + +class USERPREF_PT_studiolight_world(Panel, StudioLightPanelMixin): + bl_label = "World HDRI" + sl_orientation = 'WORLD' + + +class USERPREF_PT_studiolight_camera(Panel, StudioLightPanelMixin): + bl_label = "Camera HDRI" + sl_orientation = 'CAMERA' + + classes = ( USERPREF_HT_header, USERPREF_PT_tabs, @@ -1593,6 +1649,9 @@ classes = ( USERPREF_PT_input, USERPREF_MT_addons_online_resources, USERPREF_PT_addons, + USERPREF_PT_studiolight_matcaps, + USERPREF_PT_studiolight_world, + USERPREF_PT_studiolight_camera, ) if __name__ == "__main__": # only for live edit. diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py index 4f3396c9ed8..3a8fb3ce2f0 100644 --- a/release/scripts/startup/bl_ui/space_view3d.py +++ b/release/scripts/startup/bl_ui/space_view3d.py @@ -1483,7 +1483,7 @@ class VIEW3D_MT_object_clear(Menu): class VIEW3D_MT_object_specials(Menu): - bl_label = "Context Menu" + bl_label = "Object Context Menu" @classmethod def poll(cls, context): @@ -2113,7 +2113,7 @@ class VIEW3D_MT_particle(Menu): class VIEW3D_MT_particle_specials(Menu): - bl_label = "Context Menu" + bl_label = "Particle Context Menu" def draw(self, context): layout = self.layout @@ -2363,7 +2363,7 @@ class VIEW3D_MT_pose_apply(Menu): class VIEW3D_MT_pose_specials(Menu): - bl_label = "Context Menu" + bl_label = "Pose Context Menu" def draw(self, context): layout = self.layout @@ -2496,7 +2496,7 @@ class VIEW3D_MT_edit_mesh(Menu): class VIEW3D_MT_edit_mesh_specials(Menu): - bl_label = "Context Menu" + bl_label = "Mesh Context Menu" def draw(self, context): layout = self.layout @@ -3030,7 +3030,7 @@ class VIEW3D_MT_edit_curve_clean(Menu): class VIEW3D_MT_edit_curve_specials(Menu): - bl_label = "Context Menu" + bl_label = "Curve Context Menu" def draw(self, context): layout = self.layout @@ -3244,7 +3244,7 @@ class VIEW3D_MT_edit_armature(Menu): class VIEW3D_MT_armature_specials(Menu): - bl_label = "Context Menu" + bl_label = "Armature Context Menu" def draw(self, context): layout = self.layout @@ -3394,6 +3394,28 @@ class VIEW3D_MT_edit_gpencil_interpolate(Menu): layout.operator("gpencil.interpolate_sequence", text="Sequence") +class VIEW3D_PIE_object_mode(Menu): + bl_label = "Mode" + + def draw(self, context): + layout = self.layout + + pie = layout.menu_pie() + pie.operator_enum("OBJECT_OT_mode_set", "mode") + + +class VIEW3D_PIE_view(Menu): + bl_label = "View" + bl_idname = "VIEW3D_PIE_view" + + def draw(self, context): + layout = self.layout + + pie = layout.menu_pie() + pie.operator_enum("VIEW3D_OT_viewnumpad", "type") + pie.operator("view3d.view_selected", text="View Selected", icon='ZOOM_SELECTED') + + # ********** Panel ********** @@ -3476,31 +3498,6 @@ class VIEW3D_PT_view3d_cursor(Panel): layout.column().prop(view, "cursor_location", text="Location") -class VIEW3D_PT_view3d_name(Panel): - bl_space_type = 'VIEW_3D' - bl_region_type = 'UI' - bl_label = "Item" - - @classmethod - def poll(cls, context): - return (context.space_data and context.active_object) - - def draw(self, context): - layout = self.layout - - ob = context.active_object - row = layout.row() - row.label(text="", icon='OBJECT_DATA') - row.prop(ob, "name", text="") - - if ob.type == 'ARMATURE' and ob.mode in {'EDIT', 'POSE'}: - bone = context.active_bone - if bone: - row = layout.row() - row.label(text="", icon='BONE_DATA') - row.prop(bone, "name", text="") - - class VIEW3D_PT_shading(Panel): bl_space_type = 'VIEW_3D' bl_region_type = 'HEADER' @@ -3517,48 +3514,72 @@ class VIEW3D_PT_shading(Panel): shading = view.shading col = layout.column() - - if shading.type == 'SOLID': - col.row().prop(shading, "color_type", expand=True) - - if shading.color_type == 'SINGLE': - col.row().prop(shading, "single_color", text="") - + col.row().label("Lighting") if shading.type in ('SOLID', 'TEXTURED'): col.row().prop(shading, "light", expand=True) if shading.light == 'STUDIO': - col.row().template_icon_view(shading, "studio_light") + row = col.row() + row.template_icon_view(shading, "studio_light") + row.operator('wm.studiolight_userpref_show', emboss=False, text="", icon='ZOOMIN') if shading.studio_light_orientation == 'WORLD': col.row().prop(shading, "studiolight_rot_z") - row = col.row() - row.prop(shading, "show_specular_highlight") + elif shading.light == 'MATCAP': + row = col.row() + row.template_icon_view(shading, "matcap") + sub = row.column() + sub.operator('VIEW3D_OT_toggle_matcap_flip', emboss=False, text="", icon='ARROW_LEFTRIGHT') + sub.operator('wm.studiolight_userpref_show', emboss=False, text="", icon='ZOOMIN') + if shading.type == 'SOLID': col.separator() + col.row().label("Color") + col.row().prop(shading, "color_type", expand=True) - row = col.row() - row.prop(shading, "show_xray") - sub = row.row() - sub.active = shading.show_xray - sub.prop(shading, "xray_alpha", text="") - - row = col.row() - row.active = not shading.show_xray - row.prop(shading, "show_shadows") - sub = row.row() - sub.active = shading.show_shadows and not shading.show_xray - sub.prop(shading, "shadow_intensity", text="") + if shading.color_type == 'SINGLE': + col.row().prop(shading, "single_color", text="") - row = col.row() - row.prop(shading, "show_object_outline") - sub = row.row() - sub.active = shading.show_object_outline - sub.prop(shading, "object_outline_color", text="") + if shading.type in ('SOLID', 'TEXTURED'): + col.separator() - col.prop(view, "show_world") + if not shading.light == 'MATCAP': + row = col.row() + row.prop(shading, "show_specular_highlight") + + if shading.type in ('SOLID', 'TEXTURED'): + row = col.split(0.4) + row.prop(shading, "show_xray") + sub = row.row() + sub.active = shading.show_xray + sub.prop(shading, "xray_alpha", text="") + + row = col.split(0.4) + row.active = not shading.show_xray + row.prop(shading, "show_shadows") + sub = row.row() + sub.active = shading.show_shadows and not shading.show_xray + sub.prop(shading, "shadow_intensity", text="") + + row = col.split(0.4) + row.active = not shading.show_xray + row.prop(shading, "show_cavity") + sub = row.column(align=True) + sub.active = not shading.show_xray and shading.show_cavity + sub.prop(shading, "cavity_ridge_factor") + sub.prop(shading, "cavity_valley_factor") + + row = col.split(0.4) + row.prop(shading, "show_object_outline") + sub = row.row() + sub.active = shading.show_object_outline + sub.prop(shading, "object_outline_color", text="") + + col.prop(view, "show_world") elif shading.type in ('MATERIAL'): - col.row().template_icon_view(shading, "studio_light") + row = col.row() + row.template_icon_view(shading, "studio_light") + op = row.operator('wm.studiolight_userpref_show', emboss=False, text="", icon='ZOOMIN') if shading.studio_light_orientation == 'WORLD': col.row().prop(shading, "studiolight_rot_z") col.row().prop(shading, "studiolight_background") @@ -3580,7 +3601,6 @@ class VIEW3D_PT_overlay(Panel): view = context.space_data shading = view.shading overlay = view.overlay - scene = context.scene toolsettings = context.tool_settings display_all = overlay.show_overlays @@ -3596,7 +3616,13 @@ class VIEW3D_PT_overlay(Panel): col.prop(overlay, "show_relationship_lines") col.prop(overlay, "show_motion_paths") col.prop(overlay, "show_face_orientation") - col.prop(overlay, "show_wireframes") + + row = col.row() + row.prop(overlay, "show_wireframes") + sub = row.row() + sub.active = overlay.show_wireframes + sub.prop(overlay, "wireframe_threshold", text="") + col.prop(overlay, "show_backface_culling") if shading.type == "MATERIAL": @@ -3616,12 +3642,27 @@ class VIEW3D_PT_overlay(Panel): sub.active = bool(overlay.show_floor or view.region_quadviews or not view.region_3d.is_perspective) subsub = sub.column(align=True) subsub.active = overlay.show_floor - sub.prop(overlay, "grid_scale", text="Scale") - sub.prop(overlay, "grid_subdivisions", text="Subdivisions") + subsub.prop(overlay, "grid_scale", text="Scale") + subsub.prop(overlay, "grid_subdivisions", text="Subdivisions") + + col.prop(view, "show_reconstruction", text="Motion Tracking") + sub = col.column(align=True) + + sub.active = view.show_reconstruction + sub.prop(view, "show_camera_path", text="Camera Path") + sub.prop(view, "show_bundle_names", text="3D Marker Names") + sub.label(text="Track Type and Size:") + row = sub.row(align=True) + row.prop(view, "tracks_draw_type", text="") + row.prop(view, "tracks_draw_size", text="") + col.separator() if context.mode == 'EDIT_MESH': + data = context.active_object.data + statvis = context.tool_settings.statvis + with_freestyle = bpy.app.build_options.freestyle col.separator() - col.label(text="Edit Mode:") + col.label(text="Edit Mesh:") col.prop(overlay, "show_occlude_wire") @@ -3640,6 +3681,72 @@ class VIEW3D_PT_overlay(Panel): sub.active = overlay.show_vertex_normals or overlay.show_face_normals or overlay.show_split_normals sub.prop(overlay, "normals_length", text="Size") + split = col.split() + + sub = split.column() + sub.prop(data, "show_faces", text="Faces") + sub.prop(data, "show_edges", text="Edges") + sub.prop(data, "show_edge_crease", text="Creases") + + if with_freestyle: + sub.prop(data, "show_edge_seams", text="Seams") + + sub = split.column() + if not with_freestyle: + sub.prop(data, "show_edge_seams", text="Seams") + sub.prop(data, "show_edge_sharp", text="Sharp", text_ctxt=i18n_contexts.plural) + col.prop(data, "show_edge_bevel_weight", text="Bevel") + if with_freestyle: + sub.prop(data, "show_freestyle_edge_marks", text="Edge Marks") + sub.prop(data, "show_freestyle_face_marks", text="Face Marks") + + col.separator() + split = col.split() + sub = split.column() + sub.label(text="Edge Info:") + sub.prop(data, "show_extra_edge_length", text="Length") + sub.prop(data, "show_extra_edge_angle", text="Angle") + sub = split.column() + sub.label(text="Face Info:") + sub.prop(data, "show_extra_face_area", text="Area") + sub.prop(data, "show_extra_face_angle", text="Angle") + if bpy.app.debug: + sub.prop(data, "show_extra_indices", text="Indices") + + col.prop(data, "show_statvis", text="Mesh Analysis") + sub = col.column() + sub.active = data.show_statvis + sub.prop(statvis, "type") + statvis_type = statvis.type + if statvis_type == 'OVERHANG': + row = sub.row(align=True) + row.prop(statvis, "overhang_min", text="") + row.prop(statvis, "overhang_max", text="") + layout.row().prop(statvis, "overhang_axis", expand=True) + elif statvis_type == 'THICKNESS': + row = sub.row(align=True) + row.prop(statvis, "thickness_min", text="") + row.prop(statvis, "thickness_max", text="") + layout.prop(statvis, "thickness_samples") + elif statvis_type == 'INTERSECT': + pass + elif statvis_type == 'DISTORT': + row = sub.row(align=True) + row.prop(statvis, "distort_min", text="") + row.prop(statvis, "distort_max", text="") + elif statvis_type == 'SHARP': + row = sub.row(align=True) + row.prop(statvis, "sharp_min", text="") + row.prop(statvis, "sharp_max", text="") + + elif context.mode == 'EDIT_CURVE': + data = context.active_object.data + col.separator() + col.label(text="Edit Curve:") + row = col.row() + row.prop(data, "show_handles", text="Handles") + row.prop(data, "show_normal_face", text="Normals") + elif context.mode == 'POSE': col.separator() col.label(text="Pose Mode:") @@ -3647,7 +3754,11 @@ class VIEW3D_PT_overlay(Panel): col = layout.column() col.active = display_all col.prop(overlay, "show_transparent_bones") - col.prop(overlay, "show_bone_selection") + row = col.split(0.65) + row.prop(overlay, "show_bone_selection") + sub = row.column() + sub.active = display_all and overlay.show_bone_selection + sub.prop(overlay, "bone_selection_alpha", text="") elif context.mode == 'EDIT_ARMATURE': col.separator() @@ -3734,157 +3845,6 @@ class VIEW3D_PT_view3d_stereo(Panel): split.prop(view, "stereo_3d_volume_alpha", text="Alpha") -class VIEW3D_PT_view3d_motion_tracking(Panel): - bl_space_type = 'VIEW_3D' - bl_region_type = 'UI' - bl_label = "Motion Tracking" - bl_options = {'DEFAULT_CLOSED'} - - @classmethod - def poll(cls, context): - view = context.space_data - return (view) - - def draw_header(self, context): - view = context.space_data - - self.layout.prop(view, "show_reconstruction", text="") - - def draw(self, context): - layout = self.layout - - view = context.space_data - - col = layout.column() - col.active = view.show_reconstruction - col.prop(view, "show_camera_path", text="Camera Path") - col.prop(view, "show_bundle_names", text="3D Marker Names") - col.label(text="Track Type and Size:") - row = col.row(align=True) - row.prop(view, "tracks_draw_type", text="") - row.prop(view, "tracks_draw_size", text="") - - -class VIEW3D_PT_view3d_meshdisplay(Panel): - bl_space_type = 'VIEW_3D' - bl_region_type = 'UI' - bl_label = "Mesh Display" - - @classmethod - def poll(cls, context): - # The active object check is needed because of local-mode - return (context.active_object and (context.mode == 'EDIT_MESH')) - - def draw(self, context): - layout = self.layout - with_freestyle = bpy.app.build_options.freestyle - - mesh = context.active_object.data - scene = context.scene - - split = layout.split() - - col = split.column() - col.label(text="Overlays:") - col.prop(mesh, "show_faces", text="Faces") - col.prop(mesh, "show_edges", text="Edges") - col.prop(mesh, "show_edge_crease", text="Creases") - if with_freestyle: - col.prop(mesh, "show_edge_seams", text="Seams") - - col = split.column() - col.label() - if not with_freestyle: - col.prop(mesh, "show_edge_seams", text="Seams") - col.prop(mesh, "show_edge_sharp", text="Sharp", text_ctxt=i18n_contexts.plural) - col.prop(mesh, "show_edge_bevel_weight", text="Bevel") - if with_freestyle: - col.prop(mesh, "show_freestyle_edge_marks", text="Edge Marks") - col.prop(mesh, "show_freestyle_face_marks", text="Face Marks") - - col = layout.column() - - col.separator() - split = layout.split() - col = split.column() - col.label(text="Edge Info:") - col.prop(mesh, "show_extra_edge_length", text="Length") - col.prop(mesh, "show_extra_edge_angle", text="Angle") - col = split.column() - col.label(text="Face Info:") - col.prop(mesh, "show_extra_face_area", text="Area") - col.prop(mesh, "show_extra_face_angle", text="Angle") - if bpy.app.debug: - layout.prop(mesh, "show_extra_indices", text="Indices") - - -class VIEW3D_PT_view3d_meshstatvis(Panel): - bl_space_type = 'VIEW_3D' - bl_region_type = 'UI' - bl_label = "Mesh Analysis" - - @classmethod - def poll(cls, context): - # The active object check is needed because of local-mode - return (context.active_object and (context.mode == 'EDIT_MESH')) - - def draw_header(self, context): - mesh = context.active_object.data - - self.layout.prop(mesh, "show_statvis", text="") - - def draw(self, context): - layout = self.layout - - mesh = context.active_object.data - statvis = context.tool_settings.statvis - layout.active = mesh.show_statvis - - layout.prop(statvis, "type") - statvis_type = statvis.type - if statvis_type == 'OVERHANG': - row = layout.row(align=True) - row.prop(statvis, "overhang_min", text="") - row.prop(statvis, "overhang_max", text="") - layout.row().prop(statvis, "overhang_axis", expand=True) - elif statvis_type == 'THICKNESS': - row = layout.row(align=True) - row.prop(statvis, "thickness_min", text="") - row.prop(statvis, "thickness_max", text="") - layout.prop(statvis, "thickness_samples") - elif statvis_type == 'INTERSECT': - pass - elif statvis_type == 'DISTORT': - row = layout.row(align=True) - row.prop(statvis, "distort_min", text="") - row.prop(statvis, "distort_max", text="") - elif statvis_type == 'SHARP': - row = layout.row(align=True) - row.prop(statvis, "sharp_min", text="") - row.prop(statvis, "sharp_max", text="") - - -class VIEW3D_PT_view3d_curvedisplay(Panel): - bl_space_type = 'VIEW_3D' - bl_region_type = 'UI' - bl_label = "Curve Display" - - @classmethod - def poll(cls, context): - editmesh = context.mode == 'EDIT_CURVE' - return (editmesh) - - def draw(self, context): - layout = self.layout - - curve = context.active_object.data - - col = layout.column() - row = col.row() - row.prop(curve, "show_handles", text="Handles") - row.prop(curve, "show_normal_face", text="Normals") - - class VIEW3D_PT_transform_orientations(Panel): bl_space_type = 'VIEW_3D' bl_region_type = 'UI' @@ -4079,17 +4039,14 @@ classes = ( VIEW3D_MT_edit_armature_delete, VIEW3D_MT_edit_gpencil_transform, VIEW3D_MT_edit_gpencil_interpolate, + VIEW3D_PIE_object_mode, + VIEW3D_PIE_view, VIEW3D_PT_grease_pencil, VIEW3D_PT_grease_pencil_palettecolor, VIEW3D_PT_view3d_properties, VIEW3D_PT_view3d_cursor, - VIEW3D_PT_view3d_name, VIEW3D_PT_quad_view, VIEW3D_PT_view3d_stereo, - VIEW3D_PT_view3d_motion_tracking, - VIEW3D_PT_view3d_meshdisplay, - VIEW3D_PT_view3d_meshstatvis, - VIEW3D_PT_view3d_curvedisplay, VIEW3D_PT_shading, VIEW3D_PT_overlay, VIEW3D_PT_transform_orientations, diff --git a/release/scripts/startup/bl_ui/space_view3d_toolbar.py b/release/scripts/startup/bl_ui/space_view3d_toolbar.py index 48b80a1070a..db72dfc052e 100644 --- a/release/scripts/startup/bl_ui/space_view3d_toolbar.py +++ b/release/scripts/startup/bl_ui/space_view3d_toolbar.py @@ -69,7 +69,7 @@ def draw_vpaint_symmetry(layout, vpaint): class VIEW3D_PT_tools_meshedit_options(View3DPanel, Panel): bl_category = "Options" - bl_context = ".mesh_edit" # dot on purpose (access from topbar) + bl_context = ".mesh_edit" # dot on purpose (access from topbar) bl_label = "Mesh Options" @classmethod @@ -100,9 +100,10 @@ class VIEW3D_PT_tools_meshedit_options(View3DPanel, Panel): # ********** default tools for editmode_curve **************** + class VIEW3D_PT_tools_curveedit_options_stroke(View3DPanel, Panel): bl_category = "Options" - bl_context = ".curve_edit" # dot on purpose (access from topbar) + bl_context = ".curve_edit" # dot on purpose (access from topbar) bl_label = "Curve Stroke" def draw(self, context): @@ -154,8 +155,6 @@ class VIEW3D_PT_tools_curveedit_options_stroke(View3DPanel, Panel): colsub.prop(cps, "surface_plane", expand=True) - - # ********** default tools for editmode_armature **************** @@ -174,7 +173,7 @@ class VIEW3D_PT_tools_armatureedit_options(View3DPanel, Panel): class VIEW3D_PT_tools_posemode_options(View3DPanel, Panel): bl_category = "Options" - bl_context = ".posemode" # dot on purpose (access from topbar) + bl_context = ".posemode" # dot on purpose (access from topbar) bl_label = "Pose Options" def draw(self, context): @@ -193,7 +192,7 @@ class View3DPaintPanel(UnifiedPaintPanel): class VIEW3D_PT_imapaint_tools_missing(Panel, View3DPaintPanel): bl_category = "Tools" - bl_context = ".imagepaint" # dot on purpose (access from topbar) + bl_context = ".imagepaint" # dot on purpose (access from topbar) bl_label = "Missing Data" @classmethod @@ -527,7 +526,7 @@ class VIEW3D_MT_tools_projectpaint_uvlayer(Menu): class VIEW3D_PT_slots_projectpaint(View3DPanel, Panel): - bl_context = ".imagepaint" # dot on purpose (access from topbar) + bl_context = ".imagepaint" # dot on purpose (access from topbar) bl_label = "Slots" bl_category = "Slots" @@ -588,7 +587,7 @@ class VIEW3D_PT_slots_projectpaint(View3DPanel, Panel): class VIEW3D_PT_stencil_projectpaint(View3DPanel, Panel): - bl_context = ".imagepaint" # dot on purpose (access from topbar) + bl_context = ".imagepaint" # dot on purpose (access from topbar) bl_label = "Mask" bl_category = "Slots" @@ -722,7 +721,7 @@ class VIEW3D_PT_tools_brush_texture(Panel, View3DPaintPanel): class VIEW3D_PT_tools_mask_texture(Panel, View3DPaintPanel): bl_category = "Tools" - bl_context = ".imagepaint" # dot on purpose (access from topbar) + bl_context = ".imagepaint" # dot on purpose (access from topbar) bl_label = "Texture Mask" bl_options = {'DEFAULT_CLOSED'} @@ -885,11 +884,11 @@ class VIEW3D_PT_sculpt_dyntopo(Panel, View3DPaintPanel): def draw_header(self, context): layout = self.layout layout.operator( - "sculpt.dynamic_topology_toggle", - icon='CHECKBOX_HLT' if context.sculpt_object.use_dynamic_topology_sculpting else 'CHECKBOX_DEHLT', - text="", - emboss=False, - ) + "sculpt.dynamic_topology_toggle", + icon='CHECKBOX_HLT' if context.sculpt_object.use_dynamic_topology_sculpting else 'CHECKBOX_DEHLT', + text="", + emboss=False, + ) def draw(self, context): layout = self.layout @@ -1123,7 +1122,7 @@ class VIEW3D_PT_tools_vertexpaint_symmetry(Panel, View3DPaintPanel): class VIEW3D_PT_tools_imagepaint_external(Panel, View3DPaintPanel): bl_category = "Tools" - bl_context = ".imagepaint" # dot on purpose (access from topbar) + bl_context = ".imagepaint" # dot on purpose (access from topbar) bl_label = "External" bl_options = {'DEFAULT_CLOSED'} @@ -1145,7 +1144,7 @@ class VIEW3D_PT_tools_imagepaint_external(Panel, View3DPaintPanel): class VIEW3D_PT_tools_imagepaint_symmetry(Panel, View3DPaintPanel): bl_category = "Tools" - bl_context = ".imagepaint" # dot on purpose (access from topbar) + bl_context = ".imagepaint" # dot on purpose (access from topbar) bl_label = "Symmetry" bl_options = {'DEFAULT_CLOSED'} @@ -1164,7 +1163,7 @@ class VIEW3D_PT_tools_imagepaint_symmetry(Panel, View3DPaintPanel): class VIEW3D_PT_tools_projectpaint(View3DPaintPanel, Panel): bl_category = "Options" - bl_context = ".imagepaint" # dot on purpose (access from topbar) + bl_context = ".imagepaint" # dot on purpose (access from topbar) bl_label = "Project Paint" @classmethod @@ -1322,6 +1321,8 @@ class VIEW3D_PT_tools_grease_pencil_brush(GreasePencilBrushPanel, Panel): bl_space_type = 'VIEW_3D' # Grease Pencil drawingcurves + + class VIEW3D_PT_tools_grease_pencil_brushcurves(GreasePencilBrushCurvesPanel, Panel): bl_space_type = 'VIEW_3D' diff --git a/source/blender/alembic/ABC_alembic.h b/source/blender/alembic/ABC_alembic.h index 70250310213..08136fc2f49 100644 --- a/source/blender/alembic/ABC_alembic.h +++ b/source/blender/alembic/ABC_alembic.h @@ -29,8 +29,8 @@ extern "C" { struct bContext; struct CacheReader; -struct DerivedMesh; struct ListBase; +struct Mesh; struct Object; struct Scene; @@ -114,12 +114,13 @@ void ABC_get_transform(struct CacheReader *reader, float time, float scale); -struct DerivedMesh *ABC_read_mesh(struct CacheReader *reader, - struct Object *ob, - struct DerivedMesh *dm, - const float time, - const char **err_str, - int flags); +/* Either modifies current_mesh in-place or constructs a new mesh. */ +struct Mesh *ABC_read_mesh(struct CacheReader *reader, + struct Object *ob, + struct Mesh *current_mesh, + const float time, + const char **err_str, + int flags); void CacheReader_incref(struct CacheReader *reader); void CacheReader_free(struct CacheReader *reader); diff --git a/source/blender/alembic/intern/abc_camera.cc b/source/blender/alembic/intern/abc_camera.cc index 4c91b9a6252..457bbd2b3af 100644 --- a/source/blender/alembic/intern/abc_camera.cc +++ b/source/blender/alembic/intern/abc_camera.cc @@ -49,13 +49,11 @@ using Alembic::AbcGeom::kWrapExisting; /* ************************************************************************** */ -AbcCameraWriter::AbcCameraWriter(Depsgraph *depsgraph, - Scene *scene, - Object *ob, +AbcCameraWriter::AbcCameraWriter(Object *ob, AbcTransformWriter *parent, uint32_t time_sampling, ExportSettings &settings) - : AbcObjectWriter(depsgraph, scene, ob, time_sampling, settings, parent) + : AbcObjectWriter(ob, time_sampling, settings, parent) { OCamera camera(parent->alembicXform(), m_name, m_time_sampling); m_camera_schema = camera.getSchema(); diff --git a/source/blender/alembic/intern/abc_camera.h b/source/blender/alembic/intern/abc_camera.h index a839ca947ca..dd5dc28d598 100644 --- a/source/blender/alembic/intern/abc_camera.h +++ b/source/blender/alembic/intern/abc_camera.h @@ -35,9 +35,7 @@ class AbcCameraWriter : public AbcObjectWriter { Alembic::AbcGeom::OFloatProperty m_eye_separation; public: - AbcCameraWriter(Depsgraph *depsgraph, - Scene *scene, - Object *ob, + AbcCameraWriter(Object *ob, AbcTransformWriter *parent, uint32_t time_sampling, ExportSettings &settings); diff --git a/source/blender/alembic/intern/abc_curves.cc b/source/blender/alembic/intern/abc_curves.cc index 41c1dacabc0..e27403305da 100644 --- a/source/blender/alembic/intern/abc_curves.cc +++ b/source/blender/alembic/intern/abc_curves.cc @@ -37,8 +37,8 @@ extern "C" { #include "BLI_listbase.h" -#include "BKE_cdderivedmesh.h" #include "BKE_curve.h" +#include "BKE_mesh.h" #include "BKE_object.h" #include "ED_curve.h" @@ -71,13 +71,11 @@ using Alembic::AbcGeom::OV2fGeomParam; /* ************************************************************************** */ -AbcCurveWriter::AbcCurveWriter(Depsgraph *depsgraph, - Scene *scene, - Object *ob, +AbcCurveWriter::AbcCurveWriter(Object *ob, AbcTransformWriter *parent, uint32_t time_sampling, ExportSettings &settings) - : AbcObjectWriter(depsgraph, scene, ob, time_sampling, settings, parent) + : AbcObjectWriter(ob, time_sampling, settings, parent) { OCurves curves(parent->alembicXform(), m_name, m_time_sampling); m_schema = curves.getSchema(); @@ -258,9 +256,21 @@ void AbcCurveReader::readObjectData(Main *bmain, const Alembic::Abc::ISampleSele /* ************************************************************************** */ -void read_curve_sample(Curve *cu, const ICurvesSchema &schema, const ISampleSelector &sample_sel) +void AbcCurveReader::read_curve_sample(Curve *cu, const ICurvesSchema &schema, const ISampleSelector &sample_sel) { - ICurvesSchema::Sample smp = schema.getValue(sample_sel); + ICurvesSchema::Sample smp; + try { + smp = schema.getValue(sample_sel); + } + catch(Alembic::Util::Exception &ex) { + printf("Alembic: error reading curve sample for '%s/%s' at time %f: %s\n", + m_iobject.getFullName().c_str(), + schema.getName().c_str(), + sample_sel.getRequestedTime(), + ex.what()); + return; + } + const Int32ArraySamplePtr num_vertices = smp.getCurvesNumVertices(); const P3fArraySamplePtr positions = smp.getPositions(); const FloatArraySamplePtr weights = smp.getPositionWeights(); @@ -400,18 +410,31 @@ void read_curve_sample(Curve *cu, const ICurvesSchema &schema, const ISampleSele } } -/* NOTE: Alembic only stores data about control points, but the DerivedMesh +/* NOTE: Alembic only stores data about control points, but the Mesh * passed from the cache modifier contains the displist, which has more data * than the control points, so to avoid corrupting the displist we modify the - * object directly and create a new DerivedMesh from that. Also we might need to + * object directly and create a new Mesh from that. Also we might need to * create new or delete existing NURBS in the curve. */ -DerivedMesh *AbcCurveReader::read_derivedmesh(DerivedMesh * /*dm*/, - const ISampleSelector &sample_sel, - int /*read_flag*/, - const char ** /*err_str*/) +Mesh *AbcCurveReader::read_mesh(Mesh *existing_mesh, + const ISampleSelector &sample_sel, + int /*read_flag*/, + const char **err_str) { - const ICurvesSchema::Sample sample = m_curves_schema.getValue(sample_sel); + ICurvesSchema::Sample sample; + + try { + sample = m_curves_schema.getValue(sample_sel); + } + catch(Alembic::Util::Exception &ex) { + *err_str = "Error reading curve sample; more detail on the console"; + printf("Alembic: error reading curve sample for '%s/%s' at time %f: %s\n", + m_iobject.getFullName().c_str(), + m_curves_schema.getName().c_str(), + sample_sel.getRequestedTime(), + ex.what()); + return existing_mesh; + } const P3fArraySamplePtr &positions = sample.getPositions(); const Int32ArraySamplePtr num_vertices = sample.getCurvesNumVertices(); @@ -450,5 +473,5 @@ DerivedMesh *AbcCurveReader::read_derivedmesh(DerivedMesh * /*dm*/, } } - return CDDM_from_curve(m_object); + return BKE_mesh_new_nomain_from_curve(m_object); } diff --git a/source/blender/alembic/intern/abc_curves.h b/source/blender/alembic/intern/abc_curves.h index 1e7180bbb1f..eb80553620d 100644 --- a/source/blender/alembic/intern/abc_curves.h +++ b/source/blender/alembic/intern/abc_curves.h @@ -36,9 +36,7 @@ class AbcCurveWriter : public AbcObjectWriter { Alembic::AbcGeom::OCurvesSchema::Sample m_sample; public: - AbcCurveWriter(Depsgraph *depsgraph, - Scene *scene, - Object *ob, + AbcCurveWriter(Object *ob, AbcTransformWriter *parent, uint32_t time_sampling, ExportSettings &settings); @@ -60,16 +58,17 @@ public: const char **err_str) const; void readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel); - DerivedMesh *read_derivedmesh(DerivedMesh *dm, - const Alembic::Abc::ISampleSelector &sample_sel, - int read_flag, - const char **err_str); + struct Mesh *read_mesh(struct Mesh *existing_mesh, + const Alembic::Abc::ISampleSelector &sample_sel, + int read_flag, + const char **err_str); + + void read_curve_sample(Curve *cu, + const Alembic::AbcGeom::ICurvesSchema &schema, + const Alembic::Abc::ISampleSelector &sample_selector); + }; /* ************************************************************************** */ -void read_curve_sample(Curve *cu, - const Alembic::AbcGeom::ICurvesSchema &schema, - const Alembic::Abc::ISampleSelector &sample_selector); - #endif /* __ABC_CURVES_H__ */ diff --git a/source/blender/alembic/intern/abc_exporter.cc b/source/blender/alembic/intern/abc_exporter.cc index 093c4de085e..c766720d6cd 100644 --- a/source/blender/alembic/intern/abc_exporter.cc +++ b/source/blender/alembic/intern/abc_exporter.cc @@ -60,6 +60,8 @@ extern "C" { #include "BKE_modifier.h" #include "BKE_particle.h" #include "BKE_scene.h" + +#include "DEG_depsgraph_query.h" } using Alembic::Abc::TimeSamplingPtr; @@ -69,6 +71,8 @@ using Alembic::Abc::OBox3dProperty; ExportSettings::ExportSettings() : scene(NULL) + , view_layer(NULL) + , depsgraph(NULL) , logger() , selected_only(false) , visible_layers_only(false) @@ -168,16 +172,12 @@ static bool export_object(const ExportSettings * const settings, const Base * co /* ************************************************************************** */ -AbcExporter::AbcExporter(Main *bmain, Scene *scene, - Depsgraph *depsgraph, - const char *filename, ExportSettings &settings) +AbcExporter::AbcExporter(Main *bmain, const char *filename, ExportSettings &settings) : m_bmain(bmain) , m_settings(settings) , m_filename(filename) , m_trans_sampling_index(0) , m_shape_sampling_index(0) - , m_scene(scene) - , m_depsgraph(depsgraph) , m_writer(NULL) {} @@ -201,7 +201,7 @@ void AbcExporter::getShutterSamples(unsigned int nr_of_samples, bool time_relative, std::vector<double> &samples) { - Scene *scene = m_scene; /* for use in the FPS macro */ + Scene *scene = m_settings.scene; /* for use in the FPS macro */ samples.clear(); unsigned int frame_offset = time_relative ? m_settings.frame_start : 0; @@ -231,7 +231,7 @@ Alembic::Abc::TimeSamplingPtr AbcExporter::createTimeSampling(double step) Alembic::Abc::TimeSamplingType ts( static_cast<uint32_t>(samples.size()), - 1.0 / m_scene->r.frs_sec); + 1.0 / m_settings.scene->r.frs_sec); /* TODO(Sybren): shouldn't we use the FPS macro here? */ return TimeSamplingPtr(new Alembic::Abc::TimeSampling(ts, samples)); } @@ -265,7 +265,7 @@ void AbcExporter::operator()(float &progress, bool &was_canceled) scene_name = "untitled"; } - Scene *scene = m_scene; + Scene *scene = m_settings.scene; const double fps = FPS; char buf[16]; snprintf(buf, 15, "%f", fps); @@ -297,8 +297,8 @@ void AbcExporter::operator()(float &progress, bool &was_canceled) OBox3dProperty archive_bounds_prop = Alembic::AbcGeom::CreateOArchiveBounds(m_writer->archive(), m_trans_sampling_index); - createTransformWritersHierarchy(m_depsgraph); - createShapeWriters(m_depsgraph); + createTransformWritersHierarchy(); + createShapeWriters(); /* Make a list of frames to export. */ @@ -360,7 +360,7 @@ void AbcExporter::operator()(float &progress, bool &was_canceled) } } -void AbcExporter::createTransformWritersHierarchy(Depsgraph *depsgraph) +void AbcExporter::createTransformWritersHierarchy() { for (Base *base = static_cast<Base *>(m_settings.view_layer->object_bases.first); base; base = base->next) { Object *ob = base->object; @@ -373,27 +373,26 @@ void AbcExporter::createTransformWritersHierarchy(Depsgraph *depsgraph) /* We do not export transforms for objects of these classes. */ break; default: - exploreTransform(depsgraph, base, ob->parent, NULL); + exploreTransform(base, ob->parent, NULL); } } } } -void AbcExporter::exploreTransform(Depsgraph *depsgraph, Base *ob_base, Object *parent, Object *dupliObParent) +void AbcExporter::exploreTransform(Base *ob_base, Object *parent, Object *dupliObParent) { - Object *ob = ob_base->object; - /* If an object isn't exported itself, its duplilist shouldn't be * exported either. */ if (!export_object(&m_settings, ob_base, dupliObParent != NULL)) { return; } - if (object_type_is_exportable(m_scene, ob)) { - createTransformWriter(depsgraph, ob, parent, dupliObParent); + Object *ob = DEG_get_evaluated_object(m_settings.depsgraph, ob_base->object); + if (object_type_is_exportable(m_settings.scene, ob)) { + createTransformWriter(ob, parent, dupliObParent); } - ListBase *lb = object_duplilist(depsgraph, m_scene, ob); + ListBase *lb = object_duplilist(m_settings.depsgraph, m_settings.scene, ob); if (lb) { Base fake_base = *ob_base; // copy flags (like selection state) from the real object. @@ -414,15 +413,15 @@ void AbcExporter::exploreTransform(Depsgraph *depsgraph, Base *ob_base, Object * dupli_parent = (dupli_ob->parent) ? dupli_ob->parent : ob; fake_base.object = dupli_ob; - exploreTransform(depsgraph, &fake_base, dupli_parent, ob); + exploreTransform(&fake_base, dupli_parent, ob); } } - } - free_object_duplilist(lb); + free_object_duplilist(lb); + } } -AbcTransformWriter * AbcExporter::createTransformWriter(Depsgraph *depsgraph, Object *ob, Object *parent, Object *dupliObParent) +AbcTransformWriter * AbcExporter::createTransformWriter(Object *ob, Object *parent, Object *dupliObParent) { /* An object should not be its own parent, or we'll get infinite loops. */ BLI_assert(ob != parent); @@ -457,29 +456,29 @@ AbcTransformWriter * AbcExporter::createTransformWriter(Depsgraph *depsgraph, Ob * return the parent's AbcTransformWriter pointer. */ if (parent->parent) { if (parent == dupliObParent) { - parent_writer = createTransformWriter(depsgraph, parent, parent->parent, NULL); + parent_writer = createTransformWriter(parent, parent->parent, NULL); } else { - parent_writer = createTransformWriter(depsgraph, parent, parent->parent, dupliObParent); + parent_writer = createTransformWriter(parent, parent->parent, dupliObParent); } } else if (parent == dupliObParent) { if (dupliObParent->parent == NULL) { - parent_writer = createTransformWriter(depsgraph, parent, NULL, NULL); + parent_writer = createTransformWriter(parent, NULL, NULL); } else { - parent_writer = createTransformWriter(depsgraph, parent, dupliObParent->parent, dupliObParent->parent); + parent_writer = createTransformWriter(parent, dupliObParent->parent, dupliObParent->parent); } } else { - parent_writer = createTransformWriter(depsgraph, parent, dupliObParent, dupliObParent); + parent_writer = createTransformWriter(parent, dupliObParent, dupliObParent); } BLI_assert(parent_writer); alembic_parent = parent_writer->alembicXform(); } - my_writer = new AbcTransformWriter(depsgraph, ob, alembic_parent, parent_writer, + my_writer = new AbcTransformWriter(ob, alembic_parent, parent_writer, m_trans_sampling_index, m_settings); /* When flattening, the matrix of the dupliobject has to be added. */ @@ -491,14 +490,14 @@ AbcTransformWriter * AbcExporter::createTransformWriter(Depsgraph *depsgraph, Ob return my_writer; } -void AbcExporter::createShapeWriters(Depsgraph *depsgraph) +void AbcExporter::createShapeWriters() { for (Base *base = static_cast<Base *>(m_settings.view_layer->object_bases.first); base; base = base->next) { - exploreObject(depsgraph, base, NULL); + exploreObject(base, NULL); } } -void AbcExporter::exploreObject(Depsgraph *depsgraph, Base *ob_base, Object *dupliObParent) +void AbcExporter::exploreObject(Base *ob_base, Object *dupliObParent) { /* If an object isn't exported itself, its duplilist shouldn't be * exported either. */ @@ -506,10 +505,10 @@ void AbcExporter::exploreObject(Depsgraph *depsgraph, Base *ob_base, Object *dup return; } - createShapeWriter(ob_base, dupliObParent); - - Object *ob = ob_base->object; - ListBase *lb = object_duplilist(depsgraph, m_scene, ob); + Object *ob = DEG_get_evaluated_object(m_settings.depsgraph, ob_base->object); + createShapeWriter(ob, dupliObParent); + + ListBase *lb = object_duplilist(m_settings.depsgraph, m_settings.scene, ob); if (lb) { Base fake_base = *ob_base; // copy flags (like selection state) from the real object. @@ -524,12 +523,12 @@ void AbcExporter::exploreObject(Depsgraph *depsgraph, Base *ob_base, Object *dup } if (link->type == OB_DUPLICOLLECTION) { fake_base.object = link->ob; - exploreObject(depsgraph, &fake_base, ob); + exploreObject(&fake_base, ob); } } - } - free_object_duplilist(lb); + free_object_duplilist(lb); + } } void AbcExporter::createParticleSystemsWriters(Object *ob, AbcTransformWriter *xform) @@ -547,19 +546,17 @@ void AbcExporter::createParticleSystemsWriters(Object *ob, AbcTransformWriter *x if (m_settings.export_hair && psys->part->type == PART_HAIR) { m_settings.export_child_hairs = true; - m_shapes.push_back(new AbcHairWriter(m_depsgraph, m_scene, ob, xform, m_shape_sampling_index, m_settings, psys)); + m_shapes.push_back(new AbcHairWriter(ob, xform, m_shape_sampling_index, m_settings, psys)); } else if (m_settings.export_particles && psys->part->type == PART_EMITTER) { - m_shapes.push_back(new AbcPointsWriter(m_depsgraph, m_scene, ob, xform, m_shape_sampling_index, m_settings, psys)); + m_shapes.push_back(new AbcPointsWriter(ob, xform, m_shape_sampling_index, m_settings, psys)); } } } -void AbcExporter::createShapeWriter(Base *ob_base, Object *dupliObParent) +void AbcExporter::createShapeWriter(Object *ob, Object *dupliObParent) { - Object *ob = ob_base->object; - - if (!object_type_is_exportable(m_scene, ob)) { + if (!object_type_is_exportable(m_settings.scene, ob)) { return; } @@ -590,7 +587,7 @@ void AbcExporter::createShapeWriter(Base *ob_base, Object *dupliObParent) return; } - m_shapes.push_back(new AbcMeshWriter(m_depsgraph, m_scene, ob, xform, m_shape_sampling_index, m_settings)); + m_shapes.push_back(new AbcMeshWriter(ob, xform, m_shape_sampling_index, m_settings)); break; } case OB_SURF: @@ -601,7 +598,7 @@ void AbcExporter::createShapeWriter(Base *ob_base, Object *dupliObParent) return; } - m_shapes.push_back(new AbcNurbsWriter(m_depsgraph, m_scene, ob, xform, m_shape_sampling_index, m_settings)); + m_shapes.push_back(new AbcNurbsWriter(ob, xform, m_shape_sampling_index, m_settings)); break; } case OB_CURVE: @@ -612,7 +609,7 @@ void AbcExporter::createShapeWriter(Base *ob_base, Object *dupliObParent) return; } - m_shapes.push_back(new AbcCurveWriter(m_depsgraph, m_scene, ob, xform, m_shape_sampling_index, m_settings)); + m_shapes.push_back(new AbcCurveWriter(ob, xform, m_shape_sampling_index, m_settings)); break; } case OB_CAMERA: @@ -620,7 +617,7 @@ void AbcExporter::createShapeWriter(Base *ob_base, Object *dupliObParent) Camera *cam = static_cast<Camera *>(ob->data); if (cam->type == CAM_PERSP) { - m_shapes.push_back(new AbcCameraWriter(m_depsgraph, m_scene, ob, xform, m_shape_sampling_index, m_settings)); + m_shapes.push_back(new AbcCameraWriter(ob, xform, m_shape_sampling_index, m_settings)); } break; @@ -633,7 +630,7 @@ void AbcExporter::createShapeWriter(Base *ob_base, Object *dupliObParent) } m_shapes.push_back(new AbcMBallWriter( - m_bmain, m_depsgraph, m_scene, ob, xform, + m_bmain, ob, xform, m_shape_sampling_index, m_settings)); break; } @@ -653,7 +650,7 @@ AbcTransformWriter *AbcExporter::getXForm(const std::string &name) void AbcExporter::setCurrentFrame(Main *bmain, double t) { - m_scene->r.cfra = static_cast<int>(t); - m_scene->r.subframe = static_cast<float>(t) - m_scene->r.cfra; - BKE_scene_graph_update_for_newframe(m_depsgraph, bmain); + m_settings.scene->r.cfra = static_cast<int>(t); + m_settings.scene->r.subframe = static_cast<float>(t) - m_settings.scene->r.cfra; + BKE_scene_graph_update_for_newframe(m_settings.depsgraph, bmain); } diff --git a/source/blender/alembic/intern/abc_exporter.h b/source/blender/alembic/intern/abc_exporter.h index c891824a114..a92e426292c 100644 --- a/source/blender/alembic/intern/abc_exporter.h +++ b/source/blender/alembic/intern/abc_exporter.h @@ -92,9 +92,6 @@ class AbcExporter { unsigned int m_trans_sampling_index, m_shape_sampling_index; - Scene *m_scene; - Depsgraph *m_depsgraph; - ArchiveWriter *m_writer; /* mapping from name to transform writer */ @@ -104,8 +101,7 @@ class AbcExporter { std::vector<AbcObjectWriter *> m_shapes; public: - AbcExporter(Main *bmain, Scene *scene, Depsgraph *depsgraph, - const char *filename, ExportSettings &settings); + AbcExporter(Main *bmain, const char *filename, ExportSettings &settings); ~AbcExporter(); void operator()(float &progress, bool &was_canceled); @@ -119,12 +115,12 @@ protected: private: Alembic::Abc::TimeSamplingPtr createTimeSampling(double step); - void createTransformWritersHierarchy(Depsgraph *depsgraph); - AbcTransformWriter * createTransformWriter(Depsgraph *depsgraph, Object *ob, Object *parent, Object *dupliObParent); - void exploreTransform(Depsgraph *depsgraph, Base *ob_base, Object *parent, Object *dupliObParent); - void exploreObject(Depsgraph *depsgraph, Base *ob_base, Object *dupliObParent); - void createShapeWriters(Depsgraph *depsgraph); - void createShapeWriter(Base *ob_base, Object *dupliObParent); + void createTransformWritersHierarchy(); + AbcTransformWriter * createTransformWriter(Object *ob, Object *parent, Object *dupliObParent); + void exploreTransform(Base *ob_base, Object *parent, Object *dupliObParent); + void exploreObject(Base *ob_base, Object *dupliObParent); + void createShapeWriters(); + void createShapeWriter(Object *ob, Object *dupliObParent); void createParticleSystemsWriters(Object *ob, AbcTransformWriter *xform); AbcTransformWriter *getXForm(const std::string &name); diff --git a/source/blender/alembic/intern/abc_hair.cc b/source/blender/alembic/intern/abc_hair.cc index e7cc474e2e8..83a46a330fd 100644 --- a/source/blender/alembic/intern/abc_hair.cc +++ b/source/blender/alembic/intern/abc_hair.cc @@ -30,12 +30,16 @@ extern "C" { #include "MEM_guardedalloc.h" +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" #include "DNA_modifier_types.h" #include "BLI_listbase.h" #include "BLI_math_geom.h" -#include "BKE_DerivedMesh.h" +#include "BKE_library.h" +#include "BKE_mesh.h" +#include "BKE_mesh_runtime.h" #include "BKE_object.h" #include "BKE_particle.h" } @@ -49,14 +53,12 @@ using Alembic::AbcGeom::OV2fGeomParam; /* ************************************************************************** */ -AbcHairWriter::AbcHairWriter(Depsgraph *depsgraph, - Scene *scene, - Object *ob, +AbcHairWriter::AbcHairWriter(Object *ob, AbcTransformWriter *parent, uint32_t time_sampling, ExportSettings &settings, ParticleSystem *psys) - : AbcObjectWriter(depsgraph, scene, ob, time_sampling, settings, parent) + : AbcObjectWriter(ob, time_sampling, settings, parent) , m_uv_warning_shown(false) { m_psys = psys; @@ -70,15 +72,8 @@ void AbcHairWriter::do_write() if (!m_psys) { return; } - - ParticleSystemModifierData *psmd = psys_get_modifier(m_object, m_psys); - - if (!psmd->mesh_final) { - return; - } - - DerivedMesh *dm = mesh_create_derived_render(m_depsgraph, m_scene, m_object, CD_MASK_MESH); - DM_ensure_tessface(dm); + Mesh *mesh = mesh_get_eval_final(m_settings.depsgraph, m_settings.scene, m_object, CD_MASK_MESH); + BKE_mesh_tessface_ensure(mesh); std::vector<Imath::V3f> verts; std::vector<int32_t> hvertices; @@ -88,15 +83,13 @@ void AbcHairWriter::do_write() if (m_psys->pathcache) { ParticleSettings *part = m_psys->part; - write_hair_sample(dm, part, verts, norm_values, uv_values, hvertices); + write_hair_sample(mesh, part, verts, norm_values, uv_values, hvertices); if (m_settings.export_child_hairs && m_psys->childcache) { - write_hair_child_sample(dm, part, verts, norm_values, uv_values, hvertices); + write_hair_child_sample(mesh, part, verts, norm_values, uv_values, hvertices); } } - dm->release(dm); - Alembic::Abc::P3fArraySample iPos(verts); m_sample = OCurvesSchema::Sample(iPos, hvertices); m_sample.setBasis(Alembic::AbcGeom::kNoBasis); @@ -119,7 +112,7 @@ void AbcHairWriter::do_write() m_schema.set(m_sample); } -void AbcHairWriter::write_hair_sample(DerivedMesh *dm, +void AbcHairWriter::write_hair_sample(Mesh *mesh, ParticleSettings *part, std::vector<Imath::V3f> &verts, std::vector<Imath::V3f> &norm_values, @@ -130,9 +123,9 @@ void AbcHairWriter::write_hair_sample(DerivedMesh *dm, float inv_mat[4][4]; invert_m4_m4_safe(inv_mat, m_object->obmat); - MTFace *mtface = static_cast<MTFace *>(CustomData_get_layer(&dm->faceData, CD_MTFACE)); - MFace *mface = dm->getTessFaceArray(dm); - MVert *mverts = dm->getVertArray(dm); + MTFace *mtface = mesh->mtface; + MFace *mface = mesh->mface; + MVert *mverts = mesh->mvert; if ((!mtface || !mface) && !m_uv_warning_shown) { std::fprintf(stderr, "Warning, no UV set found for underlying geometry of %s.\n", @@ -152,11 +145,13 @@ void AbcHairWriter::write_hair_sample(DerivedMesh *dm, /* underlying info for faces-only emission */ path = cache[p]; + /* Write UV and normal vectors */ if (part->from == PART_FROM_FACE && mtface) { const int num = pa->num_dmcache >= 0 ? pa->num_dmcache : pa->num; - if (num < dm->getNumTessFaces(dm)) { - MFace *face = static_cast<MFace *>(dm->getTessFaceData(dm, num, CD_MFACE)); + if (num < mesh->totface) { + /* TODO(Sybren): check whether the NULL check here and if(mface) are actually required */ + MFace *face = mface == NULL ? NULL : &mface[num]; MTFace *tface = mtface + num; if (mface) { @@ -172,7 +167,7 @@ void AbcHairWriter::write_hair_sample(DerivedMesh *dm, } } else { - std::fprintf(stderr, "Particle to faces overflow (%d/%d)\n", num, dm->getNumTessFaces(dm)); + std::fprintf(stderr, "Particle to faces overflow (%d/%d)\n", num, mesh->totface); } } else if (part->from == PART_FROM_VERT && mtface) { @@ -180,8 +175,8 @@ void AbcHairWriter::write_hair_sample(DerivedMesh *dm, const int num = (pa->num_dmcache >= 0) ? pa->num_dmcache : pa->num; /* iterate over all faces to find a corresponding underlying UV */ - for (int n = 0; n < dm->getNumTessFaces(dm); ++n) { - MFace *face = static_cast<MFace *>(dm->getTessFaceData(dm, n, CD_MFACE)); + for (int n = 0; n < mesh->totface; ++n) { + MFace *face = &mface[n]; MTFace *tface = mtface + n; unsigned int vtx[4]; vtx[0] = face->v1; @@ -217,7 +212,7 @@ void AbcHairWriter::write_hair_sample(DerivedMesh *dm, int steps = path->segments + 1; hvertices.push_back(steps); - for (k = 0; k < steps; ++k) { + for (k = 0; k < steps; ++k, ++path) { float vert[3]; copy_v3_v3(vert, path->co); mul_m4_v3(inv_mat, vert); @@ -225,12 +220,11 @@ void AbcHairWriter::write_hair_sample(DerivedMesh *dm, /* Convert Z-up to Y-up. */ verts.push_back(Imath::V3f(vert[0], vert[2], -vert[1])); - ++path; } } } -void AbcHairWriter::write_hair_child_sample(DerivedMesh *dm, +void AbcHairWriter::write_hair_child_sample(Mesh *mesh, ParticleSettings *part, std::vector<Imath::V3f> &verts, std::vector<Imath::V3f> &norm_values, @@ -241,8 +235,8 @@ void AbcHairWriter::write_hair_child_sample(DerivedMesh *dm, float inv_mat[4][4]; invert_m4_m4_safe(inv_mat, m_object->obmat); - MTFace *mtface = static_cast<MTFace *>(CustomData_get_layer(&dm->faceData, CD_MTFACE)); - MVert *mverts = dm->getVertArray(dm); + MTFace *mtface = mesh->mtface; + MVert *mverts = mesh->mvert; ParticleCacheKey **cache = m_psys->childcache; ParticleCacheKey *path; @@ -265,7 +259,7 @@ void AbcHairWriter::write_hair_child_sample(DerivedMesh *dm, continue; } - MFace *face = static_cast<MFace *>(dm->getTessFaceData(dm, num, CD_MFACE)); + MFace *face = &mesh->mface[num]; MTFace *tface = mtface + num; float r_uv[2], tmpnor[3], mapfw[4], vec[3]; diff --git a/source/blender/alembic/intern/abc_hair.h b/source/blender/alembic/intern/abc_hair.h index 5627f7726e6..e2dffd4edaf 100644 --- a/source/blender/alembic/intern/abc_hair.h +++ b/source/blender/alembic/intern/abc_hair.h @@ -25,7 +25,6 @@ #include "abc_object.h" -struct DerivedMesh; struct ParticleSettings; struct ParticleSystem; @@ -40,9 +39,7 @@ class AbcHairWriter : public AbcObjectWriter { bool m_uv_warning_shown; public: - AbcHairWriter(Depsgraph *depsgraph, - Scene *scene, - Object *ob, + AbcHairWriter(Object *ob, AbcTransformWriter *parent, uint32_t time_sampling, ExportSettings &settings, @@ -51,14 +48,14 @@ public: private: virtual void do_write(); - void write_hair_sample(DerivedMesh *dm, + void write_hair_sample(struct Mesh *mesh, ParticleSettings *part, std::vector<Imath::V3f> &verts, std::vector<Imath::V3f> &norm_values, std::vector<Imath::V2f> &uv_values, std::vector<int32_t> &hvertices); - void write_hair_child_sample(DerivedMesh *dm, + void write_hair_child_sample(struct Mesh *mesh, ParticleSettings *part, std::vector<Imath::V3f> &verts, std::vector<Imath::V3f> &norm_values, diff --git a/source/blender/alembic/intern/abc_mball.cc b/source/blender/alembic/intern/abc_mball.cc index 1df55712abe..d6e54407922 100644 --- a/source/blender/alembic/intern/abc_mball.cc +++ b/source/blender/alembic/intern/abc_mball.cc @@ -42,13 +42,11 @@ extern "C" { AbcMBallWriter::AbcMBallWriter( Main *bmain, - Depsgraph *depsgraph, - Scene *scene, Object *ob, AbcTransformWriter *parent, uint32_t time_sampling, ExportSettings &settings) - : AbcObjectWriter(depsgraph, scene, ob, time_sampling, settings, parent) + : AbcObjectWriter(ob, time_sampling, settings, parent) , m_bmain(bmain) { m_is_animated = isAnimated(); @@ -58,8 +56,7 @@ AbcMBallWriter::AbcMBallWriter( sizeof(CurveCache), "CurveCache for AbcMBallWriter"); - m_mesh_writer = new AbcMeshWriter(depsgraph, scene, m_mesh_ob, parent, - time_sampling, settings); + m_mesh_writer = new AbcMeshWriter(m_mesh_ob, parent, time_sampling, settings); m_mesh_writer->setIsAnimated(m_is_animated); } @@ -101,7 +98,7 @@ void AbcMBallWriter::do_write() * only contains for_render flag. As soon as CoW is * implemented, this is to be rethinked. */ - BKE_displist_make_mball_forRender(m_depsgraph, m_scene, m_object, &disp); + BKE_displist_make_mball_forRender(m_settings.depsgraph, m_settings.scene, m_object, &disp); BKE_mesh_from_metaball(&disp, tmpmesh); BKE_displist_free(&disp); diff --git a/source/blender/alembic/intern/abc_mball.h b/source/blender/alembic/intern/abc_mball.h index bae4b6bcb76..07cb1908e95 100644 --- a/source/blender/alembic/intern/abc_mball.h +++ b/source/blender/alembic/intern/abc_mball.h @@ -43,8 +43,6 @@ class AbcMBallWriter : public AbcObjectWriter { public: AbcMBallWriter( Main *bmain, - Depsgraph *depsgraph, - Scene *scene, Object *ob, AbcTransformWriter *parent, uint32_t time_sampling, diff --git a/source/blender/alembic/intern/abc_mesh.cc b/source/blender/alembic/intern/abc_mesh.cc index d52d7f06048..2b739837239 100644 --- a/source/blender/alembic/intern/abc_mesh.cc +++ b/source/blender/alembic/intern/abc_mesh.cc @@ -30,6 +30,7 @@ extern "C" { #include "DNA_material_types.h" #include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" #include "DNA_modifier_types.h" #include "DNA_object_fluidsim_types.h" #include "DNA_object_types.h" @@ -37,10 +38,10 @@ extern "C" { #include "BLI_math_geom.h" #include "BLI_string.h" -#include "BKE_cdderivedmesh.h" #include "BKE_main.h" #include "BKE_material.h" #include "BKE_mesh.h" +#include "BKE_mesh_runtime.h" #include "BKE_modifier.h" #include "BKE_object.h" @@ -51,6 +52,8 @@ extern "C" { #include "bmesh.h" #include "bmesh_tools.h" + +#include "DEG_depsgraph_query.h" } using Alembic::Abc::FloatArraySample; @@ -103,27 +106,27 @@ using Alembic::AbcGeom::IN3fGeomParam; /* NOTE: Alembic's polygon winding order is clockwise, to match with Renderman. */ -static void get_vertices(DerivedMesh *dm, std::vector<Imath::V3f> &points) +static void get_vertices(struct Mesh *mesh, std::vector<Imath::V3f> &points) { points.clear(); - points.resize(dm->getNumVerts(dm)); + points.resize(mesh->totvert); - MVert *verts = dm->getVertArray(dm); + MVert *verts = mesh->mvert; - for (int i = 0, e = dm->getNumVerts(dm); i < e; ++i) { + for (int i = 0, e = mesh->totvert; i < e; ++i) { copy_yup_from_zup(points[i].getValue(), verts[i].co); } } -static void get_topology(DerivedMesh *dm, +static void get_topology(struct Mesh *mesh, std::vector<int32_t> &poly_verts, std::vector<int32_t> &loop_counts, bool &smooth_normal) { - const int num_poly = dm->getNumPolys(dm); - const int num_loops = dm->getNumLoops(dm); - MLoop *mloop = dm->getLoopArray(dm); - MPoly *mpoly = dm->getPolyArray(dm); + const int num_poly = mesh->totpoly; + const int num_loops = mesh->totloop; + MLoop *mloop = mesh->mloop; + MPoly *mpoly = mesh->mpoly; poly_verts.clear(); loop_counts.clear(); @@ -145,7 +148,7 @@ static void get_topology(DerivedMesh *dm, } } -static void get_creases(DerivedMesh *dm, +static void get_creases(struct Mesh *mesh, std::vector<int32_t> &indices, std::vector<int32_t> &lengths, std::vector<float> &sharpnesses) @@ -156,9 +159,9 @@ static void get_creases(DerivedMesh *dm, lengths.clear(); sharpnesses.clear(); - MEdge *edge = dm->getEdgeArray(dm); + MEdge *edge = mesh->medge; - for (int i = 0, e = dm->getNumEdges(dm); i < e; ++i) { + for (int i = 0, e = mesh->totedge; i < e; ++i) { const float sharpness = static_cast<float>(edge[i].crease) * factor; if (sharpness != 0.0f) { @@ -171,41 +174,40 @@ static void get_creases(DerivedMesh *dm, lengths.resize(sharpnesses.size(), 2); } -static void get_vertex_normals(DerivedMesh *dm, std::vector<Imath::V3f> &normals) +static void get_vertex_normals(struct Mesh *mesh, std::vector<Imath::V3f> &normals) { normals.clear(); - normals.resize(dm->getNumVerts(dm)); + normals.resize(mesh->totvert); - MVert *verts = dm->getVertArray(dm); + MVert *verts = mesh->mvert; float no[3]; - for (int i = 0, e = dm->getNumVerts(dm); i < e; ++i) { + for (int i = 0, e = mesh->totvert; i < e; ++i) { normal_short_to_float_v3(no, verts[i].no); copy_yup_from_zup(normals[i].getValue(), no); } } -static void get_loop_normals(DerivedMesh *dm, std::vector<Imath::V3f> &normals) +static void get_loop_normals(struct Mesh *mesh, std::vector<Imath::V3f> &normals) { - MPoly *mpoly = dm->getPolyArray(dm); - MPoly *mp = mpoly; + MPoly *mp = mesh->mpoly; - MLoop *mloop = dm->getLoopArray(dm); + MLoop *mloop = mesh->mloop; MLoop *ml = mloop; - MVert *verts = dm->getVertArray(dm); + MVert *verts = mesh->mvert; - const float (*lnors)[3] = static_cast<float(*)[3]>(dm->getLoopDataArray(dm, CD_NORMAL)); + const float (*lnors)[3] = static_cast<float(*)[3]>(CustomData_get_layer(&mesh->ldata, CD_NORMAL)); normals.clear(); - normals.resize(dm->getNumLoops(dm)); + normals.resize(mesh->totloop); unsigned loop_index = 0; /* NOTE: data needs to be written in the reverse order. */ if (lnors) { - for (int i = 0, e = dm->getNumPolys(dm); i < e; ++i, ++mp) { + for (int i = 0, e = mesh->totpoly; i < e; ++i, ++mp) { ml = mloop + mp->loopstart + (mp->totloop - 1); for (int j = 0; j < mp->totloop; --ml, ++j, ++loop_index) { @@ -217,7 +219,7 @@ static void get_loop_normals(DerivedMesh *dm, std::vector<Imath::V3f> &normals) else { float no[3]; - for (int i = 0, e = dm->getNumPolys(dm); i < e; ++i, ++mp) { + for (int i = 0, e = mesh->totpoly; i < e; ++i, ++mp) { ml = mloop + mp->loopstart + (mp->totloop - 1); /* Flat shaded, use common normal for all verts. */ @@ -286,13 +288,11 @@ static ModifierData *get_liquid_sim_modifier(Scene *scene, Object *ob) /* ************************************************************************** */ -AbcMeshWriter::AbcMeshWriter(Depsgraph *depsgraph, - Scene *scene, - Object *ob, +AbcMeshWriter::AbcMeshWriter(Object *ob, AbcTransformWriter *parent, uint32_t time_sampling, ExportSettings &settings) - : AbcObjectWriter(depsgraph, scene, ob, time_sampling, settings, parent) + : AbcObjectWriter(ob, time_sampling, settings, parent) { m_is_animated = isAnimated(); m_subsurf_mod = NULL; @@ -304,11 +304,11 @@ AbcMeshWriter::AbcMeshWriter(Depsgraph *depsgraph, } if (!m_settings.apply_subdiv) { - m_subsurf_mod = get_subsurf_modifier(m_scene, m_object); + m_subsurf_mod = get_subsurf_modifier(m_settings.scene, m_object); m_is_subd = (m_subsurf_mod != NULL); } - m_is_liquid = (get_liquid_sim_modifier(m_scene, m_object) != NULL); + m_is_liquid = (get_liquid_sim_modifier(m_settings.scene, m_object) != NULL); while (parent->alembicXform().getChildHeader(m_name)) { m_name.append("_"); @@ -369,36 +369,37 @@ void AbcMeshWriter::do_write() if (!m_first_frame && !m_is_animated) return; - DerivedMesh *dm = getFinalMesh(); + bool needsfree; + struct Mesh *mesh = getFinalMesh(needsfree); try { if (m_settings.use_subdiv_schema && m_subdiv_schema.valid()) { - writeSubD(dm); + writeSubD(mesh); } else { - writeMesh(dm); + writeMesh(mesh); } - freeMesh(dm); + if (needsfree) BKE_id_free(NULL, mesh); } catch (...) { - freeMesh(dm); + if (needsfree) BKE_id_free(NULL, mesh); throw; } } -void AbcMeshWriter::writeMesh(DerivedMesh *dm) +void AbcMeshWriter::writeMesh(struct Mesh *mesh) { std::vector<Imath::V3f> points, normals; std::vector<int32_t> poly_verts, loop_counts; bool smooth_normal = false; - get_vertices(dm, points); - get_topology(dm, poly_verts, loop_counts, smooth_normal); + get_vertices(mesh, points); + get_topology(mesh, poly_verts, loop_counts, smooth_normal); if (m_first_frame && m_settings.export_face_sets) { - writeFaceSets(dm, m_mesh_schema); + writeFaceSets(mesh, m_mesh_schema); } m_mesh_sample = OPolyMeshSchema::Sample(V3fArraySample(points), @@ -407,7 +408,7 @@ void AbcMeshWriter::writeMesh(DerivedMesh *dm) UVSample sample; if (m_first_frame && m_settings.export_uvs) { - const char *name = get_uv_sample(sample, m_custom_data_config, &dm->loopData); + const char *name = get_uv_sample(sample, m_custom_data_config, &mesh->ldata); if (!sample.indices.empty() && !sample.uvs.empty()) { OV2fGeomParam::Sample uv_sample; @@ -419,15 +420,15 @@ void AbcMeshWriter::writeMesh(DerivedMesh *dm) m_mesh_sample.setUVs(uv_sample); } - write_custom_data(m_mesh_schema.getArbGeomParams(), m_custom_data_config, &dm->loopData, CD_MLOOPUV); + write_custom_data(m_mesh_schema.getArbGeomParams(), m_custom_data_config, &mesh->ldata, CD_MLOOPUV); } if (m_settings.export_normals) { if (smooth_normal) { - get_loop_normals(dm, normals); + get_loop_normals(mesh, normals); } else { - get_vertex_normals(dm, normals); + get_vertex_normals(mesh, normals); } ON3fGeomParam::Sample normals_sample; @@ -441,7 +442,7 @@ void AbcMeshWriter::writeMesh(DerivedMesh *dm) if (m_is_liquid) { std::vector<Imath::V3f> velocities; - getVelocities(dm, velocities); + getVelocities(mesh, velocities); m_mesh_sample.setVelocities(V3fArraySample(velocities)); } @@ -450,10 +451,10 @@ void AbcMeshWriter::writeMesh(DerivedMesh *dm) m_mesh_schema.set(m_mesh_sample); - writeArbGeoParams(dm); + writeArbGeoParams(mesh); } -void AbcMeshWriter::writeSubD(DerivedMesh *dm) +void AbcMeshWriter::writeSubD(struct Mesh *mesh) { std::vector<float> crease_sharpness; std::vector<Imath::V3f> points; @@ -462,12 +463,12 @@ void AbcMeshWriter::writeSubD(DerivedMesh *dm) bool smooth_normal = false; - get_vertices(dm, points); - get_topology(dm, poly_verts, loop_counts, smooth_normal); - get_creases(dm, crease_indices, crease_lengths, crease_sharpness); + get_vertices(mesh, points); + get_topology(mesh, poly_verts, loop_counts, smooth_normal); + get_creases(mesh, crease_indices, crease_lengths, crease_sharpness); if (m_first_frame && m_settings.export_face_sets) { - writeFaceSets(dm, m_subdiv_schema); + writeFaceSets(mesh, m_subdiv_schema); } m_subdiv_sample = OSubDSchema::Sample(V3fArraySample(points), @@ -476,7 +477,7 @@ void AbcMeshWriter::writeSubD(DerivedMesh *dm) UVSample sample; if (m_first_frame && m_settings.export_uvs) { - const char *name = get_uv_sample(sample, m_custom_data_config, &dm->loopData); + const char *name = get_uv_sample(sample, m_custom_data_config, &mesh->ldata); if (!sample.indices.empty() && !sample.uvs.empty()) { OV2fGeomParam::Sample uv_sample; @@ -488,7 +489,7 @@ void AbcMeshWriter::writeSubD(DerivedMesh *dm) m_subdiv_sample.setUVs(uv_sample); } - write_custom_data(m_subdiv_schema.getArbGeomParams(), m_custom_data_config, &dm->loopData, CD_MLOOPUV); + write_custom_data(m_subdiv_schema.getArbGeomParams(), m_custom_data_config, &mesh->ldata, CD_MLOOPUV); } if (!crease_indices.empty()) { @@ -500,11 +501,11 @@ void AbcMeshWriter::writeSubD(DerivedMesh *dm) m_subdiv_sample.setSelfBounds(bounds()); m_subdiv_schema.set(m_subdiv_sample); - writeArbGeoParams(dm); + writeArbGeoParams(mesh); } template <typename Schema> -void AbcMeshWriter::writeFaceSets(DerivedMesh *dm, Schema &schema) +void AbcMeshWriter::writeFaceSets(struct Mesh *dm, Schema &schema) { std::map< std::string, std::vector<int32_t> > geo_groups; getGeoGroups(dm, geo_groups); @@ -518,14 +519,17 @@ void AbcMeshWriter::writeFaceSets(DerivedMesh *dm, Schema &schema) } } -DerivedMesh *AbcMeshWriter::getFinalMesh() +Mesh *AbcMeshWriter::getFinalMesh(bool &r_needsfree) { /* We don't want subdivided mesh data */ if (m_subsurf_mod) { m_subsurf_mod->mode |= eModifierMode_DisableTemporary; } - DerivedMesh *dm = mesh_create_derived_render(m_depsgraph, m_scene, m_object, CD_MASK_MESH); + Scene *scene = DEG_get_evaluated_scene(m_settings.depsgraph); + Object *ob_eval = DEG_get_evaluated_object(m_settings.depsgraph, m_object); + struct Mesh *mesh = mesh_get_eval_final(m_settings.depsgraph, scene, ob_eval, CD_MASK_MESH); + r_needsfree = false; if (m_subsurf_mod) { m_subsurf_mod->mode &= ~eModifierMode_DisableTemporary; @@ -536,34 +540,31 @@ DerivedMesh *AbcMeshWriter::getFinalMesh() const int quad_method = m_settings.quad_method; const int ngon_method = m_settings.ngon_method; - BMesh *bm = DM_to_bmesh(dm, true); + struct BMeshCreateParams bmcp = {false}; + struct BMeshFromMeshParams bmfmp = {true, false, false, 0}; + BMesh *bm = BKE_mesh_to_bmesh_ex(mesh, &bmcp, &bmfmp); BM_mesh_triangulate(bm, quad_method, ngon_method, tag_only, NULL, NULL, NULL); - DerivedMesh *result = CDDM_from_bmesh(bm, false); + struct BMeshToMeshParams bmmp = {0}; + Mesh *result = BKE_bmesh_to_mesh_nomain(bm, &bmmp); BM_mesh_free(bm); - freeMesh(dm); - - dm = result; + mesh = result; + r_needsfree = true; } m_custom_data_config.pack_uvs = m_settings.pack_uv; - m_custom_data_config.mpoly = dm->getPolyArray(dm); - m_custom_data_config.mloop = dm->getLoopArray(dm); - m_custom_data_config.totpoly = dm->getNumPolys(dm); - m_custom_data_config.totloop = dm->getNumLoops(dm); - m_custom_data_config.totvert = dm->getNumVerts(dm); + m_custom_data_config.mpoly = mesh->mpoly; + m_custom_data_config.mloop = mesh->mloop; + m_custom_data_config.totpoly = mesh->totpoly; + m_custom_data_config.totloop = mesh->totloop; + m_custom_data_config.totvert = mesh->totvert; - return dm; -} - -void AbcMeshWriter::freeMesh(DerivedMesh *dm) -{ - dm->release(dm); + return mesh; } -void AbcMeshWriter::writeArbGeoParams(DerivedMesh *dm) +void AbcMeshWriter::writeArbGeoParams(struct Mesh *dm) { if (m_is_liquid) { /* We don't need anything more for liquid meshes. */ @@ -572,22 +573,22 @@ void AbcMeshWriter::writeArbGeoParams(DerivedMesh *dm) if (m_first_frame && m_settings.export_vcols) { if (m_subdiv_schema.valid()) { - write_custom_data(m_subdiv_schema.getArbGeomParams(), m_custom_data_config, &dm->loopData, CD_MLOOPCOL); + write_custom_data(m_subdiv_schema.getArbGeomParams(), m_custom_data_config, &dm->ldata, CD_MLOOPCOL); } else { - write_custom_data(m_mesh_schema.getArbGeomParams(), m_custom_data_config, &dm->loopData, CD_MLOOPCOL); + write_custom_data(m_mesh_schema.getArbGeomParams(), m_custom_data_config, &dm->ldata, CD_MLOOPCOL); } } } -void AbcMeshWriter::getVelocities(DerivedMesh *dm, std::vector<Imath::V3f> &vels) +void AbcMeshWriter::getVelocities(struct Mesh *mesh, std::vector<Imath::V3f> &vels) { - const int totverts = dm->getNumVerts(dm); + const int totverts = mesh->totvert; vels.clear(); vels.resize(totverts); - ModifierData *md = get_liquid_sim_modifier(m_scene, m_object); + ModifierData *md = get_liquid_sim_modifier(m_settings.scene, m_object); FluidsimModifierData *fmd = reinterpret_cast<FluidsimModifierData *>(md); FluidsimSettings *fss = fmd->fss; @@ -605,11 +606,11 @@ void AbcMeshWriter::getVelocities(DerivedMesh *dm, std::vector<Imath::V3f> &vels } void AbcMeshWriter::getGeoGroups( - DerivedMesh *dm, + struct Mesh *mesh, std::map<std::string, std::vector<int32_t> > &geo_groups) { - const int num_poly = dm->getNumPolys(dm); - MPoly *polygons = dm->getPolyArray(dm); + const int num_poly = mesh->totpoly; + MPoly *polygons = mesh->mpoly; for (int i = 0; i < num_poly; ++i) { MPoly ¤t_poly = polygons[i]; @@ -638,7 +639,7 @@ void AbcMeshWriter::getGeoGroups( std::vector<int32_t> faceArray; - for (int i = 0, e = dm->getNumTessFaces(dm); i < e; ++i) { + for (int i = 0, e = mesh->totface; i < e; ++i) { faceArray.push_back(i); } @@ -873,11 +874,11 @@ ABC_INLINE void read_normals_params(AbcMeshData &abc_data, } } -static bool check_smooth_poly_flag(DerivedMesh *dm) +static bool check_smooth_poly_flag(Mesh *mesh) { - MPoly *mpolys = dm->getPolyArray(dm); + MPoly *mpolys = mesh->mpoly; - for (int i = 0, e = dm->getNumPolys(dm); i < e; ++i) { + for (int i = 0, e = mesh->totpoly; i < e; ++i) { MPoly &poly = mpolys[i]; if ((poly.flag & ME_SMOOTH) != 0) { @@ -888,11 +889,11 @@ static bool check_smooth_poly_flag(DerivedMesh *dm) return false; } -static void set_smooth_poly_flag(DerivedMesh *dm) +static void set_smooth_poly_flag(Mesh *mesh) { - MPoly *mpolys = dm->getPolyArray(dm); + MPoly *mpolys = mesh->mpoly; - for (int i = 0, e = dm->getNumPolys(dm); i < e; ++i) { + for (int i = 0, e = mesh->totpoly; i < e; ++i) { MPoly &poly = mpolys[i]; poly.flag |= ME_SMOOTH; } @@ -900,7 +901,7 @@ static void set_smooth_poly_flag(DerivedMesh *dm) static void *add_customdata_cb(void *user_data, const char *name, int data_type) { - DerivedMesh *dm = static_cast<DerivedMesh *>(user_data); + Mesh *mesh = static_cast<Mesh *>(user_data); CustomDataType cd_data_type = static_cast<CustomDataType>(data_type); void *cd_ptr; CustomData *loopdata; @@ -911,7 +912,7 @@ static void *add_customdata_cb(void *user_data, const char *name, int data_type) return NULL; } - loopdata = dm->getLoopDataLayout(dm); + loopdata = &mesh->ldata; cd_ptr = CustomData_get_layer_named(loopdata, cd_data_type, name); if (cd_ptr != NULL) { /* layer already exists, so just return it. */ @@ -920,7 +921,7 @@ static void *add_customdata_cb(void *user_data, const char *name, int data_type) /* create a new layer, taking care to construct the hopefully-soon-to-be-removed * CD_MTEXPOLY layer too, with the same name. */ - numloops = dm->getNumLoops(dm); + numloops = mesh->totloop; cd_ptr = CustomData_add_layer_named(loopdata, cd_data_type, CD_DEFAULT, NULL, numloops, name); return cd_ptr; @@ -986,17 +987,19 @@ static void read_mesh_sample(const std::string & iobject_full_name, } } -CDStreamConfig get_config(DerivedMesh *dm) +CDStreamConfig get_config(Mesh *mesh) { CDStreamConfig config; - config.user_data = dm; - config.mvert = dm->getVertArray(dm); - config.mloop = dm->getLoopArray(dm); - config.mpoly = dm->getPolyArray(dm); - config.totloop = dm->getNumLoops(dm); - config.totpoly = dm->getNumPolys(dm); - config.loopdata = dm->getLoopDataLayout(dm); + BLI_assert(mesh->mvert); + + config.user_data = mesh; + config.mvert = mesh->mvert; + config.mloop = mesh->mloop; + config.mpoly = mesh->mpoly; + config.totloop = mesh->totloop; + config.totpoly = mesh->totpoly; + config.loopdata = &mesh->ldata; config.add_customdata_cb = add_customdata_cb; return config; @@ -1027,14 +1030,8 @@ void AbcMeshReader::readObjectData(Main *bmain, const Alembic::Abc::ISampleSelec m_object = BKE_object_add_only_object(bmain, OB_MESH, m_object_name.c_str()); m_object->data = mesh; - DerivedMesh *dm = CDDM_from_mesh(mesh); - DerivedMesh *ndm = this->read_derivedmesh(dm, sample_sel, MOD_MESHSEQ_READ_ALL, NULL); - - if (ndm != dm) { - dm->release(dm); - } - - DM_to_mesh(ndm, mesh, m_object, CD_MASK_MESH, true); + Mesh *read_mesh = this->read_mesh(mesh, sample_sel, MOD_MESHSEQ_READ_ALL, NULL); + BKE_mesh_nomain_to_mesh(read_mesh, mesh, m_object, CD_MASK_MESH, true); if (m_settings->validate_meshes) { BKE_mesh_validate(mesh, false, false); @@ -1064,33 +1061,45 @@ bool AbcMeshReader::accepts_object_type(const Alembic::AbcCoreAbstract::ObjectHe return true; } -DerivedMesh *AbcMeshReader::read_derivedmesh(DerivedMesh *dm, - const ISampleSelector &sample_sel, - int read_flag, - const char **err_str) +Mesh *AbcMeshReader::read_mesh(Mesh *existing_mesh, + const ISampleSelector &sample_sel, + int read_flag, + const char **err_str) { - const IPolyMeshSchema::Sample sample = m_schema.getValue(sample_sel); + IPolyMeshSchema::Sample sample; + try { + sample = m_schema.getValue(sample_sel); + } + catch(Alembic::Util::Exception &ex) { + *err_str = "Error reading mesh sample; more detail on the console"; + printf("Alembic: error reading mesh sample for '%s/%s' at time %f: %s\n", + m_iobject.getFullName().c_str(), + m_schema.getName().c_str(), + sample_sel.getRequestedTime(), + ex.what()); + return existing_mesh; + } const P3fArraySamplePtr &positions = sample.getPositions(); const Alembic::Abc::Int32ArraySamplePtr &face_indices = sample.getFaceIndices(); const Alembic::Abc::Int32ArraySamplePtr &face_counts = sample.getFaceCounts(); - DerivedMesh *new_dm = NULL; + Mesh *new_mesh = NULL; /* Only read point data when streaming meshes, unless we need to create new ones. */ ImportSettings settings; settings.read_flag |= read_flag; - bool topology_changed = positions->size() != dm->getNumVerts(dm) || - face_counts->size() != dm->getNumPolys(dm) || - face_indices->size() != dm->getNumLoops(dm); + bool topology_changed = positions->size() != existing_mesh->totvert || + face_counts->size() != existing_mesh->totpoly || + face_indices->size() != existing_mesh->totloop; if (topology_changed) { - new_dm = CDDM_from_template(dm, - positions->size(), - 0, - 0, - face_indices->size(), - face_counts->size()); + new_mesh = BKE_mesh_new_nomain_from_template(existing_mesh, + positions->size(), + 0, + 0, + face_indices->size(), + face_counts->size()); settings.read_flag |= MOD_MESHSEQ_READ_ALL; } @@ -1098,8 +1107,8 @@ DerivedMesh *AbcMeshReader::read_derivedmesh(DerivedMesh *dm, /* If the face count changed (e.g. by triangulation), only read points. * This prevents crash from T49813. * TODO(kevin): perhaps find a better way to do this? */ - if (face_counts->size() != dm->getNumPolys(dm) || - face_indices->size() != dm->getNumLoops(dm)) + if (face_counts->size() != existing_mesh->totpoly || + face_indices->size() != existing_mesh->totloop) { settings.read_flag = MOD_MESHSEQ_READ_VERT; @@ -1110,40 +1119,39 @@ DerivedMesh *AbcMeshReader::read_derivedmesh(DerivedMesh *dm, } } - CDStreamConfig config = get_config(new_dm ? new_dm : dm); + CDStreamConfig config = get_config(new_mesh ? new_mesh : existing_mesh); config.time = sample_sel.getRequestedTime(); bool do_normals = false; read_mesh_sample(m_iobject.getFullName(), &settings, m_schema, sample_sel, config, do_normals); - if (new_dm) { + if (new_mesh) { /* Check if we had ME_SMOOTH flag set to restore it. */ - if (!do_normals && check_smooth_poly_flag(dm)) { - set_smooth_poly_flag(new_dm); + if (!do_normals && check_smooth_poly_flag(existing_mesh)) { + set_smooth_poly_flag(new_mesh); } - CDDM_calc_normals(new_dm); - CDDM_calc_edges(new_dm); + BKE_mesh_calc_normals(new_mesh); + BKE_mesh_calc_edges(new_mesh, false, false); /* Here we assume that the number of materials doesn't change, i.e. that * the material slots that were created when the object was loaded from * Alembic are still valid now. */ - size_t num_polys = new_dm->getNumPolys(new_dm); + size_t num_polys = new_mesh->totpoly; if (num_polys > 0) { - MPoly *dmpolies = new_dm->getPolyArray(new_dm); std::map<std::string, int> mat_map; - assign_facesets_to_mpoly(sample_sel, 0, dmpolies, num_polys, mat_map); + assign_facesets_to_mpoly(sample_sel, 0, new_mesh->mpoly, num_polys, mat_map); } - return new_dm; + return new_mesh; } if (do_normals) { - CDDM_calc_normals(dm); + BKE_mesh_calc_normals(existing_mesh); } - return dm; + return existing_mesh; } void AbcMeshReader::assign_facesets_to_mpoly( @@ -1305,16 +1313,22 @@ void AbcSubDReader::readObjectData(Main *bmain, const Alembic::Abc::ISampleSelec m_object = BKE_object_add_only_object(bmain, OB_MESH, m_object_name.c_str()); m_object->data = mesh; - DerivedMesh *dm = CDDM_from_mesh(mesh); - DerivedMesh *ndm = this->read_derivedmesh(dm, sample_sel, MOD_MESHSEQ_READ_ALL, NULL); + Mesh *read_mesh = this->read_mesh(mesh, sample_sel, MOD_MESHSEQ_READ_ALL, NULL); + BKE_mesh_nomain_to_mesh(read_mesh, mesh, m_object, CD_MASK_MESH, true); - if (ndm != dm) { - dm->release(dm); + ISubDSchema::Sample sample; + try { + sample = m_schema.getValue(sample_sel); + } + catch(Alembic::Util::Exception &ex) { + printf("Alembic: error reading mesh sample for '%s/%s' at time %f: %s\n", + m_iobject.getFullName().c_str(), + m_schema.getName().c_str(), + sample_sel.getRequestedTime(), + ex.what()); + return; } - DM_to_mesh(ndm, mesh, m_object, CD_MASK_MESH, true); - - const ISubDSchema::Sample sample = m_schema.getValue(sample_sel); Int32ArraySamplePtr indices = sample.getCreaseIndices(); Alembic::Abc::FloatArraySamplePtr sharpnesses = sample.getCreaseSharpnesses(); @@ -1344,29 +1358,41 @@ void AbcSubDReader::readObjectData(Main *bmain, const Alembic::Abc::ISampleSelec } } -DerivedMesh *AbcSubDReader::read_derivedmesh(DerivedMesh *dm, - const ISampleSelector &sample_sel, - int read_flag, - const char **err_str) +Mesh *AbcSubDReader::read_mesh(Mesh *existing_mesh, + const ISampleSelector &sample_sel, + int read_flag, + const char **err_str) { - const ISubDSchema::Sample sample = m_schema.getValue(sample_sel); + ISubDSchema::Sample sample; + try { + sample = m_schema.getValue(sample_sel); + } + catch(Alembic::Util::Exception &ex) { + *err_str = "Error reading mesh sample; more detail on the console"; + printf("Alembic: error reading mesh sample for '%s/%s' at time %f: %s\n", + m_iobject.getFullName().c_str(), + m_schema.getName().c_str(), + sample_sel.getRequestedTime(), + ex.what()); + return existing_mesh; + } const P3fArraySamplePtr &positions = sample.getPositions(); const Alembic::Abc::Int32ArraySamplePtr &face_indices = sample.getFaceIndices(); const Alembic::Abc::Int32ArraySamplePtr &face_counts = sample.getFaceCounts(); - DerivedMesh *new_dm = NULL; + Mesh *new_mesh = NULL; ImportSettings settings; settings.read_flag |= read_flag; - if (dm->getNumVerts(dm) != positions->size()) { - new_dm = CDDM_from_template(dm, - positions->size(), - 0, - 0, - face_indices->size(), - face_counts->size()); + if (existing_mesh->totvert != positions->size()) { + new_mesh = BKE_mesh_new_nomain_from_template(existing_mesh, + positions->size(), + 0, + 0, + face_indices->size(), + face_counts->size()); settings.read_flag |= MOD_MESHSEQ_READ_ALL; } @@ -1374,8 +1400,8 @@ DerivedMesh *AbcSubDReader::read_derivedmesh(DerivedMesh *dm, /* If the face count changed (e.g. by triangulation), only read points. * This prevents crash from T49813. * TODO(kevin): perhaps find a better way to do this? */ - if (face_counts->size() != dm->getNumPolys(dm) || - face_indices->size() != dm->getNumLoops(dm)) + if (face_counts->size() != existing_mesh->totpoly || + face_indices->size() != existing_mesh->totpoly) { settings.read_flag = MOD_MESHSEQ_READ_VERT; @@ -1387,22 +1413,22 @@ DerivedMesh *AbcSubDReader::read_derivedmesh(DerivedMesh *dm, } /* Only read point data when streaming meshes, unless we need to create new ones. */ - CDStreamConfig config = get_config(new_dm ? new_dm : dm); + CDStreamConfig config = get_config(new_mesh ? new_mesh : existing_mesh); config.time = sample_sel.getRequestedTime(); read_subd_sample(m_iobject.getFullName(), &settings, m_schema, sample_sel, config); - if (new_dm) { + if (new_mesh) { /* Check if we had ME_SMOOTH flag set to restore it. */ - if (check_smooth_poly_flag(dm)) { - set_smooth_poly_flag(new_dm); + if (check_smooth_poly_flag(existing_mesh)) { + set_smooth_poly_flag(new_mesh); } - CDDM_calc_normals(new_dm); - CDDM_calc_edges(new_dm); + BKE_mesh_calc_normals(new_mesh); + BKE_mesh_calc_edges(new_mesh, false, false); - return new_dm; + return new_mesh; } - return dm; + return existing_mesh; } diff --git a/source/blender/alembic/intern/abc_mesh.h b/source/blender/alembic/intern/abc_mesh.h index c57123cda4c..e1507bedd01 100644 --- a/source/blender/alembic/intern/abc_mesh.h +++ b/source/blender/alembic/intern/abc_mesh.h @@ -26,7 +26,6 @@ #include "abc_customdata.h" #include "abc_object.h" -struct DerivedMesh; struct Mesh; struct ModifierData; @@ -50,9 +49,7 @@ class AbcMeshWriter : public AbcObjectWriter { bool m_is_subd; public: - AbcMeshWriter(Depsgraph *depsgraph, - Scene *scene, - Object *ob, + AbcMeshWriter(Object *ob, AbcTransformWriter *parent, uint32_t time_sampling, ExportSettings &settings); @@ -65,29 +62,28 @@ private: bool isAnimated() const; - void writeMesh(DerivedMesh *dm); - void writeSubD(DerivedMesh *dm); + void writeMesh(struct Mesh *mesh); + void writeSubD(struct Mesh *mesh); - void getMeshInfo(DerivedMesh *dm, std::vector<float> &points, + void getMeshInfo(struct Mesh *mesh, std::vector<float> &points, std::vector<int32_t> &facePoints, std::vector<int32_t> &faceCounts, std::vector<int32_t> &creaseIndices, std::vector<int32_t> &creaseLengths, std::vector<float> &creaseSharpness); - DerivedMesh *getFinalMesh(); - void freeMesh(DerivedMesh *dm); + struct Mesh *getFinalMesh(bool &r_needsfree); - void getMaterialIndices(DerivedMesh *dm, std::vector<int32_t> &indices); + void getMaterialIndices(struct Mesh *mesh, std::vector<int32_t> &indices); - void writeArbGeoParams(DerivedMesh *dm); - void getGeoGroups(DerivedMesh *dm, std::map<std::string, std::vector<int32_t> > &geoGroups); + void writeArbGeoParams(struct Mesh *mesh); + void getGeoGroups(struct Mesh *mesh, std::map<std::string, std::vector<int32_t> > &geoGroups); /* fluid surfaces support */ - void getVelocities(DerivedMesh *dm, std::vector<Imath::V3f> &vels); + void getVelocities(struct Mesh *mesh, std::vector<Imath::V3f> &vels); template <typename Schema> - void writeFaceSets(DerivedMesh *dm, Schema &schema); + void writeFaceSets(struct Mesh *mesh, Schema &schema); }; /* ************************************************************************** */ @@ -106,10 +102,10 @@ public: const char **err_str) const; void readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel); - DerivedMesh *read_derivedmesh(DerivedMesh *dm, - const Alembic::Abc::ISampleSelector &sample_sel, - int read_flag, - const char **err_str); + struct Mesh *read_mesh(struct Mesh *existing_mesh, + const Alembic::Abc::ISampleSelector &sample_sel, + int read_flag, + const char **err_str); private: void readFaceSetsSample(Main *bmain, Mesh *mesh, size_t poly_start, @@ -136,10 +132,10 @@ public: const Object *const ob, const char **err_str) const; void readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel); - DerivedMesh *read_derivedmesh(DerivedMesh *dm, - const Alembic::Abc::ISampleSelector &sample_sel, - int read_flag, - const char **err_str); + struct Mesh *read_mesh(struct Mesh *existing_mesh, + const Alembic::Abc::ISampleSelector &sample_sel, + int read_flag, + const char **err_str); }; /* ************************************************************************** */ @@ -148,6 +144,6 @@ void read_mverts(MVert *mverts, const Alembic::AbcGeom::P3fArraySamplePtr &positions, const Alembic::AbcGeom::N3fArraySamplePtr &normals); -CDStreamConfig get_config(DerivedMesh *dm); +CDStreamConfig get_config(struct Mesh *mesh); #endif /* __ABC_MESH_H__ */ diff --git a/source/blender/alembic/intern/abc_nurbs.cc b/source/blender/alembic/intern/abc_nurbs.cc index 1f042d0bafc..95d06fc5efe 100644 --- a/source/blender/alembic/intern/abc_nurbs.cc +++ b/source/blender/alembic/intern/abc_nurbs.cc @@ -60,13 +60,11 @@ using Alembic::AbcGeom::ONuPatchSchema; /* ************************************************************************** */ -AbcNurbsWriter::AbcNurbsWriter(Depsgraph *depsgraph, - Scene *scene, - Object *ob, +AbcNurbsWriter::AbcNurbsWriter(Object *ob, AbcTransformWriter *parent, uint32_t time_sampling, ExportSettings &settings) - : AbcObjectWriter(depsgraph, scene, ob, time_sampling, settings, parent) + : AbcObjectWriter(ob, time_sampling, settings, parent) { m_is_animated = isAnimated(); @@ -255,7 +253,19 @@ void AbcNurbsReader::readObjectData(Main *bmain, const Alembic::Abc::ISampleSele nu->resolv = cu->resolv; const INuPatchSchema &schema = it->first; - const INuPatchSchema::Sample smp = schema.getValue(sample_sel); + INuPatchSchema::Sample smp; + try { + smp = schema.getValue(sample_sel); + } + catch(Alembic::Util::Exception &ex) { + printf("Alembic: error reading nurbs sample for '%s/%s' at time %f: %s\n", + m_iobject.getFullName().c_str(), + schema.getName().c_str(), + sample_sel.getRequestedTime(), + ex.what()); + return; + } + nu->orderu = smp.getUOrder() - 1; nu->orderv = smp.getVOrder() - 1; diff --git a/source/blender/alembic/intern/abc_nurbs.h b/source/blender/alembic/intern/abc_nurbs.h index d2422345c3f..827aa4b365f 100644 --- a/source/blender/alembic/intern/abc_nurbs.h +++ b/source/blender/alembic/intern/abc_nurbs.h @@ -32,9 +32,7 @@ class AbcNurbsWriter : public AbcObjectWriter { bool m_is_animated; public: - AbcNurbsWriter(Depsgraph *depsgraph, - Scene *scene, - Object *ob, + AbcNurbsWriter(Object *ob, AbcTransformWriter *parent, uint32_t time_sampling, ExportSettings &settings); diff --git a/source/blender/alembic/intern/abc_object.cc b/source/blender/alembic/intern/abc_object.cc index 85bda9aa8eb..7e0b1ccfbd4 100644 --- a/source/blender/alembic/intern/abc_object.cc +++ b/source/blender/alembic/intern/abc_object.cc @@ -58,16 +58,12 @@ using Alembic::AbcGeom::OStringProperty; /* ************************************************************************** */ -AbcObjectWriter::AbcObjectWriter(Depsgraph *depsgraph, - Scene *scene, - Object *ob, +AbcObjectWriter::AbcObjectWriter(Object *ob, uint32_t time_sampling, ExportSettings &settings, AbcObjectWriter *parent) : m_object(ob) , m_settings(settings) - , m_depsgraph(depsgraph) - , m_scene(scene) , m_time_sampling(time_sampling) , m_first_frame(true) { @@ -248,12 +244,12 @@ Imath::M44d get_matrix(const IXformSchema &schema, const float time) return s0.getMatrix(); } -DerivedMesh *AbcObjectReader::read_derivedmesh(DerivedMesh *dm, - const Alembic::Abc::ISampleSelector &UNUSED(sample_sel), - int UNUSED(read_flag), - const char **UNUSED(err_str)) +struct Mesh *AbcObjectReader::read_mesh(struct Mesh *existing_mesh, + const Alembic::Abc::ISampleSelector &UNUSED(sample_sel), + int UNUSED(read_flag), + const char **UNUSED(err_str)) { - return dm; + return existing_mesh; } void AbcObjectReader::setupObjectTransform(const float time) diff --git a/source/blender/alembic/intern/abc_object.h b/source/blender/alembic/intern/abc_object.h index d41088bdcad..8794cb61708 100644 --- a/source/blender/alembic/intern/abc_object.h +++ b/source/blender/alembic/intern/abc_object.h @@ -44,8 +44,6 @@ protected: Object *m_object; ExportSettings &m_settings; - Depsgraph *m_depsgraph; - Scene *m_scene; uint32_t m_time_sampling; Imath::Box3d m_bounds; @@ -57,9 +55,7 @@ protected: std::string m_name; public: - AbcObjectWriter(Depsgraph *depsgraph, - Scene *scene, - Object *ob, + AbcObjectWriter(Object *ob, uint32_t time_sampling, ExportSettings &settings, AbcObjectWriter *parent = NULL); @@ -124,7 +120,7 @@ static bool has_animations(Schema &schema, ImportSettings *settings) /* ************************************************************************** */ -struct DerivedMesh; +struct Mesh; using Alembic::AbcCoreAbstract::chrono_t; @@ -180,10 +176,10 @@ public: virtual void readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel) = 0; - virtual DerivedMesh *read_derivedmesh(DerivedMesh *dm, - const Alembic::Abc::ISampleSelector &sample_sel, - int read_flag, - const char **err_str); + virtual struct Mesh *read_mesh(struct Mesh *mesh, + const Alembic::Abc::ISampleSelector &sample_sel, + int read_flag, + const char **err_str); /** Reads the object matrix and sets up an object transform if animated. */ void setupObjectTransform(const float time); diff --git a/source/blender/alembic/intern/abc_points.cc b/source/blender/alembic/intern/abc_points.cc index 6f52ccec4a7..9ff995ffcbf 100644 --- a/source/blender/alembic/intern/abc_points.cc +++ b/source/blender/alembic/intern/abc_points.cc @@ -40,6 +40,8 @@ extern "C" { #include "BKE_scene.h" #include "BLI_math.h" + +#include "DEG_depsgraph_query.h" } using Alembic::AbcGeom::kVertexScope; @@ -58,14 +60,12 @@ using Alembic::AbcGeom::OPointsSchema; /* ************************************************************************** */ -AbcPointsWriter::AbcPointsWriter(Depsgraph *depsgraph, - Scene *scene, - Object *ob, +AbcPointsWriter::AbcPointsWriter(Object *ob, AbcTransformWriter *parent, uint32_t time_sampling, ExportSettings &settings, ParticleSystem *psys) - : AbcObjectWriter(depsgraph, scene, ob, time_sampling, settings, parent) + : AbcObjectWriter(ob, time_sampling, settings, parent) { m_psys = psys; @@ -87,8 +87,8 @@ void AbcPointsWriter::do_write() ParticleKey state; ParticleSimulationData sim; - sim.depsgraph = m_depsgraph; - sim.scene = m_scene; + sim.depsgraph = m_settings.depsgraph; + sim.scene = m_settings.scene; sim.ob = m_object; sim.psys = m_psys; @@ -102,7 +102,7 @@ void AbcPointsWriter::do_write() continue; } - state.time = BKE_scene_frame_get(m_scene); + state.time = DEG_get_ctime(m_settings.depsgraph); if (psys_get_particle_state(&sim, p, &state, 0) == 0) { continue; @@ -173,15 +173,9 @@ bool AbcPointsReader::accepts_object_type(const Alembic::AbcCoreAbstract::Object void AbcPointsReader::readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel) { Mesh *mesh = BKE_mesh_add(bmain, m_data_name.c_str()); + Mesh *read_mesh = this->read_mesh(mesh, sample_sel, 0, NULL); - DerivedMesh *dm = CDDM_from_mesh(mesh); - DerivedMesh *ndm = this->read_derivedmesh(dm, sample_sel, 0, NULL); - - if (ndm != dm) { - dm->release(dm); - } - - DM_to_mesh(ndm, mesh, m_object, CD_MASK_MESH, true); + BKE_mesh_nomain_to_mesh(read_mesh, mesh, m_object, CD_MASK_MESH, true); if (m_settings->validate_meshes) { BKE_mesh_validate(mesh, false, false); @@ -218,23 +212,35 @@ void read_points_sample(const IPointsSchema &schema, read_mverts(config.mvert, positions, vnormals); } -DerivedMesh *AbcPointsReader::read_derivedmesh(DerivedMesh *dm, - const ISampleSelector &sample_sel, - int /*read_flag*/, - const char ** /*err_str*/) +struct Mesh *AbcPointsReader::read_mesh(struct Mesh *existing_mesh, + const ISampleSelector &sample_sel, + int /*read_flag*/, + const char **err_str) { - const IPointsSchema::Sample sample = m_schema.getValue(sample_sel); + IPointsSchema::Sample sample; + try { + sample = m_schema.getValue(sample_sel); + } + catch(Alembic::Util::Exception &ex) { + *err_str = "Error reading points sample; more detail on the console"; + printf("Alembic: error reading points sample for '%s/%s' at time %f: %s\n", + m_iobject.getFullName().c_str(), + m_schema.getName().c_str(), + sample_sel.getRequestedTime(), + ex.what()); + return existing_mesh; + } const P3fArraySamplePtr &positions = sample.getPositions(); - DerivedMesh *new_dm = NULL; + Mesh *new_mesh = NULL; - if (dm->getNumVerts(dm) != positions->size()) { - new_dm = CDDM_new(positions->size(), 0, 0, 0, 0); + if (existing_mesh->totvert != positions->size()) { + new_mesh = BKE_mesh_new_nomain(positions->size(), 0, 0, 0, 0); } - CDStreamConfig config = get_config(new_dm ? new_dm : dm); + CDStreamConfig config = get_config(new_mesh ? new_mesh : existing_mesh); read_points_sample(m_schema, sample_sel, config); - return new_dm ? new_dm : dm; + return new_mesh ? new_mesh : existing_mesh; } diff --git a/source/blender/alembic/intern/abc_points.h b/source/blender/alembic/intern/abc_points.h index 1ac8792ede1..e986f9448f4 100644 --- a/source/blender/alembic/intern/abc_points.h +++ b/source/blender/alembic/intern/abc_points.h @@ -38,9 +38,7 @@ class AbcPointsWriter : public AbcObjectWriter { ParticleSystem *m_psys; public: - AbcPointsWriter(Depsgraph *depsgraph, - Scene *scene, - Object *ob, + AbcPointsWriter(Object *ob, AbcTransformWriter *parent, uint32_t time_sampling, ExportSettings &settings, @@ -65,10 +63,10 @@ public: void readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel); - DerivedMesh *read_derivedmesh(DerivedMesh *dm, - const Alembic::Abc::ISampleSelector &sample_sel, - int read_flag, - const char **err_str); + struct Mesh *read_mesh(struct Mesh *existing_mesh, + const Alembic::Abc::ISampleSelector &sample_sel, + int read_flag, + const char **err_str); }; void read_points_sample(const Alembic::AbcGeom::IPointsSchema &schema, diff --git a/source/blender/alembic/intern/abc_transform.cc b/source/blender/alembic/intern/abc_transform.cc index e5da367b9a9..81ebfef3e11 100644 --- a/source/blender/alembic/intern/abc_transform.cc +++ b/source/blender/alembic/intern/abc_transform.cc @@ -32,6 +32,8 @@ extern "C" { #include "BLI_math.h" #include "BKE_object.h" + +#include "DEG_depsgraph_query.h" } using Alembic::AbcGeom::OObject; @@ -57,13 +59,12 @@ static bool has_parent_camera(Object *ob) /* ************************************************************************** */ -AbcTransformWriter::AbcTransformWriter(Depsgraph *depsgraph, - Object *ob, +AbcTransformWriter::AbcTransformWriter(Object *ob, const OObject &abc_parent, AbcTransformWriter *parent, unsigned int time_sampling, ExportSettings &settings) - : AbcObjectWriter(depsgraph, NULL, ob, time_sampling, settings, parent) + : AbcObjectWriter(ob, time_sampling, settings, parent) , m_proxy_from(NULL) { m_is_animated = hasAnimation(m_object); @@ -81,29 +82,31 @@ AbcTransformWriter::AbcTransformWriter(Depsgraph *depsgraph, void AbcTransformWriter::do_write() { + Object *ob_eval = DEG_get_evaluated_object(m_settings.depsgraph, m_object); + if (m_first_frame) { m_visibility = Alembic::AbcGeom::CreateVisibilityProperty(m_xform, m_xform.getSchema().getTimeSampling()); } - m_visibility.set(!(m_object->restrictflag & OB_RESTRICT_VIEW)); + m_visibility.set(!(ob_eval->restrictflag & OB_RESTRICT_VIEW)); if (!m_first_frame && !m_is_animated) { return; } float yup_mat[4][4]; - create_transform_matrix(m_object, yup_mat, + create_transform_matrix(ob_eval, yup_mat, m_inherits_xform ? ABC_MATRIX_LOCAL : ABC_MATRIX_WORLD, m_proxy_from); /* Only apply rotation to root camera, parenting will propagate it. */ - if (m_object->type == OB_CAMERA && (!m_inherits_xform || !has_parent_camera(m_object))) { + if (ob_eval->type == OB_CAMERA && (!m_inherits_xform || !has_parent_camera(ob_eval))) { float rot_mat[4][4]; axis_angle_to_mat4_single(rot_mat, 'X', -M_PI_2); mul_m4_m4m4(yup_mat, yup_mat, rot_mat); } - if (!m_object->parent || !m_inherits_xform) { + if (!ob_eval->parent || !m_inherits_xform) { /* Only apply scaling to root objects, parenting will propagate it. */ float scale_mat[4][4]; scale_m4_fl(scale_mat, m_settings.global_scale); diff --git a/source/blender/alembic/intern/abc_transform.h b/source/blender/alembic/intern/abc_transform.h index 91420b28f93..12bf9d38007 100644 --- a/source/blender/alembic/intern/abc_transform.h +++ b/source/blender/alembic/intern/abc_transform.h @@ -43,8 +43,7 @@ public: Object *m_proxy_from; public: - AbcTransformWriter(Depsgraph *depsgraph, - Object *ob, + AbcTransformWriter(Object *ob, const Alembic::AbcGeom::OObject &abc_parent, AbcTransformWriter *parent, unsigned int time_sampling, diff --git a/source/blender/alembic/intern/abc_util.cc b/source/blender/alembic/intern/abc_util.cc index 6787d118fa1..53860ab149d 100644 --- a/source/blender/alembic/intern/abc_util.cc +++ b/source/blender/alembic/intern/abc_util.cc @@ -181,11 +181,11 @@ void copy_m44_axis_swap(float dst_mat[4][4], float src_mat[4][4], AbcAxisSwapMod unit_m3(dst_rot); unit_m4(dst_scale_mat); - /* We assume there is no sheer component and no homogeneous scaling component. */ - BLI_assert(fabs(src_mat[0][3]) < 2 * FLT_EPSILON); - BLI_assert(fabs(src_mat[1][3]) < 2 * FLT_EPSILON); - BLI_assert(fabs(src_mat[2][3]) < 2 * FLT_EPSILON); - BLI_assert(fabs(src_mat[3][3] - 1.0f) < 2 * FLT_EPSILON); + /* TODO(Sybren): This code assumes there is no sheer component and no + * homogeneous scaling component, which is not always true when writing + * non-hierarchical (e.g. flat) objects (e.g. when parent has non-uniform + * scale and the child rotates). This is currently not taken into account + * when axis-swapping. */ /* Extract translation, rotation, and scale form matrix. */ mat4_to_loc_rot_size(src_trans, src_rot, src_scale, src_mat); diff --git a/source/blender/alembic/intern/alembic_capi.cc b/source/blender/alembic/intern/alembic_capi.cc index 1a6990a1de8..cc9923189c7 100644 --- a/source/blender/alembic/intern/alembic_capi.cc +++ b/source/blender/alembic/intern/alembic_capi.cc @@ -230,9 +230,7 @@ static void find_iobject(const IObject &object, IObject &ret, } struct ExportJobData { - Scene *scene; ViewLayer *view_layer; - Depsgraph *depsgraph; Main *bmain; char filename[1024]; @@ -262,10 +260,16 @@ static void export_startjob(void *customdata, short *stop, short *do_update, flo G.is_break = false; + DEG_graph_build_from_view_layer(data->settings.depsgraph, + data->bmain, + data->settings.scene, + data->view_layer); + BKE_scene_graph_update_tagged(data->settings.depsgraph, data->bmain); + try { - Scene *scene = data->scene; - AbcExporter exporter(data->bmain, scene, data->depsgraph, data->filename, data->settings); + AbcExporter exporter(data->bmain, data->filename, data->settings); + Scene *scene = data->settings.scene; /* for the CFRA macro */ const int orig_frame = CFRA; data->was_canceled = false; @@ -274,7 +278,7 @@ static void export_startjob(void *customdata, short *stop, short *do_update, flo if (CFRA != orig_frame) { CFRA = orig_frame; - BKE_scene_graph_update_for_newframe(data->depsgraph, data->bmain); + BKE_scene_graph_update_for_newframe(data->settings.depsgraph, data->bmain); } data->export_ok = !data->was_canceled; @@ -313,9 +317,7 @@ bool ABC_export( { ExportJobData *job = static_cast<ExportJobData *>(MEM_mallocN(sizeof(ExportJobData), "ExportJobData")); - job->scene = scene; job->view_layer = CTX_data_view_layer(C); - job->depsgraph = CTX_data_depsgraph(C); job->bmain = CTX_data_main(C); job->export_ok = false; BLI_strncpy(job->filename, filepath, 1024); @@ -336,14 +338,14 @@ bool ABC_export( * do bigger refactor and maybe there is a better way which does not involve * hardcore refactoring. */ new (&job->settings) ExportSettings(); - job->settings.scene = job->scene; - job->settings.depsgraph = job->depsgraph; + job->settings.scene = scene; + job->settings.depsgraph = DEG_graph_new(scene, job->view_layer, DAG_EVAL_RENDER); /* Sybren: for now we only export the active scene layer. * Later in the 2.8 development process this may be replaced by using * a specific collection for Alembic I/O, which can then be toggled * between "real" objects and cached Alembic files. */ - job->settings.view_layer = CTX_data_view_layer(C); + job->settings.view_layer = job->view_layer; job->settings.frame_start = params->frame_start; job->settings.frame_end = params->frame_end; @@ -387,7 +389,7 @@ bool ABC_export( if (as_background_job) { wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), - job->scene, + job->settings.scene, "Alembic Export", WM_JOB_PROGRESS, WM_JOB_TYPE_ALEMBIC); @@ -960,12 +962,12 @@ void ABC_get_transform(CacheReader *reader, float r_mat[4][4], float time, float /* ************************************************************************** */ -DerivedMesh *ABC_read_mesh(CacheReader *reader, - Object *ob, - DerivedMesh *dm, - const float time, - const char **err_str, - int read_flag) +Mesh *ABC_read_mesh(CacheReader *reader, + Object *ob, + Mesh *existing_mesh, + const float time, + const char **err_str, + int read_flag) { AbcObjectReader *abc_reader = reinterpret_cast<AbcObjectReader *>(reader); IObject iobject = abc_reader->iobject(); @@ -984,7 +986,7 @@ DerivedMesh *ABC_read_mesh(CacheReader *reader, /* kFloorIndex is used to be compatible with non-interpolating * properties; they use the floor. */ ISampleSelector sample_sel(time, ISampleSelector::kFloorIndex); - return abc_reader->read_derivedmesh(dm, sample_sel, read_flag, err_str); + return abc_reader->read_mesh(existing_mesh, sample_sel, read_flag, err_str); } /* ************************************************************************** */ diff --git a/source/blender/blenfont/intern/blf.c b/source/blender/blenfont/intern/blf.c index fafee125264..5dd692d3855 100644 --- a/source/blender/blenfont/intern/blf.c +++ b/source/blender/blenfont/intern/blf.c @@ -172,7 +172,7 @@ static int blf_search_available(void) for (i = 0; i < BLF_MAX_FONT; i++) if (!global_font[i]) return i; - + return -1; } diff --git a/source/blender/blenfont/intern/blf_dir.c b/source/blender/blenfont/intern/blf_dir.c index d3349a10834..ff5c1151a82 100644 --- a/source/blender/blenfont/intern/blf_dir.c +++ b/source/blender/blenfont/intern/blf_dir.c @@ -61,7 +61,7 @@ static ListBase global_font_dir = { NULL, NULL }; static DirBLF *blf_dir_find(const char *path) { DirBLF *p; - + p = global_font_dir.first; while (p) { if (BLI_path_cmp(p->path, path) == 0) @@ -74,11 +74,11 @@ static DirBLF *blf_dir_find(const char *path) void BLF_dir_add(const char *path) { DirBLF *dir; - + dir = blf_dir_find(path); if (dir) /* already in the list ? just return. */ return; - + dir = (DirBLF *)MEM_callocN(sizeof(DirBLF), "BLF_dir_add"); dir->path = BLI_strdup(path); BLI_addhead(&global_font_dir, dir); @@ -87,7 +87,7 @@ void BLF_dir_add(const char *path) void BLF_dir_rem(const char *path) { DirBLF *dir; - + dir = blf_dir_find(path); if (dir) { BLI_remlink(&global_font_dir, dir); @@ -102,11 +102,11 @@ char **BLF_dir_get(int *ndir) char **dirs; char *path; int i, count; - + count = BLI_listbase_count(&global_font_dir); if (!count) return NULL; - + dirs = (char **)MEM_callocN(sizeof(char *) * count, "BLF_dir_get"); p = global_font_dir.first; i = 0; @@ -123,7 +123,7 @@ void BLF_dir_free(char **dirs, int count) { char *path; int i; - + for (i = 0; i < count; i++) { path = dirs[i]; MEM_freeN(path); @@ -159,7 +159,7 @@ int blf_dir_split(const char *str, char *file, int *size) { int i, len; char *s; - + /* Window, Linux or Mac, this is always / */ s = strrchr(str, '/'); if (s) { diff --git a/source/blender/blenfont/intern/blf_font.c b/source/blender/blenfont/intern/blf_font.c index c31aacb0a54..1289dc6c5a6 100644 --- a/source/blender/blenfont/intern/blf_font.c +++ b/source/blender/blenfont/intern/blf_font.c @@ -553,7 +553,7 @@ static void blf_font_draw_buffer_ex( width_clip -= chx + width_clip - buf_info->w; if (height_clip + pen_y > buf_info->h) height_clip -= pen_y + height_clip - buf_info->h; - + /* drawing below the image? */ if (pen_y < 0) { yb_start += (g->pitch < 0) ? -pen_y : pen_y; diff --git a/source/blender/blenfont/intern/blf_glyph.c b/source/blender/blenfont/intern/blf_glyph.c index f3789bee1fd..5a87c726566 100644 --- a/source/blender/blenfont/intern/blf_glyph.c +++ b/source/blender/blenfont/intern/blf_glyph.c @@ -292,11 +292,11 @@ GlyphBLF *blf_glyph_add(FontBLF *font, unsigned int index, unsigned int c) if (font->flags & BLF_HINTING) flags &= ~FT_LOAD_NO_HINTING; - + if (is_sharp) err = FT_Load_Glyph(font->face, (FT_UInt)index, FT_LOAD_TARGET_MONO); else - err = FT_Load_Glyph(font->face, (FT_UInt)index, flags); + err = FT_Load_Glyph(font->face, (FT_UInt)index, flags); if (err) { BLI_spin_unlock(font->ft_lib_mutex); diff --git a/source/blender/blenfont/intern/blf_internal_types.h b/source/blender/blenfont/intern/blf_internal_types.h index 5b9d3f1eb5b..d7b526735d1 100644 --- a/source/blender/blenfont/intern/blf_internal_types.h +++ b/source/blender/blenfont/intern/blf_internal_types.h @@ -204,7 +204,7 @@ typedef struct FontBLF { /* angle in radians. */ float angle; - + #if 0 /* BLF_BLUR_ENABLE */ /* blur: 3 or 5 large kernel */ int blur; diff --git a/source/blender/blenkernel/BKE_DerivedMesh.h b/source/blender/blenkernel/BKE_DerivedMesh.h index e918f158682..79b0e5eb95f 100644 --- a/source/blender/blenkernel/BKE_DerivedMesh.h +++ b/source/blender/blenkernel/BKE_DerivedMesh.h @@ -531,18 +531,6 @@ DMCoNo *mesh_get_mapped_verts_nors(struct Scene *scene, struct Object *ob); void mesh_get_mapped_verts_coords(DerivedMesh *dm, float (*r_cos)[3], const int totcos); /* */ -DerivedMesh *mesh_get_derived_final( - struct Depsgraph *depsgraph, struct Scene *scene, - struct Object *ob, CustomDataMask dataMask); -struct Mesh *mesh_get_eval_final( - struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, CustomDataMask dataMask); - -DerivedMesh *mesh_get_derived_deform( - struct Depsgraph *depsgraph, struct Scene *scene, - struct Object *ob, CustomDataMask dataMask); -struct Mesh *mesh_get_eval_deform( - struct Depsgraph *depsgraph, struct Scene *scene, - struct Object *ob, CustomDataMask dataMask); DerivedMesh *mesh_create_derived_for_modifier( struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, diff --git a/source/blender/blenkernel/BKE_anim.h b/source/blender/blenkernel/BKE_anim.h index 701be9d44cc..2f7d0eaba03 100644 --- a/source/blender/blenkernel/BKE_anim.h +++ b/source/blender/blenkernel/BKE_anim.h @@ -32,16 +32,17 @@ * \author nzc * \since March 2001 */ -struct Depsgraph; -struct Path; -struct Object; -struct Scene; -struct ListBase; struct bAnimVizSettings; struct bMotionPath; struct bPoseChannel; -struct ReportList; +struct Depsgraph; +struct ListBase; struct Main; +struct Object; +struct ParticleSystem; +struct Path; +struct ReportList; +struct Scene; /* ---------------------------------------------------- */ /* Animation Visualization */ @@ -68,7 +69,6 @@ int where_on_path(struct Object *ob, float ctime, float vec[4], float dir[3], fl /* ---------------------------------------------------- */ /* Dupli-Geometry */ -struct ListBase *object_duplilist_ex(struct Depsgraph *depsgraph, struct Scene *sce, struct Object *ob, bool update); struct ListBase *object_duplilist(struct Depsgraph *depsgraph, struct Scene *sce, struct Object *ob); void free_object_duplilist(struct ListBase *lb); int count_duplilist(struct Object *ob); @@ -83,6 +83,26 @@ typedef struct DupliApplyData { DupliExtraData *extra; } DupliApplyData; +typedef struct DupliObject { + struct DupliObject *next, *prev; + struct Object *ob; + float mat[4][4]; + float orco[3], uv[2]; + + short type; /* from Object.transflag */ + char no_draw; + + /* Persistent identifier for a dupli object, for inter-frame matching of + * objects with motion blur, or inter-update matching for syncing. */ + int persistent_id[16]; /* 2*MAX_DUPLI_RECUR */ + + /* Particle this dupli was generated from. */ + struct ParticleSystem *particle_system; + + /* Random ID for shading */ + unsigned int random_id; +} DupliObject; + DupliApplyData *duplilist_apply(struct Depsgraph *depsgraph, struct Object *ob, struct Scene *scene, struct ListBase *duplilist); void duplilist_restore(struct ListBase *duplilist, DupliApplyData *apply_data); void duplilist_free_apply_data(DupliApplyData *apply_data); diff --git a/source/blender/blenkernel/BKE_collection.h b/source/blender/blenkernel/BKE_collection.h index edc24d9649e..fc5b19ccb4f 100644 --- a/source/blender/blenkernel/BKE_collection.h +++ b/source/blender/blenkernel/BKE_collection.h @@ -91,7 +91,6 @@ bool BKE_collection_is_in_scene(struct Collection *collection); void BKE_collections_after_lib_link(struct Main *bmain); bool BKE_collection_object_cyclic_check(struct Main *bmain, struct Object *object, struct Collection *collection); bool BKE_collection_is_animated(struct Collection *collection, struct Object *parent); -void BKE_collection_handle_recalc_and_update(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *parent, struct Collection *collection); /* Object list cache. */ diff --git a/source/blender/blenkernel/BKE_library.h b/source/blender/blenkernel/BKE_library.h index 0f05170b47c..28bc254f25a 100644 --- a/source/blender/blenkernel/BKE_library.h +++ b/source/blender/blenkernel/BKE_library.h @@ -182,6 +182,9 @@ struct BlendThumbnail *BKE_main_thumbnail_from_imbuf(struct Main *bmain, struct struct ImBuf *BKE_main_thumbnail_to_imbuf(struct Main *bmain, struct BlendThumbnail *data); void BKE_main_thumbnail_create(struct Main *bmain); +const char *BKE_main_blendfile_path(const struct Main *bmain) ATTR_NONNULL(); +const char *BKE_main_blendfile_path_from_global(void); + void BKE_main_id_tag_idcode(struct Main *mainvar, const short type, const int tag, const bool value); void BKE_main_id_tag_listbase(struct ListBase *lb, const int tag, const bool value); void BKE_main_id_tag_all(struct Main *mainvar, const int tag, const bool value); diff --git a/source/blender/blenkernel/BKE_mball.h b/source/blender/blenkernel/BKE_mball.h index 41f04c09e69..74ef9d9dbc0 100644 --- a/source/blender/blenkernel/BKE_mball.h +++ b/source/blender/blenkernel/BKE_mball.h @@ -76,8 +76,6 @@ void BKE_mball_select_swap(struct MetaBall *mb); struct Depsgraph; -void BKE_mball_eval_geometry(struct Depsgraph *depsgraph, - struct MetaBall *mball); /* Draw Cache */ enum { diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h index efbc00c456f..cb58deb9511 100644 --- a/source/blender/blenkernel/BKE_mesh.h +++ b/source/blender/blenkernel/BKE_mesh.h @@ -178,9 +178,9 @@ struct Mesh *BKE_mesh_create_derived_for_modifier( struct ModifierData *md, int build_shapekey_layers); /* Copies a nomain-Mesh into an existing Mesh. */ -void BKE_nomain_mesh_to_mesh(struct Mesh *mesh_src, struct Mesh *mesh_dst, struct Object *ob, +void BKE_mesh_nomain_to_mesh(struct Mesh *mesh_src, struct Mesh *mesh_dst, struct Object *ob, CustomDataMask mask, bool take_ownership); -void BKE_nomain_mesh_to_meshkey(struct Mesh *mesh_src, struct Mesh *mesh_dst, struct KeyBlock *kb); +void BKE_mesh_nomain_to_meshkey(struct Mesh *mesh_src, struct Mesh *mesh_dst, struct KeyBlock *kb); /* vertex level transformations & checks (no derived mesh) */ @@ -206,23 +206,10 @@ void BKE_mesh_mselect_active_set(struct Mesh *me, int index, int type); void BKE_mesh_apply_vert_coords(struct Mesh *mesh, float (*vertCoords)[3]); -/* *** mesh_runtime.c *** */ -void BKE_mesh_runtime_reset(struct Mesh *mesh); -int BKE_mesh_runtime_looptri_len(const struct Mesh *mesh); -void BKE_mesh_runtime_looptri_recalc(struct Mesh *mesh); -const struct MLoopTri *BKE_mesh_runtime_looptri_ensure(struct Mesh *mesh); -bool BKE_mesh_runtime_ensure_edit_data(struct Mesh *mesh); -bool BKE_mesh_runtime_clear_edit_data(struct Mesh *mesh); -void BKE_mesh_runtime_clear_geometry(struct Mesh *mesh); -void BKE_mesh_runtime_clear_cache(struct Mesh *mesh); - -void BKE_mesh_runtime_verttri_from_looptri( - struct MVertTri *r_verttri, - const struct MLoop *mloop, const struct MLoopTri *looptri, int looptri_num); - /* *** mesh_evaluate.c *** */ +void BKE_mesh_calc_normals_mapping_simple(struct Mesh *me); void BKE_mesh_calc_normals_mapping( struct MVert *mverts, int numVerts, const struct MLoop *mloop, const struct MPoly *mpolys, int numLoops, int numPolys, float (*r_polyNors)[3], diff --git a/source/blender/blenkernel/BKE_mesh_runtime.h b/source/blender/blenkernel/BKE_mesh_runtime.h new file mode 100644 index 00000000000..6904ad529de --- /dev/null +++ b/source/blender/blenkernel/BKE_mesh_runtime.h @@ -0,0 +1,85 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Blender Foundation + * + * ***** END GPL LICENSE BLOCK ***** + */ +#ifndef __BKE_MESH_RUNTIME_H__ +#define __BKE_MESH_RUNTIME_H__ + +/** \file BKE_mesh_runtime.h + * \ingroup bke + * + * This file contains access functions for the Mesh.runtime struct. + */ + +#include "BKE_customdata.h" /* for CustomDataMask */ + +struct Depsgraph; +struct Mesh; +struct MLoop; +struct MLoopTri; +struct MVertTri; +struct Object; +struct Scene; + +/* Undefine to hide DerivedMesh-based function declarations */ +#define USE_DERIVEDMESH + +#ifdef USE_DERIVEDMESH +struct DerivedMesh; +#endif + +void BKE_mesh_runtime_reset(struct Mesh *mesh); +int BKE_mesh_runtime_looptri_len(const struct Mesh *mesh); +void BKE_mesh_runtime_looptri_recalc(struct Mesh *mesh); +const struct MLoopTri *BKE_mesh_runtime_looptri_ensure(struct Mesh *mesh); +bool BKE_mesh_runtime_ensure_edit_data(struct Mesh *mesh); +bool BKE_mesh_runtime_clear_edit_data(struct Mesh *mesh); +void BKE_mesh_runtime_clear_geometry(struct Mesh *mesh); +void BKE_mesh_runtime_clear_cache(struct Mesh *mesh); + +void BKE_mesh_runtime_verttri_from_looptri( + struct MVertTri *r_verttri, + const struct MLoop *mloop, const struct MLoopTri *looptri, int looptri_num); + +/* NOTE: the functions below are defined in DerivedMesh.c, and are intended to be moved + * to a more suitable location when that file is removed. */ +#ifdef USE_DERIVEDMESH +struct DerivedMesh *mesh_get_derived_final( + struct Depsgraph *depsgraph, struct Scene *scene, + struct Object *ob, CustomDataMask dataMask); +#endif +struct Mesh *mesh_get_eval_final( + struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, CustomDataMask dataMask); + +#ifdef USE_DERIVEDMESH +struct DerivedMesh *mesh_get_derived_deform( + struct Depsgraph *depsgraph, struct Scene *scene, + struct Object *ob, CustomDataMask dataMask); +#endif +struct Mesh *mesh_get_eval_deform( + struct Depsgraph *depsgraph, struct Scene *scene, + struct Object *ob, CustomDataMask dataMask); + +#endif /* __BKE_MESH_RUNTIME_H__ */ diff --git a/source/blender/blenkernel/BKE_movieclip.h b/source/blender/blenkernel/BKE_movieclip.h index 5b5ebbf035c..014ea2b9159 100644 --- a/source/blender/blenkernel/BKE_movieclip.h +++ b/source/blender/blenkernel/BKE_movieclip.h @@ -49,7 +49,7 @@ void BKE_movieclip_make_local(struct Main *bmain, struct MovieClip *clip, const struct MovieClip *BKE_movieclip_file_add(struct Main *bmain, const char *name); struct MovieClip *BKE_movieclip_file_add_exists_ex(struct Main *bmain, const char *name, bool *r_exists); struct MovieClip *BKE_movieclip_file_add_exists(struct Main *bmain, const char *name); -void BKE_movieclip_reload(struct MovieClip *clip); +void BKE_movieclip_reload(struct Main *bmain, struct MovieClip *clip); void BKE_movieclip_clear_cache(struct MovieClip *clip); void BKE_movieclip_clear_proxy_cache(struct MovieClip *clip); diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index 915cafd5d3d..cb211b65948 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -1056,9 +1056,6 @@ void free_nodesystem(void); struct Depsgraph; -void BKE_nodetree_copy_default_values(struct bNodeTree *ntree_dst, - const struct bNodeTree *ntree_src); - void BKE_nodetree_shading_params_eval(struct Depsgraph *depsgraph, struct bNodeTree *ntree_dst, const struct bNodeTree *ntree_src); diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h index 7ff0093db6c..6172c9998af 100644 --- a/source/blender/blenkernel/BKE_object.h +++ b/source/blender/blenkernel/BKE_object.h @@ -66,6 +66,7 @@ void BKE_object_free_curve_cache(struct Object *ob); void BKE_object_free(struct Object *ob); void BKE_object_free_derived_caches(struct Object *ob); +void BKE_object_free_derived_mesh_caches(struct Object *ob); void BKE_object_free_caches(struct Object *object); void BKE_object_modifier_hook_reset(struct Object *ob, struct HookModifierData *hmd); diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h index 9bd73bd7553..412cf45de2b 100644 --- a/source/blender/blenkernel/BKE_paint.h +++ b/source/blender/blenkernel/BKE_paint.h @@ -40,6 +40,7 @@ struct CurveMapping; struct MeshElemMap; struct GridPaintMask; struct Main; +struct Mesh; struct MLoop; struct MLoopTri; struct MFace; @@ -185,7 +186,8 @@ typedef struct SculptSession { float *vmask; /* Mesh connectivity */ - const struct MeshElemMap *pmap; + struct MeshElemMap *pmap; + int *pmap_mem; /* BMesh for dynamic topology sculpting */ struct BMesh *bm; @@ -258,6 +260,8 @@ int BKE_sculpt_mask_layers_ensure(struct Object *ob, struct MultiresModifierData *mmd); void BKE_sculpt_toolsettings_data_ensure(struct Scene *scene); +struct PBVH *BKE_sculpt_object_pbvh_ensure(struct Object *ob, struct Mesh *me_eval_deform); + enum { SCULPT_MASK_LAYER_CALC_VERT = (1 << 0), SCULPT_MASK_LAYER_CALC_LOOP = (1 << 1) diff --git a/source/blender/blenkernel/BKE_particle.h b/source/blender/blenkernel/BKE_particle.h index f4279fa9262..2f192c43504 100644 --- a/source/blender/blenkernel/BKE_particle.h +++ b/source/blender/blenkernel/BKE_particle.h @@ -303,9 +303,6 @@ void psys_set_current_num(Object *ob, int index); struct LatticeDeformData *psys_create_lattice_deform_data(struct ParticleSimulationData *sim); struct ParticleSystem *psys_orig_get(struct ParticleSystem *psys); -struct ParticleSystem *psys_eval_get(struct Depsgraph *depsgraph, - struct Object *object, - struct ParticleSystem *psys); bool psys_in_edit_mode(struct Depsgraph *depsgraph, struct ParticleSystem *psys); bool psys_check_enabled(struct Object *ob, struct ParticleSystem *psys, const bool use_render_params); bool psys_check_edited(struct ParticleSystem *psys); diff --git a/source/blender/blenkernel/BKE_pbvh.h b/source/blender/blenkernel/BKE_pbvh.h index c18288de1bc..78c766f6115 100644 --- a/source/blender/blenkernel/BKE_pbvh.h +++ b/source/blender/blenkernel/BKE_pbvh.h @@ -240,7 +240,7 @@ void BKE_pbvh_node_layer_disp_free(PBVHNode *node); /* vertex deformer */ float (*BKE_pbvh_get_vertCos(struct PBVH *pbvh))[3]; -void BKE_pbvh_apply_vertCos(struct PBVH *pbvh, float (*vertCos)[3]); +void BKE_pbvh_apply_vertCos(struct PBVH *pbvh, float (*vertCos)[3], const int totvert); bool BKE_pbvh_isDeformed(struct PBVH *pbvh); /* Vertex Iterator */ diff --git a/source/blender/blenkernel/BKE_studiolight.h b/source/blender/blenkernel/BKE_studiolight.h index 2f2e948ab26..7883f89f33a 100644 --- a/source/blender/blenkernel/BKE_studiolight.h +++ b/source/blender/blenkernel/BKE_studiolight.h @@ -59,15 +59,23 @@ struct GPUTexture; enum StudioLightFlag { STUDIOLIGHT_DIFFUSE_LIGHT_CALCULATED = (1 << 0), STUDIOLIGHT_LIGHT_DIRECTION_CALCULATED = (1 << 1), - STUDIOLIGHT_EXTERNAL_FILE = (1 << 2), - STUDIOLIGHT_ORIENTATION_CAMERA = (1 << 3), - STUDIOLIGHT_ORIENTATION_WORLD = (1 << 4), - STUDIOLIGHT_EQUIRECTANGULAR_IMAGE_LOADED = (1 << 5), - STUDIOLIGHT_EQUIRECTANGULAR_IRRADIANCE_IMAGE_CALCULATED = (1 << 6), - STUDIOLIGHT_EQUIRECTANGULAR_RADIANCE_GPUTEXTURE = (1 << 7), - STUDIOLIGHT_EQUIRECTANGULAR_IRRADIANCE_GPUTEXTURE = (1 << 8), - STUDIOLIGHT_RADIANCE_BUFFERS_CALCULATED = (1 << 9), + STUDIOLIGHT_INTERNAL = (1 << 2), + STUDIOLIGHT_EXTERNAL_FILE = (1 << 3), + STUDIOLIGHT_USER_DEFINED = (1 << 12), + STUDIOLIGHT_ORIENTATION_CAMERA = (1 << 4), + STUDIOLIGHT_ORIENTATION_WORLD = (1 << 5), + STUDIOLIGHT_ORIENTATION_VIEWNORMAL = (1 << 6), + STUDIOLIGHT_EXTERNAL_IMAGE_LOADED = (1 << 7), + STUDIOLIGHT_EQUIRECTANGULAR_IRRADIANCE_IMAGE_CALCULATED = (1 << 8), + STUDIOLIGHT_EQUIRECTANGULAR_RADIANCE_GPUTEXTURE = (1 << 9), + STUDIOLIGHT_EQUIRECTANGULAR_IRRADIANCE_GPUTEXTURE = (1 << 10), + STUDIOLIGHT_RADIANCE_BUFFERS_CALCULATED = (1 << 11), + STUDIOLIGHT_UI_EXPANDED = (1 << 13), } StudioLightFlag; +#define STUDIOLIGHT_FLAG_ALL (STUDIOLIGHT_INTERNAL | STUDIOLIGHT_EXTERNAL_FILE) +#define STUDIOLIGHT_FLAG_ORIENTATIONS (STUDIOLIGHT_ORIENTATION_CAMERA | STUDIOLIGHT_ORIENTATION_WORLD | STUDIOLIGHT_ORIENTATION_VIEWNORMAL) +#define STUDIOLIGHT_ORIENTATIONS_MATERIAL_MODE (STUDIOLIGHT_INTERNAL | STUDIOLIGHT_ORIENTATION_WORLD) +#define STUDIOLIGHT_ORIENTATIONS_SOLID (STUDIOLIGHT_ORIENTATION_CAMERA | STUDIOLIGHT_ORIENTATION_WORLD) typedef struct StudioLight { struct StudioLight *next, *prev; @@ -89,9 +97,11 @@ typedef struct StudioLight { void BKE_studiolight_init(void); void BKE_studiolight_free(void); struct StudioLight *BKE_studiolight_find(const char *name, int flag); -struct StudioLight *BKE_studiolight_findindex(int index); +struct StudioLight *BKE_studiolight_findindex(int index, int flag); +struct StudioLight *BKE_studiolight_find_first(int flag); unsigned int *BKE_studiolight_preview(StudioLight *sl, int icon_size, int icon_id_type); -const struct ListBase *BKE_studiolight_listbase(void); +struct ListBase *BKE_studiolight_listbase(void); void BKE_studiolight_ensure_flag(StudioLight *sl, int flag); +void BKE_studiolight_refresh(void); #endif /* __BKE_STUDIOLIGHT_H__ */ diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c index 1698946b506..c081bb0799f 100644 --- a/source/blender/blenkernel/intern/DerivedMesh.c +++ b/source/blender/blenkernel/intern/DerivedMesh.c @@ -61,6 +61,7 @@ #include "BKE_modifier.h" #include "BKE_mesh.h" #include "BKE_mesh_mapping.h" +#include "BKE_mesh_runtime.h" #include "BKE_mesh_tangent.h" #include "BKE_object.h" #include "BKE_object_deform.h" @@ -94,7 +95,6 @@ static ThreadRWMutex loops_cache_lock = PTHREAD_RWLOCK_INITIALIZER; -static void add_shapekey_layers(DerivedMesh *dm, Mesh *me, Object *ob); static void shapekey_layers_to_keyblocks(DerivedMesh *dm, Mesh *me, int actshape_uid); static void mesh_init_origspace(Mesh *mesh); @@ -1157,6 +1157,8 @@ DerivedMesh *mesh_create_derived(Mesh *me, float (*vertCos)[3]) return dm; } +/* XXX2.8(Sybren): can be removed once DerivedMesh port is done */ +#ifdef WITH_DERIVEDMESH_DEPRECATED_FUNCS DerivedMesh *mesh_create_derived_for_modifier( struct Depsgraph *depsgraph, Scene *scene, Object *ob, ModifierData *md, int build_shapekey_layers) @@ -1207,6 +1209,7 @@ DerivedMesh *mesh_create_derived_for_modifier( return dm; } +#endif static float (*get_editbmesh_orco_verts(BMEditMesh *em))[3] { @@ -1920,7 +1923,7 @@ static void shapekey_layers_to_keyblocks(DerivedMesh *dm, Mesh *me, int actshape } } -static void add_shapekey_layers(DerivedMesh *dm, Mesh *me, Object *UNUSED(ob)) +static void UNUSED_FUNCTION(add_shapekey_layers)(DerivedMesh *dm, Mesh *me, Object *UNUSED(ob)) { KeyBlock *kb; Key *key = me->key; @@ -3104,6 +3107,7 @@ void makeDerivedMesh( /***/ +#ifdef USE_DERIVEDMESH /* Deprecated DM, use: 'mesh_get_eval_final'. */ DerivedMesh *mesh_get_derived_final( struct Depsgraph *depsgraph, Scene *scene, Object *ob, CustomDataMask dataMask) @@ -3124,6 +3128,7 @@ DerivedMesh *mesh_get_derived_final( if (ob->derivedFinal) { BLI_assert(!(ob->derivedFinal->dirty & DM_DIRTY_NORMALS)); } return ob->derivedFinal; } +#endif Mesh *mesh_get_eval_final( struct Depsgraph *depsgraph, Scene *scene, Object *ob, CustomDataMask dataMask) { @@ -3133,7 +3138,7 @@ Mesh *mesh_get_eval_final( bool need_mapping; dataMask |= object_get_datamask(depsgraph, ob, &need_mapping); - if (!ob->derivedFinal || + if (!ob->runtime.mesh_eval || ((dataMask & ob->lastDataMask) != dataMask) || (need_mapping != ob->lastNeedMapping)) { @@ -3144,6 +3149,7 @@ Mesh *mesh_get_eval_final( return ob->runtime.mesh_eval; } +#ifdef USE_DERIVEDMESH /* Deprecated DM, use: 'mesh_get_eval_deform' instead. */ DerivedMesh *mesh_get_derived_deform(struct Depsgraph *depsgraph, Scene *scene, Object *ob, CustomDataMask dataMask) { @@ -3163,6 +3169,7 @@ DerivedMesh *mesh_get_derived_deform(struct Depsgraph *depsgraph, Scene *scene, return ob->derivedDeform; } +#endif Mesh *mesh_get_eval_deform(struct Depsgraph *depsgraph, Scene *scene, Object *ob, CustomDataMask dataMask) { /* if there's no derived mesh or the last data mask used doesn't include diff --git a/source/blender/blenkernel/intern/blender_undo.c b/source/blender/blenkernel/intern/blender_undo.c index 98482bcc8b1..857fc72672c 100644 --- a/source/blender/blenkernel/intern/blender_undo.c +++ b/source/blender/blenkernel/intern/blender_undo.c @@ -67,10 +67,11 @@ bool BKE_memfile_undo_decode(MemFileUndoData *mfu, bContext *C) { - char mainstr[sizeof(G.main->name)]; + Main *bmain = CTX_data_main(C); + char mainstr[sizeof(bmain->name)]; int success = 0, fileflags; - BLI_strncpy(mainstr, G.main->name, sizeof(mainstr)); /* temporal store */ + BLI_strncpy(mainstr, BKE_main_blendfile_path(bmain), sizeof(mainstr)); /* temporal store */ fileflags = G.fileflags; G.fileflags |= G_FILE_NO_UI; @@ -82,13 +83,14 @@ bool BKE_memfile_undo_decode(MemFileUndoData *mfu, bContext *C) success = BKE_blendfile_read_from_memfile(C, &mfu->memfile, NULL, 0); } - /* restore */ - BLI_strncpy(G.main->name, mainstr, sizeof(G.main->name)); /* restore */ + /* Restore, bmain has been re-allocated. */ + bmain = CTX_data_main(C); + BLI_strncpy(bmain->name, mainstr, sizeof(bmain->name)); G.fileflags = fileflags; if (success) { /* important not to update time here, else non keyed tranforms are lost */ - DEG_on_visible_update(G.main, false); + DEG_on_visible_update(bmain, false); } return success; diff --git a/source/blender/blenkernel/intern/blendfile.c b/source/blender/blenkernel/intern/blendfile.c index 34079d778f7..597c69408b5 100644 --- a/source/blender/blenkernel/intern/blendfile.c +++ b/source/blender/blenkernel/intern/blendfile.c @@ -116,6 +116,7 @@ static void setup_app_data( bContext *C, BlendFileData *bfd, const char *filepath, ReportList *reports) { + Main *bmain = G.main; /* Valid usage */ Scene *curscene = NULL; const bool is_startup = (bfd->filename[0] == '\0'); const bool recover = (G.fileflags & G_FILE_RECOVER) != 0; @@ -172,9 +173,9 @@ static void setup_app_data( bool track_undo_scene; /* comes from readfile.c */ - SWAP(ListBase, G.main->wm, bfd->main->wm); - SWAP(ListBase, G.main->workspaces, bfd->main->workspaces); - SWAP(ListBase, G.main->screen, bfd->main->screen); + SWAP(ListBase, bmain->wm, bfd->main->wm); + SWAP(ListBase, bmain->workspaces, bfd->main->workspaces); + SWAP(ListBase, bmain->screen, bfd->main->screen); /* we re-use current window and screen */ win = CTX_wm_window(C); @@ -236,9 +237,9 @@ static void setup_app_data( /* clear old property update cache, in case some old references are left dangling */ RNA_property_update_cache_free(); - G.main = bfd->main; + bmain = G.main = bfd->main; - CTX_data_main_set(C, G.main); + CTX_data_main_set(C, bmain); if (bfd->user) { @@ -266,7 +267,7 @@ static void setup_app_data( /* Keep state from preferences. */ const int fileflags_skip = G_FILE_FLAGS_RUNTIME; G.fileflags = (G.fileflags & fileflags_skip) | (bfd->fileflags & ~fileflags_skip); - CTX_wm_manager_set(C, G.main->wm.first); + CTX_wm_manager_set(C, bmain->wm.first); CTX_wm_screen_set(C, bfd->curscreen); CTX_data_scene_set(C, bfd->curscene); CTX_wm_area_set(C, NULL); @@ -280,10 +281,10 @@ static void setup_app_data( wmWindow *win = CTX_wm_window(C); /* in case we don't even have a local scene, add one */ - if (!G.main->scene.first) - BKE_scene_add(G.main, "Empty"); + if (!bmain->scene.first) + BKE_scene_add(bmain, "Empty"); - CTX_data_scene_set(C, G.main->scene.first); + CTX_data_scene_set(C, bmain->scene.first); win->scene = CTX_data_scene(C); curscene = CTX_data_scene(C); } @@ -307,35 +308,35 @@ static void setup_app_data( /* FIXME: this version patching should really be part of the file-reading code, * but we still get too many unrelated data-corruption crashes otherwise... */ - if (G.main->versionfile < 250) - do_versions_ipos_to_animato(G.main); + if (bmain->versionfile < 250) + do_versions_ipos_to_animato(bmain); - G.main->recovered = 0; + bmain->recovered = 0; /* startup.blend or recovered startup */ if (bfd->filename[0] == 0) { - G.main->name[0] = 0; + bmain->name[0] = '\0'; } else if (recover && G.relbase_valid) { /* in case of autosave or quit.blend, use original filename instead * use relbase_valid to make sure the file is saved, else we get <memory2> in the filename */ filepath = bfd->filename; - G.main->recovered = 1; + bmain->recovered = 1; /* these are the same at times, should never copy to the same location */ - if (G.main->name != filepath) - BLI_strncpy(G.main->name, filepath, FILE_MAX); + if (bmain->name != filepath) + BLI_strncpy(bmain->name, filepath, FILE_MAX); } /* baseflags, groups, make depsgraph, etc */ /* first handle case if other windows have different scenes visible */ if (mode == LOAD_UI) { - wmWindowManager *wm = G.main->wm.first; + wmWindowManager *wm = bmain->wm.first; if (wm) { for (wmWindow *win = wm->windows.first; win; win = win->next) { if (win->scene && win->scene != curscene) { - BKE_scene_set_background(G.main, win->scene); + BKE_scene_set_background(bmain, win->scene); } } } @@ -346,10 +347,10 @@ static void setup_app_data( * constructing dependency graph. */ if (mode != LOAD_UNDO) { - IMB_colormanagement_check_file_config(G.main); + IMB_colormanagement_check_file_config(bmain); } - BKE_scene_set_background(G.main, curscene); + BKE_scene_set_background(bmain, curscene); if (mode != LOAD_UNDO) { /* TODO(sergey): Can this be also move above? */ @@ -431,9 +432,10 @@ bool BKE_blendfile_read_from_memfile( bContext *C, struct MemFile *memfile, ReportList *reports, int skip_flags) { + Main *bmain = CTX_data_main(C); BlendFileData *bfd; - bfd = BLO_read_from_memfile(CTX_data_main(C), G.main->name, memfile, reports, skip_flags); + bfd = BLO_read_from_memfile(bmain, BKE_main_blendfile_path(bmain), memfile, reports, skip_flags); if (bfd) { /* remove the unused screens and wm */ while (bfd->main->wm.first) diff --git a/source/blender/blenkernel/intern/bpath.c b/source/blender/blenkernel/intern/bpath.c index 1fd2797d2f8..82d9f9f8f69 100644 --- a/source/blender/blenkernel/intern/bpath.c +++ b/source/blender/blenkernel/intern/bpath.c @@ -325,7 +325,7 @@ void BKE_bpath_missing_files_find(Main *bmain, const char *searchpath, ReportLis struct BPathFind_Data data = {NULL}; const int flag = BKE_BPATH_TRAVERSE_ABS | BKE_BPATH_TRAVERSE_RELOAD_EDITED; - data.basedir = bmain->name; + data.basedir = BKE_main_blendfile_path(bmain); data.reports = reports; data.searchdir = searchpath; data.find_all = find_all; diff --git a/source/blender/blenkernel/intern/bvhutils.c b/source/blender/blenkernel/intern/bvhutils.c index b3ea3de6ea9..e8328139d64 100644 --- a/source/blender/blenkernel/intern/bvhutils.c +++ b/source/blender/blenkernel/intern/bvhutils.c @@ -45,6 +45,7 @@ #include "BKE_DerivedMesh.h" #include "BKE_editmesh.h" #include "BKE_mesh.h" +#include "BKE_mesh_runtime.h" #include "MEM_guardedalloc.h" diff --git a/source/blender/blenkernel/intern/cachefile.c b/source/blender/blenkernel/intern/cachefile.c index 274f7b78529..74c0dca6279 100644 --- a/source/blender/blenkernel/intern/cachefile.c +++ b/source/blender/blenkernel/intern/cachefile.c @@ -89,13 +89,22 @@ void BKE_cachefile_free(CacheFile *cache_file) { BKE_animdata_free((ID *)cache_file, false); + if (cache_file->id.tag & LIB_TAG_NO_MAIN) { + /* CoW/no-main copies reuse the existing ArchiveReader and mutex */ + return; + } + + if (cache_file->handle) { #ifdef WITH_ALEMBIC - ABC_free_handle(cache_file->handle); + ABC_free_handle(cache_file->handle); #endif - + cache_file->handle = NULL; + } if (cache_file->handle_mutex) { BLI_mutex_free(cache_file->handle_mutex); + cache_file->handle_mutex = NULL; } + BLI_freelistN(&cache_file->object_paths); } @@ -110,8 +119,14 @@ void BKE_cachefile_free(CacheFile *cache_file) void BKE_cachefile_copy_data( Main *UNUSED(bmain), CacheFile *cache_file_dst, const CacheFile *UNUSED(cache_file_src), const int UNUSED(flag)) { + if (cache_file_dst->id.tag & LIB_TAG_NO_MAIN) { + /* CoW/no-main copies reuse the existing ArchiveReader and mutex */ + return; + } + cache_file_dst->handle = NULL; - BLI_listbase_clear(&cache_file_dst->object_paths); + cache_file_dst->handle_mutex = NULL; + BLI_duplicatelist(&cache_file_dst->object_paths, &cache_file_dst->object_paths); } CacheFile *BKE_cachefile_copy(Main *bmain, const CacheFile *cache_file) @@ -153,6 +168,8 @@ void BKE_cachefile_ensure_handle(const Main *bmain, CacheFile *cache_file) BLI_mutex_lock(cache_file->handle_mutex); if (cache_file->handle == NULL) { + /* Assigning to a CoW copy is a bad idea; assign to the original instead. */ + BLI_assert((cache_file->id.tag & LIB_TAG_COPIED_ON_WRITE) == 0); BKE_cachefile_reload(bmain, cache_file); } diff --git a/source/blender/blenkernel/intern/cdderivedmesh.c b/source/blender/blenkernel/intern/cdderivedmesh.c index 13b2a3a5d64..7bcc05b0e37 100644 --- a/source/blender/blenkernel/intern/cdderivedmesh.c +++ b/source/blender/blenkernel/intern/cdderivedmesh.c @@ -325,7 +325,7 @@ static PBVH *cdDM_getPBVH(Object *ob, DerivedMesh *dm) totvert = deformdm->getNumVerts(deformdm); vertCos = MEM_malloc_arrayN(totvert, sizeof(float[3]), "cdDM_getPBVH vertCos"); deformdm->getVertCos(deformdm, vertCos); - BKE_pbvh_apply_vertCos(cddm->pbvh, vertCos); + BKE_pbvh_apply_vertCos(cddm->pbvh, vertCos, totvert); MEM_freeN(vertCos); } } diff --git a/source/blender/blenkernel/intern/cloth.c b/source/blender/blenkernel/intern/cloth.c index a39de284064..cc1c7260cbc 100644 --- a/source/blender/blenkernel/intern/cloth.c +++ b/source/blender/blenkernel/intern/cloth.c @@ -48,7 +48,7 @@ #include "BKE_cloth.h" #include "BKE_effect.h" #include "BKE_global.h" -#include "BKE_mesh.h" +#include "BKE_mesh_runtime.h" #include "BKE_modifier.h" #include "BKE_pointcache.h" diff --git a/source/blender/blenkernel/intern/collection.c b/source/blender/blenkernel/intern/collection.c index c4709a32f78..ab0ec8b0491 100644 --- a/source/blender/blenkernel/intern/collection.c +++ b/source/blender/blenkernel/intern/collection.c @@ -59,7 +59,7 @@ static bool collection_child_add(Collection *parent, Collection *collection, int flag, const bool add_us); static bool collection_child_remove(Collection *parent, Collection *collection); -static bool collection_object_add(Collection *collection, Object *ob, int flag, const bool add_us); +static bool collection_object_add(Main *bmain, Collection *collection, Object *ob, int flag, const bool add_us); static bool collection_object_remove(Main *bmain, Collection *collection, Object *ob, const bool free_us); static CollectionChild *collection_find_child(Collection *parent, Collection *collection); @@ -163,7 +163,7 @@ bool BKE_collection_delete(Main *bmain, Collection *collection, bool hierarchy) /* Link child object into parent collections. */ for (CollectionParent *cparent = collection->parents.first; cparent; cparent = cparent->next) { Collection *parent = cparent->collection; - collection_object_add(parent, cob->ob, 0, true); + collection_object_add(bmain, parent, cob->ob, 0, true); } /* Remove child object. */ @@ -190,7 +190,7 @@ bool BKE_collection_delete(Main *bmain, Collection *collection, bool hierarchy) * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more). */ void BKE_collection_copy_data( - Main *UNUSED(bmain), Collection *collection_dst, const Collection *collection_src, const int flag) + Main *bmain, Collection *collection_dst, const Collection *collection_src, const int flag) { /* Do not copy collection's preview (same behavior as for objects). */ if ((flag & LIB_ID_COPY_NO_PREVIEW) == 0 && false) { /* XXX TODO temp hack */ @@ -211,7 +211,7 @@ void BKE_collection_copy_data( collection_child_add(collection_dst, child->collection, flag, false); } for (CollectionObject *cob = collection_src->gobject.first; cob; cob = cob->next) { - collection_object_add(collection_dst, cob->ob, flag, false); + collection_object_add(bmain, collection_dst, cob->ob, flag, false); } } @@ -311,23 +311,6 @@ bool BKE_collection_is_animated(Collection *collection, Object *UNUSED(parent)) return false; } -/* puts all collection members in local timing system, after this call - * you can draw everything, leaves tags in objects to signal it needs further updating */ - -/* note: does not work for derivedmesh and render... it recreates all again in convertblender.c */ -void BKE_collection_handle_recalc_and_update( - struct Depsgraph *depsgraph, Scene *scene, Object *UNUSED(parent), Collection *collection) -{ - /* only do existing tags, as set by regular depsgraph */ - FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(collection, object) - { - if (object->id.recalc & ID_RECALC_ALL) { - BKE_object_handle_update(depsgraph, scene, object); - } - } - FOREACH_COLLECTION_OBJECT_RECURSIVE_END; -} - /* **************** Object List Cache *******************/ static void collection_object_cache_fill(ListBase *lb, Collection *collection, int parent_restrict) @@ -367,12 +350,12 @@ ListBase BKE_collection_object_cache_get(Collection *collection) if (!(collection->flag & COLLECTION_HAS_OBJECT_CACHE)) { static ThreadMutex cache_lock = BLI_MUTEX_INITIALIZER; + BLI_mutex_lock(&cache_lock); if (!(collection->flag & COLLECTION_HAS_OBJECT_CACHE)) { - BLI_mutex_lock(&cache_lock); collection_object_cache_fill(&collection->object_cache, collection, 0); collection->flag |= COLLECTION_HAS_OBJECT_CACHE; - BLI_mutex_unlock(&cache_lock); } + BLI_mutex_unlock(&cache_lock); } return collection->object_cache; @@ -522,7 +505,7 @@ Collection *BKE_collection_object_find(Main *bmain, Collection *collection, Obje /********************** Collection Objects *********************/ -static bool collection_object_add(Collection *collection, Object *ob, int flag, const bool add_us) +static bool collection_object_add(Main *bmain, Collection *collection, Object *ob, int flag, const bool add_us) { if (ob->dup_group) { /* Cyclic dependency check. */ @@ -545,6 +528,10 @@ static bool collection_object_add(Collection *collection, Object *ob, int flag, id_us_plus(&ob->id); } + if ((flag & LIB_ID_CREATE_NO_MAIN) == 0) { + DEG_id_tag_update_ex(bmain, &collection->id, DEG_TAG_COPY_ON_WRITE); + } + return true; } @@ -565,6 +552,8 @@ static bool collection_object_remove(Main *bmain, Collection *collection, Object id_us_min(&ob->id); } + DEG_id_tag_update_ex(bmain, &collection->id, DEG_TAG_COPY_ON_WRITE); + return true; } @@ -577,7 +566,7 @@ bool BKE_collection_object_add(Main *bmain, Collection *collection, Object *ob) return false; } - if (!collection_object_add(collection, ob, 0, true)) { + if (!collection_object_add(bmain, collection, ob, 0, true)) { return false; } @@ -597,7 +586,7 @@ void BKE_collection_object_add_from(Main *bmain, Scene *scene, Object *ob_src, O FOREACH_SCENE_COLLECTION_BEGIN(scene, collection) { if (BKE_collection_has_object(collection, ob_src)) { - collection_object_add(collection, ob_dst, 0, true); + collection_object_add(bmain, collection, ob_dst, 0, true); } } FOREACH_SCENE_COLLECTION_END; diff --git a/source/blender/blenkernel/intern/data_transfer.c b/source/blender/blenkernel/intern/data_transfer.c index 0451031c5b8..3639649eab5 100644 --- a/source/blender/blenkernel/intern/data_transfer.c +++ b/source/blender/blenkernel/intern/data_transfer.c @@ -50,6 +50,7 @@ #include "BKE_DerivedMesh.h" #include "BKE_mesh.h" #include "BKE_mesh_mapping.h" +#include "BKE_mesh_runtime.h" #include "BKE_mesh_remap.h" #include "BKE_object.h" #include "BKE_object_deform.h" diff --git a/source/blender/blenkernel/intern/displist.c b/source/blender/blenkernel/intern/displist.c index fa996b8f73e..a591ab354f6 100644 --- a/source/blender/blenkernel/intern/displist.c +++ b/source/blender/blenkernel/intern/displist.c @@ -37,6 +37,7 @@ #include "MEM_guardedalloc.h" #include "DNA_curve_types.h" +#include "DNA_mesh_types.h" #include "DNA_scene_types.h" #include "DNA_object_types.h" #include "DNA_vfont_types.h" @@ -51,8 +52,10 @@ #include "BKE_displist.h" #include "BKE_cdderivedmesh.h" #include "BKE_object.h" +#include "BKE_library.h" #include "BKE_mball.h" #include "BKE_mball_tessellate.h" +#include "BKE_mesh.h" #include "BKE_curve.h" #include "BKE_key.h" #include "BKE_anim.h" @@ -925,7 +928,7 @@ static void curve_calc_modifiers_post( Curve *cu = ob->data; int required_mode = 0, totvert = 0; const bool editmode = (!for_render && (cu->editnurb || cu->editfont)); - DerivedMesh *dm = NULL, *ndm; + Mesh *modified = NULL, *mesh_applied; float (*vertCos)[3] = NULL; int useCache = !for_render; ModifierApplyFlag app_flag = 0; @@ -963,23 +966,21 @@ static void curve_calc_modifiers_post( continue; if (mti->type == eModifierTypeType_OnlyDeform || - (mti->type == eModifierTypeType_DeformOrConstruct && !dm)) + (mti->type == eModifierTypeType_DeformOrConstruct && !modified)) { - if (dm) { + if (modified) { if (!vertCos) { - totvert = dm->getNumVerts(dm); - vertCos = MEM_mallocN(sizeof(*vertCos) * totvert, "dfmv"); - dm->getVertCos(dm, vertCos); + vertCos = BKE_mesh_vertexCos_get(modified, &totvert); } - modifier_deformVerts_DM_deprecated(md, &mectx_deform, dm, vertCos, totvert); + modifier_deformVerts(md, &mectx_deform, modified, vertCos, totvert); } else { if (!vertCos) { vertCos = displist_get_allverts(dispbase, &totvert); } - modifier_deformVerts_DM_deprecated(md, &mectx_deform, NULL, vertCos, totvert); + modifier_deformVerts(md, &mectx_deform, NULL, vertCos, totvert); } } else { @@ -991,13 +992,17 @@ static void curve_calc_modifiers_post( break; } - if (dm) { + if (modified) { if (vertCos) { - DerivedMesh *tdm = CDDM_copy(dm); - dm->release(dm); - dm = tdm; - - CDDM_apply_vert_coords(dm, vertCos); + Mesh *temp_mesh; + BKE_id_copy_ex(NULL, &modified->id, (ID **)&temp_mesh, + LIB_ID_CREATE_NO_MAIN | LIB_ID_CREATE_NO_USER_REFCOUNT | + LIB_ID_CREATE_NO_DEG_TAG | LIB_ID_COPY_NO_PREVIEW, + false); + BKE_id_free(NULL, modified); + modified = temp_mesh; + + BKE_mesh_apply_vert_coords(modified, vertCos); } } else { @@ -1009,7 +1014,7 @@ static void curve_calc_modifiers_post( curve_to_filledpoly(cu, nurb, dispbase); } - dm = CDDM_from_curve_displist(ob, dispbase); + modified = BKE_mesh_new_nomain_from_curve_displist(ob, dispbase); } if (vertCos) { @@ -1018,26 +1023,31 @@ static void curve_calc_modifiers_post( vertCos = NULL; } - ndm = modwrap_applyModifier(md, &mectx_apply, dm); + mesh_applied = modifier_applyModifier(md, &mectx_apply, modified); - if (ndm) { + if (mesh_applied) { /* Modifier returned a new derived mesh */ - if (dm && dm != ndm) /* Modifier */ - dm->release(dm); - dm = ndm; + if (modified && modified != mesh_applied) /* Modifier */ + BKE_id_free(NULL, modified); + modified = mesh_applied; } } } if (vertCos) { - if (dm) { - DerivedMesh *tdm = CDDM_copy(dm); - dm->release(dm); - dm = tdm; + if (modified) { + Mesh *temp_mesh; + BKE_id_copy_ex(NULL, &modified->id, (ID **)&temp_mesh, + LIB_ID_CREATE_NO_MAIN | LIB_ID_CREATE_NO_USER_REFCOUNT | + LIB_ID_CREATE_NO_DEG_TAG | LIB_ID_COPY_NO_PREVIEW, + false); + BKE_id_free(NULL, modified); + modified = temp_mesh; + + BKE_mesh_apply_vert_coords(modified, vertCos); + BKE_mesh_calc_normals_mapping_simple(modified); - CDDM_apply_vert_coords(dm, vertCos); - CDDM_calc_normals_mapping(dm); MEM_freeN(vertCos); } else { @@ -1048,22 +1058,27 @@ static void curve_calc_modifiers_post( } if (r_dm_final) { - if (dm) { + if (modified) { /* see: mesh_calc_modifiers */ - if (dm->getNumTessFaces(dm) == 0) { - dm->recalcTessellation(dm); + if (modified->totface == 0) { + BKE_mesh_tessface_calc(modified); } /* Even if tessellation is not needed, some modifiers might have modified CD layers * (like mloopcol or mloopuv), hence we have to update those. */ - else if (dm->dirty & DM_DIRTY_TESS_CDLAYERS) { - DM_update_tessface_data(dm); + else if (modified->runtime.cd_dirty_vert & CD_MASK_TESSLOOPNORMAL) { + BKE_mesh_tessface_calc(modified); } - if (dm->type == DM_TYPE_CDDM) { - CDDM_calc_normals_mapping_ex(dm, (dm->dirty & DM_DIRTY_NORMALS) ? false : true); - } + /* XXX2.8(Sybren): make sure the face normals are recalculated as well */ + BKE_mesh_ensure_normals(modified); + + (*r_dm_final) = CDDM_from_mesh_ex(modified, CD_DUPLICATE, CD_MASK_MESH); + BKE_id_free(NULL, modified); + } + else { + (*r_dm_final) = NULL; } - (*r_dm_final) = dm; + } } @@ -1095,6 +1110,8 @@ static void displist_surf_indices(DispList *dl) } } +/* XXX2.8(Sybren): unused function; impossible to test after porting to Mesh */ +#ifdef WITH_DERIVEDMESH_DEPRECATED_FUNCS static DerivedMesh *create_orco_dm(Depsgraph *depsgraph, Scene *scene, Object *ob) { DerivedMesh *dm; @@ -1138,7 +1155,10 @@ static void add_orco_dm(Object *ob, DerivedMesh *dm, DerivedMesh *orcodm) else DM_add_vert_layer(dm, CD_ORCO, CD_ASSIGN, orco); } +#endif +/* XXX2.8(Sybren): unused function; impossible to test after porting to Mesh */ +#ifdef WITH_DERIVEDMESH_DEPRECATED_FUNCS static void curve_calc_orcodm( Depsgraph *depsgraph, Scene *scene, Object *ob, DerivedMesh *dm_final, const bool for_render, const bool use_render_resolution) @@ -1208,6 +1228,7 @@ static void curve_calc_orcodm( orcodm->release(orcodm); } +#endif void BKE_displist_make_surf( Depsgraph *depsgraph, Scene *scene, Object *ob, ListBase *dispbase, @@ -1816,6 +1837,8 @@ void BKE_displist_make_curveTypes_forOrco( } /* add Orco layer to the displist object which has got derived mesh and return orco */ +/* XXX2.8(Sybren): can be removed once DerivedMesh port is done */ +#ifdef WITH_DERIVEDMESH_DEPRECATED_FUNCS float *BKE_displist_make_orco( Depsgraph *depsgraph, Scene *scene, Object *ob, DerivedMesh *dm_final, const bool for_render, @@ -1838,6 +1861,7 @@ float *BKE_displist_make_orco( return orco; } +#endif void BKE_displist_minmax(ListBase *dispbase, float min[3], float max[3]) { diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c index 89f5f8facda..36452e1d2cf 100644 --- a/source/blender/blenkernel/intern/dynamicpaint.c +++ b/source/blender/blenkernel/intern/dynamicpaint.c @@ -3216,7 +3216,7 @@ void dynamicPaint_outputSurfaceImage(DynamicPaintSurface *surface, char *filenam BKE_image_path_ensure_ext_from_imtype(output_file, format); /* Validate output file path */ - BLI_path_abs(output_file, G.main->name); + BLI_path_abs(output_file, BKE_main_blendfile_path_from_global()); BLI_make_existing_file(output_file); /* Init image buffer */ diff --git a/source/blender/blenkernel/intern/font.c b/source/blender/blenkernel/intern/font.c index 34b185417e3..f7ab5415d1c 100644 --- a/source/blender/blenkernel/intern/font.c +++ b/source/blender/blenkernel/intern/font.c @@ -255,8 +255,8 @@ VFont *BKE_vfont_load(Main *bmain, const char *filepath) } else { BLI_split_file_part(filepath, filename, sizeof(filename)); - pf = newPackedFile(NULL, filepath, bmain->name); - temp_pf = newPackedFile(NULL, filepath, bmain->name); + pf = newPackedFile(NULL, filepath, BKE_main_blendfile_path(bmain)); + temp_pf = newPackedFile(NULL, filepath, BKE_main_blendfile_path(bmain)); is_builtin = false; } @@ -301,7 +301,7 @@ VFont *BKE_vfont_load_exists_ex(struct Main *bmain, const char *filepath, bool * char str[FILE_MAX], strtest[FILE_MAX]; BLI_strncpy(str, filepath, sizeof(str)); - BLI_path_abs(str, bmain->name); + BLI_path_abs(str, BKE_main_blendfile_path(bmain)); /* first search an identical filepath */ for (vfont = bmain->vfont.first; vfont; vfont = vfont->id.next) { diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c index e5c192b3e1e..9a29a8a898b 100644 --- a/source/blender/blenkernel/intern/image.c +++ b/source/blender/blenkernel/intern/image.c @@ -592,7 +592,7 @@ Image *BKE_image_load(Main *bmain, const char *filepath) char str[FILE_MAX]; STRNCPY(str, filepath); - BLI_path_abs(str, bmain->name); + BLI_path_abs(str, BKE_main_blendfile_path(bmain)); /* exists? */ file = BLI_open(str, O_BINARY | O_RDONLY, 0); @@ -621,7 +621,7 @@ Image *BKE_image_load_exists_ex(const char *filepath, bool *r_exists) char str[FILE_MAX], strtest[FILE_MAX]; STRNCPY(str, filepath); - BLI_path_abs(str, G.main->name); + BLI_path_abs(str, BKE_main_blendfile_path_from_global()); /* first search an identical filepath */ for (ima = G.main->image.first; ima; ima = ima->id.next) { @@ -1648,7 +1648,8 @@ static void stampdata(Scene *scene, Object *camera, StampData *stamp_data, int d time_t t; if (scene->r.stamp & R_STAMP_FILENAME) { - SNPRINTF(stamp_data->file, do_prefix ? "File %s" : "%s", G.relbase_valid ? G.main->name : "<untitled>"); + SNPRINTF(stamp_data->file, do_prefix ? "File %s" : "%s", + G.relbase_valid ? BKE_main_blendfile_path_from_global() : "<untitled>"); } else { stamp_data->file[0] = '\0'; @@ -4698,7 +4699,7 @@ static void image_update_views_format(Image *ima, ImageUser *iuser) char str[FILE_MAX]; STRNCPY(str, iv->filepath); - BLI_path_abs(str, G.main->name); + BLI_path_abs(str, BKE_main_blendfile_path_from_global()); /* exists? */ file = BLI_open(str, O_BINARY | O_RDONLY, 0); diff --git a/source/blender/blenkernel/intern/layer.c b/source/blender/blenkernel/intern/layer.c index 16e349465f6..c7bb24cdcee 100644 --- a/source/blender/blenkernel/intern/layer.c +++ b/source/blender/blenkernel/intern/layer.c @@ -1264,6 +1264,16 @@ void BKE_layer_eval_view_layer( /* Store base in the array. */ view_layer->object_bases_array[base_index++] = base; } + if (view_layer == DEG_get_evaluated_view_layer(depsgraph)) { + ViewLayer *view_layer_orig = DEG_get_input_view_layer(depsgraph); + Base *base_orig = view_layer_orig->object_bases.first; + const Base *base_eval = view_layer->object_bases.first; + while (base_orig != NULL) { + base_orig->flag = base_eval->flag; + base_orig = base_orig->next; + base_eval = base_eval->next; + } + } } void BKE_layer_eval_view_layer_indexed( diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c index 667445e7e17..b9244ee1f83 100644 --- a/source/blender/blenkernel/intern/library.c +++ b/source/blender/blenkernel/intern/library.c @@ -155,7 +155,7 @@ * also note that the id _must_ have a library - campbell */ void BKE_id_lib_local_paths(Main *bmain, Library *lib, ID *id) { - const char *bpath_user_data[2] = {bmain->name, lib->filepath}; + const char *bpath_user_data[2] = {BKE_main_blendfile_path(bmain), lib->filepath}; BKE_bpath_traverse_id(bmain, id, BKE_bpath_relocate_visitor, @@ -1739,6 +1739,24 @@ void BKE_main_thumbnail_create(struct Main *bmain) bmain->blen_thumb->height = BLEN_THUMB_SIZE; } +/** + * Return filepath of given \a main. + */ +const char *BKE_main_blendfile_path(const Main *bmain) +{ + return bmain->name; +} + +/** + * Return filepath of global main (G.main). + * + * \warning Usage is not recommended, you should always try to get a velid Main pointer from context... + */ +const char *BKE_main_blendfile_path_from_global(void) +{ + return BKE_main_blendfile_path(G.main); +} + /* ***************** ID ************************ */ ID *BKE_libblock_find_name(struct Main *bmain, const short type, const char *name) { @@ -2527,7 +2545,7 @@ void BKE_library_filepath_set(Main *bmain, Library *lib, const char *filepath) */ /* Never make paths relative to parent lib - reading code (blenloader) always set *all* lib->name relative to * current main, not to their parent for indirectly linked ones. */ - const char *basepath = bmain->name; + const char *basepath = BKE_main_blendfile_path(bmain); BLI_path_abs(lib->filepath, basepath); } } diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c index 109b436292e..1ea2f170922 100644 --- a/source/blender/blenkernel/intern/material.c +++ b/source/blender/blenkernel/intern/material.c @@ -1315,7 +1315,5 @@ void paste_matcopybuf(Main *bmain, Material *ma) void BKE_material_eval(struct Depsgraph *depsgraph, Material *material) { DEG_debug_print_eval(depsgraph, __func__, material->id.name, material); - if ((BLI_listbase_is_empty(&material->gpumaterial) == false)) { - GPU_material_uniform_buffer_tag_dirty(&material->gpumaterial); - } + GPU_material_free(&material->gpumaterial); } diff --git a/source/blender/blenkernel/intern/mball.c b/source/blender/blenkernel/intern/mball.c index 339e79f2757..3afaf2d569e 100644 --- a/source/blender/blenkernel/intern/mball.c +++ b/source/blender/blenkernel/intern/mball.c @@ -563,11 +563,6 @@ void BKE_mball_select_swap(struct MetaBall *mb) /* **** Depsgraph evaluation **** */ -void BKE_mball_eval_geometry(struct Depsgraph *UNUSED(depsgraph), - MetaBall *UNUSED(mball)) -{ -} - /* Draw Engine */ void (*BKE_mball_batch_cache_dirty_cb)(MetaBall *mb, int mode) = NULL; diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c index d27809586c2..b325d8d02d9 100644 --- a/source/blender/blenkernel/intern/mesh.c +++ b/source/blender/blenkernel/intern/mesh.c @@ -46,6 +46,7 @@ #include "BKE_DerivedMesh.h" #include "BKE_global.h" #include "BKE_mesh.h" +#include "BKE_mesh_runtime.h" #include "BKE_library.h" #include "BKE_material.h" #include "BKE_modifier.h" @@ -581,6 +582,34 @@ void BKE_mesh_copy_data(Main *bmain, Mesh *me_dst, const Mesh *me_src, const int } } +/* Custom data layer functions; those assume that totXXX are set correctly. */ +static void mesh_ensure_cdlayers_primary(Mesh *mesh, bool do_tessface) +{ + if (!CustomData_get_layer(&mesh->vdata, CD_MVERT)) + CustomData_add_layer(&mesh->vdata, CD_MVERT, CD_CALLOC, NULL, mesh->totvert); + if (!CustomData_get_layer(&mesh->edata, CD_MEDGE)) + CustomData_add_layer(&mesh->edata, CD_MEDGE, CD_CALLOC, NULL, mesh->totedge); + if (!CustomData_get_layer(&mesh->ldata, CD_MLOOP)) + CustomData_add_layer(&mesh->ldata, CD_MLOOP, CD_CALLOC, NULL, mesh->totloop); + if (!CustomData_get_layer(&mesh->pdata, CD_MPOLY)) + CustomData_add_layer(&mesh->pdata, CD_MPOLY, CD_CALLOC, NULL, mesh->totpoly); + + if (do_tessface && !CustomData_get_layer(&mesh->fdata, CD_MFACE)) + CustomData_add_layer(&mesh->fdata, CD_MFACE, CD_CALLOC, NULL, mesh->totface); +} +static void mesh_ensure_cdlayers_origindex(Mesh *mesh, bool do_tessface) +{ + if (!CustomData_get_layer(&mesh->vdata, CD_ORIGINDEX)) + CustomData_add_layer(&mesh->vdata, CD_ORIGINDEX, CD_CALLOC, NULL, mesh->totvert); + if (!CustomData_get_layer(&mesh->edata, CD_ORIGINDEX)) + CustomData_add_layer(&mesh->edata, CD_ORIGINDEX, CD_CALLOC, NULL, mesh->totedge); + if (!CustomData_get_layer(&mesh->pdata, CD_ORIGINDEX)) + CustomData_add_layer(&mesh->pdata, CD_ORIGINDEX, CD_CALLOC, NULL, mesh->totpoly); + + if (do_tessface && !CustomData_get_layer(&mesh->fdata, CD_ORIGINDEX)) + CustomData_add_layer(&mesh->fdata, CD_ORIGINDEX, CD_CALLOC, NULL, mesh->totface); +} + Mesh *BKE_mesh_new_nomain(int verts_len, int edges_len, int tessface_len, int loops_len, int polys_len) { Mesh *mesh = BKE_libblock_alloc( @@ -598,28 +627,16 @@ Mesh *BKE_mesh_new_nomain(int verts_len, int edges_len, int tessface_len, int lo copy_vn_i(mesh->ldata.typemap, CD_NUMTYPES, -1); copy_vn_i(mesh->pdata.typemap, CD_NUMTYPES, -1); - CustomData_add_layer(&mesh->vdata, CD_ORIGINDEX, CD_CALLOC, NULL, verts_len); - CustomData_add_layer(&mesh->edata, CD_ORIGINDEX, CD_CALLOC, NULL, edges_len); - CustomData_add_layer(&mesh->fdata, CD_ORIGINDEX, CD_CALLOC, NULL, tessface_len); - CustomData_add_layer(&mesh->pdata, CD_ORIGINDEX, CD_CALLOC, NULL, polys_len); - - CustomData_add_layer(&mesh->vdata, CD_MVERT, CD_CALLOC, NULL, verts_len); - CustomData_add_layer(&mesh->edata, CD_MEDGE, CD_CALLOC, NULL, edges_len); - CustomData_add_layer(&mesh->fdata, CD_MFACE, CD_CALLOC, NULL, tessface_len); - CustomData_add_layer(&mesh->ldata, CD_MLOOP, CD_CALLOC, NULL, loops_len); - CustomData_add_layer(&mesh->pdata, CD_MPOLY, CD_CALLOC, NULL, polys_len); - - mesh->mvert = CustomData_get_layer(&mesh->vdata, CD_MVERT); - mesh->medge = CustomData_get_layer(&mesh->edata, CD_MEDGE); - mesh->mface = CustomData_get_layer(&mesh->fdata, CD_MFACE); - mesh->mloop = CustomData_get_layer(&mesh->ldata, CD_MLOOP); - mesh->mpoly = CustomData_get_layer(&mesh->pdata, CD_MPOLY); - mesh->totvert = verts_len; mesh->totedge = edges_len; + mesh->totface = tessface_len; mesh->totloop = loops_len; mesh->totpoly = polys_len; + mesh_ensure_cdlayers_primary(mesh, true); + mesh_ensure_cdlayers_origindex(mesh, true); + BKE_mesh_update_customdata_pointers(mesh, false); + return mesh; } @@ -638,6 +655,7 @@ static Mesh *mesh_new_nomain_from_template_ex( me_dst->totvert = verts_len; me_dst->totedge = edges_len; + me_dst->totface = tessface_len; me_dst->totloop = loops_len; me_dst->totpoly = polys_len; @@ -652,15 +670,12 @@ static Mesh *mesh_new_nomain_from_template_ex( mesh_tessface_clear_intern(me_dst, false); } + /* The destination mesh should at least have valid primary CD layers, + * even in cases where the source mesh does not. */ + mesh_ensure_cdlayers_primary(me_dst, do_tessface); + mesh_ensure_cdlayers_origindex(me_dst, false); BKE_mesh_update_customdata_pointers(me_dst, false); - if (!CustomData_get_layer(&me_dst->vdata, CD_ORIGINDEX)) - CustomData_add_layer(&me_dst->vdata, CD_ORIGINDEX, CD_CALLOC, NULL, verts_len); - if (!CustomData_get_layer(&me_dst->edata, CD_ORIGINDEX)) - CustomData_add_layer(&me_dst->edata, CD_ORIGINDEX, CD_CALLOC, NULL, edges_len); - if (!CustomData_get_layer(&me_dst->pdata, CD_ORIGINDEX)) - CustomData_add_layer(&me_dst->pdata, CD_ORIGINDEX, CD_CALLOC, NULL, polys_len); - return me_dst; } diff --git a/source/blender/blenkernel/intern/mesh_convert.c b/source/blender/blenkernel/intern/mesh_convert.c index a3eef7b17b2..acd0cf32b13 100644 --- a/source/blender/blenkernel/intern/mesh_convert.c +++ b/source/blender/blenkernel/intern/mesh_convert.c @@ -43,6 +43,7 @@ #include "BKE_global.h" #include "BKE_key.h" #include "BKE_mesh.h" +#include "BKE_mesh_runtime.h" #include "BKE_modifier.h" #include "BKE_displist.h" #include "BKE_library.h" @@ -1263,7 +1264,7 @@ static void shapekey_layers_to_keyblocks(Mesh *mesh_src, Mesh *mesh_dst, int act /* This is a Mesh-based copy of DM_to_mesh() */ -void BKE_nomain_mesh_to_mesh(Mesh *mesh_src, Mesh *mesh_dst, Object *ob, CustomDataMask mask, bool take_ownership) +void BKE_mesh_nomain_to_mesh(Mesh *mesh_src, Mesh *mesh_dst, Object *ob, CustomDataMask mask, bool take_ownership) { /* mesh_src might depend on mesh_dst, so we need to do everything with a local copy */ /* TODO(Sybren): the above claim came from DM_to_mesh(); check whether it is still true with Mesh */ @@ -1414,7 +1415,7 @@ void BKE_nomain_mesh_to_mesh(Mesh *mesh_src, Mesh *mesh_dst, Object *ob, CustomD } /* This is a Mesh-based copy of DM_to_meshkey() */ -void BKE_nomain_mesh_to_meshkey(Mesh *mesh_src, Mesh *mesh_dst, KeyBlock *kb) +void BKE_mesh_nomain_to_meshkey(Mesh *mesh_src, Mesh *mesh_dst, KeyBlock *kb) { int a, totvert = mesh_src->totvert; float *fp; diff --git a/source/blender/blenkernel/intern/mesh_evaluate.c b/source/blender/blenkernel/intern/mesh_evaluate.c index 068be0ef304..2d8476d6f02 100644 --- a/source/blender/blenkernel/intern/mesh_evaluate.c +++ b/source/blender/blenkernel/intern/mesh_evaluate.c @@ -88,6 +88,20 @@ static void mesh_calc_normals_vert_fallback(MVert *mverts, int numVerts) } } +/* TODO(Sybren): we can probably rename this to BKE_mesh_calc_normals_mapping(), + * and remove the function of the same name below, as that one doesn't seem to be + * called anywhere. */ +void BKE_mesh_calc_normals_mapping_simple(struct Mesh *mesh) +{ + const bool only_face_normals = CustomData_is_referenced_layer(&mesh->vdata, CD_MVERT); + + BKE_mesh_calc_normals_mapping_ex( + mesh->mvert, mesh->totvert, + mesh->mloop, mesh->mpoly, mesh->totloop, mesh->totpoly, NULL, + mesh->mface, mesh->totface, NULL, NULL, + only_face_normals); +} + /* Calculate vertex and face normals, face normals are returned in *r_faceNors if non-NULL * and vertex normals are stored in actual mverts. */ diff --git a/source/blender/blenkernel/intern/mesh_runtime.c b/source/blender/blenkernel/intern/mesh_runtime.c index c8416811694..cd9db408d19 100644 --- a/source/blender/blenkernel/intern/mesh_runtime.c +++ b/source/blender/blenkernel/intern/mesh_runtime.c @@ -35,13 +35,22 @@ #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" +#include "DNA_object_types.h" #include "BLI_math_geom.h" #include "BLI_threads.h" #include "BKE_bvhutils.h" #include "BKE_mesh.h" +#include "BKE_mesh_runtime.h" +#ifdef USE_DERIVEDMESH +#include "BKE_DerivedMesh.h" +#endif + +/* -------------------------------------------------------------------- */ +/** \name Mesh Runtime Struct Utils + * \{ */ static ThreadRWMutex loops_cache_lock = PTHREAD_RWLOCK_INITIALIZER; @@ -145,8 +154,9 @@ const MLoopTri *BKE_mesh_runtime_looptri_ensure(Mesh *mesh) } /* This is a copy of DM_verttri_from_looptri(). */ -void BKE_mesh_runtime_verttri_from_looptri(MVertTri *r_verttri, const MLoop *mloop, - const MLoopTri *looptri, int looptri_num) +void BKE_mesh_runtime_verttri_from_looptri( + MVertTri *r_verttri, const MLoop *mloop, + const MLoopTri *looptri, int looptri_num) { int i; for (i = 0; i < looptri_num; i++) { @@ -192,6 +202,12 @@ void BKE_mesh_runtime_clear_geometry(Mesh *mesh) MEM_SAFE_FREE(mesh->runtime.looptris.array); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Mesh Batch Cache Callbacks + * \{ */ + /* Draw Engine */ void (*BKE_mesh_batch_cache_dirty_cb)(Mesh *me, int mode) = NULL; void (*BKE_mesh_batch_cache_free_cb)(Mesh *me) = NULL; @@ -208,3 +224,5 @@ void BKE_mesh_batch_cache_free(Mesh *me) BKE_mesh_batch_cache_free_cb(me); } } + +/** \} */ diff --git a/source/blender/blenkernel/intern/movieclip.c b/source/blender/blenkernel/intern/movieclip.c index d742bcea69d..fc236cc2ad0 100644 --- a/source/blender/blenkernel/intern/movieclip.c +++ b/source/blender/blenkernel/intern/movieclip.c @@ -199,7 +199,7 @@ static void get_proxy_fname(const MovieClip *clip, else BLI_snprintf(name, FILE_MAX, "%s/%s/proxy_%d/%08d", dir, clipfile, size, proxynr); - BLI_path_abs(name, G.main->name); + BLI_path_abs(name, BKE_main_blendfile_path_from_global()); BLI_path_frame(name, 1, 0); strcat(name, ".jpg"); @@ -270,7 +270,7 @@ static void movieclip_open_anim_file(MovieClip *clip) if (clip->flag & MCLIP_USE_PROXY_CUSTOM_DIR) { char dir[FILE_MAX]; BLI_strncpy(dir, clip->proxy.dir, sizeof(dir)); - BLI_path_abs(dir, G.main->name); + BLI_path_abs(dir, BKE_main_blendfile_path_from_global()); IMB_anim_set_index_dir(clip->anim, dir); } } @@ -627,13 +627,13 @@ static void movieclip_load_get_size(MovieClip *clip) } } -static void detect_clip_source(MovieClip *clip) +static void detect_clip_source(Main *bmain, MovieClip *clip) { ImBuf *ibuf; char name[FILE_MAX]; BLI_strncpy(name, clip->name, sizeof(name)); - BLI_path_abs(name, G.main->name); + BLI_path_abs(name, BKE_main_blendfile_path(bmain)); ibuf = IMB_testiffname(name, IB_rect | IB_multilayer); if (ibuf) { @@ -656,7 +656,7 @@ MovieClip *BKE_movieclip_file_add(Main *bmain, const char *name) char str[FILE_MAX]; BLI_strncpy(str, name, sizeof(str)); - BLI_path_abs(str, bmain->name); + BLI_path_abs(str, BKE_main_blendfile_path(bmain)); /* exists? */ file = BLI_open(str, O_BINARY | O_RDONLY, 0); @@ -670,7 +670,7 @@ MovieClip *BKE_movieclip_file_add(Main *bmain, const char *name) clip = movieclip_alloc(bmain, BLI_path_basename(name)); BLI_strncpy(clip->name, name, sizeof(clip->name)); - detect_clip_source(clip); + detect_clip_source(bmain, clip); movieclip_load_get_size(clip); if (clip->lastsize[0]) { @@ -690,7 +690,7 @@ MovieClip *BKE_movieclip_file_add_exists_ex(Main *bmain, const char *filepath, b char str[FILE_MAX], strtest[FILE_MAX]; BLI_strncpy(str, filepath, sizeof(str)); - BLI_path_abs(str, bmain->name); + BLI_path_abs(str, BKE_main_blendfile_path(bmain)); /* first search an identical filepath */ for (clip = bmain->movieclip.first; clip; clip = clip->id.next) { @@ -1282,13 +1282,13 @@ void BKE_movieclip_clear_proxy_cache(MovieClip *clip) } } -void BKE_movieclip_reload(MovieClip *clip) +void BKE_movieclip_reload(Main *bmain, MovieClip *clip) { /* clear cache */ free_buffers(clip); /* update clip source */ - detect_clip_source(clip); + detect_clip_source(bmain, clip); clip->lastsize[0] = clip->lastsize[1] = 0; movieclip_load_get_size(clip); diff --git a/source/blender/blenkernel/intern/multires.c b/source/blender/blenkernel/intern/multires.c index ee32c2398b2..39a472241bc 100644 --- a/source/blender/blenkernel/intern/multires.c +++ b/source/blender/blenkernel/intern/multires.c @@ -51,6 +51,7 @@ #include "BKE_cdderivedmesh.h" #include "BKE_mesh.h" #include "BKE_mesh_mapping.h" +#include "BKE_mesh_runtime.h" #include "BKE_modifier.h" #include "BKE_multires.h" #include "BKE_paint.h" diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c index 7a1f6c5d2b6..bf25306028f 100644 --- a/source/blender/blenkernel/intern/node.c +++ b/source/blender/blenkernel/intern/node.c @@ -3739,43 +3739,9 @@ void BKE_nodetree_remove_layer_n(bNodeTree *ntree, Scene *scene, const int layer } } -static void node_copy_default_values_list(ListBase *sockets_dst, - const ListBase *sockets_src) -{ - bNodeSocket *sock_dst = sockets_dst->first; - const bNodeSocket *sock_src = sockets_src->first; - while (sock_dst != NULL) { - node_socket_copy_default_value(sock_dst, sock_src); - sock_dst = sock_dst->next; - sock_src = sock_src->next; - } -} - -static void node_copy_default_values(bNode *node_dst, const bNode *node_src) -{ - node_copy_default_values_list(&node_dst->inputs, &node_src->inputs); - node_copy_default_values_list(&node_dst->outputs, &node_src->outputs); -} - -void BKE_nodetree_copy_default_values(bNodeTree *ntree_dst, - const bNodeTree *ntree_src) -{ - if (ntree_dst == ntree_src) { - return; - } - bNode *node_dst = ntree_dst->nodes.first; - const bNode *node_src = ntree_src->nodes.first; - while (node_dst != NULL) { - node_copy_default_values(node_dst, node_src); - node_dst = node_dst->next; - node_src = node_src->next; - } -} - void BKE_nodetree_shading_params_eval(struct Depsgraph *depsgraph, bNodeTree *ntree_dst, const bNodeTree *ntree_src) { DEG_debug_print_eval(depsgraph, __func__, ntree_src->id.name, ntree_dst); - BKE_nodetree_copy_default_values(ntree_dst, ntree_src); } diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index 522ed65174c..f55925f64f5 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -330,16 +330,7 @@ void BKE_object_free_derived_caches(Object *ob) ob->bb = NULL; } - if (ob->derivedFinal) { - ob->derivedFinal->needsFree = 1; - ob->derivedFinal->release(ob->derivedFinal); - ob->derivedFinal = NULL; - } - if (ob->derivedDeform) { - ob->derivedDeform->needsFree = 1; - ob->derivedDeform->release(ob->derivedDeform); - ob->derivedDeform = NULL; - } + BKE_object_free_derived_mesh_caches(ob); if (ob->runtime.mesh_eval != NULL) { Mesh *mesh_eval = ob->runtime.mesh_eval; @@ -365,6 +356,20 @@ void BKE_object_free_derived_caches(Object *ob) BKE_object_free_curve_cache(ob); } +void BKE_object_free_derived_mesh_caches(struct Object *ob) +{ + if (ob->derivedFinal) { + ob->derivedFinal->needsFree = 1; + ob->derivedFinal->release(ob->derivedFinal); + ob->derivedFinal = NULL; + } + if (ob->derivedDeform) { + ob->derivedDeform->needsFree = 1; + ob->derivedDeform->release(ob->derivedDeform); + ob->derivedDeform = NULL; + } +} + void BKE_object_free_caches(Object *object) { ModifierData *md; @@ -2875,8 +2880,7 @@ Mesh *BKE_object_get_pre_modified_mesh(Object *object) if (object->runtime.mesh_orig != NULL) { BLI_assert(object->id.tag & LIB_TAG_COPIED_ON_WRITE); BLI_assert(object->id.orig_id != NULL); - BLI_assert(object->runtime.mesh_orig->id.orig_id == - ((Object*)object->id.orig_id)->data); + BLI_assert(object->runtime.mesh_orig->id.orig_id == ((Object *)object->id.orig_id)->data); Mesh *result = object->runtime.mesh_orig; BLI_assert((result->id.tag & LIB_TAG_COPIED_ON_WRITE) != 0); BLI_assert((result->id.tag & LIB_TAG_COPIED_ON_WRITE_EVAL_RESULT) == 0); @@ -2900,7 +2904,7 @@ Mesh *BKE_object_get_original_mesh(Object *object) } else { BLI_assert((object->id.tag & LIB_TAG_COPIED_ON_WRITE) != 0); - result = ((Object*)object->id.orig_id)->data; + result = ((Object *)object->id.orig_id)->data; } BLI_assert(result != NULL); BLI_assert((result->id.tag & (LIB_TAG_COPIED_ON_WRITE | LIB_TAG_COPIED_ON_WRITE_EVAL_RESULT)) == 0); diff --git a/source/blender/blenkernel/intern/object_dupli.c b/source/blender/blenkernel/intern/object_dupli.c index 2c94dc76854..324ad3a31dc 100644 --- a/source/blender/blenkernel/intern/object_dupli.c +++ b/source/blender/blenkernel/intern/object_dupli.c @@ -56,6 +56,7 @@ #include "BKE_lattice.h" #include "BKE_main.h" #include "BKE_mesh.h" +#include "BKE_mesh_runtime.h" #include "BKE_object.h" #include "BKE_particle.h" #include "BKE_scene.h" @@ -72,8 +73,6 @@ typedef struct DupliContext { Depsgraph *depsgraph; - bool do_update; - bool animated; Collection *collection; /* XXX child objects are selected from this group if set, could be nicer */ Object *obedit; /* Only to check if the object is in edit-mode. */ @@ -99,14 +98,11 @@ typedef struct DupliGenerator { static const DupliGenerator *get_dupli_generator(const DupliContext *ctx); /* create initial context for root object */ -static void init_context(DupliContext *r_ctx, Depsgraph *depsgraph, Scene *scene, Object *ob, float space_mat[4][4], bool update) +static void init_context(DupliContext *r_ctx, Depsgraph *depsgraph, Scene *scene, Object *ob, float space_mat[4][4]) { r_ctx->depsgraph = depsgraph; r_ctx->scene = scene; r_ctx->view_layer = DEG_get_evaluated_view_layer(depsgraph); - /* don't allow BKE_object_handle_update for viewport during render, can crash */ - r_ctx->do_update = update && !(G.is_rendering && DEG_get_mode(depsgraph) != DAG_EVAL_RENDER); - r_ctx->animated = false; r_ctx->collection = NULL; r_ctx->object = ob; @@ -123,12 +119,10 @@ static void init_context(DupliContext *r_ctx, Depsgraph *depsgraph, Scene *scene } /* create sub-context for recursive duplis */ -static void copy_dupli_context(DupliContext *r_ctx, const DupliContext *ctx, Object *ob, float mat[4][4], int index, bool animated) +static void copy_dupli_context(DupliContext *r_ctx, const DupliContext *ctx, Object *ob, float mat[4][4], int index) { *r_ctx = *ctx; - r_ctx->animated |= animated; /* object animation makes all children animated */ - /* XXX annoying, previously was done by passing an ID* argument, this at least is more explicit */ if (ctx->gen->type == OB_DUPLICOLLECTION) r_ctx->collection = ctx->object->dup_group; @@ -146,8 +140,7 @@ static void copy_dupli_context(DupliContext *r_ctx, const DupliContext *ctx, Obj * mat is transform of the object relative to current context (including object obmat) */ static DupliObject *make_dupli(const DupliContext *ctx, - Object *ob, float mat[4][4], int index, - bool animated, bool hide) + Object *ob, float mat[4][4], int index) { DupliObject *dob; int i; @@ -164,7 +157,6 @@ static DupliObject *make_dupli(const DupliContext *ctx, dob->ob = ob; mul_m4_m4m4(dob->mat, (float (*)[4])ctx->space_mat, mat); dob->type = ctx->gen->type; - dob->animated = animated || ctx->animated; /* object itself or some parent is animated */ /* set persistent id, which is an array with a persistent index for each level * (particle number, vertex number, ..). by comparing this we can find the same @@ -177,8 +169,6 @@ static DupliObject *make_dupli(const DupliContext *ctx, for (; i < MAX_DUPLI_RECUR; i++) dob->persistent_id[i] = INT_MAX; - if (hide) - dob->no_draw = true; /* metaballs never draw in duplis, they are instead merged into one by the basis * mball outside of the group. this does mean that if that mball is not in the * scene, they will not show up at all, limitation that should be solved once. */ @@ -208,12 +198,12 @@ static DupliObject *make_dupli(const DupliContext *ctx, /* recursive dupli objects * space_mat is the local dupli space (excluding dupli object obmat!) */ -static void make_recursive_duplis(const DupliContext *ctx, Object *ob, float space_mat[4][4], int index, bool animated) +static void make_recursive_duplis(const DupliContext *ctx, Object *ob, float space_mat[4][4], int index) { /* simple preventing of too deep nested collections with MAX_DUPLI_RECUR */ if (ctx->level < MAX_DUPLI_RECUR) { DupliContext rctx; - copy_dupli_context(&rctx, ctx, ob, space_mat, index, animated); + copy_dupli_context(&rctx, ctx, ob, space_mat, index); if (rctx.gen) { rctx.gen->make_duplis(&rctx); } @@ -247,7 +237,7 @@ static void make_child_duplis(const DupliContext *ctx, void *userdata, MakeChild Object *ob = base->object; if ((base->flag & BASE_VISIBLED) && ob != ctx->obedit && is_child(ob, parent)) { DupliContext pctx; - copy_dupli_context(&pctx, ctx, ctx->object, NULL, collectionid, false); + copy_dupli_context(&pctx, ctx, ctx->object, NULL, collectionid); /* mballs have a different dupli handling */ if (ob->type != OB_MBALL) { @@ -266,7 +256,7 @@ static void make_child_duplis(const DupliContext *ctx, void *userdata, MakeChild Object *ob = base->object; if ((ob != ctx->obedit) && is_child(ob, parent)) { DupliContext pctx; - copy_dupli_context(&pctx, ctx, ctx->object, NULL, baseid, false); + copy_dupli_context(&pctx, ctx, ctx->object, NULL, baseid); /* mballs have a different dupli handling */ if (ob->type != OB_MBALL) @@ -289,7 +279,6 @@ static void make_duplis_collection(const DupliContext *ctx) Base *base; float collection_mat[4][4]; int id; - bool animated; if (ob->dup_group == NULL) return; collection = ob->dup_group; @@ -300,17 +289,6 @@ static void make_duplis_collection(const DupliContext *ctx) mul_m4_m4m4(collection_mat, ob->obmat, collection_mat); /* don't access 'ob->obmat' from now on. */ - /* handles animated collections */ - - /* we need to check update for objects that are not in scene... */ - if (ctx->do_update) { - /* note: update is optional because we don't always need object - * transformations to be correct. Also fixes bug [#29616]. */ - BKE_collection_handle_recalc_and_update(ctx->depsgraph, ctx->scene, ob, collection); - } - - animated = BKE_collection_is_animated(collection, ob); - const ListBase dup_collection_objects = BKE_collection_object_cache_get(collection); for (base = dup_collection_objects.first, id = 0; base; base = base->next, id++) { if (base->object != ob && (base->flag & BASE_VISIBLED)) { @@ -319,10 +297,10 @@ static void make_duplis_collection(const DupliContext *ctx) /* collection dupli offset, should apply after everything else */ mul_m4_m4m4(mat, collection_mat, base->object->obmat); - make_dupli(ctx, base->object, mat, id, animated, false); + make_dupli(ctx, base->object, mat, id); /* recursion */ - make_recursive_duplis(ctx, base->object, collection_mat, id, animated); + make_recursive_duplis(ctx, base->object, collection_mat, id); } } } @@ -383,7 +361,7 @@ static void make_duplis_frames(const DupliContext *ctx) BKE_animsys_evaluate_animdata(depsgraph, scene, &ob->id, ob->adt, (float)scene->r.cfra, ADT_RECALC_ANIM); BKE_object_where_is_calc_time(depsgraph, scene, ob, (float)scene->r.cfra); - make_dupli(ctx, ob, ob->obmat, scene->r.cfra, false, false); + make_dupli(ctx, ob, ob->obmat, scene->r.cfra); } } @@ -469,13 +447,13 @@ static void vertex_dupli__mapFunc(void *userData, int index, const float co[3], */ mul_m4_m4m4(space_mat, obmat, inst_ob->imat); - dob = make_dupli(vdd->ctx, vdd->inst_ob, obmat, index, false, false); + dob = make_dupli(vdd->ctx, vdd->inst_ob, obmat, index); if (vdd->orco) copy_v3_v3(dob->orco, vdd->orco[index]); /* recursion */ - make_recursive_duplis(vdd->ctx, vdd->inst_ob, space_mat, index, false); + make_recursive_duplis(vdd->ctx, vdd->inst_ob, space_mat, index); } static void make_child_duplis_verts(const DupliContext *ctx, void *userdata, Object *child) @@ -654,7 +632,7 @@ static void make_duplis_font(const DupliContext *ctx) copy_v3_v3(obmat[3], vec); - make_dupli(ctx, ob, obmat, a, false, false); + make_dupli(ctx, ob, obmat, a); } } @@ -760,7 +738,7 @@ static void make_child_duplis_faces(const DupliContext *ctx, void *userdata, Obj */ mul_m4_m4m4(space_mat, obmat, inst_ob->imat); - dob = make_dupli(ctx, inst_ob, obmat, a, false, false); + dob = make_dupli(ctx, inst_ob, obmat, a); if (use_texcoords) { float w = 1.0f / (float)mp->totloop; @@ -780,7 +758,7 @@ static void make_child_duplis_faces(const DupliContext *ctx, void *userdata, Obj } /* recursion */ - make_recursive_duplis(ctx, inst_ob, space_mat, a, false); + make_recursive_duplis(ctx, inst_ob, space_mat, a); } } @@ -925,10 +903,6 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem /* gather list of objects or single object */ if (part->ren_as == PART_DRAW_GR) { - if (ctx->do_update) { - BKE_collection_handle_recalc_and_update(ctx->depsgraph, scene, par, part->dup_group); - } - if (part->draw & PART_DRAW_COUNT_GR) { for (dw = part->dupliweights.first; dw; dw = dw->next) totcollection += dw->count; @@ -1075,7 +1049,7 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem /* individual particle transform */ mul_m4_m4m4(mat, pamat, tmat); - dob = make_dupli(ctx, object, mat, a, false, false); + dob = make_dupli(ctx, object, mat, a); dob->particle_system = psys; if (use_texcoords) { @@ -1129,7 +1103,7 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem if (part->draw & PART_DRAW_GLOBAL_OB) add_v3_v3v3(mat[3], mat[3], vec); - dob = make_dupli(ctx, ob, mat, a, false, false); + dob = make_dupli(ctx, ob, mat, a); dob->particle_system = psys; if (use_texcoords) psys_get_dupli_texture(psys, part, sim.psmd, pa, cpa, dob->uv, dob->orco); @@ -1166,7 +1140,7 @@ static void make_duplis_particles(const DupliContext *ctx) for (psys = ctx->object->particlesystem.first, psysid = 0; psys; psys = psys->next, psysid++) { /* particles create one more level for persistent psys index */ DupliContext pctx; - copy_dupli_context(&pctx, ctx, ctx->object, NULL, psysid, false); + copy_dupli_context(&pctx, ctx, ctx->object, NULL, psysid); make_duplis_particle_system(&pctx, psys); } } @@ -1220,11 +1194,11 @@ static const DupliGenerator *get_dupli_generator(const DupliContext *ctx) /* ---- ListBase dupli container implementation ---- */ /* Returns a list of DupliObject */ -ListBase *object_duplilist_ex(Depsgraph *depsgraph, Scene *scene, Object *ob, bool update) +ListBase *object_duplilist(Depsgraph *depsgraph, Scene *sce, Object *ob) { ListBase *duplilist = MEM_callocN(sizeof(ListBase), "duplilist"); DupliContext ctx; - init_context(&ctx, depsgraph, scene, ob, NULL, update); + init_context(&ctx, depsgraph, sce, ob, NULL); if (ctx.gen) { ctx.duplilist = duplilist; ctx.gen->make_duplis(&ctx); @@ -1233,13 +1207,6 @@ ListBase *object_duplilist_ex(Depsgraph *depsgraph, Scene *scene, Object *ob, bo return duplilist; } -/* note: previously updating was always done, this is why it defaults to be on - * but there are likely places it can be called without updating */ -ListBase *object_duplilist(Depsgraph *depsgraph, Scene *sce, Object *ob) -{ - return object_duplilist_ex(depsgraph, sce, ob, true); -} - void free_object_duplilist(ListBase *lb) { BLI_freelistN(lb); diff --git a/source/blender/blenkernel/intern/object_update.c b/source/blender/blenkernel/intern/object_update.c index 852d8197a6c..3b684ebfd94 100644 --- a/source/blender/blenkernel/intern/object_update.c +++ b/source/blender/blenkernel/intern/object_update.c @@ -145,6 +145,7 @@ void BKE_object_eval_done(Depsgraph *depsgraph, Object *ob) Object *ob_orig = DEG_get_original_object(ob); copy_m4_m4(ob_orig->obmat, ob->obmat); ob_orig->transflag = ob->transflag; + ob_orig->flag = ob->flag; } } diff --git a/source/blender/blenkernel/intern/packedFile.c b/source/blender/blenkernel/intern/packedFile.c index afb155f7646..baa88f00985 100644 --- a/source/blender/blenkernel/intern/packedFile.c +++ b/source/blender/blenkernel/intern/packedFile.c @@ -246,14 +246,14 @@ void packAll(Main *bmain, ReportList *reports, bool verbose) for (vfont = bmain->vfont.first; vfont; vfont = vfont->id.next) { if (vfont->packedfile == NULL && !ID_IS_LINKED(vfont) && BKE_vfont_is_builtin(vfont) == false) { - vfont->packedfile = newPackedFile(reports, vfont->name, bmain->name); + vfont->packedfile = newPackedFile(reports, vfont->name, BKE_main_blendfile_path(bmain)); tot ++; } } for (sound = bmain->sound.first; sound; sound = sound->id.next) { if (sound->packedfile == NULL && !ID_IS_LINKED(sound)) { - sound->packedfile = newPackedFile(reports, sound->name, bmain->name); + sound->packedfile = newPackedFile(reports, sound->name, BKE_main_blendfile_path(bmain)); tot++; } } @@ -542,7 +542,7 @@ int unpackVFont(Main *bmain, ReportList *reports, VFont *vfont, int how) if (vfont != NULL) { unpack_generate_paths(vfont->name, (ID *)vfont, absname, localname, sizeof(absname), sizeof(localname)); - newname = unpackFile(reports, bmain->name, absname, localname, vfont->packedfile, how); + newname = unpackFile(reports, BKE_main_blendfile_path(bmain), absname, localname, vfont->packedfile, how); if (newname != NULL) { ret_value = RET_OK; freePackedFile(vfont->packedfile); @@ -563,7 +563,7 @@ int unpackSound(Main *bmain, ReportList *reports, bSound *sound, int how) if (sound != NULL) { unpack_generate_paths(sound->name, (ID *)sound, absname, localname, sizeof(absname), sizeof(localname)); - newname = unpackFile(reports, bmain->name, absname, localname, sound->packedfile, how); + newname = unpackFile(reports, BKE_main_blendfile_path(bmain), absname, localname, sound->packedfile, how); if (newname != NULL) { BLI_strncpy(sound->name, newname, sizeof(sound->name)); MEM_freeN(newname); @@ -591,7 +591,7 @@ int unpackImage(Main *bmain, ReportList *reports, Image *ima, int how) ImagePackedFile *imapf = ima->packedfiles.last; unpack_generate_paths(imapf->filepath, (ID *)ima, absname, localname, sizeof(absname), sizeof(localname)); - newname = unpackFile(reports, bmain->name, absname, localname, imapf->packedfile, how); + newname = unpackFile(reports, BKE_main_blendfile_path(bmain), absname, localname, imapf->packedfile, how); if (newname != NULL) { ImageView *iv; @@ -637,7 +637,7 @@ int unpackLibraries(Main *bmain, ReportList *reports) for (lib = bmain->library.first; lib; lib = lib->id.next) { if (lib->packedfile && lib->name[0]) { - newname = unpackFile(reports, bmain->name, lib->filepath, lib->filepath, lib->packedfile, PF_WRITE_ORIGINAL); + newname = unpackFile(reports, BKE_main_blendfile_path(bmain), lib->filepath, lib->filepath, lib->packedfile, PF_WRITE_ORIGINAL); if (newname != NULL) { ret_value = RET_OK; @@ -670,7 +670,7 @@ void packLibraries(Main *bmain, ReportList *reports) for (lib = bmain->library.first; lib; lib = lib->id.next) if (lib->packedfile == NULL) - lib->packedfile = newPackedFile(reports, lib->name, bmain->name); + lib->packedfile = newPackedFile(reports, lib->name, BKE_main_blendfile_path(bmain)); } void unpackAll(Main *bmain, ReportList *reports, int how) diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c index f961510984a..f03b46c8a07 100644 --- a/source/blender/blenkernel/intern/paint.c +++ b/source/blender/blenkernel/intern/paint.c @@ -59,6 +59,8 @@ #include "BKE_key.h" #include "BKE_library.h" #include "BKE_mesh.h" +#include "BKE_mesh_mapping.h" +#include "BKE_mesh_runtime.h" #include "BKE_modifier.h" #include "BKE_object.h" #include "BKE_paint.h" @@ -753,7 +755,6 @@ void BKE_sculptsession_free(Object *ob) { if (ob && ob->sculpt) { SculptSession *ss = ob->sculpt; - DerivedMesh *dm = ob->derivedFinal; if (ss->bm) { BKE_sculptsession_bm_to_me(ob, true); @@ -762,12 +763,11 @@ void BKE_sculptsession_free(Object *ob) if (ss->pbvh) BKE_pbvh_free(ss->pbvh); + MEM_SAFE_FREE(ss->pmap); + MEM_SAFE_FREE(ss->pmap_mem); if (ss->bm_log) BM_log_free(ss->bm_log); - if (dm && dm->getPBVH) - dm->getPBVH(NULL, dm); /* signal to clear */ - if (ss->texcache) MEM_freeN(ss->texcache); @@ -872,9 +872,8 @@ void BKE_sculpt_update_mesh_elements( return; } - DerivedMesh *dm; SculptSession *ss = ob->sculpt; - Mesh *me = ob->data; + Mesh *me = BKE_object_get_original_mesh(ob); MultiresModifierData *mmd = BKE_sculpt_multires_active(scene, ob); ss->modifiers_active = sculpt_modifiers_active(scene, sd, ob); @@ -909,13 +908,14 @@ void BKE_sculpt_update_mesh_elements( ss->kb = (mmd == NULL) ? BKE_keyblock_from_object(ob) : NULL; - dm = mesh_get_derived_final(depsgraph, scene, ob, CD_MASK_BAREMESH); + Mesh *me_eval = mesh_get_eval_final(depsgraph, scene, ob, CD_MASK_BAREMESH); + Mesh *me_eval_deform = mesh_get_eval_deform(depsgraph, scene, ob, CD_MASK_BAREMESH); /* VWPaint require mesh info for loop lookup, so require sculpt mode here */ if (mmd && ob->mode & OB_MODE_SCULPT) { ss->multires = mmd; - ss->totvert = dm->getNumVerts(dm); - ss->totpoly = dm->getNumPolys(dm); + ss->totvert = me_eval->totvert; + ss->totpoly = me_eval->totpoly; ss->mvert = NULL; ss->mpoly = NULL; ss->mloop = NULL; @@ -930,8 +930,17 @@ void BKE_sculpt_update_mesh_elements( ss->vmask = CustomData_get_layer(&me->vdata, CD_PAINT_MASK); } - ss->pbvh = dm->getPBVH(ob, dm); - ss->pmap = (need_pmap && dm->getPolyMap) ? dm->getPolyMap(ob, dm) : NULL; + PBVH *pbvh = BKE_sculpt_object_pbvh_ensure(ob, me_eval_deform); + BLI_assert(pbvh == ss->pbvh); + UNUSED_VARS_NDEBUG(pbvh); + MEM_SAFE_FREE(ss->pmap); + MEM_SAFE_FREE(ss->pmap_mem); + if (need_pmap && ob->type == OB_MESH) { + BKE_mesh_vert_poly_map_create( + &ss->pmap, &ss->pmap_mem, + me->mpoly, me->mloop, + me->totvert, me->totpoly, me->totloop); + } pbvh_show_diffuse_color_set(ss->pbvh, ss->show_diffuse_color); pbvh_show_mask_set(ss->pbvh, ss->show_mask); @@ -945,7 +954,7 @@ void BKE_sculpt_update_mesh_elements( ss->orig_cos = (ss->kb) ? BKE_keyblock_convert_to_vertcos(ob, ss->kb) : BKE_mesh_vertexCos_get(me, NULL); BKE_crazyspace_build_sculpt(depsgraph, scene, ob, &ss->deform_imats, &ss->deform_cos); - BKE_pbvh_apply_vertCos(ss->pbvh, ss->deform_cos); + BKE_pbvh_apply_vertCos(ss->pbvh, ss->deform_cos, me->totvert); for (a = 0; a < me->totvert; ++a) { invert_m3(ss->deform_imats[a]); @@ -962,14 +971,14 @@ void BKE_sculpt_update_mesh_elements( /* if pbvh is deformed, key block is already applied to it */ if (ss->kb) { - bool pbvh_deformd = BKE_pbvh_isDeformed(ss->pbvh); - if (!pbvh_deformd || ss->deform_cos == NULL) { + bool pbvh_deformed = BKE_pbvh_isDeformed(ss->pbvh); + if (!pbvh_deformed || ss->deform_cos == NULL) { float (*vertCos)[3] = BKE_keyblock_convert_to_vertcos(ob, ss->kb); if (vertCos) { - if (!pbvh_deformd) { + if (!pbvh_deformed) { /* apply shape keys coordinates to PBVH */ - BKE_pbvh_apply_vertCos(ss->pbvh, vertCos); + BKE_pbvh_apply_vertCos(ss->pbvh, vertCos, me->totvert); } if (ss->deform_cos == NULL) { ss->deform_cos = vertCos; @@ -1091,3 +1100,96 @@ void BKE_sculpt_toolsettings_data_ensure(struct Scene *scene) sd->paint.tile_offset[2] = 1.0f; } } + +static bool check_sculpt_object_deformed(Object *object, const bool for_construction) +{ + bool deformed = false; + + /* Active modifiers means extra deformation, which can't be handled correct + * on birth of PBVH and sculpt "layer" levels, so use PBVH only for internal brush + * stuff and show final DerivedMesh so user would see actual object shape. + */ + deformed |= object->sculpt->modifiers_active; + + if (for_construction) { + deformed |= object->sculpt->kb != NULL; + } + else { + /* As in case with modifiers, we can't synchronize deformation made against + * PBVH and non-locked keyblock, so also use PBVH only for brushes and + * final DM to give final result to user. + */ + deformed |= object->sculpt->kb && (object->shapeflag & OB_SHAPE_LOCK) == 0; + } + + return deformed; +} + +PBVH *BKE_sculpt_object_pbvh_ensure(Object *ob, Mesh *me_eval_deform) +{ + if (!ob) { + return NULL; + } + + if (!ob->sculpt) { + return NULL; + } + + PBVH *pbvh = ob->sculpt->pbvh; + + /* Sculpting on a BMesh (dynamic-topology) gets a special PBVH */ + if (!pbvh && ob->sculpt->bm) { + pbvh = BKE_pbvh_new(); + + BKE_pbvh_build_bmesh(pbvh, ob->sculpt->bm, + ob->sculpt->bm_smooth_shading, + ob->sculpt->bm_log, ob->sculpt->cd_vert_node_offset, + ob->sculpt->cd_face_node_offset); + + pbvh_show_diffuse_color_set(pbvh, ob->sculpt->show_diffuse_color); + pbvh_show_mask_set(pbvh, ob->sculpt->show_mask); + } + + /* always build pbvh from original mesh, and only use it for drawing if + * this derivedmesh is just original mesh. it's the multires subsurf dm + * that this is actually for, to support a pbvh on a modified mesh */ + if (!pbvh && ob->type == OB_MESH) { + Mesh *me = BKE_object_get_original_mesh(ob); + const int looptris_num = poly_to_tri_count(me->totpoly, me->totloop); + MLoopTri *looptri; + bool deformed; + + pbvh = BKE_pbvh_new(); + + looptri = MEM_malloc_arrayN(looptris_num, sizeof(*looptri), __func__); + + BKE_mesh_recalc_looptri( + me->mloop, me->mpoly, + me->mvert, + me->totloop, me->totpoly, + looptri); + + BKE_pbvh_build_mesh( + pbvh, + me->mpoly, me->mloop, + me->mvert, me->totvert, &me->vdata, + looptri, looptris_num); + + pbvh_show_diffuse_color_set(pbvh, ob->sculpt->show_diffuse_color); + pbvh_show_mask_set(pbvh, ob->sculpt->show_mask); + + deformed = check_sculpt_object_deformed(ob, true); + + if (deformed && me_eval_deform) { + int totvert; + float (*v_cos)[3]; + + v_cos = BKE_mesh_vertexCos_get(me_eval_deform, &totvert); + BKE_pbvh_apply_vertCos(pbvh, v_cos, totvert); + MEM_freeN(v_cos); + } + } + + ob->sculpt->pbvh = pbvh; + return pbvh; +} diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c index a142c839142..c1fb9130b5d 100644 --- a/source/blender/blenkernel/intern/particle.c +++ b/source/blender/blenkernel/intern/particle.c @@ -298,24 +298,6 @@ ParticleSystem *psys_orig_get(ParticleSystem *psys) return psys->orig_psys; } -struct ParticleSystem *psys_eval_get(Depsgraph *depsgraph, - Object *object, - ParticleSystem *psys) -{ - Object *object_eval = DEG_get_evaluated_object(depsgraph, object); - if (object_eval == object) { - return psys; - } - ParticleSystem *psys_eval = object_eval->particlesystem.first; - while (psys_eval != NULL) { - if (psys_eval->orig_psys == psys) { - return psys_eval; - } - psys_eval = psys_eval->next; - } - return psys_eval; -} - static PTCacheEdit *psys_orig_edit_get(ParticleSystem *psys) { if (psys->orig_psys == NULL) { @@ -2623,7 +2605,6 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra, const bool use_re } void psys_cache_edit_paths(Depsgraph *depsgraph, Scene *scene, Object *ob, PTCacheEdit *edit, float cfra, const bool use_render_params) { - Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob); ParticleCacheKey *ca, **cache = edit->pathcache; ParticleEditSettings *pset = &scene->toolsettings->particle; @@ -2631,16 +2612,9 @@ void psys_cache_edit_paths(Depsgraph *depsgraph, Scene *scene, Object *ob, PTCac PTCacheEditKey *ekey = NULL; ParticleSystem *psys = edit->psys; - ParticleSystem *psys_eval = NULL; ParticleSystemModifierData *psmd = psys_get_modifier(ob, psys); - ParticleSystemModifierData *psmd_eval = NULL; - if (psmd != NULL) { - psmd_eval = (ParticleSystemModifierData *)modifiers_findByName(ob_eval, psmd->modifier.name); - psys_eval = psmd_eval->psys; - } - - ParticleData *pa = psys_eval ? psys_eval->particles : NULL; + ParticleData *pa = psys ? psys->particles : NULL; ParticleInterpolationData pind; ParticleKey result; @@ -2669,7 +2643,7 @@ void psys_cache_edit_paths(Depsgraph *depsgraph, Scene *scene, Object *ob, PTCac /* frs_sec = (psys || edit->pid.flag & PTCACHE_VEL_PER_SEC) ? 25.0f : 1.0f; */ /* UNUSED */ - const bool use_weight = (pset->brushtype == PE_BRUSH_WEIGHT) && (psys_eval != NULL) && (psys_eval->particles != NULL); + const bool use_weight = (pset->brushtype == PE_BRUSH_WEIGHT) && (psys != NULL) && (psys->particles != NULL); if (use_weight) { ; /* use weight painting colors now... */ @@ -2714,10 +2688,10 @@ void psys_cache_edit_paths(Depsgraph *depsgraph, Scene *scene, Object *ob, PTCac cache[i]->segments = segments; /*--get the first data points--*/ - init_particle_interpolation(ob_eval, psys_eval, pa, &pind); + init_particle_interpolation(ob, psys, pa, &pind); - if (psys_eval) { - psys_mat_hair_to_global(ob_eval, psmd_eval->mesh_final, psys->part->from, pa, hairmat); + if (psys) { + psys_mat_hair_to_global(ob, psmd->mesh_final, psys->part->from, pa, hairmat); copy_v3_v3(rotmat[0], hairmat[2]); copy_v3_v3(rotmat[1], hairmat[1]); copy_v3_v3(rotmat[2], hairmat[0]); @@ -2736,7 +2710,7 @@ void psys_cache_edit_paths(Depsgraph *depsgraph, Scene *scene, Object *ob, PTCac time = (float)k / (float)segments; t = birthtime + time * (dietime - birthtime); result.time = -t; - do_particle_interpolation(psys_eval, i, pa, t, &pind, &result); + do_particle_interpolation(psys, i, pa, t, &pind, &result); copy_v3_v3(ca->co, result.co); /* non-hair points are already in global space */ @@ -2833,9 +2807,9 @@ void psys_cache_edit_paths(Depsgraph *depsgraph, Scene *scene, Object *ob, PTCac ParticleSimulationData sim = {0}; sim.depsgraph = depsgraph; sim.scene = scene; - sim.ob = ob_eval; - sim.psys = psys_eval; - sim.psmd = psys_get_modifier(ob_eval, psys_eval); + sim.ob = ob; + sim.psys = psys; + sim.psmd = psys_get_modifier(ob, psys); psys_cache_child_paths(&sim, cfra, true, use_render_params); } @@ -3094,6 +3068,9 @@ void object_remove_particle_system(Scene *UNUSED(scene), Object *ob) DEG_relations_tag_update(G.main); DEG_id_tag_update(&ob->id, OB_RECALC_DATA); + + /* Flush object mode. */ + DEG_id_tag_update(&ob->id, DEG_TAG_COPY_ON_WRITE); } static void default_particle_settings(ParticleSettings *part) diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c index a2d9891ec2d..8d6991ff9f4 100644 --- a/source/blender/blenkernel/intern/particle_system.c +++ b/source/blender/blenkernel/intern/particle_system.c @@ -4217,6 +4217,18 @@ void particle_system_update(struct Depsgraph *depsgraph, Scene *scene, Object *o if (!psys_check_enabled(ob, psys, use_render_params)) return; + if (DEG_is_active(depsgraph)) { + if (psys->orig_psys != NULL && psys->orig_psys->edit != NULL) { + psys_cache_edit_paths( + depsgraph, + (Scene *)DEG_get_original_id(&scene->id), + DEG_get_original_object(ob), + psys->orig_psys->edit, + DEG_get_ctime(depsgraph), + DEG_get_mode(depsgraph) == DAG_EVAL_RENDER); + } + } + cfra = DEG_get_ctime(depsgraph); sim.depsgraph = depsgraph; diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c index 7b53c5f8811..8cc8a8510f2 100644 --- a/source/blender/blenkernel/intern/pbvh.c +++ b/source/blender/blenkernel/intern/pbvh.c @@ -2189,8 +2189,13 @@ float (*BKE_pbvh_get_vertCos(PBVH *pbvh))[3] return vertCos; } -void BKE_pbvh_apply_vertCos(PBVH *pbvh, float (*vertCos)[3]) +void BKE_pbvh_apply_vertCos(PBVH *pbvh, float (*vertCos)[3], const int totvert) { + if (totvert != pbvh->totvert) { + BLI_assert(!"PBVH: Given deforming vcos number does not natch PBVH vertex number!"); + return; + } + if (!pbvh->deformed) { if (pbvh->verts) { /* if pbvh is not already deformed, verts/faces points to the */ diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c index e219e27f851..af13909bf89 100644 --- a/source/blender/blenkernel/intern/pointcache.c +++ b/source/blender/blenkernel/intern/pointcache.c @@ -1802,7 +1802,7 @@ static int ptcache_frame_from_filename(const char *filename, const char *ext) static int ptcache_path(PTCacheID *pid, char *filename) { Library *lib = (pid->ob) ? pid->ob->id.lib : NULL; - const char *blendfilename= (lib && (pid->cache->flag & PTCACHE_IGNORE_LIBPATH)==0) ? lib->filepath: G.main->name; + const char *blendfilename= (lib && (pid->cache->flag & PTCACHE_IGNORE_LIBPATH)==0) ? lib->filepath: BKE_main_blendfile_path_from_global(); size_t i; if (pid->cache->flag & PTCACHE_EXTERNAL) { diff --git a/source/blender/blenkernel/intern/rigidbody.c b/source/blender/blenkernel/intern/rigidbody.c index 75018bbe5bd..e79f86c6520 100644 --- a/source/blender/blenkernel/intern/rigidbody.c +++ b/source/blender/blenkernel/intern/rigidbody.c @@ -705,7 +705,8 @@ static void rigidbody_validate_sim_object(RigidBodyWorld *rbw, Object *ob, bool /* --------------------- */ -static void rigidbody_constraint_set_limits(RigidBodyCon *rbc, void (*set_limits)(rbConstraint*,int,float,float)) +static void rigidbody_constraint_set_limits( + RigidBodyCon *rbc, void (*set_limits)(rbConstraint *, int, float, float)) { if (rbc->flag & RBC_FLAG_USE_LIMIT_LIN_X) set_limits(rbc->physics_constraint, RB_LIMIT_LIN_X, rbc->limit_lin_x_lower, rbc->limit_lin_x_upper); diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index a488386fed8..2916e5559c4 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -945,11 +945,11 @@ Scene *BKE_scene_set_name(Main *bmain, const char *name) Scene *sce = (Scene *)BKE_libblock_find_name(bmain, ID_SCE, name); if (sce) { BKE_scene_set_background(bmain, sce); - printf("Scene switch for render: '%s' in file: '%s'\n", name, bmain->name); + printf("Scene switch for render: '%s' in file: '%s'\n", name, BKE_main_blendfile_path(bmain)); return sce; } - printf("Can't find scene: '%s' in file: '%s'\n", name, bmain->name); + printf("Can't find scene: '%s' in file: '%s'\n", name, BKE_main_blendfile_path(bmain)); return NULL; } @@ -1029,7 +1029,7 @@ int BKE_scene_base_iter_next( * this enters eternal loop because of * makeDispListMBall getting called inside of collection_duplilist */ if ((*base)->object->dup_group == NULL) { - iter->duplilist = object_duplilist_ex(depsgraph, (*scene), (*base)->object, false); + iter->duplilist = object_duplilist(depsgraph, (*scene), (*base)->object); iter->dupob = iter->duplilist->first; diff --git a/source/blender/blenkernel/intern/seqeffects.c b/source/blender/blenkernel/intern/seqeffects.c index 0eca7a00515..00af9721f07 100644 --- a/source/blender/blenkernel/intern/seqeffects.c +++ b/source/blender/blenkernel/intern/seqeffects.c @@ -1767,13 +1767,13 @@ static float check_zone(WipeZone *wipezone, int x, int y, Sequence *seq, float f if (output != output) output = 1; if (wipe->forward) output = 1 - output; break; - /* BOX WIPE IS NOT WORKING YET */ + /* BOX WIPE IS NOT WORKING YET */ /* case DO_CROSS_WIPE: */ /* BOX WIPE IS NOT WORKING YET */ #if 0 - case DO_BOX_WIPE: - if (!wipe->forward) - facf0 = 1.0f - facf0; /* Go the other direction */ + case DO_BOX_WIPE: + if (!wipe->forward) + facf0 = 1.0f - facf0; /* Go the other direction */ width = (int)(wipe->edgeWidth * ((xo + yo) / 2.0)); hwidth = (float)width / 2.0; @@ -1806,8 +1806,9 @@ static float check_zone(WipeZone *wipezone, int x, int y, Sequence *seq, float f output = in_band(hwidth, hyp2, 1, 1) * in_band(hwidth, hyp, 1, 1); } - if (!wipe->forward) - facf0 = 1.0f - facf0; /* Go the other direction */ + if (!wipe->forward) { + facf0 = 1.0f - facf0; /* Go the other direction */ + } angle = -1 / angle; b1 = posy / 2 - (-angle) * posx / 2; b3 = (yo - posy / 2) - (-angle) * (xo - posx / 2); diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c index f5d99e2615a..ecd0335fc4e 100644 --- a/source/blender/blenkernel/intern/sequencer.c +++ b/source/blender/blenkernel/intern/sequencer.c @@ -898,7 +898,7 @@ void BKE_sequence_reload_new_file(Scene *scene, Sequence *seq, const bool lock_r BLI_join_dirfile(path, sizeof(path), seq->strip->dir, seq->strip->stripdata->name); - BLI_path_abs(path, G.main->name); + BLI_path_abs(path, BKE_main_blendfile_path_from_global()); BKE_sequence_free_anim(seq); @@ -1546,7 +1546,7 @@ static void seq_open_anim_file(Scene *scene, Sequence *seq, bool openfile) BLI_join_dirfile(name, sizeof(name), seq->strip->dir, seq->strip->stripdata->name); - BLI_path_abs(name, G.main->name); + BLI_path_abs(name, BKE_main_blendfile_path_from_global()); proxy = seq->strip->proxy; @@ -1563,7 +1563,7 @@ static void seq_open_anim_file(Scene *scene, Sequence *seq, bool openfile) else { BLI_strncpy(dir, seq->strip->proxy->dir, sizeof(dir)); } - BLI_path_abs(dir, G.main->name); + BLI_path_abs(dir, BKE_main_blendfile_path_from_global()); } if (is_multiview && seq->views_format == R_IMF_VIEWS_INDIVIDUAL) { @@ -1691,7 +1691,7 @@ static bool seq_proxy_get_fname(Editing *ed, Sequence *seq, int cfra, int render return false; } BLI_path_append(dir, sizeof(dir), fname); - BLI_path_abs(name, G.main->name); + BLI_path_abs(name, BKE_main_blendfile_path_from_global()); } else if ((proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_DIR) && (proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_FILE)) { BLI_strncpy(dir, seq->strip->proxy->dir, sizeof(dir)); @@ -1723,7 +1723,7 @@ static bool seq_proxy_get_fname(Editing *ed, Sequence *seq, int cfra, int render { char fname[FILE_MAXFILE]; BLI_join_dirfile(fname, PROXY_MAXFILE, dir, proxy->file); - BLI_path_abs(fname, G.main->name); + BLI_path_abs(fname, BKE_main_blendfile_path_from_global()); if (suffix[0] != '\0') { /* TODO(sergey): This will actually append suffix after extension * which is weird but how was originally coded in multiview branch. @@ -1749,7 +1749,7 @@ static bool seq_proxy_get_fname(Editing *ed, Sequence *seq, int cfra, int render BLI_snprintf(name, PROXY_MAXFILE, "%s/proxy_misc/%d/####%s", dir, render_size, suffix); } - BLI_path_abs(name, G.main->name); + BLI_path_abs(name, BKE_main_blendfile_path_from_global()); BLI_path_frame(name, frameno, 0); strcat(name, ".jpg"); @@ -1894,7 +1894,7 @@ static bool seq_proxy_multiview_context_invalid(Sequence *seq, Scene *scene, con char path[FILE_MAX]; BLI_join_dirfile(path, sizeof(path), seq->strip->dir, seq->strip->stripdata->name); - BLI_path_abs(path, G.main->name); + BLI_path_abs(path, BKE_main_blendfile_path_from_global()); BKE_scene_multiview_view_prefix_get(scene, path, prefix, &ext); } else { @@ -2846,7 +2846,7 @@ static ImBuf *seq_render_image_strip(const SeqRenderData *context, Sequence *seq if (s_elem) { BLI_join_dirfile(name, sizeof(name), seq->strip->dir, s_elem->name); - BLI_path_abs(name, G.main->name); + BLI_path_abs(name, BKE_main_blendfile_path_from_global()); } flag = IB_rect | IB_metadata; @@ -5151,7 +5151,7 @@ void BKE_sequence_init_colorspace(Sequence *seq) ImBuf *ibuf; BLI_join_dirfile(name, sizeof(name), seq->strip->dir, seq->strip->stripdata->name); - BLI_path_abs(name, G.main->name); + BLI_path_abs(name, BKE_main_blendfile_path_from_global()); /* initialize input color space */ if (seq->type == SEQ_TYPE_IMAGE) { @@ -5319,6 +5319,7 @@ static void seq_anim_add_suffix(Scene *scene, struct anim *anim, const int view_ Sequence *BKE_sequencer_add_movie_strip(bContext *C, ListBase *seqbasep, SeqLoadInfo *seq_load) { + Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); /* only for sound */ char path[sizeof(seq_load->path)]; @@ -5333,7 +5334,7 @@ Sequence *BKE_sequencer_add_movie_strip(bContext *C, ListBase *seqbasep, SeqLoad int i; BLI_strncpy(path, seq_load->path, sizeof(path)); - BLI_path_abs(path, G.main->name); + BLI_path_abs(path, BKE_main_blendfile_path(bmain)); anim_arr = MEM_callocN(sizeof(struct anim *) * totfiles, "Video files"); diff --git a/source/blender/blenkernel/intern/sound.c b/source/blender/blenkernel/intern/sound.c index 747ffdafe8b..a7f3fc1df9e 100644 --- a/source/blender/blenkernel/intern/sound.c +++ b/source/blender/blenkernel/intern/sound.c @@ -77,7 +77,7 @@ bSound *BKE_sound_new_file(struct Main *bmain, const char *filepath) BLI_strncpy(str, filepath, sizeof(str)); - path = /*bmain ? bmain->name :*/ G.main->name; + path = BKE_main_blendfile_path(bmain); BLI_path_abs(str, path); @@ -96,7 +96,7 @@ bSound *BKE_sound_new_file_exists_ex(struct Main *bmain, const char *filepath, b char str[FILE_MAX], strtest[FILE_MAX]; BLI_strncpy(str, filepath, sizeof(str)); - BLI_path_abs(str, bmain->name); + BLI_path_abs(str, BKE_main_blendfile_path(bmain)); /* first search an identical filepath */ for (sound = bmain->sound.first; sound; sound = sound->id.next) { diff --git a/source/blender/blenkernel/intern/studiolight.c b/source/blender/blenkernel/intern/studiolight.c index 4ef7b3d2247..e4b49656907 100644 --- a/source/blender/blenkernel/intern/studiolight.c +++ b/source/blender/blenkernel/intern/studiolight.c @@ -55,13 +55,13 @@ /* Statics */ static ListBase studiolights; -#define STUDIOLIGHT_EXTENSIONS ".jpg", ".hdr" #define STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE 8 #define STUDIOLIGHT_IRRADIANCE_EQUIRECTANGULAR_HEIGHT 32 #define STUDIOLIGHT_IRRADIANCE_EQUIRECTANGULAR_WIDTH (STUDIOLIGHT_IRRADIANCE_EQUIRECTANGULAR_HEIGHT * 2) static const char *STUDIOLIGHT_CAMERA_FOLDER = "studiolights/camera/"; static const char *STUDIOLIGHT_WORLD_FOLDER = "studiolights/world/"; +static const char *STUDIOLIGHT_MATCAP_FOLDER = "studiolights/matcap/"; /* FUNCTIONS */ static void studiolight_free(struct StudioLight *sl) @@ -168,16 +168,16 @@ static void studiolight_load_equierectangular_image(StudioLight *sl) sl->equirectangular_radiance_buffer = ibuf; } } - sl->flag |= STUDIOLIGHT_EQUIRECTANGULAR_IMAGE_LOADED; + sl->flag |= STUDIOLIGHT_EXTERNAL_IMAGE_LOADED; } static void studiolight_create_equierectangular_radiance_gputexture(StudioLight *sl) { if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) { char error[256]; - BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_EQUIRECTANGULAR_IMAGE_LOADED); + BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_EXTERNAL_IMAGE_LOADED); ImBuf *ibuf = sl->equirectangular_radiance_buffer; - sl->equirectangular_radiance_gputexture = GPU_texture_create_2D(ibuf->x, ibuf->y, GPU_RGBA16F, ibuf->rect_float, error); + sl->equirectangular_radiance_gputexture = GPU_texture_create_2D(ibuf->x, ibuf->y, GPU_RGBA8, ibuf->rect_float, error); GPUTexture *tex = sl->equirectangular_radiance_gputexture; GPU_texture_bind(tex, 0); GPU_texture_filter_mode(tex, true); @@ -206,7 +206,7 @@ static void studiolight_create_equierectangular_irradiance_gputexture(StudioLigh static void studiolight_calculate_radiance_cubemap_buffers(StudioLight *sl) { if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) { - BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_EQUIRECTANGULAR_IMAGE_LOADED); + BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_EXTERNAL_IMAGE_LOADED); ImBuf *ibuf = sl->equirectangular_radiance_buffer; if (ibuf) { float *colbuf = MEM_mallocN(SQUARE(STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE) * sizeof(float[4]), __func__); @@ -481,7 +481,7 @@ static void studiolight_add_files_from_datafolder(const int folder_id, const cha if ((dir[i].type & S_IFREG)) { const char *filename = dir[i].relname; const char *path = dir[i].path; - if (BLI_testextensie_n(filename, STUDIOLIGHT_EXTENSIONS, NULL)) { + if (BLI_testextensie_array(filename, imb_ext_image)) { sl = studiolight_create(); sl->flag = STUDIOLIGHT_EXTERNAL_FILE | flag; BLI_strncpy(sl->name, filename, FILE_MAXFILE); @@ -527,7 +527,7 @@ static int studiolight_cmp(const void *a, const void *b) /* icons */ static uint *studiolight_radiance_preview(StudioLight *sl, int icon_size) { - BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_EQUIRECTANGULAR_IMAGE_LOADED); + BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_EXTERNAL_IMAGE_LOADED); uint *rect = MEM_mallocN(icon_size * icon_size * sizeof(uint), __func__); int icon_center = icon_size / 2; @@ -579,6 +579,29 @@ static uint *studiolight_radiance_preview(StudioLight *sl, int icon_size) return rect; } +static uint *studiolight_matcap_preview(StudioLight *sl, int icon_size) +{ + BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_EXTERNAL_IMAGE_LOADED); + + uint *rect = MEM_mallocN(icon_size * icon_size * sizeof(uint), __func__); + const uint alphamask = 0xff000000; + float color[4]; + float fx, fy; + int offset = 0; + ImBuf *ibuf = sl->equirectangular_radiance_buffer; + for (int y = 0; y < icon_size; y++) { + for (int x = 0; x < icon_size; x++) { + fx = x * ibuf->x / icon_size; + fy = y * ibuf->y / icon_size; + nearest_interpolation_color(ibuf, NULL, color, fx, fy); + rect[offset++] = rgb_to_cpack(linearrgb_to_srgb(color[0]), + linearrgb_to_srgb(color[1]), + linearrgb_to_srgb(color[2])) | alphamask; + } + } + return rect; +} + static uint *studiolight_irradiance_preview(StudioLight *sl, int icon_size) { if (/*!(sl->flag & STUDIOLIGHT_EXTERNAL_FILE)*/ 1) { @@ -696,7 +719,7 @@ void BKE_studiolight_init(void) /* Add default studio light */ sl = studiolight_create(); BLI_strncpy(sl->name, "INTERNAL_01", FILE_MAXFILE); - sl->flag = STUDIOLIGHT_DIFFUSE_LIGHT_CALCULATED | STUDIOLIGHT_ORIENTATION_CAMERA; + sl->flag = STUDIOLIGHT_INTERNAL | STUDIOLIGHT_DIFFUSE_LIGHT_CALCULATED | STUDIOLIGHT_ORIENTATION_CAMERA; copy_v3_fl(sl->diffuse_light[STUDIOLIGHT_X_POS], 0.0f); copy_v3_fl(sl->diffuse_light[STUDIOLIGHT_X_NEG], 0.0f); copy_v3_fl(sl->diffuse_light[STUDIOLIGHT_Y_POS], 0.8f); @@ -706,9 +729,11 @@ void BKE_studiolight_init(void) BLI_addtail(&studiolights, sl); studiolight_add_files_from_datafolder(BLENDER_SYSTEM_DATAFILES, STUDIOLIGHT_CAMERA_FOLDER, STUDIOLIGHT_ORIENTATION_CAMERA); - studiolight_add_files_from_datafolder(BLENDER_USER_DATAFILES, STUDIOLIGHT_CAMERA_FOLDER, STUDIOLIGHT_ORIENTATION_CAMERA); + studiolight_add_files_from_datafolder(BLENDER_USER_DATAFILES, STUDIOLIGHT_CAMERA_FOLDER, STUDIOLIGHT_ORIENTATION_CAMERA | STUDIOLIGHT_USER_DEFINED); studiolight_add_files_from_datafolder(BLENDER_SYSTEM_DATAFILES, STUDIOLIGHT_WORLD_FOLDER, STUDIOLIGHT_ORIENTATION_WORLD); - studiolight_add_files_from_datafolder(BLENDER_USER_DATAFILES, STUDIOLIGHT_WORLD_FOLDER, STUDIOLIGHT_ORIENTATION_WORLD); + studiolight_add_files_from_datafolder(BLENDER_USER_DATAFILES, STUDIOLIGHT_WORLD_FOLDER, STUDIOLIGHT_ORIENTATION_WORLD | STUDIOLIGHT_USER_DEFINED); + studiolight_add_files_from_datafolder(BLENDER_SYSTEM_DATAFILES, STUDIOLIGHT_MATCAP_FOLDER, STUDIOLIGHT_ORIENTATION_VIEWNORMAL); + studiolight_add_files_from_datafolder(BLENDER_USER_DATAFILES, STUDIOLIGHT_MATCAP_FOLDER, STUDIOLIGHT_ORIENTATION_VIEWNORMAL | STUDIOLIGHT_USER_DEFINED); /* sort studio lights on filename. */ BLI_listbase_sort(&studiolights, studiolight_cmp); @@ -722,24 +747,34 @@ void BKE_studiolight_free(void) } } +struct StudioLight *BKE_studiolight_find_first(int flag) +{ + LISTBASE_FOREACH(StudioLight *, sl, &studiolights) { + if ((sl->flag & flag)) { + return sl; + } + } + return NULL; +} + struct StudioLight *BKE_studiolight_find(const char *name, int flag) { LISTBASE_FOREACH(StudioLight *, sl, &studiolights) { if (STREQLEN(sl->name, name, FILE_MAXFILE)) { - if ((sl->flag & flag) == flag) { + if ((sl->flag & flag)) { return sl; } else { /* flags do not match, so use default */ - return studiolights.first; + return BKE_studiolight_find_first(flag); } } } /* When not found, use the default studio light */ - return studiolights.first; + return BKE_studiolight_find_first(flag); } -struct StudioLight *BKE_studiolight_findindex(int index) +struct StudioLight *BKE_studiolight_findindex(int index, int flag) { LISTBASE_FOREACH(StudioLight *, sl, &studiolights) { if (sl->index == index) { @@ -747,10 +782,10 @@ struct StudioLight *BKE_studiolight_findindex(int index) } } /* When not found, use the default studio light */ - return studiolights.first; + return BKE_studiolight_find_first(flag); } -const struct ListBase *BKE_studiolight_listbase(void) +struct ListBase *BKE_studiolight_listbase(void) { return &studiolights; } @@ -758,7 +793,12 @@ const struct ListBase *BKE_studiolight_listbase(void) uint *BKE_studiolight_preview(StudioLight *sl, int icon_size, int icon_id_type) { if (icon_id_type == STUDIOLIGHT_ICON_ID_TYPE_IRRADIANCE) { - return studiolight_irradiance_preview(sl, icon_size); + if (sl->flag & STUDIOLIGHT_ORIENTATION_VIEWNORMAL) { + return studiolight_matcap_preview(sl, icon_size); + } + else { + return studiolight_irradiance_preview(sl, icon_size); + } } else { return studiolight_radiance_preview(sl, icon_size); @@ -771,7 +811,7 @@ void BKE_studiolight_ensure_flag(StudioLight *sl, int flag) return; } - if ((flag & STUDIOLIGHT_EQUIRECTANGULAR_IMAGE_LOADED)) { + if ((flag & STUDIOLIGHT_EXTERNAL_IMAGE_LOADED)) { studiolight_load_equierectangular_image(sl); } if ((flag & STUDIOLIGHT_RADIANCE_BUFFERS_CALCULATED)) { @@ -793,3 +833,9 @@ void BKE_studiolight_ensure_flag(StudioLight *sl, int flag) studiolight_calculate_irradiance_equirectangular_image(sl); } } + +void BKE_studiolight_refresh(void) +{ + BKE_studiolight_free(); + BKE_studiolight_init(); +} diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c index ef49a7af5f3..d735944c93d 100644 --- a/source/blender/blenkernel/intern/subsurf_ccg.c +++ b/source/blender/blenkernel/intern/subsurf_ccg.c @@ -2352,7 +2352,7 @@ static struct PBVH *ccgDM_getPBVH(Object *ob, DerivedMesh *dm) totvert = deformdm->getNumVerts(deformdm); vertCos = MEM_malloc_arrayN(totvert, sizeof(float[3]), "ccgDM_getPBVH vertCos"); deformdm->getVertCos(deformdm, vertCos); - BKE_pbvh_apply_vertCos(ccgdm->pbvh, vertCos); + BKE_pbvh_apply_vertCos(ccgdm->pbvh, vertCos, totvert); MEM_freeN(vertCos); } } diff --git a/source/blender/blenkernel/intern/text.c b/source/blender/blenkernel/intern/text.c index 3892b2f0546..a24020d7764 100644 --- a/source/blender/blenkernel/intern/text.c +++ b/source/blender/blenkernel/intern/text.c @@ -388,7 +388,7 @@ bool BKE_text_reload(Text *text) } BLI_strncpy(filepath_abs, text->name, FILE_MAX); - BLI_path_abs(filepath_abs, G.main->name); + BLI_path_abs(filepath_abs, BKE_main_blendfile_path_from_global()); buffer = BLI_file_read_text_as_mem(filepath_abs, 0, &buffer_len); if (buffer == NULL) { @@ -557,7 +557,7 @@ int BKE_text_file_modified_check(Text *text) return 0; BLI_strncpy(file, text->name, FILE_MAX); - BLI_path_abs(file, G.main->name); + BLI_path_abs(file, BKE_main_blendfile_path_from_global()); if (!BLI_exists(file)) return 2; @@ -585,7 +585,7 @@ void BKE_text_file_modified_ignore(Text *text) if (!text->name) return; BLI_strncpy(file, text->name, FILE_MAX); - BLI_path_abs(file, G.main->name); + BLI_path_abs(file, BKE_main_blendfile_path_from_global()); if (!BLI_exists(file)) return; diff --git a/source/blender/blenkernel/intern/undo_system.c b/source/blender/blenkernel/intern/undo_system.c index f5e4c354a02..a05e79aae1f 100644 --- a/source/blender/blenkernel/intern/undo_system.c +++ b/source/blender/blenkernel/intern/undo_system.c @@ -376,7 +376,7 @@ UndoStep *BKE_undosys_step_push_init_with_type(UndoStack *ustack, bContext *C, c us->type = ut; ustack->step_init = us; ut->step_encode_init(C, us); - undosys_stack_validate(ustack, true); + undosys_stack_validate(ustack, false); return us; } else { diff --git a/source/blender/blenkernel/intern/world.c b/source/blender/blenkernel/intern/world.c index 15bf01d2049..1b06e7ed851 100644 --- a/source/blender/blenkernel/intern/world.c +++ b/source/blender/blenkernel/intern/world.c @@ -53,6 +53,8 @@ #include "BKE_node.h" #include "BKE_world.h" +#include "DEG_depsgraph.h" + #include "GPU_material.h" /** Free (or release) any data used by this world (does not free the world itself). */ @@ -161,13 +163,10 @@ void BKE_world_make_local(Main *bmain, World *wrld, const bool lib_local) BKE_id_make_local_generic(bmain, &wrld->id, true, lib_local); } -void BKE_world_eval(struct Depsgraph *UNUSED(depsgraph), World *world) +void BKE_world_eval(struct Depsgraph *depsgraph, World *world) { - if (G.debug & G_DEBUG_DEPSGRAPH_EVAL) { - printf("%s on %s (%p)\n", __func__, world->id.name, world); - } + DEG_debug_print_eval(depsgraph, __func__, world->id.name, world); if (!BLI_listbase_is_empty(&world->gpumaterial)) { world->update_flag = 1; - GPU_material_uniform_buffer_tag_dirty(&world->gpumaterial); } } diff --git a/source/blender/blenkernel/intern/writeavi.c b/source/blender/blenkernel/intern/writeavi.c index e357f13530d..33ac312425b 100644 --- a/source/blender/blenkernel/intern/writeavi.c +++ b/source/blender/blenkernel/intern/writeavi.c @@ -145,7 +145,7 @@ static void filepath_avi(char *string, RenderData *rd, bool preview, const char } strcpy(string, rd->pic); - BLI_path_abs(string, G.main->name); + BLI_path_abs(string, BKE_main_blendfile_path_from_global()); BLI_make_existing_file(string); diff --git a/source/blender/blenkernel/intern/writeffmpeg.c b/source/blender/blenkernel/intern/writeffmpeg.c index 4a0f697c9ce..17c665f3bcd 100644 --- a/source/blender/blenkernel/intern/writeffmpeg.c +++ b/source/blender/blenkernel/intern/writeffmpeg.c @@ -1127,7 +1127,7 @@ static void ffmpeg_filepath_get(FFMpegContext *context, char *string, RenderData } strcpy(string, rd->pic); - BLI_path_abs(string, G.main->name); + BLI_path_abs(string, BKE_main_blendfile_path_from_global()); BLI_make_existing_file(string); diff --git a/source/blender/blenlib/BLI_math_base.h b/source/blender/blenlib/BLI_math_base.h index 6f8e48d83b2..f455436ce63 100644 --- a/source/blender/blenlib/BLI_math_base.h +++ b/source/blender/blenlib/BLI_math_base.h @@ -200,24 +200,28 @@ double double_round(double x, int ndigits); * check the vector is unit length, or zero length (which can't be helped in some cases). */ #ifndef NDEBUG -/* note: 0.0001 is too small becaues normals may be converted from short's: see [#34322] */ +/** \note 0.0001 is too small becaues normals may be converted from short's: see T34322. */ # define BLI_ASSERT_UNIT_EPSILON 0.0002f +/** + * \note Checks are flipped so NAN doesn't assert. This is done because we're making sure the value was normalized + * and in the case we don't want NAN to be raising asserts since there is nothing to be done in that case. + */ # define BLI_ASSERT_UNIT_V3(v) { \ const float _test_unit = len_squared_v3(v); \ - BLI_assert((fabsf(_test_unit - 1.0f) < BLI_ASSERT_UNIT_EPSILON) || \ - (fabsf(_test_unit) < BLI_ASSERT_UNIT_EPSILON)); \ + BLI_assert(!(fabsf(_test_unit - 1.0f) >= BLI_ASSERT_UNIT_EPSILON) || \ + !(fabsf(_test_unit) >= BLI_ASSERT_UNIT_EPSILON)); \ } (void)0 # define BLI_ASSERT_UNIT_V2(v) { \ const float _test_unit = len_squared_v2(v); \ - BLI_assert((fabsf(_test_unit - 1.0f) < BLI_ASSERT_UNIT_EPSILON) || \ - (fabsf(_test_unit) < BLI_ASSERT_UNIT_EPSILON)); \ + BLI_assert(!(fabsf(_test_unit - 1.0f) >= BLI_ASSERT_UNIT_EPSILON) || \ + !(fabsf(_test_unit) >= BLI_ASSERT_UNIT_EPSILON)); \ } (void)0 # define BLI_ASSERT_UNIT_QUAT(q) { \ const float _test_unit = dot_qtqt(q, q); \ - BLI_assert((fabsf(_test_unit - 1.0f) < BLI_ASSERT_UNIT_EPSILON * 10) || \ - (fabsf(_test_unit) < BLI_ASSERT_UNIT_EPSILON * 10)); \ + BLI_assert(!(fabsf(_test_unit - 1.0f) >= BLI_ASSERT_UNIT_EPSILON * 10) || \ + !(fabsf(_test_unit) >= BLI_ASSERT_UNIT_EPSILON * 10)); \ } (void)0 # define BLI_ASSERT_ZERO_M3(m) { \ diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index e6a5bc9a738..87dda371b88 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -141,6 +141,7 @@ #include "BKE_material.h" #include "BKE_main.h" // for Main #include "BKE_mesh.h" // for ME_ defines (patching) +#include "BKE_mesh_runtime.h" #include "BKE_modifier.h" #include "BKE_multires.h" #include "BKE_node.h" // for tree type defines @@ -8518,11 +8519,11 @@ static BHead *read_global(BlendFileData *bfd, FileData *fd, BHead *bhead) if (bfd->filename[0] == 0) { if (fd->fileversion < 265 || (fd->fileversion == 265 && fg->subversion < 1)) if ((G.fileflags & G_FILE_RECOVER)==0) - BLI_strncpy(bfd->filename, bfd->main->name, sizeof(bfd->filename)); + BLI_strncpy(bfd->filename, BKE_main_blendfile_path(bfd->main), sizeof(bfd->filename)); /* early 2.50 version patch - filename not in FileGlobal struct at all */ if (fd->fileversion <= 250) - BLI_strncpy(bfd->filename, bfd->main->name, sizeof(bfd->filename)); + BLI_strncpy(bfd->filename, BKE_main_blendfile_path(bfd->main), sizeof(bfd->filename)); } if (G.fileflags & G_FILE_RECOVER) @@ -10093,6 +10094,7 @@ static void add_collections_to_scene( /* Assign the collection. */ ob->dup_group = collection; + id_us_plus(&collection->id); ob->transflag |= OB_DUPLICOLLECTION; copy_v3_v3(ob->loc, scene->cursor.location); } @@ -10348,7 +10350,7 @@ static Main *library_link_begin(Main *mainvar, FileData **fd, const char *filepa blo_split_main((*fd)->mainlist, mainvar); /* which one do we need? */ - mainl = blo_find_main(*fd, filepath, G.main->name); + mainl = blo_find_main(*fd, filepath, BKE_main_blendfile_path(mainvar)); /* needed for do_version */ mainl->versionfile = (*fd)->fileversion; @@ -10423,7 +10425,7 @@ static void library_link_end(Main *mainl, FileData **fd, const short flag, Main BLI_strncpy(curlib->name, curlib->filepath, sizeof(curlib->name)); /* uses current .blend file as reference */ - BLI_path_rel(curlib->name, G.main->name); + BLI_path_rel(curlib->name, BKE_main_blendfile_path_from_global()); } blo_join_main((*fd)->mainlist); @@ -10453,7 +10455,7 @@ static void library_link_end(Main *mainl, FileData **fd, const short flag, Main BKE_main_id_tag_all(mainvar, LIB_TAG_NEW, false); lib_verify_nodetree(mainvar, false); - fix_relpaths_library(G.main->name, mainvar); /* make all relative paths, relative to the open blend file */ + fix_relpaths_library(BKE_main_blendfile_path(mainvar), mainvar); /* make all relative paths, relative to the open blend file */ /* Give a base to loose objects and collections. * Only directly linked objects & collections are instantiated by `BLO_library_link_named_part_ex()` & co, @@ -10574,7 +10576,7 @@ static void read_libraries(FileData *basefd, ListBase *mainlist) while (fd == NULL) { char newlib_path[FILE_MAX] = {0}; printf("Missing library...'\n"); - printf(" current file: %s\n", G.main->name); + printf(" current file: %s\n", BKE_main_blendfile_path_from_global()); printf(" absolute lib: %s\n", mainptr->curlib->filepath); printf(" relative lib: %s\n", mainptr->curlib->name); printf(" enter a new path:\n"); @@ -10582,7 +10584,7 @@ static void read_libraries(FileData *basefd, ListBase *mainlist) if (scanf("%1023s", newlib_path) > 0) { /* Warning, keep length in sync with FILE_MAX! */ BLI_strncpy(mainptr->curlib->name, newlib_path, sizeof(mainptr->curlib->name)); BLI_strncpy(mainptr->curlib->filepath, newlib_path, sizeof(mainptr->curlib->filepath)); - BLI_cleanup_path(G.main->name, mainptr->curlib->filepath); + BLI_cleanup_path(BKE_main_blendfile_path_from_global(), mainptr->curlib->filepath); fd = blo_openblenderfile(mainptr->curlib->filepath, basefd->reports); diff --git a/source/blender/blenloader/intern/readfile.h b/source/blender/blenloader/intern/readfile.h index 299c66f2bbb..7618c023882 100644 --- a/source/blender/blenloader/intern/readfile.h +++ b/source/blender/blenloader/intern/readfile.h @@ -169,14 +169,14 @@ void blo_do_version_old_trackto_to_constraints(struct Object *ob); void blo_do_versions_view3d_split_250(struct View3D *v3d, struct ListBase *regions); void blo_do_versions_key_uidgen(struct Key *key); -void blo_do_versions_pre250(struct FileData *fd, struct Library *lib, struct Main *main); -void blo_do_versions_250(struct FileData *fd, struct Library *lib, struct Main *main); -void blo_do_versions_260(struct FileData *fd, struct Library *lib, struct Main *main); -void blo_do_versions_270(struct FileData *fd, struct Library *lib, struct Main *main); -void blo_do_versions_280(struct FileData *fd, struct Library *lib, struct Main *main); - -void do_versions_after_linking_270(struct Main *main); -void do_versions_after_linking_280(struct Main *main); +void blo_do_versions_pre250(struct FileData *fd, struct Library *lib, struct Main *bmain); +void blo_do_versions_250(struct FileData *fd, struct Library *lib, struct Main *bmain); +void blo_do_versions_260(struct FileData *fd, struct Library *lib, struct Main *bmain); +void blo_do_versions_270(struct FileData *fd, struct Library *lib, struct Main *bmain); +void blo_do_versions_280(struct FileData *fd, struct Library *lib, struct Main *bmain); + +void do_versions_after_linking_270(struct Main *bmain); +void do_versions_after_linking_280(struct Main *bmain); #endif diff --git a/source/blender/blenloader/intern/undofile.c b/source/blender/blenloader/intern/undofile.c index 7133dee0e82..e1ae267ea11 100644 --- a/source/blender/blenloader/intern/undofile.c +++ b/source/blender/blenloader/intern/undofile.c @@ -130,7 +130,7 @@ void memfile_chunk_add( struct Main *BLO_memfile_main_get(struct MemFile *memfile, struct Main *oldmain, struct Scene **r_scene) { struct Main *bmain_undo = NULL; - BlendFileData *bfd = BLO_read_from_memfile(oldmain, oldmain->name, memfile, NULL, BLO_READ_SKIP_NONE); + BlendFileData *bfd = BLO_read_from_memfile(oldmain, BKE_main_blendfile_path(oldmain), memfile, NULL, BLO_READ_SKIP_NONE); if (bfd) { bmain_undo = bfd->main; diff --git a/source/blender/blenloader/intern/versioning_250.c b/source/blender/blenloader/intern/versioning_250.c index 3f85011db0b..d51289bee43 100644 --- a/source/blender/blenloader/intern/versioning_250.c +++ b/source/blender/blenloader/intern/versioning_250.c @@ -641,11 +641,11 @@ static void do_versions_socket_default_value_259(bNodeSocket *sock) } } -void blo_do_versions_250(FileData *fd, Library *lib, Main *main) +void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain) { /* WATCH IT!!!: pointers from libdata have not been converted */ - if (main->versionfile < 250) { + if (bmain->versionfile < 250) { bScreen *screen; Scene *scene; Base *base; @@ -663,22 +663,22 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main) bSound *sound; Sequence *seq; - for (sound = main->sound.first; sound; sound = sound->id.next) { + for (sound = bmain->sound.first; sound; sound = sound->id.next) { if (sound->newpackedfile) { sound->packedfile = sound->newpackedfile; sound->newpackedfile = NULL; } } - for (scene = main->scene.first; scene; scene = scene->id.next) { + for (scene = bmain->scene.first; scene; scene = scene->id.next) { if (scene->ed && scene->ed->seqbasep) { SEQ_BEGIN (scene->ed, seq) { if (seq->type == SEQ_TYPE_SOUND_HD) { char str[FILE_MAX]; BLI_join_dirfile(str, sizeof(str), seq->strip->dir, seq->strip->stripdata->name); - BLI_path_abs(str, main->name); - seq->sound = BKE_sound_new_file(main, str); + BLI_path_abs(str, BKE_main_blendfile_path(bmain)); + seq->sound = BKE_sound_new_file(bmain, str); } #define SEQ_USE_PROXY_CUSTOM_DIR (1 << 19) #define SEQ_USE_PROXY_CUSTOM_FILE (1 << 21) @@ -695,21 +695,21 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main) } } - for (screen = main->screen.first; screen; screen = screen->id.next) { + for (screen = bmain->screen.first; screen; screen = screen->id.next) { do_versions_windowmanager_2_50(screen); - do_versions_gpencil_2_50(main, screen); + do_versions_gpencil_2_50(bmain, screen); } /* shader, composite and texture node trees have id.name empty, put something in * to have them show in RNA viewer and accessible otherwise. */ - for (ma = main->mat.first; ma; ma = ma->id.next) { + for (ma = bmain->mat.first; ma; ma = ma->id.next) { if (ma->nodetree && ma->nodetree->id.name[0] == '\0') strcpy(ma->nodetree->id.name, "NTShader Nodetree"); } /* and composite trees */ - for (sce = main->scene.first; sce; sce = sce->id.next) { + for (sce = bmain->scene.first; sce; sce = sce->id.next) { if (sce->nodetree && sce->nodetree->id.name[0] == '\0') strcpy(sce->nodetree->id.name, "NTCompositing Nodetree"); @@ -729,7 +729,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main) } /* and texture trees */ - for (tx = main->tex.first; tx; tx = tx->id.next) { + for (tx = bmain->tex.first; tx; tx = tx->id.next) { bNode *node; if (tx->nodetree) { @@ -744,12 +744,12 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main) } /* copy standard draw flag to meshes(used to be global, is not available here) */ - for (me = main->mesh.first; me; me = me->id.next) { + for (me = bmain->mesh.first; me; me = me->id.next) { me->drawflag = ME_DRAWEDGES|ME_DRAWFACES|ME_DRAWCREASES; } /* particle draw and render types */ - for (part = main->particle.first; part; part = part->id.next) { + for (part = bmain->particle.first; part; part = part->id.next) { if (part->draw_as) { if (part->draw_as == PART_DRAW_DOT) { part->ren_as = PART_DRAW_HALO; @@ -768,7 +768,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main) } /* set old pointcaches to have disk cache flag */ - for (ob = main->object.first; ob; ob = ob->id.next) { + for (ob = bmain->object.first; ob; ob = ob->id.next) { //BKE_ptcache_ids_from_object(&pidlist, ob); @@ -779,7 +779,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main) } /* type was a mixed flag & enum. move the 2d flag elsewhere */ - for (cu = main->curve.first; cu; cu = cu->id.next) { + for (cu = bmain->curve.first; cu; cu = cu->id.next) { Nurb *nu; for (nu = cu->nurb.first; nu; nu = nu->next) { @@ -789,7 +789,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main) } } - if (main->versionfile < 250 || (main->versionfile == 250 && main->subversionfile < 1)) { + if (bmain->versionfile < 250 || (bmain->versionfile == 250 && bmain->subversionfile < 1)) { Object *ob; Tex *tex; Scene *sce; @@ -797,7 +797,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main) //PTCacheID *pid; //ListBase pidlist; - for (ob = main->object.first; ob; ob = ob->id.next) { + for (ob = bmain->object.first; ob; ob = ob->id.next) { //BKE_ptcache_ids_from_object(&pidlist, ob); //for (pid = pidlist.first; pid; pid = pid->next) { @@ -831,12 +831,12 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main) } /* texture filter */ - for (tex = main->tex.first; tex; tex = tex->id.next) { + for (tex = bmain->tex.first; tex; tex = tex->id.next) { if (tex->afmax == 0) tex->afmax = 8; } - for (sce = main->scene.first; sce; sce = sce->id.next) { + for (sce = bmain->scene.first; sce; sce = sce->id.next) { ts = sce->toolsettings; if (!ts->uv_selectmode || ts->vgroup_weight == 0.0f) { ts->selectmode = SCE_SELECT_VERTEX; @@ -854,26 +854,26 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main) } } - if (main->versionfile < 250 || (main->versionfile == 250 && main->subversionfile < 2)) { + if (bmain->versionfile < 250 || (bmain->versionfile == 250 && bmain->subversionfile < 2)) { Object *ob; - for (ob = main->object.first; ob; ob = ob->id.next) { + for (ob = bmain->object.first; ob; ob = ob->id.next) { if (ob->flag & 8192) // OB_POSEMODE = 8192 ob->mode |= OB_MODE_POSE; } } - if (main->versionfile < 250 || (main->versionfile == 250 && main->subversionfile < 4)) { + if (bmain->versionfile < 250 || (bmain->versionfile == 250 && bmain->subversionfile < 4)) { Scene *sce; Object *ob; ParticleSettings *part; bool do_gravity = false; - for (sce = main->scene.first; sce; sce = sce->id.next) + for (sce = bmain->scene.first; sce; sce = sce->id.next) if (sce->unit.scale_length == 0.0f) sce->unit.scale_length = 1.0f; - for (ob = main->object.first; ob; ob = ob->id.next) { + for (ob = bmain->object.first; ob; ob = ob->id.next) { /* fluid-sim stuff */ FluidsimModifierData *fluidmd = (FluidsimModifierData *) modifiers_findByType(ob, eModifierType_Fluidsim); if (fluidmd) @@ -883,7 +883,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main) ob->rotmode = ROT_MODE_EUL; } - for (sce = main->scene.first; sce; sce = sce->id.next) { + for (sce = bmain->scene.first; sce; sce = sce->id.next) { if (sce->audio.main == 0.0f) sce->audio.main = 1.0f; @@ -895,7 +895,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main) } /* Add default gravity to scenes */ - for (sce = main->scene.first; sce; sce = sce->id.next) { + for (sce = bmain->scene.first; sce; sce = sce->id.next) { if ((sce->physics_settings.flag & PHYS_GLOBAL_GRAVITY) == 0 && is_zero_v3(sce->physics_settings.gravity)) { @@ -908,11 +908,11 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main) /* Assign proper global gravity weights for dynamics (only z-coordinate is taken into account) */ if (do_gravity) { - for (part = main->particle.first; part; part = part->id.next) + for (part = bmain->particle.first; part; part = part->id.next) part->effector_weights->global_gravity = part->acc[2]/-9.81f; } - for (ob = main->object.first; ob; ob = ob->id.next) { + for (ob = bmain->object.first; ob; ob = ob->id.next) { ModifierData *md; if (do_gravity) { @@ -941,11 +941,11 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main) } } - if (main->versionfile < 250 || (main->versionfile == 250 && main->subversionfile < 6)) { + if (bmain->versionfile < 250 || (bmain->versionfile == 250 && bmain->subversionfile < 6)) { Object *ob; /* New variables for axis-angle rotations and/or quaternion rotations were added, and need proper initialization */ - for (ob = main->object.first; ob; ob = ob->id.next) { + for (ob = bmain->object.first; ob; ob = ob->id.next) { /* new variables for all objects */ ob->quat[0] = 1.0f; ob->rotAxis[1] = 1.0f; @@ -962,7 +962,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main) } } - if (main->versionfile < 250 || (main->versionfile == 250 && main->subversionfile < 7)) { + if (bmain->versionfile < 250 || (bmain->versionfile == 250 && bmain->subversionfile < 7)) { Mesh *me; Nurb *nu; Lattice *lt; @@ -974,7 +974,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main) /* shape keys are no longer applied to the mesh itself, but rather * to the derivedmesh/displist, so here we ensure that the basis * shape key is always set in the mesh coordinates. */ - for (me = main->mesh.first; me; me = me->id.next) { + for (me = bmain->mesh.first; me; me = me->id.next) { if ((key = blo_do_versions_newlibadr(fd, lib, me->key)) && key->refkey) { data = key->refkey->data; tot = MIN2(me->totvert, key->refkey->totelem); @@ -984,7 +984,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main) } } - for (lt = main->latt.first; lt; lt = lt->id.next) { + for (lt = bmain->latt.first; lt; lt = lt->id.next) { if ((key = blo_do_versions_newlibadr(fd, lib, lt->key)) && key->refkey) { data = key->refkey->data; tot = MIN2(lt->pntsu*lt->pntsv*lt->pntsw, key->refkey->totelem); @@ -994,7 +994,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main) } } - for (cu = main->curve.first; cu; cu = cu->id.next) { + for (cu = bmain->curve.first; cu; cu = cu->id.next) { if ((key = blo_do_versions_newlibadr(fd, lib, cu->key)) && key->refkey) { data = key->refkey->data; @@ -1022,9 +1022,9 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main) } } - if (main->versionfile < 250 || (main->versionfile == 250 && main->subversionfile < 8)) { + if (bmain->versionfile < 250 || (bmain->versionfile == 250 && bmain->subversionfile < 8)) { { - Scene *sce = main->scene.first; + Scene *sce = bmain->scene.first; while (sce) { if (sce->r.frame_step == 0) sce->r.frame_step = 1; @@ -1039,7 +1039,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main) { /* ensure all nodes have unique names */ - bNodeTree *ntree = main->nodetree.first; + bNodeTree *ntree = bmain->nodetree.first; while (ntree) { bNode *node = ntree->nodes.first; @@ -1053,7 +1053,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main) } { - Object *ob = main->object.first; + Object *ob = bmain->object.first; while (ob) { /* shaded mode disabled for now */ if (ob->dt == OB_MATERIAL) @@ -1067,7 +1067,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main) ScrArea *sa; SpaceLink *sl; - for (screen = main->screen.first; screen; screen = screen->id.next) { + for (screen = bmain->screen.first; screen; screen = screen->id.next) { for (sa = screen->areabase.first; sa; sa = sa->next) { for (sl = sa->spacedata.first; sl; sl = sl->next) { if (sl->spacetype == SPACE_VIEW3D) { @@ -1081,10 +1081,10 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main) } /* only convert old 2.50 files with color management */ - if (main->versionfile == 250) { - Scene *sce = main->scene.first; - Material *ma = main->mat.first; - Tex *tex = main->tex.first; + if (bmain->versionfile == 250) { + Scene *sce = bmain->scene.first; + Material *ma = bmain->mat.first; + Tex *tex = bmain->tex.first; int i, convert = 0; /* convert to new color management system: @@ -1120,20 +1120,20 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main) } } - if (main->versionfile < 250 || (main->versionfile == 250 && main->subversionfile < 9)) { + if (bmain->versionfile < 250 || (bmain->versionfile == 250 && bmain->subversionfile < 9)) { Scene *sce; Mesh *me; Object *ob; - for (sce = main->scene.first; sce; sce = sce->id.next) + for (sce = bmain->scene.first; sce; sce = sce->id.next) if (!sce->toolsettings->particle.selectmode) sce->toolsettings->particle.selectmode = SCE_SELECT_PATH; - if (main->versionfile == 250 && main->subversionfile > 1) { - for (me = main->mesh.first; me; me = me->id.next) + if (bmain->versionfile == 250 && bmain->subversionfile > 1) { + for (me = bmain->mesh.first; me; me = me->id.next) multires_load_old_250(me); - for (ob = main->object.first; ob; ob = ob->id.next) { + for (ob = bmain->object.first; ob; ob = ob->id.next) { MultiresModifierData *mmd = (MultiresModifierData *) modifiers_findByType(ob, eModifierType_Multires); if (mmd) { @@ -1146,11 +1146,11 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main) } } - if (main->versionfile < 250 || (main->versionfile == 250 && main->subversionfile < 10)) { + if (bmain->versionfile < 250 || (bmain->versionfile == 250 && bmain->subversionfile < 10)) { Object *ob; /* properly initialize hair clothsim data on old files */ - for (ob = main->object.first; ob; ob = ob->id.next) { + for (ob = bmain->object.first; ob; ob = ob->id.next) { ModifierData *md; for (md = ob->modifiers.first; md; md = md->next) { if (md->type == eModifierType_Cloth) { @@ -1163,14 +1163,14 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main) } /* fix bad area setup in subversion 10 */ - if (main->versionfile == 250 && main->subversionfile == 10) { + if (bmain->versionfile == 250 && bmain->subversionfile == 10) { /* fix for new view type in sequencer */ bScreen *screen; ScrArea *sa; SpaceLink *sl; /* remove all preview window in wrong spaces */ - for (screen = main->screen.first; screen; screen = screen->id.next) { + for (screen = bmain->screen.first; screen; screen = screen->id.next) { for (sa = screen->areabase.first; sa; sa = sa->next) { for (sl = sa->spacedata.first; sl; sl = sl->next) { if (sl->spacetype != SPACE_SEQ) { @@ -1200,14 +1200,14 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main) } } - if (main->versionfile < 250 || (main->versionfile == 250 && main->subversionfile < 11)) { + if (bmain->versionfile < 250 || (bmain->versionfile == 250 && bmain->subversionfile < 11)) { { /* fix for new view type in sequencer */ bScreen *screen; ScrArea *sa; SpaceLink *sl; - for (screen = main->screen.first; screen; screen = screen->id.next) { + for (screen = bmain->screen.first; screen; screen = screen->id.next) { for (sa = screen->areabase.first; sa; sa = sa->next) { for (sl = sa->spacedata.first; sl; sl = sl->next) { if (sl->spacetype == SPACE_SEQ) { @@ -1243,12 +1243,12 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main) } } - if (main->versionfile < 250 || (main->versionfile == 250 && main->subversionfile < 12)) { + if (bmain->versionfile < 250 || (bmain->versionfile == 250 && bmain->subversionfile < 12)) { Object *ob; Brush *brush; /* anim viz changes */ - for (ob = main->object.first; ob; ob = ob->id.next) { + for (ob = bmain->object.first; ob; ob = ob->id.next) { /* initialize object defaults */ animviz_settings_init(&ob->avs); @@ -1323,19 +1323,19 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main) } /* brush texture changes */ - for (brush = main->brush.first; brush; brush = brush->id.next) { + for (brush = bmain->brush.first; brush; brush = brush->id.next) { BKE_texture_mtex_default(&brush->mtex); BKE_texture_mtex_default(&brush->mask_mtex); } } - if (main->versionfile < 250 || (main->versionfile == 250 && main->subversionfile < 13)) { + if (bmain->versionfile < 250 || (bmain->versionfile == 250 && bmain->subversionfile < 13)) { /* NOTE: if you do more conversion, be sure to do it outside of this and * increase subversion again, otherwise it will not be correct */ Object *ob; /* convert degrees to radians for internal use */ - for (ob = main->object.first; ob; ob = ob->id.next) { + for (ob = bmain->object.first; ob; ob = ob->id.next) { bPoseChannel *pchan; do_version_constraints_radians_degrees_250(&ob->constraints); @@ -1355,13 +1355,13 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main) } } - if (main->versionfile < 250 || (main->versionfile == 250 && main->subversionfile < 14)) { + if (bmain->versionfile < 250 || (bmain->versionfile == 250 && bmain->subversionfile < 14)) { /* fix for bad View2D extents for Animation Editors */ bScreen *screen; ScrArea *sa; SpaceLink *sl; - for (screen = main->screen.first; screen; screen = screen->id.next) { + for (screen = bmain->screen.first; screen; screen = screen->id.next) { for (sa = screen->areabase.first; sa; sa = sa->next) { for (sl = sa->spacedata.first; sl; sl = sl->next) { ListBase *regionbase; @@ -1385,12 +1385,12 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main) } } - if (main->versionfile < 250 || (main->versionfile == 250 && main->subversionfile < 17)) { + if (bmain->versionfile < 250 || (bmain->versionfile == 250 && bmain->subversionfile < 17)) { Scene *sce; Sequence *seq; /* initialize to sane default so toggling on border shows something */ - for (sce = main->scene.first; sce; sce = sce->id.next) { + for (sce = bmain->scene.first; sce; sce = sce->id.next) { if (sce->r.border.xmin == 0.0f && sce->r.border.ymin == 0.0f && sce->r.border.xmax == 0.0f && sce->r.border.ymax == 0.0f) { @@ -1411,7 +1411,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main) } /* particle brush strength factor was changed from int to float */ - for (sce = main->scene.first; sce; sce = sce->id.next) { + for (sce = bmain->scene.first; sce; sce = sce->id.next) { ParticleEditSettings *pset = &sce->toolsettings->particle; int a; @@ -1425,7 +1425,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main) ScrArea *sa; SpaceLink *sl; - for (screen = main->screen.first; screen; screen = screen->id.next) { + for (screen = bmain->screen.first; screen; screen = screen->id.next) { for (sa = screen->areabase.first; sa; sa = sa->next) { for (sl = sa->spacedata.first; sl; sl = sl->next) { if (sl->spacetype == SPACE_SEQ) { @@ -1454,14 +1454,14 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main) } /* sequencer changes */ } - if (main->versionfile <= 251) { /* 2.5.1 had no subversions */ + if (bmain->versionfile <= 251) { /* 2.5.1 had no subversions */ bScreen *sc; /* Blender 2.5.2 - subversion 0 introduced a new setting: V3D_RENDER_OVERRIDE. * This bit was used in the past for V3D_TRANSFORM_SNAP, which is now deprecated. * Here we clear it for old files so they don't come in with V3D_RENDER_OVERRIDE set, * which would cause cameras, lamps, etc to become invisible */ - for (sc = main->screen.first; sc; sc = sc->id.next) { + for (sc = bmain->screen.first; sc; sc = sc->id.next) { ScrArea *sa; for (sa = sc->areabase.first; sa; sa = sa->next) { SpaceLink *sl; @@ -1475,19 +1475,19 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main) } } - if (main->versionfile < 252 || (main->versionfile == 252 && main->subversionfile < 1)) { + if (bmain->versionfile < 252 || (bmain->versionfile == 252 && bmain->subversionfile < 1)) { Brush *brush; Object *ob; Scene *scene; bNodeTree *ntree; - for (brush = main->brush.first; brush; brush = brush->id.next) { + for (brush = bmain->brush.first; brush; brush = brush->id.next) { if (brush->curve) brush->curve->preset = CURVE_PRESET_SMOOTH; } /* properly initialize active flag for fluidsim modifiers */ - for (ob = main->object.first; ob; ob = ob->id.next) { + for (ob = bmain->object.first; ob; ob = ob->id.next) { ModifierData *md; for (md = ob->modifiers.first; md; md = md->next) { if (md->type == eModifierType_Fluidsim) { @@ -1499,7 +1499,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main) } /* adjustment to color balance node values */ - for (scene = main->scene.first; scene; scene = scene->id.next) { + for (scene = bmain->scene.first; scene; scene = scene->id.next) { if (scene->nodetree) { bNode *node = scene->nodetree->nodes.first; @@ -1515,7 +1515,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main) } } /* check inside node groups too */ - for (ntree = main->nodetree.first; ntree; ntree = ntree->id.next) { + for (ntree = bmain->nodetree.first; ntree; ntree = ntree->id.next) { bNode *node = ntree->nodes.first; while (node) { @@ -1532,18 +1532,18 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main) } /* old-track -> constraints (this time we're really doing it!) */ - if (main->versionfile < 252 || (main->versionfile == 252 && main->subversionfile < 2)) { + if (bmain->versionfile < 252 || (bmain->versionfile == 252 && bmain->subversionfile < 2)) { Object *ob; - for (ob = main->object.first; ob; ob = ob->id.next) + for (ob = bmain->object.first; ob; ob = ob->id.next) blo_do_version_old_trackto_to_constraints(ob); } - if (main->versionfile < 252 || (main->versionfile == 252 && main->subversionfile < 5)) { + if (bmain->versionfile < 252 || (bmain->versionfile == 252 && bmain->subversionfile < 5)) { bScreen *sc; /* Image editor scopes */ - for (sc = main->screen.first; sc; sc = sc->id.next) { + for (sc = bmain->screen.first; sc; sc = sc->id.next) { ScrArea *sa; for (sa = sc->areabase.first; sa; sa = sa->next) { @@ -1559,14 +1559,14 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main) } } - if (main->versionfile < 253) { + if (bmain->versionfile < 253) { Object *ob; Scene *scene; bScreen *sc; Tex *tex; Brush *brush; - for (sc = main->screen.first; sc; sc = sc->id.next) { + for (sc = bmain->screen.first; sc; sc = sc->id.next) { ScrArea *sa; for (sa = sc->areabase.first; sa; sa = sa->next) { SpaceLink *sl; @@ -1600,10 +1600,10 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main) } } - do_version_mdef_250(main); + do_version_mdef_250(bmain); /* parent type to modifier */ - for (ob = main->object.first; ob; ob = ob->id.next) { + for (ob = bmain->object.first; ob; ob = ob->id.next) { if (ob->parent) { Object *parent = (Object *) blo_do_versions_newlibadr(fd, lib, ob->parent); if (parent) { /* parent may not be in group */ @@ -1638,7 +1638,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main) } /* initialize scene active layer */ - for (scene = main->scene.first; scene; scene = scene->id.next) { + for (scene = bmain->scene.first; scene; scene = scene->id.next) { int i; for (i = 0; i < 20; i++) { if (scene->lay & (1<<i)) { @@ -1648,7 +1648,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main) } } - for (tex = main->tex.first; tex; tex = tex->id.next) { + for (tex = bmain->tex.first; tex; tex = tex->id.next) { /* if youre picky, this isn't correct until we do a version bump * since you could set saturation to be 0.0*/ if (tex->saturation == 0.0f) @@ -1657,12 +1657,12 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main) { Curve *cu; - for (cu = main->curve.first; cu; cu = cu->id.next) { + for (cu = bmain->curve.first; cu; cu = cu->id.next) { cu->smallcaps_scale = 0.75f; } } - for (scene = main->scene.first; scene; scene = scene->id.next) { + for (scene = bmain->scene.first; scene; scene = scene->id.next) { if (scene) { Sequence *seq; SEQ_BEGIN (scene->ed, seq) @@ -1677,7 +1677,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main) /* GSOC 2010 Sculpt - New settings for Brush */ - for (brush = main->brush.first; brush; brush = brush->id.next) { + for (brush = bmain->brush.first; brush; brush = brush->id.next) { /* Sanity Check */ /* infinite number of dabs */ @@ -1721,7 +1721,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main) brush->rate = 0.1f; /* New Settings */ - if (main->versionfile < 252 || (main->versionfile == 252 && main->subversionfile < 5)) { + if (bmain->versionfile < 252 || (bmain->versionfile == 252 && bmain->subversionfile < 5)) { brush->flag |= BRUSH_SPACE_ATTEN; // explicitly enable adaptive space /* spacing was originally in pixels, convert it to percentage for new version @@ -1751,9 +1751,9 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main) } /* GSOC Sculpt 2010 - Sanity check on Sculpt/Paint settings */ - if (main->versionfile < 253) { + if (bmain->versionfile < 253) { Scene *sce; - for (sce = main->scene.first; sce; sce = sce->id.next) { + for (sce = bmain->scene.first; sce; sce = sce->id.next) { if (sce->toolsettings->sculpt_paint_unified_alpha == 0) sce->toolsettings->sculpt_paint_unified_alpha = 0.5f; @@ -1765,10 +1765,10 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main) } } - if (main->versionfile < 253 || (main->versionfile == 253 && main->subversionfile < 1)) { + if (bmain->versionfile < 253 || (bmain->versionfile == 253 && bmain->subversionfile < 1)) { Object *ob; - for (ob = main->object.first; ob; ob = ob->id.next) { + for (ob = bmain->object.first; ob; ob = ob->id.next) { ModifierData *md; for (md = ob->modifiers.first; md; md = md->next) { @@ -1788,7 +1788,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main) /* for now just add it to all flow objects in the scene */ { Object *ob2; - for (ob2 = main->object.first; ob2; ob2 = ob2->id.next) { + for (ob2 = bmain->object.first; ob2; ob2 = ob2->id.next) { ModifierData *md2; for (md2 = ob2->modifiers.first; md2; md2 = md2->next) { if (md2->type == eModifierType_Smoke) { @@ -1811,17 +1811,17 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main) } } - if (main->versionfile < 255 || (main->versionfile == 255 && main->subversionfile < 1)) { + if (bmain->versionfile < 255 || (bmain->versionfile == 255 && bmain->subversionfile < 1)) { Brush *br; ParticleSettings *part; bScreen *sc; - for (br = main->brush.first; br; br = br->id.next) { + for (br = bmain->brush.first; br; br = br->id.next) { if (br->ob_mode == 0) br->ob_mode = OB_MODE_ALL_PAINT; } - for (part = main->particle.first; part; part = part->id.next) { + for (part = bmain->particle.first; part; part = part->id.next) { if (part->boids) part->boids->pitch = 1.0f; @@ -1829,7 +1829,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main) part->kink_amp_clump = 1.f; /* keep old files looking similar */ } - for (sc = main->screen.first; sc; sc = sc->id.next) { + for (sc = bmain->screen.first; sc; sc = sc->id.next) { ScrArea *sa; for (sa = sc->areabase.first; sa; sa = sa->next) { SpaceLink *sl; @@ -1856,11 +1856,11 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main) } } - if (main->versionfile < 255 || (main->versionfile == 255 && main->subversionfile < 3)) { + if (bmain->versionfile < 255 || (bmain->versionfile == 255 && bmain->subversionfile < 3)) { Object *ob; /* ocean res is now squared, reset old ones - will be massive */ - for (ob = main->object.first; ob; ob = ob->id.next) { + for (ob = bmain->object.first; ob; ob = ob->id.next) { ModifierData *md; for (md = ob->modifiers.first; md; md = md->next) { if (md->type == eModifierType_Ocean) { @@ -1872,13 +1872,13 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main) } } - if (main->versionfile < 256) { + if (bmain->versionfile < 256) { bScreen *sc; ScrArea *sa; Key *key; /* Fix for sample line scope initializing with no height */ - for (sc = main->screen.first; sc; sc = sc->id.next) { + for (sc = bmain->screen.first; sc; sc = sc->id.next) { sa = sc->areabase.first; while (sa) { SpaceLink *sl; @@ -1897,7 +1897,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main) * 2.4x would never reveal this to users as a dummy value always ended up getting used * instead */ - for (key = main->key.first; key; key = key->id.next) { + for (key = bmain->key.first; key; key = key->id.next) { KeyBlock *kb; for (kb = key->block.first; kb; kb = kb->next) { @@ -1907,19 +1907,19 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main) } } - if (main->versionfile < 256 || (main->versionfile == 256 && main->subversionfile < 1)) { + if (bmain->versionfile < 256 || (bmain->versionfile == 256 && bmain->subversionfile < 1)) { /* fix for bones that didn't have arm_roll before */ bArmature *arm; Bone *bone; Object *ob; - for (arm = main->armature.first; arm; arm = arm->id.next) + for (arm = bmain->armature.first; arm; arm = arm->id.next) for (bone = arm->bonebase.first; bone; bone = bone->next) do_version_bone_roll_256(bone); /* fix for objects which have zero dquat's * since this is multiplied with the quat rather than added */ - for (ob = main->object.first; ob; ob = ob->id.next) { + for (ob = bmain->object.first; ob; ob = ob->id.next) { if (is_zero_v4(ob->dquat)) { unit_qt(ob->dquat); } @@ -1929,7 +1929,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main) } } - if (main->versionfile < 256 || (main->versionfile == 256 && main->subversionfile < 2)) { + if (bmain->versionfile < 256 || (bmain->versionfile == 256 && bmain->subversionfile < 2)) { bNodeTree *ntree; bNode *node; bNodeSocket *sock, *gsock; @@ -1938,7 +1938,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main) /* node sockets are not exposed automatically any more, * this mimics the old behavior by adding all unlinked sockets to groups. */ - for (ntree=main->nodetree.first; ntree; ntree=ntree->id.next) { + for (ntree=bmain->nodetree.first; ntree; ntree=ntree->id.next) { /* this adds copies and links from all unlinked internal sockets to group inputs/outputs. */ /* first make sure the own_index for new sockets is valid */ @@ -2007,14 +2007,14 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main) } } - if (main->versionfile < 256 || (main->versionfile == 256 && main->subversionfile < 3)) { + if (bmain->versionfile < 256 || (bmain->versionfile == 256 && bmain->subversionfile < 3)) { bScreen *sc; Brush *brush; Object *ob; ParticleSettings *part; /* redraws flag in SpaceTime has been moved to Screen level */ - for (sc = main->screen.first; sc; sc = sc->id.next) { + for (sc = bmain->screen.first; sc; sc = sc->id.next) { if (sc->redraws_flag == 0) { /* just initialize to default? */ /* XXX: we could also have iterated through areas, and taken them from the first timeline available... */ @@ -2022,13 +2022,13 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main) } } - for (brush = main->brush.first; brush; brush = brush->id.next) { + for (brush = bmain->brush.first; brush; brush = brush->id.next) { if (brush->height == 0) brush->height = 0.4f; } /* replace 'rim material' option for in offset*/ - for (ob = main->object.first; ob; ob = ob->id.next) { + for (ob = bmain->object.first; ob; ob = ob->id.next) { ModifierData *md; for (md = ob->modifiers.first; md; md = md->next) { if (md->type == eModifierType_Solidify) { @@ -2042,24 +2042,24 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main) } /* particle draw color from material */ - for (part = main->particle.first; part; part = part->id.next) { + for (part = bmain->particle.first; part; part = part->id.next) { if (part->draw & PART_DRAW_MAT_COL) part->draw_col = PART_DRAW_COL_MAT; } } - if (main->versionfile < 256 || (main->versionfile == 256 && main->subversionfile < 6)) { + if (bmain->versionfile < 256 || (bmain->versionfile == 256 && bmain->subversionfile < 6)) { Mesh *me; - for (me = main->mesh.first; me; me = me->id.next) + for (me = bmain->mesh.first; me; me = me->id.next) BKE_mesh_calc_normals_tessface(me->mvert, me->totvert, me->mface, me->totface, NULL); } - if (main->versionfile < 256 || (main->versionfile == 256 && main->subversionfile < 2)) { + if (bmain->versionfile < 256 || (bmain->versionfile == 256 && bmain->subversionfile < 2)) { /* update blur area sizes from 0..1 range to 0..100 percentage */ Scene *scene; bNode *node; - for (scene = main->scene.first; scene; scene = scene->id.next) + for (scene = bmain->scene.first; scene; scene = scene->id.next) if (scene->nodetree) for (node = scene->nodetree->nodes.first; node; node = node->next) if (node->type == CMP_NODE_BLUR) { @@ -2069,13 +2069,13 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main) } } - if (main->versionfile < 258 || (main->versionfile == 258 && main->subversionfile < 1)) { + if (bmain->versionfile < 258 || (bmain->versionfile == 258 && bmain->subversionfile < 1)) { /* screen view2d settings were not properly initialized [#27164] * v2d->scroll caused the bug but best reset other values too which are in old blend files only. * need to make less ugly - possibly an iterator? */ bScreen *screen; - for (screen = main->screen.first; screen; screen = screen->id.next) { + for (screen = bmain->screen.first; screen; screen = screen->id.next) { ScrArea *sa; /* add regions */ for (sa = screen->areabase.first; sa; sa = sa->next) { @@ -2106,19 +2106,19 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main) { ParticleSettings *part; - for (part = main->particle.first; part; part = part->id.next) { + for (part = bmain->particle.first; part; part = part->id.next) { /* Initialize particle billboard scale */ part->bb_size[0] = part->bb_size[1] = 1.0f; } } } - if (main->versionfile < 259 || (main->versionfile == 259 && main->subversionfile < 1)) { + if (bmain->versionfile < 259 || (bmain->versionfile == 259 && bmain->subversionfile < 1)) { { Scene *scene; Sequence *seq; - for (scene = main->scene.first; scene; scene = scene->id.next) { + for (scene = bmain->scene.first; scene; scene = scene->id.next) { scene->r.ffcodecdata.audio_channels = 2; scene->audio.volume = 1.0f; SEQ_BEGIN (scene->ed, seq) @@ -2131,7 +2131,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main) { bScreen *screen; - for (screen = main->screen.first; screen; screen = screen->id.next) { + for (screen = bmain->screen.first; screen; screen = screen->id.next) { ScrArea *sa; /* add regions */ @@ -2172,7 +2172,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main) bAction *act; FCurve *fcu; - for (act = main->action.first; act; act = act->id.next) { + for (act = bmain->action.first; act; act = act->id.next) { for (fcu = act->curves.first; fcu; fcu = fcu->next) { BezTriple *bezt; unsigned int i = 0; @@ -2197,10 +2197,10 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main) } } - if (main->versionfile < 259 || (main->versionfile == 259 && main->subversionfile < 2)) { + if (bmain->versionfile < 259 || (bmain->versionfile == 259 && bmain->subversionfile < 2)) { { /* Convert default socket values from bNodeStack */ - FOREACH_NODETREE(main, ntree, id) { + FOREACH_NODETREE(bmain, ntree, id) { bNode *node; bNodeSocket *sock; @@ -2227,17 +2227,17 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main) * associate them with specific node types for polling. */ bNodeTree *ntree; - /* all node trees in main->nodetree are considered groups */ - for (ntree = main->nodetree.first; ntree; ntree = ntree->id.next) + /* all node trees in bmain->nodetree are considered groups */ + for (ntree = bmain->nodetree.first; ntree; ntree = ntree->id.next) ntree->nodetype = NODE_GROUP; } } - if (main->versionfile < 259 || (main->versionfile == 259 && main->subversionfile < 4)) { + if (bmain->versionfile < 259 || (bmain->versionfile == 259 && bmain->subversionfile < 4)) { { /* Adaptive time step for particle systems */ ParticleSettings *part; - for (part = main->particle.first; part; part = part->id.next) { + for (part = bmain->particle.first; part; part = part->id.next) { part->courant_target = 0.2f; part->time_flag &= ~PART_TIME_AUTOSF; } diff --git a/source/blender/blenloader/intern/versioning_260.c b/source/blender/blenloader/intern/versioning_260.c index 8e0795f7e34..2cded68f7ec 100644 --- a/source/blender/blenloader/intern/versioning_260.c +++ b/source/blender/blenloader/intern/versioning_260.c @@ -608,15 +608,15 @@ static void do_versions_nodetree_customnodes(bNodeTree *ntree, int UNUSED(is_gro } } -void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main) +void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *bmain) { - if (main->versionfile < 260) { + if (bmain->versionfile < 260) { { /* set default alpha value of Image outputs in image and render layer nodes to 0 */ Scene *sce; bNodeTree *ntree; - for (sce = main->scene.first; sce; sce = sce->id.next) { + for (sce = bmain->scene.first; sce; sce = sce->id.next) { /* there are files with invalid audio_channels value, the real cause * is unknown, but we fix it here anyway to avoid crashes */ if (sce->r.ffcodecdata.audio_channels == 0) @@ -626,7 +626,7 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main) do_versions_nodetree_image_default_alpha_output(sce->nodetree); } - for (ntree = main->nodetree.first; ntree; ntree = ntree->id.next) + for (ntree = bmain->nodetree.first; ntree; ntree = ntree->id.next) do_versions_nodetree_image_default_alpha_output(ntree); } @@ -634,7 +634,7 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main) /* support old particle dupliobject rotation settings */ ParticleSettings *part; - for (part = main->particle.first; part; part = part->id.next) { + for (part = bmain->particle.first; part; part = part->id.next) { if (ELEM(part->ren_as, PART_DRAW_OB, PART_DRAW_GR)) { part->draw |= PART_DRAW_ROTATE_OB; @@ -645,16 +645,16 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main) } } - if (main->versionfile < 260 || (main->versionfile == 260 && main->subversionfile < 1)) { + if (bmain->versionfile < 260 || (bmain->versionfile == 260 && bmain->subversionfile < 1)) { Object *ob; - for (ob = main->object.first; ob; ob = ob->id.next) { + for (ob = bmain->object.first; ob; ob = ob->id.next) { ob->collision_boundtype = ob->boundtype; } { Camera *cam; - for (cam = main->camera.first; cam; cam = cam->id.next) { + for (cam = bmain->camera.first; cam; cam = cam->id.next) { if (cam->sensor_x < 0.01f) cam->sensor_x = DEFAULT_SENSOR_WIDTH; @@ -664,8 +664,8 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main) } } - if (main->versionfile < 260 || (main->versionfile == 260 && main->subversionfile < 2)) { - FOREACH_NODETREE(main, ntree, id) { + if (bmain->versionfile < 260 || (bmain->versionfile == 260 && bmain->subversionfile < 2)) { + FOREACH_NODETREE(bmain, ntree, id) { if (ntree->type == NTREE_SHADER) { bNode *node; for (node = ntree->nodes.first; node; node = node->next) { @@ -682,24 +682,24 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main) } FOREACH_NODETREE_END } - if (main->versionfile < 260 || (main->versionfile == 260 && main->subversionfile < 4)) { + if (bmain->versionfile < 260 || (bmain->versionfile == 260 && bmain->subversionfile < 4)) { { /* Convert node angles to radians! */ Scene *sce; Material *mat; bNodeTree *ntree; - for (sce = main->scene.first; sce; sce = sce->id.next) { + for (sce = bmain->scene.first; sce; sce = sce->id.next) { if (sce->nodetree) do_versions_nodetree_convert_angle(sce->nodetree); } - for (mat = main->mat.first; mat; mat = mat->id.next) { + for (mat = bmain->mat.first; mat; mat = mat->id.next) { if (mat->nodetree) do_versions_nodetree_convert_angle(mat->nodetree); } - for (ntree = main->nodetree.first; ntree; ntree = ntree->id.next) + for (ntree = bmain->nodetree.first; ntree; ntree = ntree->id.next) do_versions_nodetree_convert_angle(ntree); } @@ -708,7 +708,7 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main) bScreen *sc; MovieClip *clip; - for (sc = main->screen.first; sc; sc = sc->id.next) { + for (sc = bmain->screen.first; sc; sc = sc->id.next) { ScrArea *sa; for (sa = sc->areabase.first; sa; sa = sa->next) { SpaceLink *sl; @@ -732,7 +732,7 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main) } } - for (clip = main->movieclip.first; clip; clip = clip->id.next) { + for (clip = bmain->movieclip.first; clip; clip = clip->id.next) { MovieTrackingTrack *track; if (clip->aspx < 1.0f) { @@ -764,16 +764,16 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main) } } - if (main->versionfile < 260 || (main->versionfile == 260 && main->subversionfile < 6)) { + if (bmain->versionfile < 260 || (bmain->versionfile == 260 && bmain->subversionfile < 6)) { Scene *sce; MovieClip *clip; bScreen *sc; - for (sce = main->scene.first; sce; sce = sce->id.next) { + for (sce = bmain->scene.first; sce; sce = sce->id.next) { do_versions_image_settings_2_60(sce); } - for (clip = main->movieclip.first; clip; clip = clip->id.next) { + for (clip = bmain->movieclip.first; clip; clip = clip->id.next) { MovieTrackingSettings *settings = &clip->tracking.settings; if (settings->default_pattern_size == 0.0f) { @@ -784,7 +784,7 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main) } } - for (sc = main->screen.first; sc; sc = sc->id.next) { + for (sc = bmain->screen.first; sc; sc = sc->id.next) { ScrArea *sa; for (sa = sc->areabase.first; sa; sa = sa->next) { SpaceLink *sl; @@ -799,7 +799,7 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main) { Object *ob; - for (ob = main->object.first; ob; ob = ob->id.next) { + for (ob = bmain->object.first; ob; ob = ob->id.next) { /* convert delta addition into delta scale */ int i; for (i = 0; i < 3; i++) { @@ -819,25 +819,25 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main) /* sigh, this dscale vs dsize version patching was not done right, fix for fix, * this intentionally checks an exact subversion, also note this was never in a release, * at some point this could be removed. */ - else if (main->versionfile == 260 && main->subversionfile == 6) { + else if (bmain->versionfile == 260 && bmain->subversionfile == 6) { Object *ob; - for (ob = main->object.first; ob; ob = ob->id.next) { + for (ob = bmain->object.first; ob; ob = ob->id.next) { if (is_zero_v3(ob->dscale)) { copy_vn_fl(ob->dscale, 3, 1.0f); } } } - if (main->versionfile < 260 || (main->versionfile == 260 && main->subversionfile < 8)) { + if (bmain->versionfile < 260 || (bmain->versionfile == 260 && bmain->subversionfile < 8)) { Brush *brush; - for (brush = main->brush.first; brush; brush = brush->id.next) { + for (brush = bmain->brush.first; brush; brush = brush->id.next) { if (brush->sculpt_tool == SCULPT_TOOL_ROTATE) brush->alpha = 1.0f; } } - if (main->versionfile < 261 || (main->versionfile == 261 && main->subversionfile < 1)) { + if (bmain->versionfile < 261 || (bmain->versionfile == 261 && bmain->subversionfile < 1)) { { /* update use flags for node sockets (was only temporary before) */ Scene *sce; @@ -847,32 +847,32 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main) World *world; bNodeTree *ntree; - for (sce = main->scene.first; sce; sce = sce->id.next) { + for (sce = bmain->scene.first; sce; sce = sce->id.next) { if (sce->nodetree) do_versions_nodetree_socket_use_flags_2_62(sce->nodetree); } - for (mat = main->mat.first; mat; mat = mat->id.next) { + for (mat = bmain->mat.first; mat; mat = mat->id.next) { if (mat->nodetree) do_versions_nodetree_socket_use_flags_2_62(mat->nodetree); } - for (tex = main->tex.first; tex; tex = tex->id.next) { + for (tex = bmain->tex.first; tex; tex = tex->id.next) { if (tex->nodetree) do_versions_nodetree_socket_use_flags_2_62(tex->nodetree); } - for (lamp = main->lamp.first; lamp; lamp = lamp->id.next) { + for (lamp = bmain->lamp.first; lamp; lamp = lamp->id.next) { if (lamp->nodetree) do_versions_nodetree_socket_use_flags_2_62(lamp->nodetree); } - for (world = main->world.first; world; world = world->id.next) { + for (world = bmain->world.first; world; world = world->id.next) { if (world->nodetree) do_versions_nodetree_socket_use_flags_2_62(world->nodetree); } - for (ntree = main->nodetree.first; ntree; ntree = ntree->id.next) { + for (ntree = bmain->nodetree.first; ntree; ntree = ntree->id.next) { do_versions_nodetree_socket_use_flags_2_62(ntree); } } @@ -880,7 +880,7 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main) MovieClip *clip; Object *ob; - for (clip = main->movieclip.first; clip; clip = clip->id.next) { + for (clip = bmain->movieclip.first; clip; clip = clip->id.next) { MovieTracking *tracking = &clip->tracking; MovieTrackingObject *tracking_object = tracking->objects.first; @@ -900,7 +900,7 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main) } } - for (ob = main->object.first; ob; ob = ob->id.next) { + for (ob = bmain->object.first; ob; ob = ob->id.next) { bConstraint *con; for (con = ob->constraints.first; con; con = con->next) { if (con->type == CONSTRAINT_TYPE_OBJECTSOLVER) { @@ -914,12 +914,12 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main) } } - if (main->versionfile < 261 || (main->versionfile == 261 && main->subversionfile < 2)) { + if (bmain->versionfile < 261 || (bmain->versionfile == 261 && bmain->subversionfile < 2)) { { /* convert deprecated sculpt_paint_unified_* fields to * UnifiedPaintSettings */ Scene *scene; - for (scene = main->scene.first; scene; scene = scene->id.next) { + for (scene = bmain->scene.first; scene; scene = scene->id.next) { ToolSettings *ts = scene->toolsettings; UnifiedPaintSettings *ups = &ts->unified_paint_settings; ups->size = ts->sculpt_paint_unified_size; @@ -930,11 +930,11 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main) } } - if (main->versionfile < 261 || (main->versionfile == 261 && main->subversionfile < 3)) { + if (bmain->versionfile < 261 || (bmain->versionfile == 261 && bmain->subversionfile < 3)) { { /* convert extended ascii to utf-8 for text editor */ Text *text; - for (text = main->text.first; text; text = text->id.next) { + for (text = bmain->text.first; text; text = text->id.next) { if (!(text->flags & TXT_ISEXT)) { TextLine *tl; @@ -952,7 +952,7 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main) { /* set new dynamic paint values */ Object *ob; - for (ob = main->object.first; ob; ob = ob->id.next) { + for (ob = bmain->object.first; ob; ob = ob->id.next) { ModifierData *md; for (md = ob->modifiers.first; md; md = md->next) { if (md->type == eModifierType_DynamicPaint) { @@ -972,9 +972,9 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main) } } - if (main->versionfile < 262) { + if (bmain->versionfile < 262) { Object *ob; - for (ob = main->object.first; ob; ob = ob->id.next) { + for (ob = bmain->object.first; ob; ob = ob->id.next) { ModifierData *md; for (md = ob->modifiers.first; md; md = md->next) { @@ -987,12 +987,12 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main) } } - if (main->versionfile < 263) { + if (bmain->versionfile < 263) { /* set fluidsim rate. the version patch for this in 2.62 was wrong, so * try to correct it, if rate is 0.0 that's likely not intentional */ Object *ob; - for (ob = main->object.first; ob; ob = ob->id.next) { + for (ob = bmain->object.first; ob; ob = ob->id.next) { ModifierData *md; for (md = ob->modifiers.first; md; md = md->next) { if (md->type == eModifierType_Fluidsim) { @@ -1004,35 +1004,35 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main) } } - if (main->versionfile < 262 || (main->versionfile == 262 && main->subversionfile < 1)) { + if (bmain->versionfile < 262 || (bmain->versionfile == 262 && bmain->subversionfile < 1)) { /* update use flags for node sockets (was only temporary before) */ Scene *sce; bNodeTree *ntree; - for (sce = main->scene.first; sce; sce = sce->id.next) { + for (sce = bmain->scene.first; sce; sce = sce->id.next) { if (sce->nodetree) do_versions_nodetree_multi_file_output_format_2_62_1(sce, sce->nodetree); } /* XXX can't associate with scene for group nodes, image format will stay uninitialized */ - for (ntree = main->nodetree.first; ntree; ntree = ntree->id.next) + for (ntree = bmain->nodetree.first; ntree; ntree = ntree->id.next) do_versions_nodetree_multi_file_output_format_2_62_1(NULL, ntree); } /* only swap for pre-release bmesh merge which had MLoopCol red/blue swap */ - if (main->versionfile == 262 && main->subversionfile == 1) { + if (bmain->versionfile == 262 && bmain->subversionfile == 1) { { Mesh *me; - for (me = main->mesh.first; me; me = me->id.next) { + for (me = bmain->mesh.first; me; me = me->id.next) { do_versions_mesh_mloopcol_swap_2_62_1(me); } } } - if (main->versionfile < 262 || (main->versionfile == 262 && main->subversionfile < 2)) { + if (bmain->versionfile < 262 || (bmain->versionfile == 262 && bmain->subversionfile < 2)) { /* Set new idname of keyingsets from their now "label-only" name. */ Scene *scene; - for (scene = main->scene.first; scene; scene = scene->id.next) { + for (scene = bmain->scene.first; scene; scene = scene->id.next) { KeyingSet *ks; for (ks = scene->keyingsets.first; ks; ks = ks->next) { if (!ks->idname[0]) @@ -1041,11 +1041,11 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main) } } - if (main->versionfile < 262 || (main->versionfile == 262 && main->subversionfile < 3)) { + if (bmain->versionfile < 262 || (bmain->versionfile == 262 && bmain->subversionfile < 3)) { Object *ob; ModifierData *md; - for (ob = main->object.first; ob; ob = ob->id.next) { + for (ob = bmain->object.first; ob; ob = ob->id.next) { for (md = ob->modifiers.first; md; md = md->next) { if (md->type == eModifierType_Lattice) { LatticeModifierData *lmd = (LatticeModifierData *)md; @@ -1055,11 +1055,11 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main) } } - if (main->versionfile < 262 || (main->versionfile == 262 && main->subversionfile < 4)) { + if (bmain->versionfile < 262 || (bmain->versionfile == 262 && bmain->subversionfile < 4)) { /* Read Viscosity presets from older files */ Object *ob; - for (ob = main->object.first; ob; ob = ob->id.next) { + for (ob = bmain->object.first; ob; ob = ob->id.next) { ModifierData *md; for (md = ob->modifiers.first; md; md = md->next) { if (md->type == eModifierType_Fluidsim) { @@ -1079,27 +1079,27 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main) - if (main->versionfile < 263) { + if (bmain->versionfile < 263) { /* Default for old files is to save particle rotations to pointcache */ ParticleSettings *part; - for (part = main->particle.first; part; part = part->id.next) { + for (part = bmain->particle.first; part; part = part->id.next) { part->flag |= PART_ROTATIONS; } } - if (main->versionfile < 263 || (main->versionfile == 263 && main->subversionfile < 1)) { + if (bmain->versionfile < 263 || (bmain->versionfile == 263 && bmain->subversionfile < 1)) { /* file output node paths are now stored in the file info struct instead socket name */ Scene *sce; bNodeTree *ntree; - for (sce = main->scene.first; sce; sce = sce->id.next) + for (sce = bmain->scene.first; sce; sce = sce->id.next) if (sce->nodetree) do_versions_nodetree_multi_file_output_path_2_63_1(sce->nodetree); - for (ntree = main->nodetree.first; ntree; ntree = ntree->id.next) + for (ntree = bmain->nodetree.first; ntree; ntree = ntree->id.next) do_versions_nodetree_multi_file_output_path_2_63_1(ntree); } - if (main->versionfile < 263 || (main->versionfile == 263 && main->subversionfile < 3)) { + if (bmain->versionfile < 263 || (bmain->versionfile == 263 && bmain->subversionfile < 3)) { Scene *scene; Brush *brush; @@ -1107,7 +1107,7 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main) * unified paint settings also have weight. Update unified * paint settings and brushes with a default weight value. */ - for (scene = main->scene.first; scene; scene = scene->id.next) { + for (scene = bmain->scene.first; scene; scene = scene->id.next) { ToolSettings *ts = scene->toolsettings; if (ts) { ts->unified_paint_settings.weight = ts->vgroup_weight; @@ -1115,15 +1115,15 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main) } } - for (brush = main->brush.first; brush; brush = brush->id.next) { + for (brush = bmain->brush.first; brush; brush = brush->id.next) { brush->weight = 0.5; } } - if (main->versionfile < 263 || (main->versionfile == 263 && main->subversionfile < 2)) { + if (bmain->versionfile < 263 || (bmain->versionfile == 263 && bmain->subversionfile < 2)) { bScreen *sc; - for (sc = main->screen.first; sc; sc = sc->id.next) { + for (sc = bmain->screen.first; sc; sc = sc->id.next) { ScrArea *sa; for (sa = sc->areabase.first; sa; sa = sa->next) { SpaceLink *sl; @@ -1155,18 +1155,18 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main) } } - if (main->versionfile < 263 || (main->versionfile == 263 && main->subversionfile < 4)) { + if (bmain->versionfile < 263 || (bmain->versionfile == 263 && bmain->subversionfile < 4)) { Camera *cam; Curve *cu; - for (cam = main->camera.first; cam; cam = cam->id.next) { + for (cam = bmain->camera.first; cam; cam = cam->id.next) { if (cam->flag & CAM_PANORAMA) { cam->type = CAM_PANO; cam->flag &= ~CAM_PANORAMA; } } - for (cu = main->curve.first; cu; cu = cu->id.next) { + for (cu = bmain->curve.first; cu; cu = cu->id.next) { if (cu->bevfac2 == 0.0f) { cu->bevfac1 = 0.0f; cu->bevfac2 = 1.0f; @@ -1174,26 +1174,26 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main) } } - if (main->versionfile < 263 || (main->versionfile == 263 && main->subversionfile < 5)) { + if (bmain->versionfile < 263 || (bmain->versionfile == 263 && bmain->subversionfile < 5)) { { /* file output node paths are now stored in the file info struct instead socket name */ Scene *sce; bNodeTree *ntree; - for (sce = main->scene.first; sce; sce = sce->id.next) { + for (sce = bmain->scene.first; sce; sce = sce->id.next) { if (sce->nodetree) { do_versions_nodetree_file_output_layers_2_64_5(sce->nodetree); do_versions_nodetree_image_layer_2_64_5(sce->nodetree); } } - for (ntree = main->nodetree.first; ntree; ntree = ntree->id.next) { + for (ntree = bmain->nodetree.first; ntree; ntree = ntree->id.next) { do_versions_nodetree_file_output_layers_2_64_5(ntree); do_versions_nodetree_image_layer_2_64_5(ntree); } } } - if (main->versionfile < 263 || (main->versionfile == 263 && main->subversionfile < 6)) { + if (bmain->versionfile < 263 || (bmain->versionfile == 263 && bmain->subversionfile < 6)) { /* update use flags for node sockets (was only temporary before) */ Scene *sce; Material *mat; @@ -1202,34 +1202,34 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main) World *world; bNodeTree *ntree; - for (sce = main->scene.first; sce; sce = sce->id.next) + for (sce = bmain->scene.first; sce; sce = sce->id.next) if (sce->nodetree) do_versions_nodetree_frame_2_64_6(sce->nodetree); - for (mat = main->mat.first; mat; mat = mat->id.next) + for (mat = bmain->mat.first; mat; mat = mat->id.next) if (mat->nodetree) do_versions_nodetree_frame_2_64_6(mat->nodetree); - for (tex = main->tex.first; tex; tex = tex->id.next) + for (tex = bmain->tex.first; tex; tex = tex->id.next) if (tex->nodetree) do_versions_nodetree_frame_2_64_6(tex->nodetree); - for (lamp = main->lamp.first; lamp; lamp = lamp->id.next) + for (lamp = bmain->lamp.first; lamp; lamp = lamp->id.next) if (lamp->nodetree) do_versions_nodetree_frame_2_64_6(lamp->nodetree); - for (world = main->world.first; world; world = world->id.next) + for (world = bmain->world.first; world; world = world->id.next) if (world->nodetree) do_versions_nodetree_frame_2_64_6(world->nodetree); - for (ntree = main->nodetree.first; ntree; ntree = ntree->id.next) + for (ntree = bmain->nodetree.first; ntree; ntree = ntree->id.next) do_versions_nodetree_frame_2_64_6(ntree); } - if (main->versionfile < 263 || (main->versionfile == 263 && main->subversionfile < 7)) { + if (bmain->versionfile < 263 || (bmain->versionfile == 263 && bmain->subversionfile < 7)) { Object *ob; - for (ob = main->object.first; ob; ob = ob->id.next) { + for (ob = bmain->object.first; ob; ob = ob->id.next) { ModifierData *md; for (md = ob->modifiers.first; md; md = md->next) { if (md->type == eModifierType_Smoke) { @@ -1244,8 +1244,8 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main) } } - if (main->versionfile < 263 || (main->versionfile == 263 && main->subversionfile < 9)) { - FOREACH_NODETREE(main, ntree, id) { + if (bmain->versionfile < 263 || (bmain->versionfile == 263 && bmain->subversionfile < 9)) { + FOREACH_NODETREE(bmain, ntree, id) { if (ntree->type == NTREE_SHADER) { bNode *node; for (node = ntree->nodes.first; node; node = node->next) { @@ -1262,11 +1262,11 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main) } FOREACH_NODETREE_END } - if (main->versionfile < 263 || (main->versionfile == 263 && main->subversionfile < 10)) { + if (bmain->versionfile < 263 || (bmain->versionfile == 263 && bmain->subversionfile < 10)) { { Scene *scene; // composite redesign - for (scene = main->scene.first; scene; scene = scene->id.next) { + for (scene = bmain->scene.first; scene; scene = scene->id.next) { if (scene->nodetree) { if (scene->nodetree->chunksize == 0) { scene->nodetree->chunksize = 256; @@ -1274,7 +1274,7 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main) } } - FOREACH_NODETREE(main, ntree, id) { + FOREACH_NODETREE(bmain, ntree, id) { if (ntree->type == NTREE_COMPOSIT) { bNode *node; for (node = ntree->nodes.first; node; node = node->next) { @@ -1292,7 +1292,7 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main) { bScreen *sc; - for (sc = main->screen.first; sc; sc = sc->id.next) { + for (sc = bmain->screen.first; sc; sc = sc->id.next) { ScrArea *sa; for (sa = sc->areabase.first; sa; sa = sa->next) { @@ -1314,16 +1314,16 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main) { MovieClip *clip; - for (clip = main->movieclip.first; clip; clip = clip->id.next) { + for (clip = bmain->movieclip.first; clip; clip = clip->id.next) { clip->start_frame = 1; } } } - if (main->versionfile < 263 || (main->versionfile == 263 && main->subversionfile < 11)) { + if (bmain->versionfile < 263 || (bmain->versionfile == 263 && bmain->subversionfile < 11)) { MovieClip *clip; - for (clip = main->movieclip.first; clip; clip = clip->id.next) { + for (clip = bmain->movieclip.first; clip; clip = clip->id.next) { MovieTrackingTrack *track; track = clip->tracking.tracks.first; @@ -1335,8 +1335,8 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main) } } - if (main->versionfile < 263 || (main->versionfile == 263 && main->subversionfile < 13)) { - FOREACH_NODETREE(main, ntree, id) { + if (bmain->versionfile < 263 || (bmain->versionfile == 263 && bmain->subversionfile < 13)) { + FOREACH_NODETREE(bmain, ntree, id) { if (ntree->type == NTREE_COMPOSIT) { bNode *node; for (node = ntree->nodes.first; node; node = node->next) { @@ -1352,10 +1352,10 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main) } FOREACH_NODETREE_END } - if (main->versionfile < 263 || (main->versionfile == 263 && main->subversionfile < 14)) { + if (bmain->versionfile < 263 || (bmain->versionfile == 263 && bmain->subversionfile < 14)) { ParticleSettings *part; - FOREACH_NODETREE(main, ntree, id) { + FOREACH_NODETREE(bmain, ntree, id) { if (ntree->type == NTREE_COMPOSIT) { bNode *node; for (node = ntree->nodes.first; node; node = node->next) { @@ -1371,14 +1371,14 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main) } FOREACH_NODETREE_END /* keep compatibility for dupliobject particle size */ - for (part = main->particle.first; part; part = part->id.next) + for (part = bmain->particle.first; part; part = part->id.next) if (ELEM(part->ren_as, PART_DRAW_OB, PART_DRAW_GR)) if ((part->draw & PART_DRAW_ROTATE_OB) == 0) part->draw |= PART_DRAW_NO_SCALE_OB; } - if (main->versionfile < 263 || (main->versionfile == 263 && main->subversionfile < 17)) { - FOREACH_NODETREE(main, ntree, id) { + if (bmain->versionfile < 263 || (bmain->versionfile == 263 && bmain->subversionfile < 17)) { + FOREACH_NODETREE(bmain, ntree, id) { if (ntree->type == NTREE_COMPOSIT) { bNode *node; for (node = ntree->nodes.first; node; node = node->next) { @@ -1397,10 +1397,10 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main) } FOREACH_NODETREE_END } - if (main->versionfile < 263 || (main->versionfile == 263 && main->subversionfile < 18)) { + if (bmain->versionfile < 263 || (bmain->versionfile == 263 && bmain->subversionfile < 18)) { Scene *scene; - for (scene = main->scene.first; scene; scene = scene->id.next) { + for (scene = bmain->scene.first; scene; scene = scene->id.next) { if (scene->ed) { Sequence *seq; @@ -1434,7 +1434,7 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main) } /* color management pipeline changes compatibility code */ - if (main->versionfile < 263 || (main->versionfile == 263 && main->subversionfile < 19)) { + if (bmain->versionfile < 263 || (bmain->versionfile == 263 && bmain->subversionfile < 19)) { Scene *scene; Image *ima; bool colormanagement_disabled = false; @@ -1442,7 +1442,7 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main) /* make scenes which are not using color management have got None as display device, * so they wouldn't perform linear-to-sRGB conversion on display */ - for (scene = main->scene.first; scene; scene = scene->id.next) { + for (scene = bmain->scene.first; scene; scene = scene->id.next) { if ((scene->r.color_mgt_flag & R_COLOR_MANAGEMENT) == 0) { ColorManagedDisplaySettings *display_settings = &scene->display_settings; @@ -1455,7 +1455,7 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main) } } - for (ima = main->image.first; ima; ima = ima->id.next) { + for (ima = bmain->image.first; ima; ima = ima->id.next) { if (ima->source == IMA_SRC_VIEWER) { ima->flag |= IMA_VIEW_AS_RENDER; } @@ -1474,17 +1474,17 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main) } } - if (main->versionfile < 263 || (main->versionfile == 263 && main->subversionfile < 20)) { + if (bmain->versionfile < 263 || (bmain->versionfile == 263 && bmain->subversionfile < 20)) { Key *key; - for (key = main->key.first; key; key = key->id.next) { + for (key = bmain->key.first; key; key = key->id.next) { blo_do_versions_key_uidgen(key); } } - if (main->versionfile < 263 || (main->versionfile == 263 && main->subversionfile < 21)) { + if (bmain->versionfile < 263 || (bmain->versionfile == 263 && bmain->subversionfile < 21)) { { Mesh *me; - for (me = main->mesh.first; me; me = me->id.next) { + for (me = bmain->mesh.first; me; me = me->id.next) { CustomData_update_typemap(&me->vdata); CustomData_free_layers(&me->vdata, CD_MSTICKY, me->totvert); } @@ -1495,10 +1495,10 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main) * didn't copy animation visualization, which lead to deadlocks on motion * path calculation for proxied armatures, see [#32742] */ - if (main->versionfile < 264) { + if (bmain->versionfile < 264) { Object *ob; - for (ob = main->object.first; ob; ob = ob->id.next) { + for (ob = bmain->object.first; ob; ob = ob->id.next) { if (ob->pose) { if (ob->pose->avs.path_step == 0) { animviz_settings_init(&ob->pose->avs); @@ -1507,8 +1507,8 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main) } } - if (main->versionfile < 264 || (main->versionfile == 264 && main->subversionfile < 1)) { - FOREACH_NODETREE(main, ntree, id) { + if (bmain->versionfile < 264 || (bmain->versionfile == 264 && bmain->subversionfile < 1)) { + FOREACH_NODETREE(bmain, ntree, id) { if (ntree->type == NTREE_SHADER) { bNode *node; for (node = ntree->nodes.first; node; node = node->next) @@ -1518,10 +1518,10 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main) } FOREACH_NODETREE_END } - if (main->versionfile < 264 || (main->versionfile == 264 && main->subversionfile < 2)) { + if (bmain->versionfile < 264 || (bmain->versionfile == 264 && bmain->subversionfile < 2)) { MovieClip *clip; - for (clip = main->movieclip.first; clip; clip = clip->id.next) { + for (clip = bmain->movieclip.first; clip; clip = clip->id.next) { MovieTracking *tracking = &clip->tracking; MovieTrackingObject *tracking_object; @@ -1537,12 +1537,12 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main) } } - if (main->versionfile < 264 || (main->versionfile == 264 && main->subversionfile < 3)) { + if (bmain->versionfile < 264 || (bmain->versionfile == 264 && bmain->subversionfile < 3)) { /* smoke branch */ { Object *ob; - for (ob = main->object.first; ob; ob = ob->id.next) { + for (ob = bmain->object.first; ob; ob = ob->id.next) { ModifierData *md; for (md = ob->modifiers.first; md; md = md->next) { if (md->type == eModifierType_Smoke) { @@ -1581,7 +1581,7 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main) { bScreen *sc; - for (sc = main->screen.first; sc; sc = sc->id.next) { + for (sc = bmain->screen.first; sc; sc = sc->id.next) { ScrArea *sa; for (sa = sc->areabase.first; sa; sa = sa->next) { SpaceLink *sl; @@ -1601,11 +1601,11 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main) } } - if (main->versionfile < 264 || (main->versionfile == 264 && main->subversionfile < 5)) { + if (bmain->versionfile < 264 || (bmain->versionfile == 264 && bmain->subversionfile < 5)) { /* set a unwrapping margin and ABF by default */ Scene *scene; - for (scene = main->scene.first; scene; scene = scene->id.next) { + for (scene = bmain->scene.first; scene; scene = scene->id.next) { if (scene->toolsettings->uvcalc_margin == 0.0f) { scene->toolsettings->uvcalc_margin = 0.001f; scene->toolsettings->unwrapper = 0; @@ -1613,11 +1613,11 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main) } } - if (main->versionfile < 264 || (main->versionfile == 264 && main->subversionfile < 6)) { + if (bmain->versionfile < 264 || (bmain->versionfile == 264 && bmain->subversionfile < 6)) { /* Fix for bug #32982, internal_links list could get corrupted from r51630 onward. * Simply remove bad internal_links lists to avoid NULL pointers. */ - FOREACH_NODETREE(main, ntree, id) { + FOREACH_NODETREE(bmain, ntree, id) { bNode *node; bNodeLink *link, *nextlink; @@ -1632,12 +1632,12 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main) } FOREACH_NODETREE_END } - if (main->versionfile < 264 || (main->versionfile == 264 && main->subversionfile < 7)) { + if (bmain->versionfile < 264 || (bmain->versionfile == 264 && bmain->subversionfile < 7)) { /* convert tiles size from resolution and number of tiles */ { Scene *scene; - for (scene = main->scene.first; scene; scene = scene->id.next) { + for (scene = bmain->scene.first; scene; scene = scene->id.next) { if (scene->r.tilex == 0 || scene->r.tiley == 1) { scene->r.tilex = scene->r.tiley = 64; } @@ -1647,7 +1647,7 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main) /* collision masks */ { Object *ob; - for (ob = main->object.first; ob; ob = ob->id.next) { + for (ob = bmain->object.first; ob; ob = ob->id.next) { if (ob->col_group == 0) { ob->col_group = 0x01; ob->col_mask = 0xff; @@ -1656,10 +1656,10 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main) } } - if (main->versionfile < 264 || (main->versionfile == 264 && main->subversionfile < 7)) { + if (bmain->versionfile < 264 || (bmain->versionfile == 264 && bmain->subversionfile < 7)) { MovieClip *clip; - for (clip = main->movieclip.first; clip; clip = clip->id.next) { + for (clip = bmain->movieclip.first; clip; clip = clip->id.next) { MovieTrackingTrack *track; MovieTrackingObject *object; @@ -1675,9 +1675,9 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main) } } - if (main->versionfile < 265 || (main->versionfile == 265 && main->subversionfile < 3)) { + if (bmain->versionfile < 265 || (bmain->versionfile == 265 && bmain->subversionfile < 3)) { bScreen *sc; - for (sc = main->screen.first; sc; sc = sc->id.next) { + for (sc = bmain->screen.first; sc; sc = sc->id.next) { ScrArea *sa; for (sa = sc->areabase.first; sa; sa = sa->next) { SpaceLink *sl; @@ -1719,11 +1719,11 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main) } } - if (main->versionfile < 265 || (main->versionfile == 265 && main->subversionfile < 5)) { + if (bmain->versionfile < 265 || (bmain->versionfile == 265 && bmain->subversionfile < 5)) { Scene *scene; Tex *tex; - for (scene = main->scene.first; scene; scene = scene->id.next) { + for (scene = bmain->scene.first; scene; scene = scene->id.next) { Sequence *seq; SEQ_BEGIN (scene->ed, seq) @@ -1741,7 +1741,7 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main) scene->r.bake_samples = 256; } - for (Image *image = main->image.first; image; image = image->id.next) { + for (Image *image = bmain->image.first; image; image = image->id.next) { if (image->flag & IMA_DO_PREMUL) { image->alpha_mode = IMA_ALPHA_STRAIGHT; } @@ -1750,7 +1750,7 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main) } } - for (tex = main->tex.first; tex; tex = tex->id.next) { + for (tex = bmain->tex.first; tex; tex = tex->id.next) { if (tex->type == TEX_IMAGE && (tex->imaflag & TEX_USEALPHA) == 0) { Image *image = blo_do_versions_newlibadr(fd, tex->id.lib, tex->ima); @@ -1759,7 +1759,7 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main) } } - FOREACH_NODETREE(main, ntree, id) { + FOREACH_NODETREE(bmain, ntree, id) { if (ntree->type == NTREE_COMPOSIT) { bNode *node; for (node = ntree->nodes.first; node; node = node->next) { @@ -1775,20 +1775,20 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main) } } FOREACH_NODETREE_END } - else if (main->versionfile < 266 || (main->versionfile == 266 && main->subversionfile < 1)) { + else if (bmain->versionfile < 266 || (bmain->versionfile == 266 && bmain->subversionfile < 1)) { /* texture use alpha was removed for 2.66 but added back again for 2.66a, * for compatibility all textures assumed it to be enabled */ Tex *tex; - for (tex = main->tex.first; tex; tex = tex->id.next) + for (tex = bmain->tex.first; tex; tex = tex->id.next) if (tex->type == TEX_IMAGE) tex->imaflag |= TEX_USEALPHA; } - if (main->versionfile < 265 || (main->versionfile == 265 && main->subversionfile < 7)) { + if (bmain->versionfile < 265 || (bmain->versionfile == 265 && bmain->subversionfile < 7)) { Curve *cu; - for (cu = main->curve.first; cu; cu = cu->id.next) { + for (cu = bmain->curve.first; cu; cu = cu->id.next) { if (cu->flag & (CU_FRONT | CU_BACK)) { if ( cu->ext1 != 0.0f || cu->ext2 != 0.0f) { Nurb *nu; @@ -1820,16 +1820,16 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main) } } - if (MAIN_VERSION_OLDER(main, 265, 9)) { + if (MAIN_VERSION_OLDER(bmain, 265, 9)) { Mesh *me; - for (me = main->mesh.first; me; me = me->id.next) { + for (me = bmain->mesh.first; me; me = me->id.next) { BKE_mesh_do_versions_cd_flag_init(me); } } - if (MAIN_VERSION_OLDER(main, 265, 10)) { + if (MAIN_VERSION_OLDER(bmain, 265, 10)) { Brush *br; - for (br = main->brush.first; br; br = br->id.next) { + for (br = bmain->brush.first; br; br = br->id.next) { if (br->ob_mode & OB_MODE_TEXTURE_PAINT) { br->mtex.brush_map_mode = MTEX_MAP_MODE_TILED; } @@ -1837,8 +1837,8 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main) } // add storage for compositor translate nodes when not existing - if (MAIN_VERSION_OLDER(main, 265, 11)) { - FOREACH_NODETREE(main, ntree, id) { + if (MAIN_VERSION_OLDER(bmain, 265, 11)) { + FOREACH_NODETREE(bmain, ntree, id) { if (ntree->type == NTREE_COMPOSIT) { bNode *node; for (node = ntree->nodes.first; node; node = node->next) { @@ -1850,15 +1850,15 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main) } FOREACH_NODETREE_END } - if (MAIN_VERSION_OLDER(main, 266, 2)) { - FOREACH_NODETREE(main, ntree, id) { + if (MAIN_VERSION_OLDER(bmain, 266, 2)) { + FOREACH_NODETREE(bmain, ntree, id) { do_versions_nodetree_customnodes(ntree, ((ID *)ntree == id)); } FOREACH_NODETREE_END } - if (MAIN_VERSION_OLDER(main, 266, 2)) { + if (MAIN_VERSION_OLDER(bmain, 266, 2)) { bScreen *sc; - for (sc = main->screen.first; sc; sc = sc->id.next) { + for (sc = bmain->screen.first; sc; sc = sc->id.next) { ScrArea *sa; for (sa = sc->areabase.first; sa; sa = sa->next) { SpaceLink *sl; @@ -1892,7 +1892,7 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main) /* Set flag for delayed do_versions in lib_verify_nodetree. It needs valid typeinfo pointers ... */ { - FOREACH_NODETREE(main, ntree, id) { + FOREACH_NODETREE(bmain, ntree, id) { /* XXX This should be kept without version check for now! * As long as USE_NODE_COMPAT_CUSTOMNODES is active, files will write links * to tree interface sockets for forward compatibility. These links need to be removed again @@ -1904,22 +1904,22 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main) /* Only add interface nodes once. * In old Blender versions they will be removed automatically due to undefined type */ - if (MAIN_VERSION_OLDER(main, 266, 2)) + if (MAIN_VERSION_OLDER(bmain, 266, 2)) ntree->flag |= NTREE_DO_VERSIONS_CUSTOMNODES_GROUP_CREATE_INTERFACE; } FOREACH_NODETREE_END } - if (MAIN_VERSION_OLDER(main, 266, 3)) { + if (MAIN_VERSION_OLDER(bmain, 266, 3)) { { /* Fix for a very old issue: * Node names were nominally made unique in r24478 (2.50.8), but the do_versions check - * to update existing node names only applied to main->nodetree (i.e. group nodes). + * to update existing node names only applied to bmain->nodetree (i.e. group nodes). * Uniqueness is now required for proper preview mapping, * so do this now to ensure old files don't break. */ bNode *node; - FOREACH_NODETREE(main, ntree, id) { + FOREACH_NODETREE(bmain, ntree, id) { if (id == &ntree->id) continue; /* already fixed for node groups */ @@ -1930,9 +1930,9 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main) } } - if (!MAIN_VERSION_ATLEAST(main, 266, 4)) { + if (!MAIN_VERSION_ATLEAST(bmain, 266, 4)) { Brush *brush; - for (brush = main->brush.first; brush; brush = brush->id.next) { + for (brush = bmain->brush.first; brush; brush = brush->id.next) { BKE_texture_mtex_default(&brush->mask_mtex); if (brush->ob_mode & OB_MODE_TEXTURE_PAINT) { @@ -1941,11 +1941,11 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main) } } - if (!MAIN_VERSION_ATLEAST(main, 266, 6)) { + if (!MAIN_VERSION_ATLEAST(bmain, 266, 6)) { Brush *brush; #define BRUSH_TEXTURE_OVERLAY (1 << 21) - for (brush = main->brush.first; brush; brush = brush->id.next) { + for (brush = bmain->brush.first; brush; brush = brush->id.next) { brush->overlay_flags = 0; if (brush->flag & BRUSH_TEXTURE_OVERLAY) brush->overlay_flags |= (BRUSH_OVERLAY_PRIMARY | BRUSH_OVERLAY_CURSOR); @@ -1953,11 +1953,11 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main) #undef BRUSH_TEXTURE_OVERLAY } - if (main->versionfile < 267) { + if (bmain->versionfile < 267) { //if (!DNA_struct_elem_find(fd->filesdna, "Brush", "int", "stencil_pos")) { Brush *brush; - for (brush = main->brush.first; brush; brush = brush->id.next) { + for (brush = bmain->brush.first; brush; brush = brush->id.next) { if (brush->stencil_dimension[0] == 0) { brush->stencil_dimension[0] = 256; brush->stencil_dimension[1] = 256; @@ -1982,12 +1982,12 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main) } /* default values in Freestyle settings */ - if (main->versionfile < 267) { + if (bmain->versionfile < 267) { Scene *sce; SceneRenderLayer *srl; FreestyleLineStyle *linestyle; - for (sce = main->scene.first; sce; sce = sce->id.next) { + for (sce = bmain->scene.first; sce; sce = sce->id.next) { if (sce->r.line_thickness_mode == 0) { sce->r.line_thickness_mode = R_LINE_THICKNESS_ABSOLUTE; sce->r.unit_line_thickness = 1.0f; @@ -2023,7 +2023,7 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main) } } - for (linestyle = main->linestyle.first; linestyle; linestyle = linestyle->id.next) { + for (linestyle = bmain->linestyle.first; linestyle; linestyle = linestyle->id.next) { #if 1 /* disable the Misc panel for now */ if (linestyle->panel == LS_PANEL_MISC) { @@ -2041,13 +2041,13 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main) } } - if (main->versionfile < 267) { + if (bmain->versionfile < 267) { /* Initialize the active_viewer_key for compositing */ bScreen *screen; Scene *scene; bNodeInstanceKey active_viewer_key = {0}; /* simply pick the first node space and use that for the active viewer key */ - for (screen = main->screen.first; screen; screen = screen->id.next) { + for (screen = bmain->screen.first; screen; screen = screen->id.next) { ScrArea *sa; for (sa = screen->areabase.first; sa; sa = sa->next) { SpaceLink *sl; @@ -2069,17 +2069,17 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main) break; } - for (scene = main->scene.first; scene; scene = scene->id.next) { + for (scene = bmain->scene.first; scene; scene = scene->id.next) { /* NB: scene->nodetree is a local ID block, has been direct_link'ed */ if (scene->nodetree) scene->nodetree->active_viewer_key = active_viewer_key; } } - if (MAIN_VERSION_OLDER(main, 267, 1)) { + if (MAIN_VERSION_OLDER(bmain, 267, 1)) { Object *ob; - for (ob = main->object.first; ob; ob = ob->id.next) { + for (ob = bmain->object.first; ob; ob = ob->id.next) { ModifierData *md; for (md = ob->modifiers.first; md; md = md->next) { if (md->type == eModifierType_Smoke) { @@ -2097,17 +2097,17 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main) } } - if (!MAIN_VERSION_ATLEAST(main, 268, 1)) { + if (!MAIN_VERSION_ATLEAST(bmain, 268, 1)) { Brush *brush; - for (brush = main->brush.first; brush; brush = brush->id.next) { + for (brush = bmain->brush.first; brush; brush = brush->id.next) { brush->spacing = MAX2(1, brush->spacing); } } - if (!MAIN_VERSION_ATLEAST(main, 268, 2)) { + if (!MAIN_VERSION_ATLEAST(bmain, 268, 2)) { Brush *brush; #define BRUSH_FIXED (1 << 6) - for (brush = main->brush.first; brush; brush = brush->id.next) { + for (brush = bmain->brush.first; brush; brush = brush->id.next) { brush->flag &= ~BRUSH_FIXED; if (brush->cursor_overlay_alpha < 2) @@ -2121,11 +2121,11 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main) } - if (!MAIN_VERSION_ATLEAST(main, 268, 4)) { + if (!MAIN_VERSION_ATLEAST(bmain, 268, 4)) { bScreen *sc; Object *ob; - for (ob = main->object.first; ob; ob = ob->id.next) { + for (ob = bmain->object.first; ob; ob = ob->id.next) { bConstraint *con; for (con = ob->constraints.first; con; con = con->next) { if (con->type == CONSTRAINT_TYPE_SHRINKWRAP) { @@ -2138,7 +2138,7 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main) } } - for (ob = main->object.first; ob; ob = ob->id.next) { + for (ob = bmain->object.first; ob; ob = ob->id.next) { ModifierData *md; for (md = ob->modifiers.first; md; md = md->next) { if (md->type == eModifierType_Smoke) { @@ -2157,7 +2157,7 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main) * * We moved this check to the do versions to be sure the value makes any sense. */ - for (sc = main->screen.first; sc; sc = sc->id.next) { + for (sc = bmain->screen.first; sc; sc = sc->id.next) { ScrArea *sa; for (sa = sc->areabase.first; sa; sa = sa->next) { SpaceLink *sl; @@ -2173,12 +2173,12 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main) } } - if (!MAIN_VERSION_ATLEAST(main, 268, 5)) { + if (!MAIN_VERSION_ATLEAST(bmain, 268, 5)) { bScreen *sc; ScrArea *sa; /* add missing (+) expander in node editor */ - for (sc = main->screen.first; sc; sc = sc->id.next) { + for (sc = bmain->screen.first; sc; sc = sc->id.next) { for (sa = sc->areabase.first; sa; sa = sa->next) { ARegion *ar, *arnew; @@ -2207,9 +2207,9 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main) } } - if (!MAIN_VERSION_ATLEAST(main, 269, 1)) { + if (!MAIN_VERSION_ATLEAST(bmain, 269, 1)) { /* Removal of Cycles SSS Compatible falloff */ - FOREACH_NODETREE(main, ntree, id) { + FOREACH_NODETREE(bmain, ntree, id) { if (ntree->type == NTREE_SHADER) { bNode *node; for (node = ntree->nodes.first; node; node = node->next) { @@ -2223,9 +2223,9 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main) } FOREACH_NODETREE_END } - if (!MAIN_VERSION_ATLEAST(main, 269, 2)) { + if (!MAIN_VERSION_ATLEAST(bmain, 269, 2)) { /* Initialize CDL settings for Color Balance nodes */ - FOREACH_NODETREE(main, ntree, id) { + FOREACH_NODETREE(bmain, ntree, id) { if (ntree->type == NTREE_COMPOSIT) { bNode *node; for (node = ntree->nodes.first; node; node = node->next) { @@ -2250,14 +2250,14 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main) } FOREACH_NODETREE_END } - if (!MAIN_VERSION_ATLEAST(main, 269, 3)) { + if (!MAIN_VERSION_ATLEAST(bmain, 269, 3)) { bScreen *sc; ScrArea *sa; SpaceLink *sl; Scene *scene; /* Update files using invalid (outdated) outlinevis Outliner values. */ - for (sc = main->screen.first; sc; sc = sc->id.next) { + for (sc = bmain->screen.first; sc; sc = sc->id.next) { for (sa = sc->areabase.first; sa; sa = sa->next) { for (sl = sa->spacedata.first; sl; sl = sl->next) { if (sl->spacetype == SPACE_OUTLINER) { @@ -2278,7 +2278,7 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main) if (!DNA_struct_elem_find(fd->filesdna, "MovieTrackingTrack", "float", "weight")) { MovieClip *clip; - for (clip = main->movieclip.first; clip; clip = clip->id.next) { + for (clip = bmain->movieclip.first; clip; clip = clip->id.next) { MovieTracking *tracking = &clip->tracking; MovieTrackingObject *tracking_object; for (tracking_object = tracking->objects.first; @@ -2299,7 +2299,7 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main) if (!DNA_struct_elem_find(fd->filesdna, "TriangulateModifierData", "int", "quad_method")) { Object *ob; - for (ob = main->object.first; ob; ob = ob->id.next) { + for (ob = bmain->object.first; ob; ob = ob->id.next) { ModifierData *md; for (md = ob->modifiers.first; md; md = md->next) { if (md->type == eModifierType_Triangulate) { @@ -2317,7 +2317,7 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main) } } - for (scene = main->scene.first; scene; scene = scene->id.next) { + for (scene = bmain->scene.first; scene; scene = scene->id.next) { /* this can now be turned off */ ToolSettings *ts = scene->toolsettings; if (ts->sculpt) @@ -2337,17 +2337,17 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main) } } - if (!MAIN_VERSION_ATLEAST(main, 269, 4)) { + if (!MAIN_VERSION_ATLEAST(bmain, 269, 4)) { /* Internal degrees to radians conversions... */ { Scene *scene; Object *ob; Lamp *lamp; - for (lamp = main->lamp.first; lamp; lamp = lamp->id.next) + for (lamp = bmain->lamp.first; lamp; lamp = lamp->id.next) lamp->spotsize = DEG2RADF(lamp->spotsize); - for (ob = main->object.first; ob; ob = ob->id.next) { + for (ob = bmain->object.first; ob; ob = ob->id.next) { ModifierData *md; for (md = ob->modifiers.first; md; md = md->next) { @@ -2362,7 +2362,7 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main) } } - for (scene = main->scene.first; scene; scene = scene->id.next) { + for (scene = bmain->scene.first; scene; scene = scene->id.next) { Sequence *seq; SEQ_BEGIN (scene->ed, seq) { @@ -2374,7 +2374,7 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main) SEQ_END } - FOREACH_NODETREE(main, ntree, id) { + FOREACH_NODETREE(bmain, ntree, id) { if (ntree->type == NTREE_COMPOSIT) { bNode *node; for (node = ntree->nodes.first; node; node = node->next) { @@ -2397,7 +2397,7 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main) if (!DNA_struct_elem_find(fd->filesdna, "MovieTrackingPlaneTrack", "float", "image_opacity")) { MovieClip *clip; - for (clip = main->movieclip.first; clip; clip = clip->id.next) { + for (clip = bmain->movieclip.first; clip; clip = clip->id.next) { MovieTrackingPlaneTrack *plane_track; for (plane_track = clip->tracking.plane_tracks.first; plane_track; @@ -2409,9 +2409,9 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main) } } - if (!MAIN_VERSION_ATLEAST(main, 269, 7)) { + if (!MAIN_VERSION_ATLEAST(bmain, 269, 7)) { Scene *scene; - for (scene = main->scene.first; scene; scene = scene->id.next) { + for (scene = bmain->scene.first; scene; scene = scene->id.next) { Sculpt *sd = scene->toolsettings->sculpt; if (sd) { @@ -2429,20 +2429,20 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main) } } - if (!MAIN_VERSION_ATLEAST(main, 269, 8)) { + if (!MAIN_VERSION_ATLEAST(bmain, 269, 8)) { Curve *cu; - for (cu = main->curve.first; cu; cu = cu->id.next) { + for (cu = bmain->curve.first; cu; cu = cu->id.next) { if (cu->str) { cu->len_wchar = BLI_strlen_utf8(cu->str); } } } - if (!MAIN_VERSION_ATLEAST(main, 269, 9)) { + if (!MAIN_VERSION_ATLEAST(bmain, 269, 9)) { Object *ob; - for (ob = main->object.first; ob; ob = ob->id.next) { + for (ob = bmain->object.first; ob; ob = ob->id.next) { ModifierData *md; for (md = ob->modifiers.first; md; md = md->next) { if (md->type == eModifierType_Build) { @@ -2455,10 +2455,10 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main) } } - if (!MAIN_VERSION_ATLEAST(main, 269, 11)) { + if (!MAIN_VERSION_ATLEAST(bmain, 269, 11)) { bScreen *sc; - for (sc = main->screen.first; sc; sc = sc->id.next) { + for (sc = bmain->screen.first; sc; sc = sc->id.next) { ScrArea *sa; for (sa = sc->areabase.first; sa; sa = sa->next) { SpaceLink *space_link; diff --git a/source/blender/blenloader/intern/versioning_270.c b/source/blender/blenloader/intern/versioning_270.c index ee589e511c6..ba714405cc0 100644 --- a/source/blender/blenloader/intern/versioning_270.c +++ b/source/blender/blenloader/intern/versioning_270.c @@ -346,14 +346,14 @@ static void do_version_bbone_easing_fcurve_fix(ID *UNUSED(id), FCurve *fcu, void } -void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) +void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *bmain) { - if (!MAIN_VERSION_ATLEAST(main, 270, 0)) { + if (!MAIN_VERSION_ATLEAST(bmain, 270, 0)) { if (!DNA_struct_elem_find(fd->filesdna, "BevelModifierData", "float", "profile")) { Object *ob; - for (ob = main->object.first; ob; ob = ob->id.next) { + for (ob = bmain->object.first; ob; ob = ob->id.next) { ModifierData *md; for (md = ob->modifiers.first; md; md = md->next) { if (md->type == eModifierType_Bevel) { @@ -366,7 +366,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) } /* nodes don't use fixed node->id any more, clean up */ - FOREACH_NODETREE(main, ntree, id) { + FOREACH_NODETREE(bmain, ntree, id) { if (ntree->type == NTREE_COMPOSIT) { bNode *node; for (node = ntree->nodes.first; node; node = node->next) { @@ -380,7 +380,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) { bScreen *screen; - for (screen = main->screen.first; screen; screen = screen->id.next) { + for (screen = bmain->screen.first; screen; screen = screen->id.next) { ScrArea *area; for (area = screen->areabase.first; area; area = area->next) { SpaceLink *space_link; @@ -398,17 +398,17 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) if (!DNA_struct_elem_find(fd->filesdna, "MovieTrackingSettings", "float", "default_weight")) { MovieClip *clip; - for (clip = main->movieclip.first; clip; clip = clip->id.next) { + for (clip = bmain->movieclip.first; clip; clip = clip->id.next) { clip->tracking.settings.default_weight = 1.0f; } } } - if (!MAIN_VERSION_ATLEAST(main, 270, 1)) { + if (!MAIN_VERSION_ATLEAST(bmain, 270, 1)) { Object *ob; /* Update Transform constraint (another deg -> rad stuff). */ - for (ob = main->object.first; ob; ob = ob->id.next) { + for (ob = bmain->object.first; ob; ob = ob->id.next) { do_version_constraints_radians_degrees_270_1(&ob->constraints); if (ob->pose) { @@ -421,32 +421,32 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) } } - if (!MAIN_VERSION_ATLEAST(main, 270, 2)) { + if (!MAIN_VERSION_ATLEAST(bmain, 270, 2)) { Mesh *me; /* Mesh smoothresh deg->rad. */ - for (me = main->mesh.first; me; me = me->id.next) { + for (me = bmain->mesh.first; me; me = me->id.next) { me->smoothresh = DEG2RADF(me->smoothresh); } } - if (!MAIN_VERSION_ATLEAST(main, 270, 3)) { + if (!MAIN_VERSION_ATLEAST(bmain, 270, 3)) { FreestyleLineStyle *linestyle; - for (linestyle = main->linestyle.first; linestyle; linestyle = linestyle->id.next) { + for (linestyle = bmain->linestyle.first; linestyle; linestyle = linestyle->id.next) { linestyle->flag |= LS_NO_SORTING; linestyle->sort_key = LS_SORT_KEY_DISTANCE_FROM_CAMERA; linestyle->integration_type = LS_INTEGRATION_MEAN; } } - if (!MAIN_VERSION_ATLEAST(main, 270, 4)) { + if (!MAIN_VERSION_ATLEAST(bmain, 270, 4)) { /* ui_previews were not handled correctly when copying areas, leading to corrupted files (see T39847). * This will always reset situation to a valid state. */ bScreen *sc; - for (sc = main->screen.first; sc; sc = sc->id.next) { + for (sc = bmain->screen.first; sc; sc = sc->id.next) { ScrArea *sa; for (sa = sc->areabase.first; sa; sa = sa->next) { SpaceLink *sl; @@ -463,11 +463,11 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) } } - if (!MAIN_VERSION_ATLEAST(main, 270, 5)) { + if (!MAIN_VERSION_ATLEAST(bmain, 270, 5)) { Object *ob; /* Update Transform constraint (again :|). */ - for (ob = main->object.first; ob; ob = ob->id.next) { + for (ob = bmain->object.first; ob; ob = ob->id.next) { do_version_constraints_radians_degrees_270_5(&ob->constraints); if (ob->pose) { @@ -480,11 +480,11 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) } } - if (!MAIN_VERSION_ATLEAST(main, 271, 0)) { + if (!MAIN_VERSION_ATLEAST(bmain, 271, 0)) { if (!DNA_struct_elem_find(fd->filesdna, "RenderData", "BakeData", "bake")) { Scene *sce; - for (sce = main->scene.first; sce; sce = sce->id.next) { + for (sce = bmain->scene.first; sce; sce = sce->id.next) { sce->r.bake.flag = R_BAKE_CLEAR; sce->r.bake.width = 512; sce->r.bake.height = 512; @@ -506,7 +506,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) if (!DNA_struct_elem_find(fd->filesdna, "FreestyleLineStyle", "float", "texstep")) { FreestyleLineStyle *linestyle; - for (linestyle = main->linestyle.first; linestyle; linestyle = linestyle->id.next) { + for (linestyle = bmain->linestyle.first; linestyle; linestyle = linestyle->id.next) { linestyle->flag |= LS_TEXTURE; linestyle->texstep = 1.0; } @@ -514,18 +514,18 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) { Scene *scene; - for (scene = main->scene.first; scene; scene = scene->id.next) { + for (scene = bmain->scene.first; scene; scene = scene->id.next) { int num_layers = BLI_listbase_count(&scene->r.layers); scene->r.actlay = min_ff(scene->r.actlay, num_layers - 1); } } } - if (!MAIN_VERSION_ATLEAST(main, 271, 1)) { + if (!MAIN_VERSION_ATLEAST(bmain, 271, 1)) { if (!DNA_struct_elem_find(fd->filesdna, "Material", "float", "line_col[4]")) { Material *mat; - for (mat = main->mat.first; mat; mat = mat->id.next) { + for (mat = bmain->mat.first; mat; mat = mat->id.next) { mat->line_col[0] = mat->line_col[1] = mat->line_col[2] = 0.0f; mat->line_col[3] = mat->alpha; } @@ -533,22 +533,22 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) if (!DNA_struct_elem_find(fd->filesdna, "RenderData", "int", "preview_start_resolution")) { Scene *scene; - for (scene = main->scene.first; scene; scene = scene->id.next) { + for (scene = bmain->scene.first; scene; scene = scene->id.next) { scene->r.preview_start_resolution = 64; } } } - if (!MAIN_VERSION_ATLEAST(main, 271, 3)) { + if (!MAIN_VERSION_ATLEAST(bmain, 271, 3)) { Brush *br; - for (br = main->brush.first; br; br = br->id.next) { + for (br = bmain->brush.first; br; br = br->id.next) { br->fill_threshold = 0.2f; } if (!DNA_struct_elem_find(fd->filesdna, "BevelModifierData", "int", "mat")) { Object *ob; - for (ob = main->object.first; ob; ob = ob->id.next) { + for (ob = bmain->object.first; ob; ob = ob->id.next) { ModifierData *md; for (md = ob->modifiers.first; md; md = md->next) { @@ -561,9 +561,9 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) } } - if (!MAIN_VERSION_ATLEAST(main, 271, 6)) { + if (!MAIN_VERSION_ATLEAST(bmain, 271, 6)) { Object *ob; - for (ob = main->object.first; ob; ob = ob->id.next) { + for (ob = bmain->object.first; ob; ob = ob->id.next) { ModifierData *md; for (md = ob->modifiers.first; md; md = md->next) { @@ -577,27 +577,27 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) } } - if (!MAIN_VERSION_ATLEAST(main, 272, 0)) { + if (!MAIN_VERSION_ATLEAST(bmain, 272, 0)) { if (!DNA_struct_elem_find(fd->filesdna, "RenderData", "int", "preview_start_resolution")) { Scene *scene; - for (scene = main->scene.first; scene; scene = scene->id.next) { + for (scene = bmain->scene.first; scene; scene = scene->id.next) { scene->r.preview_start_resolution = 64; } } } - if (!MAIN_VERSION_ATLEAST(main, 272, 1)) { + if (!MAIN_VERSION_ATLEAST(bmain, 272, 1)) { Brush *br; - for (br = main->brush.first; br; br = br->id.next) { + for (br = bmain->brush.first; br; br = br->id.next) { if ((br->ob_mode & OB_MODE_SCULPT) && ELEM(br->sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_SNAKE_HOOK)) br->alpha = 1.0f; } } - if (!MAIN_VERSION_ATLEAST(main, 272, 2)) { + if (!MAIN_VERSION_ATLEAST(bmain, 272, 2)) { if (!DNA_struct_elem_find(fd->filesdna, "Image", "float", "gen_color")) { Image *image; - for (image = main->image.first; image != NULL; image = image->id.next) { + for (image = bmain->image.first; image != NULL; image = image->id.next) { image->gen_color[3] = 1.0f; } } @@ -606,7 +606,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) Object *ob; /* Update Transform constraint (again :|). */ - for (ob = main->object.first; ob; ob = ob->id.next) { + for (ob = bmain->object.first; ob; ob = ob->id.next) { do_version_constraints_stretch_to_limits(&ob->constraints); if (ob->pose) { @@ -620,13 +620,13 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) } } - if (!MAIN_VERSION_ATLEAST(main, 273, 1)) { + if (!MAIN_VERSION_ATLEAST(bmain, 273, 1)) { #define BRUSH_RAKE (1 << 7) #define BRUSH_RANDOM_ROTATION (1 << 25) Brush *br; - for (br = main->brush.first; br; br = br->id.next) { + for (br = bmain->brush.first; br; br = br->id.next) { if (br->flag & BRUSH_RAKE) { br->mtex.brush_angle_mode |= MTEX_ANGLE_RAKE; br->mask_mtex.brush_angle_mode |= MTEX_ANGLE_RAKE; @@ -644,11 +644,11 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) #undef BRUSH_RANDOM_ROTATION /* Customizable Safe Areas */ - if (!MAIN_VERSION_ATLEAST(main, 273, 2)) { + if (!MAIN_VERSION_ATLEAST(bmain, 273, 2)) { if (!DNA_struct_elem_find(fd->filesdna, "Scene", "DisplaySafeAreas", "safe_areas")) { Scene *scene; - for (scene = main->scene.first; scene; scene = scene->id.next) { + for (scene = bmain->scene.first; scene; scene = scene->id.next) { copy_v2_fl2(scene->safe_areas.title, 3.5f / 100.0f, 3.5f / 100.0f); copy_v2_fl2(scene->safe_areas.action, 10.0f / 100.0f, 5.0f / 100.0f); copy_v2_fl2(scene->safe_areas.title_center, 17.5f / 100.0f, 5.0f / 100.0f); @@ -657,9 +657,9 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) } } - if (!MAIN_VERSION_ATLEAST(main, 273, 3)) { + if (!MAIN_VERSION_ATLEAST(bmain, 273, 3)) { ParticleSettings *part; - for (part = main->particle.first; part; part = part->id.next) { + for (part = bmain->particle.first; part; part = part->id.next) { if (part->clumpcurve) part->child_flag |= PART_CHILD_USE_CLUMP_CURVE; if (part->roughcurve) @@ -667,11 +667,11 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) } } - if (!MAIN_VERSION_ATLEAST(main, 273, 6)) { + if (!MAIN_VERSION_ATLEAST(bmain, 273, 6)) { if (!DNA_struct_elem_find(fd->filesdna, "ClothSimSettings", "float", "bending_damping")) { Object *ob; ModifierData *md; - for (ob = main->object.first; ob; ob = ob->id.next) { + for (ob = bmain->object.first; ob; ob = ob->id.next) { for (md = ob->modifiers.first; md; md = md->next) { if (md->type == eModifierType_Cloth) { ClothModifierData *clmd = (ClothModifierData *)md; @@ -689,21 +689,21 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) if (!DNA_struct_elem_find(fd->filesdna, "ParticleSettings", "float", "clump_noise_size")) { ParticleSettings *part; - for (part = main->particle.first; part; part = part->id.next) { + for (part = bmain->particle.first; part; part = part->id.next) { part->clump_noise_size = 1.0f; } } if (!DNA_struct_elem_find(fd->filesdna, "ParticleSettings", "int", "kink_extra_steps")) { ParticleSettings *part; - for (part = main->particle.first; part; part = part->id.next) { + for (part = bmain->particle.first; part; part = part->id.next) { part->kink_extra_steps = 4; } } if (!DNA_struct_elem_find(fd->filesdna, "MTex", "float", "kinkampfac")) { ParticleSettings *part; - for (part = main->particle.first; part; part = part->id.next) { + for (part = bmain->particle.first; part; part = part->id.next) { int a; for (a = 0; a < MAX_MTEX; a++) { MTex *mtex = part->mtex[a]; @@ -717,7 +717,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) if (!DNA_struct_elem_find(fd->filesdna, "HookModifierData", "char", "flag")) { Object *ob; - for (ob = main->object.first; ob; ob = ob->id.next) { + for (ob = bmain->object.first; ob; ob = ob->id.next) { ModifierData *md; for (md = ob->modifiers.first; md; md = md->next) { if (md->type == eModifierType_Hook) { @@ -729,7 +729,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) } if (!DNA_struct_elem_find(fd->filesdna, "NodePlaneTrackDeformData", "char", "flag")) { - FOREACH_NODETREE(main, ntree, id) { + FOREACH_NODETREE(bmain, ntree, id) { if (ntree->type == NTREE_COMPOSIT) { bNode *node; for (node = ntree->nodes.first; node; node = node->next) { @@ -747,7 +747,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) if (!DNA_struct_elem_find(fd->filesdna, "Camera", "GPUDOFSettings", "gpu_dof")) { Camera *ca; - for (ca = main->camera.first; ca; ca = ca->id.next) { + for (ca = bmain->camera.first; ca; ca = ca->id.next) { ca->gpu_dof.fstop = 128.0f; ca->gpu_dof.focal_length = 1.0f; ca->gpu_dof.focus_distance = 1.0f; @@ -756,9 +756,9 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) } } - if (!MAIN_VERSION_ATLEAST(main, 273, 8)) { + if (!MAIN_VERSION_ATLEAST(bmain, 273, 8)) { Object *ob; - for (ob = main->object.first; ob != NULL; ob = ob->id.next) { + for (ob = bmain->object.first; ob != NULL; ob = ob->id.next) { ModifierData *md; for (md = ob->modifiers.last; md != NULL; md = md->prev) { if (modifier_unique_name(&ob->modifiers, md)) { @@ -770,14 +770,14 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) } } - if (!MAIN_VERSION_ATLEAST(main, 273, 9)) { + if (!MAIN_VERSION_ATLEAST(bmain, 273, 9)) { bScreen *scr; ScrArea *sa; SpaceLink *sl; ARegion *ar; /* Make sure sequencer preview area limits zoom */ - for (scr = main->screen.first; scr; scr = scr->id.next) { + for (scr = bmain->screen.first; scr; scr = scr->id.next) { for (sa = scr->areabase.first; sa; sa = sa->next) { for (sl = sa->spacedata.first; sl; sl = sl->next) { if (sl->spacetype == SPACE_SEQ) { @@ -795,12 +795,12 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) } } - if (!MAIN_VERSION_ATLEAST(main, 274, 1)) { + if (!MAIN_VERSION_ATLEAST(bmain, 274, 1)) { /* particle systems need to be forced to redistribute for jitter mode fix */ { Object *ob; ParticleSystem *psys; - for (ob = main->object.first; ob; ob = ob->id.next) { + for (ob = bmain->object.first; ob; ob = ob->id.next) { for (psys = ob->particlesystem.first; psys; psys = psys->next) { if ((psys->pointcache->flag & PTCACHE_BAKED) == 0) { psys->recalc |= PSYS_RECALC_RESET; @@ -812,7 +812,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) /* hysteresis setted to 10% but not actived */ if (!DNA_struct_elem_find(fd->filesdna, "LodLevel", "int", "obhysteresis")) { Object *ob; - for (ob = main->object.first; ob; ob = ob->id.next) { + for (ob = bmain->object.first; ob; ob = ob->id.next) { LodLevel *level; for (level = ob->lodlevels.first; level; level = level->next) { level->obhysteresis = 10; @@ -821,7 +821,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) } } - if (!MAIN_VERSION_ATLEAST(main, 274, 4)) { + if (!MAIN_VERSION_ATLEAST(bmain, 274, 4)) { SceneRenderView *srv; wmWindowManager *wm; bScreen *screen; @@ -830,7 +830,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) Camera *cam; Image *ima; - for (scene = main->scene.first; scene; scene = scene->id.next) { + for (scene = bmain->scene.first; scene; scene = scene->id.next) { Sequence *seq; BKE_scene_add_render_view(scene, STEREO_LEFT_NAME); @@ -860,7 +860,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) SEQ_END } - for (screen = main->screen.first; screen; screen = screen->id.next) { + for (screen = bmain->screen.first; screen; screen = screen->id.next) { ScrArea *sa; for (sa = screen->areabase.first; sa; sa = sa->next) { SpaceLink *sl; @@ -887,12 +887,12 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) } } - for (cam = main->camera.first; cam; cam = cam->id.next) { + for (cam = bmain->camera.first; cam; cam = cam->id.next) { cam->stereo.interocular_distance = 0.065f; cam->stereo.convergence_distance = 30.0f * 0.065f; } - for (ima = main->image.first; ima; ima = ima->id.next) { + for (ima = bmain->image.first; ima; ima = ima->id.next) { ima->stereo3d_format = MEM_callocN(sizeof(Stereo3dFormat), "Image Stereo 3d Format"); if (ima->packedfile) { @@ -905,18 +905,18 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) } } - for (wm = main->wm.first; wm; wm = wm->id.next) { + for (wm = bmain->wm.first; wm; wm = wm->id.next) { for (win = wm->windows.first; win; win = win->next) { win->stereo3d_format = MEM_callocN(sizeof(Stereo3dFormat), "Stereo Display 3d Format"); } } } - if (!MAIN_VERSION_ATLEAST(main, 274, 6)) { + if (!MAIN_VERSION_ATLEAST(bmain, 274, 6)) { bScreen *screen; if (!DNA_struct_elem_find(fd->filesdna, "FileSelectParams", "int", "thumbnail_size")) { - for (screen = main->screen.first; screen; screen = screen->id.next) { + for (screen = bmain->screen.first; screen; screen = screen->id.next) { ScrArea *sa; for (sa = screen->areabase.first; sa; sa = sa->next) { @@ -937,7 +937,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) if (!DNA_struct_elem_find(fd->filesdna, "RenderData", "short", "simplify_subsurf_render")) { Scene *scene; - for (scene = main->scene.first; scene != NULL; scene = scene->id.next) { + for (scene = bmain->scene.first; scene != NULL; scene = scene->id.next) { scene->r.simplify_subsurf_render = scene->r.simplify_subsurf; scene->r.simplify_particles_render = scene->r.simplify_particles; } @@ -946,7 +946,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) if (!DNA_struct_elem_find(fd->filesdna, "DecimateModifierData", "float", "defgrp_factor")) { Object *ob; - for (ob = main->object.first; ob; ob = ob->id.next) { + for (ob = bmain->object.first; ob; ob = ob->id.next) { ModifierData *md; for (md = ob->modifiers.first; md; md = md->next) { if (md->type == eModifierType_Decimate) { @@ -958,20 +958,20 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) } } - if (!MAIN_VERSION_ATLEAST(main, 275, 3)) { + if (!MAIN_VERSION_ATLEAST(bmain, 275, 3)) { Brush *br; #define BRUSH_TORUS (1 << 1) - for (br = main->brush.first; br; br = br->id.next) { + for (br = bmain->brush.first; br; br = br->id.next) { br->flag &= ~BRUSH_TORUS; } #undef BRUSH_TORUS } - if (!MAIN_VERSION_ATLEAST(main, 276, 2)) { + if (!MAIN_VERSION_ATLEAST(bmain, 276, 2)) { if (!DNA_struct_elem_find(fd->filesdna, "bPoseChannel", "float", "custom_scale")) { Object *ob; - for (ob = main->object.first; ob; ob = ob->id.next) { + for (ob = bmain->object.first; ob; ob = ob->id.next) { if (ob->pose) { bPoseChannel *pchan; for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { @@ -984,7 +984,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) { bScreen *screen; #define RV3D_VIEW_PERSPORTHO 7 - for (screen = main->screen.first; screen; screen = screen->id.next) { + for (screen = bmain->screen.first; screen; screen = screen->id.next) { ScrArea *sa; for (sa = screen->areabase.first; sa; sa = sa->next) { SpaceLink *sl; @@ -1013,7 +1013,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) { Lamp *lamp; #define LA_YF_PHOTON 5 - for (lamp = main->lamp.first; lamp; lamp = lamp->id.next) { + for (lamp = bmain->lamp.first; lamp; lamp = lamp->id.next) { if (lamp->type == LA_YF_PHOTON) { lamp->type = LA_LOCAL; } @@ -1022,10 +1022,10 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) } } - if (!MAIN_VERSION_ATLEAST(main, 276, 3)) { + if (!MAIN_VERSION_ATLEAST(bmain, 276, 3)) { if (!DNA_struct_elem_find(fd->filesdna, "RenderData", "CurveMapping", "mblur_shutter_curve")) { Scene *scene; - for (scene = main->scene.first; scene != NULL; scene = scene->id.next) { + for (scene = bmain->scene.first; scene != NULL; scene = scene->id.next) { CurveMapping *curve_mapping = &scene->r.mblur_shutter_curve; curvemapping_set_defaults(curve_mapping, 1, 0.0f, 0.0f, 1.0f, 1.0f); curvemapping_initialize(curve_mapping); @@ -1037,8 +1037,8 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) } } - if (!MAIN_VERSION_ATLEAST(main, 276, 4)) { - for (Scene *scene = main->scene.first; scene; scene = scene->id.next) { + if (!MAIN_VERSION_ATLEAST(bmain, 276, 4)) { + for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) { ToolSettings *ts = scene->toolsettings; if (ts->gp_sculpt.brush[0].size == 0) { @@ -1113,7 +1113,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) } } - for (bGPdata *gpd = main->gpencil.first; gpd; gpd = gpd->id.next) { + for (bGPdata *gpd = bmain->gpencil.first; gpd; gpd = gpd->id.next) { bool enabled = false; /* Ensure that the datablock's onionskinning toggle flag @@ -1131,13 +1131,13 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) gpd->flag &= ~GP_DATA_SHOW_ONIONSKINS; } } - if (!MAIN_VERSION_ATLEAST(main, 276, 5)) { + if (!MAIN_VERSION_ATLEAST(bmain, 276, 5)) { ListBase *lbarray[MAX_LIBARRAY]; int a; /* Important to clear all non-persistent flags from older versions here, otherwise they could collide * with any new persistent flag we may add in the future. */ - a = set_listbasepointers(main, lbarray); + a = set_listbasepointers(bmain, lbarray); while (a--) { for (ID *id = lbarray[a]->first; id; id = id->next) { id->flag &= LIB_FAKEUSER; @@ -1145,15 +1145,15 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) } } - if (!MAIN_VERSION_ATLEAST(main, 276, 7)) { + if (!MAIN_VERSION_ATLEAST(bmain, 276, 7)) { Scene *scene; - for (scene = main->scene.first; scene != NULL; scene = scene->id.next) { + for (scene = bmain->scene.first; scene != NULL; scene = scene->id.next) { scene->r.bake.pass_filter = R_BAKE_PASS_FILTER_ALL; } } - if (!MAIN_VERSION_ATLEAST(main, 277, 1)) { - for (Scene *scene = main->scene.first; scene; scene = scene->id.next) { + if (!MAIN_VERSION_ATLEAST(bmain, 277, 1)) { + for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) { ParticleEditSettings *pset = &scene->toolsettings->particle; for (int a = 0; a < ARRAY_SIZE(pset->brush); a++) { if (pset->brush[a].strength > 1.0f) { @@ -1162,7 +1162,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) } } - for (bScreen *screen = main->screen.first; screen; screen = screen->id.next) { + for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) { for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) { for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) { ListBase *regionbase = (sl == sa->spacedata.first) ? &sa->regionbase : &sl->regionbase; @@ -1195,7 +1195,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) } } - for (Scene *scene = main->scene.first; scene; scene = scene->id.next) { + for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) { CurvePaintSettings *cps = &scene->toolsettings->curve_paint_settings; if (cps->error_threshold == 0) { cps->curve_type = CU_BEZIER; @@ -1206,7 +1206,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) } } - for (Scene *scene = main->scene.first; scene; scene = scene->id.next) { + for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) { Sequence *seq; SEQ_BEGIN (scene->ed, seq) @@ -1230,7 +1230,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) } /* Adding "Properties" region to DopeSheet */ - for (bScreen *screen = main->screen.first; screen; screen = screen->id.next) { + for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) { for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) { /* handle pushed-back space data first */ for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) { @@ -1248,14 +1248,14 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) } } - if (!MAIN_VERSION_ATLEAST(main, 277, 2)) { + if (!MAIN_VERSION_ATLEAST(bmain, 277, 2)) { if (!DNA_struct_elem_find(fd->filesdna, "Bone", "float", "scaleIn")) { - for (bArmature *arm = main->armature.first; arm; arm = arm->id.next) { + for (bArmature *arm = bmain->armature.first; arm; arm = arm->id.next) { do_version_bones_super_bbone(&arm->bonebase); } } if (!DNA_struct_elem_find(fd->filesdna, "bPoseChannel", "float", "scaleIn")) { - for (Object *ob = main->object.first; ob; ob = ob->id.next) { + for (Object *ob = bmain->object.first; ob; ob = ob->id.next) { if (ob->pose) { for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { /* see do_version_bones_super_bbone()... */ @@ -1275,7 +1275,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) } } - for (Camera *camera = main->camera.first; camera != NULL; camera = camera->id.next) { + for (Camera *camera = bmain->camera.first; camera != NULL; camera = camera->id.next) { if (camera->stereo.pole_merge_angle_from == 0.0f && camera->stereo.pole_merge_angle_to == 0.0f) { @@ -1287,7 +1287,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) if (!DNA_struct_elem_find(fd->filesdna, "NormalEditModifierData", "float", "mix_limit")) { Object *ob; - for (ob = main->object.first; ob; ob = ob->id.next) { + for (ob = bmain->object.first; ob; ob = ob->id.next) { ModifierData *md; for (md = ob->modifiers.first; md; md = md->next) { if (md->type == eModifierType_NormalEdit) { @@ -1300,7 +1300,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) if (!DNA_struct_elem_find(fd->filesdna, "BooleanModifierData", "float", "double_threshold")) { Object *ob; - for (ob = main->object.first; ob; ob = ob->id.next) { + for (ob = bmain->object.first; ob; ob = ob->id.next) { ModifierData *md; for (md = ob->modifiers.first; md; md = md->next) { if (md->type == eModifierType_Boolean) { @@ -1311,7 +1311,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) } } - for (Brush *br = main->brush.first; br; br = br->id.next) { + for (Brush *br = bmain->brush.first; br; br = br->id.next) { if (br->sculpt_tool == SCULPT_TOOL_FLATTEN) { br->flag |= BRUSH_ACCUMULATE; } @@ -1320,7 +1320,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) if (!DNA_struct_elem_find(fd->filesdna, "ClothSimSettings", "float", "time_scale")) { Object *ob; ModifierData *md; - for (ob = main->object.first; ob; ob = ob->id.next) { + for (ob = bmain->object.first; ob; ob = ob->id.next) { for (md = ob->modifiers.first; md; md = md->next) { if (md->type == eModifierType_Cloth) { ClothModifierData *clmd = (ClothModifierData *)md; @@ -1337,10 +1337,10 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) } } - if (!MAIN_VERSION_ATLEAST(main, 277, 3)) { + if (!MAIN_VERSION_ATLEAST(bmain, 277, 3)) { /* ------- init of grease pencil initialization --------------- */ if (!DNA_struct_elem_find(fd->filesdna, "bGPDstroke", "bGPDpalettecolor", "*palcolor")) { - for (Scene *scene = main->scene.first; scene; scene = scene->id.next) { + for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) { ToolSettings *ts = scene->toolsettings; /* initialize use position for sculpt brushes */ ts->gp_sculpt.flag |= GP_BRUSHEDIT_FLAG_APPLY_POSITION; @@ -1359,8 +1359,8 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) } } /* create a default grease pencil drawing brushes set */ - if (!BLI_listbase_is_empty(&main->gpencil)) { - for (Scene *scene = main->scene.first; scene; scene = scene->id.next) { + if (!BLI_listbase_is_empty(&bmain->gpencil)) { + for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) { ToolSettings *ts = scene->toolsettings; if (BLI_listbase_is_empty(&ts->gp_brushes)) { BKE_gpencil_brush_init_presets(ts); @@ -1370,7 +1370,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) /* Convert Grease Pencil to new palettes/brushes * Loop all strokes and create the palette and all colors */ - for (bGPdata *gpd = main->gpencil.first; gpd; gpd = gpd->id.next) { + for (bGPdata *gpd = bmain->gpencil.first; gpd; gpd = gpd->id.next) { if (BLI_listbase_is_empty(&gpd->palettes)) { /* create palette */ bGPDpalette *palette = BKE_gpencil_palette_addnew(gpd, "GP_Palette", true); @@ -1423,10 +1423,10 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) /* ------- end of grease pencil initialization --------------- */ } - if (!MAIN_VERSION_ATLEAST(main, 278, 0)) { + if (!MAIN_VERSION_ATLEAST(bmain, 278, 0)) { if (!DNA_struct_elem_find(fd->filesdna, "MovieTrackingTrack", "float", "weight_stab")) { MovieClip *clip; - for (clip = main->movieclip.first; clip; clip = clip->id.next) { + for (clip = bmain->movieclip.first; clip; clip = clip->id.next) { MovieTracking *tracking = &clip->tracking; MovieTrackingObject *tracking_object; for (tracking_object = tracking->objects.first; @@ -1447,7 +1447,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) if (!DNA_struct_elem_find(fd->filesdna, "MovieTrackingStabilization", "int", "tot_rot_track")) { MovieClip *clip; - for (clip = main->movieclip.first; clip != NULL; clip = clip->id.next) { + for (clip = bmain->movieclip.first; clip != NULL; clip = clip->id.next) { if (clip->tracking.stabilization.rot_track) { migrate_single_rot_stabilization_track_settings(&clip->tracking.stabilization); } @@ -1467,15 +1467,15 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) } } } - if (!MAIN_VERSION_ATLEAST(main, 278, 2)) { + if (!MAIN_VERSION_ATLEAST(bmain, 278, 2)) { if (!DNA_struct_elem_find(fd->filesdna, "FFMpegCodecData", "int", "ffmpeg_preset")) { - for (Scene *scene = main->scene.first; scene; scene = scene->id.next) { + for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) { /* "medium" is the preset FFmpeg uses when no presets are given. */ scene->r.ffcodecdata.ffmpeg_preset = FFM_PRESET_MEDIUM; } } if (!DNA_struct_elem_find(fd->filesdna, "FFMpegCodecData", "int", "constant_rate_factor")) { - for (Scene *scene = main->scene.first; scene; scene = scene->id.next) { + for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) { /* fall back to behaviour from before we introduced CRF for old files */ scene->r.ffcodecdata.constant_rate_factor = FFM_CRF_NONE; } @@ -1485,7 +1485,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) Object *ob; ModifierData *md; - for (ob = main->object.first; ob; ob = ob->id.next) { + for (ob = bmain->object.first; ob; ob = ob->id.next) { for (md = ob->modifiers.first; md; md = md->next) { if (md->type == eModifierType_Smoke) { SmokeModifierData *smd = (SmokeModifierData *)md; @@ -1500,8 +1500,8 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) } } - if (!MAIN_VERSION_ATLEAST(main, 278, 3)) { - for (Scene *scene = main->scene.first; scene != NULL; scene = scene->id.next) { + if (!MAIN_VERSION_ATLEAST(bmain, 278, 3)) { + for (Scene *scene = bmain->scene.first; scene != NULL; scene = scene->id.next) { if (scene->toolsettings != NULL) { ToolSettings *ts = scene->toolsettings; ParticleEditSettings *pset = &ts->particle; @@ -1515,7 +1515,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) if (!DNA_struct_elem_find(fd->filesdna, "RigidBodyCon", "float", "spring_stiffness_ang_x")) { Object *ob; - for (ob = main->object.first; ob; ob = ob->id.next) { + for (ob = bmain->object.first; ob; ob = ob->id.next) { RigidBodyCon *rbc = ob->rigidbody_constraint; if (rbc) { rbc->spring_stiffness_ang_x = 10.0; @@ -1530,7 +1530,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) /* constant detail for sculpting is now a resolution value instead of * a percentage, we reuse old DNA struct member but convert it */ - for (Scene *scene = main->scene.first; scene != NULL; scene = scene->id.next) { + for (Scene *scene = bmain->scene.first; scene != NULL; scene = scene->id.next) { if (scene->toolsettings != NULL) { ToolSettings *ts = scene->toolsettings; if (ts->sculpt && ts->sculpt->constant_detail != 0.0f) { @@ -1540,16 +1540,16 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) } } - if (!MAIN_VERSION_ATLEAST(main, 278, 4)) { + if (!MAIN_VERSION_ATLEAST(bmain, 278, 4)) { const float sqrt_3 = (float)M_SQRT3; - for (Brush *br = main->brush.first; br; br = br->id.next) { + for (Brush *br = bmain->brush.first; br; br = br->id.next) { br->fill_threshold /= sqrt_3; } /* Custom motion paths */ if (!DNA_struct_elem_find(fd->filesdna, "bMotionPath", "int", "line_thickness")) { Object *ob; - for (ob = main->object.first; ob; ob = ob->id.next) { + for (ob = bmain->object.first; ob; ob = ob->id.next) { bMotionPath *mpath; bPoseChannel *pchan; mpath = ob->mpath; @@ -1577,9 +1577,9 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) } } - if (!MAIN_VERSION_ATLEAST(main, 278, 5)) { + if (!MAIN_VERSION_ATLEAST(bmain, 278, 5)) { /* Mask primitive adding code was not initializing correctly id_type of its points' parent. */ - for (Mask *mask = main->mask.first; mask; mask = mask->id.next) { + for (Mask *mask = bmain->mask.first; mask; mask = mask->id.next) { for (MaskLayer *mlayer = mask->masklayers.first; mlayer; mlayer = mlayer->next) { for (MaskSpline *mspline = mlayer->splines.first; mspline; mspline = mspline->next) { int i = 0; @@ -1594,7 +1594,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) /* Fix for T50736, Glare comp node using same var for two different things. */ if (!DNA_struct_elem_find(fd->filesdna, "NodeGlare", "char", "star_45")) { - FOREACH_NODETREE(main, ntree, id) { + FOREACH_NODETREE(bmain, ntree, id) { if (ntree->type == NTREE_COMPOSIT) { ntreeSetTypes(NULL, ntree); for (bNode *node = ntree->nodes.first; node; node = node->next) { @@ -1617,7 +1617,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) } if (!DNA_struct_elem_find(fd->filesdna, "SurfaceDeformModifierData", "float", "mat[4][4]")) { - for (Object *ob = main->object.first; ob; ob = ob->id.next) { + for (Object *ob = bmain->object.first; ob; ob = ob->id.next) { for (ModifierData *md = ob->modifiers.first; md; md = md->next) { if (md->type == eModifierType_SurfaceDeform) { SurfaceDeformModifierData *smd = (SurfaceDeformModifierData *)md; @@ -1627,32 +1627,32 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) } } - FOREACH_NODETREE(main, ntree, id) { + FOREACH_NODETREE(bmain, ntree, id) { if (ntree->type == NTREE_COMPOSIT) { do_versions_compositor_render_passes(ntree); } } FOREACH_NODETREE_END } - if (!MAIN_VERSION_ATLEAST(main, 279, 0)) { - for (Scene *scene = main->scene.first; scene; scene = scene->id.next) { + if (!MAIN_VERSION_ATLEAST(bmain, 279, 0)) { + for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) { if (scene->r.im_format.exr_codec == R_IMF_EXR_CODEC_DWAB) { scene->r.im_format.exr_codec = R_IMF_EXR_CODEC_DWAA; } } /* Fix related to VGroup modifiers creating named defgroup CD layers! See T51520. */ - for (Mesh *me = main->mesh.first; me; me = me->id.next) { + for (Mesh *me = bmain->mesh.first; me; me = me->id.next) { CustomData_set_layer_name(&me->vdata, CD_MDEFORMVERT, 0, ""); } } - if (!MAIN_VERSION_ATLEAST(main, 279, 3)) { + if (!MAIN_VERSION_ATLEAST(bmain, 279, 3)) { if (!DNA_struct_elem_find(fd->filesdna, "SmokeDomainSettings", "float", "clipping")) { Object *ob; ModifierData *md; - for (ob = main->object.first; ob; ob = ob->id.next) { + for (ob = bmain->object.first; ob; ob = ob->id.next) { for (md = ob->modifiers.first; md; md = md->next) { if (md->type == eModifierType_Smoke) { SmokeModifierData *smd = (SmokeModifierData *)md; @@ -1667,7 +1667,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) { /* Fix for invalid state of screen due to bug in older versions. */ - for (bScreen *sc = main->screen.first; sc; sc = sc->id.next) { + for (bScreen *sc = bmain->screen.first; sc; sc = sc->id.next) { for (ScrArea *sa = sc->areabase.first; sa; sa = sa->next) { if (sa->full && sc->state == SCREENNORMAL) { sa->full = NULL; @@ -1676,7 +1676,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) } if (!DNA_struct_elem_find(fd->filesdna, "Brush", "float", "falloff_angle")) { - for (Brush *br = main->brush.first; br; br = br->id.next) { + for (Brush *br = bmain->brush.first; br; br = br->id.next) { br->falloff_angle = DEG2RADF(80); br->flag &= ~( BRUSH_FLAG_DEPRECATED_1 | BRUSH_FLAG_DEPRECATED_2 | @@ -1684,7 +1684,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) BRUSH_FRONTFACE_FALLOFF); } - for (Scene *scene = main->scene.first; scene; scene = scene->id.next) { + for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) { ToolSettings *ts = scene->toolsettings; for (int i = 0; i < 2; i++) { VPaint *vp = i ? ts->vpaint : ts->wpaint; @@ -1699,7 +1699,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) /* Simple deform modifier no longer assumes Z axis (X for bend type). * Must set previous defaults. */ if (!DNA_struct_elem_find(fd->filesdna, "SimpleDeformModifierData", "char", "deform_axis")) { - for (Object *ob = main->object.first; ob; ob = ob->id.next) { + for (Object *ob = bmain->object.first; ob; ob = ob->id.next) { for (ModifierData *md = ob->modifiers.first; md; md = md->next) { if (md->type == eModifierType_SimpleDeform) { SimpleDeformModifierData *smd = (SimpleDeformModifierData *)md; @@ -1709,7 +1709,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) } } - for (Scene *scene = main->scene.first; scene; scene = scene->id.next) { + for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) { int preset = scene->r.ffcodecdata.ffmpeg_preset; if (preset == FFM_PRESET_NONE || preset >= FFM_PRESET_GOOD) { continue; @@ -1727,7 +1727,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) } if (!DNA_struct_elem_find(fd->filesdna, "ParticleInstanceModifierData", "float", "particle_amount")) { - for (Object *ob = main->object.first; ob; ob = ob->id.next) { + for (Object *ob = bmain->object.first; ob; ob = ob->id.next) { for (ModifierData *md = ob->modifiers.first; md; md = md->next) { if (md->type == eModifierType_ParticleInstance) { ParticleInstanceModifierData *pimd = (ParticleInstanceModifierData *)md; @@ -1740,11 +1740,11 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) } } -void do_versions_after_linking_270(Main *main) +void do_versions_after_linking_270(Main *bmain) { /* To be added to next subversion bump! */ - if (!MAIN_VERSION_ATLEAST(main, 279, 0)) { - FOREACH_NODETREE(main, ntree, id) { + if (!MAIN_VERSION_ATLEAST(bmain, 279, 0)) { + FOREACH_NODETREE(bmain, ntree, id) { if (ntree->type == NTREE_COMPOSIT) { ntreeSetTypes(NULL, ntree); for (bNode *node = ntree->nodes.first; node; node = node->next) { @@ -1756,9 +1756,9 @@ void do_versions_after_linking_270(Main *main) } FOREACH_NODETREE_END } - if (!MAIN_VERSION_ATLEAST(main, 279, 2)) { + if (!MAIN_VERSION_ATLEAST(bmain, 279, 2)) { /* B-Bones (bbone_in/out -> bbone_easein/out) + Stepped FMod Frame Start/End fix */ /* if (!DNA_struct_elem_find(fd->filesdna, "Bone", "float", "bbone_easein")) */ - BKE_fcurves_main_cb(main, do_version_bbone_easing_fcurve_fix, NULL); + BKE_fcurves_main_cb(bmain, do_version_bbone_easing_fcurve_fix, NULL); } } diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c index 144b3889d30..eb165efb4f9 100644 --- a/source/blender/blenloader/intern/versioning_280.c +++ b/source/blender/blenloader/intern/versioning_280.c @@ -67,6 +67,7 @@ #include "BKE_report.h" #include "BKE_scene.h" #include "BKE_screen.h" +#include "BKE_studiolight.h" #include "BKE_workspace.h" #include "BLO_readfile.h" @@ -96,6 +97,9 @@ static void do_version_workspaces_create_from_screens(Main *bmain) Scene *scene = screen->scene; WorkSpace *workspace; ViewLayer *layer = BLI_findlink(&scene->view_layers, scene->r.actlay); + if (screen->temp) { + continue; + } if (!layer) { layer = BKE_view_layer_default_view(scene); } @@ -671,15 +675,15 @@ static void do_version_layers_to_collections(Main *bmain, Scene *scene) scene->basact = NULL; } -void do_versions_after_linking_280(Main *main) +void do_versions_after_linking_280(Main *bmain) { bool use_collection_compat_28 = true; - if (!MAIN_VERSION_ATLEAST(main, 280, 0)) { + if (!MAIN_VERSION_ATLEAST(bmain, 280, 0)) { use_collection_compat_28 = false; /* Convert group layer visibility flags to hidden nested collection. */ - for (Collection *collection = main->collection.first; collection; collection = collection->id.next) { + for (Collection *collection = bmain->collection.first; collection; collection = collection->id.next) { /* Add fake user for all existing groups. */ id_fake_user_set(&collection->id); @@ -694,25 +698,25 @@ void do_versions_after_linking_280(Main *main) if (!(ob->lay & collection->layer)) { if (collection_hidden == NULL) { - collection_hidden = BKE_collection_add(main, collection, "Hidden"); + collection_hidden = BKE_collection_add(bmain, collection, "Hidden"); collection_hidden->id.lib = collection->id.lib; collection_hidden->flag |= COLLECTION_RESTRICT_VIEW | COLLECTION_RESTRICT_RENDER; } - BKE_collection_object_add(main, collection_hidden, ob); - BKE_collection_object_remove(main, collection, ob, true); + BKE_collection_object_add(bmain, collection_hidden, ob); + BKE_collection_object_remove(bmain, collection, ob, true); } } } /* Convert layers to collections. */ - for (Scene *scene = main->scene.first; scene; scene = scene->id.next) { - do_version_layers_to_collections(main, scene); + for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) { + do_version_layers_to_collections(bmain, scene); } } - if (!MAIN_VERSION_ATLEAST(main, 280, 0)) { - for (bScreen *screen = main->screen.first; screen; screen = screen->id.next) { + if (!MAIN_VERSION_ATLEAST(bmain, 280, 0)) { + for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) { /* same render-layer as do_version_workspaces_after_lib_link will activate, * so same layer as BKE_view_layer_from_workspace_get would return */ ViewLayer *layer = screen->scene->view_layers.first; @@ -746,14 +750,14 @@ void do_versions_after_linking_280(Main *main) } /* New workspace design */ - if (!MAIN_VERSION_ATLEAST(main, 280, 1)) { - do_version_workspaces_after_lib_link(main); + if (!MAIN_VERSION_ATLEAST(bmain, 280, 1)) { + do_version_workspaces_after_lib_link(bmain); } - if (!MAIN_VERSION_ATLEAST(main, 280, 2)) { + if (!MAIN_VERSION_ATLEAST(bmain, 280, 2)) { /* Cleanup any remaining SceneRenderLayer data for files that were created * with Blender 2.8 before the SceneRenderLayer > RenderLayer refactor. */ - for (Scene *scene = main->scene.first; scene; scene = scene->id.next) { + for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) { for (SceneRenderLayer *srl = scene->r.layers.first; srl; srl = srl->next) { if (srl->prop) { IDP_FreeProperty(srl->prop); @@ -765,10 +769,10 @@ void do_versions_after_linking_280(Main *main) } } - if (!MAIN_VERSION_ATLEAST(main, 280, 3)) { + if (!MAIN_VERSION_ATLEAST(bmain, 280, 3)) { /* Due to several changes to particle RNA and draw code particles from older files may no longer * be visible. Here we correct this by setting a default draw size for those files. */ - for (Object *object = main->object.first; object; object = object->id.next) { + for (Object *object = bmain->object.first; object; object = object->id.next) { for (ParticleSystem *psys = object->particlesystem.first; psys; psys = psys->next) { if (psys->part->draw_size == 0.0f) { psys->part->draw_size = 0.1f; @@ -777,8 +781,8 @@ void do_versions_after_linking_280(Main *main) } } - if (!MAIN_VERSION_ATLEAST(main, 280, 4)) { - for (Object *object = main->object.first; object; object = object->id.next) { + if (!MAIN_VERSION_ATLEAST(bmain, 280, 4)) { + for (Object *object = bmain->object.first; object; object = object->id.next) { #ifndef VERSION_280_SUBVERSION_4 /* If any object already has an initialized value for * duplicator_visibility_flag it means we've already doversioned it. @@ -810,9 +814,9 @@ void do_versions_after_linking_280(Main *main) } /* SpaceTime & SpaceLogic removal/replacing */ - if (!MAIN_VERSION_ATLEAST(main, 280, 9)) { - const wmWindowManager *wm = main->wm.first; - const Scene *scene = main->scene.first; + if (!MAIN_VERSION_ATLEAST(bmain, 280, 9)) { + const wmWindowManager *wm = bmain->wm.first; + const Scene *scene = bmain->scene.first; if (wm != NULL) { /* Action editors need a scene for creation. First, update active @@ -832,7 +836,7 @@ void do_versions_after_linking_280(Main *main) } } if (scene != NULL) { - for (bScreen *screen = main->screen.first; screen; screen = screen->id.next) { + for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) { for (ScrArea *area = screen->areabase.first; area; area = area->next) { if (ELEM(area->butspacetype, SPACE_TIME, SPACE_LOGIC)) { /* Areas that were already handled won't be handled again */ @@ -847,39 +851,39 @@ void do_versions_after_linking_280(Main *main) } #ifdef USE_COLLECTION_COMPAT_28 - if (use_collection_compat_28 && !MAIN_VERSION_ATLEAST(main, 280, 14)) { - for (Collection *group = main->collection.first; group; group = group->id.next) { - do_version_group_collection_to_collection(main, group); + if (use_collection_compat_28 && !MAIN_VERSION_ATLEAST(bmain, 280, 14)) { + for (Collection *group = bmain->collection.first; group; group = group->id.next) { + do_version_group_collection_to_collection(bmain, group); } - for (Scene *scene = main->scene.first; scene; scene = scene->id.next) { - do_version_scene_collection_to_collection(main, scene); + for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) { + do_version_scene_collection_to_collection(bmain, scene); } } #endif } -void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *main) +void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain) { bool use_collection_compat_28 = true; - if (!MAIN_VERSION_ATLEAST(main, 280, 0)) { + if (!MAIN_VERSION_ATLEAST(bmain, 280, 0)) { use_collection_compat_28 = false; - for (Scene *scene = main->scene.first; scene; scene = scene->id.next) { + for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) { scene->r.gauss = 1.5f; } } - if (!MAIN_VERSION_ATLEAST(main, 280, 1)) { + if (!MAIN_VERSION_ATLEAST(bmain, 280, 1)) { if (!DNA_struct_elem_find(fd->filesdna, "Lamp", "float", "bleedexp")) { - for (Lamp *la = main->lamp.first; la; la = la->id.next) { + for (Lamp *la = bmain->lamp.first; la; la = la->id.next) { la->bleedexp = 2.5f; } } if (!DNA_struct_elem_find(fd->filesdna, "GPUDOFSettings", "float", "ratio")) { - for (Camera *ca = main->camera.first; ca; ca = ca->id.next) { + for (Camera *ca = bmain->camera.first; ca; ca = ca->id.next) { ca->gpu_dof.ratio = 1.0f; } } @@ -887,7 +891,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *main) /* MTexPoly now removed. */ if (DNA_struct_find(fd->filesdna, "MTexPoly")) { const int cd_mtexpoly = 15; /* CD_MTEXPOLY, deprecated */ - for (Mesh *me = main->mesh.first; me; me = me->id.next) { + for (Mesh *me = bmain->mesh.first; me; me = me->id.next) { /* If we have UV's, so this file will have MTexPoly layers too! */ if (me->mloopuv != NULL) { CustomData_update_typemap(&me->pdata); @@ -898,9 +902,9 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *main) } } - if (!MAIN_VERSION_ATLEAST(main, 280, 2)) { + if (!MAIN_VERSION_ATLEAST(bmain, 280, 2)) { if (!DNA_struct_elem_find(fd->filesdna, "Lamp", "float", "cascade_max_dist")) { - for (Lamp *la = main->lamp.first; la; la = la->id.next) { + for (Lamp *la = bmain->lamp.first; la; la = la->id.next) { la->cascade_max_dist = 1000.0f; la->cascade_count = 4; la->cascade_exponent = 0.8f; @@ -909,7 +913,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *main) } if (!DNA_struct_elem_find(fd->filesdna, "Lamp", "float", "contact_dist")) { - for (Lamp *la = main->lamp.first; la; la = la->id.next) { + for (Lamp *la = bmain->lamp.first; la; la = la->id.next) { la->contact_dist = 1.0f; la->contact_bias = 0.03f; la->contact_spread = 0.2f; @@ -918,7 +922,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *main) } if (!DNA_struct_elem_find(fd->filesdna, "LightProbe", "float", "vis_bias")) { - for (LightProbe *probe = main->lightprobe.first; probe; probe = probe->id.next) { + for (LightProbe *probe = bmain->lightprobe.first; probe; probe = probe->id.next) { probe->vis_bias = 1.0f; probe->vis_blur = 0.2f; } @@ -937,7 +941,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *main) * Also, metallic node is now unified into the principled node. */ eNTreeDoVersionErrors error = NTREE_DOVERSION_NO_ERROR; - FOREACH_NODETREE(main, ntree, id) { + FOREACH_NODETREE(bmain, ntree, id) { if (ntree->type == NTREE_SHADER) { for (bNode *node = ntree->nodes.first; node; node = node->next) { if (node->type == 194 /* SH_NODE_EEVEE_METALLIC */ && @@ -986,7 +990,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *main) (DNA_struct_elem_find(fd->filesdna, "ViewLayer", "FreestyleConfig", "freestyle_config") == false) && DNA_struct_elem_find(fd->filesdna, "Scene", "ListBase", "view_layers")) { - for (Scene *scene = main->scene.first; scene; scene = scene->id.next) { + for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) { ViewLayer *view_layer; for (view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) { view_layer->flag |= VIEW_LAYER_FREESTYLE; @@ -1001,15 +1005,15 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *main) } #ifdef USE_COLLECTION_COMPAT_28 - if (use_collection_compat_28 && !MAIN_VERSION_ATLEAST(main, 280, 3)) { - for (Scene *scene = main->scene.first; scene; scene = scene->id.next) { + if (use_collection_compat_28 && !MAIN_VERSION_ATLEAST(bmain, 280, 3)) { + for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) { ViewLayer *view_layer; for (view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) { do_version_view_layer_visibility(view_layer); } } - for (Collection *group = main->collection.first; group; group = group->id.next) { + for (Collection *group = bmain->collection.first; group; group = group->id.next) { if (group->view_layer != NULL) { do_version_view_layer_visibility(group->view_layer); } @@ -1017,14 +1021,14 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *main) } #endif - if (!MAIN_VERSION_ATLEAST(main, 280, 6)) { + if (!MAIN_VERSION_ATLEAST(bmain, 280, 6)) { if (DNA_struct_elem_find(fd->filesdna, "SpaceOops", "int", "filter") == false) { bScreen *sc; ScrArea *sa; SpaceLink *sl; /* Update files using invalid (outdated) outlinevis Outliner values. */ - for (sc = main->screen.first; sc; sc = sc->id.next) { + for (sc = bmain->screen.first; sc; sc = sc->id.next) { for (sa = sc->areabase.first; sa; sa = sa->next) { for (sl = sa->spacedata.first; sl; sl = sl->next) { if (sl->spacetype == SPACE_OUTLINER) { @@ -1046,12 +1050,12 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *main) } if (!DNA_struct_elem_find(fd->filesdna, "LightProbe", "float", "intensity")) { - for (LightProbe *probe = main->lightprobe.first; probe; probe = probe->id.next) { + for (LightProbe *probe = bmain->lightprobe.first; probe; probe = probe->id.next) { probe->intensity = 1.0f; } } - for (Object *ob = main->object.first; ob; ob = ob->id.next) { + for (Object *ob = bmain->object.first; ob; ob = ob->id.next) { bConstraint *con, *con_next; con = ob->constraints.first; while (con) { @@ -1066,12 +1070,12 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *main) } if (!DNA_struct_elem_find(fd->filesdna, "Scene", "int", "orientation_index_custom")) { - for (Scene *scene = main->scene.first; scene; scene = scene->id.next) { + for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) { scene->orientation_index_custom = -1; } } - for (bScreen *sc = main->screen.first; sc; sc = sc->id.next) { + for (bScreen *sc = bmain->screen.first; sc; sc = sc->id.next) { for (ScrArea *sa = sc->areabase.first; sa; sa = sa->next) { for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) { if (sl->spacetype == SPACE_VIEW3D) { @@ -1081,7 +1085,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *main) /* Assume (demo) files written with 2.8 want to show * Eevee renders in the viewport. */ - if (MAIN_VERSION_ATLEAST(main, 280, 0)) { + if (MAIN_VERSION_ATLEAST(bmain, 280, 0)) { v3d->drawtype = OB_MATERIAL; } } @@ -1090,20 +1094,20 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *main) } } - if (!MAIN_VERSION_ATLEAST(main, 280, 7)) { + if (!MAIN_VERSION_ATLEAST(bmain, 280, 7)) { /* Render engine storage moved elsewhere and back during 2.8 * development, we assume any files saved in 2.8 had Eevee set * as scene render engine. */ - if (MAIN_VERSION_ATLEAST(main, 280, 0)) { - for (Scene *scene = main->scene.first; scene; scene = scene->id.next) { + if (MAIN_VERSION_ATLEAST(bmain, 280, 0)) { + for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) { BLI_strncpy(scene->r.engine, RE_engine_id_BLENDER_EEVEE, sizeof(scene->r.engine)); } } } - if (!MAIN_VERSION_ATLEAST(main, 280, 8)) { + if (!MAIN_VERSION_ATLEAST(bmain, 280, 8)) { /* Blender Internal removal */ - for (Scene *scene = main->scene.first; scene; scene = scene->id.next) { + for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) { if (STREQ(scene->r.engine, "BLENDER_RENDER") || STREQ(scene->r.engine, "BLENDER_GAME")) { @@ -1113,7 +1117,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *main) scene->r.bake_mode = 0; } - for (Tex *tex = main->tex.first; tex; tex = tex->id.next) { + for (Tex *tex = bmain->tex.first; tex; tex = tex->id.next) { /* Removed envmap, pointdensity, voxeldata, ocean textures. */ if (ELEM(tex->type, 10, 14, 15, 16)) { tex->type = 0; @@ -1121,10 +1125,10 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *main) } } - if (!MAIN_VERSION_ATLEAST(main, 280, 11)) { + if (!MAIN_VERSION_ATLEAST(bmain, 280, 11)) { /* Remove info editor, but only if at the top of the window. */ - for (bScreen *screen = main->screen.first; screen; screen = screen->id.next) { + for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) { /* Calculate window width/height from screen vertices */ int win_width = 0, win_height = 0; for (ScrVert *vert = screen->vertbase.first; vert; vert = vert->next) { @@ -1154,8 +1158,8 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *main) } } - if (!MAIN_VERSION_ATLEAST(main, 280, 11)) { - for (Lamp *lamp = main->lamp.first; lamp; lamp = lamp->id.next) { + if (!MAIN_VERSION_ATLEAST(bmain, 280, 11)) { + for (Lamp *lamp = bmain->lamp.first; lamp; lamp = lamp->id.next) { if (lamp->mode & (1 << 13)) { /* LA_SHAD_RAY */ lamp->mode |= LA_SHADOW; lamp->mode &= ~(1 << 13); @@ -1163,9 +1167,9 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *main) } } - if (!MAIN_VERSION_ATLEAST(main, 280, 12)) { + if (!MAIN_VERSION_ATLEAST(bmain, 280, 12)) { /* Remove tool property regions. */ - for (bScreen *screen = main->screen.first; screen; screen = screen->id.next) { + for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) { for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) { for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) { if (ELEM(sl->spacetype, SPACE_VIEW3D, SPACE_CLIP)) { @@ -1185,16 +1189,16 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *main) } } - if (!MAIN_VERSION_ATLEAST(main, 280, 13)) { + if (!MAIN_VERSION_ATLEAST(bmain, 280, 13)) { /* Initialize specular factor. */ if (!DNA_struct_elem_find(fd->filesdna, "Lamp", "float", "spec_fac")) { - for (Lamp *la = main->lamp.first; la; la = la->id.next) { + for (Lamp *la = bmain->lamp.first; la; la = la->id.next) { la->spec_fac = 1.0f; } } /* Initialize new view3D options. */ - for (bScreen *screen = main->screen.first; screen; screen = screen->id.next) { + for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) { for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) { for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) { if (sl->spacetype == SPACE_VIEW3D) { @@ -1213,10 +1217,10 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *main) } if (!DNA_struct_find(fd->filesdna, "View3DCursor")) { - for (Scene *scene = main->scene.first; scene; scene = scene->id.next) { + for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) { unit_qt(scene->cursor.rotation); } - for (bScreen *screen = main->screen.first; screen; screen = screen->id.next) { + for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) { for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) { for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) { if (sl->spacetype == SPACE_VIEW3D) { @@ -1229,34 +1233,34 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *main) } } - if (!MAIN_VERSION_ATLEAST(main, 280, 14)) { + if (!MAIN_VERSION_ATLEAST(bmain, 280, 14)) { if (!DNA_struct_elem_find(fd->filesdna, "Scene", "SceneDisplay", "display")) { /* Initialize new scene.SceneDisplay */ - for (Scene *scene = main->scene.first; scene; scene = scene->id.next) { + for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) { copy_v3_v3(scene->display.light_direction, (float[3]){-M_SQRT1_3, -M_SQRT1_3, M_SQRT1_3}); } } if (!DNA_struct_elem_find(fd->filesdna, "SceneDisplay", "float", "shadow_shift")) { - for (Scene *scene = main->scene.first; scene; scene = scene->id.next) { + for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) { scene->display.shadow_shift = 0.1; } } if (!DNA_struct_elem_find(fd->filesdna, "Object", "ObjectDisplay", "display")) { /* Initialize new object.ObjectDisplay */ - for (Object *ob = main->object.first; ob; ob = ob->id.next) { + for (Object *ob = bmain->object.first; ob; ob = ob->id.next) { ob->display.flag = OB_SHOW_SHADOW; } } if (!DNA_struct_elem_find(fd->filesdna, "ToolSettings", "char", "transform_pivot_point")) { - for (Scene *scene = main->scene.first; scene; scene = scene->id.next) { + for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) { scene->toolsettings->transform_pivot_point = V3D_AROUND_CENTER_MEAN; } } if (!DNA_struct_find(fd->filesdna, "SceneEEVEE")) { - for (Scene *scene = main->scene.first; scene; scene = scene->id.next) { + for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) { /* First set the default for all the properties. */ scene->eevee.gi_diffuse_bounces = 3; @@ -1438,8 +1442,8 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *main) } - if (!MAIN_VERSION_ATLEAST(main, 280, 15)) { - for (Scene *scene = main->scene.first; scene; scene = scene->id.next) { + if (!MAIN_VERSION_ATLEAST(bmain, 280, 15)) { + for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) { scene->display.matcap_icon = 1; scene->display.matcap_type = CLAY_MATCAP_NONE; scene->display.matcap_hue = 0.5f; @@ -1452,7 +1456,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *main) scene->display.matcap_ssao_samples = 16; } - for (bScreen *screen = main->screen.first; screen; screen = screen->id.next) { + for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) { for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) { for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) { if (sl->spacetype == SPACE_OUTLINER) { @@ -1464,7 +1468,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *main) } } - for (Scene *scene = main->scene.first; scene; scene = scene->id.next) { + for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) { switch (scene->toolsettings->snap_mode) { case 0: scene->toolsettings->snap_mode = SCE_SNAP_MODE_INCREMENT; break; case 1: scene->toolsettings->snap_mode = SCE_SNAP_MODE_VERTEX ; break; @@ -1485,7 +1489,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *main) } ParticleSettings *part; - for (part = main->particle.first; part; part = part->id.next) { + for (part = bmain->particle.first; part; part = part->id.next) { part->shape_flag = PART_SHAPE_CLOSE_TIP; part->shape = 0.0f; part->rad_root = 1.0f; @@ -1497,9 +1501,9 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *main) } { if (!DNA_struct_elem_find(fd->filesdna, "Material", "float", "roughness")) { - for (Material *mat = main->mat.first; mat; mat = mat->id.next) { + for (Material *mat = bmain->mat.first; mat; mat = mat->id.next) { if (mat->use_nodes) { - if (MAIN_VERSION_ATLEAST(main, 280, 0)) { + if (MAIN_VERSION_ATLEAST(bmain, 280, 0)) { mat->roughness = mat->gloss_mir; } else { @@ -1512,7 +1516,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *main) mat->metallic = mat->ray_mirror; } - for (bScreen *screen = main->screen.first; screen; screen = screen->id.next) { + for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) { for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) { for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) { if (sl->spacetype == SPACE_VIEW3D) { @@ -1525,7 +1529,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *main) } if (!DNA_struct_elem_find(fd->filesdna, "View3DShading", "float", "xray_alpha")) { - for (bScreen *screen = main->screen.first; screen; screen = screen->id.next) { + for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) { for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) { for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) { if (sl->spacetype == SPACE_VIEW3D) { @@ -1536,5 +1540,58 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *main) } } } + if (!DNA_struct_elem_find(fd->filesdna, "View3DShading", "char", "matcap[256]")) { + StudioLight *default_matcap = BKE_studiolight_find_first(STUDIOLIGHT_ORIENTATION_VIEWNORMAL); + /* when loading the internal file is loaded before the matcaps */ + if (default_matcap) { + for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) { + for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) { + for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) { + if (sl->spacetype == SPACE_VIEW3D) { + View3D *v3d = (View3D *)sl; + BLI_strncpy(v3d->shading.matcap, default_matcap->name, FILE_MAXFILE); + } + } + } + } + } + } + if (!DNA_struct_elem_find(fd->filesdna, "View3DOverlay", "float", "wireframe_threshold")) { + for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) { + for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) { + for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) { + if (sl->spacetype == SPACE_VIEW3D) { + View3D *v3d = (View3D *)sl; + v3d->overlay.wireframe_threshold = 0.5f; + } + } + } + } + } + if (!DNA_struct_elem_find(fd->filesdna, "View3DShading", "float", "cavity_valley_factor")) { + for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) { + for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) { + for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) { + if (sl->spacetype == SPACE_VIEW3D) { + View3D *v3d = (View3D *)sl; + v3d->shading.cavity_valley_factor = 1.0f; + v3d->shading.cavity_ridge_factor = 1.0f; + } + } + } + } + } + if (!DNA_struct_elem_find(fd->filesdna, "View3DOverlay", "float", "bone_selection_alpha")) { + for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) { + for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) { + for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) { + if (sl->spacetype == SPACE_VIEW3D) { + View3D *v3d = (View3D *)sl; + v3d->overlay.bone_selection_alpha = 0.5f; + } + } + } + } + } } } diff --git a/source/blender/blenloader/intern/versioning_legacy.c b/source/blender/blenloader/intern/versioning_legacy.c index a450c487dd9..bc69b1d99fc 100644 --- a/source/blender/blenloader/intern/versioning_legacy.c +++ b/source/blender/blenloader/intern/versioning_legacy.c @@ -483,13 +483,13 @@ void blo_do_version_old_trackto_to_constraints(Object *ob) ob->track = NULL; } -void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) +void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain) { /* WATCH IT!!!: pointers from libdata have not been converted */ - if (main->versionfile == 100) { + if (bmain->versionfile == 100) { /* tex->extend and tex->imageflag have changed: */ - Tex *tex = main->tex.first; + Tex *tex = bmain->tex.first; while (tex) { if (tex->id.tag & LIB_TAG_NEED_LINK) { @@ -508,9 +508,9 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) } } - if (main->versionfile <= 101) { + if (bmain->versionfile <= 101) { /* frame mapping */ - Scene *sce = main->scene.first; + Scene *sce = bmain->scene.first; while (sce) { sce->r.framapto = 100; sce->r.images = 100; @@ -519,9 +519,9 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) } } - if (main->versionfile <= 103) { + if (bmain->versionfile <= 103) { /* new variable in object: colbits */ - Object *ob = main->object.first; + Object *ob = bmain->object.first; int a; while (ob) { ob->colbits = 0; @@ -535,9 +535,9 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) } } - if (main->versionfile <= 104) { + if (bmain->versionfile <= 104) { /* timeoffs moved */ - Object *ob = main->object.first; + Object *ob = bmain->object.first; while (ob) { if (ob->transflag & 1) { ob->transflag -= 1; @@ -546,8 +546,8 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) } } - if (main->versionfile <= 105) { - Object *ob = main->object.first; + if (bmain->versionfile <= 105) { + Object *ob = bmain->object.first; while (ob) { ob->dupon = 1; ob->dupoff = 0; @@ -557,9 +557,9 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) } } - if (main->versionfile <= 106) { + if (bmain->versionfile <= 106) { /* mcol changed */ - Mesh *me = main->mesh.first; + Mesh *me = bmain->mesh.first; while (me) { if (me->mcol) vcol_to_fcol(me); @@ -568,9 +568,9 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) } - if (main->versionfile <= 107) { + if (bmain->versionfile <= 107) { Object *ob; - ob = main->object.first; + ob = bmain->object.first; while (ob) { if (ob->dt == 0) ob->dt = OB_SOLID; @@ -579,9 +579,9 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) } - if (main->versionfile <= 109) { + if (bmain->versionfile <= 109) { /* new variable: gridlines */ - bScreen *sc = main->screen.first; + bScreen *sc = bmain->screen.first; while (sc) { ScrArea *sa = sc->areabase.first; while (sa) { @@ -601,8 +601,8 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) } } - if (main->versionfile <= 134) { - Tex *tex = main->tex.first; + if (bmain->versionfile <= 134) { + Tex *tex = bmain->tex.first; while (tex) { if ((tex->rfac == 0.0f) && (tex->gfac == 0.0f) && @@ -617,9 +617,9 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) } } - if (main->versionfile <= 140) { + if (bmain->versionfile <= 140) { /* r-g-b-fac in texture */ - Tex *tex = main->tex.first; + Tex *tex = bmain->tex.first; while (tex) { if ((tex->rfac == 0.0f) && (tex->gfac == 0.0f) && @@ -634,8 +634,8 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) } } - if (main->versionfile <= 153) { - Scene *sce = main->scene.first; + if (bmain->versionfile <= 153) { + Scene *sce = bmain->scene.first; while (sce) { if (sce->r.blurfac == 0.0f) sce->r.blurfac = 1.0f; @@ -643,8 +643,8 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) } } - if (main->versionfile <= 163) { - Scene *sce = main->scene.first; + if (bmain->versionfile <= 163) { + Scene *sce = bmain->scene.first; while (sce) { if (sce->r.frs_sec == 0) sce->r.frs_sec = 25; @@ -652,16 +652,16 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) } } - if (main->versionfile <= 164) { - Mesh *me = main->mesh.first; + if (bmain->versionfile <= 164) { + Mesh *me = bmain->mesh.first; while (me) { me->smoothresh = 30; me = me->id.next; } } - if (main->versionfile <= 165) { - Mesh *me = main->mesh.first; + if (bmain->versionfile <= 165) { + Mesh *me = bmain->mesh.first; TFace *tface; int nr; char *cp; @@ -687,8 +687,8 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) } } - if (main->versionfile <= 169) { - Mesh *me = main->mesh.first; + if (bmain->versionfile <= 169) { + Mesh *me = bmain->mesh.first; while (me) { if (me->subdiv == 0) me->subdiv = 1; @@ -696,8 +696,8 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) } } - if (main->versionfile <= 169) { - bScreen *sc = main->screen.first; + if (bmain->versionfile <= 169) { + bScreen *sc = bmain->screen.first; while (sc) { ScrArea *sa = sc->areabase.first; while (sa) { @@ -715,8 +715,8 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) } } - if (main->versionfile <= 170) { - Object *ob = main->object.first; + if (bmain->versionfile <= 170) { + Object *ob = bmain->object.first; PartEff *paf; while (ob) { paf = blo_do_version_give_parteff_245(ob); @@ -729,8 +729,8 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) } } - if (main->versionfile <= 171) { - bScreen *sc = main->screen.first; + if (bmain->versionfile <= 171) { + bScreen *sc = bmain->screen.first; while (sc) { ScrArea *sa = sc->areabase.first; while (sa) { @@ -748,9 +748,9 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) } } - if (main->versionfile <= 173) { + if (bmain->versionfile <= 173) { int a, b; - Mesh *me = main->mesh.first; + Mesh *me = bmain->mesh.first; while (me) { if (me->tface) { TFace *tface = me->tface; @@ -765,10 +765,10 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) } } - if (main->versionfile <= 204) { + if (bmain->versionfile <= 204) { bSound *sound; - sound = main->sound.first; + sound = bmain->sound.first; while (sound) { if (sound->volume < 0.01f) { sound->volume = 1.0f; @@ -777,11 +777,11 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) } } - if (main->versionfile <= 212) { + if (bmain->versionfile <= 212) { bSound *sound; Mesh *me; - sound = main->sound.first; + sound = bmain->sound.first; while (sound) { sound->max_gain = 1.0; sound->min_gain = 0.0; @@ -800,7 +800,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) * it a subsurf, and reset the subdiv level because subsurf * takes a lot more work to calculate. */ - for (me = main->mesh.first; me; me = me->id.next) { + for (me = bmain->mesh.first; me; me = me->id.next) { if (me->flag & ME_SMESH) { me->flag &= ~ME_SMESH; me->flag |= ME_SUBSURF; @@ -816,14 +816,14 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) } } - if (main->versionfile <= 220) { + if (bmain->versionfile <= 220) { Mesh *me; /* Began using alpha component of vertex colors, but * old file vertex colors are undefined, reset them * to be fully opaque. -zr */ - for (me = main->mesh.first; me; me = me->id.next) { + for (me = bmain->mesh.first; me; me = me->id.next) { if (me->mcol) { int i; @@ -848,22 +848,22 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) } } - if (main->versionfile <= 223) { + if (bmain->versionfile <= 223) { VFont *vf; - for (vf = main->vfont.first; vf; vf = vf->id.next) { + for (vf = bmain->vfont.first; vf; vf = vf->id.next) { if (STREQ(vf->name + strlen(vf->name) - 6, ".Bfont")) { strcpy(vf->name, FO_BUILTIN_NAME); } } } - if (main->versionfile <= 224) { + if (bmain->versionfile <= 224) { bSound *sound; Scene *sce; Mesh *me; bScreen *sc; - for (sound = main->sound.first; sound; sound = sound->id.next) { + for (sound = bmain->sound.first; sound; sound = sound->id.next) { if (sound->packedfile) { if (sound->newpackedfile == NULL) { sound->newpackedfile = sound->packedfile; @@ -872,17 +872,17 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) } } /* Make sure that old subsurf meshes don't have zero subdivision level for rendering */ - for (me = main->mesh.first; me; me = me->id.next) { + for (me = bmain->mesh.first; me; me = me->id.next) { if ((me->flag & ME_SUBSURF) && (me->subdivr == 0)) me->subdivr = me->subdiv; } - for (sce = main->scene.first; sce; sce = sce->id.next) { + for (sce = bmain->scene.first; sce; sce = sce->id.next) { sce->r.stereomode = 1; // no stereo } /* some oldfile patch, moved from set_func_space */ - for (sc = main->screen.first; sc; sc = sc->id.next) { + for (sc = bmain->screen.first; sc; sc = sc->id.next) { ScrArea *sa; for (sa = sc->areabase.first; sa; sa = sa->next) { @@ -898,7 +898,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) } } - if (main->versionfile <= 227) { + if (bmain->versionfile <= 227) { Scene *sce; bScreen *sc; Object *ob; @@ -906,7 +906,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) /* As of now, this insures that the transition from the old Track system * to the new full constraint Track is painless for everyone. - theeth */ - ob = main->object.first; + ob = bmain->object.first; while (ob) { ListBase *list; @@ -949,13 +949,13 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) ob = ob->id.next; } - for (sce = main->scene.first; sce; sce = sce->id.next) { + for (sce = bmain->scene.first; sce; sce = sce->id.next) { sce->audio.mixrate = 48000; sce->audio.flag |= AUDIO_SCRUB; } /* patch for old wrong max view2d settings, allows zooming out more */ - for (sc = main->screen.first; sc; sc = sc->id.next) { + for (sc = bmain->screen.first; sc; sc = sc->id.next) { ScrArea *sa; for (sa = sc->areabase.first; sa; sa = sa->next) { @@ -975,14 +975,14 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) } } - if (main->versionfile <= 228) { + if (bmain->versionfile <= 228) { bScreen *sc; Object *ob; /* As of now, this insures that the transition from the old Track system * to the new full constraint Track is painless for everyone. */ - ob = main->object.first; + ob = bmain->object.first; while (ob) { ListBase *list; @@ -1022,7 +1022,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) } /* convert old mainb values for new button panels */ - for (sc = main->screen.first; sc; sc = sc->id.next) { + for (sc = bmain->screen.first; sc; sc = sc->id.next) { ScrArea *sa; for (sa = sc->areabase.first; sa; sa = sa->next) { @@ -1089,11 +1089,11 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) * check apart from the do_versions() */ - if (main->versionfile <= 230) { + if (bmain->versionfile <= 230) { bScreen *sc; /* new variable blockscale, for panels in any area */ - for (sc = main->screen.first; sc; sc = sc->id.next) { + for (sc = bmain->screen.first; sc; sc = sc->id.next) { ScrArea *sa; for (sa = sc->areabase.first; sa; sa = sa->next) { @@ -1110,9 +1110,9 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) } } - if (main->versionfile <= 231) { + if (bmain->versionfile <= 231) { /* new bit flags for showing/hiding grid floor and axes */ - bScreen *sc = main->screen.first; + bScreen *sc = bmain->screen.first; while (sc) { ScrArea *sa = sc->areabase.first; @@ -1137,8 +1137,8 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) } } - if (main->versionfile <= 231) { - bScreen *sc = main->screen.first; + if (bmain->versionfile <= 231) { + bScreen *sc = bmain->screen.first; /* new bit flags for showing/hiding grid floor and axes */ @@ -1165,9 +1165,9 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) } } - if (main->versionfile <= 232) { - Tex *tex = main->tex.first; - World *wrld = main->world.first; + if (bmain->versionfile <= 232) { + Tex *tex = bmain->tex.first; + World *wrld = bmain->world.first; bScreen *sc; while (tex) { @@ -1204,7 +1204,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) /* new variable blockscale, for panels in any area, do again because new * areas didnt initialize it to 0.7 yet */ - for (sc = main->screen.first; sc; sc = sc->id.next) { + for (sc = bmain->screen.first; sc; sc = sc->id.next) { ScrArea *sa; for (sa = sc->areabase.first; sa; sa = sa->next) { SpaceLink *sl; @@ -1219,10 +1219,10 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) } } - if (main->versionfile <= 233) { + if (bmain->versionfile <= 233) { bScreen *sc; - Material *ma = main->mat.first; - /* Object *ob = main->object.first; */ + Material *ma = bmain->mat.first; + /* Object *ob = bmain->object.first; */ while (ma) { if (ma->pr_lamp == 0) @@ -1230,7 +1230,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) ma = ma->id.next; } - for (sc = main->screen.first; sc; sc = sc->id.next) { + for (sc = bmain->screen.first; sc; sc = sc->id.next) { ScrArea *sa; for (sa = sc->areabase.first; sa; sa = sa->next) { SpaceLink *sl; @@ -1244,10 +1244,10 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) } } - if (main->versionfile <= 234) { + if (bmain->versionfile <= 234) { bScreen *sc; - for (sc = main->screen.first; sc; sc = sc->id.next) { + for (sc = bmain->screen.first; sc; sc = sc->id.next) { ScrArea *sa; for (sa = sc->areabase.first; sa; sa = sa->next) { SpaceLink *sl; @@ -1266,9 +1266,9 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) } } - if (main->versionfile <= 235) { - Tex *tex = main->tex.first; - Scene *sce = main->scene.first; + if (bmain->versionfile <= 235) { + Tex *tex = bmain->tex.first; + Scene *sce = bmain->scene.first; Sequence *seq; Editing *ed; @@ -1292,9 +1292,9 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) } } - if (main->versionfile <= 236) { + if (bmain->versionfile <= 236) { Object *ob; - Camera *cam = main->camera.first; + Camera *cam = bmain->camera.first; while (cam) { if (cam->ortho_scale == 0.0f) { @@ -1308,7 +1308,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) /* set time line var */ /* softbody init new vars */ - for (ob = main->object.first; ob; ob = ob->id.next) { + for (ob = bmain->object.first; ob; ob = ob->id.next) { if (ob->soft) { if (ob->soft->defgoal == 0.0f) ob->soft->defgoal = 0.7f; @@ -1331,20 +1331,20 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) } } - if (main->versionfile <= 237) { + if (bmain->versionfile <= 237) { bArmature *arm; bConstraint *con; Object *ob; Bone *bone; /* armature recode checks */ - for (arm = main->armature.first; arm; arm = arm->id.next) { + for (arm = bmain->armature.first; arm; arm = arm->id.next) { BKE_armature_where_is(arm); for (bone = arm->bonebase.first; bone; bone = bone->next) do_version_bone_head_tail_237(bone); } - for (ob = main->object.first; ob; ob = ob->id.next) { + for (ob = bmain->object.first; ob; ob = ob->id.next) { if (ob->parent) { Object *parent = blo_do_versions_newlibadr(fd, lib, ob->parent); if (parent && parent->type == OB_LATTICE) @@ -1354,7 +1354,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) /* btw. armature_rebuild_pose is further only called on leave editmode */ if (ob->type == OB_ARMATURE) { if (ob->pose) - BKE_pose_tag_recalc(main, ob->pose); + BKE_pose_tag_recalc(bmain, ob->pose); /* cannot call stuff now (pointers!), done in setup_app_data */ ob->id.recalc |= ID_RECALC_ALL; @@ -1405,13 +1405,13 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) } } - if (main->versionfile <= 238) { + if (bmain->versionfile <= 238) { Lattice *lt; Object *ob; bArmature *arm; Mesh *me; Key *key; - Scene *sce = main->scene.first; + Scene *sce = bmain->scene.first; while (sce) { if (sce->toolsettings == NULL) { @@ -1421,7 +1421,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) sce = sce->id.next; } - for (lt = main->latt.first; lt; lt = lt->id.next) { + for (lt = bmain->latt.first; lt; lt = lt->id.next) { if (lt->fu == 0.0f && lt->fv == 0.0f && lt->fw == 0.0f) { calc_lat_fudu(lt->flag, lt->pntsu, <->fu, <->du); calc_lat_fudu(lt->flag, lt->pntsv, <->fv, <->dv); @@ -1429,7 +1429,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) } } - for (ob = main->object.first; ob; ob = ob->id.next) { + for (ob = bmain->object.first; ob; ob = ob->id.next) { ModifierData *md; PartEff *paf; @@ -1478,7 +1478,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) data->rootbone = -1; /* update_pose_etc handles rootbone == -1 */ - BKE_pose_tag_recalc(main, ob->pose); + BKE_pose_tag_recalc(bmain, ob->pose); } } } @@ -1496,12 +1496,12 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) } } - for (arm = main->armature.first; arm; arm = arm->id.next) { + for (arm = bmain->armature.first; arm; arm = arm->id.next) { bone_version_238(&arm->bonebase); arm->deformflag |= ARM_DEF_VGROUP; } - for (me = main->mesh.first; me; me = me->id.next) { + for (me = bmain->mesh.first; me; me = me->id.next) { if (!me->medge) { BKE_mesh_calc_edges_legacy(me, true); /* true = use mface->edcode */ } @@ -1510,7 +1510,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) } } - for (key = main->key.first; key; key = key->id.next) { + for (key = bmain->key.first; key; key = key->id.next) { KeyBlock *kb; int index = 1; @@ -1529,15 +1529,15 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) } } - if (main->versionfile <= 239) { + if (bmain->versionfile <= 239) { bArmature *arm; Object *ob; - Scene *sce = main->scene.first; - Camera *cam = main->camera.first; + Scene *sce = bmain->scene.first; + Camera *cam = bmain->camera.first; int set_passepartout = 0; /* deformflag is local in modifier now */ - for (ob = main->object.first; ob; ob = ob->id.next) { + for (ob = bmain->object.first; ob; ob = ob->id.next) { ModifierData *md; for (md = ob->modifiers.first; md; md = md->next) { @@ -1553,7 +1553,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) } /* updating stepsize for ghost drawing */ - for (arm = main->armature.first; arm; arm = arm->id.next) { + for (arm = bmain->armature.first; arm; arm = arm->id.next) { if (arm->ghostsize == 0) arm->ghostsize = 1; bone_version_239(&arm->bonebase); @@ -1582,7 +1582,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) } } - if (main->versionfile <= 241) { + if (bmain->versionfile <= 241) { Object *ob; Scene *sce; Lamp *la; @@ -1590,12 +1590,12 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) bNodeTree *ntree; /* updating layers still */ - for (arm = main->armature.first; arm; arm = arm->id.next) { + for (arm = bmain->armature.first; arm; arm = arm->id.next) { bone_version_239(&arm->bonebase); if (arm->layer == 0) arm->layer = 1; } - for (sce = main->scene.first; sce; sce = sce->id.next) { + for (sce = bmain->scene.first; sce; sce = sce->id.next) { if (sce->audio.mixrate == 0) sce->audio.mixrate = 48000; @@ -1622,15 +1622,15 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) } } - for (ntree = main->nodetree.first; ntree; ntree = ntree->id.next) + for (ntree = bmain->nodetree.first; ntree; ntree = ntree->id.next) ntree_version_241(ntree); - for (la = main->lamp.first; la; la = la->id.next) + for (la = bmain->lamp.first; la; la = la->id.next) if (la->buffers == 0) la->buffers = 1; /* for empty drawsize and drawtype */ - for (ob = main->object.first; ob; ob = ob->id.next) { + for (ob = bmain->object.first; ob; ob = ob->id.next) { if (ob->empty_drawsize == 0.0f) { ob->empty_drawtype = OB_ARROWS; ob->empty_drawsize = 1.0; @@ -1638,9 +1638,9 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) } /* during 2.41 images with this name were used for viewer node output, lets fix that */ - if (main->versionfile == 241) { + if (bmain->versionfile == 241) { Image *ima; - for (ima = main->image.first; ima; ima = ima->id.next) { + for (ima = bmain->image.first; ima; ima = ima->id.next) { if (STREQ(ima->name, "Compositor")) { strcpy(ima->id.name + 2, "Viewer Node"); strcpy(ima->name, "Viewer Node"); @@ -1649,7 +1649,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) } } - if (main->versionfile <= 242) { + if (bmain->versionfile <= 242) { Scene *sce; bScreen *sc; Object *ob; @@ -1663,7 +1663,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) bNodeTree *ntree; int a; - for (sc = main->screen.first; sc; sc = sc->id.next) { + for (sc = bmain->screen.first; sc; sc = sc->id.next) { ScrArea *sa; sa = sc->areabase.first; while (sa) { @@ -1680,7 +1680,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) } } - for (sce = main->scene.first; sce; sce = sce->id.next) { + for (sce = bmain->scene.first; sce; sce = sce->id.next) { if (sce->toolsettings->select_thresh == 0.0f) sce->toolsettings->select_thresh = 0.01f; @@ -1694,11 +1694,11 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) ntree_version_242(sce->nodetree); } - for (ntree = main->nodetree.first; ntree; ntree = ntree->id.next) + for (ntree = bmain->nodetree.first; ntree; ntree = ntree->id.next) ntree_version_242(ntree); /* add default radius values to old curve points */ - for (cu = main->curve.first; cu; cu = cu->id.next) { + for (cu = bmain->curve.first; cu; cu = cu->id.next) { for (nu = cu->nurb.first; nu; nu = nu->next) { if (nu) { if (nu->bezt) { @@ -1717,7 +1717,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) } } - for (ob = main->object.first; ob; ob = ob->id.next) { + for (ob = bmain->object.first; ob; ob = ob->id.next) { ModifierData *md; ListBase *list; list = &ob->constraints; @@ -1805,25 +1805,25 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) } - for (ma = main->mat.first; ma; ma = ma->id.next) { + for (ma = bmain->mat.first; ma; ma = ma->id.next) { if (ma->nodetree) ntree_version_242(ma->nodetree); } - for (me = main->mesh.first; me; me = me->id.next) + for (me = bmain->mesh.first; me; me = me->id.next) customdata_version_242(me); - for (collection = main->collection.first; collection; collection = collection->id.next) + for (collection = bmain->collection.first; collection; collection = collection->id.next) if (collection->layer == 0) collection->layer = (1 << 20) - 1; /* now, subversion control! */ - if (main->subversionfile < 3) { + if (bmain->subversionfile < 3) { Image *ima; Tex *tex; /* Image refactor initialize */ - for (ima = main->image.first; ima; ima = ima->id.next) { + for (ima = bmain->image.first; ima; ima = ima->id.next) { ima->source = IMA_SRC_FILE; ima->type = IMA_TYPE_IMAGE; @@ -1840,7 +1840,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) } } - for (tex = main->tex.first; tex; tex = tex->id.next) { + for (tex = bmain->tex.first; tex; tex = tex->id.next) { if (tex->type == TEX_IMAGE && tex->ima) { ima = blo_do_versions_newlibadr(fd, lib, tex->ima); if (tex->imaflag & TEX_ANIM5_) @@ -1856,17 +1856,17 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) tex->iuser.sfra = tex->sfra; tex->iuser.cycl = (tex->imaflag & TEX_ANIMCYCLIC_)!=0; } - for (sce = main->scene.first; sce; sce = sce->id.next) { + for (sce = bmain->scene.first; sce; sce = sce->id.next) { if (sce->nodetree) do_version_ntree_242_2(sce->nodetree); } - for (ntree = main->nodetree.first; ntree; ntree = ntree->id.next) + for (ntree = bmain->nodetree.first; ntree; ntree = ntree->id.next) do_version_ntree_242_2(ntree); - for (ma = main->mat.first; ma; ma = ma->id.next) + for (ma = bmain->mat.first; ma; ma = ma->id.next) if (ma->nodetree) do_version_ntree_242_2(ma->nodetree); - for (sc = main->screen.first; sc; sc = sc->id.next) { + for (sc = bmain->screen.first; sc; sc = sc->id.next) { ScrArea *sa; for (sa = sc->areabase.first; sa; sa = sa->next) { SpaceLink *sl; @@ -1879,8 +1879,8 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) } } - if (main->subversionfile < 4) { - for (sce = main->scene.first; sce; sce = sce->id.next) { + if (bmain->subversionfile < 4) { + for (sce = bmain->scene.first; sce; sce = sce->id.next) { sce->r.bake_mode = 1; /* prevent to include render stuff here */ sce->r.bake_filter = 16; sce->r.bake_flag = R_BAKE_CLEAR; @@ -1888,8 +1888,8 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) } } - if (main->versionfile <= 243) { - Object *ob = main->object.first; + if (bmain->versionfile <= 243) { + Object *ob = bmain->object.first; for (; ob; ob = ob->id.next) { bDeformGroup *curdef; @@ -1901,7 +1901,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) } } - if (main->versionfile < 243 || main->subversionfile < 1) { + if (bmain->versionfile < 243 || bmain->subversionfile < 1) { ModifierData *md; /* translate old mirror modifier axis values to new flags */ @@ -1928,20 +1928,20 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) } /* render layer added, this is not the active layer */ - if (main->versionfile <= 243 || main->subversionfile < 2) { + if (bmain->versionfile <= 243 || bmain->subversionfile < 2) { Mesh *me; - for (me = main->mesh.first; me; me = me->id.next) + for (me = bmain->mesh.first; me; me = me->id.next) customdata_version_243(me); } } - if (main->versionfile <= 244) { + if (bmain->versionfile <= 244) { bScreen *sc; - if (main->versionfile != 244 || main->subversionfile < 2) { + if (bmain->versionfile != 244 || bmain->subversionfile < 2) { /* correct older action editors - incorrect scrolling */ - for (sc = main->screen.first; sc; sc = sc->id.next) { + for (sc = bmain->screen.first; sc; sc = sc->id.next) { ScrArea *sa; sa = sc->areabase.first; while (sa) { @@ -1964,7 +1964,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) } } - if (main->versionfile <= 245) { + if (bmain->versionfile <= 245) { Scene *sce; Object *ob; Image *ima; @@ -1978,10 +1978,10 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) ParticleSystem *psys; /* unless the file was created 2.44.3 but not 2.45, update the constraints */ - if (!(main->versionfile == 244 && main->subversionfile == 3) && - ((main->versionfile < 245) || (main->versionfile == 245 && main->subversionfile == 0)) ) + if (!(bmain->versionfile == 244 && bmain->subversionfile == 3) && + ((bmain->versionfile < 245) || (bmain->versionfile == 245 && bmain->subversionfile == 0)) ) { - for (ob = main->object.first; ob; ob = ob->id.next) { + for (ob = bmain->object.first; ob; ob = ob->id.next) { ListBase *list; list = &ob->constraints; @@ -2048,16 +2048,16 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) } /* fix all versions before 2.45 */ - if (main->versionfile != 245) { + if (bmain->versionfile != 245) { /* repair preview from 242 - 244*/ - for (ima = main->image.first; ima; ima = ima->id.next) { + for (ima = bmain->image.first; ima; ima = ima->id.next) { ima->preview = NULL; } } /* add point caches */ - for (ob = main->object.first; ob; ob = ob->id.next) { + for (ob = bmain->object.first; ob; ob = ob->id.next) { if (ob->soft && !ob->soft->pointcache) ob->soft->pointcache = BKE_ptcache_add(&ob->soft->ptcaches); @@ -2085,7 +2085,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) /* Copy over old per-level multires vertex data * into a single vertex array in struct Multires */ - for (me = main->mesh.first; me; me = me->id.next) { + for (me = bmain->mesh.first; me; me = me->id.next) { if (me->mr && !me->mr->verts) { MultiresLevel *lvl = me->mr->levels.last; if (lvl) { @@ -2100,8 +2100,8 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) } } - if (main->versionfile != 245 || main->subversionfile < 1) { - for (la = main->lamp.first; la; la = la->id.next) { + if (bmain->versionfile != 245 || bmain->subversionfile < 1) { + for (la = bmain->lamp.first; la; la = la->id.next) { la->falloff_type = LA_FALLOFF_INVLINEAR; if (la->curfalloff == NULL) { @@ -2111,18 +2111,18 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) } } - for (ma = main->mat.first; ma; ma = ma->id.next) { + for (ma = bmain->mat.first; ma; ma = ma->id.next) { if (ma->gloss_mir == 0.0f) { ma->gloss_mir = 1.0f; } } - for (part = main->particle.first; part; part = part->id.next) { + for (part = bmain->particle.first; part; part = part->id.next) { if (part->ren_child_nbr == 0) part->ren_child_nbr = part->child_nbr; } - for (sce = main->scene.first; sce; sce = sce->id.next) { + for (sce = bmain->scene.first; sce; sce = sce->id.next) { if (sce->nodetree) ntree_version_245(fd, lib, sce->nodetree); @@ -2132,18 +2132,18 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) } } - for (ntree = main->nodetree.first; ntree; ntree = ntree->id.next) + for (ntree = bmain->nodetree.first; ntree; ntree = ntree->id.next) ntree_version_245(fd, lib, ntree); /* fix for temporary flag changes during 245 cycle */ - for (ima = main->image.first; ima; ima = ima->id.next) { + for (ima = bmain->image.first; ima; ima = ima->id.next) { if (ima->flag & IMA_OLD_PREMUL) { ima->flag &= ~IMA_OLD_PREMUL; ima->alpha_mode = IMA_ALPHA_STRAIGHT; } } - for (tex = main->tex.first; tex; tex = tex->id.next) { + for (tex = bmain->tex.first; tex; tex = tex->id.next) { if (tex->iuser.flag & IMA_OLD_PREMUL) { tex->iuser.flag &= ~IMA_OLD_PREMUL; } @@ -2156,24 +2156,24 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) } } - if ((main->versionfile < 245) || (main->versionfile == 245 && main->subversionfile < 2)) { + if ((bmain->versionfile < 245) || (bmain->versionfile == 245 && bmain->subversionfile < 2)) { Image *ima; /* initialize 1:1 Aspect */ - for (ima = main->image.first; ima; ima = ima->id.next) { + for (ima = bmain->image.first; ima; ima = ima->id.next) { ima->aspx = ima->aspy = 1.0f; } } - if ((main->versionfile < 245) || (main->versionfile == 245 && main->subversionfile < 4)) { + if ((bmain->versionfile < 245) || (bmain->versionfile == 245 && bmain->subversionfile < 4)) { bArmature *arm; ModifierData *md; Object *ob; - for (arm = main->armature.first; arm; arm = arm->id.next) + for (arm = bmain->armature.first; arm; arm = arm->id.next) arm->deformflag |= ARM_DEF_B_BONE_REST; - for (ob = main->object.first; ob; ob = ob->id.next) { + for (ob = bmain->object.first; ob; ob = ob->id.next) { for (md = ob->modifiers.first; md; md = md->next) { if (md->type == eModifierType_Armature) ((ArmatureModifierData*) md)->deformflag |= ARM_DEF_B_BONE_REST; @@ -2181,10 +2181,10 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) } } - if ((main->versionfile < 245) || (main->versionfile == 245 && main->subversionfile < 5)) { + if ((bmain->versionfile < 245) || (bmain->versionfile == 245 && bmain->subversionfile < 5)) { /* foreground color needs to be something other then black */ Scene *sce; - for (sce = main->scene.first; sce; sce = sce->id.next) { + for (sce = bmain->scene.first; sce; sce = sce->id.next) { sce->r.fg_stamp[0] = sce->r.fg_stamp[1] = sce->r.fg_stamp[2] = 0.8f; sce->r.fg_stamp[3] = 1.0f; /* don't use text alpha yet */ sce->r.bg_stamp[3] = 0.25f; /* make sure the background has full alpha */ @@ -2192,21 +2192,21 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) } - if ((main->versionfile < 245) || (main->versionfile == 245 && main->subversionfile < 6)) { + if ((bmain->versionfile < 245) || (bmain->versionfile == 245 && bmain->subversionfile < 6)) { Scene *sce; /* fix frs_sec_base */ - for (sce = main->scene.first; sce; sce = sce->id.next) { + for (sce = bmain->scene.first; sce; sce = sce->id.next) { if (sce->r.frs_sec_base == 0) { sce->r.frs_sec_base = 1; } } } - if ((main->versionfile < 245) || (main->versionfile == 245 && main->subversionfile < 7)) { + if ((bmain->versionfile < 245) || (bmain->versionfile == 245 && bmain->subversionfile < 7)) { Object *ob; bPoseChannel *pchan; - for (ob = main->object.first; ob; ob = ob->id.next) { + for (ob = bmain->object.first; ob; ob = ob->id.next) { if (ob->pose) { for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { do_version_constraints_245(&pchan->constraints); @@ -2231,12 +2231,12 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) } } - if ((main->versionfile < 245) || (main->versionfile == 245 && main->subversionfile < 8)) { + if ((bmain->versionfile < 245) || (bmain->versionfile == 245 && bmain->subversionfile < 8)) { Scene *sce; Object *ob; PartEff *paf = NULL; - for (ob = main->object.first; ob; ob = ob->id.next) { + for (ob = bmain->object.first; ob; ob = ob->id.next) { if (ob->soft && ob->soft->keys) { SoftBody *sb = ob->soft; int k; @@ -2263,7 +2263,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) psys = MEM_callocN(sizeof(ParticleSystem), "particle_system"); psys->pointcache = BKE_ptcache_add(&psys->ptcaches); - part = psys->part = BKE_particlesettings_add(main, "ParticleSettings"); + part = psys->part = BKE_particlesettings_add(bmain, "ParticleSettings"); /* needed for proper libdata lookup */ blo_do_versions_oldnewmap_insert(fd->libmap, psys->part, psys->part, 0); @@ -2343,7 +2343,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) /* dupliobjects */ if (ob->transflag & OB_DUPLIVERTS) { - Object *dup = main->object.first; + Object *dup = bmain->object.first; for (; dup; dup = dup->id.next) { if (ob == blo_do_versions_newlibadr(fd, lib, dup->parent)) { @@ -2371,7 +2371,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) } } - for (sce = main->scene.first; sce; sce = sce->id.next) { + for (sce = bmain->scene.first; sce; sce = sce->id.next) { ParticleEditSettings *pset = &sce->toolsettings->particle; int a; @@ -2393,20 +2393,20 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) } } - if ((main->versionfile < 245) || (main->versionfile == 245 && main->subversionfile < 10)) { + if ((bmain->versionfile < 245) || (bmain->versionfile == 245 && bmain->subversionfile < 10)) { Object *ob; /* dupliface scale */ - for (ob = main->object.first; ob; ob = ob->id.next) + for (ob = bmain->object.first; ob; ob = ob->id.next) ob->dupfacesca = 1.0f; } - if ((main->versionfile < 245) || (main->versionfile == 245 && main->subversionfile < 11)) { + if ((bmain->versionfile < 245) || (bmain->versionfile == 245 && bmain->subversionfile < 11)) { Object *ob; bActionStrip *strip; /* nla-strips - scale */ - for (ob = main->object.first; ob; ob = ob->id.next) { + for (ob = bmain->object.first; ob; ob = ob->id.next) { for (strip = ob->nlastrips.first; strip; strip = strip->next) { float length, actlength, repeat; @@ -2431,11 +2431,11 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) } } - if ((main->versionfile < 245) || (main->versionfile == 245 && main->subversionfile < 14)) { + if ((bmain->versionfile < 245) || (bmain->versionfile == 245 && bmain->subversionfile < 14)) { Scene *sce; Sequence *seq; - for (sce = main->scene.first; sce; sce = sce->id.next) { + for (sce = bmain->scene.first; sce; sce = sce->id.next) { SEQ_BEGIN (sce->ed, seq) { if (seq->blend_mode == 0) @@ -2446,39 +2446,39 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) } /* fix broken group lengths in id properties */ - if ((main->versionfile < 245) || (main->versionfile == 245 && main->subversionfile < 15)) { - idproperties_fix_group_lengths(main->scene); - idproperties_fix_group_lengths(main->library); - idproperties_fix_group_lengths(main->object); - idproperties_fix_group_lengths(main->mesh); - idproperties_fix_group_lengths(main->curve); - idproperties_fix_group_lengths(main->mball); - idproperties_fix_group_lengths(main->mat); - idproperties_fix_group_lengths(main->tex); - idproperties_fix_group_lengths(main->image); - idproperties_fix_group_lengths(main->latt); - idproperties_fix_group_lengths(main->lamp); - idproperties_fix_group_lengths(main->camera); - idproperties_fix_group_lengths(main->ipo); - idproperties_fix_group_lengths(main->key); - idproperties_fix_group_lengths(main->world); - idproperties_fix_group_lengths(main->screen); - idproperties_fix_group_lengths(main->vfont); - idproperties_fix_group_lengths(main->text); - idproperties_fix_group_lengths(main->sound); - idproperties_fix_group_lengths(main->collection); - idproperties_fix_group_lengths(main->armature); - idproperties_fix_group_lengths(main->action); - idproperties_fix_group_lengths(main->nodetree); - idproperties_fix_group_lengths(main->brush); - idproperties_fix_group_lengths(main->particle); + if ((bmain->versionfile < 245) || (bmain->versionfile == 245 && bmain->subversionfile < 15)) { + idproperties_fix_group_lengths(bmain->scene); + idproperties_fix_group_lengths(bmain->library); + idproperties_fix_group_lengths(bmain->object); + idproperties_fix_group_lengths(bmain->mesh); + idproperties_fix_group_lengths(bmain->curve); + idproperties_fix_group_lengths(bmain->mball); + idproperties_fix_group_lengths(bmain->mat); + idproperties_fix_group_lengths(bmain->tex); + idproperties_fix_group_lengths(bmain->image); + idproperties_fix_group_lengths(bmain->latt); + idproperties_fix_group_lengths(bmain->lamp); + idproperties_fix_group_lengths(bmain->camera); + idproperties_fix_group_lengths(bmain->ipo); + idproperties_fix_group_lengths(bmain->key); + idproperties_fix_group_lengths(bmain->world); + idproperties_fix_group_lengths(bmain->screen); + idproperties_fix_group_lengths(bmain->vfont); + idproperties_fix_group_lengths(bmain->text); + idproperties_fix_group_lengths(bmain->sound); + idproperties_fix_group_lengths(bmain->collection); + idproperties_fix_group_lengths(bmain->armature); + idproperties_fix_group_lengths(bmain->action); + idproperties_fix_group_lengths(bmain->nodetree); + idproperties_fix_group_lengths(bmain->brush); + idproperties_fix_group_lengths(bmain->particle); } /* convert fluids to modifier */ - if (main->versionfile < 246 || (main->versionfile == 246 && main->subversionfile < 1)) { + if (bmain->versionfile < 246 || (bmain->versionfile == 246 && bmain->subversionfile < 1)) { Object *ob; - for (ob = main->object.first; ob; ob = ob->id.next) { + for (ob = bmain->object.first; ob; ob = ob->id.next) { if (ob->fluidsimSettings) { FluidsimModifierData *fluidmd = (FluidsimModifierData *)modifier_new(eModifierType_Fluidsim); BLI_addhead(&ob->modifiers, (ModifierData *)fluidmd); @@ -2495,20 +2495,20 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) } } - if (main->versionfile < 246 || (main->versionfile == 246 && main->subversionfile < 1)) { + if (bmain->versionfile < 246 || (bmain->versionfile == 246 && bmain->subversionfile < 1)) { Object *ob; - for (ob = main->object.first; ob; ob = ob->id.next) { + for (ob = bmain->object.first; ob; ob = ob->id.next) { if (ob->pd && (ob->pd->forcefield == PFIELD_WIND)) ob->pd->f_noise = 0.0f; } } /* set the curve radius interpolation to 2.47 default - easy */ - if (main->versionfile < 247 || (main->versionfile == 247 && main->subversionfile < 6)) { + if (bmain->versionfile < 247 || (bmain->versionfile == 247 && bmain->subversionfile < 6)) { Curve *cu; Nurb *nu; - for (cu = main->curve.first; cu; cu = cu->id.next) { + for (cu = bmain->curve.first; cu; cu = cu->id.next) { for (nu = cu->nurb.first; nu; nu = nu->next) { if (nu) { nu->radius_interp = 3; @@ -2526,21 +2526,21 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) } } - if (main->versionfile < 248 || (main->versionfile == 248 && main->subversionfile < 2)) { + if (bmain->versionfile < 248 || (bmain->versionfile == 248 && bmain->subversionfile < 2)) { Scene *sce; /* Note, these will need to be added for painting */ - for (sce = main->scene.first; sce; sce = sce->id.next) { + for (sce = bmain->scene.first; sce; sce = sce->id.next) { sce->toolsettings->imapaint.seam_bleed = 2; sce->toolsettings->imapaint.normal_angle = 80; } } - if (main->versionfile < 248 || (main->versionfile == 248 && main->subversionfile < 3)) { + if (bmain->versionfile < 248 || (bmain->versionfile == 248 && bmain->subversionfile < 3)) { bScreen *sc; /* adjust default settings for Animation Editors */ - for (sc = main->screen.first; sc; sc = sc->id.next) { + for (sc = bmain->screen.first; sc; sc = sc->id.next) { ScrArea *sa; for (sa = sc->areabase.first; sa; sa = sa->next) { @@ -2575,17 +2575,17 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) } /* correct introduce of seed for wind force */ - if (main->versionfile < 249 && main->subversionfile < 1) { + if (bmain->versionfile < 249 && bmain->subversionfile < 1) { Object *ob; - for (ob = main->object.first; ob; ob = ob->id.next) { + for (ob = bmain->object.first; ob; ob = ob->id.next) { if (ob->pd) ob->pd->seed = ((unsigned int)(ceil(PIL_check_seconds_timer())) + 1) % 128; } } - if (main->versionfile < 249 && main->subversionfile < 2) { - Scene *sce = main->scene.first; + if (bmain->versionfile < 249 && bmain->subversionfile < 2) { + Scene *sce = bmain->scene.first; Sequence *seq; Editing *ed; diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index 743125382c4..ddb0a39dc9a 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -4118,7 +4118,7 @@ bool BLO_write_file( * we should not have any relative paths, but if there * is somehow, an invalid or empty G.main->name it will * print an error, don't try make the absolute in this case. */ - BKE_bpath_absolute_convert(mainvar, G.main->name, NULL); + BKE_bpath_absolute_convert(mainvar, BKE_main_blendfile_path_from_global(), NULL); } } } diff --git a/source/blender/bmesh/intern/bmesh_log.c b/source/blender/bmesh/intern/bmesh_log.c index 4e6fff03411..30ab0dd9459 100644 --- a/source/blender/bmesh/intern/bmesh_log.c +++ b/source/blender/bmesh/intern/bmesh_log.c @@ -654,17 +654,21 @@ void BM_log_mesh_elems_reorder(BMesh *bm, BMLog *log) */ BMLogEntry *BM_log_entry_add(BMLog *log) { - BMLogEntry *entry, *next; - + /* WARNING: this is now handled by the UndoSystem: BKE_UNDOSYS_TYPE_SCULPT + * freeing here causes unnecesssary complications. */ + BMLogEntry *entry; +#if 0 /* Delete any entries after the current one */ entry = log->current_entry; if (entry) { + BMLogEntry *next; for (entry = entry->next; entry; entry = next) { next = entry->next; bm_log_entry_free(entry); BLI_freelinkN(&log->entries, entry); } } +#endif /* Create and append the new entry */ entry = bm_log_entry_create(); diff --git a/source/blender/bmesh/intern/bmesh_mesh_conv.c b/source/blender/bmesh/intern/bmesh_mesh_conv.c index cf6bc0e0bac..5ba3f149689 100644 --- a/source/blender/bmesh/intern/bmesh_mesh_conv.c +++ b/source/blender/bmesh/intern/bmesh_mesh_conv.c @@ -88,6 +88,7 @@ #include "BLI_math_vector.h" #include "BKE_mesh.h" +#include "BKE_mesh_runtime.h" #include "BKE_customdata.h" #include "BKE_multires.h" diff --git a/source/blender/collada/AnimationExporter.cpp b/source/blender/collada/AnimationExporter.cpp index fc4bbea108b..95298986f5a 100644 --- a/source/blender/collada/AnimationExporter.cpp +++ b/source/blender/collada/AnimationExporter.cpp @@ -270,7 +270,7 @@ void AnimationExporter::export_sampled_transrotloc_animation(Object *ob, std::ve create_sampled_animation(3, ctimes, baked_curves[SCALE], ob_name, "scale", "", false); create_sampled_animation(3, ctimes, baked_curves[LOC], ob_name, "location", "", false); - /* Not sure how to export rotation as a 3channel animation, + /* Not sure how to export rotation as a 3channel animation, * so separate into 3 single animations for now: */ @@ -314,7 +314,7 @@ void AnimationExporter::operator()(Object *ob) //This needs to be handled by extra profiles, so postponed for now //export_morph_animation(ob); - + //Export Lamp parameter animations if ( (ob->type == OB_LAMP) && ((Lamp *)ob->data)->adt && ((Lamp *)ob->data)->adt->action) { FCurve *fcu = (FCurve *)(((Lamp *)ob->data)->adt->action->curves.first); @@ -338,7 +338,7 @@ void AnimationExporter::operator()(Object *ob) if ((STREQ(transformName, "lens")) || (STREQ(transformName, "ortho_scale")) || - (STREQ(transformName, "clip_end")) || + (STREQ(transformName, "clip_end")) || (STREQ(transformName, "clip_start"))) { create_keyframed_animation(ob, fcu, transformName, true); @@ -380,7 +380,7 @@ void AnimationExporter::export_object_constraint_animation(Object *ob) } void AnimationExporter::export_morph_animation(Object *ob) -{ +{ FCurve *fcu; char *transformName; Key *key = BKE_key_from_object(ob); @@ -388,12 +388,12 @@ void AnimationExporter::export_morph_animation(Object *ob) if (key->adt && key->adt->action) { fcu = (FCurve *)key->adt->action->curves.first; - + while (fcu) { transformName = extract_transform_name(fcu->rna_path); create_keyframed_animation(ob, fcu, transformName, true); - + fcu = fcu->next; } } @@ -407,17 +407,17 @@ void AnimationExporter::make_anim_frames_from_targets(Object *ob, std::vector<fl bConstraint *con; for (con = (bConstraint *)conlist->first; con; con = con->next) { ListBase targets = {NULL, NULL}; - + const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); - + if (!validateConstraints(con)) continue; if (cti && cti->get_constraint_targets) { bConstraintTarget *ct; Object *obtar; - /* get targets + /* get targets * - constraints should use ct->matrix, not directly accessing values - * - ct->matrix members have not yet been calculated here! + * - ct->matrix members have not yet been calculated here! */ cti->get_constraint_targets(con, &targets); @@ -438,7 +438,7 @@ void AnimationExporter::make_anim_frames_from_targets(Object *ob, std::vector<fl float *AnimationExporter::get_eul_source_for_quat(Object *ob) { FCurve *fcu = (FCurve *)ob->adt->action->curves.first; - const int keys = fcu->totvert; + const int keys = fcu->totvert; float *quat = (float *)MEM_callocN(sizeof(float) * fcu->totvert * 4, "quat output source values"); float *eul = (float *)MEM_callocN(sizeof(float) * fcu->totvert * 3, "quat output source values"); float temp_quat[4]; @@ -520,11 +520,11 @@ void AnimationExporter::create_keyframed_animation(Object *ob, FCurve *fcu, char /* * Note: Handle transformation animations separately (to apply matrix inverse to fcurves) - * We will use the object to evaluate the animation on all keyframes and calculate the + * We will use the object to evaluate the animation on all keyframes and calculate the * resulting object matrix. We need this to incorporate the * effects of the parent inverse matrix (when it contains a rotation component) * - * TODO: try to combine exported fcurves into 3 channel animations like done + * TODO: try to combine exported fcurves into 3 channel animations like done * in export_sampled_animation(). For now each channel is exported as separate <Animation>. */ @@ -648,7 +648,7 @@ void AnimationExporter::create_keyframed_animation(Object *ob, FCurve *fcu, char "/common/" /*profile common is only supported */ + get_transform_sid(fcu->rna_path, -1, axis_name, true); //if shape key animation, this is the main problem, how to define the channel targets. /*target = get_morph_id(ob) + - "/value" +*/ + "/value" +*/ } addChannel(COLLADABU::URI(empty, sampler_id), target); @@ -673,7 +673,7 @@ void AnimationExporter::write_bone_animation_matrix(Object *ob_arm, Bone *bone) } bool AnimationExporter::is_bone_deform_group(Bone *bone) -{ +{ bool is_def; //Check if current bone is deform if ((bone->flag & BONE_NO_DEFORM) == 0) return true; @@ -707,7 +707,7 @@ void AnimationExporter::sample_and_write_bone_animation_matrix(Object *ob_arm, B fcu = fcu->next; } - if (!(fcu)) return;*/ + if (!(fcu)) return;*/ bPoseChannel *pchan = BKE_pose_channel_find_name(ob_arm->pose, bone->name); if (!pchan) @@ -728,7 +728,7 @@ void AnimationExporter::sample_and_write_bone_animation_matrix(Object *ob_arm, B dae_baked_animation(fra, ob_arm, bone); } - if (flag & ARM_RESTPOS) + if (flag & ARM_RESTPOS) arm->flag = flag; BKE_pose_where_is(depsgraph, scene, ob_arm); } @@ -921,7 +921,7 @@ void AnimationExporter::add_source_parameters(COLLADASW::SourceBase::ParameterNa if (axis) { param.push_back(axis); } - else + else if (transform) { param.push_back("TRANSFORM"); } @@ -1307,7 +1307,7 @@ std::string AnimationExporter::create_4x4_source(std::vector<float> &frames, Obj enable_fcurves(ob->adt->action, bone->name); } - + std::vector<float>::iterator it; int j = 0; for (it = frames.begin(); it != frames.end(); it++) { @@ -1326,7 +1326,7 @@ std::string AnimationExporter::create_4x4_source(std::vector<float> &frames, Obj else { BKE_pose_where_is_bone(depsgraph, scene, ob, pchan, ctime, 1); } - + // compute bone local mat if (bone->parent) { invert_m4_m4(ipar, parchan->pose_mat); @@ -1334,7 +1334,7 @@ std::string AnimationExporter::create_4x4_source(std::vector<float> &frames, Obj } else copy_m4_m4(mat, pchan->pose_mat); - + /* OPEN_SIM_COMPATIBILITY * AFAIK animation to second life is via BVH, but no * reason to not have the collada-animation be correct @@ -1359,7 +1359,7 @@ std::string AnimationExporter::create_4x4_source(std::vector<float> &frames, Obj else { copy_m4_m4(mat, ob->obmat); } - + UnitConverter converter; double outmat[4][4]; @@ -1515,7 +1515,7 @@ std::string AnimationExporter::get_light_param_sid(char *rna_path, int tm_type, if (tm_name.size()) { if (axis_name[0]) return tm_name + "." + std::string(axis_name); - else + else return tm_name; } @@ -1564,7 +1564,7 @@ std::string AnimationExporter::get_camera_param_sid(char *rna_path, int tm_type, if (tm_name.size()) { if (axis_name[0]) return tm_name + "." + std::string(axis_name); - else + else return tm_name; } @@ -1751,7 +1751,7 @@ void AnimationExporter::find_sampleframes(Object *ob, std::vector<float> &fra) } while (true); } -/* +/* * find keyframes of all the objects animations */ void AnimationExporter::find_keyframes(Object *ob, std::vector<float> &fra) @@ -1844,7 +1844,7 @@ void AnimationExporter::sample_and_write_bone_animation(Object *ob_arm, Bone *bo arm->flag &= ~ARM_RESTPOS; BKE_pose_where_is(depsgraph, scene, ob_arm); } - //v array will hold all values which will be exported. + //v array will hold all values which will be exported. if (fra.size()) { float *values = (float *)MEM_callocN(sizeof(float) * 3 * fra.size(), "temp. anim frames"); sample_animation(values, fra, transform_type, bone, ob_arm, pchan); @@ -1870,7 +1870,7 @@ void AnimationExporter::sample_and_write_bone_animation(Object *ob_arm, Bone *bo } // restore restpos - if (flag & ARM_RESTPOS) + if (flag & ARM_RESTPOS) arm->flag = flag; BKE_pose_where_is(depsgraph, scene, ob_arm); } diff --git a/source/blender/collada/AnimationExporter.h b/source/blender/collada/AnimationExporter.h index 2ed0a92d89c..a50bcaf0ef4 100644 --- a/source/blender/collada/AnimationExporter.h +++ b/source/blender/collada/AnimationExporter.h @@ -23,7 +23,7 @@ #include <stdlib.h> #include <stdio.h> #include <math.h> -extern "C" +extern "C" { #include "DNA_scene_types.h" #include "DNA_object_types.h" @@ -100,8 +100,8 @@ public: bool exportAnimations(Scene *sce); // called for each exported object - void operator() (Object *ob); - + void operator() (Object *ob); + protected: const ExportSettings *export_settings; @@ -127,7 +127,7 @@ protected: // dae_bone_animation -> add_bone_animation // (blend this into dae_bone_animation) void dae_bone_animation(std::vector<float> &fra, float *v, int tm_type, int axis, std::string ob_name, std::string bone_name); - + void dae_baked_animation(std::vector<float> &fra, Object *ob_arm, Bone *bone); void dae_baked_object_animation(std::vector<float> &fra, Object *ob); @@ -140,9 +140,9 @@ protected: void add_source_parameters(COLLADASW::SourceBase::ParameterNameList& param, COLLADASW::InputSemantic::Semantics semantic, bool is_rot, const char *axis, bool transform); - + void get_source_values(BezTriple *bezt, COLLADASW::InputSemantic::Semantics semantic, bool is_angle, float *values, int *length); - + float* get_eul_source_for_quat(Object *ob ); bool is_flat_line(std::vector<float> &values, int channel_count); @@ -171,12 +171,12 @@ protected: std::string create_interpolation_source(FCurve *fcu, const std::string& anim_id, const char *axis_name, bool *has_tangents); std::string fake_interpolation_source(int tot, const std::string& anim_id, const char *axis_name); - + // for rotation, axis name is always appended and the value of append_axis is ignored std::string get_transform_sid(char *rna_path, int tm_type, const char *axis_name, bool append_axis); std::string get_light_param_sid(char *rna_path, int tm_type, const char *axis_name, bool append_axis); std::string get_camera_param_sid(char *rna_path, int tm_type, const char *axis_name, bool append_axis); - + void find_keyframes(Object *ob, std::vector<float> &fra, const char *prefix, const char *tm_name); void find_keyframes(Object *ob, std::vector<float> &fra); void find_sampleframes(Object *ob, std::vector<float> &fra); @@ -185,13 +185,13 @@ protected: void make_anim_frames_from_targets(Object *ob, std::vector<float> &frames ); void find_rotation_frames(Object *ob, std::vector<float> &fra, const char *prefix, int rotmode); - + // enable fcurves driving a specific bone, disable all the rest // if bone_name = NULL enable all fcurves void enable_fcurves(bAction *act, char *bone_name); - + bool hasAnimations(Scene *sce); - + char *extract_transform_name(char *rna_path); std::string getObjectBoneName(Object *ob, const FCurve * fcu); diff --git a/source/blender/collada/AnimationImporter.cpp b/source/blender/collada/AnimationImporter.cpp index c9b2f6d6d55..e57f8c2f652 100644 --- a/source/blender/collada/AnimationImporter.cpp +++ b/source/blender/collada/AnimationImporter.cpp @@ -118,7 +118,7 @@ void AnimationImporter::animation_to_fcurves(COLLADAFW::AnimationCurve *curve) // input, output - bez.vec[1][0] = bc_get_float_value(input, j) * fps; + bez.vec[1][0] = bc_get_float_value(input, j) * fps; bez.vec[1][1] = bc_get_float_value(output, j * dim + i); @@ -135,14 +135,14 @@ void AnimationImporter::animation_to_fcurves(COLLADAFW::AnimationCurve *curve) // outtangent bez.vec[2][0] = bc_get_float_value(outtan, (j * 2 * dim) + (2 * i)) * fps; bez.vec[2][1] = bc_get_float_value(outtan, (j * 2 * dim) + (2 * i) + 1); - if (curve->getInterpolationType() == COLLADAFW::AnimationCurve::INTERPOLATION_BEZIER) + if (curve->getInterpolationType() == COLLADAFW::AnimationCurve::INTERPOLATION_BEZIER) bez.ipo = BEZT_IPO_BEZ; - else + else bez.ipo = BEZT_IPO_CONST; //bez.h1 = bez.h2 = HD_AUTO; } else { - bez.h1 = bez.h2 = HD_AUTO; + bez.h1 = bez.h2 = HD_AUTO; bez.ipo = BEZT_IPO_LIN; } // bez.ipo = U.ipo_new; /* use default interpolation mode here... */ @@ -180,13 +180,13 @@ void AnimationImporter::fcurve_is_used(FCurve *fcu) } -void AnimationImporter::add_fcurves_to_object(Object *ob, std::vector<FCurve *>& curves, char *rna_path, int array_index, Animation *animated) +void AnimationImporter::add_fcurves_to_object(Main *bmain, Object *ob, std::vector<FCurve *>& curves, char *rna_path, int array_index, Animation *animated) { bAction *act; - - if (!ob->adt || !ob->adt->action) act = verify_adt_action((ID *)&ob->id, 1); + + if (!ob->adt || !ob->adt->action) act = verify_adt_action(bmain, (ID *)&ob->id, 1); else act = ob->adt->action; - + std::vector<FCurve *>::iterator it; int i; @@ -198,39 +198,39 @@ void AnimationImporter::add_fcurves_to_object(Object *ob, std::vector<FCurve *>& if (is_rotation) fcurve_deg_to_rad(fcu); #endif - + for (it = curves.begin(), i = 0; it != curves.end(); it++, i++) { FCurve *fcu = *it; fcu->rna_path = BLI_strdupn(rna_path, strlen(rna_path)); - + if (array_index == -1) fcu->array_index = i; else fcu->array_index = array_index; - + if (ob->type == OB_ARMATURE) { bActionGroup *grp = NULL; const char *bone_name = bc_get_joint_name(animated->node); - + if (bone_name) { /* try to find group */ grp = BKE_action_group_find_name(act, bone_name); - + /* no matching groups, so add one */ if (grp == NULL) { /* Add a new group, and make it active */ grp = (bActionGroup *)MEM_callocN(sizeof(bActionGroup), "bActionGroup"); - + grp->flag = AGRP_SELECTED; BLI_strncpy(grp->name, bone_name, sizeof(grp->name)); - + BLI_addtail(&act->groups, grp); BLI_uniquename(&act->groups, grp, CTX_DATA_(BLT_I18NCONTEXT_ID_ACTION, "Group"), '.', offsetof(bActionGroup, name), 64); } - + /* add F-Curve to group */ action_groups_add_channel(act, grp, fcu); fcurve_is_used(fcu); - + } #if 0 if (is_rotation) { @@ -263,7 +263,7 @@ bool AnimationImporter::write_animation(const COLLADAFW::Animation *anim) { if (anim->getAnimationType() == COLLADAFW::Animation::ANIMATION_CURVE) { COLLADAFW::AnimationCurve *curve = (COLLADAFW::AnimationCurve *)anim; - + // XXX Don't know if it's necessary // Should we check outPhysicalDimension? if (curve->getInPhysicalDimension() != COLLADAFW::PHYSICAL_DIMENSION_TIME) { @@ -296,10 +296,10 @@ bool AnimationImporter::write_animation(const COLLADAFW::Animation *anim) else { fprintf(stderr, "FORMULA animation type is not supported yet.\n"); } - + return true; } - + // called on post-process stage after writeVisualScenes bool AnimationImporter::write_animation_list(const COLLADAFW::AnimationList *animlist) { @@ -340,16 +340,16 @@ virtual void AnimationImporter::change_eul_to_quat(Object *ob, bAction *act) { bActionGroup *grp; int i; - + for (grp = (bActionGroup *)act->groups.first; grp; grp = grp->next) { FCurve *eulcu[3] = {NULL, NULL, NULL}; - + if (fcurves_actionGroup_map.find(grp) == fcurves_actionGroup_map.end()) continue; std::vector<FCurve *> &rot_fcurves = fcurves_actionGroup_map[grp]; - + if (rot_fcurves.size() > 3) continue; for (i = 0; i < rot_fcurves.size(); i++) @@ -437,7 +437,7 @@ void AnimationImporter::modify_fcurve(std::vector<FCurve *> *curves, const char for (it = curves->begin(), i = 0; it != curves->end(); it++, i++) { FCurve *fcu = *it; fcu->rna_path = BLI_strdup(rna_path); - + if (array_index == -1) fcu->array_index = i; else fcu->array_index = array_index; @@ -674,7 +674,7 @@ void AnimationImporter:: Assign_float_animations(const COLLADAFW::UniqueId& list } } } - + } float AnimationImporter::convert_to_focal_length(float in_xfov, int fov_type, float aspect, float sensorx) @@ -711,7 +711,7 @@ void AnimationImporter::Assign_lens_animations(const COLLADAFW::UniqueId& listid //Add the curves of the current animation to the object for (iter = animcurves.begin(); iter != animcurves.end(); iter++) { FCurve *fcu = *iter; - + for (unsigned int i = 0; i < fcu->totvert; i++) { fcu->bezt[i].vec[0][1] = convert_to_focal_length(fcu->bezt[i].vec[0][1], fov_type, aspect, cam->sensor_x); fcu->bezt[i].vec[1][1] = convert_to_focal_length(fcu->bezt[i].vec[1][1], fov_type, aspect, cam->sensor_x); @@ -725,7 +725,7 @@ void AnimationImporter::Assign_lens_animations(const COLLADAFW::UniqueId& listid } } -void AnimationImporter::apply_matrix_curves(Object *ob, std::vector<FCurve *>& animcurves, COLLADAFW::Node *root, COLLADAFW::Node *node, +void AnimationImporter::apply_matrix_curves(Main *bmain, Object *ob, std::vector<FCurve *>& animcurves, COLLADAFW::Node *root, COLLADAFW::Node *node, COLLADAFW::Transformation *tm) { bool is_joint = node->getType() == COLLADAFW::Node::JOINT; @@ -840,7 +840,7 @@ void AnimationImporter::apply_matrix_curves(Object *ob, std::vector<FCurve *>& a add_bezt(newcu[i], fra, scale[i - 7]); } } - verify_adt_action((ID *)&ob->id, 1); + verify_adt_action(bmain, (ID *)&ob->id, 1); ListBase *curves = &ob->adt->action->curves; @@ -897,18 +897,18 @@ static const double get_aspect_ratio(const COLLADAFW::Camera *camera) return aspect; } -static ListBase &get_animation_curves(Material *ma) +static ListBase &get_animation_curves(Main *bmain, Material *ma) { bAction *act; if (!ma->adt || !ma->adt->action) - act = verify_adt_action((ID *)&ma->id, 1); + act = verify_adt_action(bmain, (ID *)&ma->id, 1); else act = ma->adt->action; return act->curves; } -void AnimationImporter::translate_Animations(COLLADAFW::Node *node, +void AnimationImporter::translate_Animations(Main *bmain, COLLADAFW::Node *node, std::map<COLLADAFW::UniqueId, COLLADAFW::Node *>& root_map, std::multimap<COLLADAFW::UniqueId, Object *>& object_map, std::map<COLLADAFW::UniqueId, const COLLADAFW::Object *> FW_object_map, @@ -941,7 +941,7 @@ void AnimationImporter::translate_Animations(COLLADAFW::Node *node, armature_importer->get_rna_path_for_joint(node, joint_path, sizeof(joint_path)); - if (!ob->adt || !ob->adt->action) act = verify_adt_action((ID *)&ob->id, 1); + if (!ob->adt || !ob->adt->action) act = verify_adt_action(bmain, (ID *)&ob->id, 1); else act = ob->adt->action; //Get the list of animation curves of the object @@ -949,7 +949,7 @@ void AnimationImporter::translate_Animations(COLLADAFW::Node *node, const COLLADAFW::TransformationPointerArray& nodeTransforms = node->getTransformations(); - //for each transformation in node + //for each transformation in node for (unsigned int i = 0; i < nodeTransforms.getCount(); i++) { COLLADAFW::Transformation *transform = nodeTransforms[i]; COLLADAFW::Transformation::TransformationType tm_type = transform->getTransformationType(); @@ -972,12 +972,11 @@ void AnimationImporter::translate_Animations(COLLADAFW::Node *node, for (unsigned int j = 0; j < bindings.getCount(); j++) { animcurves = curve_map[bindings[j].animation]; if (is_matrix) { - apply_matrix_curves(ob, animcurves, root, node, transform); + apply_matrix_curves(bmain, ob, animcurves, root, node, transform); } - else { - + else { if (is_joint) { - add_bone_animation_sampled(ob, animcurves, root, node, transform); + add_bone_animation_sampled(bmain, ob, animcurves, root, node, transform); } else { //calculate rnapaths and array index of fcurves according to transformation and animation class @@ -987,12 +986,12 @@ void AnimationImporter::translate_Animations(COLLADAFW::Node *node, //Add the curves of the current animation to the object for (iter = animcurves.begin(); iter != animcurves.end(); iter++) { FCurve *fcu = *iter; - + BLI_addtail(AnimCurves, fcu); fcurve_is_used(fcu); } } - + } } } @@ -1005,7 +1004,7 @@ void AnimationImporter::translate_Animations(COLLADAFW::Node *node, if ((animType->light) != 0) { Lamp *lamp = (Lamp *) ob->data; - if (!lamp->adt || !lamp->adt->action) act = verify_adt_action((ID *)&lamp->id, 1); + if (!lamp->adt || !lamp->adt->action) act = verify_adt_action(bmain, (ID *)&lamp->id, 1); else act = lamp->adt->action; ListBase *AnimCurves = &(act->curves); @@ -1018,7 +1017,7 @@ void AnimationImporter::translate_Animations(COLLADAFW::Node *node, const COLLADAFW::Color *col = &(light->getColor()); const COLLADAFW::UniqueId& listid = col->getAnimationList(); - Assign_color_animations(listid, AnimCurves, "color"); + Assign_color_animations(listid, AnimCurves, "color"); } if ((animType->light & LIGHT_FOA) != 0) { const COLLADAFW::AnimatableFloat *foa = &(light->getFallOffAngle()); @@ -1039,7 +1038,7 @@ void AnimationImporter::translate_Animations(COLLADAFW::Node *node, if (animType->camera != 0) { Camera *cam = (Camera *) ob->data; if (!cam->adt || !cam->adt->action) - act = verify_adt_action((ID *)&cam->id, 1); + act = verify_adt_action(bmain, (ID *)&cam->id, 1); else act = cam->adt->action; @@ -1052,14 +1051,14 @@ void AnimationImporter::translate_Animations(COLLADAFW::Node *node, if ((animType->camera & CAMERA_XFOV) != 0) { const COLLADAFW::AnimatableFloat *xfov = &(camera->getXFov()); const COLLADAFW::UniqueId& listid = xfov->getAnimationList(); - double aspect = get_aspect_ratio(camera); + double aspect = get_aspect_ratio(camera); Assign_lens_animations(listid, AnimCurves, aspect, cam, "lens", CAMERA_XFOV); } else if ((animType->camera & CAMERA_YFOV) != 0) { const COLLADAFW::AnimatableFloat *yfov = &(camera->getYFov()); const COLLADAFW::UniqueId& listid = yfov->getAnimationList(); - double aspect = get_aspect_ratio(camera); + double aspect = get_aspect_ratio(camera); Assign_lens_animations(listid, AnimCurves, aspect, cam, "lens", CAMERA_YFOV); } @@ -1103,7 +1102,7 @@ void AnimationImporter::translate_Animations(COLLADAFW::Node *node, fprintf(stderr, "Collada: Node %s refers to undefined material\n", node->getName().c_str()); continue; } - ListBase &AnimCurves = get_animation_curves(ma); + ListBase &AnimCurves = get_animation_curves(bmain, ma); const COLLADAFW::CommonEffectPointerArray& commonEffects = ef->getCommonEffects(); COLLADAFW::EffectCommon *efc = commonEffects[0]; if ((animType->material & MATERIAL_SHININESS) != 0) { @@ -1137,7 +1136,7 @@ void AnimationImporter::translate_Animations(COLLADAFW::Node *node, delete animType; } -void AnimationImporter::add_bone_animation_sampled(Object *ob, std::vector<FCurve *>& animcurves, COLLADAFW::Node *root, COLLADAFW::Node *node, COLLADAFW::Transformation *tm) +void AnimationImporter::add_bone_animation_sampled(Main *bmain, Object *ob, std::vector<FCurve *>& animcurves, COLLADAFW::Node *root, COLLADAFW::Node *node, COLLADAFW::Transformation *tm) { const char *bone_name = bc_get_joint_name(node); char joint_path[200]; @@ -1260,7 +1259,7 @@ void AnimationImporter::add_bone_animation_sampled(Object *ob, std::vector<FCurv add_bezt(newcu[i], fra, scale[i - 7]); } } - verify_adt_action((ID *)&ob->id, 1); + verify_adt_action(bmain, (ID *)&ob->id, 1); // add curves for (int i = 0; i < totcu; i++) { @@ -1282,7 +1281,7 @@ AnimationImporter::AnimMix *AnimationImporter::get_animation_type(const COLLADAF const COLLADAFW::TransformationPointerArray& nodeTransforms = node->getTransformations(); - //for each transformation in node + //for each transformation in node for (unsigned int i = 0; i < nodeTransforms.getCount(); i++) { COLLADAFW::Transformation *transform = nodeTransforms[i]; const COLLADAFW::UniqueId& listid = transform->getAnimationList(); @@ -1370,7 +1369,7 @@ int AnimationImporter::setAnimType(const COLLADAFW::Animatable *prop, int types, anim_type = types; return anim_type; -} +} // Is not used anymore. void AnimationImporter::find_frames_old(std::vector<float> *frames, COLLADAFW::Node *node, COLLADAFW::Transformation::TransformationType tm_type) @@ -1392,7 +1391,7 @@ void AnimationImporter::find_frames_old(std::vector<float> *frames, COLLADAFW::N const COLLADAFW::UniqueId& listid = transform->getAnimationList(); //if transform is animated its animlist must exist. if (animlist_map.find(listid) != animlist_map.end()) { - + const COLLADAFW::AnimationList *animlist = animlist_map[listid]; const COLLADAFW::AnimationList::AnimationBindings& bindings = animlist->getAnimationBindings(); @@ -1436,17 +1435,17 @@ void AnimationImporter::find_frames_old(std::vector<float> *frames, COLLADAFW::N // prerequisites: // animlist_map - map animlist id -> animlist // curve_map - map anim id -> curve(s) -Object *AnimationImporter::translate_animation_OLD(COLLADAFW::Node *node, +Object *AnimationImporter::translate_animation_OLD(Main *bmain, COLLADAFW::Node *node, std::map<COLLADAFW::UniqueId, Object *>& object_map, std::map<COLLADAFW::UniqueId, COLLADAFW::Node *>& root_map, COLLADAFW::Transformation::TransformationType tm_type, Object *par_job) { - + bool is_rotation = tm_type == COLLADAFW::Transformation::ROTATE; bool is_matrix = tm_type == COLLADAFW::Transformation::MATRIX; bool is_joint = node->getType() == COLLADAFW::Node::JOINT; - + COLLADAFW::Node *root = root_map.find(node->getUniqueId()) == root_map.end() ? node : root_map[node->getUniqueId()]; Object *ob = is_joint ? armature_importer->get_armature_for_joint(node) : object_map[node->getUniqueId()]; const char *bone_name = is_joint ? bc_get_joint_name(node) : NULL; @@ -1457,11 +1456,11 @@ Object *AnimationImporter::translate_animation_OLD(COLLADAFW::Node *node, // frames at which to sample std::vector<float> frames; - + find_frames_old(&frames, node, tm_type); - + unsigned int i; - + float irest_dae[4][4]; float rest[4][4], irest[4][4]; @@ -1659,7 +1658,7 @@ Object *AnimationImporter::translate_animation_OLD(COLLADAFW::Node *node, #endif } - verify_adt_action((ID *)&ob->id, 1); + verify_adt_action(bmain, (ID *)&ob->id, 1); ListBase *curves = &ob->adt->action->curves; @@ -1732,9 +1731,9 @@ void AnimationImporter::evaluate_transform_at_frame(float mat[4][4], COLLADAFW:: } } -static void report_class_type_unsupported(const char *path, +static void report_class_type_unsupported(const char *path, const COLLADAFW::AnimationList::AnimationClass animclass, - const COLLADAFW::Transformation::TransformationType type) + const COLLADAFW::Transformation::TransformationType type) { if (animclass == COLLADAFW::AnimationList::UNKNOWN_CLASS) { fprintf(stderr, "%s: UNKNOWN animation class\n", path); @@ -1829,7 +1828,7 @@ bool AnimationImporter::evaluate_animation(COLLADAFW::Transformation *tm, float fprintf(stderr, "%s: expected 1 curve, got %d\n", path, (int)curves.size()); return false; } - + switch (animclass) { case COLLADAFW::AnimationList::POSITION_X: vec[0] = evaluate_fcurve(curves[0], fra); @@ -2011,7 +2010,7 @@ void AnimationImporter::add_bone_fcurve(Object *ob, COLLADAFW::Node *node, FCurv { const char *bone_name = bc_get_joint_name(node); bAction *act = ob->adt->action; - + /* try to find group */ bActionGroup *grp = BKE_action_group_find_name(act, bone_name); diff --git a/source/blender/collada/AnimationImporter.h b/source/blender/collada/AnimationImporter.h index e25116cac9f..f63329158f0 100644 --- a/source/blender/collada/AnimationImporter.h +++ b/source/blender/collada/AnimationImporter.h @@ -19,7 +19,7 @@ * * ***** END GPL LICENSE BLOCK ***** */ - + /** \file AnimationImporter.h * \ingroup collada */ @@ -75,9 +75,9 @@ private: std::map<COLLADAFW::UniqueId, const COLLADAFW::AnimationList*> animlist_map; std::vector<FCurve*> unused_curves; std::map<COLLADAFW::UniqueId, Object*> joint_objects; - + FCurve *create_fcurve(int array_index, const char *rna_path); - + void add_bezt(FCurve *fcu, float frame, float value, eBezTriple_Interpolation ipo=BEZT_IPO_LIN); // create one or several fcurves depending on the number of parameters being animated @@ -87,9 +87,9 @@ private: void fcurve_is_used(FCurve *fcu); - void add_fcurves_to_object(Object *ob, std::vector<FCurve*>& curves, char *rna_path, int array_index, Animation *animated); + void add_fcurves_to_object(Main *bmain, Object *ob, std::vector<FCurve*>& curves, char *rna_path, int array_index, Animation *animated); + - int typeFlag; std::string import_from_version; @@ -121,7 +121,7 @@ private: MATERIAL_TRANSPARENCY = 1 << 4, MATERIAL_IOR = 1 << 5 }; - + enum AnimationType { INANIMATE = 0, @@ -144,7 +144,7 @@ public: void set_import_from_version(std::string import_from_version); bool write_animation(const COLLADAFW::Animation* anim); - + // called on post-process stage after writeVisualScenes bool write_animation_list(const COLLADAFW::AnimationList* animlist); @@ -153,7 +153,7 @@ public: virtual void change_eul_to_quat(Object *ob, bAction *act); #endif - void translate_Animations(COLLADAFW::Node * Node, + void translate_Animations(Main *bmain, COLLADAFW::Node * Node, std::map<COLLADAFW::UniqueId, COLLADAFW::Node*>& root_map, std::multimap<COLLADAFW::UniqueId, Object*>& object_map, std::map<COLLADAFW::UniqueId, const COLLADAFW::Object*> FW_object_map, @@ -161,10 +161,10 @@ public: AnimMix* get_animation_type( const COLLADAFW::Node * node, std::map<COLLADAFW::UniqueId, const COLLADAFW::Object*> FW_object_map ); - void apply_matrix_curves(Object *ob, std::vector<FCurve*>& animcurves, COLLADAFW::Node* root, COLLADAFW::Node* node, + void apply_matrix_curves(Main *bmain, Object *ob, std::vector<FCurve*>& animcurves, COLLADAFW::Node* root, COLLADAFW::Node* node, COLLADAFW::Transformation * tm ); - - void add_bone_animation_sampled(Object *ob, std::vector<FCurve*>& animcurves, COLLADAFW::Node* root, COLLADAFW::Node* node, COLLADAFW::Transformation * tm); + + void add_bone_animation_sampled(Main *bmain, Object *ob, std::vector<FCurve*>& animcurves, COLLADAFW::Node* root, COLLADAFW::Node* node, COLLADAFW::Transformation * tm); void Assign_transform_animations(COLLADAFW::Transformation* transform, const COLLADAFW::AnimationList::AnimationBinding *binding, @@ -175,18 +175,18 @@ public: void Assign_lens_animations(const COLLADAFW::UniqueId& listid, ListBase *AnimCurves, const double aspect, Camera *cam, const char *anim_type, int fov_type); int setAnimType ( const COLLADAFW::Animatable * prop, int type, int addition); - + void modify_fcurve(std::vector<FCurve*>* curves, const char *rna_path, int array_index ); void unused_fcurve(std::vector<FCurve*>* curves ); // prerequisites: // animlist_map - map animlist id -> animlist // curve_map - map anim id -> curve(s) - Object * translate_animation_OLD(COLLADAFW::Node *node, + Object * translate_animation_OLD(Main *bmain, COLLADAFW::Node *node, std::map<COLLADAFW::UniqueId, Object*>& object_map, std::map<COLLADAFW::UniqueId, COLLADAFW::Node*>& root_map, COLLADAFW::Transformation::TransformationType tm_type, Object *par_job = NULL); - + void find_frames( std::vector<float>* frames, std::vector<FCurve*>* curves ); void find_frames_old( std::vector<float>* frames, COLLADAFW::Node * node, COLLADAFW::Transformation::TransformationType tm_type ); // internal, better make it private diff --git a/source/blender/collada/ArmatureExporter.cpp b/source/blender/collada/ArmatureExporter.cpp index 5e349535610..85b9d3297ca 100644 --- a/source/blender/collada/ArmatureExporter.cpp +++ b/source/blender/collada/ArmatureExporter.cpp @@ -62,10 +62,11 @@ ArmatureExporter::ArmatureExporter(COLLADASW::StreamWriter *sw, const ExportSett } // write bone nodes -void ArmatureExporter::add_armature_bones(Depsgraph *depsgraph, Object *ob_arm, +void ArmatureExporter::add_armature_bones(bContext *C, Depsgraph *depsgraph, Object *ob_arm, Scene *sce, SceneExporter *se, std::list<Object *>& child_objects) { + Main *bmain = CTX_data_main(C); // write bone nodes bArmature * armature = (bArmature *)ob_arm->data; @@ -77,11 +78,11 @@ void ArmatureExporter::add_armature_bones(Depsgraph *depsgraph, Object *ob_arm, for (Bone *bone = (Bone *)armature->bonebase.first; bone; bone = bone->next) { // start from root bones if (!bone->parent) - add_bone_node(depsgraph, bone, ob_arm, sce, se, child_objects); + add_bone_node(C, depsgraph, bone, ob_arm, sce, se, child_objects); } if (!is_edited) { - ED_armature_from_edit(armature); + ED_armature_from_edit(bmain, armature); ED_armature_edit_free(armature); } } @@ -117,7 +118,7 @@ bool ArmatureExporter::add_instance_controller(Object *ob) } InstanceWriter::add_material_bindings(ins.getBindMaterial(), ob, this->export_settings->active_uv_only); - + ins.add(); return true; } @@ -146,7 +147,7 @@ void ArmatureExporter::find_objects_using_armature(Object *ob_arm, std::vector<O Base *base = (Base *) sce->base.first; while (base) { Object *ob = base->object; - + if (ob->type == OB_MESH && get_assigned_armature(ob) == ob_arm) { objects.push_back(ob); } @@ -157,7 +158,7 @@ void ArmatureExporter::find_objects_using_armature(Object *ob_arm, std::vector<O #endif // parent_mat is armature-space -void ArmatureExporter::add_bone_node(Depsgraph *depsgraph, Bone *bone, Object *ob_arm, Scene *sce, +void ArmatureExporter::add_bone_node(bContext *C, Depsgraph *depsgraph, Bone *bone, Object *ob_arm, Scene *sce, SceneExporter *se, std::list<Object *>& child_objects) { @@ -231,7 +232,7 @@ void ArmatureExporter::add_bone_node(Depsgraph *depsgraph, Bone *bone, Object *o mul_m4_m4m4((*i)->parentinv, temp, (*i)->parentinv); } - se->writeNodes(depsgraph, *i, sce); + se->writeNodes(C, depsgraph, *i, sce); copy_m4_m4((*i)->parentinv, backup_parinv); child_objects.erase(i++); @@ -240,13 +241,13 @@ void ArmatureExporter::add_bone_node(Depsgraph *depsgraph, Bone *bone, Object *o } for (Bone *child = (Bone *)bone->childbase.first; child; child = child->next) { - add_bone_node(depsgraph, child, ob_arm, sce, se, child_objects); + add_bone_node(C, depsgraph, child, ob_arm, sce, se, child_objects); } node.end(); } else { for (Bone *child = (Bone *)bone->childbase.first; child; child = child->next) { - add_bone_node(depsgraph, child, ob_arm, sce, se, child_objects); + add_bone_node(C, depsgraph, child, ob_arm, sce, se, child_objects); } } } @@ -264,7 +265,7 @@ void ArmatureExporter::add_bone_transform(Object *ob_arm, Bone *bone, COLLADASW: if (!has_restmat) { /* Have no restpose matrix stored, try old style <= Blender 2.78 */ - + bc_create_restpose_mat(this->export_settings, bone, bone_rest_mat, bone->arm_mat, true); if (bone->parent) { diff --git a/source/blender/collada/ArmatureExporter.h b/source/blender/collada/ArmatureExporter.h index 17c02d637e8..7efa8b70e43 100644 --- a/source/blender/collada/ArmatureExporter.h +++ b/source/blender/collada/ArmatureExporter.h @@ -60,7 +60,7 @@ public: ArmatureExporter(COLLADASW::StreamWriter *sw, const ExportSettings *export_settings); // write bone nodes - void add_armature_bones(struct Depsgraph *depsgraph, Object *ob_arm, Scene *sce, SceneExporter *se, + void add_armature_bones(bContext *C, struct Depsgraph *depsgraph, Object *ob_arm, Scene *sce, SceneExporter *se, std::list<Object *>& child_objects); bool add_instance_controller(Object *ob); @@ -85,7 +85,7 @@ private: // Scene, SceneExporter and the list of child_objects // are required for writing bone parented objects - void add_bone_node(struct Depsgraph *depsgraph, Bone *bone, Object *ob_arm, Scene *sce, SceneExporter *se, + void add_bone_node(bContext *C, struct Depsgraph *depsgraph, Bone *bone, Object *ob_arm, Scene *sce, SceneExporter *se, std::list<Object *>& child_objects); void add_bone_transform(Object *ob_arm, Bone *bone, COLLADASW::Node& node); diff --git a/source/blender/collada/ArmatureImporter.cpp b/source/blender/collada/ArmatureImporter.cpp index f24688479af..19f174d4840 100644 --- a/source/blender/collada/ArmatureImporter.cpp +++ b/source/blender/collada/ArmatureImporter.cpp @@ -61,7 +61,7 @@ ArmatureImporter::ArmatureImporter(UnitConverter *conv, MeshImporterBase *mesh, view_layer(view_layer), unit_converter(conv), import_settings(import_settings), - empty(NULL), + empty(NULL), mesh_importer(mesh) { } @@ -103,7 +103,7 @@ int ArmatureImporter::create_bone(SkinInfo *skin, COLLADAFW::Node *node, EditBon std::vector<COLLADAFW::Node *>::iterator it; it = std::find(finished_joints.begin(), finished_joints.end(), node); if (it != finished_joints.end()) return chain_length; - + EditBone *bone = ED_armature_ebone_add(arm, bc_get_joint_name(node)); totbone++; @@ -141,7 +141,7 @@ int ArmatureImporter::create_bone(SkinInfo *skin, COLLADAFW::Node *node, EditBon if (parent) bone->parent = parent; - float loc[3], size[3], rot[3][3]; + float loc[3], size[3], rot[3][3]; BoneExtensionMap &extended_bones = bone_extension_manager.getExtensionMap(arm); BoneExtended &be = add_bone_extended(bone, node, totchild, layer_labels, extended_bones); int layer = be.get_bone_layers(); @@ -386,7 +386,7 @@ void ArmatureImporter::set_euler_rotmode() COLLADAFW::Node *joint = it->second; std::map<COLLADAFW::UniqueId, SkinInfo>::iterator sit; - + for (sit = skin_by_data_uid.begin(); sit != skin_by_data_uid.end(); sit++) { SkinInfo& skin = sit->second; @@ -410,7 +410,7 @@ void ArmatureImporter::set_euler_rotmode() Object *ArmatureImporter::get_empty_for_leaves() { if (empty) return empty; - + empty = bc_add_object(scene, view_layer, OB_EMPTY, NULL); empty->empty_drawtype = OB_EMPTY_SPHERE; @@ -448,7 +448,7 @@ ArmatureJoints& ArmatureImporter::get_armature_joints(Object *ob_arm) return armature_joints.back(); } #endif -void ArmatureImporter::create_armature_bones(std::vector<Object *> &ob_arms) +void ArmatureImporter::create_armature_bones(Main *bmain, std::vector<Object *> &ob_arms) { std::vector<COLLADAFW::Node *>::iterator ri; std::vector<std::string> layer_labels; @@ -456,7 +456,7 @@ void ArmatureImporter::create_armature_bones(std::vector<Object *> &ob_arms) //if there is an armature created for root_joint next root_joint for (ri = root_joints.begin(); ri != root_joints.end(); ri++) { if (get_armature_for_joint(*ri) != NULL) continue; - + Object *ob_arm = joint_parent_map[(*ri)->getUniqueId()]; if (!ob_arm) continue; @@ -481,7 +481,7 @@ void ArmatureImporter::create_armature_bones(std::vector<Object *> &ob_arms) } /* exit armature edit mode to populate the Armature object */ - ED_armature_from_edit(armature); + ED_armature_from_edit(bmain, armature); ED_armature_edit_free(armature); ED_armature_to_edit(armature); @@ -489,7 +489,7 @@ void ArmatureImporter::create_armature_bones(std::vector<Object *> &ob_arms) fix_leaf_bone_hierarchy(armature, (Bone *)armature->bonebase.first, this->import_settings->fix_orientation); unskinned_armature_map[(*ri)->getUniqueId()] = ob_arm; - ED_armature_from_edit(armature); + ED_armature_from_edit(bmain, armature); ED_armature_edit_free(armature); int index = std::find(ob_arms.begin(), ob_arms.end(), ob_arm) - ob_arms.begin(); @@ -501,7 +501,7 @@ void ArmatureImporter::create_armature_bones(std::vector<Object *> &ob_arms) } } -Object *ArmatureImporter::create_armature_bones(SkinInfo& skin) +Object *ArmatureImporter::create_armature_bones(Main *bmain, SkinInfo& skin) { // just do like so: // - get armature @@ -572,8 +572,8 @@ Object *ArmatureImporter::create_armature_bones(SkinInfo& skin) } if (!shared && this->joint_parent_map.size() > 0) { - // All armatures have been created while creating the Node tree. - // The Collada exporter currently does not create a + // All armatures have been created while creating the Node tree. + // The Collada exporter currently does not create a // strict relationship between geometries and armatures // So when we reimport a Blender collada file, then we have // to guess what is meant. @@ -619,7 +619,7 @@ Object *ArmatureImporter::create_armature_bones(SkinInfo& skin) } /* exit armature edit mode to populate the Armature object */ - ED_armature_from_edit(armature); + ED_armature_from_edit(bmain, armature); ED_armature_edit_free(armature); ED_armature_to_edit(armature); @@ -627,7 +627,7 @@ Object *ArmatureImporter::create_armature_bones(SkinInfo& skin) connect_bone_chains(armature, (Bone *)armature->bonebase.first, UNLIMITED_CHAIN_MAX); } fix_leaf_bone_hierarchy(armature, (Bone *)armature->bonebase.first, this->import_settings->fix_orientation); - ED_armature_from_edit(armature); + ED_armature_from_edit(bmain, armature); ED_armature_edit_free(armature); DEG_id_tag_update(&ob_arm->id, OB_RECALC_OB | OB_RECALC_DATA); @@ -657,12 +657,12 @@ void ArmatureImporter::set_pose(Object *ob_arm, COLLADAFW::Node *root_node, con } else { - + copy_m4_m4(mat, obmat); float invObmat[4][4]; invert_m4_m4(invObmat, ob_arm->obmat); mul_m4_m4m4(pchan->pose_mat, invObmat, mat); - + } //float angle = 0.0f; @@ -709,6 +709,7 @@ void ArmatureImporter::add_root_joint(COLLADAFW::Node *node) // here we add bones to armatures, having armatures previously created in write_controller void ArmatureImporter::make_armatures(bContext *C, std::vector<Object *> &objects_to_scale) { + Main *bmain = CTX_data_main(C); std::vector<Object *> ob_arms; std::map<COLLADAFW::UniqueId, SkinInfo>::iterator it; @@ -718,7 +719,7 @@ void ArmatureImporter::make_armatures(bContext *C, std::vector<Object *> &object SkinInfo& skin = it->second; - Object *ob_arm = create_armature_bones(skin); + Object *ob_arm = create_armature_bones(bmain, skin); // link armature with a mesh object const COLLADAFW::UniqueId &uid = skin.get_controller_uid(); @@ -757,9 +758,9 @@ void ArmatureImporter::make_armatures(bContext *C, std::vector<Object *> &object // free memory stolen from SkinControllerData skin.free(); } - + //for bones without skins - create_armature_bones(ob_arms); + create_armature_bones(bmain, ob_arms); // Fix bone relations std::vector<Object *>::iterator ob_arm_it; @@ -773,7 +774,7 @@ void ArmatureImporter::make_armatures(bContext *C, std::vector<Object *> &object fix_parent_connect(armature, (Bone *)armature->bonebase.first); - ED_armature_from_edit(armature); + ED_armature_from_edit(bmain, armature); ED_armature_edit_free(armature); } } @@ -807,9 +808,9 @@ bool ArmatureImporter::write_skin_controller_data(const COLLADAFW::SkinControlle // don't forget to call defgroup_unique_name before we copy - // controller data uid -> [armature] -> joint data, + // controller data uid -> [armature] -> joint data, // [mesh object] - // + // SkinInfo skin(unit_converter); skin.borrow_skin_controller_data(data); @@ -867,7 +868,7 @@ void ArmatureImporter::make_shape_keys() //Prereq: all the geometries must be imported and mesh objects must be made Object *source_ob = this->mesh_importer->get_object_by_geom_uid((*mc)->getSource()); - + if (source_ob) { Mesh *source_me = (Mesh *)source_ob->data; @@ -875,7 +876,7 @@ void ArmatureImporter::make_shape_keys() Key *key = source_me->key = BKE_key_add((ID *)source_me); key->type = KEY_RELATIVE; KeyBlock *kb; - + //insert basis key kb = BKE_keyblock_add_ctime(key, "Basis", false); BKE_keyblock_convert_from_mesh(source_me, kb); @@ -886,14 +887,14 @@ void ArmatureImporter::make_shape_keys() //This'll do for now since only mesh morphing is imported Mesh *me = this->mesh_importer->get_mesh_by_geom_uid(morphTargetIds[i]); - + if (me) { me->key = key; std::string morph_name = *this->mesh_importer->get_geometry_name(me->id.name); kb = BKE_keyblock_add_ctime(key, morph_name.c_str(), false); BKE_keyblock_convert_from_mesh(me, kb); - + //apply weights weight = morphWeights.getFloatValues()->getData()[i]; kb->curval = weight; @@ -989,14 +990,14 @@ BoneExtended &ArmatureImporter::add_bone_extended(EditBone *bone, COLLADAFW::Nod has_connect = et->setData("connect", &connect_type); bool has_roll = et->setData("roll", &roll); - + layers = et->setData("layer", layers); if (has_tail && !has_connect) { /* got a bone tail definition but no connect info -> bone is not connected */ has_connect = true; - connect_type = 0; + connect_type = 0; } be->set_bone_layers(layers, layer_labels); diff --git a/source/blender/collada/ArmatureImporter.h b/source/blender/collada/ArmatureImporter.h index f260bb2307c..b13e40bf855 100644 --- a/source/blender/collada/ArmatureImporter.h +++ b/source/blender/collada/ArmatureImporter.h @@ -130,8 +130,8 @@ private: ArmatureJoints& get_armature_joints(Object *ob_arm); #endif - Object *create_armature_bones(SkinInfo& skin); - void create_armature_bones(std::vector<Object *> &arm_objs); + Object *create_armature_bones(Main *bmain, SkinInfo& skin); + void create_armature_bones(Main *bmain, std::vector<Object *> &arm_objs); /** TagsMap typedef for uid_tags_map. */ typedef std::map<std::string, ExtraTags*> TagsMap; @@ -158,16 +158,16 @@ public: bool write_controller(const COLLADAFW::Controller* controller); COLLADAFW::UniqueId *get_geometry_uid(const COLLADAFW::UniqueId& controller_uid); - + Object *get_armature_for_joint(COLLADAFW::Node *node); void get_rna_path_for_joint(COLLADAFW::Node *node, char *joint_path, size_t count); - + // gives a world-space mat bool get_joint_bind_mat(float m[4][4], COLLADAFW::Node *joint); void set_tags_map( TagsMap& tags_map); - + }; #endif diff --git a/source/blender/collada/CameraExporter.cpp b/source/blender/collada/CameraExporter.cpp index 649288c2db4..32bd24f1e0b 100644 --- a/source/blender/collada/CameraExporter.cpp +++ b/source/blender/collada/CameraExporter.cpp @@ -56,9 +56,9 @@ void forEachCameraObjectInExportSet(Scene *sce, Functor &f, LinkNode *export_set void CamerasExporter::exportCameras(Scene *sce) { openLibrary(); - + forEachCameraObjectInExportSet(sce, *this, this->export_settings->export_set); - + closeLibrary(); } void CamerasExporter::operator()(Object *ob, Scene *sce) diff --git a/source/blender/collada/ControllerExporter.cpp b/source/blender/collada/ControllerExporter.cpp index f6dbc965b42..122094e33a6 100644 --- a/source/blender/collada/ControllerExporter.cpp +++ b/source/blender/collada/ControllerExporter.cpp @@ -99,7 +99,7 @@ bool ControllerExporter::add_instance_controller(Object *ob) } InstanceWriter::add_material_bindings(ins.getBindMaterial(), ob, this->export_settings->active_uv_only); - + ins.add(); return true; } @@ -148,7 +148,7 @@ void ArmatureExporter::find_objects_using_armature(Object *ob_arm, std::vector<O Base *base = (Base *) sce->base.first; while (base) { Object *ob = base->object; - + if (ob->type == OB_MESH && get_assigned_armature(ob) == ob_arm) { objects.push_back(ob); } @@ -203,7 +203,7 @@ void ControllerExporter::export_skin_controller(Object *ob, Object *ob_arm) this->export_settings->export_mesh_type, this->export_settings->apply_modifiers, this->export_settings->triangulate); - + if (!me->dvert) return; std::string controller_name = id_name(ob_arm); @@ -246,7 +246,7 @@ void ControllerExporter::export_skin_controller(Object *ob, Object *ob_arm) for (j = 0; j < vert->totweight; j++) { int idx = vert->dw[j].def_nr; if (idx >= joint_index_by_def_index.size()) { - // XXX: Maybe better find out where and + // XXX: Maybe better find out where and // why the Out Of Bound indexes get created ? oob_counter += 1; } @@ -314,7 +314,7 @@ void ControllerExporter::export_morph_controller(Object *ob, Key *key) std::string targets_id = add_morph_targets(key, ob); std::string morph_weights_id = add_morph_weights(key, ob); - + COLLADASW::TargetsElement targets(mSW); COLLADASW::InputList &input = targets.getInputList(); @@ -376,7 +376,7 @@ std::string ControllerExporter::add_morph_weights(Key *key, Object *ob) COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList(); param.push_back("MORPH_WEIGHT"); - + source.prepareToAppendValues(); KeyBlock *kb = (KeyBlock *)key->block.first; @@ -396,7 +396,7 @@ void ControllerExporter::add_weight_extras(Key *key) { // can also try the base element and param alternative COLLADASW::BaseExtraTechnique extra; - + KeyBlock * kb = (KeyBlock *)key->block.first; //skip the basis kb = kb->next; @@ -447,7 +447,7 @@ std::string ControllerExporter::add_joints_source(Object *ob_arm, ListBase *defb source.setArrayId(source_id + ARRAY_ID_SUFFIX); source.setAccessorCount(totjoint); source.setAccessorStride(1); - + COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList(); param.push_back("JOINT"); @@ -480,7 +480,7 @@ std::string ControllerExporter::add_inv_bind_mats_source(Object *ob_arm, ListBas source.setArrayId(source_id + ARRAY_ID_SUFFIX); source.setAccessorCount(totjoint); //BLI_listbase_count(defbase)); source.setAccessorStride(16); - + source.setParameterTypeName(&COLLADASW::CSWC::CSW_VALUE_TYPE_FLOAT4x4); COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList(); param.push_back("TRANSFORM"); @@ -509,7 +509,7 @@ std::string ControllerExporter::add_inv_bind_mats_source(Object *ob_arm, ListBas float bind_mat[4][4]; /* derived from bone->arm_mat */ bool has_bindmat = bc_get_property_matrix(pchan->bone, "bind_mat", bind_mat); - + if (!has_bindmat) { /* Have no bind matrix stored, try old style <= Blender 2.78 */ @@ -571,7 +571,7 @@ std::string ControllerExporter::add_weights_source(Mesh *me, const std::string& source.setArrayId(source_id + ARRAY_ID_SUFFIX); source.setAccessorCount(weights.size()); source.setAccessorStride(1); - + COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList(); param.push_back("WEIGHT"); diff --git a/source/blender/collada/DocumentExporter.cpp b/source/blender/collada/DocumentExporter.cpp index a66c4db7b4d..9e78c164dad 100644 --- a/source/blender/collada/DocumentExporter.cpp +++ b/source/blender/collada/DocumentExporter.cpp @@ -62,7 +62,7 @@ #include "COLLADASWInstanceNode.h" #include "COLLADASWBaseInputElement.h" -extern "C" +extern "C" { #include "DNA_scene_types.h" #include "DNA_object_types.h" @@ -180,8 +180,7 @@ static COLLADABU::NativeString make_temp_filepath(const char *name, const char * // COLLADA allows this through multiple <channel>s in <animation>. // For this to work, we need to know objects that use a certain action. - -int DocumentExporter::exportCurrentScene(Scene *sce) +int DocumentExporter::exportCurrentScene(bContext *C, Scene *sce) { PointerRNA sceneptr, unit_settings; PropertyRNA *system; /* unused , *scale; */ @@ -258,14 +257,14 @@ int DocumentExporter::exportCurrentScene(Scene *sce) #endif asset.getContributor().mAuthoringTool = version_buf; asset.add(); - + LinkNode *export_set = this->export_settings->export_set; // <library_cameras> if (bc_has_object_type(export_set, OB_CAMERA)) { CamerasExporter ce(writer, this->export_settings); ce.exportCameras(sce); } - + // <library_lights> if (bc_has_object_type(export_set, OB_LAMP)) { LightsExporter le(writer, this->export_settings); @@ -275,11 +274,11 @@ int DocumentExporter::exportCurrentScene(Scene *sce) // <library_images> ImagesExporter ie(writer, this->export_settings); ie.exportImages(sce); - + // <library_effects> EffectsExporter ee(writer, this->export_settings); ee.exportEffects(sce); - + // <library_materials> MaterialsExporter me(writer, this->export_settings); me.exportMaterials(sce); @@ -293,7 +292,7 @@ int DocumentExporter::exportCurrentScene(Scene *sce) // <library_controllers> ArmatureExporter arm_exporter(writer, this->export_settings); ControllerExporter controller_exporter(writer, this->export_settings); - if (bc_has_object_type(export_set, OB_ARMATURE) || this->export_settings->include_shapekeys) + if (bc_has_object_type(export_set, OB_ARMATURE) || this->export_settings->include_shapekeys) { controller_exporter.export_controllers(depsgraph, sce); } @@ -307,14 +306,14 @@ int DocumentExporter::exportCurrentScene(Scene *sce) AnimationExporter ae(depsgraph, writer, this->export_settings); ae.exportAnimations(sce); } - se.exportScene(depsgraph, sce); - + se.exportScene(C, depsgraph, sce); + // <scene> std::string scene_name(translate_id(id_name(sce))); COLLADASW::Scene scene(writer, COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, scene_name)); scene.add(); - + // close <Collada> writer->endDocument(); delete writer; diff --git a/source/blender/collada/DocumentExporter.h b/source/blender/collada/DocumentExporter.h index c98f82e68b4..8a48ca29090 100644 --- a/source/blender/collada/DocumentExporter.h +++ b/source/blender/collada/DocumentExporter.h @@ -40,7 +40,7 @@ class DocumentExporter { public: DocumentExporter(Depsgraph *depsgraph, const ExportSettings *export_settings); - int exportCurrentScene(Scene *sce); + int exportCurrentScene(bContext *C, Scene *sce); void exportScenes(const char *filename); private: diff --git a/source/blender/collada/DocumentImporter.cpp b/source/blender/collada/DocumentImporter.cpp index 47b720614ea..ae573fec0d8 100644 --- a/source/blender/collada/DocumentImporter.cpp +++ b/source/blender/collada/DocumentImporter.cpp @@ -130,7 +130,7 @@ bool DocumentImporter::import() COLLADASaxFWL::Loader loader(&errorHandler); COLLADAFW::Root root(&loader, this); ExtraHandler *ehandler = new ExtraHandler(this, &(this->anim_importer)); - + loader.registerExtraDataCallbackHandler(ehandler); // deselect all to select new objects @@ -143,19 +143,19 @@ bool DocumentImporter::import() delete ehandler; return false; } - + if (errorHandler.hasError()) { delete ehandler; return false; } - + /** TODO set up scene graph and such here */ - + mImportStage = Controller; - + COLLADASaxFWL::Loader loader2; COLLADAFW::Root root2(&loader2, this); - + if (!root2.loadDocument(encodedFilename)) { fprintf(stderr, "COLLADAFW::Root::loadDocument() returned false on 2nd pass\n"); delete ehandler; @@ -198,7 +198,7 @@ void DocumentImporter::finish() for (sit = vscenes.begin(); sit != vscenes.end(); sit++) { PointerRNA sceneptr, unit_settings; PropertyRNA *system, *scale; - + // for scene unit settings: system, scale_length RNA_id_pointer_create(&sce->id, &sceneptr); @@ -207,7 +207,7 @@ void DocumentImporter::finish() scale = RNA_struct_find_property(&unit_settings, "scale_length"); if (this->import_settings->import_units) { - + switch (unit_converter.isMetricSystem()) { case UnitConverter::Metric: RNA_property_enum_set(&unit_settings, system, USER_UNIT_METRIC); @@ -272,7 +272,7 @@ void DocumentImporter::finish() DEG_relations_tag_update(bmain); } - + bc_match_scale(objects_to_scale, unit_converter, !this->import_settings->import_units); delete objects_to_scale; @@ -281,7 +281,7 @@ void DocumentImporter::finish() void DocumentImporter::translate_anim_recursive(COLLADAFW::Node *node, COLLADAFW::Node *par = NULL, Object *parob = NULL) { - + Main *bmain = CTX_data_main(mContext); // The split in #29246, rootmap must point at actual root when // calculating bones in apply_curves_as_matrix. - actual root is the root node. // This has to do with inverse bind poses being world space @@ -316,7 +316,7 @@ void DocumentImporter::translate_anim_recursive(COLLADAFW::Node *node, COLLADAFW translate_anim_recursive(node, node, parob); } else { - anim_importer.translate_Animations(node, root_map, object_map, FW_object_map, uid_material_map); + anim_importer.translate_Animations(bmain, node, root_map, object_map, FW_object_map, uid_material_map); COLLADAFW::NodePointerArray &children = node->getChildNodes(); for (i = 0; i < children.getCount(); i++) { translate_anim_recursive(children[i], node, NULL); @@ -473,7 +473,7 @@ void DocumentImporter::create_constraints(ExtraTags *et, Object *ob) short type = 0; et->setData("type", &type); BKE_constraint_add_for_object(ob, "Test_con", type); - + } } @@ -634,7 +634,7 @@ std::vector<Object *> *DocumentImporter::write_node(COLLADAFW::Node *node, COLLA root_objects->push_back(ob); } } - + // XXX: if there're multiple instances, only one is stored if (!ob) { @@ -700,7 +700,7 @@ bool DocumentImporter::writeVisualScene(const COLLADAFW::VisualScene *visualScen { if (mImportStage != General) return true; - + // this method called on post process after writeGeometry, writeMaterial, etc. // for each <node> in <visual_scene>: @@ -712,18 +712,18 @@ bool DocumentImporter::writeVisualScene(const COLLADAFW::VisualScene *visualScen // we link Objects with Meshes here vscenes.push_back(visualScene); - + return true; } -/** When this method is called, the writer must handle all nodes contained in the +/** When this method is called, the writer must handle all nodes contained in the * library nodes. * \return The writer should return true, if writing succeeded, false otherwise.*/ bool DocumentImporter::writeLibraryNodes(const COLLADAFW::LibraryNodes *libraryNodes) { if (mImportStage != General) return true; - + Scene *sce = CTX_data_scene(mContext); const COLLADAFW::NodePointerArray& nodes = libraryNodes->getNodes(); @@ -743,7 +743,7 @@ bool DocumentImporter::writeGeometry(const COLLADAFW::Geometry *geom) { if (mImportStage != General) return true; - + return mesh_importer.write_geometry(geom); } @@ -753,13 +753,13 @@ bool DocumentImporter::writeMaterial(const COLLADAFW::Material *cmat) { if (mImportStage != General) return true; - + const std::string& str_mat_id = cmat->getName().size() ? cmat->getName() : cmat->getOriginalId(); Material *ma = BKE_material_add(G.main, (char *)str_mat_id.c_str()); - + this->uid_effect_map[cmat->getInstantiatedEffect()] = ma; this->uid_material_map[cmat->getUniqueId()] = ma; - + return true; } @@ -768,7 +768,7 @@ void DocumentImporter::write_profile_COMMON(COLLADAFW::EffectCommon *ef, Materia COLLADAFW::EffectCommon::ShaderType shader = ef->getShaderType(); // TODO: add back texture and extended material parameter support - + // blinn if (shader == COLLADAFW::EffectCommon::SHADER_BLINN) { #if 0 @@ -802,9 +802,9 @@ void DocumentImporter::write_profile_COMMON(COLLADAFW::EffectCommon *ef, Materia #if 0 ma->ang = ef->getIndexOfRefraction().getFloatValue(); #endif - + COLLADAFW::Color col; - + // DIFFUSE // color if (ef->getDiffuse().isColor()) { @@ -816,7 +816,7 @@ void DocumentImporter::write_profile_COMMON(COLLADAFW::EffectCommon *ef, Materia // texture else if (ef->getDiffuse().isTexture()) { #if 0 - COLLADAFW::Texture ctex = ef->getDiffuse().getTexture(); + COLLADAFW::Texture ctex = ef->getDiffuse().getTexture(); #endif } // AMBIENT @@ -829,7 +829,7 @@ void DocumentImporter::write_profile_COMMON(COLLADAFW::EffectCommon *ef, Materia // texture else if (ef->getAmbient().isTexture()) { #if 0 - COLLADAFW::Texture ctex = ef->getAmbient().getTexture(); + COLLADAFW::Texture ctex = ef->getAmbient().getTexture(); #endif } // SPECULAR @@ -843,7 +843,7 @@ void DocumentImporter::write_profile_COMMON(COLLADAFW::EffectCommon *ef, Materia // texture else if (ef->getSpecular().isTexture()) { #if 0 - COLLADAFW::Texture ctex = ef->getSpecular().getTexture(); + COLLADAFW::Texture ctex = ef->getSpecular().getTexture(); #endif } // REFLECTIVE @@ -856,7 +856,7 @@ void DocumentImporter::write_profile_COMMON(COLLADAFW::EffectCommon *ef, Materia // texture else if (ef->getReflective().isTexture()) { #if 0 - COLLADAFW::Texture ctex = ef->getReflective().getTexture(); + COLLADAFW::Texture ctex = ef->getReflective().getTexture(); #endif } @@ -869,7 +869,7 @@ void DocumentImporter::write_profile_COMMON(COLLADAFW::EffectCommon *ef, Materia // texture else if (ef->getEmission().isTexture()) { #if 0 - COLLADAFW::Texture ctex = ef->getEmission().getTexture(); + COLLADAFW::Texture ctex = ef->getEmission().getTexture(); #endif } @@ -902,14 +902,14 @@ bool DocumentImporter::writeEffect(const COLLADAFW::Effect *effect) { if (mImportStage != General) return true; - + const COLLADAFW::UniqueId& uid = effect->getUniqueId(); - + if (uid_effect_map.find(uid) == uid_effect_map.end()) { fprintf(stderr, "Couldn't find a material by UID.\n"); return true; } - + Material *ma = uid_effect_map[uid]; std::map<COLLADAFW::UniqueId, Material *>::iterator iter; for (iter = uid_material_map.begin(); iter != uid_material_map.end(); iter++) { @@ -928,7 +928,7 @@ bool DocumentImporter::writeEffect(const COLLADAFW::Effect *effect) COLLADAFW::EffectCommon *ef = common_efs[0]; write_profile_COMMON(ef, ma); this->FW_object_map[effect->getUniqueId()] = effect; - + return true; } @@ -939,16 +939,16 @@ bool DocumentImporter::writeCamera(const COLLADAFW::Camera *camera) { if (mImportStage != General) return true; - + Camera *cam = NULL; std::string cam_id, cam_name; - + ExtraTags *et=getExtraTags(camera->getUniqueId()); cam_id = camera->getOriginalId(); cam_name = camera->getName(); if (cam_name.size()) cam = (Camera *)BKE_camera_add(G.main, (char *)cam_name.c_str()); else cam = (Camera *)BKE_camera_add(G.main, (char *)cam_id.c_str()); - + if (!cam) { fprintf(stderr, "Cannot create camera.\n"); return true; @@ -961,7 +961,7 @@ bool DocumentImporter::writeCamera(const COLLADAFW::Camera *camera) } cam->clipsta = camera->getNearClippingPlane().getValue(); cam->clipend = camera->getFarClippingPlane().getValue(); - + COLLADAFW::Camera::CameraType type = camera->getCameraType(); switch (type) { case COLLADAFW::Camera::ORTHOGRAPHIC: @@ -981,7 +981,7 @@ bool DocumentImporter::writeCamera(const COLLADAFW::Camera *camera) } break; } - + switch (camera->getDescriptionType()) { case COLLADAFW::Camera::ASPECTRATIO_AND_Y: { @@ -1051,7 +1051,7 @@ bool DocumentImporter::writeCamera(const COLLADAFW::Camera *camera) // read nothing, use blender defaults. break; } - + this->uid_camera_map[camera->getUniqueId()] = cam; this->FW_object_map[camera->getUniqueId()] = camera; // XXX import camera options @@ -1064,7 +1064,7 @@ bool DocumentImporter::writeImage(const COLLADAFW::Image *image) { if (mImportStage != General) return true; - + const std::string& imagepath = image->getImageURI().toNativePath(); char dir[FILE_MAX]; @@ -1075,7 +1075,7 @@ bool DocumentImporter::writeImage(const COLLADAFW::Image *image) BLI_join_dirfile(absolute_path, sizeof(absolute_path), dir, imagepath.c_str()); if (BLI_exists(absolute_path)) { workpath = absolute_path; - } + } else { // Maybe imagepath was already absolute ? if (!BLI_exists(imagepath.c_str())) { @@ -1091,7 +1091,7 @@ bool DocumentImporter::writeImage(const COLLADAFW::Image *image) return true; } this->uid_image_map[image->getUniqueId()] = ima; - + return true; } @@ -1185,7 +1185,7 @@ bool DocumentImporter::writeLight(const COLLADAFW::Light *light) // assuming point light (const att = 1.0); att1 = 1.0f; } - + d *= (1.0f / unit_converter.getLinearMeter()); lamp->energy = e; @@ -1247,7 +1247,7 @@ bool DocumentImporter::writeAnimation(const COLLADAFW::Animation *anim) { if (mImportStage != General) return true; - + // return true; return anim_importer.write_animation(anim); } @@ -1257,7 +1257,7 @@ bool DocumentImporter::writeAnimationList(const COLLADAFW::AnimationList *animat { if (mImportStage != General) return true; - + // return true; return anim_importer.write_animation_list(animationList); } @@ -1274,7 +1274,7 @@ bool DocumentImporter::writeController(const COLLADAFW::Controller *controller) { if (mImportStage != General) return true; - + return armature_importer.write_controller(controller); } diff --git a/source/blender/collada/DocumentImporter.h b/source/blender/collada/DocumentImporter.h index 758caef7e60..b31a086d710 100644 --- a/source/blender/collada/DocumentImporter.h +++ b/source/blender/collada/DocumentImporter.h @@ -78,7 +78,7 @@ public: void create_constraints(ExtraTags *et, Object *ob); std::vector<Object *> *write_node(COLLADAFW::Node*, COLLADAFW::Node*, Scene*, Object*, bool); void write_profile_COMMON(COLLADAFW::EffectCommon*, Material*); - + void translate_anim_recursive(COLLADAFW::Node*, COLLADAFW::Node*, Object*); /** @@ -149,7 +149,7 @@ private: ArmatureImporter armature_importer; MeshImporter mesh_importer; AnimationImporter anim_importer; - + /** TagsMap typedef for uid_tags_map. */ typedef std::map<std::string, ExtraTags*> TagsMap; /** Tags map of unique id as a string and ExtraTags instance. */ @@ -165,7 +165,7 @@ private: std::map<COLLADAFW::UniqueId, COLLADAFW::Node*> node_map; std::vector<const COLLADAFW::VisualScene*> vscenes; std::vector<Object*> libnode_ob; - + std::map<COLLADAFW::UniqueId, COLLADAFW::Node*> root_map; // find root joint by child joint uid, for bone tree evaluation during resampling std::map<COLLADAFW::UniqueId, const COLLADAFW::Object*> FW_object_map; diff --git a/source/blender/collada/EffectExporter.cpp b/source/blender/collada/EffectExporter.cpp index dbcdfd01a9c..271dab5deea 100644 --- a/source/blender/collada/EffectExporter.cpp +++ b/source/blender/collada/EffectExporter.cpp @@ -57,7 +57,7 @@ static std::string getActiveUVLayerName(Object *ob) int num_layers = CustomData_number_of_layers(&me->fdata, CD_MTFACE); if (num_layers) return std::string(bc_CustomData_get_active_layer_name(&me->fdata, CD_MTFACE)); - + return ""; } @@ -105,12 +105,12 @@ void EffectsExporter::operator()(Material *ma, Object *ob) // TODO: add back texture and extended material parameter support openEffect(translate_id(id_name(ma)) + "-effect"); - + COLLADASW::EffectProfile ep(mSW); ep.setProfileType(COLLADASW::EffectProfile::COMMON); ep.openProfile(); writeLambert(ep, ma); - + COLLADASW::ColorOrTexture cot; // transparency @@ -144,7 +144,7 @@ void EffectsExporter::operator()(Material *ma, Object *ob) //COLLADASW::Surface surfaces[MAX_MTEX]; //void *samp_surf[MAX_MTEX][2]; void *samp_surf[MAX_MTEX]; - + // image to index to samp_surf map // samp_surf[index] stores 2 pointers, sampler and surface std::map<std::string, int> im_samp_map; @@ -153,10 +153,10 @@ void EffectsExporter::operator()(Material *ma, Object *ob) for (a = 0, b = 0; a < tex_indices.size(); a++) { MTex *t = ma->mtex[tex_indices[a]]; Image *ima = t->tex->ima; - + // Image not set for texture if (!ima) continue; - + std::string key(id_name(ima)); key = translate_id(key); @@ -171,7 +171,7 @@ void EffectsExporter::operator()(Material *ma, Object *ob) // COLLADASW::NewParamSurface surface(mSW); // surface->setParamType(COLLADASW::CSW_SURFACE_TYPE_2D); - + //<newparam> <sampler> <source> COLLADASW::Sampler sampler(COLLADASW::Sampler::SAMPLER_TYPE_2D, key + COLLADASW::Sampler::SAMPLER_SID_SUFFIX, @@ -180,11 +180,11 @@ void EffectsExporter::operator()(Material *ma, Object *ob) // copy values to arrays since they will live longer samplers[a] = sampler; //surfaces[a] = surface; - + // store pointers so they can be used later when we create <texture>s samp_surf[b] = &samplers[a]; //samp_surf[b][1] = &surfaces[a]; - + im_samp_map[key] = b; b++; } @@ -238,12 +238,12 @@ COLLADASW::ColorOrTexture EffectsExporter::createTexture(Image *ima, COLLADASW::Sampler *sampler /*COLLADASW::Surface *surface*/) { - + COLLADASW::Texture texture(translate_id(id_name(ima))); texture.setTexcoord(uv_layer_name); //texture.setSurface(*surface); texture.setSampler(*sampler); - + COLLADASW::ColorOrTexture cot(texture); return cot; } diff --git a/source/blender/collada/EffectExporter.h b/source/blender/collada/EffectExporter.h index eac428ae330..a1395bfde9f 100644 --- a/source/blender/collada/EffectExporter.h +++ b/source/blender/collada/EffectExporter.h @@ -50,25 +50,25 @@ public: void exportEffects(Scene *sce); void operator()(Material *ma, Object *ob); - + COLLADASW::ColorOrTexture createTexture(Image *ima, std::string& uv_layer_name, COLLADASW::Sampler *sampler /*COLLADASW::Surface *surface*/); - + COLLADASW::ColorOrTexture getcol(float r, float g, float b, float a); private: void writeLambert(COLLADASW::EffectProfile &ep, Material *ma); void writeTextures(COLLADASW::EffectProfile &ep, std::string &key, - COLLADASW::Sampler *sampler, + COLLADASW::Sampler *sampler, MTex *t, Image *ima, std::string &uvname ); bool hasEffects(Scene *sce); - + const ExportSettings *export_settings; - + Scene *scene; }; diff --git a/source/blender/collada/ErrorHandler.cpp b/source/blender/collada/ErrorHandler.cpp index 7e18328f000..26674445d98 100644 --- a/source/blender/collada/ErrorHandler.cpp +++ b/source/blender/collada/ErrorHandler.cpp @@ -53,7 +53,7 @@ bool ErrorHandler::handleError(const COLLADASaxFWL::IError *error) See https://github.com/KhronosGroup/OpenCOLLADA/issues/442 */ bool isWarning = false; - + if (error->getErrorClass() == COLLADASaxFWL::IError::ERROR_SAXPARSER) { COLLADASaxFWL::SaxParserError *saxParserError = (COLLADASaxFWL::SaxParserError *) error; const GeneratedSaxParser::ParserError& parserError = saxParserError->getError(); diff --git a/source/blender/collada/ExtraHandler.cpp b/source/blender/collada/ExtraHandler.cpp index bef7accd9f7..5d704bc9abc 100644 --- a/source/blender/collada/ExtraHandler.cpp +++ b/source/blender/collada/ExtraHandler.cpp @@ -54,9 +54,9 @@ bool ExtraHandler::elementEnd(const char *elementName) bool ExtraHandler::textData(const char *text, size_t textLength) { char buf[1024]; - + if (currentElement.length() == 0 || currentExtraTags == 0) return false; - + BLI_strncpy(buf, text, textLength + 1); currentExtraTags->addTag(currentElement, std::string(buf)); return true; diff --git a/source/blender/collada/ExtraHandler.h b/source/blender/collada/ExtraHandler.h index f380c3d6871..4dda862b3cc 100644 --- a/source/blender/collada/ExtraHandler.h +++ b/source/blender/collada/ExtraHandler.h @@ -50,31 +50,31 @@ public: /** Handle the beginning of an element. */ bool elementBegin( const char* elementName, const char** attributes); - + /** Handle the end of an element. */ bool elementEnd(const char* elementName ); - + /** Receive the data in text format. */ bool textData(const char* text, size_t textLength); /** Method to ask, if the current callback handler want to read the data of the given extra element. */ - bool parseElement ( - const char* profileName, - const unsigned long& elementHash, + bool parseElement ( + const char* profileName, + const unsigned long& elementHash, const COLLADAFW::UniqueId& uniqueId, COLLADAFW::Object* object); /** For backwards compatibility with older OpenCollada, new version added object parameter */ - bool parseElement ( - const char* profileName, - const unsigned long& elementHash, + bool parseElement ( + const char* profileName, + const unsigned long& elementHash, const COLLADAFW::UniqueId& uniqueId); private: /** Disable default copy constructor. */ ExtraHandler(const ExtraHandler& pre); /** Disable default assignment operator. */ const ExtraHandler& operator= ( const ExtraHandler& pre ); - + /** Handle to DocumentImporter for interface to extra element data saving. */ DocumentImporter* dimp; AnimationImporter* aimp; diff --git a/source/blender/collada/ExtraTags.cpp b/source/blender/collada/ExtraTags.cpp index ea225d8a4ae..fd249884c3f 100644 --- a/source/blender/collada/ExtraTags.cpp +++ b/source/blender/collada/ExtraTags.cpp @@ -50,7 +50,7 @@ bool ExtraTags::isProfile(std::string profile) bool ExtraTags::addTag(std::string tag, std::string data) { tags[tag] = data; - + return true; } diff --git a/source/blender/collada/ExtraTags.h b/source/blender/collada/ExtraTags.h index ad272dcba65..84857622ee8 100644 --- a/source/blender/collada/ExtraTags.h +++ b/source/blender/collada/ExtraTags.h @@ -41,35 +41,35 @@ public: /** Handle the beginning of an element. */ bool addTag(std::string tag, std::string data); - + /** Set given short pointer to value of tag, if it exists. */ bool setData(std::string tag, short *data); - + /** Set given int pointer to value of tag, if it exists. */ bool setData(std::string tag, int *data); - + /** Set given float pointer to value of tag, if it exists. */ bool setData(std::string tag, float *data); - + /** Set given char pointer to value of tag, if it exists. */ bool setData(std::string tag, char *data); std::string setData(std::string tag, std::string &data); /** Return true if the extra tags is for specified profile. */ bool isProfile(std::string profile); - + private: /** Disable default copy constructor. */ ExtraTags(const ExtraTags& pre); /** Disable default assignment operator. */ const ExtraTags& operator= ( const ExtraTags& pre ); - + /** The profile for which the tags are. */ std::string profile; - + /** Map of tag and text pairs. */ std::map<std::string, std::string> tags; - + /** Get text data for tag as an int. */ int asInt(std::string tag, bool *ok); /** Get text data for tag as a float. */ diff --git a/source/blender/collada/GeometryExporter.cpp b/source/blender/collada/GeometryExporter.cpp index 87b47353596..65e844cbe50 100644 --- a/source/blender/collada/GeometryExporter.cpp +++ b/source/blender/collada/GeometryExporter.cpp @@ -70,14 +70,14 @@ void GeometryExporter::exportGeom(struct Depsgraph *depsgraph, Scene *sce) } void GeometryExporter::operator()(Object *ob) -{ +{ // XXX don't use DerivedMesh, Mesh instead? -#if 0 +#if 0 DerivedMesh *dm = mesh_get_derived_final(mScene, ob, CD_MASK_BAREMESH); #endif bool use_instantiation = this->export_settings->use_object_instantiation; - Mesh *me = bc_get_mesh_copy(mDepsgraph, mScene, + Mesh *me = bc_get_mesh_copy(mDepsgraph, mScene, ob, this->export_settings->export_mesh_type, this->export_settings->apply_modifiers, @@ -88,7 +88,7 @@ void GeometryExporter::operator()(Object *ob) std::vector<BCPolygonNormalsIndices> norind; // Skip if linked geometry was already exported from another reference - if (use_instantiation && + if (use_instantiation && exportedGeometry.find(geom_id) != exportedGeometry.end()) { return; @@ -104,15 +104,15 @@ void GeometryExporter::operator()(Object *ob) // openMesh(geoId, geoName, meshId) openMesh(geom_id, geom_name); - + // writes <source> for vertex coords createVertsSource(geom_id, me); - + // writes <source> for normal coords createNormalsSource(geom_id, me, nor); bool has_uvs = (bool)CustomData_has_layer(&me->fdata, CD_MTFACE); - + // writes <source> for uv coords if mesh has uv coords if (has_uvs) { createTexcoordsSource(geom_id, me); @@ -144,9 +144,9 @@ void GeometryExporter::operator()(Object *ob) createPolylist(0, has_uvs, has_color, ob, me, geom_id, norind); } } - + closeMesh(); - + if (me->flag & ME_TWOSIDED) { mSW->appendTextBlock("<extra><technique profile=\"MAYA\"><double_sided>1</double_sided></technique></extra>"); } @@ -175,7 +175,7 @@ void GeometryExporter::export_key_mesh(Object *ob, Mesh *me, KeyBlock *kb) std::string geom_id = get_geometry_id(ob, false) + "_morph_" + translate_id(kb->name); std::vector<Normal> nor; std::vector<BCPolygonNormalsIndices> norind; - + if (exportedGeometry.find(geom_id) != exportedGeometry.end()) { return; @@ -191,15 +191,15 @@ void GeometryExporter::export_key_mesh(Object *ob, Mesh *me, KeyBlock *kb) // openMesh(geoId, geoName, meshId) openMesh(geom_id, geom_name); - + // writes <source> for vertex coords createVertsSource(geom_id, me); - + // writes <source> for normal coords createNormalsSource(geom_id, me, nor); bool has_uvs = (bool)CustomData_has_layer(&me->fdata, CD_MTFACE); - + // writes <source> for uv coords if mesh has uv coords if (has_uvs) { createTexcoordsSource(geom_id, me); @@ -220,7 +220,7 @@ void GeometryExporter::export_key_mesh(Object *ob, Mesh *me, KeyBlock *kb) //createLooseEdgeList(ob, me, geom_id, norind); - // XXX slow + // XXX slow if (ob->totcol) { for (int a = 0; a < ob->totcol; a++) { createPolylist(a, has_uvs, has_color, ob, me, geom_id, norind); @@ -229,9 +229,9 @@ void GeometryExporter::export_key_mesh(Object *ob, Mesh *me, KeyBlock *kb) else { createPolylist(0, has_uvs, has_color, ob, me, geom_id, norind); } - + closeMesh(); - + if (me->flag & ME_TWOSIDED) { mSW->appendTextBlock("<extra><technique profile=\"MAYA\"><double_sided>1</double_sided></technique></extra>"); } @@ -250,9 +250,9 @@ void GeometryExporter::createLooseEdgeList(Object *ob, std::vector<unsigned int> edge_list; int index; - // Find all loose edges in Mesh + // Find all loose edges in Mesh // and save vertex indices in edge_list - for (index = 0; index < totedges; index++) + for (index = 0; index < totedges; index++) { MEdge *edge = &medges[index]; @@ -273,14 +273,14 @@ void GeometryExporter::createLooseEdgeList(Object *ob, COLLADASW::InputList &til = lines.getInputList(); - - // creates <input> in <lines> for vertices + + // creates <input> in <lines> for vertices COLLADASW::Input input1(COLLADASW::InputSemantic::VERTEX, getUrlBySemantics(geom_id, COLLADASW::InputSemantic::VERTEX), 0); til.push_back(input1); lines.prepareToAppendValues(); - for (index = 0; index < edges_in_linelist; index++) + for (index = 0; index < edges_in_linelist; index++) { lines.appendValues(edge_list[2 * index + 1]); lines.appendValues(edge_list[2 * index]); @@ -318,7 +318,7 @@ void GeometryExporter::createPolylist(short material_index, // count faces with this material for (i = 0; i < totpolys; i++) { MPoly *p = &mpolys[i]; - + if (p->mat_nr == material_index) { faces_in_polylist++; vcount_list.push_back(p->totloop); @@ -330,13 +330,13 @@ void GeometryExporter::createPolylist(short material_index, fprintf(stderr, "%s: material with index %d is not used.\n", id_name(ob).c_str(), material_index); return; } - + Material *ma = ob->totcol ? give_current_material(ob, material_index + 1) : NULL; COLLADASW::Polylist polylist(mSW); - + // sets count attribute in <polylist> polylist.setCount(faces_in_polylist); - + // sets material name if (ma) { std::string material_id = get_material_id(ma); @@ -344,18 +344,18 @@ void GeometryExporter::createPolylist(short material_index, ostr << translate_id(material_id); polylist.setMaterial(ostr.str()); } - + COLLADASW::InputList &til = polylist.getInputList(); - - // creates <input> in <polylist> for vertices + + // creates <input> in <polylist> for vertices COLLADASW::Input input1(COLLADASW::InputSemantic::VERTEX, getUrlBySemantics(geom_id, COLLADASW::InputSemantic::VERTEX), 0); - + // creates <input> in <polylist> for normals COLLADASW::Input input2(COLLADASW::InputSemantic::NORMAL, getUrlBySemantics(geom_id, COLLADASW::InputSemantic::NORMAL), 1); - + til.push_back(input1); til.push_back(input2); - + // if mesh has uv coords writes <input> for TEXCOORD int num_layers = CustomData_number_of_layers(&me->fdata, CD_MTFACE); int active_uv_index = CustomData_get_active_layer_index(&me->fdata, CD_MTFACE)-1; @@ -387,13 +387,13 @@ void GeometryExporter::createPolylist(short material_index, map_index++; } } - + // sets <vcount> polylist.setVCountList(vcount_list); - + // performs the actual writing polylist.prepareToAppendValues(); - + // <p> int texindex = 0; for (i = 0; i < totpolys; i++) { @@ -417,7 +417,7 @@ void GeometryExporter::createPolylist(short material_index, texindex += loop_count; } - + polylist.finish(); } @@ -430,7 +430,7 @@ void GeometryExporter::createVertsSource(std::string geom_id, Mesh *me) #endif int totverts = me->totvert; MVert *verts = me->mvert; - + COLLADASW::FloatSourceF source(mSW); source.setId(getIdBySemantics(geom_id, COLLADASW::InputSemantic::POSITION)); source.setArrayId(getIdBySemantics(geom_id, COLLADASW::InputSemantic::POSITION) + @@ -450,7 +450,7 @@ void GeometryExporter::createVertsSource(std::string geom_id, Mesh *me) for (i = 0; i < totverts; i++) { source.appendValues(verts[i].co[0], verts[i].co[1], verts[i].co[2]); } - + source.finish(); } @@ -502,7 +502,7 @@ void GeometryExporter::createVertexColorSource(std::string geom_id, Mesh *me) ); } } - + source.finish(); } } @@ -537,20 +537,20 @@ void GeometryExporter::createTexcoordsSource(std::string geom_id, Mesh *me) int layer_index = CustomData_get_layer_index_n(&me->ldata, CD_MLOOPUV, a); if (!this->export_settings->active_uv_only || layer_index == active_uv_index) { MLoopUV *mloops = (MLoopUV *)CustomData_get_layer_n(&me->ldata, CD_MLOOPUV, a); - + COLLADASW::FloatSourceF source(mSW); std::string layer_id = makeTexcoordSourceId(geom_id, a, this->export_settings->active_uv_only); source.setId(layer_id); source.setArrayId(layer_id + ARRAY_ID_SUFFIX); - + source.setAccessorCount(totuv); source.setAccessorStride(2); COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList(); param.push_back("S"); param.push_back("T"); - + source.prepareToAppendValues(); - + for (int index = 0; index < totpoly; index++) { MPoly *mpoly = mpolys+index; MLoopUV *mloop = mloops+mpoly->loopstart; @@ -559,7 +559,7 @@ void GeometryExporter::createTexcoordsSource(std::string geom_id, Mesh *me) mloop[j].uv[1]); } } - + source.finish(); } } @@ -589,7 +589,7 @@ void GeometryExporter::createNormalsSource(std::string geom_id, Mesh *me, std::v param.push_back("X"); param.push_back("Y"); param.push_back("Z"); - + source.prepareToAppendValues(); std::vector<Normal>::iterator it; @@ -674,10 +674,10 @@ std::string GeometryExporter::getIdBySemantics(std::string geom_id, COLLADASW::I COLLADASW::URI GeometryExporter::getUrlBySemantics(std::string geom_id, COLLADASW::InputSemantic::Semantics type, std::string other_suffix) { - + std::string id(getIdBySemantics(geom_id, type, other_suffix)); return COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, id); - + } COLLADASW::URI GeometryExporter::makeUrl(std::string id) diff --git a/source/blender/collada/GeometryExporter.h b/source/blender/collada/GeometryExporter.h index 88420b4ad2f..b0cd650adcd 100644 --- a/source/blender/collada/GeometryExporter.h +++ b/source/blender/collada/GeometryExporter.h @@ -96,7 +96,7 @@ public: Mesh *me, std::string& geom_id, std::vector<BCPolygonNormalsIndices>& norind); - + // creates <source> for positions void createVertsSource(std::string geom_id, Mesh *me); @@ -112,7 +112,7 @@ public: void createNormalsSource(std::string geom_id, Mesh *me, std::vector<Normal>& nor); void create_normals(std::vector<Normal> &nor, std::vector<BCPolygonNormalsIndices> &ind, Mesh *me); - + std::string getIdBySemantics(std::string geom_id, COLLADASW::InputSemantic::Semantics type, std::string other_suffix = ""); std::string makeVertexColorSourceId(std::string& geom_id, char *layer_name); @@ -121,10 +121,10 @@ public: COLLADASW::URI makeUrl(std::string id); void export_key_mesh(Object *ob, Mesh *me, KeyBlock *kb); - + private: std::set<std::string> exportedGeometry; - + const ExportSettings *export_settings; Mesh * get_mesh(Scene *sce, Object *ob, int apply_modifiers); diff --git a/source/blender/collada/ImageExporter.cpp b/source/blender/collada/ImageExporter.cpp index 657037a869a..bb3cebf4cf0 100644 --- a/source/blender/collada/ImageExporter.cpp +++ b/source/blender/collada/ImageExporter.cpp @@ -34,7 +34,7 @@ extern "C" { #include "DNA_image_types.h" #include "DNA_meshdata_types.h" -#include "BKE_customdata.h" +#include "BKE_customdata.h" #include "BKE_global.h" #include "BKE_image.h" #include "BKE_main.h" @@ -53,7 +53,7 @@ ImagesExporter::ImagesExporter(COLLADASW::StreamWriter *sw, const ExportSettings { } -void ImagesExporter::export_UV_Image(Image *image, bool use_copies) +void ImagesExporter::export_UV_Image(Image *image, bool use_copies) { std::string name(id_name(image)); std::string translated_name(translate_id(name)); @@ -113,11 +113,11 @@ void ImagesExporter::export_UV_Image(Image *image, bool use_copies) // make absolute source path BLI_strncpy(source_path, image->name, sizeof(source_path)); - BLI_path_abs(source_path, G.main->name); + BLI_path_abs(source_path, BKE_main_blendfile_path_from_global()); BLI_cleanup_path(NULL, source_path); if (use_copies) { - + // This image is already located on the file system. // But we want to create copies here. // To move images into the same export directory. @@ -155,7 +155,7 @@ void ImagesExporter::export_UV_Image(Image *image, bool use_copies) bool ImagesExporter::hasImages(Scene *sce) { LinkNode *node; - + for (node = this->export_settings->export_set; node; node = node->next) { Object *ob = (Object *)node->link; diff --git a/source/blender/collada/ImageExporter.h b/source/blender/collada/ImageExporter.h index f3dd2b336e4..1867c44ac9c 100644 --- a/source/blender/collada/ImageExporter.h +++ b/source/blender/collada/ImageExporter.h @@ -45,7 +45,7 @@ class ImagesExporter: COLLADASW::LibraryImages { public: ImagesExporter(COLLADASW::StreamWriter *sw, const ExportSettings *export_settings); - + void exportImages(Scene *sce); void operator()(Material *ma, Object *ob); private: diff --git a/source/blender/collada/InstanceWriter.cpp b/source/blender/collada/InstanceWriter.cpp index d96d590597a..68842596550 100644 --- a/source/blender/collada/InstanceWriter.cpp +++ b/source/blender/collada/InstanceWriter.cpp @@ -45,7 +45,7 @@ void InstanceWriter::add_material_bindings(COLLADASW::BindMaterial& bind_materia { for (int a = 0; a < ob->totcol; a++) { Material *ma = give_current_material(ob, a + 1); - + COLLADASW::InstanceMaterialList& iml = bind_material.getInstanceMaterialList(); if (ma) { @@ -54,11 +54,11 @@ void InstanceWriter::add_material_bindings(COLLADASW::BindMaterial& bind_materia std::ostringstream ostr; ostr << matid; COLLADASW::InstanceMaterial im(ostr.str(), COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, matid)); - + // create <bind_vertex_input> for each uv map Mesh *me = (Mesh *)ob->data; int totlayer = CustomData_number_of_layers(&me->fdata, CD_MTFACE); - + int map_index = 0; int active_uv_index = CustomData_get_active_layer_index(&me->fdata, CD_MTFACE) -1; for (int b = 0; b < totlayer; b++) { @@ -67,7 +67,7 @@ void InstanceWriter::add_material_bindings(COLLADASW::BindMaterial& bind_materia im.push_back(COLLADASW::BindVertexInput(name, "TEXCOORD", map_index++)); } } - + iml.push_back(im); } } diff --git a/source/blender/collada/LightExporter.cpp b/source/blender/collada/LightExporter.cpp index d17941574d7..11377e06ce8 100644 --- a/source/blender/collada/LightExporter.cpp +++ b/source/blender/collada/LightExporter.cpp @@ -54,9 +54,9 @@ LightsExporter::LightsExporter(COLLADASW::StreamWriter *sw, const ExportSettings void LightsExporter::exportLights(Scene *sce) { openLibrary(); - + forEachLampObjectInExportSet(sce, *this, this->export_settings->export_set); - + closeLibrary(); } @@ -67,11 +67,11 @@ void LightsExporter::operator()(Object *ob) std::string la_name(id_name(la)); COLLADASW::Color col(la->r * la->energy, la->g * la->energy, la->b * la->energy); float d, constatt, linatt, quadatt; - + d = la->dist; - + constatt = 1.0f; - + if (la->falloff_type == LA_FALLOFF_INVLINEAR) { linatt = 1.0f / d; quadatt = 0.0f; @@ -80,7 +80,7 @@ void LightsExporter::operator()(Object *ob) linatt = 0.0f; quadatt = 1.0f / (d * d); } - + // sun if (la->type == LA_SUN) { COLLADASW::DirectionalLight cla(mSW, la_id, la_name); @@ -130,7 +130,7 @@ void LightsExporter::operator()(Object *ob) exportBlenderProfile(cla, la); addLight(cla); } - + } bool LightsExporter::exportBlenderProfile(COLLADASW::Light &cla, Lamp *la) @@ -164,6 +164,6 @@ bool LightsExporter::exportBlenderProfile(COLLADASW::Light &cla, Lamp *la) cla.addExtraTechniqueParameter("blender", "area_size", la->area_size); cla.addExtraTechniqueParameter("blender", "area_sizey", la->area_sizey); cla.addExtraTechniqueParameter("blender", "area_sizez", la->area_sizez); - + return true; } diff --git a/source/blender/collada/MaterialExporter.h b/source/blender/collada/MaterialExporter.h index ef44bf8a03e..e830a433432 100644 --- a/source/blender/collada/MaterialExporter.h +++ b/source/blender/collada/MaterialExporter.h @@ -65,7 +65,7 @@ class ForEachMaterialFunctor Functor *f; public: ForEachMaterialFunctor(Functor*f) : f(f) {} - + void operator ()(Object *ob) { int a; diff --git a/source/blender/collada/MeshImporter.cpp b/source/blender/collada/MeshImporter.cpp index add4a93bccd..e95f8ed0888 100644 --- a/source/blender/collada/MeshImporter.cpp +++ b/source/blender/collada/MeshImporter.cpp @@ -154,7 +154,7 @@ void UVDataWrapper::getUV(int uv_index, float *uv) if (values->empty()) return; uv[0] = (*values)[uv_index * stride]; uv[1] = (*values)[uv_index * stride + 1]; - + } break; case COLLADAFW::MeshVertexData::DATA_TYPE_DOUBLE: @@ -163,7 +163,7 @@ void UVDataWrapper::getUV(int uv_index, float *uv) if (values->empty()) return; uv[0] = (float)(*values)[uv_index * stride]; uv[1] = (float)(*values)[uv_index * stride + 1]; - + } break; case COLLADAFW::MeshVertexData::DATA_TYPE_UNKNOWN: @@ -208,7 +208,7 @@ void VCOLDataWrapper::get_vcol(int v_index, MLoopCol *mloopcol) } MeshImporter::MeshImporter(UnitConverter *unitconv, ArmatureImporter *arm, Scene *sce, ViewLayer *view_layer): - unitconverter(unitconv), + unitconverter(unitconv), scene(sce), view_layer(view_layer), armature_importer(arm) { @@ -320,7 +320,7 @@ bool MeshImporter::is_nice_mesh(COLLADAFW::Mesh *mesh) // checks if mesh has su return false; } } - + return true; } @@ -360,7 +360,7 @@ bool MeshImporter::primitive_has_useable_normals(COLLADAFW::MeshPrimitive *mp) { int normals_count = mp->getNormalIndices().getCount(); if (normals_count > 0) { int index_count = mp->getPositionIndices().getCount(); - if (index_count == normals_count) + if (index_count == normals_count) has_useable_normals = true; else { fprintf(stderr, @@ -391,7 +391,7 @@ bool MeshImporter::primitive_has_faces(COLLADAFW::MeshPrimitive *mp) { break; } default: { - has_faces = false; + has_faces = false; break; } } @@ -435,7 +435,7 @@ void MeshImporter::allocate_poly_data(COLLADAFW::Mesh *collada_mesh, Mesh *me) size_t prim_poly_count = mpvc->getFaceCount(); size_t prim_loop_count = 0; - for (int index=0; index < prim_poly_count; index++) + for (int index=0; index < prim_poly_count; index++) { int vcount = get_vertex_count(mpvc, index); if (vcount > 0) { @@ -547,7 +547,7 @@ unsigned int MeshImporter::get_loose_edge_count(COLLADAFW::Mesh *mesh) { // This functin is copied from source/blender/editors/mesh/mesh_data.c // // TODO: (As discussed with sergey-) : -// Maybe move this function to blenderkernel/intern/mesh.c +// Maybe move this function to blenderkernel/intern/mesh.c // and add definition to BKE_mesh.c // ================================================================= void MeshImporter::mesh_add_edges(Mesh *mesh, int len) @@ -582,7 +582,7 @@ void MeshImporter::mesh_add_edges(Mesh *mesh, int len) // ================================================================= // Read all loose edges. -// Important: This function assumes that all edges from existing +// Important: This function assumes that all edges from existing // faces have allready been generated and added to me->medge // So this function MUST be called after read_faces() (see below) // ================================================================= @@ -593,21 +593,21 @@ void MeshImporter::read_lines(COLLADAFW::Mesh *mesh, Mesh *me) unsigned int face_edge_count = me->totedge; /* unsigned int total_edge_count = loose_edge_count + face_edge_count; */ /* UNUSED */ - + mesh_add_edges(me, loose_edge_count); MEdge *med = me->medge + face_edge_count; COLLADAFW::MeshPrimitiveArray& prim_arr = mesh->getMeshPrimitives(); for (int i = 0; i < prim_arr.getCount(); i++) { - + COLLADAFW::MeshPrimitive *mp = prim_arr[i]; int type = mp->getPrimitiveType(); if (type == COLLADAFW::MeshPrimitive::LINES) { unsigned int edge_count = mp->getFaceCount(); unsigned int *indices = mp->getPositionIndices().getData(); - + for (int j = 0; j < edge_count; j++, med++) { med->bweight = 0; med->crease = 0; @@ -624,7 +624,7 @@ void MeshImporter::read_lines(COLLADAFW::Mesh *mesh, Mesh *me) // ======================================================================= // Read all faces from TRIANGLES, TRIANGLE_FANS, POLYLIST, POLYGON -// Important: This function MUST be called before read_lines() +// Important: This function MUST be called before read_lines() // Otherwise we will loose all edges from faces (see read_lines() above) // // TODO: import uv set names @@ -632,7 +632,7 @@ void MeshImporter::read_lines(COLLADAFW::Mesh *mesh, Mesh *me) void MeshImporter::read_polys(COLLADAFW::Mesh *collada_mesh, Mesh *me) { unsigned int i; - + allocate_poly_data(collada_mesh, me); UVDataWrapper uvs(collada_mesh->getUVCoords()); @@ -648,7 +648,7 @@ void MeshImporter::read_polys(COLLADAFW::Mesh *collada_mesh, Mesh *me) COLLADAFW::MeshVertexData& nor = collada_mesh->getNormals(); for (i = 0; i < prim_arr.getCount(); i++) { - + COLLADAFW::MeshPrimitive *mp = prim_arr[i]; // faces @@ -661,7 +661,7 @@ void MeshImporter::read_polys(COLLADAFW::Mesh *collada_mesh, Mesh *me) bool mp_has_faces = primitive_has_faces(mp); int collada_meshtype = mp->getPrimitiveType(); - + // since we cannot set mpoly->mat_nr here, we store a portion of me->mpoly in Primitive Primitive prim = {mpoly, 0}; @@ -688,7 +688,7 @@ void MeshImporter::read_polys(COLLADAFW::Mesh *collada_mesh, Mesh *me) mpoly->flag |= ME_SMOOTH; normal_indices++; } - + mpoly++; mloop += 3; loop_index += 3; @@ -798,7 +798,7 @@ void MeshImporter::read_polys(COLLADAFW::Mesh *collada_mesh, Mesh *me) void MeshImporter::get_vector(float v[3], COLLADAFW::MeshVertexData& arr, int i, int stride) { i *= stride; - + switch (arr.getType()) { case COLLADAFW::MeshVertexData::DATA_TYPE_FLOAT: { @@ -888,7 +888,7 @@ static bool bc_has_same_material_configuration(Object *ob1, Object *ob2) { if (ob1->totcol != ob2->totcol) return false; // not same number of materials if (ob1->totcol == 0) return false; // no material at all - + for (int index=0; index < ob1->totcol; index++) { if (ob1->matbits[index] != ob2->matbits[index]) return false; // shouldn't happen if (ob1->matbits[index] == 0) return false; // shouldn't happen @@ -1019,34 +1019,34 @@ void MeshImporter::assign_material_to_geom( short mat_index) { const COLLADAFW::UniqueId& ma_uid = cmaterial.getReferencedMaterial(); - + // do we know this material? if (uid_material_map.find(ma_uid) == uid_material_map.end()) { - + fprintf(stderr, "Cannot find material by UID.\n"); return; } // first time we get geom_uid, ma_uid pair. Save for later check. materials_mapped_to_geom.insert(std::pair<COLLADAFW::UniqueId, COLLADAFW::UniqueId>(*geom_uid, ma_uid)); - + Material *ma = uid_material_map[ma_uid]; // Attention! This temporaly assigns material to object on purpose! // See note above. ob->actcol=0; assign_material(G.main, ob, ma, mat_index + 1, BKE_MAT_ASSIGN_OBJECT); - + MaterialIdPrimitiveArrayMap& mat_prim_map = geom_uid_mat_mapping_map[*geom_uid]; COLLADAFW::MaterialId mat_id = cmaterial.getMaterialId(); - + // assign material indices to mesh faces if (mat_prim_map.find(mat_id) != mat_prim_map.end()) { - + std::vector<Primitive>& prims = mat_prim_map[mat_id]; - + std::vector<Primitive>::iterator it; - + for (it = prims.begin(); it != prims.end(); it++) { Primitive& prim = *it; MPoly *mpoly = prim.mpoly; @@ -1055,7 +1055,7 @@ void MeshImporter::assign_material_to_geom( mpoly->mat_nr = mat_index; } } - } + } } Object *MeshImporter::create_mesh_object(COLLADAFW::Node *node, COLLADAFW::InstanceGeometry *geom, @@ -1063,19 +1063,19 @@ Object *MeshImporter::create_mesh_object(COLLADAFW::Node *node, COLLADAFW::Insta std::map<COLLADAFW::UniqueId, Material *>& uid_material_map) { const COLLADAFW::UniqueId *geom_uid = &geom->getInstanciatedObjectId(); - + // check if node instanciates controller or geometry if (isController) { - + geom_uid = armature_importer->get_geometry_uid(*geom_uid); - + if (!geom_uid) { fprintf(stderr, "Couldn't find a mesh UID by controller's UID.\n"); return NULL; } } else { - + if (uid_mesh_map.find(*geom_uid) == uid_mesh_map.end()) { // this could happen if a mesh was not created // (e.g. if it contains unsupported geometry) @@ -1084,11 +1084,11 @@ Object *MeshImporter::create_mesh_object(COLLADAFW::Node *node, COLLADAFW::Insta } } if (!uid_mesh_map[*geom_uid]) return NULL; - + // name Object const std::string& id = node->getName().size() ? node->getName() : node->getOriginalId(); const char *name = (id.length()) ? id.c_str() : NULL; - + // add object Object *ob = bc_add_object(scene, view_layer, OB_MESH, name); bc_set_mark(ob); // used later for material assignement optimization @@ -1097,7 +1097,7 @@ Object *MeshImporter::create_mesh_object(COLLADAFW::Node *node, COLLADAFW::Insta // store object pointer for ArmatureImporter uid_object_map[*geom_uid] = ob; imported_objects.push_back(ob); - + // replace ob->data freeing the old one Mesh *old_mesh = (Mesh *)ob->data; Mesh *new_mesh = uid_mesh_map[*geom_uid]; @@ -1110,10 +1110,10 @@ Object *MeshImporter::create_mesh_object(COLLADAFW::Node *node, COLLADAFW::Insta COLLADAFW::MaterialBindingArray& mat_array = geom->getMaterialBindings(); - + // loop through geom's materials for (unsigned int i = 0; i < mat_array.getCount(); i++) { - + if (mat_array[i].getReferencedMaterial().isValid()) { assign_material_to_geom( mat_array[i], uid_material_map, ob, geom_uid, @@ -1136,14 +1136,14 @@ bool MeshImporter::write_geometry(const COLLADAFW::Geometry *geom) fprintf(stderr, "Mesh type %s is not supported\n", bc_geomTypeToStr(geom->getType())); return true; } - + COLLADAFW::Mesh *mesh = (COLLADAFW::Mesh *)geom; - + if (!is_nice_mesh(mesh)) { fprintf(stderr, "Ignoring mesh %s\n", bc_get_dae_name(mesh).c_str()); return true; } - + const std::string& str_geom_id = mesh->getName().size() ? mesh->getName() : mesh->getOriginalId(); Mesh *me = BKE_mesh_add(G.main, (char *)str_geom_id.c_str()); id_us_min(&me->id); // is already 1 here, but will be set later in BKE_mesh_assign_object @@ -1152,7 +1152,7 @@ bool MeshImporter::write_geometry(const COLLADAFW::Geometry *geom) // mesh_geom_map needed to map mesh to its geometry name (for shape key naming) this->uid_mesh_map[mesh->getUniqueId()] = me; this->mesh_geom_map[std::string(me->id.name)] = str_geom_id; - + read_vertices(mesh, me); read_polys(mesh, me); diff --git a/source/blender/collada/MeshImporter.h b/source/blender/collada/MeshImporter.h index 09b3005d795..c98126916d7 100644 --- a/source/blender/collada/MeshImporter.h +++ b/source/blender/collada/MeshImporter.h @@ -109,7 +109,7 @@ private: typedef std::map<COLLADAFW::MaterialId, std::vector<Primitive> > MaterialIdPrimitiveArrayMap; std::map<COLLADAFW::UniqueId, MaterialIdPrimitiveArrayMap> geom_uid_mat_mapping_map; // crazy name! std::multimap<COLLADAFW::UniqueId, COLLADAFW::UniqueId> materials_mapped_to_geom; //< materials that have already been mapped to a geometry. A pair of geom uid and mat uid, one geometry can have several materials - + bool set_poly_indices(MPoly *mpoly, MLoop *mloop, int loop_index, @@ -135,7 +135,7 @@ private: bool is_nice_mesh(COLLADAFW::Mesh *mesh); void read_vertices(COLLADAFW::Mesh *mesh, Mesh *me); - + bool primitive_has_useable_normals(COLLADAFW::MeshPrimitive *mp); bool primitive_has_faces(COLLADAFW::MeshPrimitive *mp); @@ -165,7 +165,7 @@ public: virtual Object *get_object_by_geom_uid(const COLLADAFW::UniqueId& geom_uid); virtual Mesh *get_mesh_by_geom_uid(const COLLADAFW::UniqueId& geom_uid); - + void optimize_material_assignements(); void assign_material_to_geom( @@ -173,8 +173,8 @@ public: std::map<COLLADAFW::UniqueId, Material*>& uid_material_map, Object *ob, const COLLADAFW::UniqueId *geom_uid, short mat_index); - - + + Object *create_mesh_object(COLLADAFW::Node *node, COLLADAFW::InstanceGeometry *geom, bool isController, std::map<COLLADAFW::UniqueId, Material*>& uid_material_map); diff --git a/source/blender/collada/SceneExporter.cpp b/source/blender/collada/SceneExporter.cpp index 5d1df800746..d909203488e 100644 --- a/source/blender/collada/SceneExporter.cpp +++ b/source/blender/collada/SceneExporter.cpp @@ -39,18 +39,18 @@ SceneExporter::SceneExporter(COLLADASW::StreamWriter *sw, ArmatureExporter *arm, { } -void SceneExporter::exportScene(Depsgraph *depsgraph, Scene *sce) +void SceneExporter::exportScene(bContext *C, Depsgraph *depsgraph, Scene *sce) { // <library_visual_scenes> <visual_scene> std::string id_naming = id_name(sce); openVisualScene(translate_id(id_naming), id_naming); - exportHierarchy(depsgraph, sce); + exportHierarchy(C, depsgraph, sce); closeVisualScene(); closeLibrary(); } -void SceneExporter::exportHierarchy(Depsgraph *depsgraph, Scene *sce) -{ +void SceneExporter::exportHierarchy(bContext *C, Depsgraph *depsgraph, Scene *sce) +{ LinkNode *node; std::vector<Object *> base_objects; @@ -59,7 +59,7 @@ void SceneExporter::exportHierarchy(Depsgraph *depsgraph, Scene *sce) Object *ob = (Object *) node->link; ob->id.tag |= LIB_TAG_DOIT; } - + // Now find all exportable base ojects (highest in export hierarchy) for (node = this->export_settings->export_set; node; node = node->next) { Object *ob = (Object *) node->link; @@ -81,13 +81,13 @@ void SceneExporter::exportHierarchy(Depsgraph *depsgraph, Scene *sce) Object *ob = base_objects[index]; if (bc_is_marked(ob)) { bc_remove_mark(ob); - writeNodes(depsgraph, ob, sce); + writeNodes(C, depsgraph, ob, sce); } } } -void SceneExporter::writeNodes(Depsgraph *depsgraph, Object *ob, Scene *sce) +void SceneExporter::writeNodes(bContext *C, Depsgraph *depsgraph, Object *ob, Scene *sce) { // Add associated armature first if available bool armature_exported = false; @@ -96,7 +96,7 @@ void SceneExporter::writeNodes(Depsgraph *depsgraph, Object *ob, Scene *sce) armature_exported = bc_is_in_Export_set(this->export_settings->export_set, ob_arm); if (armature_exported && bc_is_marked(ob_arm)) { bc_remove_mark(ob_arm); - writeNodes(depsgraph, ob_arm, sce); + writeNodes(C, depsgraph, ob_arm, sce); armature_exported = true; } } @@ -155,7 +155,7 @@ void SceneExporter::writeNodes(Depsgraph *depsgraph, Object *ob, Scene *sce) // <instance_controller> else if (ob->type == OB_ARMATURE) { - arm_exporter->add_armature_bones(depsgraph, ob, sce, this, child_objects); + arm_exporter->add_armature_bones(C, depsgraph, ob, sce, this, child_objects); } // <instance_camera> @@ -203,17 +203,17 @@ void SceneExporter::writeNodes(Depsgraph *depsgraph, Object *ob, Scene *sce) colladaNode.addExtraTechniqueChildParameter("blender",con_tag,"rot_error",con->rot_error); colladaNode.addExtraTechniqueChildParameter("blender",con_tag,"tar_space",con->tarspace); colladaNode.addExtraTechniqueChildParameter("blender",con_tag,"lin_error",con->lin_error); - - //not ideal: add the target object name as another parameter. + + //not ideal: add the target object name as another parameter. //No real mapping in the .dae //Need support for multiple target objects also. const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); ListBase targets = {NULL, NULL}; if (cti && cti->get_constraint_targets) { - + bConstraintTarget *ct; Object *obtar; - + cti->get_constraint_targets(con, &targets); for (ct = (bConstraintTarget *)targets.first; ct; ct = ct->next) { @@ -234,7 +234,7 @@ void SceneExporter::writeNodes(Depsgraph *depsgraph, Object *ob, Scene *sce) for (std::list<Object *>::iterator i = child_objects.begin(); i != child_objects.end(); ++i) { if (bc_is_marked(*i)) { bc_remove_mark(*i); - writeNodes(depsgraph, *i, sce); + writeNodes(C, depsgraph, *i, sce); } } diff --git a/source/blender/collada/SceneExporter.h b/source/blender/collada/SceneExporter.h index c330aa81e91..91f98063020 100644 --- a/source/blender/collada/SceneExporter.h +++ b/source/blender/collada/SceneExporter.h @@ -96,13 +96,13 @@ class SceneExporter: COLLADASW::LibraryVisualScenes, protected TransformWriter, { public: SceneExporter(COLLADASW::StreamWriter *sw, ArmatureExporter *arm, const ExportSettings *export_settings); - void exportScene(Depsgraph *depsgraph, Scene *sce); + void exportScene(bContext *C, Depsgraph *depsgraph, Scene *sce); private: friend class ArmatureExporter; - void exportHierarchy(struct Depsgraph *depsgraph, Scene *sce); - void writeNodes(struct Depsgraph *depsgraph, Object *ob, Scene *sce); - + void exportHierarchy(bContext *C, struct Depsgraph *depsgraph, Scene *sce); + void writeNodes(bContext *C, struct Depsgraph *depsgraph, Object *ob, Scene *sce); + ArmatureExporter *arm_exporter; const ExportSettings *export_settings; }; diff --git a/source/blender/collada/SkinInfo.cpp b/source/blender/collada/SkinInfo.cpp index a2cb8237d08..7ec3f04aabf 100644 --- a/source/blender/collada/SkinInfo.cpp +++ b/source/blender/collada/SkinInfo.cpp @@ -121,7 +121,7 @@ void SkinInfo::borrow_skin_controller_data(const COLLADAFW::SkinControllerData * unit_converter->dae_matrix_to_mat4_(bind_shape_matrix, skin->getBindShapeMatrix()); } - + void SkinInfo::free() { joints_per_vertex.releaseMemory(); @@ -199,7 +199,7 @@ const COLLADAFW::UniqueId& SkinInfo::get_controller_uid() } // check if this skin controller references a joint or any descendant of it -// +// // some nodes may not be referenced by SkinController, // in this case to determine if the node belongs to this armature, // we need to search down the tree @@ -259,9 +259,9 @@ void SkinInfo::link_armature(bContext *C, Object *ob, std::map<COLLADAFW::Unique // skip joints that have invalid UID if ((*it).joint_uid == COLLADAFW::UniqueId::INVALID) continue; - + // name group by joint node name - + if (joint_by_uid.find((*it).joint_uid) != joint_by_uid.end()) { name = bc_get_joint_name(joint_by_uid[(*it).joint_uid]); } diff --git a/source/blender/collada/SkinInfo.h b/source/blender/collada/SkinInfo.h index a399bff9e3c..fdfee0a943a 100644 --- a/source/blender/collada/SkinInfo.h +++ b/source/blender/collada/SkinInfo.h @@ -88,7 +88,7 @@ public: void transfer_uint_array_data_const(const COLLADAFW::UIntValuesArray& src, COLLADAFW::UIntValuesArray& dest); void borrow_skin_controller_data(const COLLADAFW::SkinControllerData* skin); - + void free(); // using inverse bind matrices to construct armature @@ -110,7 +110,7 @@ public: const COLLADAFW::UniqueId& get_controller_uid(); // check if this skin controller references a joint or any descendant of it - // + // // some nodes may not be referenced by SkinController, // in this case to determine if the node belongs to this armature, // we need to search down the tree diff --git a/source/blender/collada/TransformReader.cpp b/source/blender/collada/TransformReader.cpp index 7f742be7e30..bf9c34153b7 100644 --- a/source/blender/collada/TransformReader.cpp +++ b/source/blender/collada/TransformReader.cpp @@ -54,7 +54,7 @@ void TransformReader::get_node_mat( float copy[4][4]; unit_m4(mat); - + for (unsigned int i = 0; i < node->getTransformations().getCount(); i++) { COLLADAFW::Transformation *tm = node->getTransformations()[i]; @@ -87,11 +87,11 @@ void TransformReader::get_node_mat( copy_m4_m4(copy, mat); mul_m4_m4m4(mat, copy, cur); - + if (animation_map) { // AnimationList that drives this Transformation const COLLADAFW::UniqueId& anim_list_id = tm->getAnimationList(); - + // store this so later we can link animation data with ob Animation anim = {ob, node, tm}; (*animation_map)[anim_list_id] = anim; diff --git a/source/blender/collada/TransformReader.h b/source/blender/collada/TransformReader.h index 08bb17ccac1..6544aa1c040 100644 --- a/source/blender/collada/TransformReader.h +++ b/source/blender/collada/TransformReader.h @@ -19,7 +19,7 @@ * * ***** END GPL LICENSE BLOCK ***** */ - + /** \file TransformReader.h * \ingroup collada */ diff --git a/source/blender/collada/TransformWriter.cpp b/source/blender/collada/TransformWriter.cpp index 1fb54e99147..9f75a604f96 100644 --- a/source/blender/collada/TransformWriter.cpp +++ b/source/blender/collada/TransformWriter.cpp @@ -119,7 +119,7 @@ void TransformWriter::add_node_transform_ob(COLLADASW::Node& node, Object *ob, { float loc[3], rot[3], scale[3]; bc_decompose(f_obmat, loc, rot, NULL, scale); - add_transform(node, loc, rot, scale); + add_transform(node, loc, rot, scale); break; } } diff --git a/source/blender/collada/collada.cpp b/source/blender/collada/collada.cpp index 5def6638df6..bf310cb24d8 100644 --- a/source/blender/collada/collada.cpp +++ b/source/blender/collada/collada.cpp @@ -51,7 +51,8 @@ int collada_import(bContext *C, ImportSettings *import_settings) return (imp.import())? 1:0; } -int collada_export(Depsgraph *depsgraph, +int collada_export(bContext *C, + Depsgraph *depsgraph, Scene *sce, ExportSettings *export_settings) { @@ -80,7 +81,7 @@ int collada_export(Depsgraph *depsgraph, } DocumentExporter exporter(depsgraph, export_settings); - int status = exporter.exportCurrentScene(sce); + int status = exporter.exportCurrentScene(C, sce); BLI_linklist_free(export_settings->export_set, NULL); diff --git a/source/blender/collada/collada.h b/source/blender/collada/collada.h index 5cf526af1f2..a47463b5a7a 100644 --- a/source/blender/collada/collada.h +++ b/source/blender/collada/collada.h @@ -51,8 +51,8 @@ struct ViewLayer; int collada_import(struct bContext *C, ImportSettings *import_settings); - -int collada_export(struct Depsgraph *depsgraph, +int collada_export(struct bContext *C, + struct Depsgraph *depsgraph, struct Scene *sce, ExportSettings *export_settings); diff --git a/source/blender/collada/collada_internal.h b/source/blender/collada/collada_internal.h index 299e13326ce..1eac5b68778 100644 --- a/source/blender/collada/collada_internal.h +++ b/source/blender/collada/collada_internal.h @@ -51,7 +51,7 @@ private: float y_up_mat4[4][4]; float z_up_mat4[4][4]; float scale_mat4[4][4]; - + public: enum UnitSystem { @@ -66,11 +66,11 @@ public: void read_asset(const COLLADAFW::FileInfo *asset); void convertVector3(COLLADABU::Math::Vector3 &vec, float *v); - + UnitConverter::UnitSystem isMetricSystem(void); - + float getLinearMeter(void); - + // TODO need also for angle conversion, time conversion... void dae_matrix_to_mat4_(float out[4][4], const COLLADABU::Math::Matrix4& in); diff --git a/source/blender/collada/collada_utils.cpp b/source/blender/collada/collada_utils.cpp index bf441effc81..945dda68745 100644 --- a/source/blender/collada/collada_utils.cpp +++ b/source/blender/collada/collada_utils.cpp @@ -77,7 +77,7 @@ float bc_get_float_value(const COLLADAFW::FloatOrDoubleArray& array, unsigned in if (array.getType() == COLLADAFW::MeshVertexData::DATA_TYPE_FLOAT) return array.getFloatValues()->getData()[index]; - else + else return array.getDoubleValues()->getData()[index]; } @@ -85,10 +85,10 @@ float bc_get_float_value(const COLLADAFW::FloatOrDoubleArray& array, unsigned in int bc_test_parent_loop(Object *par, Object *ob) { /* test if 'ob' is a parent somewhere in par's parents */ - + if (par == NULL) return 0; if (ob == par) return 1; - + return bc_test_parent_loop(par->parent, ob); } @@ -117,7 +117,7 @@ int bc_set_parent(Object *ob, Object *par, bContext *C, bool is_parent_space) mul_m4_m4m4(mat, par->obmat, ob->obmat); copy_m4_m4(ob->obmat, mat); } - + // apply child obmat (i.e. decompose it into rot/loc/size) BKE_object_apply_mat4(ob, ob->obmat, 0, 0); @@ -231,7 +231,7 @@ Object *bc_get_assigned_armature(Object *ob) // IMPORTANT: This function expects that // all exported objects have set: // ob->id.tag & LIB_TAG_DOIT -Object *bc_get_highest_selected_ancestor_or_self(LinkNode *export_set, Object *ob) +Object *bc_get_highest_selected_ancestor_or_self(LinkNode *export_set, Object *ob) { Object *ancestor = ob; while (ob->parent && bc_is_marked(ob->parent)) { @@ -256,7 +256,7 @@ bool bc_is_in_Export_set(LinkNode *export_set, Object *ob) bool bc_has_object_type(LinkNode *export_set, short obtype) { LinkNode *node; - + for (node = export_set; node; node = node->next) { Object *ob = (Object *)node->link; /* XXX - why is this checking for ob->data? - we could be looking for empties */ @@ -290,7 +290,7 @@ void bc_bubble_sort_by_Object_name(LinkNode *export_set) for (node = export_set; node->next && !sorted; node = node->next) { sorted = true; - + LinkNode *current; for (current = export_set; current->next; current = current->next) { Object *a = (Object *)current->link; @@ -301,12 +301,12 @@ void bc_bubble_sort_by_Object_name(LinkNode *export_set) current->next->link = a; sorted = false; } - + } } } -/* Check if a bone is the top most exportable bone in the bone hierarchy. +/* Check if a bone is the top most exportable bone in the bone hierarchy. * When deform_bones_only == false, then only bones with NO parent * can be root bones. Otherwise the top most deform bones in the hierarchy * are root bones. @@ -367,13 +367,13 @@ void bc_match_scale(Object *ob, UnitConverter &bc_unit, bool scale_to_scene) BKE_object_apply_mat4(ob, ob->obmat, 0, 0); } -void bc_match_scale(std::vector<Object *> *objects_done, +void bc_match_scale(std::vector<Object *> *objects_done, UnitConverter &bc_unit, bool scale_to_scene) { for (std::vector<Object *>::iterator it = objects_done->begin(); it != objects_done->end(); - ++it) + ++it) { Object *ob = *it; if (ob -> parent == NULL) { @@ -781,7 +781,7 @@ float bc_get_property(Bone *bone, std::string key, float def) /** * Read a custom bone property and convert to matrix * Return true if conversion was succesfull -* +* * Return false if: * - the property does not exist * - is not an array of size 16 diff --git a/source/blender/collada/collada_utils.h b/source/blender/collada/collada_utils.h index 89765375afb..20c569834d8 100644 --- a/source/blender/collada/collada_utils.h +++ b/source/blender/collada/collada_utils.h @@ -92,8 +92,8 @@ extern void bc_bubble_sort_by_Object_name(LinkNode *export_set); extern bool bc_is_root_bone(Bone *aBone, bool deform_bones_only); extern int bc_get_active_UVLayer(Object *ob); -extern std::string bc_replace_string(std::string data, const std::string& pattern, const std::string& replacement); -extern std::string bc_url_encode(std::string data); +extern std::string bc_replace_string(std::string data, const std::string& pattern, const std::string& replacement); +extern std::string bc_url_encode(std::string data); extern void bc_match_scale(Object *ob, UnitConverter &bc_unit, bool scale_to_scene); extern void bc_match_scale(std::vector<Object *> *objects_done, UnitConverter &unit_converter, bool scale_to_scene); @@ -135,8 +135,8 @@ class BCPolygonNormalsIndices normal_indices.push_back(index); } - unsigned int operator[](unsigned int i) { - return normal_indices[i]; + unsigned int operator[](unsigned int i) { + return normal_indices[i]; } }; diff --git a/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cpp b/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cpp index 7786359c06a..f7fcf63fabb 100644 --- a/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cpp +++ b/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cpp @@ -31,6 +31,7 @@ #include "BLI_string.h" #include "BKE_image.h" #include "BKE_global.h" +#include "BKE_library.h" #include "BKE_main.h" #include "BKE_scene.h" @@ -100,11 +101,10 @@ void OutputOpenExrSingleLayerMultiViewOperation::deinitExecution() if (width != 0 && height != 0) { void *exrhandle; - Main *bmain = G.main; /* TODO, have this passed along */ char filename[FILE_MAX]; BKE_image_path_from_imtype( - filename, this->m_path, bmain->name, this->m_rd->cfra, R_IMF_IMTYPE_OPENEXR, + filename, this->m_path, BKE_main_blendfile_path_from_global(), this->m_rd->cfra, R_IMF_IMTYPE_OPENEXR, (this->m_rd->scemode & R_EXTENSION) != 0, true, NULL); exrhandle = this->get_handle(filename); @@ -190,11 +190,10 @@ void OutputOpenExrMultiLayerMultiViewOperation::deinitExecution() if (width != 0 && height != 0) { void *exrhandle; - Main *bmain = G.main; /* TODO, have this passed along */ char filename[FILE_MAX]; BKE_image_path_from_imtype( - filename, this->m_path, bmain->name, this->m_rd->cfra, R_IMF_IMTYPE_MULTILAYER, + filename, this->m_path, BKE_main_blendfile_path_from_global(), this->m_rd->cfra, R_IMF_IMTYPE_MULTILAYER, (this->m_rd->scemode & R_EXTENSION) != 0, true, NULL); exrhandle = this->get_handle(filename); @@ -283,7 +282,6 @@ void OutputStereoOperation::deinitExecution() if (BKE_scene_multiview_is_render_view_last(this->m_rd, this->m_viewName)) { ImBuf *ibuf[3] = {NULL}; const char *names[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME}; - Main *bmain = G.main; /* TODO, have this passed along */ char filename[FILE_MAX]; int i; @@ -307,7 +305,7 @@ void OutputStereoOperation::deinitExecution() ibuf[2] = IMB_stereo3d_ImBuf(this->m_format, ibuf[0], ibuf[1]); BKE_image_path_from_imformat( - filename, this->m_path, bmain->name, this->m_rd->cfra, this->m_format, + filename, this->m_path, BKE_main_blendfile_path_from_global(), this->m_rd->cfra, this->m_format, (this->m_rd->scemode & R_EXTENSION) != 0, true, NULL); BKE_imbuf_write(ibuf[2], filename, this->m_format); diff --git a/source/blender/compositor/operations/COM_OutputFileOperation.cpp b/source/blender/compositor/operations/COM_OutputFileOperation.cpp index db816816034..39877e35605 100644 --- a/source/blender/compositor/operations/COM_OutputFileOperation.cpp +++ b/source/blender/compositor/operations/COM_OutputFileOperation.cpp @@ -28,6 +28,7 @@ #include "BLI_string.h" #include "BKE_image.h" #include "BKE_global.h" +#include "BKE_library.h" #include "BKE_main.h" #include "BKE_scene.h" @@ -185,7 +186,6 @@ void OutputSingleLayerOperation::deinitExecution() int size = get_datatype_size(this->m_datatype); ImBuf *ibuf = IMB_allocImBuf(this->getWidth(), this->getHeight(), this->m_format->planes, 0); - Main *bmain = G.main; /* TODO, have this passed along */ char filename[FILE_MAX]; const char *suffix; @@ -200,7 +200,7 @@ void OutputSingleLayerOperation::deinitExecution() suffix = BKE_scene_multiview_view_suffix_get(this->m_rd, this->m_viewName); BKE_image_path_from_imformat( - filename, this->m_path, bmain->name, this->m_rd->cfra, this->m_format, + filename, this->m_path, BKE_main_blendfile_path_from_global(), this->m_rd->cfra, this->m_format, (this->m_rd->scemode & R_EXTENSION) != 0, true, suffix); if (0 == BKE_imbuf_write(ibuf, filename, this->m_format)) @@ -271,14 +271,13 @@ void OutputOpenExrMultiLayerOperation::deinitExecution() unsigned int width = this->getWidth(); unsigned int height = this->getHeight(); if (width != 0 && height != 0) { - Main *bmain = G.main; /* TODO, have this passed along */ char filename[FILE_MAX]; const char *suffix; void *exrhandle = IMB_exr_get_handle(); suffix = BKE_scene_multiview_view_suffix_get(this->m_rd, this->m_viewName); BKE_image_path_from_imtype( - filename, this->m_path, bmain->name, this->m_rd->cfra, R_IMF_IMTYPE_MULTILAYER, + filename, this->m_path, BKE_main_blendfile_path_from_global(), this->m_rd->cfra, R_IMF_IMTYPE_MULTILAYER, (this->m_rd->scemode & R_EXTENSION) != 0, true, suffix); BLI_make_existing_file(filename); diff --git a/source/blender/datatoc/datatoc_icon.c b/source/blender/datatoc/datatoc_icon.c index 92048f32a28..e5f82ae09c8 100644 --- a/source/blender/datatoc/datatoc_icon.c +++ b/source/blender/datatoc/datatoc_icon.c @@ -386,7 +386,7 @@ int main(int argc, char **argv) { const char *path_src; const char *file_dst; - + if (argc < 3) { printf("Usage: datatoc_icon <dir_icons> <data_icon_to.png>\n"); diff --git a/source/blender/depsgraph/DEG_depsgraph_query.h b/source/blender/depsgraph/DEG_depsgraph_query.h index 7a4d9a19335..1c4e11d1197 100644 --- a/source/blender/depsgraph/DEG_depsgraph_query.h +++ b/source/blender/depsgraph/DEG_depsgraph_query.h @@ -107,14 +107,8 @@ enum { DEG_ITER_OBJECT_FLAG_DUPLI = (1 << 4), }; -typedef enum eDepsObjectIteratorMode { - DEG_ITER_OBJECT_MODE_VIEWPORT = 0, - DEG_ITER_OBJECT_MODE_RENDER = 1, -} eDepsObjectIteratorMode; - typedef struct DEGObjectIterData { struct Depsgraph *graph; - eDepsObjectIteratorMode mode; int flag; struct Scene *scene; @@ -152,11 +146,10 @@ void DEG_iterator_objects_end(struct BLI_Iterator *iter); * Although they are available they have no overrides (collection_properties) * and will crash if you try to access it. */ -#define DEG_OBJECT_ITER_BEGIN(graph_, instance_, mode_, flag_) \ +#define DEG_OBJECT_ITER_BEGIN(graph_, instance_, flag_) \ { \ DEGObjectIterData data_ = { \ graph_, \ - mode_, \ flag_ \ }; \ \ @@ -172,8 +165,8 @@ void DEG_iterator_objects_end(struct BLI_Iterator *iter); /** * Depsgraph objects iterator for draw manager and final render */ -#define DEG_OBJECT_ITER_FOR_RENDER_ENGINE_BEGIN(graph_, instance_, mode_) \ - DEG_OBJECT_ITER_BEGIN(graph_, instance_, mode_, \ +#define DEG_OBJECT_ITER_FOR_RENDER_ENGINE_BEGIN(graph_, instance_) \ + DEG_OBJECT_ITER_BEGIN(graph_, instance_, \ DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY | \ DEG_ITER_OBJECT_FLAG_LINKED_VIA_SET | \ DEG_ITER_OBJECT_FLAG_VISIBLE | \ diff --git a/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc b/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc index 026aa309b02..feaba1a4aa8 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc @@ -68,7 +68,9 @@ struct CyclesSolverState { : graph(graph), traversal_stack(BLI_stack_new(sizeof(StackEntry), "DEG detect cycles stack")), - num_cycles(0) { + num_cycles(0) + { + /* pass */ } ~CyclesSolverState() { BLI_stack_free(traversal_stack); diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc index f01baed06c3..aaf96a47711 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc @@ -378,17 +378,32 @@ void DepsgraphNodeBuilder::end_build() } } -void DepsgraphNodeBuilder::build_id(ID* id) { +void DepsgraphNodeBuilder::build_id(ID *id) { if (id == NULL) { return; } switch (GS(id->name)) { + case ID_AR: + build_armature((bArmature *)id); + break; + case ID_CA: + build_camera((Camera *)id); + break; case ID_GR: - build_collection((Collection *)id); + build_collection(DEG_COLLECTION_OWNER_UNKNOWN, (Collection *)id); break; case ID_OB: build_object(-1, (Object *)id, DEG_ID_LINKED_INDIRECTLY); break; + case ID_KE: + build_shapekeys((Key *)id); + break; + case ID_LA: + build_lamp((Lamp *)id); + break; + case ID_LP: + build_lightprobe((LightProbe *)id); + break; case ID_NT: build_nodetree((bNodeTree *)id); break; @@ -410,33 +425,45 @@ void DepsgraphNodeBuilder::build_id(ID* id) { case ID_MC: build_movieclip((MovieClip *)id); break; + case ID_ME: + case ID_CU: + case ID_MB: + case ID_LT: + build_object_data_geometry_datablock(id); + break; default: fprintf(stderr, "Unhandled ID %s\n", id->name); + BLI_assert(!"Should never happen"); + break; } } -void DepsgraphNodeBuilder::build_collection(Collection *collection) +void DepsgraphNodeBuilder::build_collection( + eDepsNode_CollectionOwner owner_type, + Collection *collection) { if (built_map_.checkIsBuiltAndTag(collection)) { return; } - - const int restrict_flag = (graph_->mode == DAG_EVAL_VIEWPORT) ? - COLLECTION_RESTRICT_VIEW : COLLECTION_RESTRICT_RENDER; - if (collection->flag & restrict_flag) { - return; + const bool allow_restrict_flags = (owner_type == DEG_COLLECTION_OWNER_SCENE); + if (allow_restrict_flags) { + const int restrict_flag = (graph_->mode == DAG_EVAL_VIEWPORT) + ? COLLECTION_RESTRICT_VIEW + : COLLECTION_RESTRICT_RENDER; + if (collection->flag & restrict_flag) { + return; + } } - + /* Collection itself. */ + add_id_node(&collection->id); /* Build collection objects. */ LISTBASE_FOREACH (CollectionObject *, cob, &collection->gobject) { build_object(-1, cob->ob, DEG_ID_LINKED_INDIRECTLY); } /* Build child collections. */ LISTBASE_FOREACH (CollectionChild *, child, &collection->children) { - build_collection(child->collection); + build_collection(owner_type, child->collection); } - - add_id_node(&collection->id); } void DepsgraphNodeBuilder::build_object(int base_index, @@ -508,7 +535,7 @@ void DepsgraphNodeBuilder::build_object(int base_index, } /* Object dupligroup. */ if (object->dup_group != NULL) { - build_collection(object->dup_group); + build_collection(DEG_COLLECTION_OWNER_OBJECT, object->dup_group); } } @@ -549,7 +576,7 @@ void DepsgraphNodeBuilder::build_object_data(Object *object) case OB_SURF: case OB_MBALL: case OB_LATTICE: - build_obdata_geom(object); + build_object_data_geometry(object); /* TODO(sergey): Only for until we support granular * update of curves. */ @@ -569,13 +596,13 @@ void DepsgraphNodeBuilder::build_object_data(Object *object) } break; case OB_LAMP: - build_lamp(object); + build_object_data_lamp(object); break; case OB_CAMERA: - build_camera(object); + build_object_data_camera(object); break; case OB_LIGHTPROBE: - build_lightprobe(object); + build_object_data_lightprobe(object); break; default: { @@ -588,6 +615,28 @@ void DepsgraphNodeBuilder::build_object_data(Object *object) } } +void DepsgraphNodeBuilder::build_object_data_camera(Object *object) +{ + Camera *camera = (Camera *)object->data; + build_camera(camera); +} + +void DepsgraphNodeBuilder::build_object_data_lamp(Object *object) +{ + Lamp *lamp = (Lamp *)object->data; + build_lamp(lamp); +} + +void DepsgraphNodeBuilder::build_object_data_lightprobe(Object *object) +{ + LightProbe *probe = (LightProbe *)object->data; + build_lightprobe(probe); + add_operation_node(&object->id, + DEG_NODE_TYPE_PARAMETERS, + NULL, + DEG_OPCODE_LIGHT_PROBE_EVAL); +} + void DepsgraphNodeBuilder::build_object_transform(Object *object) { OperationDepsNode *op_node; @@ -923,7 +972,7 @@ void DepsgraphNodeBuilder::build_particles(Object *object) break; case PART_DRAW_GR: if (part->dup_group != NULL) { - build_collection(part->dup_group); + build_collection(DEG_COLLECTION_OWNER_OBJECT, part->dup_group); } break; } @@ -968,6 +1017,9 @@ void DepsgraphNodeBuilder::build_cloth(Object *object) /* Shapekeys */ void DepsgraphNodeBuilder::build_shapekeys(Key *key) { + if (built_map_.checkIsBuiltAndTag(key)) { + return; + } build_animdata(&key->id); add_operation_node(&key->id, DEG_NODE_TYPE_GEOMETRY, @@ -977,12 +1029,11 @@ void DepsgraphNodeBuilder::build_shapekeys(Key *key) /* ObData Geometry Evaluation */ // XXX: what happens if the datablock is shared! -void DepsgraphNodeBuilder::build_obdata_geom(Object *object) +void DepsgraphNodeBuilder::build_object_data_geometry(Object *object) { OperationDepsNode *op_node; Scene *scene_cow = get_cow_datablock(scene_); Object *object_cow = get_cow_datablock(object); - /* Temporary uber-update node, which does everything. * It is for the being we're porting old dependencies into the new system. * We'll get rid of this node as soon as all the granular update functions @@ -1005,17 +1056,14 @@ void DepsgraphNodeBuilder::build_obdata_geom(Object *object) DEG_OPCODE_PLACEHOLDER, "Eval Init"); op_node->set_as_entry(); - // TODO: "Done" operation - /* Cloth modifier. */ LISTBASE_FOREACH (ModifierData *, md, &object->modifiers) { if (md->type == eModifierType_Cloth) { build_cloth(object); } } - - /* materials */ + /* Materials. */ if (object->totcol != 0) { if (object->type == OB_MESH) { add_operation_node(&object->id, @@ -1033,37 +1081,36 @@ void DepsgraphNodeBuilder::build_obdata_geom(Object *object) } } } - - /* geometry collision */ + /* Geometry collision. */ if (ELEM(object->type, OB_MESH, OB_CURVE, OB_LATTICE)) { // add geometry collider relations } + build_object_data_geometry_datablock((ID *)object->data); +} - ID *obdata = (ID *)object->data; +void DepsgraphNodeBuilder::build_object_data_geometry_datablock(ID *obdata) +{ if (built_map_.checkIsBuiltAndTag(obdata)) { return; } + OperationDepsNode *op_node; /* Make sure we've got an ID node before requesting CoW pointer. */ (void) add_id_node((ID *)obdata); ID *obdata_cow = get_cow_id(obdata); - + /* Animation. */ + build_animdata(obdata); /* ShapeKeys */ - Key *key = BKE_key_from_object(object); + Key *key = BKE_key_from_id(obdata); if (key) { build_shapekeys(key); } - - build_animdata(obdata); - /* Nodes for result of obdata's evaluation, and geometry * evaluation on object. */ - switch (object->type) { - case OB_MESH: + const ID_Type id_type = GS(obdata->name); + switch (id_type) { + case ID_ME: { - //Mesh *me = (Mesh *)object->data; - - /* evaluation operations */ op_node = add_operation_node(obdata, DEG_NODE_TYPE_GEOMETRY, function_bind(BKE_mesh_eval_geometry, @@ -1074,41 +1121,18 @@ void DepsgraphNodeBuilder::build_obdata_geom(Object *object) op_node->set_as_entry(); break; } - - case OB_MBALL: + case ID_MB: { - Object *mom = BKE_mball_basis_find(scene_, object); - /* NOTE: Only the motherball gets evaluated, it's children are - * having empty placeholders for the correct relations being built. - */ - if (mom == object) { - /* metaball evaluation operations */ - op_node = add_operation_node(obdata, - DEG_NODE_TYPE_GEOMETRY, - function_bind( - BKE_mball_eval_geometry, - _1, - (MetaBall *)obdata_cow), - DEG_OPCODE_PLACEHOLDER, - "Geometry Eval"); - } - else { - op_node = add_operation_node(obdata, - DEG_NODE_TYPE_GEOMETRY, - NULL, - DEG_OPCODE_PLACEHOLDER, - "Geometry Eval"); - op_node->set_as_entry(); - } + op_node = add_operation_node(obdata, + DEG_NODE_TYPE_GEOMETRY, + NULL, + DEG_OPCODE_PLACEHOLDER, + "Geometry Eval"); + op_node->set_as_entry(); break; } - - case OB_CURVE: - case OB_SURF: - case OB_FONT: + case ID_CU: { - /* Curve/nurms evaluation operations. */ - /* - calculate curve geometry (including path) */ op_node = add_operation_node(obdata, DEG_NODE_TYPE_GEOMETRY, function_bind(BKE_curve_eval_geometry, @@ -1127,15 +1151,13 @@ void DepsgraphNodeBuilder::build_obdata_geom(Object *object) if (cu->taperobj != NULL) { build_object(-1, cu->taperobj, DEG_ID_LINKED_INDIRECTLY); } - if (object->type == OB_FONT && cu->textoncurve != NULL) { + if (cu->textoncurve != NULL) { build_object(-1, cu->textoncurve, DEG_ID_LINKED_INDIRECTLY); } break; } - - case OB_LATTICE: + case ID_LT: { - /* Lattice evaluation operations. */ op_node = add_operation_node(obdata, DEG_NODE_TYPE_GEOMETRY, function_bind(BKE_lattice_eval_geometry, @@ -1146,18 +1168,18 @@ void DepsgraphNodeBuilder::build_obdata_geom(Object *object) op_node->set_as_entry(); break; } + default: + BLI_assert(!"Should not happen"); + break; } - op_node = add_operation_node(obdata, DEG_NODE_TYPE_GEOMETRY, NULL, DEG_OPCODE_PLACEHOLDER, "Eval Done"); op_node->set_as_exit(); - /* Parameters for driver sources. */ add_operation_node(obdata, DEG_NODE_TYPE_PARAMETERS, NULL, DEG_OPCODE_PARAMETERS_EVAL); - /* Batch cache. */ add_operation_node(obdata, DEG_NODE_TYPE_BATCH_CACHE, @@ -1167,35 +1189,46 @@ void DepsgraphNodeBuilder::build_obdata_geom(Object *object) DEG_OPCODE_GEOMETRY_SELECT_UPDATE); } -/* Cameras */ -void DepsgraphNodeBuilder::build_camera(Object *object) +void DepsgraphNodeBuilder::build_armature(bArmature *armature) { - /* Object data. */ - /* TODO: Link scene-camera links in somehow... */ - Camera *camera = (Camera *)object->data; - if (built_map_.checkIsBuiltAndTag(camera)) { + if (built_map_.checkIsBuiltAndTag(armature)) { return; } - build_animdata(&camera->id); - add_operation_node(&camera->id, + build_animdata(&armature->id); + /* Make sure pose is up-to-date with armature updates. */ + add_operation_node(&armature->id, DEG_NODE_TYPE_PARAMETERS, NULL, - DEG_OPCODE_PARAMETERS_EVAL); + DEG_OPCODE_PLACEHOLDER, + "Armature Eval"); } -/* Lamps */ -void DepsgraphNodeBuilder::build_lamp(Object *object) +void DepsgraphNodeBuilder::build_camera(Camera *camera) +{ + if (built_map_.checkIsBuiltAndTag(camera)) { + return; + } + OperationDepsNode *op_node; + build_animdata(&camera->id); + op_node = add_operation_node(&camera->id, + DEG_NODE_TYPE_PARAMETERS, + NULL, + DEG_OPCODE_PARAMETERS_EVAL); + op_node->set_as_exit(); +} + +void DepsgraphNodeBuilder::build_lamp(Lamp *lamp) { - /* Object data. */ - Lamp *lamp = (Lamp *)object->data; if (built_map_.checkIsBuiltAndTag(lamp)) { return; } + OperationDepsNode *op_node; build_animdata(&lamp->id); - add_operation_node(&lamp->id, - DEG_NODE_TYPE_PARAMETERS, - NULL, - DEG_OPCODE_PARAMETERS_EVAL); + op_node = add_operation_node(&lamp->id, + DEG_NODE_TYPE_PARAMETERS, + NULL, + DEG_OPCODE_PARAMETERS_EVAL); + op_node->set_as_exit(); /* lamp's nodetree */ build_nodetree(lamp->nodetree); } @@ -1405,9 +1438,8 @@ void DepsgraphNodeBuilder::build_movieclip(MovieClip *clip) DEG_OPCODE_MOVIECLIP_EVAL); } -void DepsgraphNodeBuilder::build_lightprobe(Object *object) +void DepsgraphNodeBuilder::build_lightprobe(LightProbe *probe) { - LightProbe *probe = (LightProbe *)object->data; if (built_map_.checkIsBuiltAndTag(probe)) { return; } @@ -1415,13 +1447,7 @@ void DepsgraphNodeBuilder::build_lightprobe(Object *object) add_operation_node(&probe->id, DEG_NODE_TYPE_PARAMETERS, NULL, - DEG_OPCODE_PLACEHOLDER, - "LightProbe Eval"); - add_operation_node(&object->id, - DEG_NODE_TYPE_PARAMETERS, - NULL, - DEG_OPCODE_PLACEHOLDER, - "LightProbe Eval"); + DEG_OPCODE_LIGHT_PROBE_EVAL); build_animdata(&probe->id); } diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h index b7c5a33f2c0..72aa5dbe003 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h @@ -36,7 +36,9 @@ #include "DEG_depsgraph.h" struct Base; +struct bArmature; struct CacheFile; +struct Camera; struct bGPdata; struct ListBase; struct GHash; @@ -45,7 +47,9 @@ struct Image; struct FCurve; struct Collection; struct Key; +struct Lamp; struct LayerCollection; +struct LightProbe; struct Main; struct Material; struct Mask; @@ -155,9 +159,10 @@ struct DepsgraphNodeBuilder { void build_id(ID* id); void build_layer_collections(ListBase *lb); void build_view_layer(Scene *scene, - ViewLayer *view_layer, - eDepsNode_LinkedState_Type linked_state); - void build_collection(Collection *collection); + ViewLayer *view_layer, + eDepsNode_LinkedState_Type linked_state); + void build_collection(eDepsNode_CollectionOwner owner_type, + Collection *collection); void build_object(int base_index, Object *object, eDepsNode_LinkedState_Type linked_state); @@ -165,6 +170,11 @@ struct DepsgraphNodeBuilder { Object *object, eDepsNode_LinkedState_Type linked_state); void build_object_data(Object *object); + void build_object_data_camera(Object *object); + void build_object_data_geometry(Object *object); + void build_object_data_geometry_datablock(ID *obdata); + void build_object_data_lamp(Object *object); + void build_object_data_lightprobe(Object *object); void build_object_transform(Object *object); void build_object_constraints(Object *object); void build_pose_constraints(Object *object, bPoseChannel *pchan, int pchan_index); @@ -184,10 +194,10 @@ struct DepsgraphNodeBuilder { bConstraint *con); void build_rig(Object *object); void build_proxy_rig(Object *object); + void build_armature(bArmature *armature); void build_shapekeys(Key *key); - void build_obdata_geom(Object *object); - void build_camera(Object *object); - void build_lamp(Object *object); + void build_camera(Camera *camera); + void build_lamp(Lamp *lamp); void build_nodetree(bNodeTree *ntree); void build_material(Material *ma); void build_texture(Tex *tex); @@ -198,7 +208,7 @@ struct DepsgraphNodeBuilder { void build_cachefile(CacheFile *cache_file); void build_mask(Mask *mask); void build_movieclip(MovieClip *clip); - void build_lightprobe(Object *object); + void build_lightprobe(LightProbe *probe); protected: struct SavedEntryTag { diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc index d3c4ce01674..00d7a5da455 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc @@ -148,7 +148,6 @@ void DepsgraphNodeBuilder::build_rig(Object *object) Scene *scene_cow = get_cow_datablock(scene_); Object *object_cow = get_cow_datablock(object); OperationDepsNode *op_node; - /* Animation and/or drivers linking posebones to base-armature used to * define them. * @@ -158,16 +157,8 @@ void DepsgraphNodeBuilder::build_rig(Object *object) * mechanism in-between here to ensure that we can use same rig * multiple times in same scene. */ - if (!built_map_.checkIsBuiltAndTag(armature)) { - build_animdata(&armature->id); - /* Make sure pose is up-to-date with armature updates. */ - add_operation_node(&armature->id, - DEG_NODE_TYPE_PARAMETERS, - NULL, - DEG_OPCODE_PLACEHOLDER, - "Armature Eval"); - } - + /* Armature. */ + build_armature(armature); /* Rebuild pose if not up to date. */ if (object->pose == NULL || (object->pose->flag & POSE_RECALC)) { BKE_pose_rebuild(object, armature); @@ -179,15 +170,13 @@ void DepsgraphNodeBuilder::build_rig(Object *object) object->adt->recalc |= ADT_RECALC_ANIM; } } - - /* speed optimization for animation lookups */ + /* Speed optimization for animation lookups. */ if (object->pose != NULL) { BKE_pose_channels_hash_make(object->pose); if (object->pose->flag & POSE_CONSTRAINTS_NEED_UPDATE_FLAGS) { BKE_pose_update_constraint_flags(object->pose); } } - /** * Pose Rig Graph * ============== @@ -209,8 +198,7 @@ void DepsgraphNodeBuilder::build_rig(Object *object) * only so that we can redirect those to point at either the the post-IK/ * post-constraint/post-matrix steps, as needed. */ - - /* pose eval context */ + /* Pose eval context. */ op_node = add_operation_node(&object->id, DEG_NODE_TYPE_EVAL_POSE, function_bind(BKE_pose_eval_init, @@ -236,8 +224,7 @@ void DepsgraphNodeBuilder::build_rig(Object *object) object_cow), DEG_OPCODE_POSE_DONE); op_node->set_as_exit(); - - /* bones */ + /* Bones. */ int pchan_index = 0; LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) { /* Node for bone evaluation. */ @@ -302,25 +289,23 @@ void DepsgraphNodeBuilder::build_rig(Object *object) break; } } - /* Custom shape. */ if (pchan->custom != NULL) { build_object(-1, pchan->custom, DEG_ID_LINKED_INDIRECTLY); } - pchan_index++; } } void DepsgraphNodeBuilder::build_proxy_rig(Object *object) { - bArmature *arm = (bArmature *)object->data; + bArmature *armature = (bArmature *)object->data; OperationDepsNode *op_node; Object *object_cow = get_cow_datablock(object); /* Sanity check. */ BLI_assert(object->pose != NULL); - /* Animation. */ - build_animdata(&arm->id); + /* Armature. */ + build_armature(armature); /* speed optimization for animation lookups */ BKE_pose_channels_hash_make(object->pose); if (object->pose->flag & POSE_CONSTRAINTS_NEED_UPDATE_FLAGS) { diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes_view_layer.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes_view_layer.cc index 3fc97ee3fcf..e2526272570 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes_view_layer.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes_view_layer.cc @@ -71,13 +71,13 @@ void DepsgraphNodeBuilder::build_layer_collections(ListBase *lb) COLLECTION_RESTRICT_VIEW : COLLECTION_RESTRICT_RENDER; for (LayerCollection *lc = (LayerCollection *)lb->first; lc; lc = lc->next) { - if (!(lc->collection->flag & restrict_flag)) { - if (!(lc->flag & LAYER_COLLECTION_EXCLUDE)) { - build_collection(lc->collection); - } - - build_layer_collections(&lc->layer_collections); + if (lc->collection->flag & restrict_flag) { + continue; + } + if ((lc->flag & LAYER_COLLECTION_EXCLUDE) == 0) { + build_collection(DEG_COLLECTION_OWNER_SCENE, lc->collection); } + build_layer_collections(&lc->layer_collections); } } diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc index d5ea8103742..eb1ee0c1535 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc @@ -161,6 +161,9 @@ static bool particle_system_depends_on_time(ParticleSystem *psys) static bool object_particles_depends_on_time(Object *object) { + if (object->type != OB_MESH) { + return false; + } LISTBASE_FOREACH (ParticleSystem *, psys, &object->particlesystem) { if (particle_system_depends_on_time(psys)) { return true; @@ -396,12 +399,27 @@ void DepsgraphRelationBuilder::build_id(ID *id) return; } switch (GS(id->name)) { + case ID_AR: + build_armature((bArmature *)id); + break; + case ID_CA: + build_camera((Camera *)id); + break; case ID_GR: - build_collection(NULL, (Collection *)id); + build_collection(DEG_COLLECTION_OWNER_UNKNOWN, NULL, (Collection *)id); break; case ID_OB: build_object(NULL, (Object *)id); break; + case ID_KE: + build_shapekeys((Key *)id); + break; + case ID_LA: + build_lamp((Lamp *)id); + break; + case ID_LP: + build_lightprobe((LightProbe *)id); + break; case ID_NT: build_nodetree((bNodeTree *)id); break; @@ -420,19 +438,33 @@ void DepsgraphRelationBuilder::build_id(ID *id) case ID_MC: build_movieclip((MovieClip *)id); break; + case ID_ME: + case ID_CU: + case ID_MB: + case ID_LT: + build_object_data_geometry_datablock(id); + break; default: fprintf(stderr, "Unhandled ID %s\n", id->name); + BLI_assert(!"Should never happen"); + break; } } -void DepsgraphRelationBuilder::build_collection(Object *object, Collection *collection) +void DepsgraphRelationBuilder::build_collection( + eDepsNode_CollectionOwner owner_type, + Object *object, + Collection *collection) { - const int restrict_flag = (graph_->mode == DAG_EVAL_VIEWPORT) ? - COLLECTION_RESTRICT_VIEW : COLLECTION_RESTRICT_RENDER; - if (collection->flag & restrict_flag) { - return; + const bool allow_restrict_flags = (owner_type == DEG_COLLECTION_OWNER_SCENE); + if (allow_restrict_flags) { + const int restrict_flag = (graph_->mode == DAG_EVAL_VIEWPORT) + ? COLLECTION_RESTRICT_VIEW + : COLLECTION_RESTRICT_RENDER; + if (collection->flag & restrict_flag) { + return; + } } - const bool group_done = built_map_.checkIsBuiltAndTag(collection); OperationKey object_local_transform_key(object != NULL ? &object->id : NULL, DEG_NODE_TYPE_TRANSFORM, @@ -442,12 +474,17 @@ void DepsgraphRelationBuilder::build_collection(Object *object, Collection *coll build_object(NULL, cob->ob); } LISTBASE_FOREACH (CollectionChild *, child, &collection->children) { - build_collection(NULL, child->collection); + build_collection(owner_type, NULL, child->collection); } } if (object != NULL) { const ListBase group_objects = BKE_collection_object_cache_get(collection); + const int base_flag = (graph_->mode == DAG_EVAL_VIEWPORT) ? + BASE_VISIBLE_VIEWPORT : BASE_VISIBLE_RENDER; LISTBASE_FOREACH (Base *, base, &group_objects) { + if ((base->flag & base_flag) == 0) { + continue; + } ComponentKey dupli_transform_key(&base->object->id, DEG_NODE_TYPE_TRANSFORM); add_relation(dupli_transform_key, object_local_transform_key, "Dupligroup"); } @@ -560,7 +597,7 @@ void DepsgraphRelationBuilder::build_object(Base *base, Object *object) /* Object dupligroup. */ if (object->dup_group != NULL) { - build_collection(object, object->dup_group); + build_collection(DEG_COLLECTION_OWNER_OBJECT, object, object->dup_group); } } @@ -597,7 +634,7 @@ void DepsgraphRelationBuilder::build_object_data(Object *object) case OB_MBALL: case OB_LATTICE: { - build_obdata_geom(object); + build_object_data_geometry(object); break; } case OB_ARMATURE: @@ -609,13 +646,13 @@ void DepsgraphRelationBuilder::build_object_data(Object *object) } break; case OB_LAMP: - build_lamp(object); + build_object_data_lamp(object); break; case OB_CAMERA: - build_camera(object); + build_object_data_camera(object); break; case OB_LIGHTPROBE: - build_lightprobe(object); + build_object_data_lightprobe(object); break; } Key *key = BKE_key_from_object(object); @@ -627,6 +664,37 @@ void DepsgraphRelationBuilder::build_object_data(Object *object) } } +void DepsgraphRelationBuilder::build_object_data_camera(Object *object) +{ + Camera *camera = (Camera *)object->data; + build_camera(camera); + ComponentKey object_parameters_key(&object->id, DEG_NODE_TYPE_PARAMETERS); + ComponentKey camera_parameters_key(&camera->id, DEG_NODE_TYPE_PARAMETERS); + add_relation(camera_parameters_key, object_parameters_key, "Camera -> Object"); +} + +void DepsgraphRelationBuilder::build_object_data_lamp(Object *object) +{ + Lamp *lamp = (Lamp *)object->data; + build_lamp(lamp); + ComponentKey object_parameters_key(&object->id, DEG_NODE_TYPE_PARAMETERS); + ComponentKey lamp_parameters_key(&lamp->id, DEG_NODE_TYPE_PARAMETERS); + add_relation(lamp_parameters_key, object_parameters_key, "Lamp -> Object"); +} + +void DepsgraphRelationBuilder::build_object_data_lightprobe(Object *object) +{ + LightProbe *probe = (LightProbe *)object->data; + build_lightprobe(probe); + OperationKey probe_key(&probe->id, + DEG_NODE_TYPE_PARAMETERS, + DEG_OPCODE_LIGHT_PROBE_EVAL); + OperationKey object_key(&object->id, + DEG_NODE_TYPE_PARAMETERS, + DEG_OPCODE_LIGHT_PROBE_EVAL); + add_relation(probe_key, object_key, "LightProbe Update"); +} + void DepsgraphRelationBuilder::build_object_parent(Object *object) { /* XXX: for now, need to use the component key (not just direct to the parent op), @@ -1540,7 +1608,7 @@ void DepsgraphRelationBuilder::build_particles(Object *object) break; case PART_DRAW_GR: if (part->dup_group != NULL) { - build_collection(NULL, part->dup_group); + build_collection(DEG_COLLECTION_OWNER_OBJECT, NULL, part->dup_group); LISTBASE_FOREACH (CollectionObject *, go, &part->dup_group->gobject) { build_particles_visualization_object(object, psys, @@ -1612,27 +1680,13 @@ void DepsgraphRelationBuilder::build_cloth(Object *object, } /* Shapekeys */ -void DepsgraphRelationBuilder::build_shapekeys(ID *obdata, Key *key) +void DepsgraphRelationBuilder::build_shapekeys(Key *key) { - ComponentKey obdata_key(obdata, DEG_NODE_TYPE_GEOMETRY); - + if (built_map_.checkIsBuiltAndTag(key)) { + return; + } /* attach animdata to geometry */ build_animdata(&key->id); - - if (key->adt) { - // TODO: this should really be handled in build_animdata, since many of these cases will need it - if (key->adt->action || key->adt->nla_tracks.first) { - ComponentKey adt_key(&key->id, DEG_NODE_TYPE_ANIMATION); - add_relation(adt_key, obdata_key, "Animation"); - } - - /* NOTE: individual shapekey drivers are handled above already */ - } - - /* attach to geometry */ - // XXX: aren't shapekeys now done as a pseudo-modifier on object? - //ComponentKey key_key(&key->id, DEG_NODE_TYPE_GEOMETRY); // FIXME: this doesn't exist - //add_relation(key_key, obdata_key, "Shapekeys"); } /** @@ -1640,56 +1694,53 @@ void DepsgraphRelationBuilder::build_shapekeys(ID *obdata, Key *key) * ========================== * * The evaluation of geometry on objects is as follows: - * - The actual evaluated of the derived geometry (e.g. DerivedMesh, DispList, etc.) - * occurs in the Geometry component of the object which references this. This includes - * modifiers, and the temporary "ubereval" for geometry. - * - Therefore, each user of a piece of shared geometry data ends up evaluating its own - * version of the stuff, complete with whatever modifiers it may use. + * - The actual evaluated of the derived geometry (e.g. DerivedMesh, DispList) + * occurs in the Geometry component of the object which references this. + * This includes modifiers, and the temporary "ubereval" for geometry. + * Therefore, each user of a piece of shared geometry data ends up evaluating + * its own version of the stuff, complete with whatever modifiers it may use. * - * - The datablocks for the geometry data - "obdata" (e.g. ID_ME, ID_CU, ID_LT, etc.) are used for + * - The datablocks for the geometry data - "obdata" (e.g. ID_ME, ID_CU, ID_LT.) + * are used for * 1) calculating the bounding boxes of the geometry data, - * 2) aggregating inward links from other objects (e.g. for text on curve, etc.) + * 2) aggregating inward links from other objects (e.g. for text on curve) * and also for the links coming from the shapekey datablocks - * - Animation/Drivers affecting the parameters of the geometry are made to trigger - * updates on the obdata geometry component, which then trigger downstream - * re-evaluation of the individual instances of this geometry. + * - Animation/Drivers affecting the parameters of the geometry are made to + * trigger updates on the obdata geometry component, which then trigger + * downstream re-evaluation of the individual instances of this geometry. */ -// TODO: Materials and lighting should probably get their own component, instead of being lumped under geometry? -void DepsgraphRelationBuilder::build_obdata_geom(Object *object) +void DepsgraphRelationBuilder::build_object_data_geometry(Object *object) { ID *obdata = (ID *)object->data; - /* Init operation of object-level geometry evaluation. */ - OperationKey geom_init_key(&object->id, DEG_NODE_TYPE_GEOMETRY, DEG_OPCODE_PLACEHOLDER, "Eval Init"); - - /* get nodes for result of obdata's evaluation, and geometry evaluation on object */ + OperationKey geom_init_key(&object->id, + DEG_NODE_TYPE_GEOMETRY, + DEG_OPCODE_PLACEHOLDER, + "Eval Init"); + /* Get nodes for result of obdata's evaluation, and geometry evaluation + * on object. + */ ComponentKey obdata_geom_key(obdata, DEG_NODE_TYPE_GEOMETRY); ComponentKey geom_key(&object->id, DEG_NODE_TYPE_GEOMETRY); - - /* link components to each other */ + /* Link components to each other. */ add_relation(obdata_geom_key, geom_key, "Object Geometry Base Data"); - OperationKey obdata_ubereval_key(&object->id, DEG_NODE_TYPE_GEOMETRY, DEG_OPCODE_GEOMETRY_UBEREVAL); - - /* Special case: modifiers and DerivedMesh creation queries scene for various - * things like data mask to be used. We add relation here to ensure object is - * never evaluated prior to Scene's CoW is ready. + /* Special case: modifiers evaluation queries scene for various things like + * data mask to be used. We add relation here to ensure object is never + * evaluated prior to Scene's CoW is ready. */ OperationKey scene_key(&scene_->id, - DEG_NODE_TYPE_PARAMETERS, - DEG_OPCODE_PLACEHOLDER, - "Scene Eval"); + DEG_NODE_TYPE_LAYER_COLLECTIONS, + DEG_OPCODE_VIEW_LAYER_EVAL); DepsRelation *rel = add_relation(scene_key, obdata_ubereval_key, "CoW Relation"); rel->flag |= DEPSREL_FLAG_NO_FLUSH; - /* Modifiers */ if (object->modifiers.first != NULL) { ModifierUpdateDepsgraphContext ctx = {}; ctx.scene = scene_; ctx.object = object; - LISTBASE_FOREACH (ModifierData *, md, &object->modifiers) { const ModifierTypeInfo *mti = modifierType_getInfo((ModifierType)md->type); if (mti->updateDepsgraph) { @@ -1706,8 +1757,7 @@ void DepsgraphRelationBuilder::build_obdata_geom(Object *object) } } } - - /* materials */ + /* Materials. */ if (object->totcol) { for (int a = 1; a <= object->totcol; a++) { Material *ma = give_current_material(object, a); @@ -1718,179 +1768,183 @@ void DepsgraphRelationBuilder::build_obdata_geom(Object *object) OperationKey material_key(&ma->id, DEG_NODE_TYPE_SHADING, DEG_OPCODE_MATERIAL_UPDATE); - OperationKey shading_key(&object->id, DEG_NODE_TYPE_SHADING, DEG_OPCODE_SHADING); + OperationKey shading_key(&object->id, + DEG_NODE_TYPE_SHADING, + DEG_OPCODE_SHADING); add_relation(material_key, shading_key, "Material Update"); } } } } - - /* geometry collision */ + /* Geometry collision. */ if (ELEM(object->type, OB_MESH, OB_CURVE, OB_LATTICE)) { // add geometry collider relations } - /* Make sure uber update is the last in the dependencies. * * TODO(sergey): Get rid of this node. */ if (object->type != OB_ARMATURE) { /* Armatures does no longer require uber node. */ - OperationKey obdata_ubereval_key(&object->id, DEG_NODE_TYPE_GEOMETRY, DEG_OPCODE_GEOMETRY_UBEREVAL); - add_relation(geom_init_key, obdata_ubereval_key, "Object Geometry UberEval"); + OperationKey obdata_ubereval_key(&object->id, + DEG_NODE_TYPE_GEOMETRY, + DEG_OPCODE_GEOMETRY_UBEREVAL); + add_relation(geom_init_key, + obdata_ubereval_key, + "Object Geometry UberEval"); + } + if (object->type == OB_MBALL) { + Object *mom = BKE_mball_basis_find(scene_, object); + ComponentKey mom_geom_key(&mom->id, DEG_NODE_TYPE_GEOMETRY); + /* motherball - mom depends on children! */ + if (mom == object) { + ComponentKey mom_transform_key(&mom->id, + DEG_NODE_TYPE_TRANSFORM); + add_relation(mom_transform_key, + mom_geom_key, + "Metaball Motherball Transform -> Geometry"); + } + else { + ComponentKey transform_key(&object->id, DEG_NODE_TYPE_TRANSFORM); + add_relation(geom_key, mom_geom_key, "Metaball Motherball"); + add_relation(transform_key, mom_geom_key, "Metaball Motherball"); + } + } + /* NOTE: This is compatibility code to support particle systems + * + * for viewport being properly rendered in final render mode. + * This relation is similar to what dag_object_time_update_flags() + * was doing for mesh objects with particle system. + * + * Ideally we need to get rid of this relation. + */ + if (object_particles_depends_on_time(object)) { + TimeSourceKey time_key; + OperationKey obdata_ubereval_key(&object->id, + DEG_NODE_TYPE_GEOMETRY, + DEG_OPCODE_GEOMETRY_UBEREVAL); + add_relation(time_key, obdata_ubereval_key, "Legacy particle time"); + } + /* Object data datablock. */ + build_object_data_geometry_datablock((ID *)object->data); + Key *key = BKE_key_from_object(object); + if (key != NULL) { + if (key->adt != NULL) { + if (key->adt->action || key->adt->nla_tracks.first) { + ComponentKey obdata_key((ID *)object->data, + DEG_NODE_TYPE_GEOMETRY); + ComponentKey adt_key(&key->id, DEG_NODE_TYPE_ANIMATION); + add_relation(adt_key, obdata_key, "Animation"); + } + } } +} +void DepsgraphRelationBuilder::build_object_data_geometry_datablock(ID *obdata) +{ if (built_map_.checkIsBuiltAndTag(obdata)) { return; } - + /* Animation. */ + build_animdata(obdata); + /* ShapeKeys. */ + Key *key = BKE_key_from_id(obdata); + if (key != NULL) { + build_shapekeys(key); + } /* Link object data evaluation node to exit operation. */ - OperationKey obdata_geom_eval_key(obdata, DEG_NODE_TYPE_GEOMETRY, DEG_OPCODE_PLACEHOLDER, "Geometry Eval"); - OperationKey obdata_geom_done_key(obdata, DEG_NODE_TYPE_GEOMETRY, DEG_OPCODE_PLACEHOLDER, "Eval Done"); - add_relation(obdata_geom_eval_key, obdata_geom_done_key, "ObData Geom Eval Done"); - - /* type-specific node/links */ - switch (object->type) { - case OB_MESH: - /* NOTE: This is compatibility code to support particle systems - * - * for viewport being properly rendered in final render mode. - * This relation is similar to what dag_object_time_update_flags() - * was doing for mesh objects with particle system. - * - * Ideally we need to get rid of this relation. - */ - if (object_particles_depends_on_time(object)) { - TimeSourceKey time_key; - OperationKey obdata_ubereval_key(&object->id, - DEG_NODE_TYPE_GEOMETRY, - DEG_OPCODE_GEOMETRY_UBEREVAL); - add_relation(time_key, obdata_ubereval_key, "Legacy particle time"); - } + OperationKey obdata_geom_eval_key(obdata, + DEG_NODE_TYPE_GEOMETRY, + DEG_OPCODE_PLACEHOLDER, + "Geometry Eval"); + OperationKey obdata_geom_done_key(obdata, + DEG_NODE_TYPE_GEOMETRY, + DEG_OPCODE_PLACEHOLDER, + "Eval Done"); + add_relation(obdata_geom_eval_key, + obdata_geom_done_key, + "ObData Geom Eval Done"); + /* Type-specific links. */ + const ID_Type id_type = GS(obdata->name); + switch (id_type) { + case ID_ME: break; - - case OB_MBALL: - { - Object *mom = BKE_mball_basis_find(scene_, object); - ComponentKey mom_geom_key(&mom->id, DEG_NODE_TYPE_GEOMETRY); - /* motherball - mom depends on children! */ - if (mom == object) { - ComponentKey mom_transform_key(&mom->id, - DEG_NODE_TYPE_TRANSFORM); - add_relation(mom_transform_key, - mom_geom_key, - "Metaball Motherball Transform -> Geometry"); - } - else { - ComponentKey transform_key(&object->id, DEG_NODE_TYPE_TRANSFORM); - add_relation(geom_key, mom_geom_key, "Metaball Motherball"); - add_relation(transform_key, mom_geom_key, "Metaball Motherball"); - } + case ID_MB: break; - } - - case OB_CURVE: - case OB_FONT: + case ID_CU: { Curve *cu = (Curve *)obdata; - - /* curve's dependencies */ - // XXX: these needs geom data, but where is geom stored? - if (cu->bevobj) { - ComponentKey bevob_geom_key(&cu->bevobj->id, DEG_NODE_TYPE_GEOMETRY); - add_relation(bevob_geom_key, obdata_geom_key, "Curve Bevel Geometry"); - /* We only need scale, but we can't tag individual TRANSFORM components. */ - ComponentKey bevob_key(&cu->bevobj->id, DEG_NODE_TYPE_TRANSFORM); - add_relation(bevob_key, obdata_geom_key, "Curve Bevel Scale"); + if (cu->bevobj != NULL) { + ComponentKey bevob_geom_key(&cu->bevobj->id, + DEG_NODE_TYPE_GEOMETRY); + add_relation(bevob_geom_key, + obdata_geom_eval_key, + "Curve Bevel Geometry"); + ComponentKey bevob_key(&cu->bevobj->id, + DEG_NODE_TYPE_TRANSFORM); + add_relation(bevob_key, + obdata_geom_eval_key, + "Curve Bevel Transform"); build_object(NULL, cu->bevobj); } - if (cu->taperobj) { - ComponentKey taperob_key(&cu->taperobj->id, DEG_NODE_TYPE_GEOMETRY); + if (cu->taperobj != NULL) { + ComponentKey taperob_key(&cu->taperobj->id, + DEG_NODE_TYPE_GEOMETRY); + add_relation(taperob_key, obdata_geom_eval_key, "Curve Taper"); build_object(NULL, cu->taperobj); - add_relation(taperob_key, geom_key, "Curve Taper"); } - if (object->type == OB_FONT) { - if (cu->textoncurve) { - ComponentKey textoncurve_key(&cu->textoncurve->id, DEG_NODE_TYPE_GEOMETRY); - build_object(NULL, cu->textoncurve); - add_relation(textoncurve_key, geom_key, "Text on Curve"); - } + if (cu->textoncurve != NULL) { + ComponentKey textoncurve_key(&cu->textoncurve->id, + DEG_NODE_TYPE_GEOMETRY); + add_relation(textoncurve_key, + obdata_geom_eval_key, + "Text on Curve"); + build_object(NULL, cu->textoncurve); } break; } - - case OB_SURF: /* Nurbs Surface */ - { + case ID_LT: break; - } - - case OB_LATTICE: /* Lattice */ - { + default: + BLI_assert(!"Should not happen"); break; - } } +} - /* ShapeKeys */ - Key *key = BKE_key_from_object(object); - if (key) { - build_shapekeys(obdata, key); +void DepsgraphRelationBuilder::build_armature(bArmature *armature) +{ + if (built_map_.checkIsBuiltAndTag(armature)) { + return; } + build_animdata(&armature->id); } -/* Cameras */ -// TODO: Link scene-camera links in somehow... -void DepsgraphRelationBuilder::build_camera(Object *object) +void DepsgraphRelationBuilder::build_camera(Camera *camera) { - Camera *camera = (Camera *)object->data; if (built_map_.checkIsBuiltAndTag(camera)) { return; } - - ComponentKey object_parameters_key(&object->id, DEG_NODE_TYPE_PARAMETERS); - ComponentKey camera_parameters_key(&camera->id, DEG_NODE_TYPE_PARAMETERS); - - add_relation(camera_parameters_key, object_parameters_key, - "Camera -> Object"); - - /* DOF */ if (camera->dof_ob != NULL) { + ComponentKey camera_parameters_key(&camera->id, DEG_NODE_TYPE_PARAMETERS); ComponentKey dof_ob_key(&camera->dof_ob->id, DEG_NODE_TYPE_TRANSFORM); - add_relation(dof_ob_key, object_parameters_key, "Camera DOF"); + add_relation(dof_ob_key, camera_parameters_key, "Camera DOF"); } } /* Lamps */ -void DepsgraphRelationBuilder::build_lamp(Object *object) +void DepsgraphRelationBuilder::build_lamp(Lamp *lamp) { - Lamp *lamp = (Lamp *)object->data; if (built_map_.checkIsBuiltAndTag(lamp)) { return; } - - ComponentKey object_parameters_key(&object->id, DEG_NODE_TYPE_PARAMETERS); - ComponentKey lamp_parameters_key(&lamp->id, DEG_NODE_TYPE_PARAMETERS); - - add_relation(lamp_parameters_key, object_parameters_key, - "Lamp -> Object"); - /* lamp's nodetree */ if (lamp->nodetree != NULL) { build_nodetree(lamp->nodetree); + ComponentKey lamp_parameters_key(&lamp->id, DEG_NODE_TYPE_PARAMETERS); ComponentKey nodetree_key(&lamp->nodetree->id, DEG_NODE_TYPE_SHADING); add_relation(nodetree_key, lamp_parameters_key, "NTree->Lamp Parameters"); build_nested_nodetree(&lamp->id, lamp->nodetree); } - - /* Make sure copy on write of lamp data is always properly updated for - * visible lamps. - */ - OperationKey ob_copy_on_write_key(&object->id, - DEG_NODE_TYPE_COPY_ON_WRITE, - DEG_OPCODE_COPY_ON_WRITE); - OperationKey lamp_copy_on_write_key(&lamp->id, - DEG_NODE_TYPE_COPY_ON_WRITE, - DEG_OPCODE_COPY_ON_WRITE); - add_relation(lamp_copy_on_write_key, ob_copy_on_write_key, "Eval Order"); } void DepsgraphRelationBuilder::build_nodetree(bNodeTree *ntree) @@ -1952,7 +2006,7 @@ void DepsgraphRelationBuilder::build_nodetree(bNodeTree *ntree) if (check_id_has_anim_component(&ntree->id)) { ComponentKey animation_key(&ntree->id, DEG_NODE_TYPE_ANIMATION); - add_relation(shading_parameters_key, animation_key, "NTree Shading Parameters"); + add_relation(animation_key, shading_parameters_key, "NTree Shading Parameters"); } } @@ -2045,23 +2099,12 @@ void DepsgraphRelationBuilder::build_movieclip(MovieClip *clip) build_animdata(&clip->id); } -void DepsgraphRelationBuilder::build_lightprobe(Object *object) +void DepsgraphRelationBuilder::build_lightprobe(LightProbe *probe) { - LightProbe *probe = (LightProbe *)object->data; if (built_map_.checkIsBuiltAndTag(probe)) { return; } build_animdata(&probe->id); - - OperationKey probe_key(&probe->id, - DEG_NODE_TYPE_PARAMETERS, - DEG_OPCODE_PLACEHOLDER, - "LightProbe Eval"); - OperationKey object_key(&object->id, - DEG_NODE_TYPE_PARAMETERS, - DEG_OPCODE_PLACEHOLDER, - "LightProbe Eval"); - add_relation(probe_key, object_key, "LightProbe Update"); } void DepsgraphRelationBuilder::build_copy_on_write_relations() diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.h b/source/blender/depsgraph/intern/builder/deg_builder_relations.h index dbfaff4dc18..3d3a73b6551 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.h +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.h @@ -49,15 +49,19 @@ #include "intern/nodes/deg_node_operation.h" struct Base; +struct bArmature; struct bGPdata; struct CacheFile; +struct Camera; struct ListBase; struct GHash; struct ID; struct FCurve; struct Collection; struct Key; +struct Lamp; struct LayerCollection; +struct LightProbe; struct Main; struct Mask; struct Material; @@ -197,10 +201,17 @@ struct DepsgraphRelationBuilder void build_id(ID *id); void build_layer_collections(ListBase *lb); void build_view_layer(Scene *scene, ViewLayer *view_layer); - void build_collection(Object *object, Collection *collection); + void build_collection(eDepsNode_CollectionOwner owner_type, + Object *object, + Collection *collection); void build_object(Base *base, Object *object); void build_object_flags(Base *base, Object *object); void build_object_data(Object *object); + void build_object_data_camera(Object *object); + void build_object_data_geometry(Object *object); + void build_object_data_geometry_datablock(ID *obdata); + void build_object_data_lamp(Object *object); + void build_object_data_lightprobe(Object *object); void build_object_parent(Object *object); void build_constraints(ID *id, eDepsNode_Type component_type, @@ -239,10 +250,10 @@ struct DepsgraphRelationBuilder RootPChanMap *root_map); void build_rig(Object *object); void build_proxy_rig(Object *object); - void build_shapekeys(ID *obdata, Key *key); - void build_obdata_geom(Object *object); - void build_camera(Object *object); - void build_lamp(Object *object); + void build_shapekeys(Key *key); + void build_armature(bArmature *armature); + void build_camera(Camera *camera); + void build_lamp(Lamp *lamp); void build_nodetree(bNodeTree *ntree); void build_material(Material *ma); void build_texture(Tex *tex); @@ -251,7 +262,7 @@ struct DepsgraphRelationBuilder void build_cachefile(CacheFile *cache_file); void build_mask(Mask *mask); void build_movieclip(MovieClip *clip); - void build_lightprobe(Object *object); + void build_lightprobe(LightProbe *probe); void build_nested_datablock(ID *owner, ID *id); void build_nested_nodetree(ID *owner, bNodeTree *ntree); diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc index a9895eb3af1..49c107c988f 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc @@ -304,27 +304,21 @@ void DepsgraphRelationBuilder::build_splineik_pose(Object *object, void DepsgraphRelationBuilder::build_rig(Object *object) { /* Armature-Data */ - bArmature *arm = (bArmature *)object->data; - + bArmature *armature = (bArmature *)object->data; // TODO: selection status? - - /* attach links between pose operations */ + /* Attach links between pose operations. */ OperationKey init_key(&object->id, DEG_NODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_INIT); OperationKey init_ik_key(&object->id, DEG_NODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_INIT_IK); OperationKey flush_key(&object->id, DEG_NODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_DONE); - add_relation(init_key, init_ik_key, "Pose Init -> Pose Init IK"); add_relation(init_ik_key, flush_key, "Pose Init IK -> Pose Cleanup"); - /* Make sure pose is up-to-date with armature updates. */ - if (!built_map_.checkIsBuiltAndTag(arm)) { - OperationKey armature_key(&arm->id, - DEG_NODE_TYPE_PARAMETERS, - DEG_OPCODE_PLACEHOLDER, - "Armature Eval"); - add_relation(armature_key, init_key, "Data dependency"); - } - + build_armature(armature); + OperationKey armature_key(&armature->id, + DEG_NODE_TYPE_PARAMETERS, + DEG_OPCODE_PLACEHOLDER, + "Armature Eval"); + add_relation(armature_key, init_key, "Data dependency"); /* IK Solvers... * - These require separate processing steps are pose-level * to be executed between chains of bones (i.e. once the @@ -337,7 +331,8 @@ void DepsgraphRelationBuilder::build_rig(Object *object) * references, or with bones being parented to IK'd bones) * * Unsolved Issues: - * - Care is needed to ensure that multi-headed trees work out the same as in ik-tree building + * - Care is needed to ensure that multi-headed trees work out the same as + * in ik-tree building * - Animated chain-lengths are a problem... */ RootPChanMap root_map; @@ -372,7 +367,6 @@ void DepsgraphRelationBuilder::build_rig(Object *object) } } //root_map.print_debug(); - if (pose_depends_on_local_transform) { /* TODO(sergey): Once partial updates are possible use relation between * object transform and solver itself in it's build function. @@ -381,8 +375,7 @@ void DepsgraphRelationBuilder::build_rig(Object *object) ComponentKey local_transform_key(&object->id, DEG_NODE_TYPE_TRANSFORM); add_relation(local_transform_key, pose_key, "Local Transforms"); } - - /* links between operations for each bone */ + /* Links between operations for each bone. */ LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) { OperationKey bone_local_key(&object->id, DEG_NODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_LOCAL); OperationKey bone_pose_key(&object->id, DEG_NODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_POSE_PARENT); @@ -397,7 +390,9 @@ void DepsgraphRelationBuilder::build_rig(Object *object) if (pchan->parent != NULL) { eDepsOperation_Code parent_key_opcode; - /* NOTE: this difference in handling allows us to prevent lockups while ensuring correct poses for separate chains */ + /* NOTE: this difference in handling allows us to prevent lockups + * while ensuring correct poses for separate chains. + */ if (root_map.has_common_root(pchan->name, pchan->parent->name)) { parent_key_opcode = DEG_OPCODE_BONE_READY; } @@ -433,14 +428,15 @@ void DepsgraphRelationBuilder::build_rig(Object *object) /* bone ready -> done * NOTE: For bones without IK, this is all that's needed. - * For IK chains however, an additional rel is created from IK to done, - * with transitive reduction removing this one... + * For IK chains however, an additional rel is created from IK + * to done, with transitive reduction removing this one.. */ add_relation(bone_ready_key, bone_done_key, "Ready -> Done"); - /* assume that all bones must be done for the pose to be ready (for deformers) */ + /* assume that all bones must be done for the pose to be ready + * (for deformers) + */ add_relation(bone_done_key, flush_key, "PoseEval Result-Bone Link"); - /* Custom shape. */ if (pchan->custom != NULL) { build_object(NULL, pchan->custom); @@ -450,7 +446,9 @@ void DepsgraphRelationBuilder::build_rig(Object *object) void DepsgraphRelationBuilder::build_proxy_rig(Object *object) { + bArmature *armature = (bArmature *)object->data; Object *proxy_from = object->proxy_from; + build_armature(armature); OperationKey pose_init_key(&object->id, DEG_NODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_INIT); diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_view_layer.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations_view_layer.cc index 0f159248ff4..b940fc3035e 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations_view_layer.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_view_layer.cc @@ -75,13 +75,13 @@ void DepsgraphRelationBuilder::build_layer_collections(ListBase *lb) COLLECTION_RESTRICT_VIEW : COLLECTION_RESTRICT_RENDER; for (LayerCollection *lc = (LayerCollection *)lb->first; lc; lc = lc->next) { - if (!(lc->collection->flag & restrict_flag)) { - if (!(lc->flag & LAYER_COLLECTION_EXCLUDE)) { - build_collection(NULL, lc->collection); - } - - build_layer_collections(&lc->layer_collections); + if ((lc->collection->flag & restrict_flag)) { + continue; + } + if ((lc->flag & LAYER_COLLECTION_EXCLUDE) == 0) { + build_collection(DEG_COLLECTION_OWNER_SCENE, NULL, lc->collection); } + build_layer_collections(&lc->layer_collections); } } diff --git a/source/blender/depsgraph/intern/depsgraph_query_iter.cc b/source/blender/depsgraph/intern/depsgraph_query_iter.cc index 4f3769b6768..97a28038b7b 100644 --- a/source/blender/depsgraph/intern/depsgraph_query_iter.cc +++ b/source/blender/depsgraph/intern/depsgraph_query_iter.cc @@ -120,7 +120,7 @@ static bool deg_objects_dupli_iterator_next(BLI_Iterator *iter) /* Duplicated elements shouldn't care whether their original collection is visible or not. */ temp_dupli_object->base_flag |= BASE_VISIBLED; - if (BKE_object_is_visible(temp_dupli_object, (eObjectVisibilityCheck)data->visibility_check) == false) { + if (BKE_object_is_visible(temp_dupli_object, OB_VISIBILITY_CHECK_UNKNOWN_RENDER_MODE) == false) { continue; } @@ -211,7 +211,9 @@ void DEG_iterator_objects_begin(BLI_Iterator *iter, DEGObjectIterData *data) data->scene = DEG_get_evaluated_scene(depsgraph); data->id_node_index = 0; data->num_id_nodes = num_id_nodes; - data->visibility_check = (data->mode == DEG_ITER_OBJECT_MODE_RENDER) + eEvaluationMode eval_mode = DEG_get_mode(depsgraph); + /* Viewport rendered mode is DAG_EVAL_PREVIEW but still treated as viewport. */ + data->visibility_check = (eval_mode == DAG_EVAL_RENDER) ? OB_VISIBILITY_CHECK_FOR_RENDER : OB_VISIBILITY_CHECK_FOR_VIEWPORT; diff --git a/source/blender/depsgraph/intern/depsgraph_tag.cc b/source/blender/depsgraph/intern/depsgraph_tag.cc index e772aefe8cb..437999a06a9 100644 --- a/source/blender/depsgraph/intern/depsgraph_tag.cc +++ b/source/blender/depsgraph/intern/depsgraph_tag.cc @@ -449,17 +449,7 @@ void deg_graph_node_tag_zero(Main *bmain, Depsgraph *graph, IDDepsNode *id_node) GHASH_FOREACH_BEGIN(ComponentDepsNode *, comp_node, id_node->components) { if (comp_node->type == DEG_NODE_TYPE_ANIMATION) { - AnimData *adt = BKE_animdata_from_id(id); - /* NOTE: Animation data might be null if relations are tagged - * for update. - */ - if (adt == NULL || (adt->recalc & ADT_RECALC_ANIM) == 0) { - /* If there is no animation, or animation is not tagged for - * update yet, we don't force animation channel to be evaluated. - */ - continue; - } - id->recalc |= ID_RECALC_ANIMATION; + continue; } comp_node->tag_update(graph); } @@ -520,7 +510,7 @@ void deg_graph_on_visible_update(Main *bmain, Depsgraph *graph) /* Make sure objects are up to date. */ foreach (DEG::IDDepsNode *id_node, graph->id_nodes) { const ID_Type id_type = GS(id_node->id_orig->name); - int flag = DEG_TAG_TIME | DEG_TAG_COPY_ON_WRITE; + int flag = DEG_TAG_COPY_ON_WRITE; /* We only tag components which needs an update. Tagging everything is * not a good idea because that might reset particles cache (or any * other type of cache). diff --git a/source/blender/depsgraph/intern/depsgraph_type_defines.cc b/source/blender/depsgraph/intern/depsgraph_type_defines.cc index 19cc82a6b10..79d29f72b8d 100644 --- a/source/blender/depsgraph/intern/depsgraph_type_defines.cc +++ b/source/blender/depsgraph/intern/depsgraph_type_defines.cc @@ -138,6 +138,8 @@ const char *operationCodeAsString(eDepsOperation_Code opcode) STRINGIFY_OPCODE(GEOMETRY_UBEREVAL); STRINGIFY_OPCODE(GEOMETRY_CLOTH_MODIFIER); STRINGIFY_OPCODE(GEOMETRY_SHAPEKEY); + /* Object data. */ + STRINGIFY_OPCODE(LIGHT_PROBE_EVAL); /* Pose. */ STRINGIFY_OPCODE(POSE_INIT); STRINGIFY_OPCODE(POSE_INIT_IK); diff --git a/source/blender/depsgraph/intern/depsgraph_types.h b/source/blender/depsgraph/intern/depsgraph_types.h index 14cd62e6cec..cec279a04bb 100644 --- a/source/blender/depsgraph/intern/depsgraph_types.h +++ b/source/blender/depsgraph/intern/depsgraph_types.h @@ -205,6 +205,9 @@ typedef enum eDepsOperation_Code { DEG_OPCODE_GEOMETRY_CLOTH_MODIFIER, DEG_OPCODE_GEOMETRY_SHAPEKEY, + /* Object data. ------------------------------------- */ + DEG_OPCODE_LIGHT_PROBE_EVAL, + /* Pose. -------------------------------------------- */ /* Init pose, clear flags, etc. */ DEG_OPCODE_POSE_INIT, @@ -269,7 +272,17 @@ typedef enum eDepsOperation_Code { DEG_NUM_OPCODES, } eDepsOperation_Code; - const char *operationCodeAsString(eDepsOperation_Code opcode); +typedef enum eDepsNode_CollectionOwner { + /* Unknown owner of collection, collection is pulled directly, maybe + * via driver. + */ + DEG_COLLECTION_OWNER_UNKNOWN, + /* Collection belongs to a scene. */ + DEG_COLLECTION_OWNER_SCENE, + /* Collection is used by object, as a dupli-system. */ + DEG_COLLECTION_OWNER_OBJECT, +} eDepsNode_CollectionOwner; + } // namespace DEG diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index c7d3d935b26..6743bea350b 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -222,6 +222,8 @@ data_to_c_simple(engines/eevee/shaders/volumetric_scatter_frag.glsl SRC) data_to_c_simple(engines/eevee/shaders/volumetric_integration_frag.glsl SRC) data_to_c_simple(engines/workbench/shaders/workbench_background_lib.glsl SRC) +data_to_c_simple(engines/workbench/shaders/workbench_cavity_lib.glsl SRC) +data_to_c_simple(engines/workbench/shaders/workbench_cavity_frag.glsl SRC) data_to_c_simple(engines/workbench/shaders/workbench_checkerboard_depth_frag.glsl SRC) data_to_c_simple(engines/workbench/shaders/workbench_common_lib.glsl SRC) data_to_c_simple(engines/workbench/shaders/workbench_data_lib.glsl SRC) diff --git a/source/blender/draw/engines/basic/basic_engine.c b/source/blender/draw/engines/basic/basic_engine.c index c86574f7557..2c771578514 100644 --- a/source/blender/draw/engines/basic/basic_engine.c +++ b/source/blender/draw/engines/basic/basic_engine.c @@ -155,7 +155,7 @@ static void basic_cache_populate(void *vedata, Object *ob) continue; } if (!DRW_check_psys_visible_within_active_context(ob, psys)) { - return; + continue; } ParticleSettings *part = psys->part; const int draw_as = (part->draw_as == PART_DRAW_REND) ? part->ren_as : part->draw_as; diff --git a/source/blender/draw/engines/clay/clay_engine.c b/source/blender/draw/engines/clay/clay_engine.c index d08fee6039f..5d3717097b1 100644 --- a/source/blender/draw/engines/clay/clay_engine.c +++ b/source/blender/draw/engines/clay/clay_engine.c @@ -838,7 +838,7 @@ static void clay_cache_populate_particles(void *vedata, Object *ob) continue; } if (!DRW_check_psys_visible_within_active_context(ob, psys)) { - return; + continue; } ParticleSettings *part = psys->part; const int draw_as = (part->draw_as == PART_DRAW_REND) ? part->ren_as : part->draw_as; diff --git a/source/blender/draw/engines/eevee/eevee_lights.c b/source/blender/draw/engines/eevee/eevee_lights.c index dd69e19e7c1..f5673d1a616 100644 --- a/source/blender/draw/engines/eevee/eevee_lights.c +++ b/source/blender/draw/engines/eevee/eevee_lights.c @@ -40,7 +40,9 @@ static struct { struct GPUShader *shadow_sh; struct GPUShader *shadow_store_cube_sh[SHADOW_METHOD_MAX]; + struct GPUShader *shadow_store_cube_high_sh[SHADOW_METHOD_MAX]; struct GPUShader *shadow_store_cascade_sh[SHADOW_METHOD_MAX]; + struct GPUShader *shadow_store_cascade_high_sh[SHADOW_METHOD_MAX]; struct GPUShader *shadow_copy_cube_sh[SHADOW_METHOD_MAX]; struct GPUShader *shadow_copy_cascade_sh[SHADOW_METHOD_MAX]; } e_data = {NULL}; /* Engine data */ @@ -172,22 +174,7 @@ void EEVEE_lights_init(EEVEE_ViewLayerData *sldata) linfo->shadow_cascade_size = sh_cascade_size; /* only compile the ones needed. reduce startup time. */ - if ((sh_method == SHADOW_ESM) && !e_data.shadow_store_cube_sh[SHADOW_ESM]) { - DynStr *ds_frag = BLI_dynstr_new(); - BLI_dynstr_append(ds_frag, datatoc_concentric_samples_lib_glsl); - BLI_dynstr_append(ds_frag, datatoc_shadow_store_frag_glsl); - char *store_shadow_shader_str = BLI_dynstr_get_cstring(ds_frag); - BLI_dynstr_free(ds_frag); - - e_data.shadow_store_cube_sh[SHADOW_ESM] = DRW_shader_create_fullscreen( - store_shadow_shader_str, - "#define ESM\n"); - e_data.shadow_store_cascade_sh[SHADOW_ESM] = DRW_shader_create_fullscreen( - store_shadow_shader_str, - "#define ESM\n" - "#define CSM\n"); - MEM_freeN(store_shadow_shader_str); - + if ((sh_method == SHADOW_ESM) && !e_data.shadow_copy_cube_sh[SHADOW_ESM]) { e_data.shadow_copy_cube_sh[SHADOW_ESM] = DRW_shader_create_fullscreen( datatoc_shadow_copy_frag_glsl, "#define ESM\n" @@ -198,22 +185,7 @@ void EEVEE_lights_init(EEVEE_ViewLayerData *sldata) "#define COPY\n" "#define CSM\n"); } - else if ((sh_method == SHADOW_VSM) && !e_data.shadow_store_cube_sh[SHADOW_VSM]) { - DynStr *ds_frag = BLI_dynstr_new(); - BLI_dynstr_append(ds_frag, datatoc_concentric_samples_lib_glsl); - BLI_dynstr_append(ds_frag, datatoc_shadow_store_frag_glsl); - char *store_shadow_shader_str = BLI_dynstr_get_cstring(ds_frag); - BLI_dynstr_free(ds_frag); - - e_data.shadow_store_cube_sh[SHADOW_VSM] = DRW_shader_create_fullscreen( - store_shadow_shader_str, - "#define VSM\n"); - e_data.shadow_store_cascade_sh[SHADOW_VSM] = DRW_shader_create_fullscreen( - store_shadow_shader_str, - "#define VSM\n" - "#define CSM\n"); - MEM_freeN(store_shadow_shader_str); - + else if ((sh_method == SHADOW_VSM) && !e_data.shadow_copy_cube_sh[SHADOW_VSM]) { e_data.shadow_copy_cube_sh[SHADOW_VSM] = DRW_shader_create_fullscreen( datatoc_shadow_copy_frag_glsl, "#define VSM\n" @@ -226,6 +198,78 @@ void EEVEE_lights_init(EEVEE_ViewLayerData *sldata) } } +static GPUShader *eevee_lights_get_store_sh(int shadow_method, bool high_blur, bool cascade) +{ + GPUShader **shader; + + if (cascade) { + shader = (high_blur) ? &e_data.shadow_store_cascade_high_sh[shadow_method] + : &e_data.shadow_store_cascade_sh[shadow_method]; + } + else { + shader = (high_blur) ? &e_data.shadow_store_cube_high_sh[shadow_method] + : &e_data.shadow_store_cube_sh[shadow_method]; + } + + if (*shader == NULL) { + DynStr *ds_frag = BLI_dynstr_new(); + BLI_dynstr_append(ds_frag, datatoc_concentric_samples_lib_glsl); + BLI_dynstr_append(ds_frag, datatoc_shadow_store_frag_glsl); + char *store_shadow_shader_str = BLI_dynstr_get_cstring(ds_frag); + BLI_dynstr_free(ds_frag); + + ds_frag = BLI_dynstr_new(); + BLI_dynstr_append(ds_frag, (shadow_method == SHADOW_VSM) ? "#define VSM\n" : "#define ESM\n"); + if (high_blur) BLI_dynstr_append(ds_frag, "#define HIGH_BLUR\n"); + if (cascade) BLI_dynstr_append(ds_frag, "#define CSM\n"); + char *define_str = BLI_dynstr_get_cstring(ds_frag); + BLI_dynstr_free(ds_frag); + + *shader = DRW_shader_create_fullscreen( + store_shadow_shader_str, define_str); + + MEM_freeN(store_shadow_shader_str); + MEM_freeN(define_str); + } + + return *shader; +} + +static DRWPass *eevee_lights_cube_store_pass_get(EEVEE_PassList *psl, EEVEE_ViewLayerData *sldata, int shadow_method, int shadow_samples_ct) +{ + bool high_blur = shadow_samples_ct > 16; + DRWPass **pass = (high_blur) ? &psl->shadow_cube_store_pass : &psl->shadow_cube_store_high_pass; + if (*pass == NULL) { + EEVEE_LampsInfo *linfo = sldata->lamps; + *pass = DRW_pass_create("Shadow Cube Storage Pass", DRW_STATE_WRITE_COLOR); + GPUShader *shader = eevee_lights_get_store_sh(shadow_method, high_blur, false); + DRWShadingGroup *grp = DRW_shgroup_create(shader, *pass); + DRW_shgroup_uniform_texture_ref(grp, "shadowTexture", &sldata->shadow_cube_blur); + DRW_shgroup_uniform_block(grp, "shadow_render_block", sldata->shadow_render_ubo); + DRW_shgroup_uniform_float(grp, "shadowFilterSize", &linfo->filter_size, 1); + DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL); + } + return *pass; +} + +static DRWPass *eevee_lights_cascade_store_pass_get(EEVEE_PassList *psl, EEVEE_ViewLayerData *sldata, int shadow_method, int shadow_samples_ct) +{ + bool high_blur = shadow_samples_ct > 16; + DRWPass **pass = (high_blur) ? &psl->shadow_cascade_store_pass : &psl->shadow_cascade_store_high_pass; + if (*pass == NULL) { + EEVEE_LampsInfo *linfo = sldata->lamps; + *pass = DRW_pass_create("Shadow Cascade Storage Pass", DRW_STATE_WRITE_COLOR); + GPUShader *shader = eevee_lights_get_store_sh(shadow_method, high_blur, true); + DRWShadingGroup *grp = DRW_shgroup_create(shader, *pass); + DRW_shgroup_uniform_texture_ref(grp, "shadowTexture", &sldata->shadow_cascade_blur); + DRW_shgroup_uniform_block(grp, "shadow_render_block", sldata->shadow_render_ubo); + DRW_shgroup_uniform_int(grp, "cascadeId", &linfo->current_shadow_cascade, 1); + DRW_shgroup_uniform_float(grp, "shadowFilterSize", &linfo->filter_size, 1); + DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL); + } + return *pass; +} + void EEVEE_lights_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) { EEVEE_LampsInfo *linfo = sldata->lamps; @@ -247,28 +291,10 @@ void EEVEE_lights_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) memset(linfo->shcaster_backbuffer->flags, (char)SHADOW_CASTER_PRUNED, linfo->shcaster_backbuffer->alloc_count); memset(linfo->shcaster_frontbuffer->flags, 0x00, linfo->shcaster_frontbuffer->alloc_count); - { - psl->shadow_cube_store_pass = DRW_pass_create("Shadow Storage Pass", DRW_STATE_WRITE_COLOR); - - DRWShadingGroup *grp = DRW_shgroup_create( - e_data.shadow_store_cube_sh[linfo->shadow_method], psl->shadow_cube_store_pass); - DRW_shgroup_uniform_texture_ref(grp, "shadowTexture", &sldata->shadow_cube_blur); - DRW_shgroup_uniform_block(grp, "shadow_render_block", sldata->shadow_render_ubo); - DRW_shgroup_uniform_float(grp, "shadowFilterSize", &linfo->filter_size, 1); - DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL); - } - - { - psl->shadow_cascade_store_pass = DRW_pass_create("Shadow Cascade Storage Pass", DRW_STATE_WRITE_COLOR); - - DRWShadingGroup *grp = DRW_shgroup_create( - e_data.shadow_store_cascade_sh[linfo->shadow_method], psl->shadow_cascade_store_pass); - DRW_shgroup_uniform_texture_ref(grp, "shadowTexture", &sldata->shadow_cascade_blur); - DRW_shgroup_uniform_block(grp, "shadow_render_block", sldata->shadow_render_ubo); - DRW_shgroup_uniform_int(grp, "cascadeId", &linfo->current_shadow_cascade, 1); - DRW_shgroup_uniform_float(grp, "shadowFilterSize", &linfo->filter_size, 1); - DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL); - } + psl->shadow_cube_store_pass = NULL; + psl->shadow_cube_store_high_pass = NULL; + psl->shadow_cascade_store_pass = NULL; + psl->shadow_cascade_store_high_pass = NULL; { psl->shadow_cube_copy_pass = DRW_pass_create("Shadow Copy Pass", DRW_STATE_WRITE_COLOR); @@ -1124,7 +1150,9 @@ void EEVEE_draw_shadows(EEVEE_ViewLayerData *sldata, EEVEE_PassList *psl) GPU_framebuffer_texture_layer_attach(sldata->shadow_cube_store_fb, sldata->shadow_cube_pool, 0, evscd->layer_id, 0); GPU_framebuffer_bind(sldata->shadow_cube_store_fb); - DRW_draw_pass(psl->shadow_cube_store_pass); + + DRWPass *store_pass = eevee_lights_cube_store_pass_get(psl, sldata, linfo->shadow_method, srd->shadow_samples_ct); + DRW_draw_pass(store_pass); led->need_update = false; } @@ -1224,7 +1252,9 @@ void EEVEE_draw_shadows(EEVEE_ViewLayerData *sldata, EEVEE_PassList *psl) int layer = evscd->layer_id + linfo->current_shadow_cascade; GPU_framebuffer_texture_layer_attach(sldata->shadow_cascade_store_fb, sldata->shadow_cascade_pool, 0, layer, 0); GPU_framebuffer_bind(sldata->shadow_cascade_store_fb); - DRW_draw_pass(psl->shadow_cascade_store_pass); + + DRWPass *store_pass = eevee_lights_cascade_store_pass_get(psl, sldata, linfo->shadow_method, srd->shadow_samples_ct); + DRW_draw_pass(store_pass); } } @@ -1241,7 +1271,9 @@ void EEVEE_lights_free(void) DRW_SHADER_FREE_SAFE(e_data.shadow_sh); for (int i = 0; i < SHADOW_METHOD_MAX; ++i) { DRW_SHADER_FREE_SAFE(e_data.shadow_store_cube_sh[i]); + DRW_SHADER_FREE_SAFE(e_data.shadow_store_cube_high_sh[i]); DRW_SHADER_FREE_SAFE(e_data.shadow_store_cascade_sh[i]); + DRW_SHADER_FREE_SAFE(e_data.shadow_store_cascade_high_sh[i]); DRW_SHADER_FREE_SAFE(e_data.shadow_copy_cube_sh[i]); DRW_SHADER_FREE_SAFE(e_data.shadow_copy_cascade_sh[i]); } diff --git a/source/blender/draw/engines/eevee/eevee_lookdev.c b/source/blender/draw/engines/eevee/eevee_lookdev.c index 8107aa33d2b..5c626b42ddd 100644 --- a/source/blender/draw/engines/eevee/eevee_lookdev.c +++ b/source/blender/draw/engines/eevee/eevee_lookdev.c @@ -42,7 +42,7 @@ void EEVEE_lookdev_cache_init( const DRWContextState *draw_ctx = DRW_context_state_get(); View3D *v3d = draw_ctx->v3d; if (LOOK_DEV_MODE_ENABLED(v3d)) { - StudioLight *sl = BKE_studiolight_find(v3d->shading.studio_light, STUDIOLIGHT_ORIENTATION_WORLD); + StudioLight *sl = BKE_studiolight_find(v3d->shading.studio_light, STUDIOLIGHT_INTERNAL | STUDIOLIGHT_ORIENTATION_WORLD); if ((sl->flag & STUDIOLIGHT_ORIENTATION_WORLD)) { struct Gwn_Batch *geom = DRW_cache_fullscreen_quad_get(); GPUTexture *tex; @@ -51,7 +51,9 @@ void EEVEE_lookdev_cache_init( axis_angle_to_mat3_single(stl->g_data->studiolight_matrix, 'Z', v3d->shading.studiolight_rot_z); DRW_shgroup_uniform_mat3(*grp, "StudioLightMatrix", stl->g_data->studiolight_matrix); - DRW_shgroup_uniform_vec3(*grp, "color", &world->horr, 1); + if (world) { + DRW_shgroup_uniform_vec3(*grp, "color", &world->horr, 1); + } DRW_shgroup_uniform_float(*grp, "backgroundAlpha", &stl->g_data->background_alpha, 1); DRW_shgroup_call_add(*grp, geom, NULL); if (!pinfo) { diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h index 3963459b1d6..d0b7044a018 100644 --- a/source/blender/draw/engines/eevee/eevee_private.h +++ b/source/blender/draw/engines/eevee/eevee_private.h @@ -145,8 +145,10 @@ typedef struct EEVEE_PassList { struct DRWPass *shadow_pass; struct DRWPass *shadow_cube_copy_pass; struct DRWPass *shadow_cube_store_pass; + struct DRWPass *shadow_cube_store_high_pass; struct DRWPass *shadow_cascade_copy_pass; struct DRWPass *shadow_cascade_store_pass; + struct DRWPass *shadow_cascade_store_high_pass; /* Probes */ struct DRWPass *probe_background; diff --git a/source/blender/draw/engines/eevee/eevee_render.c b/source/blender/draw/engines/eevee/eevee_render.c index 6cb3fa259eb..76887145ad2 100644 --- a/source/blender/draw/engines/eevee/eevee_render.c +++ b/source/blender/draw/engines/eevee/eevee_render.c @@ -143,25 +143,26 @@ void EEVEE_render_cache( char info[42]; BLI_snprintf(info, sizeof(info), "Syncing %s", ob->id.name + 2); RE_engine_update_stats(engine, NULL, info); + bool cast_shadow = false; - if (DRW_check_object_visible_within_active_context(ob) == false) { - return; + if (ob->base_flag & BASE_VISIBLED) { + EEVEE_hair_cache_populate(vedata, sldata, ob, &cast_shadow); } - if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT)) { - bool cast_shadow; - - EEVEE_materials_cache_populate(vedata, sldata, ob, &cast_shadow); - - if (cast_shadow) { - EEVEE_lights_cache_shcaster_object_add(sldata, ob); + if (DRW_check_object_visible_within_active_context(ob)) { + if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT)) { + EEVEE_materials_cache_populate(vedata, sldata, ob, &cast_shadow); + } + else if (ob->type == OB_LIGHTPROBE) { + EEVEE_lightprobes_cache_add(sldata, ob); + } + else if (ob->type == OB_LAMP) { + EEVEE_lights_cache_add(sldata, ob); } } - else if (ob->type == OB_LIGHTPROBE) { - EEVEE_lightprobes_cache_add(sldata, ob); - } - else if (ob->type == OB_LAMP) { - EEVEE_lights_cache_add(sldata, ob); + + if (cast_shadow) { + EEVEE_lights_cache_shcaster_object_add(sldata, ob); } } @@ -421,6 +422,9 @@ void EEVEE_render_draw(EEVEE_Data *vedata, RenderEngine *engine, RenderLayer *rl /* Push instances attribs to the GPU. */ DRW_render_instance_buffer_finish(); + /* Need to be called after DRW_render_instance_buffer_finish() */ + DRW_hair_update(); + if ((view_layer->passflag & (SCE_PASS_SUBSURFACE_COLOR | SCE_PASS_SUBSURFACE_DIRECT | SCE_PASS_SUBSURFACE_INDIRECT)) != 0) diff --git a/source/blender/draw/engines/eevee/shaders/shadow_store_frag.glsl b/source/blender/draw/engines/eevee/shaders/shadow_store_frag.glsl index b40155be454..d5ac821c3fa 100644 --- a/source/blender/draw/engines/eevee/shaders/shadow_store_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/shadow_store_frag.glsl @@ -165,6 +165,7 @@ void main() { grouped_samples_accum(cos, concentric[28], concentric[29], concentric[30], concentric[31], accum); grouped_samples_accum(cos, concentric[32], concentric[33], concentric[34], concentric[35], accum); } +#ifdef HIGH_BLUR if (shadowSampleCount > 36) { grouped_samples_accum(cos, concentric[36], concentric[37], concentric[38], concentric[39], accum); grouped_samples_accum(cos, concentric[40], concentric[41], concentric[42], concentric[43], accum); @@ -230,6 +231,7 @@ void main() { grouped_samples_accum(cos, concentric[248], concentric[249], concentric[250], concentric[251], accum); grouped_samples_accum(cos, concentric[252], concentric[253], concentric[254], concentric[255], accum); } +#endif #ifdef ESM accum.x = ln_space_prefilter(1.0, accum.x, 1.0, accum.y); diff --git a/source/blender/draw/engines/workbench/shaders/workbench_cavity_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_cavity_frag.glsl new file mode 100644 index 00000000000..38f55015877 --- /dev/null +++ b/source/blender/draw/engines/workbench/shaders/workbench_cavity_frag.glsl @@ -0,0 +1,71 @@ +out vec4 fragColor; + +uniform sampler2D depthBuffer; +uniform sampler2D colorBuffer; +uniform sampler2D normalBuffer; +uniform sampler2D positionBuffer; + +uniform vec2 invertedViewportSize; +uniform mat4 WinMatrix; /* inverse WinMatrix */ + +uniform vec4 viewvecs[3]; +uniform vec4 ssao_params; +uniform vec4 ssao_settings; +uniform sampler2D ssao_jitter; + +layout(std140) uniform samples_block { + vec4 ssao_samples[500]; +}; + +#define ssao_samples_num ssao_params.x +#define jitter_tilling ssao_params.yz +#define dfdy_sign ssao_params.w + +#define ssao_distance ssao_settings.x +#define ssao_factor_cavity ssao_settings.y +#define ssao_factor_edge ssao_settings.z +#define ssao_attenuation ssao_settings.a + +vec3 get_view_space_from_depth(in vec2 uvcoords, in float depth) +{ + if (WinMatrix[3][3] == 0.0) { + /* Perspective */ + float d = 2.0 * depth - 1.0; + + float zview = -WinMatrix[3][2] / (d + WinMatrix[2][2]); + + return zview * (viewvecs[0].xyz + vec3(uvcoords, 0.0) * viewvecs[1].xyz); + } + else { + /* Orthographic */ + vec3 offset = vec3(uvcoords, depth); + + return viewvecs[0].xyz + offset * viewvecs[1].xyz; + } +} + +/* forward declartion */ +void ssao_factors( + in float depth, in vec3 normal, in vec3 position, in vec2 screenco, + out float cavities, out float edges); + + +void main() +{ + vec2 screenco = vec2(gl_FragCoord.xy) * invertedViewportSize; + ivec2 texel = ivec2(gl_FragCoord.xy); + + float depth = texelFetch(depthBuffer, texel, 0).x; + vec3 position = get_view_space_from_depth(screenco, depth); + + vec4 diffuse_color = texelFetch(colorBuffer, texel, 0); + vec3 normal_viewport = normal_decode(texelFetch(normalBuffer, texel, 0).rg); + if (diffuse_color.a == 0.0) { + normal_viewport = -normal_viewport; + } + + float cavity = 0.0, edges = 0.0; + ssao_factors(depth, normal_viewport, position, screenco, cavity, edges); + + fragColor = vec4(cavity, edges, 0.0, 1.0); +} diff --git a/source/blender/draw/engines/workbench/shaders/workbench_cavity_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_cavity_lib.glsl new file mode 100644 index 00000000000..da0198ab2e7 --- /dev/null +++ b/source/blender/draw/engines/workbench/shaders/workbench_cavity_lib.glsl @@ -0,0 +1,79 @@ + + +/* from The Alchemy screen-space ambient obscurance algorithm + * http://graphics.cs.williams.edu/papers/AlchemyHPG11/VV11AlchemyAO.pdf */ + +void ssao_factors( + in float depth, in vec3 normal, in vec3 position, in vec2 screenco, + out float cavities, out float edges) +{ + cavities = edges = 0.0; + /* early out if there is no need for SSAO */ + if (ssao_factor_cavity == 0.0 && ssao_factor_edge == 0.0) + return; + + /* take the normalized ray direction here */ + vec3 noise = texture(ssao_jitter, screenco.xy * jitter_tilling).rgb; + + /* find the offset in screen space by multiplying a point + * in camera space at the depth of the point by the projection matrix. */ + vec2 offset; + float homcoord = WinMatrix[2][3] * position.z + WinMatrix[3][3]; + offset.x = WinMatrix[0][0] * ssao_distance / homcoord; + offset.y = WinMatrix[1][1] * ssao_distance / homcoord; + /* convert from -1.0...1.0 range to 0.0..1.0 for easy use with texture coordinates */ + offset *= 0.5; + + int num_samples = int(ssao_samples_num); + + /* Note. Putting noise usage here to put some ALU after texture fetch. */ + vec2 rotX = noise.rg; + vec2 rotY = vec2(-rotX.y, rotX.x); + + for (int x = 0; x < num_samples && x < 500; x++) { + /* ssao_samples[x].xy is sample direction (normalized). + * ssao_samples[x].z is sample distance from disk center. */ + + /* Rotate with random direction to get jittered result. */ + vec2 dir_jittered = vec2(dot(ssao_samples[x].xy, rotX), dot(ssao_samples[x].xy, rotY)); + dir_jittered.xy *= ssao_samples[x].z + noise.b; + + vec2 uvcoords = screenco.xy + dir_jittered * offset; + + if (uvcoords.x > 1.0 || uvcoords.x < 0.0 || uvcoords.y > 1.0 || uvcoords.y < 0.0) + continue; + + float depth_new = texture(depthBuffer, uvcoords).r; + + /* Handle Background case */ + bool is_background = (depth_new == 1.0); + + /* This trick provide good edge effect even if no neighboor is found. */ + vec3 pos_new = get_view_space_from_depth(uvcoords, (is_background) ? depth : depth_new); + + if (is_background) + pos_new.z -= ssao_distance; + + vec3 dir = pos_new - position; + float len = length(dir); + float f_cavities = dot(dir, normal); + float f_edge = -f_cavities; + float f_bias = 0.05 * len + 0.0001; + + float attenuation = 1.0 / (len * (1.0 + len * len * ssao_attenuation)); + + /* use minor bias here to avoid self shadowing */ + if (f_cavities > -f_bias) + cavities += f_cavities * attenuation; + + if (f_edge > f_bias) + edges += f_edge * attenuation; + } + + cavities /= ssao_samples_num; + edges /= ssao_samples_num; + + /* don't let cavity wash out the surface appearance */ + cavities = clamp(cavities * ssao_factor_cavity, 0.0, 1.0); + edges = edges * ssao_factor_edge; +} diff --git a/source/blender/draw/engines/workbench/shaders/workbench_data_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_data_lib.glsl index fc076ee8117..f67d2ff6745 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_data_lib.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_data_lib.glsl @@ -16,7 +16,8 @@ struct WorldData { vec4 light_direction_vs; LightData lights[3]; int num_lights; - int pad[3]; + int matcap_orientation; + int pad[2]; }; struct MaterialData { diff --git a/source/blender/draw/engines/workbench/shaders/workbench_deferred_composite_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_deferred_composite_frag.glsl index 5f37490603d..e5ee272e7fd 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_deferred_composite_frag.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_deferred_composite_frag.glsl @@ -5,12 +5,17 @@ uniform sampler2D colorBuffer; uniform sampler2D specularBuffer; uniform sampler2D normalBuffer; /* normalBuffer contains viewport normals */ +uniform sampler2D cavityBuffer; + uniform vec2 invertedViewportSize; uniform float shadowMultiplier; uniform float lightMultiplier; uniform float shadowShift = 0.1; uniform mat3 normalWorldMatrix; +#ifdef STUDIOLIGHT_ORIENTATION_VIEWNORMAL +uniform sampler2D matcapImage; +#endif layout(std140) uniform world_block { WorldData world_data; @@ -43,16 +48,25 @@ void main() #endif /* !V3D_SHADING_OBJECT_OUTLINE */ vec4 diffuse_color = texelFetch(colorBuffer, texel, 0); + /* Do we need normals */ #ifdef NORMAL_VIEWPORT_PASS_ENABLED -#ifdef WORKBENCH_ENCODE_NORMALS +# ifdef WORKBENCH_ENCODE_NORMALS vec3 normal_viewport = normal_decode(texelFetch(normalBuffer, texel, 0).rg); if (diffuse_color.a == 0.0) { normal_viewport = -normal_viewport; } -#else /* WORKBENCH_ENCODE_NORMALS */ +# else /* WORKBENCH_ENCODE_NORMALS */ vec3 normal_viewport = texelFetch(normalBuffer, texel, 0).rgb; -#endif /* WORKBENCH_ENCODE_NORMALS */ +# endif /* WORKBENCH_ENCODE_NORMALS */ +#endif + +#ifdef STUDIOLIGHT_ORIENTATION_VIEWNORMAL + vec2 matcap_uv = normal_viewport.xy / 2.0 + 0.5; + if (world_data.matcap_orientation != 0) { + matcap_uv.x = 1.0 - matcap_uv.x; + } + diffuse_color = texture(matcapImage, matcap_uv); #endif #ifdef V3D_SHADING_SPECULAR_HIGHLIGHT @@ -64,21 +78,31 @@ void main() vec3 specular_color = vec3(0.0); #endif +#ifdef V3D_LIGHTING_FLAT + vec3 diffuse_light = vec3(1.0); +#endif + +#ifdef V3D_LIGHTING_MATCAP + vec3 diffuse_light = texelFetch(specularBuffer, texel, 0).rgb; +#endif + #ifdef V3D_LIGHTING_STUDIO - #ifdef STUDIOLIGHT_ORIENTATION_CAMERA +# ifdef STUDIOLIGHT_ORIENTATION_CAMERA vec3 diffuse_light = get_camera_diffuse_light(world_data, normal_viewport); - #endif +# endif - #ifdef STUDIOLIGHT_ORIENTATION_WORLD +# ifdef STUDIOLIGHT_ORIENTATION_WORLD vec3 normal_world = normalWorldMatrix * normal_viewport; vec3 diffuse_light = get_world_diffuse_light(world_data, normal_world); - #endif +# endif +#endif vec3 shaded_color = diffuse_light * diffuse_color.rgb + specular_color; -#else /* V3D_LIGHTING_STUDIO */ - vec3 shaded_color = diffuse_color.rgb + specular_color; - -#endif /* V3D_LIGHTING_STUDIO */ +#ifdef V3D_SHADING_CAVITY + vec2 cavity = texelFetch(cavityBuffer, texel, 0).rg; + shaded_color *= 1.0 - cavity.x; + shaded_color *= 1.0 + cavity.y; +#endif #ifdef V3D_SHADING_SHADOW float light_factor = -dot(normal_viewport, world_data.light_direction_vs.xyz); diff --git a/source/blender/draw/engines/workbench/shaders/workbench_forward_transparent_accum_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_forward_transparent_accum_frag.glsl index a9c84e11aa6..e04bffdeea5 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_forward_transparent_accum_frag.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_forward_transparent_accum_frag.glsl @@ -10,6 +10,9 @@ in vec3 normal_viewport; #ifdef OB_TEXTURE in vec2 uv_interp; #endif +#ifdef STUDIOLIGHT_ORIENTATION_VIEWNORMAL +uniform sampler2D matcapImage; +#endif layout(std140) uniform world_block { WorldData world_data; @@ -25,6 +28,7 @@ layout(location=0) out vec4 transparentAccum; void main() { vec4 diffuse_color; + vec3 diffuse_light = vec3(1.0); #ifdef OB_SOLID diffuse_color = material_data.diffuse_color; #endif /* OB_SOLID */ @@ -32,6 +36,10 @@ void main() diffuse_color = texture(image, uv_interp); #endif /* OB_TEXTURE */ +#ifdef V3D_LIGHTING_MATCAP + diffuse_light = texture(matcapImage, normal_viewport.xy / 2.0 + 0.5).rgb; +#endif + #ifdef V3D_SHADING_SPECULAR_HIGHLIGHT vec3 specular_color = get_world_specular_lights(world_data, vec4(material_data.specular_color.rgb, material_data.roughness), normal_viewport, vec3(0.0, 0.0, 1.0)); #else @@ -40,17 +48,16 @@ void main() #ifdef V3D_LIGHTING_STUDIO # ifdef STUDIOLIGHT_ORIENTATION_CAMERA - vec3 diffuse_light = get_camera_diffuse_light(world_data, normal_viewport); + diffuse_light = get_camera_diffuse_light(world_data, normal_viewport); # endif # ifdef STUDIOLIGHT_ORIENTATION_WORLD vec3 normal_world = normalWorldMatrix * normal_viewport; - vec3 diffuse_light = get_world_diffuse_light(world_data, normal_world); + diffuse_light = get_world_diffuse_light(world_data, normal_world); # endif - vec3 shaded_color = diffuse_light * diffuse_color.rgb + specular_color; -#else - vec3 shaded_color = diffuse_color.rgb + specular_color; #endif + vec3 shaded_color = diffuse_light * diffuse_color.rgb + specular_color; + vec4 premultiplied = vec4(shaded_color.rgb * alpha, alpha); transparentAccum = calculate_transparent_accum(premultiplied); } diff --git a/source/blender/draw/engines/workbench/shaders/workbench_prepass_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_prepass_frag.glsl index bc7741f853c..200850e3036 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_prepass_frag.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_prepass_frag.glsl @@ -9,9 +9,9 @@ uniform sampler2D image; #endif #ifdef NORMAL_VIEWPORT_PASS_ENABLED -in vec3 position_viewport; in vec3 normal_viewport; #endif /* NORMAL_VIEWPORT_PASS_ENABLED */ + #ifdef OB_TEXTURE in vec2 uv_interp; #endif /* OB_TEXTURE */ @@ -24,19 +24,30 @@ layout(location=0) out uint objectId; layout(location=1) out vec4 diffuseColor; layout(location=2) out vec4 specularColor; #ifdef NORMAL_VIEWPORT_PASS_ENABLED - #ifdef WORKBENCH_ENCODE_NORMALS +# ifdef WORKBENCH_ENCODE_NORMALS layout(location=3) out vec2 normalViewport; - #else /* WORKBENCH_ENCODE_NORMALS */ +# else /* WORKBENCH_ENCODE_NORMALS */ layout(location=3) out vec3 normalViewport; - #endif /* WORKBENCH_ENCODE_NORMALS */ +# endif /* WORKBENCH_ENCODE_NORMALS */ #endif /* NORMAL_VIEWPORT_PASS_ENABLED */ void main() { objectId = uint(object_id); + +#ifdef NORMAL_VIEWPORT_PASS_ENABLED + vec3 n = (gl_FrontFacing) ? normal_viewport : -normal_viewport; + n = normalize(n); +#endif + #ifdef OB_SOLID diffuseColor = vec4(material_data.diffuse_color.rgb, 0.0); +# ifdef STUDIOLIGHT_ORIENTATION_VIEWNORMAL + + specularColor = vec4(material_data.diffuse_color.rgb, 0.0); +# endif #endif /* OB_SOLID */ + #ifdef OB_TEXTURE diffuseColor = texture(image, uv_interp); #endif /* OB_TEXTURE */ @@ -47,14 +58,12 @@ void main() #ifdef V3D_SHADING_SPECULAR_HIGHLIGHT specularColor = vec4(material_data.specular_color.rgb, material_data.roughness); -#ifdef HAIR_SHADER +# ifdef HAIR_SHADER specularColor.rgb = clamp(specularColor.rgb - hair_color_variation, 0.0, 1.0); -#endif +# endif #endif #ifdef NORMAL_VIEWPORT_PASS_ENABLED - vec3 n = (gl_FrontFacing) ? normal_viewport : -normal_viewport; - n = normalize(n); # ifdef WORKBENCH_ENCODE_NORMALS diffuseColor.a = float(gl_FrontFacing); normalViewport = normal_encode(n); diff --git a/source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl b/source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl index 7da9c2644fe..82443e7336b 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl @@ -18,6 +18,7 @@ flat out float hair_rand; #ifdef NORMAL_VIEWPORT_PASS_ENABLED out vec3 normal_viewport; #endif + #ifdef OB_TEXTURE out vec2 uv_interp; #endif @@ -57,6 +58,7 @@ void main() #ifdef OB_TEXTURE uv_interp = uv; #endif + #ifdef NORMAL_VIEWPORT_PASS_ENABLED normal_viewport = NormalMatrix * nor; # ifndef HAIR_SHADER diff --git a/source/blender/draw/engines/workbench/shaders/workbench_world_light_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_world_light_lib.glsl index be124257c33..6f4237ebd0a 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_world_light_lib.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_world_light_lib.glsl @@ -29,7 +29,7 @@ vec3 get_world_specular_light(vec4 specular_data, LightData light_data, vec3 N, float shininess = exp2(10*(1.0-specular_data.a) + 1); -#ifdef BLINN +# ifdef BLINN float normalization_factor = (shininess + 8) / (8 * M_PI); vec3 L = -light_data.light_direction_vs.xyz; vec3 halfDir = normalize(L + I); @@ -37,11 +37,11 @@ vec3 get_world_specular_light(vec4 specular_data, LightData light_data, vec3 N, float NL = max(dot(L, N), 0.0); float specular_influence = pow(specAngle, shininess) * NL * normalization_factor; -#else +# else vec3 reflection_vector = reflect(I, N); float specAngle = max(dot(light_data.light_direction_vs.xyz, reflection_vector), 0.0); float specular_influence = pow(specAngle, shininess); -#endif +# endif vec3 specular_color = specular_light * specular_influence; diff --git a/source/blender/draw/engines/workbench/workbench_data.c b/source/blender/draw/engines/workbench/workbench_data.c index 4ee12a692f5..df0a2bf4684 100644 --- a/source/blender/draw/engines/workbench/workbench_data.c +++ b/source/blender/draw/engines/workbench/workbench_data.c @@ -15,7 +15,14 @@ void workbench_private_data_init(WORKBENCH_PrivateData *wpd) if (v3d) { wpd->shading = v3d->shading; wpd->drawtype = v3d->drawtype; - wpd->studio_light = BKE_studiolight_find(wpd->shading.studio_light, 0); + if (wpd->shading.light == V3D_LIGHTING_MATCAP) { + wpd->studio_light = BKE_studiolight_find( + wpd->shading.matcap, STUDIOLIGHT_ORIENTATION_VIEWNORMAL); + } + else { + wpd->studio_light = BKE_studiolight_find( + wpd->shading.studio_light, STUDIOLIGHT_ORIENTATION_CAMERA | STUDIOLIGHT_ORIENTATION_WORLD); + } } else { memset(&wpd->shading, 0, sizeof(wpd->shading)); @@ -23,11 +30,12 @@ void workbench_private_data_init(WORKBENCH_PrivateData *wpd) wpd->shading.shadow_intensity = 0.5; copy_v3_fl(wpd->shading.single_color, 0.8f); wpd->drawtype = OB_SOLID; - wpd->studio_light = BKE_studiolight_findindex(0); + wpd->studio_light = BKE_studiolight_find_first(STUDIOLIGHT_INTERNAL); } wpd->shadow_multiplier = 1.0 - wpd->shading.shadow_intensity; WORKBENCH_UBO_World *wd = &wpd->world_data; + wd->matcap_orientation = (wpd->shading.flag & V3D_SHADING_MATCAP_FLIP_X) > 0; if ((v3d->flag3 & V3D_SHOW_WORLD) && (scene->world != NULL)) @@ -51,6 +59,64 @@ void workbench_private_data_init(WORKBENCH_PrivateData *wpd) wd->object_outline_color[3] = 1.0f; wpd->world_ubo = DRW_uniformbuffer_create(sizeof(WORKBENCH_UBO_World), &wpd->world_data); + + /* Cavity settings */ + { + const int ssao_samples = scene->display.matcap_ssao_samples; + + float invproj[4][4]; + float dfdyfacs[2]; + const bool is_persp = DRW_viewport_is_persp_get(); + /* view vectors for the corners of the view frustum. + * Can be used to recreate the world space position easily */ + float viewvecs[3][4] = { + {-1.0f, -1.0f, -1.0f, 1.0f}, + {1.0f, -1.0f, -1.0f, 1.0f}, + {-1.0f, 1.0f, -1.0f, 1.0f} + }; + int i; + const float *size = DRW_viewport_size_get(); + + DRW_state_dfdy_factors_get(dfdyfacs); + + wpd->ssao_params[0] = ssao_samples; + wpd->ssao_params[1] = size[0] / 64.0; + wpd->ssao_params[2] = size[1] / 64.0; + wpd->ssao_params[3] = dfdyfacs[1]; /* dfdy sign for offscreen */ + + /* distance, factor, factor, attenuation */ + copy_v4_fl4(wpd->ssao_settings, scene->display.matcap_ssao_distance, wpd->shading.cavity_valley_factor, wpd->shading.cavity_ridge_factor, scene->display.matcap_ssao_attenuation); + + /* invert the view matrix */ + DRW_viewport_matrix_get(wpd->winmat, DRW_MAT_WIN); + invert_m4_m4(invproj, wpd->winmat); + + /* convert the view vectors to view space */ + for (i = 0; i < 3; i++) { + mul_m4_v4(invproj, viewvecs[i]); + /* normalized trick see: + * http://www.derschmale.com/2014/01/26/reconstructing-positions-from-the-depth-buffer */ + mul_v3_fl(viewvecs[i], 1.0f / viewvecs[i][3]); + if (is_persp) + mul_v3_fl(viewvecs[i], 1.0f / viewvecs[i][2]); + viewvecs[i][3] = 1.0; + + copy_v4_v4(wpd->viewvecs[i], viewvecs[i]); + } + + /* we need to store the differences */ + wpd->viewvecs[1][0] -= wpd->viewvecs[0][0]; + wpd->viewvecs[1][1] = wpd->viewvecs[2][1] - wpd->viewvecs[0][1]; + + /* calculate a depth offset as well */ + if (!is_persp) { + float vec_far[] = {-1.0f, -1.0f, 1.0f, 1.0f}; + mul_m4_v4(invproj, vec_far); + mul_v3_fl(vec_far, 1.0f / vec_far[3]); + wpd->viewvecs[1][2] = vec_far[2] - wpd->viewvecs[0][2]; + } + } + } void workbench_private_data_get_light_direction(WORKBENCH_PrivateData *wpd, float light_direction[3]) @@ -71,7 +137,7 @@ void workbench_private_data_get_light_direction(WORKBENCH_PrivateData *wpd, floa wd->num_lights = 1; } - if (STUDIOLIGHT_ORIENTATION_CAMERA_ENABLED(wpd)) { + if (!STUDIOLIGHT_ORIENTATION_WORLD_ENABLED(wpd)) { int light_index = 0; for (int index = 0 ; index < 3; index++) { SolidLight *sl = &U.light[index]; diff --git a/source/blender/draw/engines/workbench/workbench_deferred.c b/source/blender/draw/engines/workbench/workbench_deferred.c index ba5ab7f1cc3..c4fa82d39b7 100644 --- a/source/blender/draw/engines/workbench/workbench_deferred.c +++ b/source/blender/draw/engines/workbench/workbench_deferred.c @@ -30,6 +30,7 @@ #include "BLI_alloca.h" #include "BLI_dynstr.h" #include "BLI_utildefines.h" +#include "BLI_rand.h" #include "BKE_node.h" #include "BKE_particle.h" @@ -44,6 +45,7 @@ #include "GPU_shader.h" #include "GPU_texture.h" +#include "../eevee/eevee_lut.h" /* TODO find somewhere to share blue noise Table */ /* *********** STATIC *********** */ @@ -56,6 +58,7 @@ static struct { struct GPUShader *prepass_sh_cache[MAX_SHADERS]; struct GPUShader *composite_sh_cache[MAX_SHADERS]; + struct GPUShader *cavity_sh; struct GPUShader *shadow_fail_sh; struct GPUShader *shadow_fail_manifold_sh; struct GPUShader *shadow_pass_sh; @@ -65,6 +68,7 @@ static struct { struct GPUTexture *object_id_tx; /* ref only, not alloced */ struct GPUTexture *color_buffer_tx; /* ref only, not alloced */ + struct GPUTexture *cavity_buffer_tx; /* ref only, not alloced */ struct GPUTexture *specular_buffer_tx; /* ref only, not alloced */ struct GPUTexture *normal_buffer_tx; /* ref only, not alloced */ struct GPUTexture *composite_buffer_tx; /* ref only, not alloced */ @@ -73,6 +77,10 @@ static struct { float light_direction_vs[3]; int next_object_id; float normal_world_matrix[3][3]; + + struct GPUUniformBuffer *sampling_ubo; + struct GPUTexture *jitter_tx; + int cached_sample_num; } e_data = {{NULL}}; /* Shaders */ @@ -80,6 +88,7 @@ extern char datatoc_common_hair_lib_glsl[]; extern char datatoc_workbench_prepass_vert_glsl[]; extern char datatoc_workbench_prepass_frag_glsl[]; +extern char datatoc_workbench_cavity_frag_glsl[]; extern char datatoc_workbench_deferred_composite_frag_glsl[]; extern char datatoc_workbench_shadow_vert_glsl[]; @@ -88,6 +97,7 @@ extern char datatoc_workbench_shadow_caps_geom_glsl[]; extern char datatoc_workbench_shadow_debug_frag_glsl[]; extern char datatoc_workbench_background_lib_glsl[]; +extern char datatoc_workbench_cavity_lib_glsl[]; extern char datatoc_workbench_common_lib_glsl[]; extern char datatoc_workbench_data_lib_glsl[]; extern char datatoc_workbench_object_outline_lib_glsl[]; @@ -146,6 +156,21 @@ static char *workbench_build_prepass_vert(void) return str; } +static char *workbench_build_cavity_frag(void) +{ + char *str = NULL; + + DynStr *ds = BLI_dynstr_new(); + + BLI_dynstr_append(ds, datatoc_workbench_common_lib_glsl); + BLI_dynstr_append(ds, datatoc_workbench_cavity_frag_glsl); + BLI_dynstr_append(ds, datatoc_workbench_cavity_lib_glsl); + + str = BLI_dynstr_get_cstring(ds); + BLI_dynstr_free(ds); + return str; +} + static void ensure_deferred_shaders(WORKBENCH_PrivateData *wpd, int index, int drawtype, bool is_hair) { if (e_data.prepass_sh_cache[index] == NULL) { @@ -185,13 +210,57 @@ static void select_deferred_shaders(WORKBENCH_PrivateData *wpd) wpd->composite_sh = e_data.composite_sh_cache[index_solid]; } + +/* Using Hammersley distribution */ +static float *create_disk_samples(int num_samples) +{ + /* vec4 to ensure memory alignment. */ + float (*texels)[4] = MEM_mallocN(sizeof(float[4]) * num_samples, "concentric_tex"); + const float num_samples_inv = 1.0f / num_samples; + + for (int i = 0; i < num_samples; i++) { + float r = (i + 0.5f) * num_samples_inv; + double dphi; + BLI_hammersley_1D(i, &dphi); + + float phi = (float)dphi * 2.0f * M_PI; + texels[i][0] = cosf(phi); + texels[i][1] = sinf(phi); + /* This deliberatly distribute more samples + * at the center of the disk (and thus the shadow). */ + texels[i][2] = r; + } + + return (float *)texels; +} + +static struct GPUTexture *create_jitter_texture(int num_samples) +{ + float jitter[64 * 64][3]; + const float num_samples_inv = 1.0f / num_samples; + + for (int i = 0; i < 64 * 64; i++) { + float phi = blue_noise[i][0] * 2.0f * M_PI; + /* This rotate the sample per pixels */ + jitter[i][0] = cosf(phi); + jitter[i][1] = sinf(phi); + /* This offset the sample along it's direction axis (reduce banding) */ + float bn = blue_noise[i][1] - 0.5f; + CLAMP(bn, -0.499f, 0.499f); /* fix fireflies */ + jitter[i][2] = bn * num_samples_inv; + } + + UNUSED_VARS(bsdf_split_sum_ggx, btdf_split_sum_ggx, ltc_mag_ggx, ltc_mat_ggx, ltc_disk_integral); + + return DRW_texture_create_2D(64, 64, GPU_RGB16F, DRW_TEX_FILTER | DRW_TEX_WRAP, &jitter[0][0]); +} /* Functions */ static void workbench_init_object_data(ObjectEngineData *engine_data) { WORKBENCH_ObjectData *data = (WORKBENCH_ObjectData *)engine_data; - data->object_id = e_data.next_object_id++; + data->object_id = ((e_data.next_object_id++) & 0xff) + 1; data->shadow_bbox_dirty = true; } @@ -244,6 +313,10 @@ void workbench_deferred_engine_init(WORKBENCH_Data *vedata) datatoc_workbench_shadow_caps_geom_glsl, shadow_frag, "#define SHADOW_FAIL\n"); + + char *cavity_frag = workbench_build_cavity_frag(); + e_data.cavity_sh = DRW_shader_create_fullscreen(cavity_frag, NULL); + MEM_freeN(cavity_frag); } if (!stl->g_data) { @@ -251,13 +324,15 @@ void workbench_deferred_engine_init(WORKBENCH_Data *vedata) stl->g_data = MEM_mallocN(sizeof(*stl->g_data), __func__); } - workbench_private_data_init(stl->g_data); + WORKBENCH_PrivateData *wpd = stl->g_data; + workbench_private_data_init(wpd); { const float *viewport_size = DRW_viewport_size_get(); const int size[2] = {(int)viewport_size[0], (int)viewport_size[1]}; e_data.object_id_tx = DRW_texture_pool_query_2D(size[0], size[1], GPU_R32UI, &draw_engine_workbench_solid); e_data.color_buffer_tx = DRW_texture_pool_query_2D(size[0], size[1], GPU_RGBA8, &draw_engine_workbench_solid); + e_data.cavity_buffer_tx = DRW_texture_pool_query_2D(size[0], size[1], GPU_RG16, &draw_engine_workbench_solid); e_data.specular_buffer_tx = DRW_texture_pool_query_2D(size[0], size[1], GPU_RGBA8, &draw_engine_workbench_solid); e_data.composite_buffer_tx = DRW_texture_pool_query_2D( size[0], size[1], GPU_RGBA16F, &draw_engine_workbench_solid); @@ -278,18 +353,59 @@ void workbench_deferred_engine_init(WORKBENCH_Data *vedata) GPU_ATTACHMENT_TEXTURE(e_data.specular_buffer_tx), GPU_ATTACHMENT_TEXTURE(e_data.normal_buffer_tx), }); + GPU_framebuffer_ensure_config(&fbl->cavity_fb, { + GPU_ATTACHMENT_NONE, + GPU_ATTACHMENT_TEXTURE(e_data.cavity_buffer_tx), + }); GPU_framebuffer_ensure_config(&fbl->composite_fb, { GPU_ATTACHMENT_TEXTURE(dtxl->depth), GPU_ATTACHMENT_TEXTURE(e_data.composite_buffer_tx), }); } + { + const DRWContextState *draw_ctx = DRW_context_state_get(); + Scene *scene = draw_ctx->scene; + /* AO Samples Tex */ + const int ssao_samples = scene->display.matcap_ssao_samples; + if (e_data.sampling_ubo && (e_data.cached_sample_num != ssao_samples)) { + DRW_UBO_FREE_SAFE(e_data.sampling_ubo); + DRW_TEXTURE_FREE_SAFE(e_data.jitter_tx); + } + + if (e_data.sampling_ubo == NULL) { + float *samples = create_disk_samples(ssao_samples); + e_data.jitter_tx = create_jitter_texture(ssao_samples); + e_data.sampling_ubo = DRW_uniformbuffer_create(sizeof(float[4]) * ssao_samples, samples); + e_data.cached_sample_num = ssao_samples; + MEM_freeN(samples); + } + } + /* Prepass */ { int state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL; psl->prepass_pass = DRW_pass_create("Prepass", state); psl->prepass_hair_pass = DRW_pass_create("Prepass", state); } + + { + int state = DRW_STATE_WRITE_COLOR; + psl->cavity_pass = DRW_pass_create("Cavity", state); + DRWShadingGroup *grp = DRW_shgroup_create(e_data.cavity_sh, psl->cavity_pass); + DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &dtxl->depth); + DRW_shgroup_uniform_texture_ref(grp, "colorBuffer", &e_data.color_buffer_tx); + DRW_shgroup_uniform_texture_ref(grp, "normalBuffer", &e_data.normal_buffer_tx); + + DRW_shgroup_uniform_vec2(grp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1); + DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)wpd->viewvecs, 3); + DRW_shgroup_uniform_vec4(grp, "ssao_params", wpd->ssao_params, 1); + DRW_shgroup_uniform_vec4(grp, "ssao_settings", wpd->ssao_settings, 1); + DRW_shgroup_uniform_mat4(grp, "WinMatrix", wpd->winmat); + DRW_shgroup_uniform_texture(grp, "ssao_jitter", e_data.jitter_tx); + DRW_shgroup_uniform_block(grp, "samples_block", e_data.sampling_ubo); + DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL); + } } void workbench_deferred_engine_free() @@ -298,22 +414,30 @@ void workbench_deferred_engine_free() DRW_SHADER_FREE_SAFE(e_data.prepass_sh_cache[index]); DRW_SHADER_FREE_SAFE(e_data.composite_sh_cache[index]); } + DRW_SHADER_FREE_SAFE(e_data.cavity_sh); + DRW_UBO_FREE_SAFE(e_data.sampling_ubo); + DRW_TEXTURE_FREE_SAFE(e_data.jitter_tx); + DRW_SHADER_FREE_SAFE(e_data.shadow_pass_sh); DRW_SHADER_FREE_SAFE(e_data.shadow_pass_manifold_sh); DRW_SHADER_FREE_SAFE(e_data.shadow_fail_sh); DRW_SHADER_FREE_SAFE(e_data.shadow_fail_manifold_sh); DRW_SHADER_FREE_SAFE(e_data.shadow_caps_sh); DRW_SHADER_FREE_SAFE(e_data.shadow_caps_manifold_sh); + } static void workbench_composite_uniforms(WORKBENCH_PrivateData *wpd, DRWShadingGroup *grp) { DRW_shgroup_uniform_texture_ref(grp, "colorBuffer", &e_data.color_buffer_tx); DRW_shgroup_uniform_texture_ref(grp, "objectId", &e_data.object_id_tx); - if (NORMAL_VIEWPORT_PASS_ENABLED(wpd)) { + if (NORMAL_VIEWPORT_COMP_PASS_ENABLED(wpd)) { DRW_shgroup_uniform_texture_ref(grp, "normalBuffer", &e_data.normal_buffer_tx); } - if (SPECULAR_HIGHLIGHT_ENABLED(wpd)) { + if (CAVITY_ENABLED(wpd)) { + DRW_shgroup_uniform_texture_ref(grp, "cavityBuffer", &e_data.cavity_buffer_tx); + } + if (SPECULAR_HIGHLIGHT_ENABLED(wpd) || MATCAP_ENABLED(wpd)) { DRW_shgroup_uniform_texture_ref(grp, "specularBuffer", &e_data.specular_buffer_tx); #if 0 @@ -338,6 +462,11 @@ static void workbench_composite_uniforms(WORKBENCH_PrivateData *wpd, DRWShadingG DRW_shgroup_uniform_block(grp, "world_block", wpd->world_ubo); DRW_shgroup_uniform_vec2(grp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1); + if (STUDIOLIGHT_ORIENTATION_VIEWNORMAL_ENABLED(wpd)) { + BKE_studiolight_ensure_flag(wpd->studio_light, STUDIOLIGHT_EQUIRECTANGULAR_RADIANCE_GPUTEXTURE); + DRW_shgroup_uniform_texture(grp, "matcapImage", wpd->studio_light->equirectangular_radiance_gputexture); DRW_shgroup_uniform_texture(grp, "matcapImage", wpd->studio_light->equirectangular_radiance_gputexture); + } + workbench_material_set_normal_world_matrix(grp, wpd, e_data.normal_world_matrix); } @@ -436,7 +565,7 @@ static WORKBENCH_MaterialData *get_or_create_material_data( /* Solid */ workbench_material_update_data(wpd, ob, mat, &material_template); - material_template.object_id = engine_object_data->object_id; + material_template.object_id = OBJECT_ID_PASS_ENABLED(wpd) ? engine_object_data->object_id : 1; material_template.drawtype = drawtype; material_template.ima = ima; uint hash = workbench_material_get_hash(&material_template); @@ -447,7 +576,7 @@ static WORKBENCH_MaterialData *get_or_create_material_data( material->shgrp = DRW_shgroup_create( drawtype == OB_SOLID ? wpd->prepass_solid_sh : wpd->prepass_texture_sh, psl->prepass_pass); DRW_shgroup_stencil_mask(material->shgrp, 0xFF); - material->object_id = engine_object_data->object_id; + material->object_id = material_template.object_id; copy_v4_v4(material->material_data.diffuse_color, material_template.material_data.diffuse_color); copy_v4_v4(material->material_data.specular_color, material_template.material_data.specular_color); material->material_data.roughness = material_template.material_data.roughness; @@ -489,7 +618,7 @@ static void workbench_cache_populate_particles(WORKBENCH_Data *vedata, Object *o continue; } if (!DRW_check_psys_visible_within_active_context(ob, psys)) { - return; + continue; } ParticleSettings *part = psys->part; const int draw_as = (part->draw_as == PART_DRAW_REND) ? part->ren_as : part->draw_as; @@ -532,7 +661,6 @@ void workbench_deferred_solid_cache_populate(WORKBENCH_Data *vedata, Object *ob) WORKBENCH_StorageList *stl = vedata->stl; WORKBENCH_PassList *psl = vedata->psl; WORKBENCH_PrivateData *wpd = stl->g_data; - if (!DRW_object_is_renderable(ob)) return; @@ -540,6 +668,10 @@ void workbench_deferred_solid_cache_populate(WORKBENCH_Data *vedata, Object *ob) workbench_cache_populate_particles(vedata, ob); } + if (!DRW_check_object_visible_within_active_context(ob)) { + return; + } + WORKBENCH_MaterialData *material; if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT)) { const DRWContextState *draw_ctx = DRW_context_state_get(); @@ -710,6 +842,12 @@ void workbench_deferred_draw_scene(WORKBENCH_Data *vedata) GPU_framebuffer_bind(fbl->prepass_fb); DRW_draw_pass(psl->prepass_pass); DRW_draw_pass(psl->prepass_hair_pass); + + if (CAVITY_ENABLED(wpd)) { + GPU_framebuffer_bind(fbl->cavity_fb); + DRW_draw_pass(psl->cavity_pass); + } + if (SHADOW_ENABLED(wpd)) { #ifdef DEBUG_SHADOW_VOLUME GPU_framebuffer_bind(fbl->composite_fb); diff --git a/source/blender/draw/engines/workbench/workbench_forward.c b/source/blender/draw/engines/workbench/workbench_forward.c index 3ed0c207bec..8bd27e18da2 100644 --- a/source/blender/draw/engines/workbench/workbench_forward.c +++ b/source/blender/draw/engines/workbench/workbench_forward.c @@ -163,7 +163,7 @@ static char *workbench_build_forward_composite_frag(void) static void workbench_init_object_data(ObjectEngineData *engine_data) { WORKBENCH_ObjectData *data = (WORKBENCH_ObjectData *)engine_data; - data->object_id = e_data.next_object_id++; + data->object_id = ((e_data.next_object_id++) & 0xff) + 1; } static WORKBENCH_MaterialData *get_or_create_material_data( @@ -180,7 +180,7 @@ static WORKBENCH_MaterialData *get_or_create_material_data( /* Solid */ workbench_material_update_data(wpd, ob, mat, &material_template); - material_template.object_id = engine_object_data->object_id; + material_template.object_id = OBJECT_ID_PASS_ENABLED(wpd) ? engine_object_data->object_id : 1; material_template.drawtype = drawtype; material_template.ima = ima; uint hash = workbench_material_get_hash(&material_template); @@ -202,7 +202,13 @@ static WORKBENCH_MaterialData *get_or_create_material_data( material->material_data.roughness = material_template.material_data.roughness; switch (drawtype) { case OB_SOLID: + { + if (STUDIOLIGHT_ORIENTATION_VIEWNORMAL_ENABLED(wpd)) { + BKE_studiolight_ensure_flag(wpd->studio_light, STUDIOLIGHT_EQUIRECTANGULAR_RADIANCE_GPUTEXTURE); + DRW_shgroup_uniform_texture(grp, "matcapImage", wpd->studio_light->equirectangular_radiance_gputexture); + } break; + } case OB_TEXTURE: { @@ -451,7 +457,7 @@ static void workbench_forward_cache_populate_particles(WORKBENCH_Data *vedata, O continue; } if (!DRW_check_psys_visible_within_active_context(ob, psys)) { - return; + continue; } ParticleSettings *part = psys->part; const int draw_as = (part->draw_as == PART_DRAW_REND) ? part->ren_as : part->draw_as; @@ -511,6 +517,11 @@ void workbench_forward_cache_populate(WORKBENCH_Data *vedata, Object *ob) if (ob->type == OB_MESH) { workbench_forward_cache_populate_particles(vedata, ob); } + + if (!DRW_check_object_visible_within_active_context(ob)) { + return; + } + if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT)) { const DRWContextState *draw_ctx = DRW_context_state_get(); const bool is_active = (ob == draw_ctx->obact); diff --git a/source/blender/draw/engines/workbench/workbench_materials.c b/source/blender/draw/engines/workbench/workbench_materials.c index 7c9c7b96b7b..b25938cd0e5 100644 --- a/source/blender/draw/engines/workbench/workbench_materials.c +++ b/source/blender/draw/engines/workbench/workbench_materials.c @@ -12,10 +12,10 @@ void workbench_material_update_data(WORKBENCH_PrivateData *wpd, Object *ob, Mate /* When in OB_TEXTURE always uyse V3D_SHADING_MATERIAL_COLOR as fallback when no texture could be determined */ int color_type = wpd->drawtype == OB_SOLID ? wpd->shading.color_type : V3D_SHADING_MATERIAL_COLOR; static float default_diffuse_color[] = {0.8f, 0.8f, 0.8f, 1.0f}; - static float default_specular_color[] = {1.0f, 1.0f, 1.0f, 1.0f}; + static float default_specular_color[] = {0.5f, 0.5f, 0.5f, 0.5f}; copy_v4_v4(data->material_data.diffuse_color, default_diffuse_color); copy_v4_v4(data->material_data.specular_color, default_specular_color); - data->material_data.roughness = 0.25f; + data->material_data.roughness = 0.5f; if (DRW_object_is_paint_mode(ob) || color_type == V3D_SHADING_SINGLE_COLOR) { copy_v3_v3(data->material_data.diffuse_color, wpd->shading.single_color); @@ -52,17 +52,29 @@ char *workbench_material_build_defines(WORKBENCH_PrivateData *wpd, int drawtype, if (wpd->shading.flag & V3D_SHADING_SHADOW) { BLI_dynstr_appendf(ds, "#define V3D_SHADING_SHADOW\n"); } - if (wpd->shading.flag & V3D_SHADING_SPECULAR_HIGHLIGHT) { + if (CAVITY_ENABLED(wpd)) { + BLI_dynstr_appendf(ds, "#define V3D_SHADING_CAVITY\n"); + } + if (SPECULAR_HIGHLIGHT_ENABLED(wpd)) { BLI_dynstr_appendf(ds, "#define V3D_SHADING_SPECULAR_HIGHLIGHT\n"); } - if (wpd->shading.light & V3D_LIGHTING_STUDIO) { + if (STUDIOLIGHT_ENABLED(wpd)) { BLI_dynstr_appendf(ds, "#define V3D_LIGHTING_STUDIO\n"); - if (STUDIOLIGHT_ORIENTATION_WORLD_ENABLED(wpd)) { - BLI_dynstr_appendf(ds, "#define STUDIOLIGHT_ORIENTATION_WORLD\n"); - } - else { - BLI_dynstr_appendf(ds, "#define STUDIOLIGHT_ORIENTATION_CAMERA\n"); - } + } + if (FLAT_ENABLED(wpd)) { + BLI_dynstr_appendf(ds, "#define V3D_LIGHTING_FLAT\n"); + } + if (MATCAP_ENABLED(wpd)) { + BLI_dynstr_appendf(ds, "#define V3D_LIGHTING_MATCAP\n"); + } + if (STUDIOLIGHT_ORIENTATION_WORLD_ENABLED(wpd)) { + BLI_dynstr_appendf(ds, "#define STUDIOLIGHT_ORIENTATION_WORLD\n"); + } + if (STUDIOLIGHT_ORIENTATION_CAMERA_ENABLED(wpd)) { + BLI_dynstr_appendf(ds, "#define STUDIOLIGHT_ORIENTATION_CAMERA\n"); + } + if (STUDIOLIGHT_ORIENTATION_VIEWNORMAL_ENABLED(wpd)) { + BLI_dynstr_appendf(ds, "#define STUDIOLIGHT_ORIENTATION_VIEWNORMAL\n"); } if (NORMAL_VIEWPORT_PASS_ENABLED(wpd)) { BLI_dynstr_appendf(ds, "#define NORMAL_VIEWPORT_PASS_ENABLED\n"); @@ -94,7 +106,6 @@ char *workbench_material_build_defines(WORKBENCH_PrivateData *wpd, int drawtype, uint workbench_material_get_hash(WORKBENCH_MaterialData *material_template) { - /* TODO: make a C-string with settings and hash the string */ uint input[4]; uint result; float *color = material_template->material_data.diffuse_color; @@ -121,18 +132,21 @@ uint workbench_material_get_hash(WORKBENCH_MaterialData *material_template) int workbench_material_get_shader_index(WORKBENCH_PrivateData *wpd, int drawtype, bool is_hair) { /* NOTE: change MAX_SHADERS accordingly when modifying this function. */ - const int DRAWOPTIONS_MASK = V3D_SHADING_OBJECT_OUTLINE | V3D_SHADING_SHADOW | V3D_SHADING_SPECULAR_HIGHLIGHT; - int index = (wpd->shading.flag & DRAWOPTIONS_MASK); - index = (index << 2) + wpd->shading.light; - index = (index << 3); - /* set the drawtype flag - 0 = OB_SOLID, - 1 = OB_TEXTURE - 2 = STUDIOLIGHT_ORIENTATION_WORLD - */ - SET_FLAG_FROM_TEST(index, wpd->studio_light->flag & STUDIOLIGHT_ORIENTATION_WORLD, 2); - SET_FLAG_FROM_TEST(index, drawtype == OB_TEXTURE, 1); - SET_FLAG_FROM_TEST(index, is_hair, 4); + int index = 0; + /* 1 bit OB_SOLID and OB_TEXTURE */ + SET_FLAG_FROM_TEST(index, drawtype == OB_TEXTURE, 1 << 0); + /* 2 bits FLAT/STUDIO/MATCAP/SCENE */ + SET_FLAG_FROM_TEST(index, wpd->shading.light, wpd->shading.light << 1); + /* 1 bit V3D_SHADING_SPECULAR_HIGHLIGHT */ + SET_FLAG_FROM_TEST(index, wpd->shading.flag & V3D_SHADING_SPECULAR_HIGHLIGHT, 1 << 3); + SET_FLAG_FROM_TEST(index, wpd->shading.flag & V3D_SHADING_SHADOW, 1 << 4); + SET_FLAG_FROM_TEST(index, wpd->shading.flag & V3D_SHADING_CAVITY, 1 << 5); + SET_FLAG_FROM_TEST(index, wpd->shading.flag & V3D_SHADING_OBJECT_OUTLINE, 1 << 6); + /* 2 bits STUDIOLIGHT_ORIENTATION */ + SET_FLAG_FROM_TEST(index, wpd->studio_light->flag & STUDIOLIGHT_ORIENTATION_WORLD, 1 << 7); + SET_FLAG_FROM_TEST(index, wpd->studio_light->flag & STUDIOLIGHT_ORIENTATION_VIEWNORMAL, 1 << 8); + /* 1 bit for hair */ + SET_FLAG_FROM_TEST(index, is_hair, 1 << 9); return index; } diff --git a/source/blender/draw/engines/workbench/workbench_private.h b/source/blender/draw/engines/workbench/workbench_private.h index 00cb6666430..9c5f97729bf 100644 --- a/source/blender/draw/engines/workbench/workbench_private.h +++ b/source/blender/draw/engines/workbench/workbench_private.h @@ -40,20 +40,28 @@ #define M_GOLDEN_RATION_CONJUGATE 0.618033988749895 #define MAX_SHADERS (1 << 10) - -#define OBJECT_ID_PASS_ENABLED(wpd) (wpd->shading.flag & V3D_SHADING_OBJECT_OUTLINE) +#define OB_SOLID_ENABLED(wpd) (wpd->drawtype & OB_SOLID) +#define OB_TEXTURE_ENABLED(wpd) (wpd->drawtype & OB_TEXTURE) +#define FLAT_ENABLED(wpd) (wpd->shading.light == V3D_LIGHTING_FLAT) +#define STUDIOLIGHT_ENABLED(wpd) (wpd->shading.light == V3D_LIGHTING_STUDIO) +#define MATCAP_ENABLED(wpd) (wpd->shading.light == V3D_LIGHTING_MATCAP && OB_SOLID_ENABLED(wpd)) +#define STUDIOLIGHT_ORIENTATION_WORLD_ENABLED(wpd) (STUDIOLIGHT_ENABLED(wpd) && (wpd->studio_light->flag & STUDIOLIGHT_ORIENTATION_WORLD)) +#define STUDIOLIGHT_ORIENTATION_CAMERA_ENABLED(wpd) (STUDIOLIGHT_ENABLED(wpd) && (wpd->studio_light->flag & STUDIOLIGHT_ORIENTATION_CAMERA)) +#define STUDIOLIGHT_ORIENTATION_VIEWNORMAL_ENABLED(wpd) (MATCAP_ENABLED(wpd) && (wpd->studio_light->flag & STUDIOLIGHT_ORIENTATION_VIEWNORMAL)) +#define CAVITY_ENABLED(wpd) (wpd->shading.flag & V3D_SHADING_CAVITY) #define SHADOW_ENABLED(wpd) (wpd->shading.flag & V3D_SHADING_SHADOW) -#define SPECULAR_HIGHLIGHT_ENABLED(wpd) (wpd->shading.flag & V3D_SHADING_SPECULAR_HIGHLIGHT) -#define NORMAL_VIEWPORT_PASS_ENABLED(wpd) (wpd->shading.light & V3D_LIGHTING_STUDIO || SHADOW_ENABLED(wpd) || SPECULAR_HIGHLIGHT_ENABLED (wpd)) +#define SPECULAR_HIGHLIGHT_ENABLED(wpd) ((wpd->shading.flag & V3D_SHADING_SPECULAR_HIGHLIGHT) && (!STUDIOLIGHT_ORIENTATION_VIEWNORMAL_ENABLED(wpd))) +#define OBJECT_ID_PASS_ENABLED(wpd) (wpd->shading.flag & V3D_SHADING_OBJECT_OUTLINE) +#define NORMAL_VIEWPORT_COMP_PASS_ENABLED(wpd) (MATCAP_ENABLED(wpd) || STUDIOLIGHT_ENABLED(wpd) || SHADOW_ENABLED(wpd) || SPECULAR_HIGHLIGHT_ENABLED(wpd)) +#define NORMAL_VIEWPORT_PASS_ENABLED(wpd) (NORMAL_VIEWPORT_COMP_PASS_ENABLED(wpd) || CAVITY_ENABLED(wpd)) #define NORMAL_ENCODING_ENABLED() (true) #define WORKBENCH_REVEALAGE_ENABLED -#define STUDIOLIGHT_ORIENTATION_WORLD_ENABLED(wpd) (wpd->studio_light->flag & STUDIOLIGHT_ORIENTATION_WORLD) -#define STUDIOLIGHT_ORIENTATION_CAMERA_ENABLED(wpd) (wpd->studio_light->flag & STUDIOLIGHT_ORIENTATION_CAMERA) typedef struct WORKBENCH_FramebufferList { /* Deferred render buffers */ struct GPUFrameBuffer *prepass_fb; + struct GPUFrameBuffer *cavity_fb; struct GPUFrameBuffer *composite_fb; /* Forward render buffers */ @@ -73,6 +81,7 @@ typedef struct WORKBENCH_PassList { /* deferred rendering */ struct DRWPass *prepass_pass; struct DRWPass *prepass_hair_pass; + struct DRWPass *cavity_pass; struct DRWPass *shadow_depth_pass_pass; struct DRWPass *shadow_depth_pass_mani_pass; struct DRWPass *shadow_depth_fail_pass; @@ -119,7 +128,8 @@ typedef struct WORKBENCH_UBO_World { float light_direction_vs[4]; WORKBENCH_UBO_Light lights[3]; int num_lights; - int pad[3]; + int matcap_orientation; + int pad[2]; } WORKBENCH_UBO_World; BLI_STATIC_ASSERT_ALIGN(WORKBENCH_UBO_World, 16) @@ -162,6 +172,12 @@ typedef struct WORKBENCH_PrivateData { float shadow_near_max[3]; float shadow_near_sides[2][4]; /* This is a parallelogram, so only 2 normal and distance to the edges. */ bool shadow_changed; + + /* Ssao */ + float winmat[4][4]; + float viewvecs[3][4]; + float ssao_params[4]; + float ssao_settings[4]; } WORKBENCH_PrivateData; /* Transient data */ typedef struct WORKBENCH_MaterialData { diff --git a/source/blender/draw/intern/DRW_render.h b/source/blender/draw/intern/DRW_render.h index 935a6d362f1..b74e6ba9204 100644 --- a/source/blender/draw/intern/DRW_render.h +++ b/source/blender/draw/intern/DRW_render.h @@ -349,6 +349,7 @@ void DRW_shgroup_call_range_add( void DRW_shgroup_call_procedural_points_add(DRWShadingGroup *shgroup, unsigned int point_count, float (*obmat)[4]); void DRW_shgroup_call_procedural_lines_add(DRWShadingGroup *shgroup, unsigned int line_count, float (*obmat)[4]); void DRW_shgroup_call_procedural_triangles_add(DRWShadingGroup *shgroup, unsigned int tria_count, float (*obmat)[4]); +void DRW_shgroup_call_object_procedural_triangles_culled_add(DRWShadingGroup *shgroup, uint tria_count, struct Object *ob); void DRW_shgroup_call_object_add_ex(DRWShadingGroup *shgroup, struct Gwn_Batch *geom, struct Object *ob, bool bypass_culling); #define DRW_shgroup_call_object_add(shgroup, geom, ob) DRW_shgroup_call_object_add_ex(shgroup, geom, ob, false) #define DRW_shgroup_call_object_add_no_cull(shgroup, geom, ob) DRW_shgroup_call_object_add_ex(shgroup, geom, ob, true) @@ -523,8 +524,6 @@ bool DRW_state_show_text(void); bool DRW_state_draw_support(void); bool DRW_state_draw_background(void); -enum eDepsObjectIteratorMode DRW_iterator_mode_get(void); - struct DRWTextStore *DRW_state_text_cache_get(void); /* Avoid too many lookups while drawing */ diff --git a/source/blender/draw/intern/draw_armature.c b/source/blender/draw/intern/draw_armature.c index ed9bb6f8ca9..a736f0a31fb 100644 --- a/source/blender/draw/intern/draw_armature.c +++ b/source/blender/draw/intern/draw_armature.c @@ -319,21 +319,32 @@ static void drw_shgroup_bone_custom_solid( Object *custom) { /* grr, not re-using instances! */ - struct Gwn_Batch *geom = DRW_cache_object_surface_get(custom); - if (geom) { - DRWShadingGroup *shgrp_geom_solid = shgroup_instance_bone_shape_solid(g_data.passes.bone_solid, geom); - float final_bonemat[4][4]; + struct Gwn_Batch *surf = DRW_cache_object_surface_get(custom); + struct Gwn_Batch *edges = DRW_cache_object_edge_detection_get(custom, NULL); + struct Gwn_Batch *ledges = DRW_cache_object_loose_edges_get(custom); + float final_bonemat[4][4]; + + if (surf || edges || ledges) { mul_m4_m4m4(final_bonemat, g_data.ob->obmat, bone_mat); + } + + if (surf) { + DRWShadingGroup *shgrp_geom_solid = shgroup_instance_bone_shape_solid(g_data.passes.bone_solid, surf); DRW_shgroup_call_dynamic_add(shgrp_geom_solid, final_bonemat, bone_color, hint_color); } - geom = DRW_cache_object_edge_detection_get(custom, NULL); - if (geom && outline_color[3] > 0.0f) { - DRWShadingGroup *shgrp_geom_wire = shgroup_instance_bone_shape_outline(g_data.passes.bone_outline, geom); - float final_bonemat[4][4]; - mul_m4_m4m4(final_bonemat, g_data.ob->obmat, bone_mat); + if (edges && outline_color[3] > 0.0f) { + DRWShadingGroup *shgrp_geom_wire = shgroup_instance_bone_shape_outline(g_data.passes.bone_outline, edges); DRW_shgroup_call_dynamic_add(shgrp_geom_wire, final_bonemat, outline_color); } + + if (ledges) { + DRWShadingGroup *shgrp_geom_ledges = shgroup_instance_wire(g_data.passes.bone_wire, ledges); + float final_color[4]; + copy_v3_v3(final_color, outline_color); + final_color[3] = 1.0f; /* hack */ + DRW_shgroup_call_dynamic_add(shgrp_geom_ledges, final_bonemat, final_color); + } } static void drw_shgroup_bone_custom_wire( diff --git a/source/blender/draw/intern/draw_cache_impl_mesh.c b/source/blender/draw/intern/draw_cache_impl_mesh.c index e6dde8adc97..c5d5eac51b7 100644 --- a/source/blender/draw/intern/draw_cache_impl_mesh.c +++ b/source/blender/draw/intern/draw_cache_impl_mesh.c @@ -112,6 +112,10 @@ typedef struct EdgeAdjacentPolys { int face_index[2]; } EdgeAdjacentPolys; +typedef struct EdgeAdjacentVerts { + int vert_index[2]; /* -1 if none */ +} EdgeAdjacentVerts; + typedef struct EdgeDrawAttr { unsigned char v_flag; unsigned char e_flag; @@ -1589,7 +1593,7 @@ typedef struct MeshBatchCache { Gwn_VertBuf *edges_face_overlay; GPUTexture *edges_face_overlay_tx; - int edges_face_overlay_tri_count; /* Number of tri in edges_face_overlay_tx */ + int edges_face_overlay_tri_count; /* Number of tri in edges_face_overlay(_adj)_tx */ /* Maybe have shaded_triangles_data split into pos_nor and uv_tangent * to minimise data transfer for skinned mesh. */ @@ -3341,29 +3345,66 @@ static Gwn_IndexBuf *mesh_batch_cache_get_edges_adjacency(MeshRenderData *rdata, } #undef NO_EDGE -static GPUTexture *mesh_batch_cache_get_edges_overlay_texture_buf(MeshRenderData *rdata, MeshBatchCache *cache) +static EdgeHash *create_looptri_edge_adjacency_hash(MeshRenderData *rdata) { - BLI_assert(rdata->types & (MR_DATATYPE_VERT | MR_DATATYPE_EDGE | MR_DATATYPE_LOOP | MR_DATATYPE_LOOPTRI)); - - BLI_assert(rdata->edit_bmesh == NULL); /* Not supported in edit mode */ + const int tri_len = mesh_render_data_looptri_len_get(rdata); + /* Create adjacency info in looptri */ + EdgeHash *eh = BLI_edgehash_new_ex(__func__, tri_len * 3); + /* Create edges for each pair of triangles sharing an edge. */ + for (int i = 0; i < tri_len; i++) { + for (int e = 0; e < 3; ++e) { + uint v0, v1, v2; + if (rdata->edit_bmesh) { + const BMLoop **bm_looptri = (const BMLoop **)rdata->edit_bmesh->looptris[i]; + if (BM_elem_flag_test(bm_looptri[0]->f, BM_ELEM_HIDDEN)) { + break; + } + v0 = BM_elem_index_get(bm_looptri[e]->v); + v1 = BM_elem_index_get(bm_looptri[(e + 1) % 3]->v); + v2 = BM_elem_index_get(bm_looptri[(e + 2) % 3]->v); + } + else { + MLoop *mloop = rdata->mloop; + MLoopTri *mlt = rdata->mlooptri + i; + v0 = mloop[mlt->tri[e]].v; + v1 = mloop[mlt->tri[(e + 1) % 3]].v; + v2 = mloop[mlt->tri[(e + 2) % 3]].v; + } - if (cache->edges_face_overlay_tx != NULL) { - return cache->edges_face_overlay_tx; + EdgeAdjacentVerts **eav; + bool value_is_init = BLI_edgehash_ensure_p(eh, v1, v2, (void ***)&eav); + if (!value_is_init) { + *eav = MEM_mallocN(sizeof(**eav), "EdgeAdjacentVerts"); + (*eav)->vert_index[0] = v0; + (*eav)->vert_index[1] = -1; + } + else { + if ((*eav)->vert_index[1] == -1) { + (*eav)->vert_index[1] = v0; + } + else { + /* Not a manifold edge. */ + } + } + } } + return eh; +} +static Gwn_VertBuf *mesh_batch_cache_create_edges_overlay_texture_buf(MeshRenderData *rdata) +{ const int tri_len = mesh_render_data_looptri_len_get(rdata); - cache->is_manifold = true; - Gwn_VertFormat format = {0}; - uint index_id = GWN_vertformat_attr_add(&format, "index", GWN_COMP_I32, 1, GWN_FETCH_INT); + uint index_id = GWN_vertformat_attr_add(&format, "index", GWN_COMP_U32, 1, GWN_FETCH_INT); Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format); - cache->edges_face_overlay = vbo; int vbo_len_capacity = tri_len * 3; GWN_vertbuf_data_alloc(vbo, vbo_len_capacity); int vidx = 0; + EdgeHash *eh = NULL; + eh = create_looptri_edge_adjacency_hash(rdata); for (int i = 0; i < tri_len; i++) { bool edge_is_real[3] = {false, false, false}; @@ -3385,23 +3426,49 @@ static GPUTexture *mesh_batch_cache_get_edges_overlay_texture_buf(MeshRenderData } for (int e = 0; e < 3; ++e) { - /* Save if there is an edge or not inside the sign bit. */ - int value = (int)mloop[mlt->tri[e]].v + 1; /* Int 0 cannot be signed */ - value = (edge_is_real[e]) ? -value : value; + int v0 = mloop[mlt->tri[e]].v; + int v1 = mloop[mlt->tri[(e + 1) % 3]].v; + EdgeAdjacentVerts *eav = BLI_edgehash_lookup(eh, v0, v1); + uint value = (uint)v0; + /* Real edge */ + if (edge_is_real[e]) { + value |= (1 << 30); + } + /* Non-manifold edge */ + if (eav->vert_index[1] == -1) { + value |= (1 << 31); + } GWN_vertbuf_attr_set(vbo, index_id, vidx++, &value); } } + BLI_edgehash_free(eh, MEM_freeN); + int vbo_len_used = vidx; if (vbo_len_capacity != vbo_len_used) { GWN_vertbuf_data_resize(vbo, vbo_len_used); } + return vbo; +} + +static GPUTexture *mesh_batch_cache_get_edges_overlay_texture_buf(MeshRenderData *rdata, MeshBatchCache *cache) +{ + BLI_assert(rdata->types & (MR_DATATYPE_VERT | MR_DATATYPE_EDGE | MR_DATATYPE_LOOP | MR_DATATYPE_LOOPTRI)); + + BLI_assert(rdata->edit_bmesh == NULL); /* Not supported in edit mode */ + + if (cache->edges_face_overlay_tx != NULL) { + return cache->edges_face_overlay_tx; + } + + Gwn_VertBuf *vbo = cache->edges_face_overlay = mesh_batch_cache_create_edges_overlay_texture_buf(rdata); + /* Upload data early because we need to create the texture for it. */ GWN_vertbuf_use(vbo); cache->edges_face_overlay_tx = GPU_texture_create_from_vertbuf(vbo); - cache->edges_face_overlay_tri_count = vbo_len_used / 3; + cache->edges_face_overlay_tri_count = vbo->vertex_alloc / 3; return cache->edges_face_overlay_tx; } diff --git a/source/blender/draw/intern/draw_cache_impl_particles.c b/source/blender/draw/intern/draw_cache_impl_particles.c index 1348968bad7..380cb089628 100644 --- a/source/blender/draw/intern/draw_cache_impl_particles.c +++ b/source/blender/draw/intern/draw_cache_impl_particles.c @@ -181,7 +181,7 @@ static void particle_batch_cache_clear_hair(ParticleHairCache *hair_cache) for (int i = 0; i < MAX_HAIR_SUBDIV; ++i) { GWN_VERTBUF_DISCARD_SAFE(hair_cache->final[i].proc_buf); DRW_TEXTURE_FREE_SAFE(hair_cache->final[i].proc_tex); - for (int j = 0; j < MAX_THICKRES - 1; ++j) { + for (int j = 0; j < MAX_THICKRES; ++j) { GWN_BATCH_DISCARD_SAFE(hair_cache->final[i].proc_hairs[j]); } } @@ -779,7 +779,7 @@ static void particle_batch_cache_ensure_procedural_strand_data( ParticleSystemModifierData *psmd = (ParticleSystemModifierData *)md; - if (psmd != NULL) { + if (psmd != NULL && psmd->mesh_final != NULL) { if (CustomData_has_layer(&psmd->mesh_final->ldata, CD_MLOOPUV)) { cache->num_uv_layers = CustomData_number_of_layers(&psmd->mesh_final->ldata, CD_MLOOPUV); active_uv = CustomData_get_active_layer(&psmd->mesh_final->ldata, CD_MLOOPUV); diff --git a/source/blender/draw/intern/draw_hair.c b/source/blender/draw/intern/draw_hair.c index 2c03caf0ac3..d5923419b37 100644 --- a/source/blender/draw/intern/draw_hair.c +++ b/source/blender/draw/intern/draw_hair.c @@ -109,6 +109,7 @@ static DRWShadingGroup *drw_shgroup_create_hair_procedural_ex( shgrp = DRW_shgroup_create(gpu_shader, hair_pass); } else { + shgrp = NULL; BLI_assert(0); } diff --git a/source/blender/draw/intern/draw_instance_data.h b/source/blender/draw/intern/draw_instance_data.h index 86c4429a091..0ea40a50a6b 100644 --- a/source/blender/draw/intern/draw_instance_data.h +++ b/source/blender/draw/intern/draw_instance_data.h @@ -31,7 +31,7 @@ #include "GPU_batch.h" -#define MAX_INSTANCE_DATA_SIZE 48 /* Can be adjusted for more */ +#define MAX_INSTANCE_DATA_SIZE 64 /* Can be adjusted for more */ typedef struct DRWInstanceData DRWInstanceData; typedef struct DRWInstanceDataList DRWInstanceDataList; diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c index d54c943f736..a70f5f8a487 100644 --- a/source/blender/draw/intern/draw_manager.c +++ b/source/blender/draw/intern/draw_manager.c @@ -764,6 +764,7 @@ ObjectEngineData *DRW_object_engine_data_ensure( const size_t t = sizeof(float) - 1; size = (size + t) & ~t; size_t fsize = size / sizeof(float); + BLI_assert(fsize < MAX_INSTANCE_DATA_SIZE); if (DST.object_instance_data[fsize] == NULL) { DST.object_instance_data[fsize] = DRW_instance_data_request(DST.idatalist, fsize); } @@ -1232,7 +1233,9 @@ void DRW_draw_view(const bContext *C) /* Reset before using it. */ drw_state_prepare_clean_for_draw(&DST); - DST.options.draw_text = (v3d->overlay.flag & V3D_OVERLAY_HIDE_TEXT) != 0; + DST.options.draw_text = ( + (v3d->flag2 & V3D_RENDER_OVERRIDE) == 0 && + (v3d->overlay.flag & V3D_OVERLAY_HIDE_TEXT) != 0); DRW_draw_render_loop_ex(depsgraph, engine_type, ar, v3d, viewport, C); } @@ -1292,7 +1295,7 @@ void DRW_draw_render_loop_ex( PROFILE_START(stime); drw_engines_cache_init(); - DEG_OBJECT_ITER_FOR_RENDER_ENGINE_BEGIN(depsgraph, ob, DRW_iterator_mode_get()) + DEG_OBJECT_ITER_FOR_RENDER_ENGINE_BEGIN(depsgraph, ob) { drw_engines_cache_populate(ob); } @@ -1544,14 +1547,12 @@ void DRW_render_object_iter( { DRW_hair_init(); - DEG_OBJECT_ITER_FOR_RENDER_ENGINE_BEGIN(depsgraph, ob, DRW_iterator_mode_get()) + DEG_OBJECT_ITER_FOR_RENDER_ENGINE_BEGIN(depsgraph, ob) { DST.ob_state = NULL; callback(vedata, ob, engine, depsgraph); } DEG_OBJECT_ITER_FOR_RENDER_ENGINE_END - - DRW_hair_update(); } static struct DRWSelectBuffer { @@ -1689,13 +1690,17 @@ void DRW_draw_select_loop( } else { DEG_OBJECT_ITER_BEGIN( - depsgraph, ob, DRW_iterator_mode_get(), + depsgraph, ob, DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY | DEG_ITER_OBJECT_FLAG_VISIBLE | DEG_ITER_OBJECT_FLAG_DUPLI) { if ((ob->base_flag & BASE_SELECTABLED) != 0) { - DRW_select_load_id(ob->select_color); + /* This relies on dupli instances being after their instancing object. */ + if ((ob->base_flag & BASE_FROMDUPLI) == 0) { + Object *ob_orig = DEG_get_original_object(ob); + DRW_select_load_id(ob_orig->select_color); + } drw_engines_cache_populate(ob); } } @@ -1856,7 +1861,7 @@ void DRW_draw_depth_loop( if (cache_is_dirty) { drw_engines_cache_init(); - DEG_OBJECT_ITER_FOR_RENDER_ENGINE_BEGIN(depsgraph, ob, DRW_iterator_mode_get()) + DEG_OBJECT_ITER_FOR_RENDER_ENGINE_BEGIN(depsgraph, ob) { drw_engines_cache_populate(ob); } @@ -1971,15 +1976,6 @@ bool DRW_state_is_opengl_render(void) } /** - * Gives you the iterator mode to use for depsgraph. - */ -eDepsObjectIteratorMode DRW_iterator_mode_get(void) -{ - return DRW_state_is_scene_render() ? DEG_ITER_OBJECT_MODE_RENDER : - DEG_ITER_OBJECT_MODE_VIEWPORT; -} - -/** * Should text draw in this mode? */ bool DRW_state_show_text(void) diff --git a/source/blender/draw/intern/draw_manager_data.c b/source/blender/draw/intern/draw_manager_data.c index c419e9e2535..b49af47223f 100644 --- a/source/blender/draw/intern/draw_manager_data.c +++ b/source/blender/draw/intern/draw_manager_data.c @@ -391,12 +391,17 @@ void DRW_shgroup_call_range_add(DRWShadingGroup *shgroup, Gwn_Batch *geom, float } static void drw_shgroup_call_procedural_add_ex( - DRWShadingGroup *shgroup, Gwn_PrimType prim_type, uint vert_count, float (*obmat)[4]) + DRWShadingGroup *shgroup, Gwn_PrimType prim_type, uint vert_count, float (*obmat)[4], Object *ob) { BLI_assert(ELEM(shgroup->type, DRW_SHG_NORMAL, DRW_SHG_FEEDBACK_TRANSFORM)); DRWCall *call = BLI_mempool_alloc(DST.vmempool->calls); - call->state = drw_call_state_create(shgroup, obmat, NULL); + if (ob) { + call->state = drw_call_state_object(shgroup, ob->obmat, ob); + } + else { + call->state = drw_call_state_create(shgroup, obmat, NULL); + } call->type = DRW_CALL_PROCEDURAL; call->procedural.prim_type = prim_type; call->procedural.vert_count = vert_count; @@ -409,17 +414,24 @@ static void drw_shgroup_call_procedural_add_ex( void DRW_shgroup_call_procedural_points_add(DRWShadingGroup *shgroup, uint point_count, float (*obmat)[4]) { - drw_shgroup_call_procedural_add_ex(shgroup, GWN_PRIM_POINTS, point_count, obmat); + drw_shgroup_call_procedural_add_ex(shgroup, GWN_PRIM_POINTS, point_count, obmat, NULL); } void DRW_shgroup_call_procedural_lines_add(DRWShadingGroup *shgroup, uint line_count, float (*obmat)[4]) { - drw_shgroup_call_procedural_add_ex(shgroup, GWN_PRIM_LINES, line_count * 2, obmat); + drw_shgroup_call_procedural_add_ex(shgroup, GWN_PRIM_LINES, line_count * 2, obmat, NULL); } void DRW_shgroup_call_procedural_triangles_add(DRWShadingGroup *shgroup, uint tria_count, float (*obmat)[4]) { - drw_shgroup_call_procedural_add_ex(shgroup, GWN_PRIM_TRIS, tria_count * 3, obmat); + drw_shgroup_call_procedural_add_ex(shgroup, GWN_PRIM_TRIS, tria_count * 3, obmat, NULL); +} + +/* TODO (fclem): this is a sign that the api is starting to be limiting. + * Maybe add special function that general purpose for special cases. */ +void DRW_shgroup_call_object_procedural_triangles_culled_add(DRWShadingGroup *shgroup, uint tria_count, Object *ob) +{ + drw_shgroup_call_procedural_add_ex(shgroup, GWN_PRIM_TRIS, tria_count * 3, NULL, ob); } /* These calls can be culled and are optimized for redraw */ @@ -732,7 +744,14 @@ static DRWShadingGroup *drw_shgroup_material_create_ex(GPUPass *gpupass, DRWPass return NULL; } - DRWShadingGroup *grp = drw_shgroup_create_ex(GPU_pass_shader(gpupass), pass); + GPUShader *sh = GPU_pass_shader_get(gpupass); + + if (!sh) { + /* Shader not yet compiled */ + return NULL; + } + + DRWShadingGroup *grp = drw_shgroup_create_ex(sh, pass); return grp; } @@ -780,7 +799,7 @@ static DRWShadingGroup *drw_shgroup_material_inputs(DRWShadingGroup *grp, struct } } - GPUUniformBuffer *ubo = GPU_material_get_uniform_buffer(material); + GPUUniformBuffer *ubo = GPU_material_uniform_buffer_get(material); if (ubo != NULL) { DRW_shgroup_uniform_block(grp, GPU_UBO_BLOCK_NAME, ubo); } @@ -808,7 +827,7 @@ DRWShadingGroup *DRW_shgroup_material_create( DRWShadingGroup *shgroup = drw_shgroup_material_create_ex(gpupass, pass); if (shgroup) { - drw_shgroup_init(shgroup, GPU_pass_shader(gpupass)); + drw_shgroup_init(shgroup, GPU_pass_shader_get(gpupass)); drw_shgroup_material_inputs(shgroup, material); } @@ -825,7 +844,7 @@ DRWShadingGroup *DRW_shgroup_material_instance_create( shgroup->type = DRW_SHG_INSTANCE; shgroup->instance_geom = geom; drw_call_calc_orco(ob, shgroup->instance_orcofac); - drw_shgroup_instance_init(shgroup, GPU_pass_shader(gpupass), geom, format); + drw_shgroup_instance_init(shgroup, GPU_pass_shader_get(gpupass), geom, format); drw_shgroup_material_inputs(shgroup, material); } @@ -843,7 +862,7 @@ DRWShadingGroup *DRW_shgroup_material_empty_tri_batch_create( if (shgroup) { /* Calling drw_shgroup_init will cause it to call GWN_draw_primitive(). */ - drw_shgroup_init(shgroup, GPU_pass_shader(gpupass)); + drw_shgroup_init(shgroup, GPU_pass_shader_get(gpupass)); shgroup->type = DRW_SHG_TRIANGLE_BATCH; shgroup->instance_count = tri_count * 3; drw_shgroup_material_inputs(shgroup, material); diff --git a/source/blender/draw/intern/draw_manager_shader.c b/source/blender/draw/intern/draw_manager_shader.c index 56a7c5db08e..0b6974b7b36 100644 --- a/source/blender/draw/intern/draw_manager_shader.c +++ b/source/blender/draw/intern/draw_manager_shader.c @@ -62,7 +62,6 @@ typedef struct DRWDeferredShader { struct DRWDeferredShader *prev, *next; GPUMaterial *mat; - char *vert, *geom, *frag, *defs; } DRWDeferredShader; typedef struct DRWShaderCompiler { @@ -80,11 +79,6 @@ typedef struct DRWShaderCompiler { static void drw_deferred_shader_free(DRWDeferredShader *dsh) { /* Make sure it is not queued before freeing. */ - MEM_SAFE_FREE(dsh->vert); - MEM_SAFE_FREE(dsh->geom); - MEM_SAFE_FREE(dsh->frag); - MEM_SAFE_FREE(dsh->defs); - MEM_freeN(dsh); } @@ -129,12 +123,7 @@ static void drw_deferred_shader_compilation_exec(void *custom_data, short *stop, BLI_spin_unlock(&comp->list_lock); /* Do the compilation. */ - GPU_material_generate_pass( - comp->mat_compiling->mat, - comp->mat_compiling->vert, - comp->mat_compiling->geom, - comp->mat_compiling->frag, - comp->mat_compiling->defs); + GPU_material_compile(comp->mat_compiling->mat); *progress = (float)comp->shaders_done / (float)total; *do_update = true; @@ -165,25 +154,20 @@ static void drw_deferred_shader_compilation_free(void *custom_data) MEM_freeN(comp); } -static void drw_deferred_shader_add( - GPUMaterial *mat, const char *vert, const char *geom, const char *frag_lib, const char *defines) +static void drw_deferred_shader_add(GPUMaterial *mat) { /* Do not deferre the compilation if we are rendering for image. */ if (DRW_state_is_image_render() || !USE_DEFERRED_COMPILATION) { /* Double checking that this GPUMaterial is not going to be * compiled by another thread. */ DRW_deferred_shader_remove(mat); - GPU_material_generate_pass(mat, vert, geom, frag_lib, defines); + GPU_material_compile(mat); return; } DRWDeferredShader *dsh = MEM_callocN(sizeof(DRWDeferredShader), "Deferred Shader"); dsh->mat = mat; - if (vert) dsh->vert = BLI_strdup(vert); - if (geom) dsh->geom = BLI_strdup(geom); - if (frag_lib) dsh->frag = BLI_strdup(frag_lib); - if (defines) dsh->defs = BLI_strdup(defines); BLI_assert(DST.draw_ctx.evil_C); wmWindowManager *wm = CTX_wm_manager(DST.draw_ctx.evil_C); @@ -361,10 +345,13 @@ GPUMaterial *DRW_shader_create_from_world( if (mat == NULL) { mat = GPU_material_from_nodetree( - scene, wo->nodetree, &wo->gpumaterial, engine_type, options); + scene, wo->nodetree, &wo->gpumaterial, engine_type, options, + vert, geom, frag_lib, defines); } - drw_deferred_shader_add(mat, vert, geom, frag_lib, defines); + if (GPU_material_status(mat) == GPU_MAT_QUEUED) { + drw_deferred_shader_add(mat); + } return mat; } @@ -380,10 +367,13 @@ GPUMaterial *DRW_shader_create_from_material( if (mat == NULL) { mat = GPU_material_from_nodetree( - scene, ma->nodetree, &ma->gpumaterial, engine_type, options); + scene, ma->nodetree, &ma->gpumaterial, engine_type, options, + vert, geom, frag_lib, defines); } - drw_deferred_shader_add(mat, vert, geom, frag_lib, defines); + if (GPU_material_status(mat) == GPU_MAT_QUEUED) { + drw_deferred_shader_add(mat); + } return mat; } diff --git a/source/blender/draw/modes/object_mode.c b/source/blender/draw/modes/object_mode.c index 7762a6c5dc8..09ed4b96756 100644 --- a/source/blender/draw/modes/object_mode.c +++ b/source/blender/draw/modes/object_mode.c @@ -2017,16 +2017,12 @@ static void OBJECT_cache_populate_particles(Object *ob, continue; } if (!DRW_check_psys_visible_within_active_context(ob, psys)) { - return; + continue; } ParticleSettings *part = psys->part; int draw_as = (part->draw_as == PART_DRAW_REND) ? part->ren_as : part->draw_as; - if (draw_as == PART_DRAW_PATH && !psys->pathcache && !psys->childcache) { - draw_as = PART_DRAW_DOT; - } - static float mat[4][4]; unit_m4(mat); diff --git a/source/blender/draw/modes/overlay_mode.c b/source/blender/draw/modes/overlay_mode.c index 131a9bc10db..97403b14ac5 100644 --- a/source/blender/draw/modes/overlay_mode.c +++ b/source/blender/draw/modes/overlay_mode.c @@ -52,8 +52,10 @@ typedef struct OVERLAY_Data { } OVERLAY_Data; typedef struct OVERLAY_PrivateData { + GPUShader *wire_sh; /* reference */ DRWShadingGroup *face_orientation_shgrp; View3DOverlay overlay; + float wire_step_param[2]; } OVERLAY_PrivateData; /* Transient data */ /* *********** STATIC *********** */ @@ -62,6 +64,7 @@ static struct { struct GPUShader *face_orientation_sh; /* Wireframe shader */ struct GPUShader *face_wireframe_sh; + struct GPUShader *face_wireframe_pretty_sh; } e_data = {NULL}; /* Shaders */ @@ -93,14 +96,22 @@ static void overlay_engine_init(void *vedata) } if (!e_data.face_wireframe_sh) { - char *wireframe_geom = NULL; - if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_ANY, GPU_DRIVER_ANY)) { - wireframe_geom = datatoc_overlay_face_wireframe_geom_glsl; - } + bool use_geom = GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_ANY, GPU_DRIVER_ANY); + e_data.face_wireframe_sh = DRW_shader_create( datatoc_overlay_face_wireframe_vert_glsl, - wireframe_geom, - datatoc_overlay_face_wireframe_frag_glsl, NULL); + use_geom ? datatoc_overlay_face_wireframe_geom_glsl : NULL, + datatoc_overlay_face_wireframe_frag_glsl, + use_geom ? "#define USE_GEOM_SHADER\n" + : NULL); + + e_data.face_wireframe_pretty_sh = DRW_shader_create( + datatoc_overlay_face_wireframe_vert_glsl, + use_geom ? datatoc_overlay_face_wireframe_geom_glsl : NULL, + datatoc_overlay_face_wireframe_frag_glsl, + use_geom ? "#define USE_GEOM_SHADER\n" + "#define LIGHT_EDGES\n" + : "#define LIGHT_EDGES\n"); } } @@ -130,6 +141,25 @@ static void overlay_cache_init(void *vedata) if (stl->g_data->overlay.flag & V3D_OVERLAY_WIREFRAMES) { DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_BLEND; psl->face_wireframe_pass = DRW_pass_create("Face Wires", state); + /* Sticky uniforms (don't need to respecify each time since shader does not change). */ + stl->g_data->wire_sh = (stl->g_data->overlay.wireframe_threshold == 1.0f) ? e_data.face_wireframe_sh + : e_data.face_wireframe_pretty_sh; + DRWShadingGroup *shgrp = DRW_shgroup_create(stl->g_data->wire_sh, psl->face_wireframe_pass); + DRW_shgroup_uniform_vec2(shgrp, "viewportSize", DRW_viewport_size_get(), 1); + DRW_shgroup_uniform_vec2(shgrp, "wireStepParam", stl->g_data->wire_step_param, 1); + + /** + * The wireframe threshold ranges from 0.0 to 1.0 + * When 1.0 we show all the edges, when 0.5 we show as many as 2.7. + * + * If we wanted 0.0 to match 2.7, factor would need to be 0.003f. + * The range controls the falloff effect. If range was 0.0f we would get a hard cut (as in 2.7). + * That said we are using a different algorithm so the results will always differ. + */ + const float factor = 0.0045f; + const float range = 0.00125f; + stl->g_data->wire_step_param[1] = (1.0f - factor) + stl->g_data->overlay.wireframe_threshold * factor; + stl->g_data->wire_step_param[0] = stl->g_data->wire_step_param[1] + range; } } @@ -162,14 +192,12 @@ static void overlay_cache_populate(void *vedata, Object *ob) if ((ob->base_flag & BASE_SELECTED) != 0) { rim_col = (ob == draw_ctx->obact) ? ts.colorActive : ts.colorSelect; } - /* TODO(fclem): Compare performance with a geom shader based approach. */ - DRWShadingGroup *shgrp = DRW_shgroup_create(e_data.face_wireframe_sh, psl->face_wireframe_pass); + DRWShadingGroup *shgrp = DRW_shgroup_create(stl->g_data->wire_sh, psl->face_wireframe_pass); DRW_shgroup_uniform_texture(shgrp, "vertData", verts); DRW_shgroup_uniform_texture(shgrp, "faceIds", faceids); DRW_shgroup_uniform_vec3(shgrp, "wireColor", ts.colorWire, 1); DRW_shgroup_uniform_vec3(shgrp, "rimColor", rim_col, 1); - DRW_shgroup_uniform_vec2(shgrp, "viewportSize", DRW_viewport_size_get(), 1); - DRW_shgroup_call_procedural_triangles_add(shgrp, tri_count, ob->obmat); + DRW_shgroup_call_object_procedural_triangles_culled_add(shgrp, tri_count, ob); } } } @@ -198,6 +226,7 @@ static void overlay_engine_free(void) { DRW_SHADER_FREE_SAFE(e_data.face_orientation_sh); DRW_SHADER_FREE_SAFE(e_data.face_wireframe_sh); + DRW_SHADER_FREE_SAFE(e_data.face_wireframe_pretty_sh); } static const DrawEngineDataSize overlay_data_size = DRW_VIEWPORT_DATA_SIZE(OVERLAY_Data); diff --git a/source/blender/draw/modes/particle_mode.c b/source/blender/draw/modes/particle_mode.c index dacd4b72834..19c3ddd4b50 100644 --- a/source/blender/draw/modes/particle_mode.c +++ b/source/blender/draw/modes/particle_mode.c @@ -183,6 +183,12 @@ static void particle_cache_populate(void *vedata, Object *object) Object *object_orig = DEG_get_original_object(object); PTCacheEdit *edit = PE_create_current( draw_ctx->depsgraph, scene_orig, object_orig); + if (edit == NULL) { + /* Happens when trying to edit particles in EMITTER mode without + * having them cached. + */ + return; + } /* NOTE: We need to pass evaluated particle system, which we need * to find first. */ diff --git a/source/blender/draw/modes/pose_mode.c b/source/blender/draw/modes/pose_mode.c index 586fb590ebf..ad9567cd9c0 100644 --- a/source/blender/draw/modes/pose_mode.c +++ b/source/blender/draw/modes/pose_mode.c @@ -72,13 +72,15 @@ typedef struct POSE_Data { typedef struct POSE_PrivateData { DRWShadingGroup *bone_selection_shgrp; + DRWShadingGroup *bone_selection_invert_shgrp; + float blend_color[4]; + float blend_color_invert[4]; } POSE_PrivateData; /* Transient data */ static struct { struct GPUShader *bone_selection_sh; } e_data = {NULL}; -static float blend_color[4] = {0.0, 0.0, 0.0, 0.5}; /* *********** FUNCTIONS *********** */ static bool POSE_is_bone_selection_overlay_active(void) @@ -105,11 +107,14 @@ static void POSE_cache_init(void *vedata) { POSE_PassList *psl = ((POSE_Data *)vedata)->psl; POSE_StorageList *stl = ((POSE_Data *)vedata)->stl; + const DRWContextState *draw_ctx = DRW_context_state_get(); + View3D *v3d = draw_ctx->v3d; if (!stl->g_data) { /* Alloc transient pointers */ stl->g_data = MEM_mallocN(sizeof(*stl->g_data), __func__); } + POSE_PrivateData *ppd = stl->g_data; { /* Solid bones */ @@ -150,13 +155,18 @@ static void POSE_cache_init(void *vedata) { if (POSE_is_bone_selection_overlay_active()) { + copy_v4_fl4(ppd->blend_color, 0.0f, 0.0f, 0.0f, v3d->overlay.bone_selection_alpha); + copy_v4_fl4(ppd->blend_color_invert, 0.0f, 0.0f, 0.0f, pow(v3d->overlay.bone_selection_alpha, 4)); DRWShadingGroup *grp; psl->bone_selection = DRW_pass_create( "Bone Selection", DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_BLEND); grp = DRW_shgroup_create(e_data.bone_selection_sh, psl->bone_selection); - DRW_shgroup_uniform_vec4(grp, "color", blend_color, 1); + DRW_shgroup_uniform_vec4(grp, "color", ppd->blend_color, 1); stl->g_data->bone_selection_shgrp = grp; + grp = DRW_shgroup_create(e_data.bone_selection_sh, psl->bone_selection); + DRW_shgroup_uniform_vec4(grp, "color", ppd->blend_color_invert, 1); + stl->g_data->bone_selection_invert_shgrp = grp; } } } @@ -206,12 +216,16 @@ static void POSE_cache_populate(void *vedata, Object *ob) } else if (ob->type == OB_MESH && !DRW_state_is_select() && - POSE_is_bone_selection_overlay_active() && - POSE_is_driven_by_active_armature(ob)) + POSE_is_bone_selection_overlay_active()) { struct Gwn_Batch *geom = DRW_cache_object_surface_get(ob); if (geom) { - DRW_shgroup_call_object_add(stl->g_data->bone_selection_shgrp, geom, ob); + if (POSE_is_driven_by_active_armature(ob)) { + DRW_shgroup_call_object_add(stl->g_data->bone_selection_shgrp, geom, ob); + } + else { + DRW_shgroup_call_object_add(stl->g_data->bone_selection_invert_shgrp, geom, ob); + } } } } diff --git a/source/blender/draw/modes/shaders/armature_shape_outline_geom.glsl b/source/blender/draw/modes/shaders/armature_shape_outline_geom.glsl index 11924b19cf8..4d6f3e94693 100644 --- a/source/blender/draw/modes/shaders/armature_shape_outline_geom.glsl +++ b/source/blender/draw/modes/shaders/armature_shape_outline_geom.glsl @@ -69,7 +69,7 @@ void main(void) return; /* Don't outline if concave edge. */ - if (dot(n0, v13) > 0.0) + if (dot(n0, v13) > 0.0001) return; vec2 thick = vColSize[0].w * (lineThickness / viewportSize); diff --git a/source/blender/draw/modes/shaders/overlay_face_wireframe_frag.glsl b/source/blender/draw/modes/shaders/overlay_face_wireframe_frag.glsl index a714de9579a..00ababc624d 100644 --- a/source/blender/draw/modes/shaders/overlay_face_wireframe_frag.glsl +++ b/source/blender/draw/modes/shaders/overlay_face_wireframe_frag.glsl @@ -6,9 +6,14 @@ flat in vec3 ssVec1; flat in vec3 ssVec2; in float facing; +#ifdef LIGHT_EDGES +in float edgeSharpness; +#endif + out vec4 fragColor; float min_v3(vec3 v) { return min(v.x, min(v.y, v.z)); } +float max_v3(vec3 v) { return max(v.x, max(v.y, v.z)); } /* In pixels */ const float wire_size = 0.0; /* Expands the core of the wire (part that is 100% wire color) */ @@ -27,10 +32,22 @@ void main() dot(ss_pos, ssVec2) ); - float fac = smoothstep(wire_size, wire_size + wire_smooth, min_v3(abs(dist_to_edge))); +#ifdef LIGHT_EDGES + vec3 fac = abs(dist_to_edge); +#else + float fac = min_v3(abs(dist_to_edge)); +#endif + + fac = smoothstep(wire_size + wire_smooth, wire_size, fac); + float facing_clamped = clamp((gl_FrontFacing) ? facing : -facing, 0.0, 1.0); vec3 final_front_col = mix(rimColor, wireColor, 0.05); fragColor = mix(vec4(rimColor, rim_alpha), vec4(final_front_col, front_alpha), facing_clamped); - fragColor.a *= (1.0 - fac); + +#ifdef LIGHT_EDGES + fragColor.a *= max_v3(fac * edgeSharpness); +#else + fragColor.a *= fac; +#endif } diff --git a/source/blender/draw/modes/shaders/overlay_face_wireframe_geom.glsl b/source/blender/draw/modes/shaders/overlay_face_wireframe_geom.glsl index 1cea418419e..6e833a4e16b 100644 --- a/source/blender/draw/modes/shaders/overlay_face_wireframe_geom.glsl +++ b/source/blender/draw/modes/shaders/overlay_face_wireframe_geom.glsl @@ -1,7 +1,12 @@ +/* This shader is only used for intel GPU where the Geom shader is faster + * than doing everything thrice in the vertex shader. */ + layout(triangles) in; layout(triangle_strip, max_vertices = 3) out; +uniform vec2 wireStepParam; + in vec2 ssPos[]; in float facingOut[]; @@ -10,8 +15,17 @@ flat out vec3 ssVec1; flat out vec3 ssVec2; out float facing; +#ifdef LIGHT_EDGES +in vec3 obPos[]; +in vec3 vNor[]; +in float forceEdge[]; + +out float edgeSharpness; +#endif + #define NO_EDGE vec3(10000.0); +/* TODO(fclem) remove code duplication. */ vec3 compute_vec(vec2 v0, vec2 v1) { vec2 v = normalize(v1 - v0); @@ -19,6 +33,12 @@ vec3 compute_vec(vec2 v0, vec2 v1) return vec3(v, -dot(v, v0)); } +float get_edge_sharpness(vec3 fnor, vec3 vnor) +{ + float sharpness = abs(dot(fnor, vnor)); + return smoothstep(wireStepParam.x, wireStepParam.y, sharpness); +} + void main(void) { vec3 facings = vec3(facingOut[0], facingOut[1], facingOut[2]); @@ -29,12 +49,28 @@ void main(void) ssVec1 = do_edge.y ? compute_vec(ssPos[1], ssPos[2]) : NO_EDGE; ssVec2 = do_edge.z ? compute_vec(ssPos[2], ssPos[0]) : NO_EDGE; +#ifdef LIGHT_EDGES + vec3 fnor = normalize(cross(obPos[1] - obPos[0], obPos[2] - obPos[0])); + + edgeSharpness = get_edge_sharpness(fnor, vNor[0]); + edgeSharpness = (forceEdge[0] == 1.0 || forceEdge[2] == 1.0) ? 1.0 : edgeSharpness; +#endif gl_Position = gl_in[0].gl_Position; facing = facings.x; EmitVertex(); + +#ifdef LIGHT_EDGES + edgeSharpness = get_edge_sharpness(fnor, vNor[1]); + edgeSharpness = (forceEdge[1] == 1.0 || forceEdge[0] == 1.0) ? 1.0 : edgeSharpness; +#endif gl_Position = gl_in[1].gl_Position; facing = facings.y; EmitVertex(); + +#ifdef LIGHT_EDGES + edgeSharpness = get_edge_sharpness(fnor, vNor[2]); + edgeSharpness = (forceEdge[2] == 1.0 || forceEdge[1] == 1.0) ? 1.0 : edgeSharpness; +#endif gl_Position = gl_in[2].gl_Position; facing = facings.z; EmitVertex(); diff --git a/source/blender/draw/modes/shaders/overlay_face_wireframe_vert.glsl b/source/blender/draw/modes/shaders/overlay_face_wireframe_vert.glsl index 2cd888e7537..616cd5379e9 100644 --- a/source/blender/draw/modes/shaders/overlay_face_wireframe_vert.glsl +++ b/source/blender/draw/modes/shaders/overlay_face_wireframe_vert.glsl @@ -1,18 +1,15 @@ -#ifdef GPU_INTEL -#define USE_GEOM_SHADER -#endif - uniform mat4 ModelViewProjectionMatrix; uniform mat4 ModelViewMatrix; uniform mat4 ProjectionMatrix; uniform mat3 NormalMatrix; +uniform vec2 wireStepParam; uniform vec2 viewportSize; uniform float nearDist; uniform samplerBuffer vertData; -uniform isamplerBuffer faceIds; +uniform usamplerBuffer faceIds; #ifdef USE_GEOM_SHADER out vec2 ssPos; @@ -24,6 +21,16 @@ flat out vec3 ssVec2; out float facing; #endif +#ifdef LIGHT_EDGES +#ifdef USE_GEOM_SHADER +out vec3 obPos; +out vec3 vNor; +out float forceEdge; +#else +out float edgeSharpness; +#endif +#endif + /* project to screen space */ vec2 proj(vec4 pos) { @@ -46,9 +53,9 @@ float short_to_unit_float(uint s) return float(value) / float(0x7FFF); } -vec3 get_vertex_nor(int v_id) +vec3 get_vertex_nor(uint id) { - v_id *= 5; /* See vertex format for explanation. */ + int v_id = int(id) * 5; /* See vertex format for explanation. */ /* Fetch compressed normal as float and unpack them. */ vec2 data; data.x = texelFetch(vertData, v_id + 3).r; @@ -63,9 +70,9 @@ vec3 get_vertex_nor(int v_id) return nor; } -vec3 get_vertex_pos(int v_id) +vec3 get_vertex_pos(uint id) { - v_id *= 5; /* See vertex format for explanation. */ + int v_id = int(id) * 5; /* See vertex format for explanation. */ vec3 pos; pos.x = texelFetch(vertData, v_id).r; pos.y = texelFetch(vertData, v_id + 1).r; @@ -73,15 +80,22 @@ vec3 get_vertex_pos(int v_id) return pos; } +float get_edge_sharpness(vec3 fnor, vec3 vnor) +{ + float sharpness = abs(dot(fnor, vnor)); + return smoothstep(wireStepParam.x, wireStepParam.y, sharpness); +} + #define NO_EDGE vec3(10000.0); void main() { #ifdef USE_GEOM_SHADER - int v_id = texelFetch(faceIds, gl_VertexID).r; + uint v_id = texelFetch(faceIds, gl_VertexID).r; - bool do_edge = v_id < 0; - v_id = abs(v_id) - 1; + bool do_edge = (v_id & (1u << 30u)) != 0u; + bool force_edge = (v_id & (1u << 31u)) != 0u; + v_id = (v_id << 2u) >> 2u; vec3 pos = get_vertex_pos(v_id); vec3 nor = get_vertex_nor(v_id); @@ -91,18 +105,30 @@ void main() gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); ssPos = proj(gl_Position); -#else +# ifdef LIGHT_EDGES + obPos = pos; + vNor = nor; + forceEdge = float(force_edge); /* meh, could try to also encode it in facingOut */ +# endif +#else int v_0 = (gl_VertexID / 3) * 3; int v_n = gl_VertexID % 3; + /* Getting the same positions for each of the 3 verts. */ - ivec3 v_id; + uvec3 v_id; v_id.x = texelFetch(faceIds, v_0).r; v_id.y = texelFetch(faceIds, v_0 + 1).r; v_id.z = texelFetch(faceIds, v_0 + 2).r; - bvec3 do_edge = lessThan(v_id, ivec3(0)); - v_id = abs(v_id) - 1; + bvec3 do_edge, force_edge; + do_edge.x = (v_id.x & (1u << 30u)) != 0u; + do_edge.y = (v_id.y & (1u << 30u)) != 0u; + do_edge.z = (v_id.z & (1u << 30u)) != 0u; + force_edge.x = (v_id.x & (1u << 31u)) != 0u; + force_edge.y = (v_id.y & (1u << 31u)) != 0u; + force_edge.z = (v_id.z & (1u << 31u)) != 0u; + v_id = (v_id << 2u) >> 2u; vec3 pos[3]; pos[0] = get_vertex_pos(v_id.x); @@ -128,5 +154,22 @@ void main() vec3 nor = get_vertex_nor(v_id[v_n]); facing = normalize(NormalMatrix * nor).z; + +# ifdef LIGHT_EDGES + vec3 fnor = normalize(cross(pos[1] - pos[0], pos[2] - pos[0])); + edgeSharpness = get_edge_sharpness(fnor, nor); + + /* Fix disapearing edges. */ + if (v_n == 0) { + force_edge.xy = force_edge.xz; + } + else if (v_n == 2) { + force_edge.xy = force_edge.yz; + } + if (any(force_edge.xy)) { + edgeSharpness = 1.0; + } +# endif + #endif } diff --git a/source/blender/editors/animation/anim_channels_defines.c b/source/blender/editors/animation/anim_channels_defines.c index 5d5d8f10a88..e4213a8d907 100644 --- a/source/blender/editors/animation/anim_channels_defines.c +++ b/source/blender/editors/animation/anim_channels_defines.c @@ -65,6 +65,7 @@ #include "BKE_animsys.h" #include "BKE_curve.h" #include "BKE_key.h" +#include "BKE_main.h" #include "BKE_nla.h" #include "BKE_context.h" @@ -4144,6 +4145,7 @@ static void achannel_setting_slider_cb(bContext *C, void *id_poin, void *fcu_poi /* callback for shapekey widget sliders - insert keyframes */ static void achannel_setting_slider_shapekey_cb(bContext *C, void *key_poin, void *kb_poin) { + Main *bmain = CTX_data_main(C); Key *key = (Key *)key_poin; KeyBlock *kb = (KeyBlock *)kb_poin; char *rna_path = BKE_keyblock_curval_rnapath_get(key, kb); @@ -4171,7 +4173,7 @@ static void achannel_setting_slider_shapekey_cb(bContext *C, void *key_poin, voi if (RNA_path_resolve_property(&id_ptr, rna_path, &ptr, &prop)) { /* find or create new F-Curve */ // XXX is the group name for this ok? - bAction *act = verify_adt_action((ID *)key, 1); + bAction *act = verify_adt_action(bmain, (ID *)key, 1); FCurve *fcu = verify_fcurve(act, NULL, &ptr, rna_path, 0, 1); /* set the special 'replace' flag if on a keyframe */ diff --git a/source/blender/editors/animation/anim_deps.c b/source/blender/editors/animation/anim_deps.c index cfdbe87c8a1..adb5a10c19d 100644 --- a/source/blender/editors/animation/anim_deps.c +++ b/source/blender/editors/animation/anim_deps.c @@ -46,10 +46,10 @@ #include "BKE_animsys.h" #include "BKE_action.h" +#include "BKE_context.h" #include "BKE_fcurve.h" #include "BKE_gpencil.h" -#include "BKE_context.h" -#include "BKE_global.h" +#include "BKE_main.h" #include "BKE_node.h" #include "BKE_sequencer.h" @@ -64,7 +64,7 @@ /* tags the given anim list element for refreshes (if applicable) * due to Animation Editor editing */ -void ANIM_list_elem_update(Scene *scene, bAnimListElem *ale) +void ANIM_list_elem_update(Main *bmain, Scene *scene, bAnimListElem *ale) { ID *id; FCurve *fcu; @@ -97,7 +97,7 @@ void ANIM_list_elem_update(Scene *scene, bAnimListElem *ale) RNA_id_pointer_create(id, &id_ptr); if (RNA_path_resolve_property(&id_ptr, fcu->rna_path, &ptr, &prop)) - RNA_property_update_main(G.main, scene, &ptr, prop); + RNA_property_update_main(bmain, scene, &ptr, prop); } else { /* in other case we do standard depsgraph update, ideally @@ -406,7 +406,7 @@ void ANIM_animdata_update(bAnimContext *ac, ListBase *anim_data) if (ale->update & ANIM_UPDATE_DEPS) { ale->update &= ~ANIM_UPDATE_DEPS; - ANIM_list_elem_update(ac->scene, ale); + ANIM_list_elem_update(ac->bmain, ac->scene, ale); } } else if (ale->datatype == ALE_FCURVE) { @@ -426,13 +426,13 @@ void ANIM_animdata_update(bAnimContext *ac, ListBase *anim_data) if (ale->update & ANIM_UPDATE_DEPS) { ale->update &= ~ANIM_UPDATE_DEPS; - ANIM_list_elem_update(ac->scene, ale); + ANIM_list_elem_update(ac->bmain, ac->scene, ale); } } else if (ale->datatype == ALE_NLASTRIP) { if (ale->update & ANIM_UPDATE_DEPS) { ale->update &= ~ANIM_UPDATE_DEPS; - ANIM_list_elem_update(ac->scene, ale); + ANIM_list_elem_update(ac->bmain, ac->scene, ale); } } diff --git a/source/blender/editors/animation/anim_filter.c b/source/blender/editors/animation/anim_filter.c index 6f748725790..8892fed025a 100644 --- a/source/blender/editors/animation/anim_filter.c +++ b/source/blender/editors/animation/anim_filter.c @@ -378,6 +378,7 @@ bool ANIM_animdata_context_getdata(bAnimContext *ac) */ bool ANIM_animdata_get_context(const bContext *C, bAnimContext *ac) { + Main *bmain = CTX_data_main(C); ScrArea *sa = CTX_wm_area(C); ARegion *ar = CTX_wm_region(C); SpaceLink *sl = CTX_wm_space_data(C); @@ -388,6 +389,7 @@ bool ANIM_animdata_get_context(const bContext *C, bAnimContext *ac) memset(ac, 0, sizeof(bAnimContext)); /* get useful default context settings from context */ + ac->bmain = bmain; ac->scene = scene; if (scene) { ac->markers = ED_context_get_markers(C); @@ -1742,7 +1744,7 @@ static size_t animdata_filter_gpencil(bAnimContext *ac, ListBase *anim_data, voi bGPdata *gpd; /* Grab all Grease Pencil datablocks directly from main, but only those that seem to be useful somewhere */ - for (gpd = G.main->gpencil.first; gpd; gpd = gpd->id.next) { + for (gpd = ac->bmain->gpencil.first; gpd; gpd = gpd->id.next) { /* only show if gpd is used by something... */ if (ID_REAL_USERS(gpd) < 1) continue; @@ -1858,14 +1860,14 @@ static size_t animdata_filter_mask_data(ListBase *anim_data, Mask *mask, const i } /* Grab all mask data */ -static size_t animdata_filter_mask(ListBase *anim_data, void *UNUSED(data), int filter_mode) +static size_t animdata_filter_mask(Main *bmain, ListBase *anim_data, void *UNUSED(data), int filter_mode) { Mask *mask; size_t items = 0; /* for now, grab mask datablocks directly from main */ // XXX: this is not good... - for (mask = G.main->mask.first; mask; mask = mask->id.next) { + for (mask = bmain->mask.first; mask; mask = mask->id.next) { ListBase tmp_data = {NULL, NULL}; size_t tmp_items = 0; @@ -2820,7 +2822,7 @@ static size_t animdata_filter_dopesheet_movieclips(bAnimContext *ac, ListBase *a { size_t items = 0; MovieClip *clip; - for (clip = G.main->movieclip.first; clip != NULL; clip = clip->id.next) { + for (clip = ac->bmain->movieclip.first; clip != NULL; clip = clip->id.next) { /* only show if gpd is used by something... */ if (ID_REAL_USERS(clip) < 1) { continue; @@ -2959,7 +2961,7 @@ static size_t animdata_filter_dopesheet(bAnimContext *ac, ListBase *anim_data, b } /* Cache files level animations (frame duration and such). */ - CacheFile *cache_file = G.main->cachefiles.first; + CacheFile *cache_file = ac->bmain->cachefiles.first; for (; cache_file; cache_file = cache_file->id.next) { items += animdata_filter_ds_cachefile(ac, anim_data, ads, cache_file, filter_mode); } @@ -3223,7 +3225,7 @@ size_t ANIM_animdata_filter(bAnimContext *ac, ListBase *anim_data, eAnimFilter_F case ANIMCONT_MASK: { if (animdata_filter_dopesheet_summary(ac, anim_data, filter_mode, &items)) - items = animdata_filter_mask(anim_data, data, filter_mode); + items = animdata_filter_mask(ac->bmain, anim_data, data, filter_mode); break; } diff --git a/source/blender/editors/animation/keyframes_general.c b/source/blender/editors/animation/keyframes_general.c index f8af504f1ed..a6ed6643257 100644 --- a/source/blender/editors/animation/keyframes_general.c +++ b/source/blender/editors/animation/keyframes_general.c @@ -48,6 +48,7 @@ #include "BKE_fcurve.h" #include "BKE_report.h" #include "BKE_library.h" +#include "BKE_main.h" #include "BKE_global.h" #include "BKE_deform.h" @@ -729,7 +730,8 @@ static tAnimCopybufItem *pastebuf_match_path_full(FCurve *fcu, const short from_ } /* medium match strictness: path match only (i.e. ignore ID) */ -static tAnimCopybufItem *pastebuf_match_path_property(FCurve *fcu, const short from_single, const short UNUSED(to_simple)) +static tAnimCopybufItem *pastebuf_match_path_property( + Main *bmain, FCurve *fcu, const short from_single, const short UNUSED(to_simple)) { tAnimCopybufItem *aci; @@ -742,7 +744,7 @@ static tAnimCopybufItem *pastebuf_match_path_property(FCurve *fcu, const short f * resolve, or a bone could be renamed after copying for eg. but in normal copy & paste * this should work out ok. */ - if (BLI_findindex(which_libbase(G.main, aci->id_type), aci->id) == -1) { + if (BLI_findindex(which_libbase(bmain, aci->id_type), aci->id) == -1) { /* pedantic but the ID could have been removed, and beats crashing! */ printf("paste_animedit_keys: error ID has been removed!\n"); } @@ -996,7 +998,7 @@ short paste_animedit_keys(bAnimContext *ac, ListBase *anim_data, case 1: /* less strict, just compare property names */ - aci = pastebuf_match_path_property(fcu, from_single, to_simple); + aci = pastebuf_match_path_property(ac->bmain, fcu, from_single, to_simple); break; case 2: diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c index 25b3b4f58fa..1913eb944d9 100644 --- a/source/blender/editors/animation/keyframing.c +++ b/source/blender/editors/animation/keyframing.c @@ -53,17 +53,18 @@ #include "DNA_object_types.h" #include "DNA_rigidbody_types.h" -#include "BKE_animsys.h" #include "BKE_action.h" +#include "BKE_animsys.h" #include "BKE_armature.h" +#include "BKE_context.h" #include "BKE_fcurve.h" -#include "BKE_idcode.h" -#include "BKE_nla.h" #include "BKE_global.h" -#include "BKE_context.h" -#include "BKE_report.h" +#include "BKE_idcode.h" #include "BKE_key.h" +#include "BKE_main.h" #include "BKE_material.h" +#include "BKE_nla.h" +#include "BKE_report.h" #include "DEG_depsgraph.h" #include "DEG_depsgraph_build.h" @@ -126,7 +127,7 @@ short ANIM_get_keyframing_flags(Scene *scene, short incl_mode) /* Get (or add relevant data to be able to do so) the Active Action for the given * Animation Data block, given an ID block where the Animation Data should reside. */ -bAction *verify_adt_action(ID *id, short add) +bAction *verify_adt_action(Main *bmain, ID *id, short add) { AnimData *adt; @@ -148,7 +149,7 @@ bAction *verify_adt_action(ID *id, short add) BLI_snprintf(actname, sizeof(actname), "%sAction", id->name + 2); /* create action */ - adt->action = BKE_action_add(G.main, actname); + adt->action = BKE_action_add(bmain, actname); /* set ID-type from ID-block that this is going to be assigned to * so that users can't accidentally break actions by assigning them @@ -158,7 +159,7 @@ bAction *verify_adt_action(ID *id, short add) /* tag depsgraph to be rebuilt to include time dependency */ /* XXX: we probably should have bmain passed down, but that involves altering too many API's */ - DEG_relations_tag_update(G.main); + DEG_relations_tag_update(bmain); } DEG_id_tag_update(&adt->action->id, DEG_TAG_COPY_ON_WRITE); @@ -616,12 +617,14 @@ static short new_key_needed(FCurve *fcu, float cFrame, float nValue) /* ------------------ RNA Data-Access Functions ------------------ */ /* Try to read value using RNA-properties obtained already */ -static float setting_get_rna_value(Depsgraph *depsgraph, PointerRNA *ptr, PropertyRNA *prop, int index) +static float setting_get_rna_value(Depsgraph *depsgraph, PointerRNA *ptr, PropertyRNA *prop, int index, const bool get_evaluated) { - PointerRNA ptr_eval; + PointerRNA ptr_eval = *ptr; float value = 0.0f; - DEG_get_evaluated_rna_pointer(depsgraph, ptr, &ptr_eval); + if (get_evaluated) { + DEG_get_evaluated_rna_pointer(depsgraph, ptr, &ptr_eval); + } switch (RNA_property_type(prop)) { case PROP_BOOLEAN: @@ -847,7 +850,7 @@ static float visualkey_get_value(Depsgraph *depsgraph, PointerRNA *ptr, Property } } else { - return setting_get_rna_value(depsgraph, ptr, prop, array_index); + return setting_get_rna_value(depsgraph, ptr, prop, array_index, true); } /* Rot/Scale code are common! */ @@ -885,7 +888,7 @@ static float visualkey_get_value(Depsgraph *depsgraph, PointerRNA *ptr, Property } /* as the function hasn't returned yet, read value from system in the default way */ - return setting_get_rna_value(depsgraph, ptr, prop, array_index); + return setting_get_rna_value(depsgraph, ptr, prop, array_index, true); } /* ------------------------- Insert Key API ------------------------- */ @@ -970,7 +973,7 @@ bool insert_keyframe_direct(Depsgraph *depsgraph, ReportList *reports, PointerRN } else { /* read value from system */ - curval = setting_get_rna_value(depsgraph, &ptr, prop, fcu->array_index); + curval = setting_get_rna_value(depsgraph, &ptr, prop, fcu->array_index, false); } /* only insert keyframes where they are needed */ @@ -1019,7 +1022,9 @@ bool insert_keyframe_direct(Depsgraph *depsgraph, ReportList *reports, PointerRN * * index of -1 keys all array indices */ -short insert_keyframe(Depsgraph *depsgraph, ReportList *reports, ID *id, bAction *act, const char group[], const char rna_path[], int array_index, float cfra, eBezTriple_KeyframeType keytype, eInsertKeyFlags flag) +short insert_keyframe( + Main *bmain, Depsgraph *depsgraph, ReportList *reports, ID *id, bAction *act, + const char group[], const char rna_path[], int array_index, float cfra, eBezTriple_KeyframeType keytype, eInsertKeyFlags flag) { PointerRNA id_ptr, ptr; PropertyRNA *prop = NULL; @@ -1045,7 +1050,7 @@ short insert_keyframe(Depsgraph *depsgraph, ReportList *reports, ID *id, bAction /* if no action is provided, keyframe to the default one attached to this ID-block */ if (act == NULL) { /* get action to add F-Curve+keyframe to */ - act = verify_adt_action(id, 1); + act = verify_adt_action(bmain, id, 1); if (act == NULL) { BKE_reportf(reports, RPT_ERROR, @@ -1101,6 +1106,10 @@ short insert_keyframe(Depsgraph *depsgraph, ReportList *reports, ID *id, bAction } } + if (ret) { + DEG_id_tag_update(&adt->action->id, DEG_TAG_COPY_ON_WRITE); + } + return ret; } @@ -1771,6 +1780,7 @@ void ANIM_OT_keyframe_delete_v3d(wmOperatorType *ot) static int insert_key_button_exec(bContext *C, wmOperator *op) { Depsgraph *depsgraph = CTX_data_depsgraph(C); + Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); ToolSettings *ts = scene->toolsettings; PointerRNA ptr = {{NULL}}; @@ -1854,7 +1864,7 @@ static int insert_key_button_exec(bContext *C, wmOperator *op) index = -1; } - success = insert_keyframe(depsgraph, op->reports, ptr.id.data, NULL, group, path, index, cfra, ts->keyframe_type, flag); + success = insert_keyframe(bmain, depsgraph, op->reports, ptr.id.data, NULL, group, path, index, cfra, ts->keyframe_type, flag); MEM_freeN(path); } diff --git a/source/blender/editors/animation/keyingsets.c b/source/blender/editors/animation/keyingsets.c index c443c66d0f5..5bf23a53819 100644 --- a/source/blender/editors/animation/keyingsets.c +++ b/source/blender/editors/animation/keyingsets.c @@ -959,6 +959,7 @@ static short keyingset_apply_keying_flags(const short base_flags, const short ov int ANIM_apply_keyingset(bContext *C, ListBase *dsources, bAction *act, KeyingSet *ks, short mode, float cfra) { Depsgraph *depsgraph = CTX_data_depsgraph(C); + Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); ReportList *reports = CTX_wm_reports(C); KS_Path *ksp; @@ -1039,7 +1040,7 @@ int ANIM_apply_keyingset(bContext *C, ListBase *dsources, bAction *act, KeyingSe for (; i < arraylen; i++) { /* action to take depends on mode */ if (mode == MODIFYKEY_MODE_INSERT) - success += insert_keyframe(depsgraph, reports, ksp->id, act, groupname, ksp->rna_path, i, cfra, keytype, kflag2); + success += insert_keyframe(bmain, depsgraph, reports, ksp->id, act, groupname, ksp->rna_path, i, cfra, keytype, kflag2); else if (mode == MODIFYKEY_MODE_DELETE) success += delete_keyframe(reports, ksp->id, act, groupname, ksp->rna_path, i, cfra, kflag2); } @@ -1051,7 +1052,7 @@ int ANIM_apply_keyingset(bContext *C, ListBase *dsources, bAction *act, KeyingSe Object *ob = (Object *)ksp->id; // XXX: only object transforms? - DEG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); + DEG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA); break; } default: diff --git a/source/blender/editors/armature/armature_edit.c b/source/blender/editors/armature/armature_edit.c index 9fcf6ad4826..ccc1eefd9dc 100644 --- a/source/blender/editors/armature/armature_edit.c +++ b/source/blender/editors/armature/armature_edit.c @@ -50,6 +50,7 @@ #include "BKE_context.h" #include "BKE_layer.h" #include "BKE_global.h" +#include "BKE_main.h" #include "BKE_report.h" #include "BKE_object.h" @@ -68,7 +69,7 @@ /* ************************** Object Tools Exports ******************************* */ /* NOTE: these functions are exported to the Object module to be called from the tools there */ -void ED_armature_transform_apply(Object *ob, float mat[4][4], const bool do_props) +void ED_armature_transform_apply(Main *bmain, Object *ob, float mat[4][4], const bool do_props) { bArmature *arm = ob->data; @@ -79,7 +80,7 @@ void ED_armature_transform_apply(Object *ob, float mat[4][4], const bool do_prop ED_armature_transform_bones(arm, mat, do_props); /* Turn the list into an armature */ - ED_armature_from_edit(arm); + ED_armature_from_edit(bmain, arm); ED_armature_edit_free(arm); } @@ -120,7 +121,7 @@ void ED_armature_transform_bones(struct bArmature *arm, float mat[4][4], const b } } -void ED_armature_transform(struct bArmature *arm, float mat[4][4], const bool do_props) +void ED_armature_transform(Main *bmain, bArmature *arm, float mat[4][4], const bool do_props) { if (arm->edbo) { ED_armature_transform_bones(arm, mat, do_props); @@ -133,14 +134,14 @@ void ED_armature_transform(struct bArmature *arm, float mat[4][4], const bool do ED_armature_transform_bones(arm, mat, do_props); /* Go back to object mode*/ - ED_armature_from_edit(arm); + ED_armature_from_edit(bmain, arm); ED_armature_edit_free(arm); } } /* exported for use in editors/object/ */ /* 0 == do center, 1 == center new, 2 == center cursor */ -void ED_armature_origin_set(Object *ob, float cursor[3], int centermode, int around) +void ED_armature_origin_set(Main *bmain, Object *ob, float cursor[3], int centermode, int around) { const bool is_editmode = BKE_object_is_in_editmode(ob); EditBone *ebone; @@ -190,7 +191,7 @@ void ED_armature_origin_set(Object *ob, float cursor[3], int centermode, int aro /* Turn the list into an armature */ if (is_editmode == false) { - ED_armature_from_edit(arm); + ED_armature_from_edit(bmain, arm); ED_armature_edit_free(arm); } diff --git a/source/blender/editors/armature/armature_naming.c b/source/blender/editors/armature/armature_naming.c index 1a5e9e38099..a73e64af0ee 100644 --- a/source/blender/editors/armature/armature_naming.c +++ b/source/blender/editors/armature/armature_naming.c @@ -137,7 +137,7 @@ static void constraint_bone_name_fix(Object *ob, ListBase *conlist, const char * /* called by UI for renaming a bone */ /* warning: make sure the original bone was not renamed yet! */ /* seems messy, but thats what you get with not using pointers but channel names :) */ -void ED_armature_bone_rename(bArmature *arm, const char *oldnamep, const char *newnamep) +void ED_armature_bone_rename(Main *bmain, bArmature *arm, const char *oldnamep, const char *newnamep) { Object *ob; char newname[MAXBONENAME]; @@ -176,7 +176,7 @@ void ED_armature_bone_rename(bArmature *arm, const char *oldnamep, const char *n } /* do entire dbase - objects */ - for (ob = G.main->object.first; ob; ob = ob->id.next) { + for (ob = bmain->object.first; ob; ob = ob->id.next) { ModifierData *md; /* we have the object using the armature */ @@ -206,7 +206,7 @@ void ED_armature_bone_rename(bArmature *arm, const char *oldnamep, const char *n } /* Update any object constraints to use the new bone name */ - for (cob = G.main->object.first; cob; cob = cob->id.next) { + for (cob = bmain->object.first; cob; cob = cob->id.next) { if (cob->constraints.first) constraint_bone_name_fix(ob, &cob->constraints, oldname, newname); if (cob->pose) { @@ -279,7 +279,7 @@ void ED_armature_bone_rename(bArmature *arm, const char *oldnamep, const char *n /* correct view locking */ { bScreen *screen; - for (screen = G.main->screen.first; screen; screen = screen->id.next) { + for (screen = bmain->screen.first; screen; screen = screen->id.next) { ScrArea *sa; /* add regions */ for (sa = screen->areabase.first; sa; sa = sa->next) { @@ -316,7 +316,7 @@ typedef struct BoneFlipNameData { * \param bones_names: List of BoneConflict elems. * \param do_strip_numbers: if set, try to get rid of dot-numbers at end of bone names. */ -void ED_armature_bones_flip_names(bArmature *arm, ListBase *bones_names, const bool do_strip_numbers) +void ED_armature_bones_flip_names(Main *bmain, bArmature *arm, ListBase *bones_names, const bool do_strip_numbers) { ListBase bones_names_conflicts = {NULL}; BoneFlipNameData *bfn; @@ -332,7 +332,7 @@ void ED_armature_bones_flip_names(bArmature *arm, ListBase *bones_names, const b * Bone.R, Bone.R.001, Bone.R.002, etc. */ BLI_string_flip_side_name(name_flip, name, do_strip_numbers, sizeof(name_flip)); - ED_armature_bone_rename(arm, name, name_flip); + ED_armature_bone_rename(bmain, arm, name, name_flip); if (!STREQ(name, name_flip)) { bfn = alloca(sizeof(BoneFlipNameData)); @@ -346,7 +346,7 @@ void ED_armature_bones_flip_names(bArmature *arm, ListBase *bones_names, const b * Note that if the other bone was not selected, its name was not flipped, so conflict remains and that second * rename simply generates a new numbered alternative name. */ for (bfn = bones_names_conflicts.first; bfn; bfn = bfn->next) { - ED_armature_bone_rename(arm, bfn->name, bfn->name_flip); + ED_armature_bone_rename(bmain, arm, bfn->name, bfn->name_flip); } } @@ -355,6 +355,7 @@ void ED_armature_bones_flip_names(bArmature *arm, ListBase *bones_names, const b static int armature_flip_names_exec(bContext *C, wmOperator *op) { + Main *bmain = CTX_data_main(C); Object *ob = CTX_data_edit_object(C); bArmature *arm; @@ -374,7 +375,7 @@ static int armature_flip_names_exec(bContext *C, wmOperator *op) } CTX_DATA_END; - ED_armature_bones_flip_names(arm, &bones_names, do_strip_numbers); + ED_armature_bones_flip_names(bmain, arm, &bones_names, do_strip_numbers); BLI_freelistN(&bones_names); @@ -413,6 +414,7 @@ void ARMATURE_OT_flip_names(wmOperatorType *ot) static int armature_autoside_names_exec(bContext *C, wmOperator *op) { + Main *bmain = CTX_data_main(C); Object *ob = CTX_data_edit_object(C); bArmature *arm; char newname[MAXBONENAME]; @@ -428,7 +430,7 @@ static int armature_autoside_names_exec(bContext *C, wmOperator *op) { BLI_strncpy(newname, ebone->name, sizeof(newname)); if (bone_autoside_name(newname, 1, axis, ebone->head[axis], ebone->tail[axis])) - ED_armature_bone_rename(arm, ebone->name, newname); + ED_armature_bone_rename(bmain, arm, ebone->name, newname); } CTX_DATA_END; diff --git a/source/blender/editors/armature/armature_relations.c b/source/blender/editors/armature/armature_relations.c index 5d6c383b24b..9282148e857 100644 --- a/source/blender/editors/armature/armature_relations.c +++ b/source/blender/editors/armature/armature_relations.c @@ -400,7 +400,7 @@ int join_armature_exec(bContext *C, wmOperator *op) DEG_relations_tag_update(bmain); /* because we removed object(s) */ - ED_armature_from_edit(arm); + ED_armature_from_edit(bmain, arm); ED_armature_edit_free(arm); WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene); @@ -411,7 +411,7 @@ int join_armature_exec(bContext *C, wmOperator *op) /* *********************************** Separate *********************************************** */ /* Helper function for armature separating - link fixing */ -static void separated_armature_fix_links(Object *origArm, Object *newArm) +static void separated_armature_fix_links(Main *bmain, Object *origArm, Object *newArm) { Object *ob; bPoseChannel *pchan; @@ -423,7 +423,7 @@ static void separated_armature_fix_links(Object *origArm, Object *newArm) npchans = &newArm->pose->chanbase; /* let's go through all objects in database */ - for (ob = G.main->object.first; ob; ob = ob->id.next) { + for (ob = bmain->object.first; ob; ob = ob->id.next) { /* do some object-type specific things */ if (ob->type == OB_ARMATURE) { for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { @@ -516,7 +516,7 @@ static void separated_armature_fix_links(Object *origArm, Object *newArm) * sel: remove selected bones from the armature, otherwise the unselected bones are removed * (ob is not in editmode) */ -static void separate_armature_bones(Object *ob, short sel) +static void separate_armature_bones(Main *bmain, Object *ob, short sel) { bArmature *arm = (bArmature *)ob->data; bPoseChannel *pchan, *pchann; @@ -563,7 +563,7 @@ static void separate_armature_bones(Object *ob, short sel) } /* exit editmode (recalculates pchans too) */ - ED_armature_from_edit(ob->data); + ED_armature_from_edit(bmain, ob->data); ED_armature_edit_free(ob->data); } @@ -611,7 +611,7 @@ static int separate_armature_exec(bContext *C, wmOperator *op) oldob->mode &= ~OB_MODE_POSE; //oldbase->flag &= ~OB_POSEMODE; - ED_armature_from_edit(obedit->data); + ED_armature_from_edit(bmain, obedit->data); ED_armature_edit_free(obedit->data); /* 2) duplicate base */ @@ -623,12 +623,12 @@ static int separate_armature_exec(bContext *C, wmOperator *op) /* 3) remove bones that shouldn't still be around on both armatures */ - separate_armature_bones(oldob, 1); - separate_armature_bones(newob, 0); + separate_armature_bones(bmain, oldob, 1); + separate_armature_bones(bmain, newob, 0); /* 4) fix links before depsgraph flushes */ // err... or after? - separated_armature_fix_links(oldob, newob); + separated_armature_fix_links(bmain, oldob, newob); DEG_id_tag_update(&oldob->id, OB_RECALC_DATA); /* this is the original one */ DEG_id_tag_update(&newob->id, OB_RECALC_DATA); /* this is the separated one */ diff --git a/source/blender/editors/armature/armature_skinning.c b/source/blender/editors/armature/armature_skinning.c index 463e00957e6..87a66514417 100644 --- a/source/blender/editors/armature/armature_skinning.c +++ b/source/blender/editors/armature/armature_skinning.c @@ -45,6 +45,7 @@ #include "BKE_armature.h" #include "BKE_context.h" #include "BKE_deform.h" +#include "BKE_mesh_runtime.h" #include "BKE_object_deform.h" #include "BKE_report.h" #include "BKE_subsurf.h" diff --git a/source/blender/editors/armature/armature_utils.c b/source/blender/editors/armature/armature_utils.c index a8116ce26cf..02d45a4e041 100644 --- a/source/blender/editors/armature/armature_utils.c +++ b/source/blender/editors/armature/armature_utils.c @@ -585,7 +585,7 @@ static void armature_finalize_restpose(ListBase *bonelist, ListBase *editbonelis } /* put EditMode back in Object */ -void ED_armature_from_edit(bArmature *arm) +void ED_armature_from_edit(Main *bmain, bArmature *arm) { EditBone *eBone, *neBone; Bone *newBone; @@ -679,7 +679,7 @@ void ED_armature_from_edit(bArmature *arm) armature_finalize_restpose(&arm->bonebase, arm->edbo); /* so all users of this armature should get rebuilt */ - for (obt = G.main->object.first; obt; obt = obt->id.next) { + for (obt = bmain->object.first; obt; obt = obt->id.next) { if (obt->data == arm) { BKE_pose_rebuild(obt, arm); } diff --git a/source/blender/editors/armature/editarmature_retarget.c b/source/blender/editors/armature/editarmature_retarget.c new file mode 100644 index 00000000000..b74b515b37f --- /dev/null +++ b/source/blender/editors/armature/editarmature_retarget.c @@ -0,0 +1,2644 @@ +/* + * ***** 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. + * + * Contributor(s): Martin Poirier + * + * ***** END GPL LICENSE BLOCK ***** + * autoarmature.c: Interface for automagically manipulating armature (retarget, created, ...) + */ + +/** \file blender/editors/armature/editarmature_retarget.c + * \ingroup edarmature + */ + +#include "MEM_guardedalloc.h" + +#include "PIL_time.h" + +#include "DNA_armature_types.h" +#include "DNA_constraint_types.h" +#include "DNA_scene_types.h" +#include "DNA_object_types.h" + +#include "BLI_blenlib.h" +#include "BLI_math.h" + +#include "BKE_constraint.h" +#include "BKE_armature.h" +#include "BKE_context.h" +#include "BKE_main.h" + +#include "ED_armature.h" +#include "ED_undo.h" + +#include "BIF_retarget.h" + +#include "armature_intern.h" + +/************ RIG RETARGET DATA STRUCTURES ***************/ + +typedef struct MemoNode { + float weight; + int next; +} MemoNode; + +typedef struct RetargetParam { + RigGraph *rigg; + RigArc *iarc; + RigNode *inode_start; + bContext *context; +} RetargetParam; + +typedef enum { + RETARGET_LENGTH, + RETARGET_AGGRESSIVE +} RetargetMode; + +typedef enum { + METHOD_BRUTE_FORCE = 0, + METHOD_MEMOIZE = 1 +} RetargetMethod; + +typedef enum { + ARC_FREE = 0, + ARC_TAKEN = 1, + ARC_USED = 2 +} ArcUsageFlags; + +static RigGraph *GLOBAL_RIGG = NULL; + +/*******************************************************************************************************/ + +void exec_retargetArctoArc(TaskPool * __restrict pool, void *taskdata, int threadid); + +static void RIG_calculateEdgeAngles(RigEdge *edge_first, RigEdge *edge_second); +float rollBoneByQuat(EditBone *bone, float old_up_axis[3], float qrot[4]); + +/* two levels */ +#define SHAPE_LEVELS (SHAPE_RADIX * SHAPE_RADIX) + +/*********************************** EDITBONE UTILS ****************************************************/ + +static int countEditBoneChildren(ListBase *list, EditBone *parent) +{ + EditBone *ebone; + int count = 0; + + for (ebone = list->first; ebone; ebone = ebone->next) { + if (ebone->parent == parent) { + count++; + } + } + + return count; +} + +static EditBone *nextEditBoneChild(ListBase *list, EditBone *parent, int n) +{ + EditBone *ebone; + + for (ebone = list->first; ebone; ebone = ebone->next) { + if (ebone->parent == parent) { + if (n == 0) { + return ebone; + } + n--; + } + } + + return NULL; +} + +static void getEditBoneRollUpAxis(EditBone *bone, float roll, float up_axis[3]) +{ + float mat[3][3], nor[3]; + + sub_v3_v3v3(nor, bone->tail, bone->head); + + vec_roll_to_mat3(nor, roll, mat); + copy_v3_v3(up_axis, mat[2]); +} + +static float rollBoneByQuatAligned(EditBone *bone, float old_up_axis[3], float qrot[4], float qroll[4], float aligned_axis[3]) +{ + float nor[3], new_up_axis[3], x_axis[3], z_axis[3]; + + copy_v3_v3(new_up_axis, old_up_axis); + mul_qt_v3(qrot, new_up_axis); + + sub_v3_v3v3(nor, bone->tail, bone->head); + + cross_v3_v3v3(x_axis, nor, aligned_axis); + cross_v3_v3v3(z_axis, x_axis, nor); + + normalize_v3(new_up_axis); + normalize_v3(x_axis); + normalize_v3(z_axis); + + if (dot_v3v3(new_up_axis, x_axis) < 0) { + negate_v3(x_axis); + } + + if (dot_v3v3(new_up_axis, z_axis) < 0) { + negate_v3(z_axis); + } + + if (angle_normalized_v3v3(x_axis, new_up_axis) < angle_normalized_v3v3(z_axis, new_up_axis)) { + rotation_between_vecs_to_quat(qroll, new_up_axis, x_axis); /* set roll rotation quat */ + return ED_armature_ebone_roll_to_vector(bone, x_axis, false); + } + else { + rotation_between_vecs_to_quat(qroll, new_up_axis, z_axis); /* set roll rotation quat */ + return ED_armature_ebone_roll_to_vector(bone, z_axis, false); + } +} + +static float rollBoneByQuatJoint(RigEdge *edge, RigEdge *previous, float qrot[4], float qroll[4], float up_axis[3]) +{ + if (previous == NULL) { + /* default to up_axis if no previous */ + return rollBoneByQuatAligned(edge->bone, edge->up_axis, qrot, qroll, up_axis); + } + else { + float new_up_axis[3]; + float vec_first[3], vec_second[3], normal[3]; + + if (previous->bone) { + sub_v3_v3v3(vec_first, previous->bone->tail, previous->bone->head); + } + else if (previous->prev->bone) { + sub_v3_v3v3(vec_first, edge->bone->head, previous->prev->bone->tail); + } + else { + /* default to up_axis if first bone in the chain is an offset */ + return rollBoneByQuatAligned(edge->bone, edge->up_axis, qrot, qroll, up_axis); + } + + sub_v3_v3v3(vec_second, edge->bone->tail, edge->bone->head); + + normalize_v3(vec_first); + normalize_v3(vec_second); + + cross_v3_v3v3(normal, vec_first, vec_second); + normalize_v3(normal); + + axis_angle_to_quat(qroll, vec_second, edge->up_angle); + + mul_qt_v3(qroll, normal); + + copy_v3_v3(new_up_axis, edge->up_axis); + mul_qt_v3(qrot, new_up_axis); + + normalize_v3(new_up_axis); + + /* real qroll between normal and up_axis */ + rotation_between_vecs_to_quat(qroll, new_up_axis, normal); + + return ED_armature_ebone_roll_to_vector(edge->bone, normal, false); + } +} + +float rollBoneByQuat(EditBone *bone, float old_up_axis[3], float qrot[4]) +{ + float new_up_axis[3]; + + copy_v3_v3(new_up_axis, old_up_axis); + mul_qt_v3(qrot, new_up_axis); + + return ED_armature_ebone_roll_to_vector(bone, new_up_axis, false); +} + +/************************************ DESTRUCTORS ******************************************************/ + +static void RIG_freeRigArc(BArc *arc) +{ + BLI_freelistN(&((RigArc *)arc)->edges); +} + +void RIG_freeRigGraph(BGraph *rg) +{ + RigGraph *rigg = (RigGraph *)rg; + BNode *node; + BArc *arc; + + BLI_task_pool_free(rigg->task_pool); + BLI_task_scheduler_free(rigg->task_scheduler); + + if (rigg->link_mesh) { + REEB_freeGraph(rigg->link_mesh); + } + + for (arc = rg->arcs.first; arc; arc = arc->next) { + RIG_freeRigArc(arc); + } + BLI_freelistN(&rg->arcs); + + for (node = rg->nodes.first; node; node = node->next) { + BLI_freeNode(rg, (BNode *)node); + } + BLI_freelistN(&rg->nodes); + + BLI_freelistN(&rigg->controls); + + BLI_ghash_free(rigg->bones_map, NULL, NULL); + BLI_ghash_free(rigg->controls_map, NULL, NULL); + + if (rigg->flag & RIG_FREE_BONELIST) { + BLI_freelistN(rigg->editbones); + MEM_freeN(rigg->editbones); + } + + MEM_freeN(rg); +} + +/************************************* ALLOCATORS ******************************************************/ + +static RigGraph *newRigGraph(void) +{ + RigGraph *rg; + int totthread; + + rg = MEM_callocN(sizeof(RigGraph), "rig graph"); + + rg->head = NULL; + + rg->bones_map = BLI_ghash_str_new("newRigGraph bones gh"); + rg->controls_map = BLI_ghash_str_new("newRigGraph cont gh"); + + rg->free_arc = RIG_freeRigArc; + rg->free_node = NULL; + +#ifdef USE_THREADS + totthread = TASK_SCHEDULER_AUTO_THREADS; +#else + totthread = TASK_SCHEDULER_SINGLE_THREAD; +#endif + + rg->task_scheduler = BLI_task_scheduler_create(totthread); + rg->task_pool = BLI_task_pool_create(rg->task_scheduler, NULL); + + return rg; +} + +static RigArc *newRigArc(RigGraph *rg) +{ + RigArc *arc; + + arc = MEM_callocN(sizeof(RigArc), "rig arc"); + arc->count = 0; + BLI_addtail(&rg->arcs, arc); + + return arc; +} + +static RigControl *newRigControl(RigGraph *rg) +{ + RigControl *ctrl; + + ctrl = MEM_callocN(sizeof(RigControl), "rig control"); + + BLI_addtail(&rg->controls, ctrl); + + return ctrl; +} + +static RigNode *newRigNodeHead(RigGraph *rg, RigArc *arc, float p[3]) +{ + RigNode *node; + node = MEM_callocN(sizeof(RigNode), "rig node"); + BLI_addtail(&rg->nodes, node); + + copy_v3_v3(node->p, p); + node->degree = 1; + node->arcs = NULL; + + arc->head = node; + + return node; +} + +static void addRigNodeHead(RigGraph *UNUSED(rg), RigArc *arc, RigNode *node) +{ + node->degree++; + + arc->head = node; +} + +static RigNode *newRigNode(RigGraph *rg, float p[3]) +{ + RigNode *node; + node = MEM_callocN(sizeof(RigNode), "rig node"); + BLI_addtail(&rg->nodes, node); + + copy_v3_v3(node->p, p); + node->degree = 0; + node->arcs = NULL; + + return node; +} + +static RigNode *newRigNodeTail(RigGraph *rg, RigArc *arc, float p[3]) +{ + RigNode *node = newRigNode(rg, p); + + node->degree = 1; + arc->tail = node; + + return node; +} + +static void RIG_appendEdgeToArc(RigArc *arc, RigEdge *edge) +{ + BLI_addtail(&arc->edges, edge); + + if (edge->prev == NULL) { + copy_v3_v3(edge->head, arc->head->p); + } + else { + RigEdge *last_edge = edge->prev; + copy_v3_v3(edge->head, last_edge->tail); + RIG_calculateEdgeAngles(last_edge, edge); + } + + edge->length = len_v3v3(edge->head, edge->tail); + + arc->length += edge->length; + + arc->count += 1; +} + +static void RIG_addEdgeToArc(RigArc *arc, float tail[3], EditBone *bone) +{ + RigEdge *edge; + + edge = MEM_callocN(sizeof(RigEdge), "rig edge"); + + copy_v3_v3(edge->tail, tail); + edge->bone = bone; + + if (bone) { + getEditBoneRollUpAxis(bone, bone->roll, edge->up_axis); + } + + RIG_appendEdgeToArc(arc, edge); +} +/************************************** CLONING TEMPLATES **********************************************/ + +static void renameTemplateBone(char *name, char *template_name, ListBase *editbones, char *side_string, char *num_string) +{ + int i, j; + + for (i = 0, j = 0; i < (MAXBONENAME - 1) && j < (MAXBONENAME - 1) && template_name[i] != '\0'; i++) { + if (template_name[i] == '&') { + if (template_name[i + 1] == 'S' || template_name[i + 1] == 's') { + j += BLI_strncpy_rlen(name + j, side_string, MAXBONENAME); + i++; + } + else if (template_name[i + 1] == 'N' || template_name[i + 1] == 'n') { + j += BLI_strncpy_rlen(name + j, num_string, MAXBONENAME); + i++; + } + else { + name[j] = template_name[i]; + j++; + } + } + else { + name[j] = template_name[i]; + j++; + } + } + + name[j] = '\0'; + + ED_armature_ebone_unique_name(editbones, name, NULL); +} + +static RigControl *cloneControl(RigGraph *rg, RigGraph *src_rg, RigControl *src_ctrl, GHash *ptr_hash, char *side_string, char *num_string) +{ + RigControl *ctrl; + char name[MAXBONENAME]; + + ctrl = newRigControl(rg); + + copy_v3_v3(ctrl->head, src_ctrl->head); + copy_v3_v3(ctrl->tail, src_ctrl->tail); + copy_v3_v3(ctrl->up_axis, src_ctrl->up_axis); + copy_v3_v3(ctrl->offset, src_ctrl->offset); + + ctrl->tail_mode = src_ctrl->tail_mode; + ctrl->flag = src_ctrl->flag; + + renameTemplateBone(name, src_ctrl->bone->name, rg->editbones, side_string, num_string); + ctrl->bone = duplicateEditBoneObjects(src_ctrl->bone, name, rg->editbones, src_rg->ob, rg->ob); + ctrl->bone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL); + BLI_ghash_insert(ptr_hash, src_ctrl->bone, ctrl->bone); + + ctrl->link = src_ctrl->link; + ctrl->link_tail = src_ctrl->link_tail; + + return ctrl; +} + +static RigArc *cloneArc(RigGraph *rg, RigGraph *src_rg, RigArc *src_arc, GHash *ptr_hash, char *side_string, char *num_string) +{ + RigEdge *src_edge; + RigArc *arc; + + arc = newRigArc(rg); + + arc->head = BLI_ghash_lookup(ptr_hash, src_arc->head); + arc->tail = BLI_ghash_lookup(ptr_hash, src_arc->tail); + + arc->head->degree++; + arc->tail->degree++; + + arc->length = src_arc->length; + + arc->count = src_arc->count; + + for (src_edge = src_arc->edges.first; src_edge; src_edge = src_edge->next) { + RigEdge *edge; + + edge = MEM_callocN(sizeof(RigEdge), "rig edge"); + + copy_v3_v3(edge->head, src_edge->head); + copy_v3_v3(edge->tail, src_edge->tail); + copy_v3_v3(edge->up_axis, src_edge->up_axis); + + edge->length = src_edge->length; + edge->angle = src_edge->angle; + edge->up_angle = src_edge->up_angle; + + if (src_edge->bone != NULL) { + char name[MAXBONENAME]; + renameTemplateBone(name, src_edge->bone->name, rg->editbones, side_string, num_string); + edge->bone = duplicateEditBoneObjects(src_edge->bone, name, rg->editbones, src_rg->ob, rg->ob); + edge->bone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL); + BLI_ghash_insert(ptr_hash, src_edge->bone, edge->bone); + } + + BLI_addtail(&arc->edges, edge); + } + + return arc; +} + +static RigGraph *cloneRigGraph(RigGraph *src, ListBase *editbones, Object *ob, char *side_string, char *num_string) +{ + GHash *ptr_hash; + RigNode *node; + RigArc *arc; + RigControl *ctrl; + RigGraph *rg; + + ptr_hash = BLI_ghash_ptr_new("cloneRigGraph gh"); + + rg = newRigGraph(); + + rg->ob = ob; + rg->editbones = editbones; + + preEditBoneDuplicate(rg->editbones); /* prime bones for duplication */ + preEditBoneDuplicate(src->editbones); /* prime bones for duplication */ + + /* Clone nodes */ + for (node = src->nodes.first; node; node = node->next) { + RigNode *cloned_node = newRigNode(rg, node->p); + BLI_ghash_insert(ptr_hash, node, cloned_node); + } + + rg->head = BLI_ghash_lookup(ptr_hash, src->head); + + /* Clone arcs */ + for (arc = src->arcs.first; arc; arc = arc->next) { + cloneArc(rg, src, arc, ptr_hash, side_string, num_string); + } + + /* Clone controls */ + for (ctrl = src->controls.first; ctrl; ctrl = ctrl->next) { + cloneControl(rg, src, ctrl, ptr_hash, side_string, num_string); + } + + /* Relink bones properly */ + for (arc = rg->arcs.first; arc; arc = arc->next) { + RigEdge *edge; + + for (edge = arc->edges.first; edge; edge = edge->next) { + if (edge->bone != NULL) { + EditBone *bone; + + updateDuplicateSubtargetObjects(edge->bone, src->editbones, src->ob, rg->ob); + + if (edge->bone->parent) { + bone = BLI_ghash_lookup(ptr_hash, edge->bone->parent); + + if (bone != NULL) { + edge->bone->parent = bone; + } + else { + /* disconnect since parent isn't cloned + * this will only happen when cloning from selected bones + * */ + edge->bone->flag &= ~BONE_CONNECTED; + } + } + } + } + } + + for (ctrl = rg->controls.first; ctrl; ctrl = ctrl->next) { + EditBone *bone; + + updateDuplicateSubtargetObjects(ctrl->bone, src->editbones, src->ob, rg->ob); + + if (ctrl->bone->parent) { + bone = BLI_ghash_lookup(ptr_hash, ctrl->bone->parent); + + if (bone != NULL) { + ctrl->bone->parent = bone; + } + else { + /* disconnect since parent isn't cloned + * this will only happen when cloning from selected bones + * */ + ctrl->bone->flag &= ~BONE_CONNECTED; + } + } + + ctrl->link = BLI_ghash_lookup(ptr_hash, ctrl->link); + ctrl->link_tail = BLI_ghash_lookup(ptr_hash, ctrl->link_tail); + } + + BLI_ghash_free(ptr_hash, NULL, NULL); + + return rg; +} + + +/*******************************************************************************************************/ + +static void RIG_calculateEdgeAngles(RigEdge *edge_first, RigEdge *edge_second) +{ + float vec_first[3], vec_second[3]; + + sub_v3_v3v3(vec_first, edge_first->tail, edge_first->head); + sub_v3_v3v3(vec_second, edge_second->tail, edge_second->head); + + normalize_v3(vec_first); + normalize_v3(vec_second); + + edge_first->angle = angle_normalized_v3v3(vec_first, vec_second); + + if (edge_second->bone != NULL) { + float normal[3]; + + cross_v3_v3v3(normal, vec_first, vec_second); + normalize_v3(normal); + + edge_second->up_angle = angle_normalized_v3v3(normal, edge_second->up_axis); + } +} + +/************************************ CONTROL BONES ****************************************************/ + +static void RIG_addControlBone(RigGraph *rg, EditBone *bone) +{ + RigControl *ctrl = newRigControl(rg); + ctrl->bone = bone; + copy_v3_v3(ctrl->head, bone->head); + copy_v3_v3(ctrl->tail, bone->tail); + getEditBoneRollUpAxis(bone, bone->roll, ctrl->up_axis); + ctrl->tail_mode = TL_NONE; + + BLI_ghash_insert(rg->controls_map, bone->name, ctrl); +} + +static int RIG_parentControl(RigControl *ctrl, EditBone *link) +{ + if (link) { + float offset[3]; + int flag = 0; + + sub_v3_v3v3(offset, ctrl->bone->head, link->head); + + /* if root matches, check for direction too */ + if (dot_v3v3(offset, offset) < 0.0001f) { + float vbone[3], vparent[3]; + + flag |= RIG_CTRL_FIT_ROOT; + + sub_v3_v3v3(vbone, ctrl->bone->tail, ctrl->bone->head); + sub_v3_v3v3(vparent, link->tail, link->head); + + /* test for opposite direction */ + if (dot_v3v3(vbone, vparent) > 0) { + float nor[3]; + float len; + + cross_v3_v3v3(nor, vbone, vparent); + + len = dot_v3v3(nor, nor); + if (len < 0.0001f) { + flag |= RIG_CTRL_FIT_BONE; + } + } + } + + /* Bail out if old one is automatically better */ + if (flag < ctrl->flag) { + return 0; + } + + /* if there's already a link + * overwrite only if new link is higher in the chain */ + if (ctrl->link && flag == ctrl->flag) { + EditBone *bone = NULL; + + for (bone = ctrl->link; bone; bone = bone->parent) { + /* if link is in the chain, break and use that one */ + if (bone == link) { + break; + } + } + + /* not in chain, don't update link */ + if (bone == NULL) { + return 0; + } + } + + + ctrl->link = link; + ctrl->flag = flag; + + copy_v3_v3(ctrl->offset, offset); + + return 1; + } + + return 0; +} + +static void RIG_reconnectControlBones(RigGraph *rg) +{ + RigControl *ctrl; + bool changed = true; + + /* first pass, link to deform bones */ + for (ctrl = rg->controls.first; ctrl; ctrl = ctrl->next) { + bPoseChannel *pchan; + bConstraint *con; + int found = 0; + + /* DO SOME MAGIC HERE */ + for (pchan = rg->ob->pose->chanbase.first; pchan; pchan = pchan->next) { + for (con = pchan->constraints.first; con; con = con->next) { + const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); + ListBase targets = {NULL, NULL}; + bConstraintTarget *ct; + + /* constraint targets */ + if (cti && cti->get_constraint_targets) { + int target_index; + + cti->get_constraint_targets(con, &targets); + + for (target_index = 0, ct = targets.first; ct; target_index++, ct = ct->next) { + if ((ct->tar == rg->ob) && STREQ(ct->subtarget, ctrl->bone->name)) { + /* SET bone link to bone corresponding to pchan */ + EditBone *link = BLI_ghash_lookup(rg->bones_map, pchan->name); + + /* Making sure bone is in this armature */ + if (link != NULL) { + /* for pole targets, link to parent bone instead, if possible */ + if (con->type == CONSTRAINT_TYPE_KINEMATIC && target_index == 1) { + if (link->parent && BLI_ghash_haskey(rg->bones_map, link->parent->name)) { + link = link->parent; + } + } + + found = RIG_parentControl(ctrl, link); + } + } + } + + if (cti->flush_constraint_targets) + cti->flush_constraint_targets(con, &targets, 0); + } + } + } + + /* if not found yet, check parent */ + if (found == 0) { + if (ctrl->bone->parent) { + /* make sure parent is a deforming bone + * NULL if not + * */ + EditBone *link = BLI_ghash_lookup(rg->bones_map, ctrl->bone->parent->name); + + found = RIG_parentControl(ctrl, link); + } + + /* check if bone is not superposed on another one */ + { + RigArc *arc; + RigArc *best_arc = NULL; + EditBone *link = NULL; + + for (arc = rg->arcs.first; arc; arc = arc->next) { + RigEdge *edge; + for (edge = arc->edges.first; edge; edge = edge->next) { + if (edge->bone) { + int fit = 0; + + fit = len_v3v3(ctrl->bone->head, edge->bone->head) < 0.0001f; + fit = fit || len_v3v3(ctrl->bone->tail, edge->bone->tail) < 0.0001f; + + if (fit) { + /* pick the bone on the arc with the lowest symmetry level + * means you connect control to the trunk of the skeleton */ + if (best_arc == NULL || arc->symmetry_level < best_arc->symmetry_level) { + best_arc = arc; + link = edge->bone; + } + } + } + } + } + + found = RIG_parentControl(ctrl, link); + } + } + + /* if not found yet, check child */ + if (found == 0) { + RigArc *arc; + RigArc *best_arc = NULL; + EditBone *link = NULL; + + for (arc = rg->arcs.first; arc; arc = arc->next) { + RigEdge *edge; + for (edge = arc->edges.first; edge; edge = edge->next) { + if (edge->bone && edge->bone->parent == ctrl->bone) { + /* pick the bone on the arc with the lowest symmetry level + * means you connect control to the trunk of the skeleton */ + if (best_arc == NULL || arc->symmetry_level < best_arc->symmetry_level) { + best_arc = arc; + link = edge->bone; + } + } + } + } + + found = RIG_parentControl(ctrl, link); + } + + } + + + /* second pass, make chains in control bones */ + while (changed) { + changed = false; + + for (ctrl = rg->controls.first; ctrl; ctrl = ctrl->next) { + /* if control is not linked yet */ + if (ctrl->link == NULL) { + bPoseChannel *pchan; + bConstraint *con; + RigControl *ctrl_parent = NULL; + RigControl *ctrl_child; + int found = 0; + + if (ctrl->bone->parent) { + ctrl_parent = BLI_ghash_lookup(rg->controls_map, ctrl->bone->parent->name); + } + + /* check constraints first */ + + /* DO SOME MAGIC HERE */ + for (pchan = rg->ob->pose->chanbase.first; pchan; pchan = pchan->next) { + for (con = pchan->constraints.first; con; con = con->next) { + const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); + ListBase targets = {NULL, NULL}; + bConstraintTarget *ct; + + /* constraint targets */ + if (cti && cti->get_constraint_targets) { + cti->get_constraint_targets(con, &targets); + + for (ct = targets.first; ct; ct = ct->next) { + if ((ct->tar == rg->ob) && STREQ(ct->subtarget, ctrl->bone->name)) { + /* SET bone link to ctrl corresponding to pchan */ + RigControl *link = BLI_ghash_lookup(rg->controls_map, pchan->name); + + /* if owner is a control bone, link with it */ + if (link && link->link) { + RIG_parentControl(ctrl, link->bone); + found = 1; + break; + } + } + } + + if (cti->flush_constraint_targets) + cti->flush_constraint_targets(con, &targets, 0); + } + } + } + + if (found == 0) { + /* check if parent is already linked */ + if (ctrl_parent && ctrl_parent->link) { + RIG_parentControl(ctrl, ctrl_parent->bone); + changed = true; + } + else { + /* check childs */ + for (ctrl_child = rg->controls.first; ctrl_child; ctrl_child = ctrl_child->next) { + /* if a child is linked, link to that one */ + if (ctrl_child->link && ctrl_child->bone->parent == ctrl->bone) { + RIG_parentControl(ctrl, ctrl_child->bone); + changed = true; + break; + } + } + } + } + } + } + } + + /* third pass, link control tails */ + for (ctrl = rg->controls.first; ctrl; ctrl = ctrl->next) { + /* fit bone already means full match, so skip those */ + if ((ctrl->flag & RIG_CTRL_FIT_BONE) == 0) { + GHashIterator ghi; + + /* look on deform bones first */ + BLI_ghashIterator_init(&ghi, rg->bones_map); + + for (; !BLI_ghashIterator_done(&ghi); BLI_ghashIterator_step(&ghi)) { + EditBone *bone = (EditBone *)BLI_ghashIterator_getValue(&ghi); + + /* don't link with parent */ + if (bone->parent != ctrl->bone) { + if (len_v3v3(ctrl->bone->tail, bone->head) < 0.01f) { + ctrl->tail_mode = TL_HEAD; + ctrl->link_tail = bone; + break; + } + else if (len_v3v3(ctrl->bone->tail, bone->tail) < 0.01f) { + ctrl->tail_mode = TL_TAIL; + ctrl->link_tail = bone; + break; + } + } + } + + /* if we haven't found one yet, look in control bones */ + if (ctrl->tail_mode == TL_NONE) { + /* pass */ + } + } + } + +} + +/*******************************************************************************************************/ + +static void RIG_joinArcs(RigGraph *rg, RigNode *node, RigArc *joined_arc1, RigArc *joined_arc2) +{ + RigEdge *edge, *next_edge; + + /* ignore cases where joint is at start or end */ + if (joined_arc1->head == joined_arc2->head || joined_arc1->tail == joined_arc2->tail) { + return; + } + + /* swap arcs to make sure arc1 is before arc2 */ + if (joined_arc1->head == joined_arc2->tail) { + RigArc *tmp = joined_arc1; + joined_arc1 = joined_arc2; + joined_arc2 = tmp; + } + + for (edge = joined_arc2->edges.first; edge; edge = next_edge) { + next_edge = edge->next; + + RIG_appendEdgeToArc(joined_arc1, edge); + } + + joined_arc1->tail = joined_arc2->tail; + + BLI_listbase_clear(&joined_arc2->edges); + + BLI_removeArc((BGraph *)rg, (BArc *)joined_arc2); + + BLI_removeNode((BGraph *)rg, (BNode *)node); +} + +static void RIG_removeNormalNodes(RigGraph *rg) +{ + RigNode *node, *next_node; + + for (node = rg->nodes.first; node; node = next_node) { + next_node = node->next; + + if (node->degree == 2) { + RigArc *arc, *joined_arc1 = NULL, *joined_arc2 = NULL; + + for (arc = rg->arcs.first; arc; arc = arc->next) { + if (arc->head == node || arc->tail == node) { + if (joined_arc1 == NULL) { + joined_arc1 = arc; + } + else { + joined_arc2 = arc; + break; + } + } + } + + RIG_joinArcs(rg, node, joined_arc1, joined_arc2); + } + } +} + +static void RIG_removeUneededOffsets(RigGraph *rg) +{ + RigArc *arc; + + for (arc = rg->arcs.first; arc; arc = arc->next) { + RigEdge *first_edge, *last_edge; + + first_edge = arc->edges.first; + last_edge = arc->edges.last; + + if (first_edge->bone == NULL) { + if (first_edge->bone == NULL && len_v3v3(first_edge->tail, arc->head->p) <= 0.001f) { + BLI_remlink(&arc->edges, first_edge); + MEM_freeN(first_edge); + } + else if (arc->head->degree == 1) { + RigNode *new_node = (RigNode *)BLI_FindNodeByPosition((BGraph *)rg, first_edge->tail, 0.001f); + + if (new_node) { + BLI_remlink(&arc->edges, first_edge); + MEM_freeN(first_edge); + BLI_replaceNodeInArc((BGraph *)rg, (BArc *)arc, (BNode *)new_node, (BNode *)arc->head); + } + else { + RigEdge *next_edge = first_edge->next; + + if (next_edge) { + BLI_remlink(&arc->edges, first_edge); + MEM_freeN(first_edge); + + copy_v3_v3(arc->head->p, next_edge->head); + } + } + } + else { + /* check if all arc connected start with a null edge */ + RigArc *other_arc; + for (other_arc = rg->arcs.first; other_arc; other_arc = other_arc->next) { + if (other_arc != arc) { + RigEdge *test_edge; + if (other_arc->head == arc->head) { + test_edge = other_arc->edges.first; + + if (test_edge->bone != NULL) { + break; + } + } + else if (other_arc->tail == arc->head) { + test_edge = other_arc->edges.last; + + if (test_edge->bone != NULL) { + break; + } + } + } + } + + if (other_arc == NULL) { + RigNode *new_node = (RigNode *)BLI_FindNodeByPosition((BGraph *)rg, first_edge->tail, 0.001); + + if (new_node) { + /* remove null edge in other arcs too */ + for (other_arc = rg->arcs.first; other_arc; other_arc = other_arc->next) { + if (other_arc != arc) { + RigEdge *test_edge; + if (other_arc->head == arc->head) { + BLI_replaceNodeInArc((BGraph *)rg, (BArc *)other_arc, (BNode *)new_node, (BNode *)other_arc->head); + test_edge = other_arc->edges.first; + BLI_remlink(&other_arc->edges, test_edge); + MEM_freeN(test_edge); + } + else if (other_arc->tail == arc->head) { + BLI_replaceNodeInArc((BGraph *)rg, (BArc *)other_arc, (BNode *)new_node, (BNode *)other_arc->tail); + test_edge = other_arc->edges.last; + BLI_remlink(&other_arc->edges, test_edge); + MEM_freeN(test_edge); + } + } + } + + BLI_remlink(&arc->edges, first_edge); + MEM_freeN(first_edge); + BLI_replaceNodeInArc((BGraph *)rg, (BArc *)arc, (BNode *)new_node, (BNode *)arc->head); + } + else { + RigEdge *next_edge = first_edge->next; + + if (next_edge) { + BLI_remlink(&arc->edges, first_edge); + MEM_freeN(first_edge); + + copy_v3_v3(arc->head->p, next_edge->head); + + /* remove null edge in other arcs too */ + for (other_arc = rg->arcs.first; other_arc; other_arc = other_arc->next) { + if (other_arc != arc) { + RigEdge *test_edge; + if (other_arc->head == arc->head) { + test_edge = other_arc->edges.first; + BLI_remlink(&other_arc->edges, test_edge); + MEM_freeN(test_edge); + } + else if (other_arc->tail == arc->head) { + test_edge = other_arc->edges.last; + BLI_remlink(&other_arc->edges, test_edge); + MEM_freeN(test_edge); + } + } + } + } + } + } + } + } + + if (last_edge->bone == NULL) { + if (len_v3v3(last_edge->head, arc->tail->p) <= 0.001f) { + BLI_remlink(&arc->edges, last_edge); + MEM_freeN(last_edge); + } + else if (arc->tail->degree == 1) { + RigNode *new_node = (RigNode *)BLI_FindNodeByPosition((BGraph *)rg, last_edge->head, 0.001f); + + if (new_node) { + RigEdge *previous_edge = last_edge->prev; + + BLI_remlink(&arc->edges, last_edge); + MEM_freeN(last_edge); + BLI_replaceNodeInArc((BGraph *)rg, (BArc *)arc, (BNode *)new_node, (BNode *)arc->tail); + + /* set previous angle to 0, since there's no following edges */ + if (previous_edge) { + previous_edge->angle = 0; + } + } + else { + RigEdge *previous_edge = last_edge->prev; + + if (previous_edge) { + BLI_remlink(&arc->edges, last_edge); + MEM_freeN(last_edge); + + copy_v3_v3(arc->tail->p, previous_edge->tail); + previous_edge->angle = 0; + } + } + } + } + } +} + +static void RIG_arcFromBoneChain(RigGraph *rg, ListBase *list, EditBone *root_bone, RigNode *starting_node, bool selected) +{ + EditBone *bone, *last_bone = root_bone; + RigArc *arc = NULL; + int contain_head = 0; + + for (bone = root_bone; bone; bone = nextEditBoneChild(list, bone, 0)) { + int nb_children; + + if (selected == 0 || (bone->flag & BONE_SELECTED)) { + if ((bone->flag & BONE_NO_DEFORM) == 0) { + BLI_ghash_insert(rg->bones_map, bone->name, bone); + + if (arc == NULL) { + arc = newRigArc(rg); + + if (starting_node == NULL) { + starting_node = newRigNodeHead(rg, arc, root_bone->head); + } + else { + addRigNodeHead(rg, arc, starting_node); + } + } + + if (bone->parent && (bone->flag & BONE_CONNECTED) == 0) { + RIG_addEdgeToArc(arc, bone->head, NULL); + } + + RIG_addEdgeToArc(arc, bone->tail, bone); + + last_bone = bone; + + if (STREQ(bone->name, "head")) { + contain_head = 1; + } + } + else if ((bone->flag & BONE_EDITMODE_LOCKED) == 0) { /* ignore locked bones */ + RIG_addControlBone(rg, bone); + } + } + + nb_children = countEditBoneChildren(list, bone); + if (nb_children > 1) { + RigNode *end_node = NULL; + int i; + + if (arc != NULL) { + end_node = newRigNodeTail(rg, arc, bone->tail); + } + else { + end_node = newRigNode(rg, bone->tail); + } + + for (i = 0; i < nb_children; i++) { + root_bone = nextEditBoneChild(list, bone, i); + RIG_arcFromBoneChain(rg, list, root_bone, end_node, selected); + } + + /* arc ends here, break */ + break; + } + } + + /* If the loop exited without forking */ + if (arc != NULL && bone == NULL) { + newRigNodeTail(rg, arc, last_bone->tail); + } + + if (contain_head) { + rg->head = arc->tail; + } +} + +/*******************************************************************************************************/ +static void RIG_findHead(RigGraph *rg) +{ + if (rg->head == NULL) { + if (BLI_listbase_is_single(&rg->arcs)) { + RigArc *arc = rg->arcs.first; + + rg->head = (RigNode *)arc->head; + } + else { + RigArc *arc; + + for (arc = rg->arcs.first; arc; arc = arc->next) { + RigEdge *edge = arc->edges.last; + + if (edge->bone->flag & (BONE_TIPSEL | BONE_SELECTED)) { + rg->head = arc->tail; + break; + } + } + } + + if (rg->head == NULL) { + rg->head = rg->nodes.first; + } + } +} + +/*******************************************************************************************************/ + +static void RIG_printNode(RigNode *node, const char name[]) +{ + printf("%s %p %i <%0.3f, %0.3f, %0.3f>\n", name, (void *)node, node->degree, node->p[0], node->p[1], node->p[2]); + + if (node->symmetry_flag & SYM_TOPOLOGICAL) { + if (node->symmetry_flag & SYM_AXIAL) + printf("Symmetry AXIAL\n"); + else if (node->symmetry_flag & SYM_RADIAL) + printf("Symmetry RADIAL\n"); + + print_v3("symmetry axis", node->symmetry_axis); + } +} + +void RIG_printArcBones(RigArc *arc) +{ + RigEdge *edge; + + for (edge = arc->edges.first; edge; edge = edge->next) { + if (edge->bone) + printf("%s ", edge->bone->name); + else + printf("---- "); + } + printf("\n"); +} + +static void RIG_printCtrl(RigControl *ctrl, char *indent) +{ + char text[128]; + + printf("%sBone: %s\n", indent, ctrl->bone->name); + printf("%sLink: %s\n", indent, ctrl->link ? ctrl->link->name : "!NONE!"); + + BLI_snprintf(text, sizeof(text), "%soffset", indent); + print_v3(text, ctrl->offset); + + printf("%sFlag: %i\n", indent, ctrl->flag); +} + +static void RIG_printLinkedCtrl(RigGraph *rg, EditBone *bone, int tabs) +{ + RigControl *ctrl; + char indent[64]; + char *s = indent; + int i; + + for (i = 0; i < tabs; i++) { + s[0] = '\t'; + s++; + } + s[0] = 0; + + for (ctrl = rg->controls.first; ctrl; ctrl = ctrl->next) { + if (ctrl->link == bone) { + RIG_printCtrl(ctrl, indent); + RIG_printLinkedCtrl(rg, ctrl->bone, tabs + 1); + } + } +} + +void RIG_printArc(RigGraph *rg, RigArc *arc) +{ + RigEdge *edge; + + RIG_printNode((RigNode *)arc->head, "head"); + + for (edge = arc->edges.first; edge; edge = edge->next) { + printf("\tinner joints %0.3f %0.3f %0.3f\n", edge->tail[0], edge->tail[1], edge->tail[2]); + printf("\t\tlength %f\n", edge->length); + printf("\t\tangle %f\n", edge->angle * (float)(180 / M_PI)); + if (edge->bone) { + printf("\t\t%s\n", edge->bone->name); + RIG_printLinkedCtrl(rg, edge->bone, 3); + } + } + printf("symmetry level: %i flag: %i group %i\n", arc->symmetry_level, arc->symmetry_flag, arc->symmetry_group); + + RIG_printNode((RigNode *)arc->tail, "tail"); +} + +void RIG_printGraph(RigGraph *rg) +{ + RigArc *arc; + + printf("---- ARCS ----\n"); + for (arc = rg->arcs.first; arc; arc = arc->next) { + RIG_printArc(rg, arc); + printf("\n"); + } + + if (rg->head) { + RIG_printNode(rg->head, "HEAD NODE:"); + } + else { + printf("HEAD NODE: NONE\n"); + } +} + +/*******************************************************************************************************/ + +RigGraph *RIG_graphFromArmature(const bContext *C, Object *ob, bArmature *arm) +{ + Object *obedit = CTX_data_edit_object(C); + Scene *scene = CTX_data_scene(C); + EditBone *ebone; + RigGraph *rg; + + rg = newRigGraph(); + + if (obedit == ob) { + rg->editbones = ((bArmature *)obedit->data)->edbo; + } + else { + rg->editbones = MEM_callocN(sizeof(ListBase), "EditBones"); + make_boneList(rg->editbones, &arm->bonebase, NULL, NULL); + rg->flag |= RIG_FREE_BONELIST; + } + + rg->ob = ob; + + /* Do the rotations */ + for (ebone = rg->editbones->first; ebone; ebone = ebone->next) { + if (ebone->parent == NULL) { + RIG_arcFromBoneChain(rg, rg->editbones, ebone, NULL, 0); + } + } + + BLI_removeDoubleNodes((BGraph *)rg, 0.001); + + RIG_removeNormalNodes(rg); + + RIG_removeUneededOffsets(rg); + + BLI_buildAdjacencyList((BGraph *)rg); + + RIG_findHead(rg); + + BLI_markdownSymmetry((BGraph *)rg, (BNode *)rg->head, scene->toolsettings->skgen_symmetry_limit); + + RIG_reconnectControlBones(rg); /* after symmetry, because we use levels to find best match */ + + if (BLI_isGraphCyclic((BGraph *)rg)) { + printf("armature cyclic\n"); + } + + return rg; +} + +static RigGraph *armatureSelectedToGraph(bContext *C, Object *ob, bArmature *arm) +{ + Object *obedit = CTX_data_edit_object(C); + Scene *scene = CTX_data_scene(C); + EditBone *ebone; + RigGraph *rg; + + rg = newRigGraph(); + + if (obedit == ob) { + rg->editbones = arm->edbo; + } + else { + rg->editbones = MEM_callocN(sizeof(ListBase), "EditBones"); + make_boneList(rg->editbones, &arm->bonebase, NULL, NULL); + rg->flag |= RIG_FREE_BONELIST; + } + + rg->ob = ob; + + /* Do the rotations */ + for (ebone = rg->editbones->first; ebone; ebone = ebone->next) { + if (ebone->parent == NULL) { + RIG_arcFromBoneChain(rg, rg->editbones, ebone, NULL, 1); + } + } + + BLI_removeDoubleNodes((BGraph *)rg, 0.001); + + RIG_removeNormalNodes(rg); + + RIG_removeUneededOffsets(rg); + + BLI_buildAdjacencyList((BGraph *)rg); + + RIG_findHead(rg); + + BLI_markdownSymmetry((BGraph *)rg, (BNode *)rg->head, scene->toolsettings->skgen_symmetry_limit); + + RIG_reconnectControlBones(rg); /* after symmetry, because we use levels to find best match */ + + if (BLI_isGraphCyclic((BGraph *)rg)) { + printf("armature cyclic\n"); + } + + return rg; +} +/************************************ GENERATING *****************************************************/ + +#if 0 +static EditBone *add_editbonetolist(char *name, ListBase *list) +{ + EditBone *bone = MEM_callocN(sizeof(EditBone), "eBone"); + + BLI_strncpy(bone->name, name, sizeof(bone->name)); + ED_armature_ebone_unique_name(list, bone->name, NULL); + + BLI_addtail(list, bone); + + bone->flag |= BONE_TIPSEL; + bone->weight = 1.0F; + bone->dist = 0.25F; + bone->xwidth = 0.1; + bone->zwidth = 0.1; + bone->rad_head = 0.10; + bone->rad_tail = 0.05; + bone->segments = 1; + bone->layer = 1; //arm->layer; + + /* Bendy-Bone parameters */ + bone->roll1 = 0.0f; + bone->roll2 = 0.0f; + bone->curveInX = 0.0f; + bone->curveInY = 0.0f; + bone->curveOutX = 0.0f; + bone->curveOutY = 0.0f; + bone->ease1 = 1.0f; + bone->ease2 = 1.0f; + bone->scaleIn = 1.0f; + bone->scaleOut = 1.0f; + + return bone; +} +#endif + +#if 0 /* UNUSED */ +static void generateMissingArcsFromNode(RigGraph *rigg, ReebNode *node, int multi_level_limit) +{ + while (node->multi_level > multi_level_limit && node->link_up) + { + node = node->link_up; + } + + while (node->multi_level < multi_level_limit && node->link_down) + { + node = node->link_down; + } + + if (node->multi_level == multi_level_limit) + { + int i; + + for (i = 0; i < node->degree; i++) + { + ReebArc *earc = node->arcs[i]; + + if (earc->flag == ARC_FREE && earc->head == node) + { + ReebNode *other = BIF_otherNodeFromIndex(earc, node); + + earc->flag = ARC_USED; + + //generateBonesForArc(rigg, earc, node, other); + generateMissingArcsFromNode(rigg, other, multi_level_limit); + } + } + } +} + +static void generateMissingArcs(RigGraph *rigg) +{ + ReebGraph *reebg; + int multi_level_limit = 5; + + for (reebg = rigg->link_mesh; reebg; reebg = reebg->link_up) + { + ReebArc *earc; + + for (earc = reebg->arcs.first; earc; earc = earc->next) + { + if (earc->flag == ARC_USED) + { + generateMissingArcsFromNode(rigg, earc->head, multi_level_limit); + generateMissingArcsFromNode(rigg, earc->tail, multi_level_limit); + } + } + } +} +#endif + +/************************************ RETARGETTING *****************************************************/ + +static void repositionControl(RigGraph *rigg, RigControl *ctrl, float head[3], float tail[3], float qrot[4], float resize); + +static void repositionTailControl(RigGraph *rigg, RigControl *ctrl); + +static void finalizeControl(RigGraph *rigg, RigControl *ctrl, float resize) +{ + if ((ctrl->flag & RIG_CTRL_DONE) == RIG_CTRL_DONE) { + RigControl *ctrl_child; + +#if 0 + printf("CTRL: %s LINK: %s", ctrl->bone->name, ctrl->link->name); + + if (ctrl->link_tail) + { + printf(" TAIL: %s", ctrl->link_tail->name); + } + + printf("\n"); +#endif + + /* if there was a tail link: apply link, recalc resize factor and qrot */ + if (ctrl->tail_mode != TL_NONE) { + float *tail_vec = NULL; + float v1[3], v2[3], qtail[4]; + + if (ctrl->tail_mode == TL_TAIL) { + tail_vec = ctrl->link_tail->tail; + } + else if (ctrl->tail_mode == TL_HEAD) { + tail_vec = ctrl->link_tail->head; + } + + sub_v3_v3v3(v1, ctrl->bone->tail, ctrl->bone->head); + sub_v3_v3v3(v2, tail_vec, ctrl->bone->head); + + copy_v3_v3(ctrl->bone->tail, tail_vec); + + rotation_between_vecs_to_quat(qtail, v1, v2); + mul_qt_qtqt(ctrl->qrot, qtail, ctrl->qrot); + + resize = len_v3(v2) / len_v3v3(ctrl->head, ctrl->tail); + } + + ctrl->bone->roll = rollBoneByQuat(ctrl->bone, ctrl->up_axis, ctrl->qrot); + + /* Cascade to connected control bones */ + for (ctrl_child = rigg->controls.first; ctrl_child; ctrl_child = ctrl_child->next) { + if (ctrl_child->link == ctrl->bone) { + repositionControl(rigg, ctrl_child, ctrl->bone->head, ctrl->bone->tail, ctrl->qrot, resize); + } + if (ctrl_child->link_tail == ctrl->bone) { + repositionTailControl(rigg, ctrl_child); + } + } + } +} + +static void repositionTailControl(RigGraph *rigg, RigControl *ctrl) +{ + ctrl->flag |= RIG_CTRL_TAIL_DONE; + + finalizeControl(rigg, ctrl, 1); /* resize will be recalculated anyway so we don't need it */ +} + +static void repositionControl(RigGraph *rigg, RigControl *ctrl, float head[3], float UNUSED(tail[3]), float qrot[4], float resize) +{ + float parent_offset[3], tail_offset[3]; + + copy_v3_v3(parent_offset, ctrl->offset); + mul_v3_fl(parent_offset, resize); + mul_qt_v3(qrot, parent_offset); + + add_v3_v3v3(ctrl->bone->head, head, parent_offset); + + ctrl->flag |= RIG_CTRL_HEAD_DONE; + + copy_qt_qt(ctrl->qrot, qrot); + + if (ctrl->tail_mode == TL_NONE) { + sub_v3_v3v3(tail_offset, ctrl->tail, ctrl->head); + mul_v3_fl(tail_offset, resize); + mul_qt_v3(qrot, tail_offset); + + add_v3_v3v3(ctrl->bone->tail, ctrl->bone->head, tail_offset); + + ctrl->flag |= RIG_CTRL_TAIL_DONE; + } + + finalizeControl(rigg, ctrl, resize); +} + +static void repositionBone(bContext *C, RigGraph *rigg, RigEdge *edge, float vec0[3], float vec1[3], float up_axis[3]) +{ + Scene *scene = CTX_data_scene(C); + EditBone *bone; + RigControl *ctrl; + float qrot[4], resize; + float v1[3], v2[3]; + float l1, l2; + + bone = edge->bone; + + sub_v3_v3v3(v1, edge->tail, edge->head); + sub_v3_v3v3(v2, vec1, vec0); + + l1 = normalize_v3(v1); + l2 = normalize_v3(v2); + + resize = l2 / l1; + + rotation_between_vecs_to_quat(qrot, v1, v2); + + copy_v3_v3(bone->head, vec0); + copy_v3_v3(bone->tail, vec1); + + if (!is_zero_v3(up_axis)) { + float qroll[4]; + + if (scene->toolsettings->skgen_retarget_roll == SK_RETARGET_ROLL_VIEW) { + bone->roll = rollBoneByQuatAligned(bone, edge->up_axis, qrot, qroll, up_axis); + } + else if (scene->toolsettings->skgen_retarget_roll == SK_RETARGET_ROLL_JOINT) { + bone->roll = rollBoneByQuatJoint(edge, edge->prev, qrot, qroll, up_axis); + } + else { + unit_qt(qroll); + } + + mul_qt_qtqt(qrot, qroll, qrot); + } + else { + bone->roll = rollBoneByQuat(bone, edge->up_axis, qrot); + } + + for (ctrl = rigg->controls.first; ctrl; ctrl = ctrl->next) { + if (ctrl->link == bone) { + repositionControl(rigg, ctrl, vec0, vec1, qrot, resize); + } + if (ctrl->link_tail == bone) { + repositionTailControl(rigg, ctrl); + } + } +} + +static RetargetMode detectArcRetargetMode(RigArc *arc); +static void retargetArctoArcLength(bContext *C, RigGraph *rigg, RigArc *iarc, RigNode *inode_start); + + +static RetargetMode detectArcRetargetMode(RigArc *iarc) +{ + RetargetMode mode = RETARGET_AGGRESSIVE; + ReebArc *earc = iarc->link_mesh; + RigEdge *edge; + int large_angle = 0; + float avg_angle = 0; + /* float avg_length = 0; */ /* UNUSED */ + int nb_edges = 0; + + + for (edge = iarc->edges.first; edge; edge = edge->next) { + avg_angle += edge->angle; + nb_edges++; + } + + avg_angle /= nb_edges - 1; /* -1 because last edge doesn't have an angle */ + + /* avg_length = iarc->length / nb_edges; */ /* UNUSED */ + + + if (nb_edges > 2) { + for (edge = iarc->edges.first; edge; edge = edge->next) { + if (fabsf(edge->angle - avg_angle) > (float)(M_PI / 6)) { + large_angle = 1; + } + } + } + else if (nb_edges == 2 && avg_angle > 0) { + large_angle = 1; + } + + + if (large_angle == 0) { + mode = RETARGET_LENGTH; + } + + if (earc->bcount <= (iarc->count - 1)) { + mode = RETARGET_LENGTH; + } + + return mode; +} + +#ifndef USE_THREADS +static void printMovesNeeded(int *positions, int nb_positions) +{ + int moves = 0; + int i; + + for (i = 0; i < nb_positions; i++) { + moves += positions[i] - (i + 1); + } + + printf("%i moves needed\n", moves); +} + +static void printPositions(int *positions, int nb_positions) +{ + int i; + + for (i = 0; i < nb_positions; i++) { + printf("%i ", positions[i]); + } + printf("\n"); +} +#endif + +#define MAX_COST FLT_MAX /* FIX ME */ + +static float costDistance(BArcIterator *iter, float *vec0, float *vec1, int i0, int i1, float distance_weight) +{ + EmbedBucket *bucket = NULL; + float max_dist = 0; + float v1[3], v2[3], c[3]; + float v1_inpf; + + if (distance_weight > 0) { + sub_v3_v3v3(v1, vec0, vec1); + + v1_inpf = dot_v3v3(v1, v1); + + if (v1_inpf > 0) { + int j; + for (j = i0 + 1; j < i1 - 1; j++) { + float dist; + + bucket = IT_peek(iter, j); + + sub_v3_v3v3(v2, bucket->p, vec1); + + cross_v3_v3v3(c, v1, v2); + + dist = dot_v3v3(c, c) / v1_inpf; + + max_dist = dist > max_dist ? dist : max_dist; + } + + return distance_weight * max_dist; + } + else { + return MAX_COST; + } + } + else { + return 0; + } +} + +static float costAngle(float original_angle, float vec_first[3], float vec_second[3], float angle_weight) +{ + if (angle_weight > 0) { + float current_angle; + + if (!is_zero_v3(vec_first) && !is_zero_v3(vec_second)) { + current_angle = saacos(dot_v3v3(vec_first, vec_second)); + + return angle_weight * fabsf(current_angle - original_angle); + } + else { + return angle_weight * (float)M_PI; + } + } + else { + return 0; + } +} + +static float costLength(float original_length, float current_length, float length_weight) +{ + if (current_length == 0) { + return MAX_COST; + } + else { + float length_ratio = fabsf((current_length - original_length) / original_length); + return length_weight * length_ratio * length_ratio; + } +} + +#if 0 +static float calcCostLengthDistance(BArcIterator *iter, float **vec_cache, RigEdge *edge, float *vec1, float *vec2, int i1, int i2) +{ + float vec[3]; + float length; + + sub_v3_v3v3(vec, vec2, vec1); + length = normalize_v3(vec); + + return costLength(edge->length, length) + costDistance(iter, vec1, vec2, i1, i2); +} +#endif + +static float calcCostAngleLengthDistance(BArcIterator *iter, float **UNUSED(vec_cache), RigEdge *edge, + float *vec0, float *vec1, float *vec2, int i1, int i2, + float angle_weight, float length_weight, float distance_weight) +{ + float vec_second[3], vec_first[3]; + float length2; + float new_cost = 0; + + sub_v3_v3v3(vec_second, vec2, vec1); + length2 = normalize_v3(vec_second); + + + /* Angle cost */ + if (edge->prev) { + sub_v3_v3v3(vec_first, vec1, vec0); + normalize_v3(vec_first); + + new_cost += costAngle(edge->prev->angle, vec_first, vec_second, angle_weight); + } + + /* Length cost */ + new_cost += costLength(edge->length, length2, length_weight); + + /* Distance cost */ + new_cost += costDistance(iter, vec1, vec2, i1, i2, distance_weight); + + return new_cost; +} + +static int indexMemoNode(int nb_positions, int previous, int current, int joints_left) +{ + return joints_left * nb_positions * nb_positions + current * nb_positions + previous; +} + +static void copyMemoPositions(int *positions, MemoNode *table, int nb_positions, int joints_left) +{ + int previous = 0, current = 0; + int i = 0; + + for (i = 0; joints_left > 0; joints_left--, i++) { + MemoNode *node; + node = table + indexMemoNode(nb_positions, previous, current, joints_left); + + positions[i] = node->next; + + previous = current; + current = node->next; + } +} + +static MemoNode *solveJoints(MemoNode *table, BArcIterator *iter, float **vec_cache, + int nb_joints, int nb_positions, int previous, int current, RigEdge *edge, + int joints_left, float angle_weight, float length_weight, float distance_weight) +{ + MemoNode *node; + int index = indexMemoNode(nb_positions, previous, current, joints_left); + + node = table + index; + + if (node->weight != 0) { + return node; + } + else if (joints_left == 0) { + float *vec0 = vec_cache[previous]; + float *vec1 = vec_cache[current]; + float *vec2 = vec_cache[nb_positions + 1]; + + node->weight = calcCostAngleLengthDistance(iter, vec_cache, edge, vec0, vec1, vec2, current, iter->length, angle_weight, length_weight, distance_weight); + + return node; + } + else { + MemoNode *min_node = NULL; + float *vec0 = vec_cache[previous]; + float *vec1 = vec_cache[current]; + float min_weight = 0.0f; + int min_next = 0; + int next; + + for (next = current + 1; next <= nb_positions - (joints_left - 1); next++) { + MemoNode *next_node; + float *vec2 = vec_cache[next]; + float weight = 0.0f; + + /* ADD WEIGHT OF PREVIOUS - CURRENT - NEXT triple */ + weight = calcCostAngleLengthDistance(iter, vec_cache, edge, vec0, vec1, vec2, current, next, angle_weight, length_weight, distance_weight); + + if (weight >= MAX_COST) { + continue; + } + + /* add node weight */ + next_node = solveJoints(table, iter, vec_cache, nb_joints, nb_positions, current, next, edge->next, joints_left - 1, angle_weight, length_weight, distance_weight); + weight += next_node->weight; + + if (min_node == NULL || weight < min_weight) { + min_weight = weight; + min_node = next_node; + min_next = next; + } + } + + if (min_node) { + node->weight = min_weight; + node->next = min_next; + return node; + } + else { + node->weight = MAX_COST; + return node; + } + } + +} + +static int testFlipArc(RigArc *iarc, RigNode *inode_start) +{ + ReebArc *earc = iarc->link_mesh; + ReebNode *enode_start = BIF_NodeFromIndex(earc, inode_start->link_mesh); + + /* no flip needed if both nodes are the same */ + if ((enode_start == earc->head && inode_start == iarc->head) || + (enode_start == earc->tail && inode_start == iarc->tail)) + { + return 0; + } + else { + return 1; + } +} + +static void retargetArctoArcAggresive(bContext *C, RigGraph *rigg, RigArc *iarc, RigNode *inode_start) +{ + ReebArcIterator arc_iter; + BArcIterator *iter = (BArcIterator *)&arc_iter; + RigEdge *edge; + ReebNode *node_start, *node_end; + ReebArc *earc = iarc->link_mesh; + float angle_weight = 1.0; // GET FROM CONTEXT + float length_weight = 1.0; + float distance_weight = 1.0; +#ifndef USE_THREADS + float min_cost = FLT_MAX; +#endif + float *vec0, *vec1; + int *best_positions; + int nb_edges = BLI_listbase_count(&iarc->edges); + int nb_joints = nb_edges - 1; + RetargetMethod method = METHOD_MEMOIZE; + int i; + + if (nb_joints > earc->bcount) { + printf("NOT ENOUGH BUCKETS!\n"); + return; + } + + best_positions = MEM_callocN(sizeof(int) * nb_joints, "Best positions"); + + if (testFlipArc(iarc, inode_start)) { + node_start = earc->tail; + node_end = earc->head; + } + else { + node_start = earc->head; + node_end = earc->tail; + } + + /* equal number of joints and potential position, just fill them in */ + if (nb_joints == earc->bcount) { + /* init with first values */ + for (i = 0; i < nb_joints; i++) { + best_positions[i] = i + 1; + } + } + if (method == METHOD_MEMOIZE) { + int nb_positions = earc->bcount; + int nb_memo_nodes = nb_positions * nb_positions * (nb_joints + 1); + MemoNode *table = MEM_callocN(nb_memo_nodes * sizeof(MemoNode), "memoization table"); +#ifndef USE_THREADS + MemoNode *result; +#endif + float **positions_cache = MEM_callocN(sizeof(float *) * (nb_positions + 2), "positions cache"); + + positions_cache[0] = node_start->p; + positions_cache[nb_positions + 1] = node_end->p; + + initArcIterator(iter, earc, node_start); + + for (i = 1; i <= nb_positions; i++) { + EmbedBucket *bucket = IT_peek(iter, i); + positions_cache[i] = bucket->p; + } + +#ifndef USE_THREADS + result = solveJoints(table, iter, positions_cache, nb_joints, earc->bcount, 0, 0, iarc->edges.first, nb_joints, angle_weight, length_weight, distance_weight); + min_cost = result->weight; +#else + solveJoints(table, iter, positions_cache, nb_joints, earc->bcount, 0, 0, iarc->edges.first, nb_joints, angle_weight, length_weight, distance_weight); +#endif + + copyMemoPositions(best_positions, table, earc->bcount, nb_joints); + + MEM_freeN(table); + MEM_freeN(positions_cache); + } + + vec0 = node_start->p; + initArcIterator(iter, earc, node_start); + +#ifndef USE_THREADS + printPositions(best_positions, nb_joints); + printMovesNeeded(best_positions, nb_joints); + printf("min_cost %f\n", min_cost); + printf("buckets: %i\n", earc->bcount); +#endif + + /* set joints to best position */ + for (edge = iarc->edges.first, i = 0; + edge; + edge = edge->next, i++) + { + float *no = NULL; + if (i < nb_joints) { + EmbedBucket *bucket = IT_peek(iter, best_positions[i]); + vec1 = bucket->p; + no = bucket->no; + } + else { + vec1 = node_end->p; + no = node_end->no; + } + + if (edge->bone) { + repositionBone(C, rigg, edge, vec0, vec1, no); + } + + vec0 = vec1; + } + + MEM_freeN(best_positions); +} + +static void retargetArctoArcLength(bContext *C, RigGraph *rigg, RigArc *iarc, RigNode *inode_start) +{ + ReebArcIterator arc_iter; + BArcIterator *iter = (BArcIterator *)&arc_iter; + ReebArc *earc = iarc->link_mesh; + ReebNode *node_start, *node_end; + RigEdge *edge; + EmbedBucket *bucket = NULL; + float embedding_length = 0; + float *vec0 = NULL; + float *vec1 = NULL; + float *previous_vec = NULL; + + + if (testFlipArc(iarc, inode_start)) { + node_start = (ReebNode *)earc->tail; + node_end = (ReebNode *)earc->head; + } + else { + node_start = (ReebNode *)earc->head; + node_end = (ReebNode *)earc->tail; + } + + initArcIterator(iter, earc, node_start); + + bucket = IT_next(iter); + + vec0 = node_start->p; + + while (bucket != NULL) { + vec1 = bucket->p; + + embedding_length += len_v3v3(vec0, vec1); + + vec0 = vec1; + bucket = IT_next(iter); + } + + embedding_length += len_v3v3(node_end->p, vec1); + + /* fit bones */ + initArcIterator(iter, earc, node_start); + + bucket = IT_next(iter); + + vec0 = node_start->p; + previous_vec = vec0; + vec1 = bucket->p; + + for (edge = iarc->edges.first; edge; edge = edge->next) { + float new_bone_length = edge->length / iarc->length * embedding_length; + float *no = NULL; + float length = 0; + + while (bucket && new_bone_length > length) { + length += len_v3v3(previous_vec, vec1); + bucket = IT_next(iter); + previous_vec = vec1; + vec1 = bucket->p; + no = bucket->no; + } + + if (bucket == NULL) { + vec1 = node_end->p; + no = node_end->no; + } + + /* no need to move virtual edges (space between unconnected bones) */ + if (edge->bone) { + repositionBone(C, rigg, edge, vec0, vec1, no); + } + + vec0 = vec1; + previous_vec = vec1; + } +} + +static void retargetArctoArc(bContext *C, RigGraph *rigg, RigArc *iarc, RigNode *inode_start) +{ + RetargetParam *p = MEM_callocN(sizeof(RetargetParam), "RetargetParam"); + + p->rigg = rigg; + p->iarc = iarc; + p->inode_start = inode_start; + p->context = C; + + BLI_task_pool_push(rigg->task_pool, exec_retargetArctoArc, p, true, TASK_PRIORITY_HIGH); +} + +void exec_retargetArctoArc(TaskPool * __restrict UNUSED(pool), void *taskdata, int UNUSED(threadid)) +{ + RetargetParam *p = (RetargetParam *)taskdata; + RigGraph *rigg = p->rigg; + RigArc *iarc = p->iarc; + bContext *C = p->context; + RigNode *inode_start = p->inode_start; + ReebArc *earc = iarc->link_mesh; + + if (BLI_listbase_is_single(&iarc->edges)) { + RigEdge *edge = iarc->edges.first; + + if (testFlipArc(iarc, inode_start)) { + repositionBone(C, rigg, edge, earc->tail->p, earc->head->p, earc->head->no); + } + else { + repositionBone(C, rigg, edge, earc->head->p, earc->tail->p, earc->tail->no); + } + } + else { + RetargetMode mode = detectArcRetargetMode(iarc); + + if (mode == RETARGET_AGGRESSIVE) { + retargetArctoArcAggresive(C, rigg, iarc, inode_start); + } + else { + retargetArctoArcLength(C, rigg, iarc, inode_start); + } + } +} + +static void matchMultiResolutionNode(RigGraph *rigg, RigNode *inode, ReebNode *top_node) +{ + ReebNode *enode = top_node; + ReebGraph *reebg = BIF_graphForMultiNode(rigg->link_mesh, enode); + int ishape, eshape; + + ishape = BLI_subtreeShape((BGraph *)rigg, (BNode *)inode, NULL, 0) % SHAPE_LEVELS; + eshape = BLI_subtreeShape((BGraph *)reebg, (BNode *)enode, NULL, 0) % SHAPE_LEVELS; + + inode->link_mesh = enode; + + while (ishape == eshape && enode->link_down) { + inode->link_mesh = enode; + + enode = enode->link_down; + reebg = BIF_graphForMultiNode(rigg->link_mesh, enode); /* replace with call to link_down once that exists */ + eshape = BLI_subtreeShape((BGraph *)reebg, (BNode *)enode, NULL, 0) % SHAPE_LEVELS; + } +} + +static void markMultiResolutionChildArc(ReebNode *end_enode, ReebNode *enode) +{ + int i; + + for (i = 0; i < enode->degree; i++) { + ReebArc *earc = (ReebArc *)enode->arcs[i]; + + if (earc->flag == ARC_FREE) { + earc->flag = ARC_TAKEN; + + if (earc->tail->degree > 1 && earc->tail != end_enode) { + markMultiResolutionChildArc(end_enode, earc->tail); + } + break; + } + } +} + +static void markMultiResolutionArc(ReebArc *start_earc) +{ + if (start_earc->link_up) { + ReebArc *earc; + for (earc = start_earc->link_up; earc; earc = earc->link_up) { + earc->flag = ARC_TAKEN; + + if (earc->tail->index != start_earc->tail->index) { + markMultiResolutionChildArc(earc->tail, earc->tail); + } + } + } +} + +static void matchMultiResolutionArc(RigGraph *rigg, RigNode *start_node, RigArc *next_iarc, ReebArc *next_earc) +{ + ReebNode *enode = next_earc->head; + ReebGraph *reebg = BIF_graphForMultiNode(rigg->link_mesh, enode); + int ishape, eshape; + + ishape = BLI_subtreeShape((BGraph *)rigg, (BNode *)start_node, (BArc *)next_iarc, 1) % SHAPE_LEVELS; + eshape = BLI_subtreeShape((BGraph *)reebg, (BNode *)enode, (BArc *)next_earc, 1) % SHAPE_LEVELS; + + while (ishape != eshape && next_earc->link_up) { + next_earc->flag = ARC_TAKEN; // mark previous as taken, to prevent backtrack on lower levels + + next_earc = next_earc->link_up; + reebg = reebg->link_up; + enode = next_earc->head; + eshape = BLI_subtreeShape((BGraph *)reebg, (BNode *)enode, (BArc *)next_earc, 1) % SHAPE_LEVELS; + } + + next_earc->flag = ARC_USED; + next_iarc->link_mesh = next_earc; + + /* mark all higher levels as taken too */ + markMultiResolutionArc(next_earc); +// while (next_earc->link_up) +// { +// next_earc = next_earc->link_up; +// next_earc->flag = ARC_TAKEN; +// } +} + +static void matchMultiResolutionStartingNode(RigGraph *rigg, ReebGraph *reebg, RigNode *inode) +{ + ReebNode *enode; + int ishape, eshape; + + enode = reebg->nodes.first; + + ishape = BLI_subtreeShape((BGraph *)rigg, (BNode *)inode, NULL, 0) % SHAPE_LEVELS; + eshape = BLI_subtreeShape((BGraph *)rigg->link_mesh, (BNode *)enode, NULL, 0) % SHAPE_LEVELS; + + while (ishape != eshape && reebg->link_up) { + reebg = reebg->link_up; + + enode = reebg->nodes.first; + + eshape = BLI_subtreeShape((BGraph *)reebg, (BNode *)enode, NULL, 0) % SHAPE_LEVELS; + } + + inode->link_mesh = enode; +} + +static void findCorrespondingArc(RigGraph *rigg, RigArc *start_arc, RigNode *start_node, RigArc *next_iarc, int root) +{ + ReebNode *enode = start_node->link_mesh; + ReebArc *next_earc; + int symmetry_level = next_iarc->symmetry_level; + int symmetry_group = next_iarc->symmetry_group; + int symmetry_flag = next_iarc->symmetry_flag; + int i; + + next_iarc->link_mesh = NULL; + +// if (root) +// { +// printf("-----------------------\n"); +// printf("MATCHING LIMB\n"); +// RIG_printArcBones(next_iarc); +// } + + for (i = 0; i < enode->degree; i++) { + next_earc = (ReebArc *)enode->arcs[i]; + +// if (next_earc->flag == ARC_FREE) +// { +// printf("candidate (level %i ?= %i) (flag %i ?= %i) (group %i ?= %i)\n", +// symmetry_level, next_earc->symmetry_level, +// symmetry_flag, next_earc->symmetry_flag, +// symmetry_group, next_earc->symmetry_flag); +// } + + if (next_earc->flag == ARC_FREE && + next_earc->symmetry_flag == symmetry_flag && + next_earc->symmetry_group == symmetry_group && + next_earc->symmetry_level == symmetry_level) + { +// printf("CORRESPONDING ARC FOUND\n"); +// printf("flag %i -- level %i -- flag %i -- group %i\n", next_earc->flag, next_earc->symmetry_level, next_earc->symmetry_flag, next_earc->symmetry_group); + + matchMultiResolutionArc(rigg, start_node, next_iarc, next_earc); + break; + } + } + + /* not found, try at higher nodes (lower node might have filtered internal arcs, messing shape of tree */ + if (next_iarc->link_mesh == NULL) { +// printf("NO CORRESPONDING ARC FOUND - GOING TO HIGHER LEVELS\n"); + + if (enode->link_up) { + start_node->link_mesh = enode->link_up; + findCorrespondingArc(rigg, start_arc, start_node, next_iarc, 0); + } + } + + /* still not found, print debug info */ + if (root && next_iarc->link_mesh == NULL) { + start_node->link_mesh = enode; /* linking back with root node */ + +// printf("NO CORRESPONDING ARC FOUND\n"); +// RIG_printArcBones(next_iarc); +// +// printf("ON NODE %i, multilevel %i\n", enode->index, enode->multi_level); +// +// printf("LOOKING FOR\n"); +// printf("flag %i -- level %i -- flag %i -- group %i\n", ARC_FREE, symmetry_level, symmetry_flag, symmetry_group); +// +// printf("CANDIDATES\n"); +// for (i = 0; i < enode->degree; i++) +// { +// next_earc = (ReebArc *)enode->arcs[i]; +// printf("flag %i -- level %i -- flag %i -- group %i\n", next_earc->flag, next_earc->symmetry_level, next_earc->symmetry_flag, next_earc->symmetry_group); +// } + + /* Emergency matching */ + for (i = 0; i < enode->degree; i++) { + next_earc = (ReebArc *)enode->arcs[i]; + + if (next_earc->flag == ARC_FREE && next_earc->symmetry_level == symmetry_level) { +// printf("USING:\n"); +// printf("flag %i -- level %i -- flag %i -- group %i\n", next_earc->flag, next_earc->symmetry_level, next_earc->symmetry_flag, next_earc->symmetry_group); + matchMultiResolutionArc(rigg, start_node, next_iarc, next_earc); + break; + } + } + } + +} + +static void retargetSubgraph(bContext *C, RigGraph *rigg, RigArc *start_arc, RigNode *start_node) +{ + RigNode *inode = start_node; + int i; + + /* no start arc on first node */ + if (start_arc) { + ReebNode *enode = start_node->link_mesh; + ReebArc *earc = start_arc->link_mesh; + + retargetArctoArc(C, rigg, start_arc, start_node); + + enode = BIF_otherNodeFromIndex(earc, enode); + inode = (RigNode *)BLI_otherNode((BArc *)start_arc, (BNode *)inode); + + /* match with lowest node with correct shape */ + matchMultiResolutionNode(rigg, inode, enode); + } + + for (i = 0; i < inode->degree; i++) { + RigArc *next_iarc = (RigArc *)inode->arcs[i]; + + /* no back tracking */ + if (next_iarc != start_arc) { + findCorrespondingArc(rigg, start_arc, inode, next_iarc, 1); + if (next_iarc->link_mesh) { + retargetSubgraph(C, rigg, next_iarc, inode); + } + } + } +} + +static void finishRetarget(RigGraph *rigg) +{ + BLI_task_pool_work_and_wait(rigg->task_pool); +} + +static void adjustGraphs(bContext *C, RigGraph *rigg) +{ + Main *bmain = CTX_data_main(C); + bArmature *arm = rigg->ob->data; + RigArc *arc; + + for (arc = rigg->arcs.first; arc; arc = arc->next) { + if (arc->link_mesh) { + retargetArctoArc(C, rigg, arc, arc->head); + } + } + + finishRetarget(rigg); + + /* Turn the list into an armature */ + arm->edbo = rigg->editbones; + ED_armature_from_edit(bmain, arm); + + ED_undo_push(C, "Retarget Skeleton"); +} + +static void retargetGraphs(bContext *C, RigGraph *rigg) +{ + Main *bmain = CTX_data_main(C); + bArmature *arm = rigg->ob->data; + ReebGraph *reebg = rigg->link_mesh; + RigNode *inode; + + /* flag all ReebArcs as free */ + BIF_flagMultiArcs(reebg, ARC_FREE); + + /* return to first level */ + inode = rigg->head; + + matchMultiResolutionStartingNode(rigg, reebg, inode); + + retargetSubgraph(C, rigg, NULL, inode); + + //generateMissingArcs(rigg); + + finishRetarget(rigg); + + /* Turn the list into an armature */ + arm->edbo = rigg->editbones; + ED_armature_from_edit(bmain, arm); +} + +const char *RIG_nameBone(RigGraph *rg, int arc_index, int bone_index) +{ + RigArc *arc = BLI_findlink(&rg->arcs, arc_index); + RigEdge *iedge; + + if (arc == NULL) { + return "None"; + } + + if (bone_index == BLI_listbase_count(&arc->edges)) { + return "Last joint"; + } + + iedge = BLI_findlink(&arc->edges, bone_index); + + if (iedge == NULL) { + return "Done"; + } + + if (iedge->bone == NULL) { + return "Bone offset"; + } + + return iedge->bone->name; +} + +int RIG_nbJoints(RigGraph *rg) +{ + RigArc *arc; + int total = 0; + + total += BLI_listbase_count(&rg->nodes); + + for (arc = rg->arcs.first; arc; arc = arc->next) { + total += BLI_listbase_count(&arc->edges) - 1; /* -1 because end nodes are already counted */ + } + + return total; +} + +static void BIF_freeRetarget(void) +{ + if (GLOBAL_RIGG) { + RIG_freeRigGraph((BGraph *)GLOBAL_RIGG); + GLOBAL_RIGG = NULL; + } +} + +void BIF_retargetArmature(bContext *C) +{ + ReebGraph *reebg; + double start_time, end_time; + double gstart_time, gend_time; + double reeb_time, rig_time = 0.0, retarget_time = 0.0, total_time; + + gstart_time = start_time = PIL_check_seconds_timer(); + + reebg = BIF_ReebGraphMultiFromEditMesh(C); + + end_time = PIL_check_seconds_timer(); + reeb_time = end_time - start_time; + + printf("Reeb Graph created\n"); + + CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases) + { + Object *ob = base->object; + + if (ob->type == OB_ARMATURE) { + RigGraph *rigg; + bArmature *arm; + + arm = ob->data; + + /* Put the armature into editmode */ + + + start_time = PIL_check_seconds_timer(); + + rigg = RIG_graphFromArmature(C, ob, arm); + + end_time = PIL_check_seconds_timer(); + rig_time = end_time - start_time; + + printf("Armature graph created\n"); + + //RIG_printGraph(rigg); + + rigg->link_mesh = reebg; + + printf("retargetting %s\n", ob->id.name); + + start_time = PIL_check_seconds_timer(); + + retargetGraphs(C, rigg); + + end_time = PIL_check_seconds_timer(); + retarget_time = end_time - start_time; + + BIF_freeRetarget(); + + GLOBAL_RIGG = rigg; + + break; /* only one armature at a time */ + } + } + CTX_DATA_END; + + + gend_time = PIL_check_seconds_timer(); + + total_time = gend_time - gstart_time; + + printf("-----------\n"); + printf("runtime: \t%.3f\n", total_time); + printf("reeb: \t\t%.3f (%.1f%%)\n", reeb_time, reeb_time / total_time * 100); + printf("rig: \t\t%.3f (%.1f%%)\n", rig_time, rig_time / total_time * 100); + printf("retarget: \t%.3f (%.1f%%)\n", retarget_time, retarget_time / total_time * 100); + printf("-----------\n"); + + ED_undo_push(C, "Retarget Skeleton"); + + // XXX +// allqueue(REDRAWVIEW3D, 0); +} + +void BIF_retargetArc(bContext *C, ReebArc *earc, RigGraph *template_rigg) +{ + Object *obedit = CTX_data_edit_object(C); + Scene *scene = CTX_data_scene(C); + bArmature *armedit = obedit->data; + Object *ob; + RigGraph *rigg; + RigArc *iarc; + char *side_string = scene->toolsettings->skgen_side_string; + char *num_string = scene->toolsettings->skgen_num_string; + int free_template = 0; + + if (template_rigg) { + ob = template_rigg->ob; + } + else { + free_template = 1; + ob = obedit; + template_rigg = armatureSelectedToGraph(C, ob, ob->data); + } + + if (BLI_listbase_is_empty(&template_rigg->arcs)) { +// XXX +// error("No Template and no deforming bones selected"); + return; + } + + rigg = cloneRigGraph(template_rigg, armedit->edbo, obedit, side_string, num_string); + + iarc = rigg->arcs.first; + + iarc->link_mesh = earc; + iarc->head->link_mesh = earc->head; + iarc->tail->link_mesh = earc->tail; + + retargetArctoArc(C, rigg, iarc, iarc->head); + + finishRetarget(rigg); + + /* free template if it comes from the edit armature */ + if (free_template) { + RIG_freeRigGraph((BGraph *)template_rigg); + } + RIG_freeRigGraph((BGraph *)rigg); + + ED_armature_edit_validate_active(armedit); + +// XXX +// allqueue(REDRAWVIEW3D, 0); +} + +void BIF_adjustRetarget(bContext *C) +{ + if (GLOBAL_RIGG) { + adjustGraphs(C, GLOBAL_RIGG); + } +} diff --git a/source/blender/editors/armature/meshlaplacian.c b/source/blender/editors/armature/meshlaplacian.c index bc6d776911a..1f01def5133 100644 --- a/source/blender/editors/armature/meshlaplacian.c +++ b/source/blender/editors/armature/meshlaplacian.c @@ -42,6 +42,7 @@ #include "BKE_DerivedMesh.h" #include "BKE_modifier.h" #include "BKE_mesh.h" +#include "BKE_mesh_runtime.h" #include "ED_mesh.h" #include "ED_armature.h" diff --git a/source/blender/editors/armature/pose_edit.c b/source/blender/editors/armature/pose_edit.c index fa9927419a0..ffe64cc24b0 100644 --- a/source/blender/editors/armature/pose_edit.c +++ b/source/blender/editors/armature/pose_edit.c @@ -46,6 +46,7 @@ #include "BKE_armature.h" #include "BKE_context.h" #include "BKE_deform.h" +#include "BKE_main.h" #include "BKE_object.h" #include "BKE_report.h" #include "BKE_layer.h" @@ -622,6 +623,7 @@ static void pose_copy_menu(Scene *scene) static int pose_flip_names_exec(bContext *C, wmOperator *op) { + Main *bmain = CTX_data_main(C); ViewLayer *view_layer = CTX_data_view_layer(C); const bool do_strip_numbers = RNA_boolean_get(op->ptr, "do_strip_numbers"); @@ -636,7 +638,7 @@ static int pose_flip_names_exec(bContext *C, wmOperator *op) } FOREACH_PCHAN_SELECTED_IN_OBJECT_END; - ED_armature_bones_flip_names(arm, &bones_names, do_strip_numbers); + ED_armature_bones_flip_names(bmain, arm, &bones_names, do_strip_numbers); BLI_freelistN(&bones_names); @@ -674,6 +676,7 @@ void POSE_OT_flip_names(wmOperatorType *ot) static int pose_autoside_names_exec(bContext *C, wmOperator *op) { + Main *bmain = CTX_data_main(C); Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C)); bArmature *arm; char newname[MAXBONENAME]; @@ -689,7 +692,7 @@ static int pose_autoside_names_exec(bContext *C, wmOperator *op) { BLI_strncpy(newname, pchan->name, sizeof(newname)); if (bone_autoside_name(newname, 1, axis, pchan->bone->head[axis], pchan->bone->tail[axis])) - ED_armature_bone_rename(arm, pchan->name, newname); + ED_armature_bone_rename(bmain, arm, pchan->name, newname); } CTX_DATA_END; diff --git a/source/blender/editors/armature/pose_lib.c b/source/blender/editors/armature/pose_lib.c index 02a1e22dbba..b9c4584ff15 100644 --- a/source/blender/editors/armature/pose_lib.c +++ b/source/blender/editors/armature/pose_lib.c @@ -48,6 +48,7 @@ #include "BKE_armature.h" #include "BKE_global.h" #include "BKE_idprop.h" +#include "BKE_main.h" #include "BKE_library.h" #include "BKE_object.h" @@ -191,7 +192,7 @@ static int has_poselib_pose_data_for_editing_poll(bContext *C) /* ----------------------------------- */ /* Initialize a new poselib (whether it is needed or not) */ -static bAction *poselib_init_new(Object *ob) +static bAction *poselib_init_new(Main *bmain, Object *ob) { /* sanity checks - only for armatures */ if (ELEM(NULL, ob, ob->pose)) @@ -201,19 +202,19 @@ static bAction *poselib_init_new(Object *ob) if (ob->poselib) id_us_min(&ob->poselib->id); - ob->poselib = BKE_action_add(G.main, "PoseLib"); + ob->poselib = BKE_action_add(bmain, "PoseLib"); ob->poselib->idroot = ID_OB; return ob->poselib; } /* Initialize a new poselib (checks if that needs to happen) */ -static bAction *poselib_validate(Object *ob) +static bAction *poselib_validate(Main *bmain, Object *ob) { if (ELEM(NULL, ob, ob->pose)) return NULL; else if (ob->poselib == NULL) - return poselib_init_new(ob); + return poselib_init_new(bmain, ob); else return ob->poselib; } @@ -223,6 +224,7 @@ static bAction *poselib_validate(Object *ob) static int poselib_new_exec(bContext *C, wmOperator *UNUSED(op)) { + Main *bmain = CTX_data_main(C); Object *ob = get_poselib_object(C); /* sanity checks */ @@ -230,7 +232,7 @@ static int poselib_new_exec(bContext *C, wmOperator *UNUSED(op)) return OPERATOR_CANCELLED; /* new method here deals with the rest... */ - poselib_init_new(ob); + poselib_init_new(bmain, ob); /* notifier here might evolve? */ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL); @@ -458,8 +460,9 @@ static int poselib_add_menu_invoke(bContext *C, wmOperator *op, const wmEvent *U static int poselib_add_exec(bContext *C, wmOperator *op) { + Main *bmain = CTX_data_main(C); Object *ob = get_poselib_object(C); - bAction *act = poselib_validate(ob); + bAction *act = poselib_validate(bmain, ob); bPose *pose = (ob) ? ob->pose : NULL; TimeMarker *marker; KeyingSet *ks; diff --git a/source/blender/editors/armature/pose_transform.c b/source/blender/editors/armature/pose_transform.c index de0612d840d..22c710dcda5 100644 --- a/source/blender/editors/armature/pose_transform.c +++ b/source/blender/editors/armature/pose_transform.c @@ -97,6 +97,7 @@ static void applyarmature_fix_boneparents(const bContext *C, Scene *scene, Objec /* set the current pose as the restpose */ static int apply_armature_pose2bones_exec(bContext *C, wmOperator *op) { + Main *bmain = CTX_data_main(C); Depsgraph *depsgraph = CTX_data_depsgraph(C); Scene *scene = CTX_data_scene(C); Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C)); // must be active object, not edit-object @@ -195,7 +196,7 @@ static int apply_armature_pose2bones_exec(bContext *C, wmOperator *op) } /* convert editbones back to bones, and then free the edit-data */ - ED_armature_from_edit(arm); + ED_armature_from_edit(bmain, arm); ED_armature_edit_free(arm); /* flush positions of posebones */ diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c index ab6586d2ab6..616017dac0a 100644 --- a/source/blender/editors/curve/editcurve.c +++ b/source/blender/editors/curve/editcurve.c @@ -1105,7 +1105,7 @@ static int *initialize_index_map(Object *obedit, int *r_old_totvert) return old_to_new_map; } -static void remap_hooks_and_vertex_parents(Object *obedit) +static void remap_hooks_and_vertex_parents(Main *bmain, Object *obedit) { Object *object; Curve *curve = (Curve *) obedit->data; @@ -1121,7 +1121,7 @@ static void remap_hooks_and_vertex_parents(Object *obedit) return; } - for (object = G.main->object.first; object; object = object->id.next) { + for (object = bmain->object.first; object; object = object->id.next) { ModifierData *md; int index; if ((object->parent) && @@ -1184,7 +1184,7 @@ static void remap_hooks_and_vertex_parents(Object *obedit) } /* load editNurb in object */ -void ED_curve_editnurb_load(Object *obedit) +void ED_curve_editnurb_load(Main *bmain, Object *obedit) { ListBase *editnurb = object_editcurve_get(obedit); @@ -1195,7 +1195,7 @@ void ED_curve_editnurb_load(Object *obedit) Nurb *nu, *newnu; ListBase newnurb = {NULL, NULL}, oldnurb = cu->nurb; - remap_hooks_and_vertex_parents(obedit); + remap_hooks_and_vertex_parents(bmain, obedit); for (nu = editnurb->first; nu; nu = nu->next) { newnu = BKE_nurb_duplicate(nu); @@ -1325,7 +1325,7 @@ static int separate_exec(bContext *C, wmOperator *op) BLI_movelisttolist(&newedit->nurbs, &newnurb); /* 4. put old object out of editmode and delete separated geometry */ - ED_curve_editnurb_load(newob); + ED_curve_editnurb_load(bmain, newob); ED_curve_editnurb_free(newob); curve_delete_segments(oldob, true); @@ -5026,7 +5026,7 @@ static int add_vertex_invoke(bContext *C, wmOperator *op, const wmEvent *event) const float mval[2] = {UNPACK2(event->mval)}; struct SnapObjectContext *snap_context = ED_transform_snap_object_context_create_view3d( - vc.scene, CTX_data_depsgraph(C), 0, vc.ar, vc.v3d); + vc.bmain, vc.scene, vc.depsgraph, 0, vc.ar, vc.v3d); ED_transform_snap_object_project_view3d( snap_context, diff --git a/source/blender/editors/curve/editcurve_paint.c b/source/blender/editors/curve/editcurve_paint.c index e6f5f82f96a..887f3dd13da 100644 --- a/source/blender/editors/curve/editcurve_paint.c +++ b/source/blender/editors/curve/editcurve_paint.c @@ -34,6 +34,7 @@ #include "BKE_context.h" #include "BKE_curve.h" #include "BKE_fcurve.h" +#include "BKE_main.h" #include "BKE_report.h" #include "DEG_depsgraph.h" @@ -616,6 +617,7 @@ static bool curve_draw_init(bContext *C, wmOperator *op, bool is_invoke) } } else { + cdd->vc.bmain = CTX_data_main(C); cdd->vc.depsgraph = CTX_data_depsgraph(C); cdd->vc.scene = CTX_data_scene(C); cdd->vc.view_layer = CTX_data_view_layer(C); diff --git a/source/blender/editors/gpencil/gpencil_convert.c b/source/blender/editors/gpencil/gpencil_convert.c index 72331d9e588..dfaa1420d68 100644 --- a/source/blender/editors/gpencil/gpencil_convert.c +++ b/source/blender/editors/gpencil/gpencil_convert.c @@ -66,6 +66,7 @@ #include "BKE_gpencil.h" #include "BKE_layer.h" #include "BKE_library.h" +#include "BKE_main.h" #include "BKE_object.h" #include "BKE_report.h" #include "BKE_scene.h" @@ -456,6 +457,7 @@ static void gp_stroke_path_animation_add_keyframes(Depsgraph *depsgraph, ReportL static void gp_stroke_path_animation(bContext *C, ReportList *reports, Curve *cu, tGpTimingData *gtd) { Depsgraph *depsgraph = CTX_data_depsgraph(C); + Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); bAction *act; FCurve *fcu; @@ -479,7 +481,7 @@ static void gp_stroke_path_animation(bContext *C, ReportList *reports, Curve *cu prop = RNA_struct_find_property(&ptr, "eval_time"); /* Ensure we have an F-Curve to add keyframes to */ - act = verify_adt_action((ID *)cu, true); + act = verify_adt_action(bmain, (ID *)cu, true); fcu = verify_fcurve(act, NULL, &ptr, "eval_time", 0, true); if (G.debug & G_DEBUG) { diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c index 9f01c1d0cd7..45caadf3742 100644 --- a/source/blender/editors/gpencil/gpencil_edit.c +++ b/source/blender/editors/gpencil/gpencil_edit.c @@ -57,6 +57,7 @@ #include "BKE_context.h" #include "BKE_gpencil.h" #include "BKE_library.h" +#include "BKE_main.h" #include "BKE_report.h" #include "BKE_screen.h" diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c index c28d80a801f..437d5cef6f8 100644 --- a/source/blender/editors/gpencil/gpencil_paint.c +++ b/source/blender/editors/gpencil/gpencil_paint.c @@ -46,14 +46,15 @@ #include "PIL_time.h" -#include "BKE_paint.h" -#include "BKE_gpencil.h" +#include "BKE_colortools.h" #include "BKE_context.h" #include "BKE_global.h" +#include "BKE_gpencil.h" +#include "BKE_main.h" +#include "BKE_paint.h" #include "BKE_report.h" #include "BKE_screen.h" #include "BKE_tracking.h" -#include "BKE_colortools.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" @@ -115,6 +116,7 @@ typedef enum eGPencil_PaintFlags { * "p" = op->customdata */ typedef struct tGPsdata { + Main *bmain; Scene *scene; /* current scene from context */ struct Depsgraph *depsgraph; @@ -1399,6 +1401,7 @@ static bool gp_session_initdata(bContext *C, tGPsdata *p) } /* pass on current scene and window */ + p->bmain = CTX_data_main(C); p->scene = CTX_data_scene(C); p->depsgraph = CTX_data_depsgraph(C); p->win = CTX_wm_window(C); @@ -2511,7 +2514,7 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event) * (Disabling RIGHTMOUSE case here results in bugs like [#32647]) * also making sure we have a valid event value, to not exit too early */ - if (ELEM(event->type, LEFTMOUSE, RIGHTMOUSE) && (event->val != KM_NOTHING)) { + if (ELEM(event->type, LEFTMOUSE, RIGHTMOUSE) && (ELEM(event->val, KM_PRESS, KM_RELEASE))) { /* if painting, end stroke */ if (p->status == GP_STATUS_PAINTING) { int sketch = 0; @@ -2657,7 +2660,7 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event) estate = OPERATOR_FINISHED; } } - else { + else if (event->val == KM_RELEASE) { p->status = GP_STATUS_IDLING; op->flag |= OP_IS_MODAL_CURSOR_REGION; } diff --git a/source/blender/editors/gpencil/gpencil_utils.c b/source/blender/editors/gpencil/gpencil_utils.c index 861fdcac080..f6d72d9e575 100644 --- a/source/blender/editors/gpencil/gpencil_utils.c +++ b/source/blender/editors/gpencil/gpencil_utils.c @@ -47,10 +47,11 @@ #include "DNA_space_types.h" #include "DNA_view3d_types.h" +#include "BKE_action.h" #include "BKE_context.h" #include "BKE_gpencil.h" +#include "BKE_main.h" #include "BKE_tracking.h" -#include "BKE_action.h" #include "WM_api.h" diff --git a/source/blender/editors/include/ED_anim_api.h b/source/blender/editors/include/ED_anim_api.h index 045d4281585..943191c8892 100644 --- a/source/blender/editors/include/ED_anim_api.h +++ b/source/blender/editors/include/ED_anim_api.h @@ -36,6 +36,7 @@ struct ListBase; struct AnimData; struct bContext; +struct Main; struct wmKeyConfig; struct ReportList; struct ScrArea; @@ -82,6 +83,7 @@ typedef struct bAnimContext { struct bDopeSheet *ads; /* dopesheet data for editor (or which is being used) */ struct Depsgraph *depsgraph; /* active dependency graph */ + struct Main *bmain; /* Current Main */ struct Scene *scene; /* active scene */ struct ViewLayer *view_layer; /* active scene layer */ struct Object *obact; /* active object */ @@ -682,7 +684,7 @@ float ANIM_unit_mapping_get_factor(struct Scene *scene, struct ID *id, struct FC /* --------- anim_deps.c, animation updates -------- */ void ANIM_id_update(struct Scene *scene, struct ID *id); -void ANIM_list_elem_update(struct Scene *scene, bAnimListElem *ale); +void ANIM_list_elem_update(struct Main *bmain, struct Scene *scene, bAnimListElem *ale); /* data -> channels syncing */ void ANIM_sync_animchannels_to_data(const struct bContext *C); diff --git a/source/blender/editors/include/ED_armature.h b/source/blender/editors/include/ED_armature.h index 60374f87955..cb422c2fb95 100644 --- a/source/blender/editors/include/ED_armature.h +++ b/source/blender/editors/include/ED_armature.h @@ -42,6 +42,7 @@ struct bPoseChannel; struct Depsgraph; struct IDProperty; struct ListBase; +struct Main; struct MeshDeformModifierData; struct Mesh; struct Object; @@ -135,7 +136,7 @@ void ED_operatormacros_armature(void); void ED_keymap_armature(struct wmKeyConfig *keyconf); /* editarmature.c */ -void ED_armature_from_edit(struct bArmature *arm); +void ED_armature_from_edit(struct Main *bmain, struct bArmature *arm); void ED_armature_to_edit(struct bArmature *arm); void ED_armature_edit_free(struct bArmature *arm); @@ -181,11 +182,11 @@ void ED_armature_ebone_from_mat3(EditBone *ebone, float mat[3][3]); void ED_armature_ebone_from_mat4(EditBone *ebone, float mat[4][4]); void ED_armature_edit_transform_mirror_update(struct Object *obedit); -void ED_armature_origin_set(struct Object *ob, float cursor[3], int centermode, int around); +void ED_armature_origin_set(struct Main *bmain, struct Object *ob, float cursor[3], int centermode, int around); void ED_armature_transform_bones(struct bArmature *arm, float mat[4][4], const bool do_props); -void ED_armature_transform_apply(struct Object *ob, float mat[4][4], const bool do_props); -void ED_armature_transform(struct bArmature *arm, float mat[4][4], const bool do_props); +void ED_armature_transform_apply(struct Main *bmain, struct Object *ob, float mat[4][4], const bool do_props); +void ED_armature_transform(struct Main *bmain, struct bArmature *arm, float mat[4][4], const bool do_props); #define ARM_GROUPS_NAME 1 #define ARM_GROUPS_ENVELOPE 2 @@ -197,8 +198,8 @@ void ED_object_vgroup_calc_from_armature( /* if bone is already in list, pass it as param to ignore it */ void ED_armature_ebone_unique_name(struct ListBase *ebones, char *name, EditBone *bone); -void ED_armature_bone_rename(struct bArmature *arm, const char *oldnamep, const char *newnamep); -void ED_armature_bones_flip_names(struct bArmature *arm, struct ListBase *bones_names, const bool do_strip_numbers); +void ED_armature_bone_rename(struct Main *bmain, struct bArmature *arm, const char *oldnamep, const char *newnamep); +void ED_armature_bones_flip_names(struct Main *bmain, struct bArmature *arm, struct ListBase *bones_names, const bool do_strip_numbers); /* low level selection functions which handle */ int ED_armature_ebone_selectflag_get(const EditBone *ebone); diff --git a/source/blender/editors/include/ED_curve.h b/source/blender/editors/include/ED_curve.h index 74c8334322f..8fcfb4743d5 100644 --- a/source/blender/editors/include/ED_curve.h +++ b/source/blender/editors/include/ED_curve.h @@ -32,15 +32,16 @@ #define __ED_CURVE_H__ struct bContext; +struct BezTriple; +struct BPoint; +struct Curve; +struct EditNurb; +struct Main; struct Nurb; struct Object; struct Text; struct wmOperator; struct wmKeyConfig; -struct Curve; -struct EditNurb; -struct BezTriple; -struct BPoint; struct UndoType; /* curve_ops.c */ @@ -51,7 +52,7 @@ void ED_keymap_curve(struct wmKeyConfig *keyconf); /* editcurve.c */ struct ListBase *object_editcurve_get(struct Object *ob); -void ED_curve_editnurb_load(struct Object *obedit); +void ED_curve_editnurb_load(struct Main *bmain, struct Object *obedit); void ED_curve_editnurb_make(struct Object *obedit); void ED_curve_editnurb_free(struct Object *obedit); diff --git a/source/blender/editors/include/ED_keyframing.h b/source/blender/editors/include/ED_keyframing.h index 9c33f835b74..5882c44a9b3 100644 --- a/source/blender/editors/include/ED_keyframing.h +++ b/source/blender/editors/include/ED_keyframing.h @@ -71,7 +71,7 @@ short ANIM_get_keyframing_flags(struct Scene *scene, short incl_mode); /* Get (or add relevant data to be able to do so) the Active Action for the given * Animation Data block, given an ID block where the Animation Data should reside. */ -struct bAction *verify_adt_action(struct ID *id, short add); +struct bAction *verify_adt_action(struct Main *bmain, struct ID *id, short add); /* Get (or add relevant data to be able to do so) F-Curve from the given Action. * This assumes that all the destinations are valid. @@ -117,7 +117,9 @@ bool insert_keyframe_direct(struct Depsgraph *depsgraph, struct ReportList *repo * Use this to create any necessary animation data, and then insert a keyframe * using the current value being keyframed, in the relevant place. Returns success. */ -short insert_keyframe(struct Depsgraph *depsgraph, struct ReportList *reports, struct ID *id, struct bAction *act, const char group[], const char rna_path[], int array_index, float cfra, eBezTriple_KeyframeType keytype, eInsertKeyFlags flag); +short insert_keyframe( + struct Main *bmain, struct Depsgraph *depsgraph, struct ReportList *reports, struct ID *id, struct bAction *act, + const char group[], const char rna_path[], int array_index, float cfra, eBezTriple_KeyframeType keytype, eInsertKeyFlags flag); /* Main Keyframing API call: * Use this to delete keyframe on current frame for relevant channel. Will perform checks just in case. diff --git a/source/blender/editors/include/ED_object.h b/source/blender/editors/include/ED_object.h index c793c0aad2b..71b713da0d0 100644 --- a/source/blender/editors/include/ED_object.h +++ b/source/blender/editors/include/ED_object.h @@ -126,7 +126,7 @@ enum { EM_NO_CONTEXT = (1 << 4), }; bool ED_object_editmode_exit_ex( - struct Scene *scene, struct Object *obedit, int flag); + struct Main *bmain, struct Scene *scene, struct Object *obedit, int flag); bool ED_object_editmode_exit(struct bContext *C, int flag); bool ED_object_editmode_enter_ex(struct Main *bmain, struct Scene *scene, struct Object *ob, int flag); @@ -151,7 +151,7 @@ void ED_object_wpaintmode_exit_ex(struct Object *ob); void ED_object_wpaintmode_exit(struct bContext *C); void ED_object_sculptmode_enter_ex( - struct Depsgraph *depsgraph, + struct Main *bmain, struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, struct ReportList *reports); void ED_object_sculptmode_enter(struct bContext *C, struct ReportList *reports); diff --git a/source/blender/editors/include/ED_screen.h b/source/blender/editors/include/ED_screen.h index 63485800a9b..cd1fb1f91d8 100644 --- a/source/blender/editors/include/ED_screen.h +++ b/source/blender/editors/include/ED_screen.h @@ -160,7 +160,7 @@ ScrArea *ED_screen_areas_iter_next(const bScreen *screen, const ScrArea *area); vert_name = (vert_name == (win)->global_areas.vertbase.last) ? (screen)->vertbase.first : vert_name->next) /* screens */ -void ED_screens_initialize(struct wmWindowManager *wm); +void ED_screens_initialize(struct Main *bmain, struct wmWindowManager *wm); void ED_screen_draw_edges(struct wmWindow *win); void ED_screen_draw_join_shape(struct ScrArea *sa1, struct ScrArea *sa2); void ED_screen_draw_split_preview(struct ScrArea *sa, const int dir, const float fac); @@ -211,10 +211,12 @@ void ED_workspace_view_layer_unset( const struct Main *bmain, struct Scene *scene, const ViewLayer *layer_unset, ViewLayer *layer_new) ATTR_NONNULL(1, 2); struct WorkSpaceLayout *ED_workspace_layout_add( + struct Main *bmain, struct WorkSpace *workspace, struct wmWindow *win, const char *name) ATTR_NONNULL(); struct WorkSpaceLayout *ED_workspace_layout_duplicate( + struct Main *bmain, struct WorkSpace *workspace, const struct WorkSpaceLayout *layout_old, struct wmWindow *win) ATTR_NONNULL(); bool ED_workspace_layout_delete( diff --git a/source/blender/editors/include/ED_transform_snap_object_context.h b/source/blender/editors/include/ED_transform_snap_object_context.h index 18d5101ebf7..8ac7dfcf9d8 100644 --- a/source/blender/editors/include/ED_transform_snap_object_context.h +++ b/source/blender/editors/include/ED_transform_snap_object_context.h @@ -79,9 +79,9 @@ struct SnapObjectParams { typedef struct SnapObjectContext SnapObjectContext; SnapObjectContext *ED_transform_snap_object_context_create( - struct Scene *scene, struct Depsgraph *depsgraph, int flag); + struct Main *bmain, struct Scene *scene, struct Depsgraph *depsgraph, int flag); SnapObjectContext *ED_transform_snap_object_context_create_view3d( - struct Scene *scene, struct Depsgraph *depsgraph, int flag, + struct Main *bmain, struct Scene *scene, struct Depsgraph *depsgraph, int flag, /* extra args for view3d */ const struct ARegion *ar, const struct View3D *v3d); void ED_transform_snap_object_context_destroy(SnapObjectContext *sctx); diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h index f00982d4102..24e5b3e2662 100644 --- a/source/blender/editors/include/ED_view3d.h +++ b/source/blender/editors/include/ED_view3d.h @@ -75,6 +75,7 @@ enum eGPUFXFlags; /* for derivedmesh drawing callbacks, for view3d_select, .... */ typedef struct ViewContext { + struct Main *bmain; struct Depsgraph *depsgraph; struct Scene *scene; struct ViewLayer *view_layer; @@ -331,7 +332,8 @@ bool ED_view3d_autodist( const bool alphaoverride, const float fallback_depth_pt[3]); /* only draw so ED_view3d_autodist_simple can be called many times after */ -void ED_view3d_autodist_init(struct Depsgraph *depsgraph, struct ARegion *ar, struct View3D *v3d, int mode); +void ED_view3d_autodist_init( + struct Depsgraph *depsgraph, struct ARegion *ar, struct View3D *v3d, int mode); bool ED_view3d_autodist_simple(struct ARegion *ar, const int mval[2], float mouse_worldloc[3], int margin, float *force_depth); bool ED_view3d_autodist_depth(struct ARegion *ar, const int mval[2], int margin, float *depth); bool ED_view3d_autodist_depth_seg(struct ARegion *ar, const int mval_sta[2], const int mval_end[2], int margin, float *depth); diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index 4d1f1350047..a283068853c 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -828,6 +828,7 @@ struct Panel *UI_panel_begin(struct ScrArea *sa, struct ARegion *ar, struct List bool *r_open); void UI_panel_end(uiBlock *block, int width, int height); void UI_panels_scale(struct ARegion *ar, float new_width); +void UI_panel_label_offset(struct uiBlock *block, int *x, int *y); bool UI_panel_category_is_visible(struct ARegion *ar); void UI_panel_category_add(struct ARegion *ar, const char *name); @@ -859,7 +860,7 @@ void UI_popup_handlers_remove_all(struct bContext *C, struct ListBase *handlers) * be used to reinitialize some internal state if user preferences change. */ void UI_init(void); -void UI_init_userdef(void); +void UI_init_userdef(struct Main *bmain); void UI_reinit_font(void); void UI_exit(void); @@ -1244,10 +1245,10 @@ void UI_widgetbase_draw_cache_flush(void); void UI_widgetbase_draw_cache_end(void); /* Special drawing for toolbar, mainly workarounds for inflexible icon sizing. */ -#define USE_TOOLBAR_HACK +#define USE_UI_TOOLBAR_HACK /* Support click-drag motion which presses the button and closes a popover (like a menu). */ -#define USE_POPOVER_ONCE +#define USE_UI_POPOVER_ONCE bool UI_but_is_tool(const uiBut *but); diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c index 6cb667cb9a8..28f4c40469a 100644 --- a/source/blender/editors/interface/interface.c +++ b/source/blender/editors/interface/interface.c @@ -53,10 +53,11 @@ #include "BKE_animsys.h" #include "BKE_context.h" -#include "BKE_unit.h" +#include "BKE_idprop.h" +#include "BKE_main.h" #include "BKE_scene.h" #include "BKE_screen.h" -#include "BKE_idprop.h" +#include "BKE_unit.h" #include "GPU_glew.h" #include "GPU_matrix.h" @@ -4694,10 +4695,10 @@ void UI_init(void) } /* after reading userdef file */ -void UI_init_userdef(void) +void UI_init_userdef(Main *bmain) { /* fix saved themes */ - init_userdef_do_versions(); + init_userdef_do_versions(bmain); uiStyleInit(); } diff --git a/source/blender/editors/interface/interface_anim.c b/source/blender/editors/interface/interface_anim.c index ea1b58107bd..fc0ad7e5dce 100644 --- a/source/blender/editors/interface/interface_anim.c +++ b/source/blender/editors/interface/interface_anim.c @@ -41,6 +41,7 @@ #include "BKE_context.h" #include "BKE_fcurve.h" #include "BKE_global.h" +#include "BKE_main.h" #include "BKE_nla.h" #include "DEG_depsgraph.h" @@ -226,6 +227,7 @@ bool ui_but_anim_expression_create(uiBut *but, const char *str) void ui_but_anim_autokey(bContext *C, uiBut *but, Scene *scene, float cfra) { + Main *bmain = CTX_data_main(C); ID *id; bAction *action; FCurve *fcu; @@ -277,7 +279,7 @@ void ui_but_anim_autokey(bContext *C, uiBut *but, Scene *scene, float cfra) * because a button may control all items of an array at once. * E.g., color wheels (see T42567). */ BLI_assert((fcu->array_index == but->rnaindex) || (but->rnaindex == -1)); - insert_keyframe(depsgraph, reports, id, action, + insert_keyframe(bmain, depsgraph, reports, id, action, ((fcu->grp) ? (fcu->grp->name) : (NULL)), fcu->rna_path, but->rnaindex, cfra, ts->keyframe_type, flag); diff --git a/source/blender/editors/interface/interface_eyedropper_depth.c b/source/blender/editors/interface/interface_eyedropper_depth.c index bd23fbb961d..df09c327da1 100644 --- a/source/blender/editors/interface/interface_eyedropper_depth.c +++ b/source/blender/editors/interface/interface_eyedropper_depth.c @@ -41,6 +41,7 @@ #include "BLI_math_vector.h" #include "BKE_context.h" +#include "BKE_main.h" #include "BKE_screen.h" #include "BKE_unit.h" diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index 0ebe079703b..b05dbe9c3b0 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -506,7 +506,7 @@ bool ui_but_is_toggle(const uiBut *but) ); } -#ifdef USE_POPOVER_ONCE +#ifdef USE_UI_POPOVER_ONCE bool ui_but_is_popover_once_compat(const uiBut *but) { return ( @@ -1400,7 +1400,7 @@ static int ui_handler_region_drag_toggle(bContext *C, const wmEvent *event, void switch (event->type) { case LEFTMOUSE: { - if (event->val != KM_PRESS) { + if (event->val == KM_RELEASE) { done = true; } break; @@ -3594,7 +3594,7 @@ static int ui_do_but_BUT( button_activate_state(C, but, BUTTON_STATE_WAIT_RELEASE); return WM_UI_HANDLER_BREAK; } - else if (event->type == LEFTMOUSE && but->block->handle) { + else if (event->type == LEFTMOUSE && event->val == KM_RELEASE && but->block->handle) { /* regular buttons will be 'UI_SELECT', menu items 'UI_ACTIVE' */ if (!(but->flag & (UI_SELECT | UI_ACTIVE))) data->cancel = true; @@ -3607,7 +3607,7 @@ static int ui_do_but_BUT( } } else if (data->state == BUTTON_STATE_WAIT_RELEASE) { - if (event->type == LEFTMOUSE && event->val != KM_PRESS) { + if (event->type == LEFTMOUSE && event->val == KM_RELEASE) { if (!(but->flag & UI_SELECT)) data->cancel = true; button_activate_state(C, but, BUTTON_STATE_EXIT); @@ -4317,7 +4317,7 @@ static int ui_do_but_NUM( button_activate_state(C, but, BUTTON_STATE_EXIT); } } - else if (event->type == LEFTMOUSE && event->val != KM_PRESS) { + else if (event->type == LEFTMOUSE && event->val == KM_RELEASE) { if (data->dragchange) { #ifdef USE_DRAG_MULTINUM /* if we started multibutton but didnt drag, then edit */ @@ -4625,7 +4625,7 @@ static int ui_do_but_SLI( button_activate_state(C, but, BUTTON_STATE_EXIT); } } - else if (event->type == LEFTMOUSE && event->val != KM_PRESS) { + else if (event->type == LEFTMOUSE && event->val == KM_RELEASE) { if (data->dragchange) { #ifdef USE_DRAG_MULTINUM /* if we started multibutton but didnt drag, then edit */ @@ -4778,7 +4778,7 @@ static int ui_do_but_SCROLL( button_activate_state(C, but, BUTTON_STATE_EXIT); } } - else if (event->type == LEFTMOUSE && event->val != KM_PRESS) { + else if (event->type == LEFTMOUSE && event->val == KM_RELEASE) { button_activate_state(C, but, BUTTON_STATE_EXIT); } else if (event->type == MOUSEMOVE) { @@ -4830,7 +4830,7 @@ static int ui_do_but_GRIP( button_activate_state(C, but, BUTTON_STATE_EXIT); } } - else if (event->type == LEFTMOUSE && event->val != KM_PRESS) { + else if (event->type == LEFTMOUSE && event->val == KM_RELEASE) { button_activate_state(C, but, BUTTON_STATE_EXIT); } else if (event->type == MOUSEMOVE) { @@ -5216,7 +5216,7 @@ static int ui_do_but_UNITVEC( ui_numedit_apply(C, block, but, data); } } - else if (event->type == LEFTMOUSE && event->val != KM_PRESS) { + else if (event->type == LEFTMOUSE && event->val == KM_RELEASE) { button_activate_state(C, but, BUTTON_STATE_EXIT); } @@ -5550,7 +5550,7 @@ static int ui_do_but_HSVCUBE( ui_numedit_apply(C, block, but, data); } } - else if (event->type == LEFTMOUSE && event->val != KM_PRESS) { + else if (event->type == LEFTMOUSE && event->val == KM_RELEASE) { button_activate_state(C, but, BUTTON_STATE_EXIT); } @@ -5828,7 +5828,7 @@ static int ui_do_but_HSVCIRCLE( } } } - else if (event->type == LEFTMOUSE && event->val != KM_PRESS) { + else if (event->type == LEFTMOUSE && event->val == KM_RELEASE) { button_activate_state(C, but, BUTTON_STATE_EXIT); } return WM_UI_HANDLER_BREAK; @@ -5918,7 +5918,7 @@ static int ui_do_but_COLORBAND( ui_numedit_apply(C, block, but, data); } } - else if (event->type == LEFTMOUSE && event->val != KM_PRESS) { + else if (event->type == LEFTMOUSE && event->val == KM_RELEASE) { button_activate_state(C, but, BUTTON_STATE_EXIT); } else if (ELEM(event->type, ESCKEY, RIGHTMOUSE)) { @@ -6169,7 +6169,7 @@ static int ui_do_but_CURVE( ui_numedit_apply(C, block, but, data); } } - else if (event->type == LEFTMOUSE && event->val != KM_PRESS) { + else if (event->type == LEFTMOUSE && event->val == KM_RELEASE) { if (data->dragsel != -1) { CurveMapping *cumap = (CurveMapping *)but->poin; CurveMap *cuma = cumap->cm + cumap->cur; @@ -6267,7 +6267,7 @@ static int ui_do_but_HISTOGRAM( ui_numedit_apply(C, block, but, data); } } - else if (event->type == LEFTMOUSE && event->val != KM_PRESS) { + else if (event->type == LEFTMOUSE && event->val == KM_RELEASE) { button_activate_state(C, but, BUTTON_STATE_EXIT); } return WM_UI_HANDLER_BREAK; @@ -6342,7 +6342,7 @@ static int ui_do_but_WAVEFORM( ui_numedit_apply(C, block, but, data); } } - else if (event->type == LEFTMOUSE && event->val != KM_PRESS) { + else if (event->type == LEFTMOUSE && event->val == KM_RELEASE) { button_activate_state(C, but, BUTTON_STATE_EXIT); } return WM_UI_HANDLER_BREAK; @@ -6426,7 +6426,7 @@ static int ui_do_but_TRACKPREVIEW( ui_numedit_apply(C, block, but, data); } } - else if (event->type == LEFTMOUSE && event->val != KM_PRESS) { + else if (event->type == LEFTMOUSE && event->val == KM_RELEASE) { button_activate_state(C, but, BUTTON_STATE_EXIT); } return WM_UI_HANDLER_BREAK; @@ -8362,7 +8362,7 @@ static int ui_handle_button_event(bContext *C, const wmEvent *event, uiBut *but) data->cancel = true; button_activate_state(C, but, BUTTON_STATE_EXIT); break; -#ifdef USE_POPOVER_ONCE +#ifdef USE_UI_POPOVER_ONCE case LEFTMOUSE: { if (event->val == KM_RELEASE) { @@ -9527,7 +9527,7 @@ static int ui_handle_menu_event( retval = ui_handle_menu_button(C, event, menu); } -#ifdef USE_POPOVER_ONCE +#ifdef USE_UI_POPOVER_ONCE if (block->flag & UI_BLOCK_POPOVER_ONCE) { if ((event->type == LEFTMOUSE) && (event->val == KM_RELEASE)) { UI_popover_once_clear(menu->popup_create_vars.arg); diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c index 2c813d152e9..c2ada1e3733 100644 --- a/source/blender/editors/interface/interface_icons.c +++ b/source/blender/editors/interface/interface_icons.c @@ -1252,7 +1252,7 @@ static void icon_draw_size( /* We need to flush widget base first to ensure correct ordering. */ UI_widgetbase_draw_cache_flush(); -#ifdef USE_TOOLBAR_HACK +#ifdef USE_UI_TOOLBAR_HACK /* TODO(campbell): scale icons up for toolbar, we need a way to detect larger buttons and do this automatic. */ { float scale = (float)ICON_DEFAULT_HEIGHT_TOOLBAR / (float)ICON_DEFAULT_HEIGHT; diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h index c7cf03a44dd..b5bf9be737b 100644 --- a/source/blender/editors/interface/interface_intern.h +++ b/source/blender/editors/interface/interface_intern.h @@ -784,7 +784,7 @@ void ui_icon_ensure_deferred(const struct bContext *C, const int icon_id, const int ui_id_icon_get(const struct bContext *C, struct ID *id, const bool big); /* resources.c */ -void init_userdef_do_versions(void); +void init_userdef_do_versions(struct Main *bmain); void ui_theme_init_default(void); void ui_style_init_default(void); void ui_resources_init(void); diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c index ea40c8e8fd8..b3bd98c7b94 100644 --- a/source/blender/editors/interface/interface_layout.c +++ b/source/blender/editors/interface/interface_layout.c @@ -701,6 +701,7 @@ static uiBut *ui_item_with_label( PropertyType type; PropertySubType subtype; int prop_but_width = w_hint; + const bool use_prop_sep = ((layout->item.flag & UI_ITEM_PROP_SEP) != 0); sub = uiLayoutRow(layout, layout->align); UI_block_layout_set_current(block, sub); @@ -708,15 +709,25 @@ static uiBut *ui_item_with_label( if (name[0]) { int w_label; - if (ui_layout_vary_direction(layout) == UI_ITEM_VARY_X) { - /* w_hint is width for label in this case. Use a default width for property button(s) */ - prop_but_width = UI_UNIT_X * 5; - w_label = w_hint; + if (use_prop_sep) { + w_label = (int)((w_hint * 2) * UI_ITEM_PROP_SEP_DIVIDE); } else { - w_label = w_hint / 3; + if (ui_layout_vary_direction(layout) == UI_ITEM_VARY_X) { + /* w_hint is width for label in this case. Use a default width for property button(s) */ + prop_but_width = UI_UNIT_X * 5; + w_label = w_hint; + } + else { + w_label = w_hint / 3; + } + } + + uiBut *but_label = uiDefBut(block, UI_BTYPE_LABEL, 0, name, x, y, w_label, h, NULL, 0.0, 0.0, 0, 0, ""); + if (use_prop_sep) { + but_label->drawflag |= UI_BUT_TEXT_RIGHT; + but_label->drawflag &= ~UI_BUT_TEXT_LEFT; } - uiDefBut(block, UI_BTYPE_LABEL, 0, name, x, y, w_label, h, NULL, 0.0, 0.0, 0, 0, ""); } type = RNA_property_type(prop); @@ -1851,6 +1862,7 @@ void uiItemPointerR(uiLayout *layout, struct PointerRNA *ptr, const char *propna StructRNA *icontype; int w, h; char namestr[UI_MAX_NAME_STR]; + const bool use_prop_sep = ((layout->item.flag & UI_ITEM_PROP_SEP) != 0); /* validate arguments */ prop = RNA_struct_find_property(ptr, propname); @@ -1893,7 +1905,9 @@ void uiItemPointerR(uiLayout *layout, struct PointerRNA *ptr, const char *propna if (!name) name = RNA_property_ui_name(prop); - name = ui_item_name_add_colon(name, namestr); + if (use_prop_sep == false) { + name = ui_item_name_add_colon(name, namestr); + } /* create button */ block = uiLayoutGetBlock(layout); diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c index 5c2fb0e7aaa..6fcede58737 100644 --- a/source/blender/editors/interface/interface_ops.c +++ b/source/blender/editors/interface/interface_ops.c @@ -957,7 +957,7 @@ static int editsource_text_edit( } if (text == NULL) { - text = BKE_text_load(bmain, filepath, bmain->name); + text = BKE_text_load(bmain, filepath, BKE_main_blendfile_path(bmain)); id_us_ensure_real(&text->id); } diff --git a/source/blender/editors/interface/interface_panel.c b/source/blender/editors/interface/interface_panel.c index 3847aa72519..dbdf2a0863c 100644 --- a/source/blender/editors/interface/interface_panel.c +++ b/source/blender/editors/interface/interface_panel.c @@ -612,6 +612,20 @@ static void ui_draw_panel_dragwidget(unsigned int pos, unsigned int col, const r immEnd(); } +/* For button layout next to label. */ +void UI_panel_label_offset(uiBlock *block, int *x, int *y) +{ + Panel *panel = block->panel; + uiStyle *style = UI_style_get_dpi(); + const bool is_subpanel = (panel->type && panel->type->parent); + + *x = UI_UNIT_X * 1.1f; + *y = (UI_UNIT_Y * 1.1f) + style->panelspace; + + if (is_subpanel) { + *x += 5.0f / block->aspect; + } +} static void ui_draw_aligned_panel_header(uiStyle *style, uiBlock *block, const rcti *rect, char dir) { @@ -619,6 +633,8 @@ static void ui_draw_aligned_panel_header(uiStyle *style, uiBlock *block, const r rcti hrect; int pnl_icons; const char *activename = panel->drawname[0] ? panel->drawname : panel->panelname; + const bool is_subpanel = (panel->type && panel->type->parent); + uiFontStyle *fontstyle = (is_subpanel) ? &style->widgetlabel : &style->paneltitle; unsigned char col_title[4]; /* + 0.001f to avoid flirting with float inaccuracy */ @@ -635,14 +651,14 @@ static void ui_draw_aligned_panel_header(uiStyle *style, uiBlock *block, const r if (dir == 'h') { hrect.xmin = rect->xmin + pnl_icons; hrect.ymin += 2.0f / block->aspect; - UI_fontstyle_draw(&style->paneltitle, &hrect, activename, col_title); + UI_fontstyle_draw(fontstyle, &hrect, activename, col_title); } else { /* ignore 'pnl_icons', otherwise the text gets offset horizontally * + 0.001f to avoid flirting with float inaccuracy */ hrect.xmin = rect->xmin + (PNL_ICON + 5) / block->aspect + 0.001f; - UI_fontstyle_draw_rotated(&style->paneltitle, &hrect, activename, col_title); + UI_fontstyle_draw_rotated(fontstyle, &hrect, activename, col_title); } } @@ -667,6 +683,11 @@ void ui_draw_aligned_panel(uiStyle *style, uiBlock *block, const rcti *rect, con headrect.ymin = headrect.ymax; headrect.ymax = headrect.ymin + floor(PNL_HEADER / block->aspect + 0.001f); + rcti titlerect = headrect; + if (is_subpanel) { + titlerect.xmin += 5.0f / block->aspect; + } + unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); @@ -738,7 +759,7 @@ void ui_draw_aligned_panel(uiStyle *style, uiBlock *block, const rcti *rect, con /* horizontal title */ if (is_closed_x == false) { - ui_draw_aligned_panel_header(style, block, &headrect, 'h'); + ui_draw_aligned_panel_header(style, block, &titlerect, 'h'); if (show_drag) { unsigned int col; @@ -817,10 +838,10 @@ void ui_draw_aligned_panel(uiStyle *style, uiBlock *block, const rcti *rect, con /* draw collapse icon */ /* itemrect smaller */ - itemrect.xmin = headrect.xmin + 3.0f / block->aspect; - itemrect.xmax = itemrect.xmin + BLI_rcti_size_y(&headrect); - itemrect.ymin = headrect.ymin; - itemrect.ymax = headrect.ymax; + itemrect.xmin = titlerect.xmin + 3.0f / block->aspect; + itemrect.xmax = itemrect.xmin + BLI_rcti_size_y(&titlerect); + itemrect.ymin = titlerect.ymin; + itemrect.ymax = titlerect.ymax; BLI_rctf_scale(&itemrect, 0.25f); @@ -2284,7 +2305,7 @@ static int ui_handler_panel(bContext *C, const wmEvent *event, void *userdata) uiHandlePanelData *data = panel->activedata; /* verify if we can stop */ - if (event->type == LEFTMOUSE && event->val != KM_PRESS) { + if (event->type == LEFTMOUSE && event->val == KM_RELEASE) { ScrArea *sa = CTX_wm_area(C); ARegion *ar = CTX_wm_region(C); int align = panel_aligned(sa, ar); diff --git a/source/blender/editors/interface/interface_region_menu_pie.c b/source/blender/editors/interface/interface_region_menu_pie.c index 0c43b787a84..504e1807a8f 100644 --- a/source/blender/editors/interface/interface_region_menu_pie.c +++ b/source/blender/editors/interface/interface_region_menu_pie.c @@ -150,8 +150,16 @@ uiPieMenu *UI_pie_menu_begin(struct bContext *C, const char *title, int icon, co } pie->layout = UI_block_layout(pie->block_radial, UI_LAYOUT_VERTICAL, UI_LAYOUT_PIEMENU, 0, 0, 200, 0, 0, style); - pie->mx = event->x; - pie->my = event->y; + + /* Open from where we started dragging. */ + if (event->val == KM_CLICK_DRAG) { + pie->mx = event->prevclickx; + pie->my = event->prevclicky; + } + else { + pie->mx = event->x; + pie->my = event->y; + } /* create title button */ if (title[0]) { diff --git a/source/blender/editors/interface/interface_region_popover.c b/source/blender/editors/interface/interface_region_popover.c index 9d10713c868..c681cfe776f 100644 --- a/source/blender/editors/interface/interface_region_popover.c +++ b/source/blender/editors/interface/interface_region_popover.c @@ -87,7 +87,7 @@ struct uiPopover { uiMenuCreateFunc menu_func; void *menu_arg; -#ifdef USE_POPOVER_ONCE +#ifdef USE_UI_POPOVER_ONCE bool is_once; #endif }; @@ -136,7 +136,7 @@ static uiBlock *ui_block_func_POPOVER(bContext *C, uiPopupBlockHandle *handle, v UI_block_region_set(block, handle->region); UI_block_layout_resolve(block, &width, &height); UI_block_flag_enable(block, UI_BLOCK_MOVEMOUSE_QUIT | UI_BLOCK_KEEP_OPEN | UI_BLOCK_POPOVER); -#ifdef USE_POPOVER_ONCE +#ifdef USE_UI_POPOVER_ONCE if (pup->is_once) { UI_block_flag_enable(block, UI_BLOCK_POPOVER_ONCE); } @@ -231,7 +231,7 @@ uiPopupBlockHandle *ui_popover_panel_create( pup->menu_func = menu_func; pup->menu_arg = arg; -#ifdef USE_POPOVER_ONCE +#ifdef USE_UI_POPOVER_ONCE pup->is_once = true; #endif @@ -365,7 +365,7 @@ uiLayout *UI_popover_layout(uiPopover *pup) return pup->layout; } -#ifdef USE_POPOVER_ONCE +#ifdef USE_UI_POPOVER_ONCE void UI_popover_once_clear(uiPopover *pup) { pup->is_once = false; diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index d934d4dd1e4..9978726fa74 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -3970,7 +3970,9 @@ eAutoPropButsReturn uiTemplateOperatorPropertyButs( #endif /* set various special settings for buttons */ - { + + /* Only do this if we're not refreshing an existing UI. */ + if (block->oldblock == NULL) { const bool is_popup = (block->flag & UI_BLOCK_KEEP_OPEN) != 0; uiBut *but; diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c index 928ac8c9171..3188bc847a7 100644 --- a/source/blender/editors/interface/interface_widgets.c +++ b/source/blender/editors/interface/interface_widgets.c @@ -2008,11 +2008,20 @@ static void widget_draw_text_icon(uiFontStyle *fstyle, uiWidgetColors *wcol, uiB else if (but->flag & UI_HAS_ICON || show_menu_icon) { const bool is_tool = UI_but_is_tool(but); + /* XXX add way to draw icons at a different size! + * Use small icons for popup. */ +#ifdef USE_UI_TOOLBAR_HACK + const float aspect_orig = but->block->aspect; + if (is_tool && (but->block->flag & UI_BLOCK_POPOVER)) { + but->block->aspect *= 2.0f; + } +#endif + const BIFIconID icon = (but->flag & UI_HAS_ICON) ? but->icon + but->iconadd : ICON_NONE; int icon_size_init = is_tool ? ICON_DEFAULT_HEIGHT_TOOLBAR : ICON_DEFAULT_HEIGHT; const float icon_size = icon_size_init / (but->block->aspect / UI_DPI_FAC); -#ifdef USE_TOOLBAR_HACK +#ifdef USE_UI_TOOLBAR_HACK if (is_tool) { /* pass (even if its a menu toolbar) */ but->drawflag |= UI_BUT_TEXT_LEFT; @@ -2034,6 +2043,10 @@ static void widget_draw_text_icon(uiFontStyle *fstyle, uiWidgetColors *wcol, uiB widget_draw_icon(but, icon, alpha, rect, show_menu_icon); +#ifdef USE_UI_TOOLBAR_HACK + but->block->aspect = aspect_orig; +#endif + rect->xmin += icon_size; /* without this menu keybindings will overlap the arrow icon [#38083] */ if (show_menu_icon) { @@ -4359,7 +4372,7 @@ void ui_draw_but(const bContext *C, ARegion *ar, uiStyle *style, uiBut *but, rct uiFontStyle *fstyle = &style->widget; uiWidgetType *wt = NULL; -#ifdef USE_POPOVER_ONCE +#ifdef USE_UI_POPOVER_ONCE const rcti rect_orig = *rect; #endif @@ -4413,7 +4426,7 @@ void ui_draw_but(const bContext *C, ARegion *ar, uiStyle *style, uiBut *but, rct break; case UI_BTYPE_BUT: -#ifdef USE_TOOLBAR_HACK +#ifdef USE_UI_TOOLBAR_HACK if (UI_but_is_tool(but)) { wt = widget_type(UI_WTYPE_TOOLBAR_ITEM); } @@ -4639,7 +4652,7 @@ void ui_draw_but(const bContext *C, ARegion *ar, uiStyle *style, uiBut *but, rct if (disabled) glEnable(GL_BLEND); -#ifdef USE_POPOVER_ONCE +#ifdef USE_UI_POPOVER_ONCE if (but->block->flag & UI_BLOCK_POPOVER_ONCE) { if ((state & UI_ACTIVE) && ui_but_is_popover_once_compat(but)) { uiWidgetType wt_back = *wt; diff --git a/source/blender/editors/interface/resources.c b/source/blender/editors/interface/resources.c index 1bfb050563d..2a61be21589 100644 --- a/source/blender/editors/interface/resources.c +++ b/source/blender/editors/interface/resources.c @@ -1818,10 +1818,8 @@ void UI_make_axis_color(const unsigned char src_col[3], unsigned char dst_col[3] /* ************************************************************* */ /* patching UserDef struct and Themes */ -void init_userdef_do_versions(void) +void init_userdef_do_versions(Main *bmain) { - Main *bmain = G.main; - #define USER_VERSION_ATLEAST(ver, subver) MAIN_VERSION_ATLEAST(bmain, ver, subver) /* the UserDef struct is not corrected with do_versions() .... ugh! */ diff --git a/source/blender/editors/io/io_alembic.c b/source/blender/editors/io/io_alembic.c index b584782e183..4440b99f211 100644 --- a/source/blender/editors/io/io_alembic.c +++ b/source/blender/editors/io/io_alembic.c @@ -79,11 +79,11 @@ static int wm_alembic_export_invoke(bContext *C, wmOperator *op, const wmEvent * Main *bmain = CTX_data_main(C); char filepath[FILE_MAX]; - if (bmain->name[0] == '\0') { + if (BKE_main_blendfile_path(bmain)[0] == '\0') { BLI_strncpy(filepath, "untitled", sizeof(filepath)); } else { - BLI_strncpy(filepath, bmain->name, sizeof(filepath)); + BLI_strncpy(filepath, BKE_main_blendfile_path(bmain), sizeof(filepath)); } BLI_replace_extension(filepath, sizeof(filepath), ".abc"); @@ -422,12 +422,12 @@ static int get_sequence_len(char *filename, int *ofs) } char path[FILE_MAX]; - BLI_path_abs(filename, G.main->name); + BLI_path_abs(filename, BKE_main_blendfile_path_from_global()); BLI_split_dir_part(filename, path, FILE_MAX); if (path[0] == '\0') { /* The filename had no path, so just use the blend file path. */ - BLI_split_dir_part(G.main->name, path, FILE_MAX); + BLI_split_dir_part(BKE_main_blendfile_path_from_global(), path, FILE_MAX); } DIR *dir = opendir(path); diff --git a/source/blender/editors/io/io_cache.c b/source/blender/editors/io/io_cache.c index eb79d0bec13..b13eaced843 100644 --- a/source/blender/editors/io/io_cache.c +++ b/source/blender/editors/io/io_cache.c @@ -60,7 +60,7 @@ static int cachefile_open_invoke(bContext *C, wmOperator *op, const wmEvent *eve char filepath[FILE_MAX]; Main *bmain = CTX_data_main(C); - BLI_strncpy(filepath, bmain->name, sizeof(filepath)); + BLI_strncpy(filepath, BKE_main_blendfile_path(bmain), sizeof(filepath)); BLI_replace_extension(filepath, sizeof(filepath), ".abc"); RNA_string_set(op->ptr, "filepath", filepath); } diff --git a/source/blender/editors/io/io_collada.c b/source/blender/editors/io/io_collada.c index bb0280875bd..aca380c3123 100644 --- a/source/blender/editors/io/io_collada.c +++ b/source/blender/editors/io/io_collada.c @@ -61,13 +61,16 @@ static int wm_collada_export_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { + Main *bmain = CTX_data_main(C); + if (!RNA_struct_property_is_set(op->ptr, "filepath")) { char filepath[FILE_MAX]; + const char *blendfile_path = BKE_main_blendfile_path(bmain); - if (G.main->name[0] == 0) + if (blendfile_path[0] == '\0') BLI_strncpy(filepath, "untitled", sizeof(filepath)); else - BLI_strncpy(filepath, G.main->name, sizeof(filepath)); + BLI_strncpy(filepath, blendfile_path, sizeof(filepath)); BLI_replace_extension(filepath, sizeof(filepath), ".dae"); RNA_string_set(op->ptr, "filepath", filepath); @@ -202,9 +205,11 @@ static int wm_collada_export_exec(bContext *C, wmOperator *op) if (export_settings.include_armatures) includeFilter |= OB_REL_MOD_ARMATURE; if (export_settings.include_children) includeFilter |= OB_REL_CHILDREN_RECURSIVE; - export_count = collada_export(CTX_data_depsgraph(C), - scene, - &export_settings + export_count = collada_export( + C, + CTX_data_depsgraph(C), + scene, + &export_settings ); if (export_count == 0) { diff --git a/source/blender/editors/mesh/editmesh_knife_project.c b/source/blender/editors/mesh/editmesh_knife_project.c index 5a61c5aab48..5ccbcf063ad 100644 --- a/source/blender/editors/mesh/editmesh_knife_project.c +++ b/source/blender/editors/mesh/editmesh_knife_project.c @@ -40,6 +40,7 @@ #include "BKE_curve.h" #include "BKE_cdderivedmesh.h" #include "BKE_editmesh.h" +#include "BKE_mesh_runtime.h" #include "BKE_report.h" #include "DEG_depsgraph.h" diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c index 5c6b6da54a6..17f643636cf 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -359,6 +359,7 @@ void MESH_OT_unsubdivide(wmOperatorType *ot) void EMBM_project_snap_verts(bContext *C, ARegion *ar, BMEditMesh *em) { + Main *bmain = CTX_data_main(C); Object *obedit = em->ob; BMIter iter; BMVert *eve; @@ -366,7 +367,7 @@ void EMBM_project_snap_verts(bContext *C, ARegion *ar, BMEditMesh *em) ED_view3d_init_mats_rv3d(obedit, ar->regiondata); struct SnapObjectContext *snap_context = ED_transform_snap_object_context_create_view3d( - CTX_data_scene(C), CTX_data_depsgraph(C), 0, + bmain, CTX_data_scene(C), CTX_data_depsgraph(C), 0, ar, CTX_wm_view3d(C)); BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { diff --git a/source/blender/editors/mesh/mesh_ops.c b/source/blender/editors/mesh/mesh_ops.c index b3c507affb7..f5c5a85d5ca 100644 --- a/source/blender/editors/mesh/mesh_ops.c +++ b/source/blender/editors/mesh/mesh_ops.c @@ -335,6 +335,24 @@ void ED_keymap_mesh(wmKeyConfig *keyconf) RNA_boolean_set(kmi->ptr, "vertex_only", true); /* selecting */ + + kmi = WM_keymap_add_item(keymap, "MESH_OT_select_mode", ONEKEY, KM_PRESS, 0, 0); + RNA_enum_set(kmi->ptr, "type", SCE_SELECT_VERTEX); + kmi = WM_keymap_add_item(keymap, "MESH_OT_select_mode", TWOKEY, KM_PRESS, 0, 0); + RNA_enum_set(kmi->ptr, "type", SCE_SELECT_EDGE); + kmi = WM_keymap_add_item(keymap, "MESH_OT_select_mode", THREEKEY, KM_PRESS, 0, 0); + RNA_enum_set(kmi->ptr, "type", SCE_SELECT_FACE); + + kmi = WM_keymap_add_item(keymap, "MESH_OT_select_mode", ONEKEY, KM_PRESS, KM_SHIFT, 0); + RNA_enum_set(kmi->ptr, "type", SCE_SELECT_VERTEX); + RNA_boolean_set(kmi->ptr, "use_extend", true); + kmi = WM_keymap_add_item(keymap, "MESH_OT_select_mode", TWOKEY, KM_PRESS, KM_SHIFT, 0); + RNA_enum_set(kmi->ptr, "type", SCE_SELECT_EDGE); + RNA_boolean_set(kmi->ptr, "use_extend", true); + kmi = WM_keymap_add_item(keymap, "MESH_OT_select_mode", THREEKEY, KM_PRESS, KM_SHIFT, 0); + RNA_enum_set(kmi->ptr, "type", SCE_SELECT_FACE); + RNA_boolean_set(kmi->ptr, "use_extend", true); + /* standard mouse selection goes via space_view3d */ kmi = WM_keymap_add_item(keymap, "MESH_OT_loop_select", SELECTMOUSE, KM_PRESS, KM_ALT, 0); RNA_boolean_set(kmi->ptr, "extend", false); diff --git a/source/blender/editors/mesh/meshtools.c b/source/blender/editors/mesh/meshtools.c index 786b27ee816..41e1ca13b79 100644 --- a/source/blender/editors/mesh/meshtools.c +++ b/source/blender/editors/mesh/meshtools.c @@ -54,6 +54,7 @@ #include "BKE_library.h" #include "BKE_main.h" #include "BKE_mesh.h" +#include "BKE_mesh_runtime.h" #include "BKE_material.h" #include "BKE_object.h" #include "BKE_object_deform.h" diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c index d66a176ddfc..37589177037 100644 --- a/source/blender/editors/object/object_add.c +++ b/source/blender/editors/object/object_add.c @@ -82,6 +82,7 @@ #include "BKE_material.h" #include "BKE_mball.h" #include "BKE_mesh.h" +#include "BKE_mesh_runtime.h" #include "BKE_nla.h" #include "BKE_object.h" #include "BKE_particle.h" diff --git a/source/blender/editors/object/object_bake_api.c b/source/blender/editors/object/object_bake_api.c index 677a98cf942..5210182510f 100644 --- a/source/blender/editors/object/object_bake_api.c +++ b/source/blender/editors/object/object_bake_api.c @@ -1021,7 +1021,8 @@ cage_cleanup: BakeData *bake = &scene->r.bake; char name[FILE_MAX]; - BKE_image_path_from_imtype(name, filepath, bmain->name, 0, bake->im_format.imtype, true, false, NULL); + BKE_image_path_from_imtype(name, filepath, BKE_main_blendfile_path(bmain), + 0, bake->im_format.imtype, true, false, NULL); if (is_automatic_name) { BLI_path_suffix(name, FILE_MAX, ob_low->id.name + 2, "_"); diff --git a/source/blender/editors/object/object_constraint.c b/source/blender/editors/object/object_constraint.c index 121a30c754a..3b5a8d190ff 100644 --- a/source/blender/editors/object/object_constraint.c +++ b/source/blender/editors/object/object_constraint.c @@ -152,7 +152,7 @@ bConstraint *get_active_constraint(Object *ob) /* ------------- PyConstraints ------------------ */ /* this callback sets the text-file to be used for selected menu item */ -static void validate_pyconstraint_cb(void *arg1, void *arg2) +static void validate_pyconstraint_cb(Main *bmain, void *arg1, void *arg2) { bPythonConstraint *data = arg1; Text *text = NULL; @@ -162,13 +162,13 @@ static void validate_pyconstraint_cb(void *arg1, void *arg2) /* exception for no script */ if (index) { /* innovative use of a for...loop to search */ - for (text = G.main->text.first, i = 1; text && index != i; i++, text = text->id.next) ; + for (text = bmain->text.first, i = 1; text && index != i; i++, text = text->id.next) ; } data->text = text; } /* this returns a string for the list of usable pyconstraint script names */ -static char *buildmenu_pyconstraints(Text *con_text, int *pyconindex) +static char *buildmenu_pyconstraints(Main *bmain, Text *con_text, int *pyconindex) { DynStr *pupds = BLI_dynstr_new(); Text *text; @@ -185,7 +185,7 @@ static char *buildmenu_pyconstraints(Text *con_text, int *pyconindex) *pyconindex = 0; /* loop through markers, adding them */ - for (text = G.main->text.first, i = 1; text; i++, text = text->id.next) { + for (text = bmain->text.first, i = 1; text; i++, text = text->id.next) { /* this is important to ensure that right script is shown as active */ if (text == con_text) *pyconindex = i; @@ -969,6 +969,7 @@ void CONSTRAINT_OT_childof_clear_inverse(wmOperatorType *ot) static int followpath_path_animate_exec(bContext *C, wmOperator *op) { + Main *bmain = CTX_data_main(C); Object *ob = ED_object_active_context(C); bConstraint *con = edit_constraint_property_get(op, ob, CONSTRAINT_TYPE_FOLLOWPATH); bFollowPathConstraint *data = (con) ? (bFollowPathConstraint *)con->data : NULL; @@ -993,7 +994,7 @@ static int followpath_path_animate_exec(bContext *C, wmOperator *op) (list_find_fcurve(&cu->adt->action->curves, "eval_time", 0) == NULL)) { /* create F-Curve for path animation */ - act = verify_adt_action(&cu->id, 1); + act = verify_adt_action(bmain, &cu->id, 1); fcu = verify_fcurve(act, NULL, NULL, "eval_time", 0, 1); /* standard vertical range - 1:1 = 100 frames */ @@ -1018,7 +1019,7 @@ static int followpath_path_animate_exec(bContext *C, wmOperator *op) path = RNA_path_from_ID_to_property(&ptr, prop); /* create F-Curve for constraint */ - act = verify_adt_action(&ob->id, 1); + act = verify_adt_action(bmain, &ob->id, 1); fcu = verify_fcurve(act, NULL, NULL, path, 0, 1); /* standard vertical range - 0.0 to 1.0 */ @@ -1798,14 +1799,14 @@ static int constraint_add_exec(bContext *C, wmOperator *op, Object *ob, ListBase char *menustr; int scriptint = 0; /* popup a list of usable scripts */ - menustr = buildmenu_pyconstraints(NULL, &scriptint); + menustr = buildmenu_pyconstraints(bmain, NULL, &scriptint); /* XXX scriptint = pupmenu(menustr); */ MEM_freeN(menustr); /* only add constraint if a script was chosen */ if (scriptint) { /* add constraint */ - validate_pyconstraint_cb(con->data, &scriptint); + validate_pyconstraint_cb(bmain, con->data, &scriptint); /* make sure target allowance is set correctly */ BPY_pyconstraint_update(ob, con); diff --git a/source/blender/editors/object/object_data_transfer.c b/source/blender/editors/object/object_data_transfer.c index d4e8955b38e..db81c51cc90 100644 --- a/source/blender/editors/object/object_data_transfer.c +++ b/source/blender/editors/object/object_data_transfer.c @@ -43,6 +43,7 @@ #include "BKE_DerivedMesh.h" #include "BKE_mesh_mapping.h" #include "BKE_mesh_remap.h" +#include "BKE_mesh_runtime.h" #include "BKE_object.h" #include "BKE_report.h" diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c index 9bc01892ef0..d47a2576a8a 100644 --- a/source/blender/editors/object/object_edit.c +++ b/source/blender/editors/object/object_edit.c @@ -209,7 +209,7 @@ static bool ED_object_editmode_load_ex(Main *bmain, Object *obedit, const bool f if (arm->edbo == NULL) { return false; } - ED_armature_from_edit(obedit->data); + ED_armature_from_edit(bmain, obedit->data); if (freedata) { ED_armature_edit_free(obedit->data); } @@ -224,7 +224,7 @@ static bool ED_object_editmode_load_ex(Main *bmain, Object *obedit, const bool f if (cu->editnurb == NULL) { return false; } - ED_curve_editnurb_load(obedit); + ED_curve_editnurb_load(bmain, obedit); if (freedata) { ED_curve_editnurb_free(obedit); } @@ -272,13 +272,13 @@ bool ED_object_editmode_load(Main *bmain, Object *obedit) * \param flag: * - If #EM_FREEDATA isn't in the flag, use ED_object_editmode_load directly. */ -bool ED_object_editmode_exit_ex(Scene *scene, Object *obedit, int flag) +bool ED_object_editmode_exit_ex(Main *bmain, Scene *scene, Object *obedit, int flag) { const bool freedata = (flag & EM_FREEDATA) != 0; if (flag & EM_WAITCURSOR) waitcursor(1); - if (ED_object_editmode_load_ex(G.main, obedit, freedata) == false) { + if (ED_object_editmode_load_ex(bmain, obedit, freedata) == false) { /* in rare cases (background mode) its possible active object * is flagged for editmode, without 'obedit' being set [#35489] */ if (UNLIKELY(obedit && obedit->mode & OB_MODE_EDIT)) { @@ -318,9 +318,10 @@ bool ED_object_editmode_exit_ex(Scene *scene, Object *obedit, int flag) bool ED_object_editmode_exit(bContext *C, int flag) { + Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); Object *obedit = CTX_data_edit_object(C); - return ED_object_editmode_exit_ex(scene, obedit, flag); + return ED_object_editmode_exit_ex(bmain, scene, obedit, flag); } bool ED_object_editmode_enter_ex(Main *bmain, Scene *scene, Object *ob, int flag) @@ -465,7 +466,7 @@ static int editmode_toggle_exec(bContext *C, wmOperator *op) FOREACH_OBJECT_BEGIN(view_layer, ob) { if ((ob != obact) && (ob->type == obact->type)) { - ED_object_editmode_exit_ex(scene, ob, EM_FREEDATA | EM_WAITCURSOR); + ED_object_editmode_exit_ex(bmain, scene, ob, EM_FREEDATA | EM_WAITCURSOR); } } FOREACH_OBJECT_END; diff --git a/source/blender/editors/object/object_group.c b/source/blender/editors/object/object_group.c index debbe4bd379..8a52b6c5ef5 100644 --- a/source/blender/editors/object/object_group.c +++ b/source/blender/editors/object/object_group.c @@ -361,6 +361,7 @@ static int collection_create_exec(bContext *C, wmOperator *op) RNA_string_get(op->ptr, "name", name); Collection *collection = BKE_collection_add(bmain, NULL, name); + id_fake_user_set(&collection->id); CTX_DATA_BEGIN (C, Base *, base, selected_bases) { @@ -402,6 +403,7 @@ static int collection_add_exec(bContext *C, wmOperator *UNUSED(op)) return OPERATOR_CANCELLED; Collection *collection = BKE_collection_add(bmain, NULL, "Collection"); + id_fake_user_set(&collection->id); BKE_collection_object_add(bmain, collection, ob); WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); diff --git a/source/blender/editors/object/object_hook.c b/source/blender/editors/object/object_hook.c index 7687bd476b9..31e8685e323 100644 --- a/source/blender/editors/object/object_hook.c +++ b/source/blender/editors/object/object_hook.c @@ -304,7 +304,7 @@ static int return_editcurve_indexar( return totvert; } -static bool object_hook_index_array(Scene *scene, Object *obedit, +static bool object_hook_index_array(Main *bmain, Scene *scene, Object *obedit, int *r_tot, int **r_indexar, char *r_name, float r_cent[3]) { *r_indexar = NULL; @@ -336,7 +336,7 @@ static bool object_hook_index_array(Scene *scene, Object *obedit, } case OB_CURVE: case OB_SURF: - ED_curve_editnurb_load(obedit); + ED_curve_editnurb_load(bmain, obedit); ED_curve_editnurb_make(obedit); return return_editcurve_indexar(obedit, r_tot, r_indexar, r_cent); case OB_LATTICE: @@ -476,7 +476,7 @@ static int add_hook_object(const bContext *C, Main *bmain, Scene *scene, ViewLay int tot, ok, *indexar; char name[MAX_NAME]; - ok = object_hook_index_array(scene, obedit, &tot, &indexar, name, cent); + ok = object_hook_index_array(bmain, scene, obedit, &tot, &indexar, name, cent); if (!ok) { BKE_report(reports, RPT_ERROR, "Requires selected vertices or active vertex group"); @@ -814,6 +814,7 @@ void OBJECT_OT_hook_recenter(wmOperatorType *ot) static int object_hook_assign_exec(bContext *C, wmOperator *op) { + Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); PointerRNA ptr = CTX_data_pointer_get_type(C, "modifier", &RNA_HookModifier); int num = RNA_enum_get(op->ptr, "modifier"); @@ -831,7 +832,7 @@ static int object_hook_assign_exec(bContext *C, wmOperator *op) /* assign functionality */ - if (!object_hook_index_array(scene, ob, &tot, &indexar, name, cent)) { + if (!object_hook_index_array(bmain, scene, ob, &tot, &indexar, name, cent)) { BKE_report(op->reports, RPT_WARNING, "Requires selected vertices or active vertex group"); return OPERATOR_CANCELLED; } diff --git a/source/blender/editors/object/object_modes.c b/source/blender/editors/object/object_modes.c index 66c2ad5fa9b..e9bd6fbce8f 100644 --- a/source/blender/editors/object/object_modes.c +++ b/source/blender/editors/object/object_modes.c @@ -209,7 +209,7 @@ static bool ed_object_mode_generic_exit_ex( if (only_test) { return true; } - ED_object_editmode_exit_ex(scene, ob, EM_FREEDATA); + ED_object_editmode_exit_ex(bmain, scene, ob, EM_FREEDATA); } } else if (ob->mode & OB_MODE_VERTEX_PAINT) { diff --git a/source/blender/editors/object/object_modifier.c b/source/blender/editors/object/object_modifier.c index fb2884ea07f..71c9cb3eb69 100644 --- a/source/blender/editors/object/object_modifier.c +++ b/source/blender/editors/object/object_modifier.c @@ -64,6 +64,7 @@ #include "BKE_main.h" #include "BKE_mesh.h" #include "BKE_mesh_mapping.h" +#include "BKE_mesh_runtime.h" #include "BKE_mesh_sample.h" #include "BKE_modifier.h" #include "BKE_multires.h" @@ -574,7 +575,7 @@ static int modifier_apply_shape(ReportList *reports, Depsgraph *depsgraph, Scene } kb = BKE_keyblock_add(key, md->name); - BKE_nomain_mesh_to_meshkey(mesh_applied, me, kb); + BKE_mesh_nomain_to_meshkey(mesh_applied, me, kb); BKE_id_free(NULL, mesh_applied); } @@ -623,7 +624,7 @@ static int modifier_apply_obdata(ReportList *reports, Depsgraph *depsgraph, Scen return 0; } - BKE_nomain_mesh_to_mesh(mesh_applied, me, ob, CD_MASK_MESH, true); + BKE_mesh_nomain_to_mesh(mesh_applied, me, ob, CD_MASK_MESH, true); if (md->type == eModifierType_Multires) multires_customdata_delete(me); @@ -1331,7 +1332,7 @@ static int multires_external_save_exec(bContext *C, wmOperator *op) RNA_string_get(op->ptr, "filepath", path); if (relative) - BLI_path_rel(path, bmain->name); + BLI_path_rel(path, BKE_main_blendfile_path(bmain)); CustomData_external_add(&me->ldata, &me->id, CD_MDISPS, me->totloop, path); CustomData_external_write(&me->ldata, &me->id, CD_MASK_MESH, me->totloop, 0); @@ -1783,7 +1784,7 @@ static Object *modifier_skin_armature_create(Depsgraph *depsgraph, Main *bmain, MEM_freeN(emap); MEM_freeN(emap_mem); - ED_armature_from_edit(arm); + ED_armature_from_edit(bmain, arm); ED_armature_edit_free(arm); return arm_ob; diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c index e0d3ecaf561..93ac141e7d9 100644 --- a/source/blender/editors/object/object_ops.c +++ b/source/blender/editors/object/object_ops.c @@ -290,23 +290,11 @@ void ED_keymap_object(wmKeyConfig *keyconf) keymap = WM_keymap_find(keyconf, "Object Non-modal", 0, 0); /* modes */ - { - short key_mode_pair[][2] = { - {ONEKEY, OB_MODE_OBJECT}, - {TWOKEY, OB_MODE_EDIT}, - {THREEKEY, OB_MODE_POSE}, - {THREEKEY, OB_MODE_WEIGHT_PAINT}, - {FOURKEY, OB_MODE_VERTEX_PAINT}, - {FIVEKEY, OB_MODE_TEXTURE_PAINT}, - {SIXKEY, OB_MODE_SCULPT}, - {SEVENKEY, OB_MODE_PARTICLE_EDIT}, - }; - - for (uint i = 0; i < ARRAY_SIZE(key_mode_pair); i++) { - kmi = WM_keymap_add_item(keymap, "OBJECT_OT_mode_set_or_submode", key_mode_pair[i][0], KM_PRESS, 0, 0); - RNA_enum_set(kmi->ptr, "mode", key_mode_pair[i][1]); - } - } + kmi = WM_keymap_add_item(keymap, "OBJECT_OT_mode_set", TABKEY, KM_RELEASE, 0, 0); + RNA_enum_set(kmi->ptr, "mode", OB_MODE_EDIT); + RNA_boolean_set(kmi->ptr, "toggle", true); + + kmi = WM_keymap_add_menu_pie(keymap, "VIEW3D_PIE_object_mode", TABKEY, KM_CLICK_DRAG, 0, 0); WM_keymap_add_item(keymap, "OBJECT_OT_origin_set", CKEY, KM_PRESS, KM_ALT | KM_SHIFT | KM_CTRL, 0); diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c index d417437ad99..4f441826bfd 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -640,7 +640,7 @@ bool ED_object_parent_set(ReportList *reports, const bContext *C, Scene *scene, /* if follow, add F-Curve for ctime (i.e. "eval_time") so that path-follow works */ if (partype == PAR_FOLLOW) { /* get or create F-Curve */ - bAction *act = verify_adt_action(&cu->id, 1); + bAction *act = verify_adt_action(bmain, &cu->id, 1); FCurve *fcu = verify_fcurve(act, NULL, NULL, "eval_time", 0, 1); /* setup dummy 'generator' modifier here to get 1-1 correspondence still working */ diff --git a/source/blender/editors/object/object_transform.c b/source/blender/editors/object/object_transform.c index cb609b2567b..721d248ae4c 100644 --- a/source/blender/editors/object/object_transform.c +++ b/source/blender/editors/object/object_transform.c @@ -553,7 +553,7 @@ static int apply_objects_internal( BKE_mesh_calc_normals(me); } else if (ob->type == OB_ARMATURE) { - ED_armature_transform_apply(ob, mat, do_props); + ED_armature_transform_apply(bmain, ob, mat, do_props); } else if (ob->type == OB_LATTICE) { Lattice *lt = ob->data; @@ -1006,7 +1006,7 @@ static int object_origin_set_exec(bContext *C, wmOperator *op) /* Function to recenter armatures in editarmature.c * Bone + object locations are handled there. */ - ED_armature_origin_set(ob, cursor, centermode, around); + ED_armature_origin_set(bmain, ob, cursor, centermode, around); tot_change++; arm->id.tag |= LIB_TAG_DOIT; diff --git a/source/blender/editors/object/object_vgroup.c b/source/blender/editors/object/object_vgroup.c index e39d889d9d9..84786024160 100644 --- a/source/blender/editors/object/object_vgroup.c +++ b/source/blender/editors/object/object_vgroup.c @@ -58,6 +58,7 @@ #include "BKE_customdata.h" #include "BKE_deform.h" #include "BKE_mesh_mapping.h" +#include "BKE_mesh_runtime.h" #include "BKE_editmesh.h" #include "BKE_layer.h" #include "BKE_modifier.h" diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c index c705434c509..359e9365ea7 100644 --- a/source/blender/editors/physics/particle_edit.c +++ b/source/blender/editors/physics/particle_edit.c @@ -57,9 +57,11 @@ #include "BKE_object.h" #include "BKE_library.h" #include "BKE_mesh.h" +#include "BKE_mesh_runtime.h" #include "BKE_modifier.h" #include "BKE_particle.h" #include "BKE_report.h" +#include "BKE_scene.h" #include "BKE_bvhutils.h" #include "BKE_pointcache.h" @@ -260,8 +262,7 @@ static PTCacheEdit *pe_get_current( } else { if (create && !psys->edit) { - ParticleSystem *psys_eval = psys_eval_get(depsgraph, ob, psys); - if (psys_eval->flag & PSYS_HAIR_DONE) { + if (psys->flag & PSYS_HAIR_DONE) { PE_create_particle_edit(depsgraph, scene, ob, NULL, psys); } } @@ -643,11 +644,9 @@ static void foreach_mouse_hit_point(PEData *data, ForPointFunc func, int selecte static void foreach_mouse_hit_key(PEData *data, ForKeyMatFunc func, int selected) { - Object *ob_eval = DEG_get_evaluated_object(data->depsgraph, data->ob); PTCacheEdit *edit = data->edit; ParticleSystem *psys = edit->psys; ParticleSystemModifierData *psmd = NULL; - ParticleSystemModifierData *psmd_eval = NULL; ParticleEditSettings *pset= PE_settings(data->scene); POINT_P; KEY_K; float mat[4][4], imat[4][4]; @@ -658,10 +657,6 @@ static void foreach_mouse_hit_key(PEData *data, ForKeyMatFunc func, int selected if (edit->psys) psmd= psys_get_modifier(data->ob, edit->psys); - if (psmd != NULL) { - psmd_eval = (ParticleSystemModifierData *)modifiers_findByName(ob_eval, psmd->modifier.name); - } - /* all is selected in path mode */ if (pset->selectmode==SCE_SELECT_PATH) selected= 0; @@ -675,7 +670,7 @@ static void foreach_mouse_hit_key(PEData *data, ForKeyMatFunc func, int selected if (selected==0 || key->flag & PEK_SELECT) { if (key_inside_circle(data, data->rad, KEY_WCO, &data->dist)) { if (edit->psys && !(edit->psys->flag & PSYS_GLOBAL_HAIR)) { - psys_mat_hair_to_global(data->ob, psmd_eval->mesh_final, psys->part->from, psys->particles + p, mat); + psys_mat_hair_to_global(data->ob, psmd->mesh_final, psys->part->from, psys->particles + p, mat); invert_m4_m4(imat, mat); } @@ -690,7 +685,7 @@ static void foreach_mouse_hit_key(PEData *data, ForKeyMatFunc func, int selected if (selected==0 || key->flag & PEK_SELECT) { if (key_inside_circle(data, data->rad, KEY_WCO, &data->dist)) { if (edit->psys && !(edit->psys->flag & PSYS_GLOBAL_HAIR)) { - psys_mat_hair_to_global(data->ob, psmd_eval->mesh_final, psys->part->from, psys->particles + p, mat); + psys_mat_hair_to_global(data->ob, psmd->mesh_final, psys->part->from, psys->particles + p, mat); invert_m4_m4(imat, mat); } @@ -1109,11 +1104,9 @@ void recalc_lengths(PTCacheEdit *edit) } /* calculate a tree for finding nearest emitter's vertice */ -void recalc_emitter_field(Depsgraph *depsgraph, Object *ob, ParticleSystem *psys) +void recalc_emitter_field(Depsgraph *UNUSED(depsgraph), Object *ob, ParticleSystem *psys) { - Object *object_eval = DEG_get_evaluated_object(depsgraph, ob); - ParticleSystem *psys_eval = psys_eval_get(depsgraph, ob, psys); - Mesh *mesh = psys_get_modifier(object_eval, psys_eval)->mesh_final; + Mesh *mesh = psys_get_modifier(ob, psys)->mesh_final; PTCacheEdit *edit = psys->edit; float *vec, *nor; int i, totface /*, totvert*/; @@ -1201,27 +1194,19 @@ static void PE_update_selection(Depsgraph *depsgraph, Scene *scene, Object *ob, DEG_id_tag_update(&ob->id, DEG_TAG_SELECT_UPDATE); } -void update_world_cos(Depsgraph *depsgraph, Object *ob, PTCacheEdit *edit) +void update_world_cos(Depsgraph *UNUSED(depsgraph), Object *ob, PTCacheEdit *edit) { - Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob); ParticleSystem *psys = edit->psys; - ParticleSystem *psys_eval = NULL; ParticleSystemModifierData *psmd = psys_get_modifier(ob, psys); - ParticleSystemModifierData *psmd_eval = NULL; POINT_P; KEY_K; float hairmat[4][4]; - if (psmd != NULL) { - psmd_eval = (ParticleSystemModifierData *)modifiers_findByName(ob_eval, psmd->modifier.name); - psys_eval = psmd_eval->psys; - } - - if (psys == 0 || psys->edit == 0 || psmd_eval->mesh_final == NULL) + if (psys == 0 || psys->edit == 0 || psmd->mesh_final == NULL) return; LOOP_POINTS { if (!(psys->flag & PSYS_GLOBAL_HAIR)) - psys_mat_hair_to_global(ob_eval, psmd_eval->mesh_final, psys->part->from, psys_eval->particles+p, hairmat); + psys_mat_hair_to_global(ob, psmd->mesh_final, psys->part->from, psys->particles+p, hairmat); LOOP_KEYS { copy_v3_v3(key->world_co, key->co); @@ -4362,20 +4347,14 @@ void PE_create_particle_edit( Depsgraph *depsgraph, Scene *scene, Object *ob, PointCache *cache, ParticleSystem *psys) { PTCacheEdit *edit; - Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob); ParticleSystemModifierData *psmd = (psys) ? psys_get_modifier(ob, psys) : NULL; - ParticleSystemModifierData *psmd_eval = NULL; POINT_P; KEY_K; ParticleData *pa = NULL; HairKey *hkey; int totpoint; - if (psmd != NULL) { - psmd_eval = (ParticleSystemModifierData *)modifiers_findByName(ob_eval, psmd->modifier.name); - } - /* no psmd->dm happens in case particle system modifier is not enabled */ - if (!(psys && psmd_eval && psmd_eval->mesh_final) && !cache) + if (!(psys && psmd && psmd->mesh_final) && !cache) return; if (cache && cache->flag & PTCACHE_DISK_CACHE) @@ -4505,7 +4484,16 @@ static int particle_edit_toggle_exec(bContext *C, wmOperator *op) if (!is_mode_set) { PTCacheEdit *edit; + /* Particle edit mode requires original object to have all strands + * cached. A bit annoying to do update here, but is simpler than + * rewriting the while edit mode code. + */ + ob->id.recalc |= (ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); + BKE_scene_graph_update_tagged(depsgraph, CTX_data_main(C)); + BKE_object_eval_transform_all(depsgraph, scene, ob); + BKE_object_handle_data_update(depsgraph, scene, ob); ob->mode |= mode_flag; + edit= PE_create_current(depsgraph, scene, ob); /* mesh may have changed since last entering editmode. diff --git a/source/blender/editors/physics/particle_object.c b/source/blender/editors/physics/particle_object.c index 48a80cbbc1f..fbccdcfcdba 100644 --- a/source/blender/editors/physics/particle_object.c +++ b/source/blender/editors/physics/particle_object.c @@ -50,6 +50,7 @@ #include "BKE_library.h" #include "BKE_main.h" #include "BKE_mesh.h" +#include "BKE_mesh_runtime.h" #include "BKE_modifier.h" #include "BKE_object.h" #include "BKE_particle.h" diff --git a/source/blender/editors/render/render_opengl.c b/source/blender/editors/render/render_opengl.c index bb979087400..7e33549c5ac 100644 --- a/source/blender/editors/render/render_opengl.c +++ b/source/blender/editors/render/render_opengl.c @@ -404,7 +404,7 @@ static void screen_opengl_render_write(OGLRender *oglrender) rr = RE_AcquireResultRead(oglrender->re); BKE_image_path_from_imformat( - name, scene->r.pic, oglrender->bmain->name, scene->r.cfra, + name, scene->r.pic, BKE_main_blendfile_path(oglrender->bmain), scene->r.cfra, &scene->r.im_format, (scene->r.scemode & R_EXTENSION) != 0, false, NULL); /* write images as individual images or stereo */ @@ -943,7 +943,7 @@ static void write_result_func(TaskPool * __restrict pool, char name[FILE_MAX]; BKE_image_path_from_imformat(name, scene->r.pic, - oglrender->bmain->name, + BKE_main_blendfile_path(oglrender->bmain), cfra, &scene->r.im_format, (scene->r.scemode & R_EXTENSION) != 0, @@ -1030,7 +1030,7 @@ static bool screen_opengl_render_anim_step(bContext *C, wmOperator *op) if (!is_movie) { BKE_image_path_from_imformat( - name, scene->r.pic, oglrender->bmain->name, scene->r.cfra, + name, scene->r.pic, BKE_main_blendfile_path(oglrender->bmain), scene->r.cfra, &scene->r.im_format, (scene->r.scemode & R_EXTENSION) != 0, true, NULL); if ((scene->r.mode & R_NO_OVERWRITE) && BLI_exists(name)) { diff --git a/source/blender/editors/render/render_preview.c b/source/blender/editors/render/render_preview.c index b3601226932..4a3c7a3fd4b 100644 --- a/source/blender/editors/render/render_preview.c +++ b/source/blender/editors/render/render_preview.c @@ -122,7 +122,7 @@ ImBuf *get_brush_icon(Brush *brush) // first use the path directly to try and load the file BLI_strncpy(path, brush->icon_filepath, sizeof(brush->icon_filepath)); - BLI_path_abs(path, G.main->name); + BLI_path_abs(path, BKE_main_blendfile_path_from_global()); /* use default colorspaces for brushes */ brush->icon_imbuf = IMB_loadiffname(path, flags, NULL); @@ -131,7 +131,7 @@ ImBuf *get_brush_icon(Brush *brush) if (!(brush->icon_imbuf)) { folder = BKE_appdir_folder_id(BLENDER_DATAFILES, "brushicons"); - BLI_make_file_string(G.main->name, path, folder, brush->icon_filepath); + BLI_make_file_string(BKE_main_blendfile_path_from_global(), path, folder, brush->icon_filepath); if (path[0]) { /* use fefault color spaces */ @@ -319,7 +319,7 @@ static Scene *preview_prepare_scene(Main *bmain, Scene *scene, ID *id, int id_ty Scene *sce; Main *pr_main = sp->pr_main; - memcpy(pr_main->name, bmain->name, sizeof(pr_main->name)); + memcpy(pr_main->name, BKE_main_blendfile_path(bmain), sizeof(pr_main->name)); sce = preview_get_scene(pr_main); if (sce) { diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c index 9a70d6f23de..034ccdf2e7b 100644 --- a/source/blender/editors/screen/area.c +++ b/source/blender/editors/screen/area.c @@ -1825,19 +1825,21 @@ static void ed_panel_draw(const bContext *C, panel = UI_panel_begin(sa, ar, lb, block, pt, panel, &open); /* bad fixed values */ - int triangle = (int)(UI_UNIT_Y * 1.1f); int xco, yco, h = 0; if (pt->draw_header && !(pt->flag & PNL_NO_HEADER) && (open || vertical)) { + int labelx, labely; + UI_panel_label_offset(block, &labelx, &labely); + /* for enabled buttons */ panel->layout = UI_block_layout( block, UI_LAYOUT_HORIZONTAL, UI_LAYOUT_HEADER, - triangle, (UI_UNIT_Y * 1.1f) + style->panelspace, UI_UNIT_Y, 1, 0, style); + labelx, labely, UI_UNIT_Y, 1, 0, style); pt->draw_header(C, panel); UI_block_layout_resolve(block, &xco, &yco); - panel->labelofs = xco - triangle; + panel->labelofs = xco - labelx; panel->layout = NULL; } else { diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c index 06735eb8689..ac4ab3461a3 100644 --- a/source/blender/editors/screen/screen_edit.c +++ b/source/blender/editors/screen/screen_edit.c @@ -340,12 +340,12 @@ ScrArea *area_split(bScreen *sc, ScrArea *sa, char dir, float fac, int merge) /** * Empty screen, with 1 dummy area without spacedata. Uses window size. */ -bScreen *screen_add(const char *name, const rcti *rect) +bScreen *screen_add(Main *bmain, const char *name, const rcti *rect) { bScreen *sc; ScrVert *sv1, *sv2, *sv3, *sv4; - sc = BKE_libblock_alloc(G.main, ID_SCR, name, 0); + sc = BKE_libblock_alloc(bmain, ID_SCR, name, 0); sc->do_refresh = true; sc->redraws_flag = TIME_ALL_3D_WIN | TIME_ALL_ANIM_WIN; @@ -832,7 +832,7 @@ void ED_screen_refresh(wmWindowManager *wm, wmWindow *win) } /* file read, set all screens, ... */ -void ED_screens_initialize(wmWindowManager *wm) +void ED_screens_initialize(Main *UNUSED(bmain), wmWindowManager *wm) { wmWindow *win; @@ -1399,6 +1399,7 @@ void ED_screen_full_restore(bContext *C, ScrArea *sa) */ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *sa, const short state) { + Main *bmain = CTX_data_main(C); wmWindowManager *wm = CTX_wm_manager(C); WorkSpace *workspace = WM_window_get_active_workspace(win); bScreen *sc, *oldscreen; @@ -1489,7 +1490,7 @@ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *sa, const s oldscreen->state = state; BLI_snprintf(newname, sizeof(newname), "%s-%s", oldscreen->id.name + 2, "nonnormal"); - layout_new = ED_workspace_layout_add(workspace, win, newname); + layout_new = ED_workspace_layout_add(bmain, workspace, win, newname); sc = BKE_workspace_layout_screen_get(layout_new); sc->state = state; @@ -1502,7 +1503,7 @@ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *sa, const s /* use random area when we have no active one, e.g. when the * mouse is outside of the window and we open a file browser */ - if (!sa) { + if (!sa || sa->global) { sa = oldscreen->areabase.first; } diff --git a/source/blender/editors/screen/screen_intern.h b/source/blender/editors/screen/screen_intern.h index adfd7b185ab..b02198764e0 100644 --- a/source/blender/editors/screen/screen_intern.h +++ b/source/blender/editors/screen/screen_intern.h @@ -48,7 +48,7 @@ void screen_area_update_region_sizes(wmWindowManager *wm, wmWindow *win, void region_toggle_hidden(struct bContext *C, ARegion *ar, const bool do_fade); /* screen_edit.c */ -bScreen *screen_add(const char *name, const rcti *rect); +bScreen *screen_add(struct Main *bmain, const char *name, const rcti *rect); void screen_data_copy(bScreen *to, bScreen *from); void screen_new_activate_prepare(const wmWindow *win, bScreen *screen_new); void screen_change_update(struct bContext *C, wmWindow *win, bScreen *sc); diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c index e504a116384..f6bd238170d 100644 --- a/source/blender/editors/screen/screen_ops.c +++ b/source/blender/editors/screen/screen_ops.c @@ -1069,6 +1069,7 @@ static void SCREEN_OT_area_swap(wmOperatorType *ot) /* operator callback */ static int area_dupli_invoke(bContext *C, wmOperator *op, const wmEvent *event) { + Main *bmain = CTX_data_main(C); wmWindow *newwin, *win = CTX_wm_window(C); Scene *scene; WorkSpace *workspace = WM_window_get_active_workspace(win); @@ -1110,7 +1111,7 @@ static int area_dupli_invoke(bContext *C, wmOperator *op, const wmEvent *event) WM_window_set_active_workspace(newwin, workspace); /* allocs new screen and adds to newly created window, using window size */ - layout_new = ED_workspace_layout_add(workspace, newwin, BKE_workspace_layout_name_get(layout_old)); + layout_new = ED_workspace_layout_add(bmain, workspace, newwin, BKE_workspace_layout_name_get(layout_old)); newsc = BKE_workspace_layout_screen_get(layout_new); WM_window_set_active_layout(newwin, workspace, layout_new); @@ -4301,12 +4302,13 @@ static void SCREEN_OT_drivers_editor_show(struct wmOperatorType *ot) static int screen_new_exec(bContext *C, wmOperator *UNUSED(op)) { + Main *bmain = CTX_data_main(C); wmWindow *win = CTX_wm_window(C); WorkSpace *workspace = BKE_workspace_active_get(win->workspace_hook); WorkSpaceLayout *layout_old = BKE_workspace_active_layout_get(win->workspace_hook); WorkSpaceLayout *layout_new; - layout_new = ED_workspace_layout_duplicate(workspace, layout_old, win); + layout_new = ED_workspace_layout_duplicate(bmain, workspace, layout_old, win); WM_event_add_notifier(C, NC_SCREEN | ND_LAYOUTBROWSE, layout_new); return OPERATOR_FINISHED; diff --git a/source/blender/editors/screen/screendump.c b/source/blender/editors/screen/screendump.c index 63b9fe4043c..7e50f8d41c4 100644 --- a/source/blender/editors/screen/screendump.c +++ b/source/blender/editors/screen/screendump.c @@ -194,7 +194,7 @@ static int screenshot_exec(bContext *C, wmOperator *op) char path[FILE_MAX]; RNA_string_get(op->ptr, "filepath", path); - BLI_path_abs(path, G.main->name); + BLI_path_abs(path, BKE_main_blendfile_path_from_global()); /* operator ensures the extension */ ibuf = IMB_allocImBuf(scd->dumpsx, scd->dumpsy, 24, 0); @@ -233,7 +233,7 @@ static int screenshot_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED( /* extension is added by 'screenshot_check' after */ char filepath[FILE_MAX] = "//screen"; if (G.relbase_valid) { - BLI_strncpy(filepath, G.main->name, sizeof(filepath)); + BLI_strncpy(filepath, BKE_main_blendfile_path_from_global(), sizeof(filepath)); BLI_replace_extension(filepath, sizeof(filepath), ""); /* strip '.blend' */ } RNA_string_set(op->ptr, "filepath", filepath); @@ -409,7 +409,7 @@ static void screenshot_startjob(void *sjv, short *stop, short *do_update, float int ok; BKE_image_path_from_imformat( - name, rd.pic, sj->bmain->name, rd.cfra, + name, rd.pic, BKE_main_blendfile_path(sj->bmain), rd.cfra, &rd.im_format, (rd.scemode & R_EXTENSION) != 0, true, NULL); ibuf->rect = sj->dumprect; diff --git a/source/blender/editors/screen/workspace_edit.c b/source/blender/editors/screen/workspace_edit.c index d54996bad59..a044a7d377a 100644 --- a/source/blender/editors/screen/workspace_edit.c +++ b/source/blender/editors/screen/workspace_edit.c @@ -131,7 +131,7 @@ static bool workspace_change_find_new_layout_cb(const WorkSpaceLayout *layout, v } static WorkSpaceLayout *workspace_change_get_new_layout( - WorkSpace *workspace_new, wmWindow *win) + Main *bmain, WorkSpace *workspace_new, wmWindow *win) { /* ED_workspace_duplicate may have stored a layout to activate once the workspace gets activated. */ WorkSpaceLayout *layout_new; @@ -155,7 +155,7 @@ static WorkSpaceLayout *workspace_change_get_new_layout( NULL, false); if (!layout_temp) { /* fallback solution: duplicate layout */ - layout_temp = ED_workspace_layout_duplicate(workspace_new, layout_new, win); + layout_temp = ED_workspace_layout_duplicate(bmain, workspace_new, layout_new, win); } layout_new = layout_temp; } @@ -177,7 +177,7 @@ bool ED_workspace_change( { Main *bmain = CTX_data_main(C); WorkSpace *workspace_old = WM_window_get_active_workspace(win); - WorkSpaceLayout *layout_new = workspace_change_get_new_layout(workspace_new, win); + WorkSpaceLayout *layout_new = workspace_change_get_new_layout(bmain, workspace_new, win); bScreen *screen_new = BKE_workspace_layout_screen_get(layout_new); bScreen *screen_old = BKE_workspace_active_screen_get(win->workspace_hook); @@ -228,7 +228,7 @@ WorkSpace *ED_workspace_duplicate( /* TODO(campbell): tools */ for (WorkSpaceLayout *layout_old = layouts_old->first; layout_old; layout_old = layout_old->next) { - WorkSpaceLayout *layout_new = ED_workspace_layout_duplicate(workspace_new, layout_old, win); + WorkSpaceLayout *layout_new = ED_workspace_layout_duplicate(bmain, workspace_new, layout_old, win); if (layout_active_old == layout_old) { win->workspace_hook->temp_layout_store = layout_new; diff --git a/source/blender/editors/screen/workspace_layout_edit.c b/source/blender/editors/screen/workspace_layout_edit.c index 6285f031836..0c7431cb2e7 100644 --- a/source/blender/editors/screen/workspace_layout_edit.c +++ b/source/blender/editors/screen/workspace_layout_edit.c @@ -46,6 +46,7 @@ * Empty screen, with 1 dummy area without spacedata. Uses window size. */ WorkSpaceLayout *ED_workspace_layout_add( + Main *bmain, WorkSpace *workspace, wmWindow *win, const char *name) @@ -54,12 +55,13 @@ WorkSpaceLayout *ED_workspace_layout_add( rcti screen_rect; WM_window_screen_rect_calc(win, &screen_rect); - screen = screen_add(name, &screen_rect); + screen = screen_add(bmain, name, &screen_rect); return BKE_workspace_layout_add(workspace, screen, name); } WorkSpaceLayout *ED_workspace_layout_duplicate( + Main *bmain, WorkSpace *workspace, const WorkSpaceLayout *layout_old, wmWindow *win) { @@ -72,7 +74,7 @@ WorkSpaceLayout *ED_workspace_layout_duplicate( return NULL; /* XXX handle this case! */ } - layout_new = ED_workspace_layout_add(workspace, win, name); + layout_new = ED_workspace_layout_add(bmain, workspace, win, name); screen_new = BKE_workspace_layout_screen_get(layout_new); screen_data_copy(screen_new, screen_old); diff --git a/source/blender/editors/sculpt_paint/paint_hide.c b/source/blender/editors/sculpt_paint/paint_hide.c index 3d4f6c05ff4..ac5b0624d56 100644 --- a/source/blender/editors/sculpt_paint/paint_hide.c +++ b/source/blender/editors/sculpt_paint/paint_hide.c @@ -48,6 +48,7 @@ #include "BKE_context.h" #include "BKE_DerivedMesh.h" #include "BKE_mesh.h" +#include "BKE_mesh_runtime.h" #include "BKE_multires.h" #include "BKE_paint.h" #include "BKE_subsurf.h" @@ -368,7 +369,6 @@ static int hide_show_exec(bContext *C, wmOperator *op) PartialVisArea area; PBVH *pbvh; PBVHNode **nodes; - DerivedMesh *dm; PBVHType pbvh_type; float clip_planes[4][4]; rcti rect; @@ -381,9 +381,9 @@ static int hide_show_exec(bContext *C, wmOperator *op) clip_planes_from_rect(C, clip_planes, &rect); - dm = mesh_get_derived_final(depsgraph, CTX_data_scene(C), ob, CD_MASK_BAREMESH); - pbvh = dm->getPBVH(ob, dm); - ob->sculpt->pbvh = pbvh; + Mesh *me_eval_deform = mesh_get_eval_deform(depsgraph, CTX_data_scene(C), ob, CD_MASK_BAREMESH); + pbvh = BKE_sculpt_object_pbvh_ensure(ob, me_eval_deform); + BLI_assert(ob->sculpt->pbvh == pbvh); get_pbvh_nodes(pbvh, &nodes, &totnode, clip_planes, area); pbvh_type = BKE_pbvh_type(pbvh); diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c index 0e48596ca1a..32355d41ada 100644 --- a/source/blender/editors/sculpt_paint/paint_image_proj.c +++ b/source/blender/editors/sculpt_paint/paint_image_proj.c @@ -74,6 +74,7 @@ #include "BKE_material.h" #include "BKE_mesh.h" #include "BKE_mesh_mapping.h" +#include "BKE_mesh_runtime.h" #include "BKE_node.h" #include "BKE_paint.h" #include "BKE_report.h" diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c index 53b73562322..02dae51c594 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex.c +++ b/source/blender/editors/sculpt_paint/paint_vertex.c @@ -59,6 +59,7 @@ #include "BKE_main.h" #include "BKE_mesh.h" #include "BKE_mesh_mapping.h" +#include "BKE_object.h" #include "BKE_object_deform.h" #include "BKE_paint.h" #include "BKE_report.h" @@ -974,7 +975,7 @@ static void vertex_paint_init_session(Depsgraph *depsgraph, Scene *scene, Object if (ob->sculpt == NULL) { ob->sculpt = MEM_callocN(sizeof(SculptSession), "sculpt session"); - BKE_sculpt_update_mesh_elements(depsgraph, scene, scene->toolsettings->sculpt, ob, 0, false); + BKE_sculpt_update_mesh_elements(depsgraph, scene, scene->toolsettings->sculpt, ob, false, false); } } @@ -1067,6 +1068,11 @@ static void ed_vwpaintmode_enter_generic( ob->mode |= mode_flag; Mesh *me = BKE_mesh_from_object(ob); + /* Same as sculpt mode, make sure we don't have cached derived mesh which + * points to freed arrays. + */ + BKE_object_free_derived_caches(ob); + if (mode_flag == OB_MODE_VERTEX_PAINT) { const ePaintMode paint_mode = ePaintVertex; ED_mesh_color_ensure(me, NULL); @@ -1108,6 +1114,9 @@ static void ed_vwpaintmode_enter_generic( } vertex_paint_init_session(depsgraph, scene, ob); + + /* Flush object mode. */ + DEG_id_tag_update(&ob->id, DEG_TAG_COPY_ON_WRITE); } void ED_object_vpaintmode_enter_ex( @@ -1189,6 +1198,10 @@ static void ed_vwpaintmode_exit_generic( ED_mesh_mirror_topo_table(NULL, NULL, 'e'); } + /* Never leave derived meshes behind. */ + BKE_object_free_derived_caches(ob); + + /* Flush object mode. */ DEG_id_tag_update(&ob->id, DEG_TAG_COPY_ON_WRITE); } @@ -3139,6 +3152,10 @@ static void vpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P * avoid this if we can! */ DEG_id_tag_update(ob->data, 0); } + else { + /* Flush changes through DEG. */ + DEG_id_tag_update(ob->data, DEG_TAG_COPY_ON_WRITE); + } } static void vpaint_stroke_done(const bContext *C, struct PaintStroke *stroke) diff --git a/source/blender/editors/sculpt_paint/paint_vertex_color_ops.c b/source/blender/editors/sculpt_paint/paint_vertex_color_ops.c index d7668a48139..8516d92214d 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex_color_ops.c +++ b/source/blender/editors/sculpt_paint/paint_vertex_color_ops.c @@ -152,6 +152,7 @@ static bool vertex_paint_from_weight(Object *ob) } /* TODO: respect selection. */ + /* TODO: Do we want to take weights from evaluated mesh instead? 2.7x was not doing it anyway... */ mp = me->mpoly; vgroup_active = ob->actdef - 1; for (int i = 0; i < me->totpoly; i++, mp++) { diff --git a/source/blender/editors/sculpt_paint/paint_vertex_proj.c b/source/blender/editors/sculpt_paint/paint_vertex_proj.c index c5c9aa48760..cacfdc2dbba 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex_proj.c +++ b/source/blender/editors/sculpt_paint/paint_vertex_proj.c @@ -41,6 +41,7 @@ #include "BKE_DerivedMesh.h" #include "BKE_context.h" +#include "BKE_mesh_runtime.h" #include "DEG_depsgraph.h" diff --git a/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c b/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c index e560a4cddff..7c2977a0788 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c +++ b/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c @@ -52,6 +52,7 @@ #include "BKE_deform.h" #include "BKE_mesh.h" #include "BKE_mesh_mapping.h" +#include "BKE_mesh_runtime.h" #include "BKE_modifier.h" #include "BKE_object_deform.h" #include "BKE_paint.h" diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index 5dd7f23864c..3475aadd171 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -5210,14 +5210,12 @@ static void sculpt_dynamic_topology_triangulate(BMesh *bm) void sculpt_pbvh_clear(Object *ob) { SculptSession *ss = ob->sculpt; - DerivedMesh *dm = ob->derivedFinal; /* Clear out any existing DM and PBVH */ - if (ss->pbvh) + if (ss->pbvh) { BKE_pbvh_free(ss->pbvh); + } ss->pbvh = NULL; - if (dm) - dm->getPBVH(NULL, dm); BKE_object_free_derived_caches(ob); } @@ -5629,7 +5627,7 @@ static void sculpt_init_session(Depsgraph *depsgraph, Scene *scene, Object *ob) ob->sculpt = MEM_callocN(sizeof(SculptSession), "sculpt session"); ob->sculpt->mode_type = OB_MODE_SCULPT; - BKE_sculpt_update_mesh_elements(depsgraph, scene, scene->toolsettings->sculpt, ob, 0, false); + BKE_sculpt_update_mesh_elements(depsgraph, scene, scene->toolsettings->sculpt, ob, false, false); } static int ed_object_sculptmode_flush_recalc_flag(Scene *scene, Object *ob, MultiresModifierData *mmd) @@ -5643,7 +5641,7 @@ static int ed_object_sculptmode_flush_recalc_flag(Scene *scene, Object *ob, Mult } void ED_object_sculptmode_enter_ex( - Depsgraph *depsgraph, + Main *bmain, Depsgraph *depsgraph, Scene *scene, Object *ob, ReportList *reports) { @@ -5665,6 +5663,11 @@ void ED_object_sculptmode_enter_ex( BKE_sculptsession_free(ob); } + /* Make sure derived final from original object does not reference possibly + * freed memory. + */ + BKE_object_free_derived_mesh_caches(ob); + sculpt_init_session(depsgraph, scene, ob); /* Mask layer is required */ @@ -5686,7 +5689,7 @@ void ED_object_sculptmode_enter_ex( Paint *paint = BKE_paint_get_active_from_paintmode(scene, ePaintSculpt); BKE_paint_init(scene, ePaintSculpt, PAINT_CURSOR_SCULPT); - paint_cursor_start_explicit(paint, G.main->wm.first, sculpt_poll_view3d); + paint_cursor_start_explicit(paint, bmain->wm.first, sculpt_poll_view3d); /* Check dynamic-topology flag; re-enter dynamic-topology mode when changing modes, * As long as no data was added that is not supported. */ @@ -5735,14 +5738,18 @@ void ED_object_sculptmode_enter_ex( } // ED_workspace_object_mode_sync_from_object(G.main->wm.first, workspace, ob); + + /* Flush object mode. */ + DEG_id_tag_update(&ob->id, DEG_TAG_COPY_ON_WRITE); } void ED_object_sculptmode_enter(struct bContext *C, ReportList *reports) { + Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); Object *ob = CTX_data_active_object(C); Depsgraph *depsgraph = CTX_data_depsgraph(C); - ED_object_sculptmode_enter_ex(depsgraph, scene, ob, reports); + ED_object_sculptmode_enter_ex(bmain, depsgraph, scene, ob, reports); } void ED_object_sculptmode_exit_ex( @@ -5788,6 +5795,10 @@ void ED_object_sculptmode_exit_ex( paint_cursor_delete_textures(); + /* Never leave derived meshes behind. */ + BKE_object_free_derived_mesh_caches(ob); + + /* Flush object mode. */ DEG_id_tag_update(&ob->id, DEG_TAG_COPY_ON_WRITE); } @@ -5802,6 +5813,7 @@ void ED_object_sculptmode_exit(bContext *C) static int sculpt_mode_toggle_exec(bContext *C, wmOperator *op) { struct wmMsgBus *mbus = CTX_wm_message_bus(C); + Main *bmain = CTX_data_main(C); Depsgraph *depsgraph = CTX_data_depsgraph_on_load(C); Scene *scene = CTX_data_scene(C); Object *ob = CTX_data_active_object(C); @@ -5818,7 +5830,7 @@ static int sculpt_mode_toggle_exec(bContext *C, wmOperator *op) ED_object_sculptmode_exit_ex(depsgraph, scene, ob); } else { - ED_object_sculptmode_enter_ex(depsgraph, scene, ob, op->reports); + ED_object_sculptmode_enter_ex(bmain, depsgraph, scene, ob, op->reports); } WM_event_add_notifier(C, NC_SCENE | ND_MODE, scene); diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c index fbdca27b018..2872ad4fb9c 100644 --- a/source/blender/editors/sculpt_paint/sculpt_undo.c +++ b/source/blender/editors/sculpt_paint/sculpt_undo.c @@ -58,6 +58,7 @@ #include "BKE_paint.h" #include "BKE_key.h" #include "BKE_mesh.h" +#include "BKE_mesh_runtime.h" #include "BKE_subsurf.h" #include "BKE_undo_system.h" @@ -157,7 +158,7 @@ static bool sculpt_undo_restore_coords(bContext *C, DerivedMesh *dm, SculptUndoN if (kb) { ob->shapenr = BLI_findindex(&key->block, kb) + 1; - BKE_sculpt_update_mesh_elements(depsgraph, scene, sd, ob, 0, false); + BKE_sculpt_update_mesh_elements(depsgraph, scene, sd, ob, false, false); WM_event_add_notifier(C, NC_OBJECT | ND_DATA, ob); } else { @@ -197,7 +198,7 @@ static bool sculpt_undo_restore_coords(bContext *C, DerivedMesh *dm, SculptUndoN /* pbvh uses it's own mvert array, so coords should be */ /* propagated to pbvh here */ - BKE_pbvh_apply_vertCos(ss->pbvh, vertCos); + BKE_pbvh_apply_vertCos(ss->pbvh, vertCos, unode->totvert); MEM_freeN(vertCos); } @@ -492,7 +493,9 @@ static void sculpt_undo_restore_list(bContext *C, ListBase *lb) } } - BKE_sculpt_update_mesh_elements(depsgraph, scene, sd, ob, 0, need_mask); + DEG_id_tag_update(&ob->id, DEG_TAG_COPY_ON_WRITE); + + BKE_sculpt_update_mesh_elements(depsgraph, scene, sd, ob, false, need_mask); /* call _after_ sculpt_update_mesh_elements() which may update 'ob->derivedFinal' */ dm = mesh_get_derived_final(depsgraph, scene, ob, 0); diff --git a/source/blender/editors/sound/sound_ops.c b/source/blender/editors/sound/sound_ops.c index 07d12de3662..b7a80a92998 100644 --- a/source/blender/editors/sound/sound_ops.c +++ b/source/blender/editors/sound/sound_ops.c @@ -375,7 +375,7 @@ static int sound_mixdown_exec(bContext *C, wmOperator *op) specs.rate = scene->r.ffcodecdata.audio_mixrate; BLI_strncpy(filename, path, sizeof(filename)); - BLI_path_abs(filename, bmain->name); + BLI_path_abs(filename, BKE_main_blendfile_path(bmain)); if (split) result = AUD_mixdown_per_channel(scene->sound_scene, SFRA * specs.rate / FPS, (EFRA - SFRA + 1) * specs.rate / FPS, diff --git a/source/blender/editors/space_action/action_edit.c b/source/blender/editors/space_action/action_edit.c index b3c1c536ad8..a9f9488d049 100644 --- a/source/blender/editors/space_action/action_edit.c +++ b/source/blender/editors/space_action/action_edit.c @@ -57,8 +57,9 @@ #include "BKE_fcurve.h" #include "BKE_gpencil.h" #include "BKE_global.h" -#include "BKE_library.h" #include "BKE_key.h" +#include "BKE_library.h" +#include "BKE_main.h" #include "BKE_nla.h" #include "BKE_context.h" #include "BKE_report.h" @@ -718,7 +719,8 @@ static void insert_action_keys(bAnimContext *ac, short mode) * (TODO: add the full-blown PointerRNA relative parsing case here...) */ if (ale->id && !ale->owner) { - insert_keyframe(depsgraph, reports, ale->id, NULL, ((fcu->grp) ? (fcu->grp->name) : (NULL)), fcu->rna_path, fcu->array_index, cfra, ts->keyframe_type, flag); + insert_keyframe(ac->bmain, depsgraph, reports, ale->id, NULL, ((fcu->grp) ? (fcu->grp->name) : (NULL)), + fcu->rna_path, fcu->array_index, cfra, ts->keyframe_type, flag); } else { const float curval = evaluate_fcurve(fcu, cfra); diff --git a/source/blender/editors/space_action/action_ops.c b/source/blender/editors/space_action/action_ops.c index 25218358ed4..bf7f75db95c 100644 --- a/source/blender/editors/space_action/action_ops.c +++ b/source/blender/editors/space_action/action_ops.c @@ -216,6 +216,9 @@ static void action_keymap_keyframes(wmKeyConfig *keyconf, wmKeyMap *keymap) WM_keymap_add_item(keymap, "ACTION_OT_extrapolation_type", EKEY, KM_PRESS, KM_SHIFT, 0); WM_keymap_add_item(keymap, "ACTION_OT_keyframe_type", RKEY, KM_PRESS, 0, 0); + /* specials */ + WM_keymap_add_menu(keymap, "DOPESHEET_MT_specials", WKEY, KM_PRESS, 0, 0); + /* destructive */ WM_keymap_add_item(keymap, "ACTION_OT_sample", OKEY, KM_PRESS, KM_SHIFT, 0); @@ -289,4 +292,3 @@ void action_keymap(wmKeyConfig *keyconf) keymap = WM_keymap_find(keyconf, "Dopesheet", SPACE_ACTION, 0); action_keymap_keyframes(keyconf, keymap); } - diff --git a/source/blender/editors/space_action/space_action.c b/source/blender/editors/space_action/space_action.c index ffcaf53513a..e130ea9369c 100644 --- a/source/blender/editors/space_action/space_action.c +++ b/source/blender/editors/space_action/space_action.c @@ -295,6 +295,8 @@ static void action_channel_region_init(wmWindowManager *wm, ARegion *ar) keymap = WM_keymap_find(wm->defaultconf, "Animation Channels", 0, 0); WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); + WM_keymap_add_menu(keymap, "DOPESHEET_MT_specials_channels", WKEY, KM_PRESS, 0, 0); + keymap = WM_keymap_find(wm->defaultconf, "Dopesheet Generic", SPACE_ACTION, 0); WM_event_add_keymap_handler(&ar->handlers, keymap); } @@ -903,4 +905,3 @@ void ED_spacetype_action(void) BKE_spacetype_register(st); } - diff --git a/source/blender/editors/space_buttons/buttons_context.c b/source/blender/editors/space_buttons/buttons_context.c index 9caf381c93d..dd943e7988d 100644 --- a/source/blender/editors/space_buttons/buttons_context.c +++ b/source/blender/editors/space_buttons/buttons_context.c @@ -489,7 +489,7 @@ static int buttons_context_path(const bContext *C, ButsContextPath *path, int ma } /* No pinned root, use scene as initial root. */ else { - if (mainb == BCONTEXT_WORKSPACE) { + if (ELEM(mainb, BCONTEXT_WORKSPACE, BCONTEXT_TOOL)) { RNA_id_pointer_create(&workspace->id, &path->ptr[0]); path->len++; } @@ -525,6 +525,7 @@ static int buttons_context_path(const bContext *C, ButsContextPath *path, int ma case BCONTEXT_WORLD: found = buttons_context_path_world(path); break; + case BCONTEXT_TOOL: case BCONTEXT_WORKSPACE: found = buttons_context_path_workspace(path); break; diff --git a/source/blender/editors/space_buttons/buttons_ops.c b/source/blender/editors/space_buttons/buttons_ops.c index 813f4202a49..47f97b8087f 100644 --- a/source/blender/editors/space_buttons/buttons_ops.c +++ b/source/blender/editors/space_buttons/buttons_ops.c @@ -102,6 +102,7 @@ typedef struct FileBrowseOp { static int file_browse_exec(bContext *C, wmOperator *op) { + Main *bmain = CTX_data_main(C); FileBrowseOp *fbo = op->customdata; ID *id; char *str, path[FILE_MAX]; @@ -118,14 +119,14 @@ static int file_browse_exec(bContext *C, wmOperator *op) id = fbo->ptr.id.data; BLI_strncpy(path, str, FILE_MAX); - BLI_path_abs(path, id ? ID_BLEND_PATH(G.main, id) : G.main->name); + BLI_path_abs(path, id ? ID_BLEND_PATH(bmain, id) : BKE_main_blendfile_path(bmain)); if (BLI_is_dir(path)) { /* do this first so '//' isnt converted to '//\' on windows */ BLI_add_slash(path); if (is_relative) { BLI_strncpy(path, str, FILE_MAX); - BLI_path_rel(path, G.main->name); + BLI_path_rel(path, BKE_main_blendfile_path(bmain)); str = MEM_reallocN(str, strlen(path) + 2); BLI_strncpy(str, path, FILE_MAX); } diff --git a/source/blender/editors/space_buttons/space_buttons.c b/source/blender/editors/space_buttons/space_buttons.c index 11857dd0b27..be687d365f3 100644 --- a/source/blender/editors/space_buttons/space_buttons.c +++ b/source/blender/editors/space_buttons/space_buttons.c @@ -52,6 +52,8 @@ #include "UI_resources.h" +#include "GPU_glew.h" + #include "buttons_intern.h" /* own include */ /* ******************** default callbacks for buttons space ***************** */ @@ -144,7 +146,6 @@ static void buttons_main_region_init(wmWindowManager *wm, ARegion *ar) static void buttons_main_region_draw_properties(const bContext *C, SpaceButs *sbuts, ARegion *ar) { - BLI_assert(sbuts->space_subtype == SB_SUBTYPE_DATA); const bool vertical = (sbuts->align == BUT_VERTICAL); buttons_context_compute(C, sbuts); @@ -197,6 +198,9 @@ static void buttons_main_region_draw_properties(const bContext *C, SpaceButs *sb case BCONTEXT_BONE_CONSTRAINT: contexts[0] = "bone_constraint"; break; + case BCONTEXT_TOOL: + contexts[0] = "tool"; + break; } if (contexts[0]) { @@ -206,13 +210,12 @@ static void buttons_main_region_draw_properties(const bContext *C, SpaceButs *sb static void buttons_main_region_draw_tool(const bContext *C, SpaceButs *sbuts, ARegion *ar) { - BLI_assert(sbuts->space_subtype == SB_SUBTYPE_TOOL); const bool vertical = (sbuts->align == BUT_VERTICAL); + const char *contexts[3] = {NULL}; const WorkSpace *workspace = CTX_wm_workspace(C); if (workspace->tools_space_type == SPACE_VIEW3D) { const int mode = CTX_data_mode_enum(C); - const char *contexts[3] = {NULL}; switch (mode) { case CTX_MODE_EDIT_MESH: ARRAY_SET_ITEMS(contexts, ".mesh_edit"); @@ -264,6 +267,11 @@ static void buttons_main_region_draw_tool(const bContext *C, SpaceButs *sbuts, A else if (workspace->tools_space_type == SPACE_IMAGE) { /* TODO */ } + + if (contexts[0] == NULL) { + UI_ThemeClearColor(TH_BACK); + glClear(GL_COLOR_BUFFER_BIT); + } } static void buttons_main_region_draw(const bContext *C, ARegion *ar) @@ -271,12 +279,12 @@ static void buttons_main_region_draw(const bContext *C, ARegion *ar) /* draw entirely, view changes should be handled here */ SpaceButs *sbuts = CTX_wm_space_buts(C); - if (sbuts->space_subtype == SB_SUBTYPE_DATA) { - buttons_main_region_draw_properties(C, sbuts, ar); - } - else if (sbuts->space_subtype == SB_SUBTYPE_TOOL) { + if (sbuts->mainb == BCONTEXT_TOOL) { buttons_main_region_draw_tool(C, sbuts, ar); } + else { + buttons_main_region_draw_properties(C, sbuts, ar); + } sbuts->re_align = 0; sbuts->mainbo = sbuts->mainb; @@ -320,10 +328,8 @@ static void buttons_header_region_draw(const bContext *C, ARegion *ar) { SpaceButs *sbuts = CTX_wm_space_buts(C); - if (sbuts->space_subtype == SB_SUBTYPE_DATA) { - /* Needed for RNA to get the good values! */ - buttons_context_compute(C, sbuts); - } + /* Needed for RNA to get the good values! */ + buttons_context_compute(C, sbuts); ED_region_header(C, ar); } @@ -590,24 +596,6 @@ static void buttons_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, } } -static int buttons_space_subtype_get(ScrArea *sa) -{ - SpaceButs *sbuts = sa->spacedata.first; - return sbuts->space_subtype; -} - -static void buttons_space_subtype_set(ScrArea *sa, int value) -{ - SpaceButs *sbuts = sa->spacedata.first; - sbuts->space_subtype = value; -} - -static void buttons_space_subtype_item_extend( - bContext *UNUSED(C), EnumPropertyItem **item, int *totitem) -{ - RNA_enum_items_add(item, totitem, rna_enum_space_button_mode_items); -} - /* only called once, from space/spacetypes.c */ void ED_spacetype_buttons(void) { @@ -626,9 +614,6 @@ void ED_spacetype_buttons(void) st->listener = buttons_area_listener; st->context = buttons_context; st->id_remap = buttons_id_remap; - st->space_subtype_item_extend = buttons_space_subtype_item_extend; - st->space_subtype_get = buttons_space_subtype_get; - st->space_subtype_set = buttons_space_subtype_set; /* regions: main window */ art = MEM_callocN(sizeof(ARegionType), "spacetype buttons region"); diff --git a/source/blender/editors/space_clip/clip_ops.c b/source/blender/editors/space_clip/clip_ops.c index 0d9371a7784..498a4d6fbbd 100644 --- a/source/blender/editors/space_clip/clip_ops.c +++ b/source/blender/editors/space_clip/clip_ops.c @@ -318,7 +318,7 @@ static int reload_exec(bContext *C, wmOperator *UNUSED(op)) if (!clip) return OPERATOR_CANCELLED; - BKE_movieclip_reload(clip); + BKE_movieclip_reload(CTX_data_main(C), clip); WM_event_add_notifier(C, NC_MOVIECLIP | NA_EDITED, clip); @@ -1315,7 +1315,7 @@ static void proxy_endjob(void *pjv) if (pj->clip->source == MCLIP_SRC_MOVIE) { /* Timecode might have changed, so do a full reload to deal with this. */ - BKE_movieclip_reload(pj->clip); + BKE_movieclip_reload(pj->main, pj->clip); } else { /* For image sequences we'll preserve original cache. */ diff --git a/source/blender/editors/space_file/file_draw.c b/source/blender/editors/space_file/file_draw.c index fcfe745546e..360009d3ea4 100644 --- a/source/blender/editors/space_file/file_draw.c +++ b/source/blender/editors/space_file/file_draw.c @@ -424,6 +424,7 @@ static void file_draw_preview( static void renamebutton_cb(bContext *C, void *UNUSED(arg1), char *oldname) { + Main *bmain = CTX_data_main(C); char newname[FILE_MAX + 12]; char orgname[FILE_MAX + 12]; char filename[FILE_MAX + 12]; @@ -432,10 +433,11 @@ static void renamebutton_cb(bContext *C, void *UNUSED(arg1), char *oldname) ScrArea *sa = CTX_wm_area(C); ARegion *ar = CTX_wm_region(C); - BLI_make_file_string(G.main->name, orgname, sfile->params->dir, oldname); + const char *blendfile_path = BKE_main_blendfile_path(bmain); + BLI_make_file_string(blendfile_path, orgname, sfile->params->dir, oldname); BLI_strncpy(filename, sfile->params->renameedit, sizeof(filename)); BLI_filename_make_safe(filename); - BLI_make_file_string(G.main->name, newname, sfile->params->dir, filename); + BLI_make_file_string(blendfile_path, newname, sfile->params->dir, filename); if (!STREQ(orgname, newname)) { if (!BLI_exists(newname)) { diff --git a/source/blender/editors/space_file/file_intern.h b/source/blender/editors/space_file/file_intern.h index 977d9fe7f3a..742715039cf 100644 --- a/source/blender/editors/space_file/file_intern.h +++ b/source/blender/editors/space_file/file_intern.h @@ -109,9 +109,9 @@ void file_filename_enter_handle(bContext *C, void *arg_unused, void *arg_but); int file_highlight_set(struct SpaceFile *sfile, struct ARegion *ar, int mx, int my); void file_sfile_filepath_set(struct SpaceFile *sfile, const char *filepath); -void file_sfile_to_operator_ex(struct wmOperator *op, struct SpaceFile *sfile, char *filepath); -void file_sfile_to_operator(struct wmOperator *op, struct SpaceFile *sfile); -void file_operator_to_sfile(struct SpaceFile *sfile, struct wmOperator *op); +void file_sfile_to_operator_ex(bContext *C, struct wmOperator *op, struct SpaceFile *sfile, char *filepath); +void file_sfile_to_operator(bContext *C, struct wmOperator *op, struct SpaceFile *sfile); +void file_operator_to_sfile(bContext *C, struct SpaceFile *sfile, struct wmOperator *op); /* filesel.c */ diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c index 828cca53012..0cd31ce7ca5 100644 --- a/source/blender/editors/space_file/file_ops.c +++ b/source/blender/editors/space_file/file_ops.c @@ -176,6 +176,7 @@ static FileSelection file_selection_get(bContext *C, const rcti *rect, bool fill static FileSelect file_select_do(bContext *C, int selected_idx, bool do_diropen) { + Main *bmain = CTX_data_main(C); FileSelect retval = FILE_SELECT_NOTHING; SpaceFile *sfile = CTX_wm_space_file(C); FileSelectParams *params = ED_fileselect_get_params(sfile); @@ -213,7 +214,7 @@ static FileSelect file_select_do(bContext *C, int selected_idx, bool do_diropen) } } else { - BLI_cleanup_dir(G.main->name, params->dir); + BLI_cleanup_dir(BKE_main_blendfile_path(bmain), params->dir); strcat(params->dir, file->relpath); BLI_add_slash(params->dir); } @@ -826,6 +827,7 @@ void FILE_OT_select_all_toggle(wmOperatorType *ot) /* Note we could get rid of this one, but it's used by some addon so... Does not hurt keeping it around for now. */ static int bookmark_select_exec(bContext *C, wmOperator *op) { + Main *bmain = CTX_data_main(C); SpaceFile *sfile = CTX_wm_space_file(C); PropertyRNA *prop; @@ -835,7 +837,7 @@ static int bookmark_select_exec(bContext *C, wmOperator *op) RNA_property_string_get(op->ptr, prop, entry); BLI_strncpy(params->dir, entry, sizeof(params->dir)); - BLI_cleanup_dir(G.main->name, params->dir); + BLI_cleanup_dir(BKE_main_blendfile_path(bmain), params->dir); ED_file_change_dir(C); WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL); @@ -1200,15 +1202,16 @@ void FILE_OT_cancel(struct wmOperatorType *ot) } -void file_sfile_to_operator_ex(wmOperator *op, SpaceFile *sfile, char *filepath) +void file_sfile_to_operator_ex(bContext *C, wmOperator *op, SpaceFile *sfile, char *filepath) { + Main *bmain = CTX_data_main(C); PropertyRNA *prop; BLI_join_dirfile(filepath, FILE_MAX, sfile->params->dir, sfile->params->file); /* XXX, not real length */ if ((prop = RNA_struct_find_property(op->ptr, "relative_path"))) { if (RNA_property_boolean_get(op->ptr, prop)) { - BLI_path_rel(filepath, G.main->name); + BLI_path_rel(filepath, BKE_main_blendfile_path(bmain)); } } @@ -1270,15 +1273,16 @@ void file_sfile_to_operator_ex(wmOperator *op, SpaceFile *sfile, char *filepath) } } -void file_sfile_to_operator(wmOperator *op, SpaceFile *sfile) +void file_sfile_to_operator(bContext *C, wmOperator *op, SpaceFile *sfile) { char filepath[FILE_MAX]; - file_sfile_to_operator_ex(op, sfile, filepath); + file_sfile_to_operator_ex(C, op, sfile, filepath); } -void file_operator_to_sfile(SpaceFile *sfile, wmOperator *op) +void file_operator_to_sfile(bContext *C, SpaceFile *sfile, wmOperator *op) { + Main *bmain = CTX_data_main(C); PropertyRNA *prop; /* If neither of the above are set, split the filepath back */ @@ -1298,7 +1302,7 @@ void file_operator_to_sfile(SpaceFile *sfile, wmOperator *op) /* we could check for relative_path property which is used when converting * in the other direction but doesnt hurt to do this every time */ - BLI_path_abs(sfile->params->dir, G.main->name); + BLI_path_abs(sfile->params->dir, BKE_main_blendfile_path(bmain)); /* XXX, files and dirs updates missing, not really so important though */ } @@ -1330,11 +1334,11 @@ void file_draw_check(bContext *C) wmOperator *op = sfile->op; if (op) { /* fail on reload */ if (op->type->check) { - file_sfile_to_operator(op, sfile); + file_sfile_to_operator(C, op, sfile); /* redraw */ if (op->type->check(C, op)) { - file_operator_to_sfile(sfile, op); + file_operator_to_sfile(C, sfile, op); /* redraw, else the changed settings wont get updated */ ED_area_tag_redraw(CTX_wm_area(C)); @@ -1369,6 +1373,7 @@ bool file_draw_check_exists(SpaceFile *sfile) int file_exec(bContext *C, wmOperator *exec_op) { + Main *bmain = CTX_data_main(C); wmWindowManager *wm = CTX_wm_manager(C); SpaceFile *sfile = CTX_wm_space_file(C); const struct FileDirEntry *file = filelist_file(sfile->files, sfile->params->active_file); @@ -1384,7 +1389,7 @@ int file_exec(bContext *C, wmOperator *exec_op) BLI_parent_dir(sfile->params->dir); } else { - BLI_cleanup_path(G.main->name, sfile->params->dir); + BLI_cleanup_path(BKE_main_blendfile_path(bmain), sfile->params->dir); BLI_path_append(sfile->params->dir, sizeof(sfile->params->dir) - 1, file->relpath); BLI_add_slash(sfile->params->dir); } @@ -1413,14 +1418,14 @@ int file_exec(bContext *C, wmOperator *exec_op) sfile->op = NULL; - file_sfile_to_operator_ex(op, sfile, filepath); + file_sfile_to_operator_ex(C, op, sfile, filepath); if (BLI_exists(sfile->params->dir)) { fsmenu_insert_entry(ED_fsmenu_get(), FS_CATEGORY_RECENT, sfile->params->dir, NULL, FS_INSERT_SAVE | FS_INSERT_FIRST); } - BLI_make_file_string(G.main->name, filepath, BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL), + BLI_make_file_string(BKE_main_blendfile_path(bmain), filepath, BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL), BLENDER_BOOKMARK_FILE); fsmenu_write_file(ED_fsmenu_get(), filepath); WM_event_fileselect_event(wm, op, EVT_FILESELECT_EXEC); @@ -1452,11 +1457,12 @@ void FILE_OT_execute(struct wmOperatorType *ot) int file_parent_exec(bContext *C, wmOperator *UNUSED(unused)) { + Main *bmain = CTX_data_main(C); SpaceFile *sfile = CTX_wm_space_file(C); if (sfile->params) { if (BLI_parent_dir(sfile->params->dir)) { - BLI_cleanup_dir(G.main->name, sfile->params->dir); + BLI_cleanup_dir(BKE_main_blendfile_path(bmain), sfile->params->dir); ED_file_change_dir(C); if (sfile->params->recursion_level > 1) { /* Disable 'dirtree' recursion when going up in tree. */ @@ -1694,7 +1700,7 @@ static int filepath_drop_exec(bContext *C, wmOperator *op) file_sfile_filepath_set(sfile, filepath); if (sfile->op) { - file_sfile_to_operator(sfile->op, sfile); + file_sfile_to_operator(C, sfile->op, sfile); file_draw_check(C); } @@ -1840,12 +1846,13 @@ void FILE_OT_directory_new(struct wmOperatorType *ot) /* TODO This should go to BLI_path_utils. */ static void file_expand_directory(bContext *C) { + Main *bmain = CTX_data_main(C); SpaceFile *sfile = CTX_wm_space_file(C); if (sfile->params) { if (BLI_path_is_rel(sfile->params->dir)) { /* Use of 'default' folder here is just to avoid an error message on '//' prefix. */ - BLI_path_abs(sfile->params->dir, G.relbase_valid ? G.main->name : BKE_appdir_folder_default()); + BLI_path_abs(sfile->params->dir, G.relbase_valid ? BKE_main_blendfile_path(bmain) : BKE_appdir_folder_default()); } else if (sfile->params->dir[0] == '~') { char tmpstr[sizeof(sfile->params->dir) - 1]; @@ -1898,6 +1905,7 @@ static bool can_create_dir(const char *dir) void file_directory_enter_handle(bContext *C, void *UNUSED(arg_unused), void *UNUSED(arg_but)) { + Main *bmain = CTX_data_main(C); SpaceFile *sfile = CTX_wm_space_file(C); if (sfile->params) { @@ -1928,7 +1936,7 @@ void file_directory_enter_handle(bContext *C, void *UNUSED(arg_unused), void *UN } } - BLI_cleanup_dir(G.main->name, sfile->params->dir); + BLI_cleanup_dir(BKE_main_blendfile_path(bmain), sfile->params->dir); if (filelist_is_dir(sfile->files, sfile->params->dir)) { /* if directory exists, enter it immediately */ @@ -1975,6 +1983,7 @@ void file_directory_enter_handle(bContext *C, void *UNUSED(arg_unused), void *UN void file_filename_enter_handle(bContext *C, void *UNUSED(arg_unused), void *arg_but) { + Main *bmain = CTX_data_main(C); SpaceFile *sfile = CTX_wm_space_file(C); uiBut *but = arg_but; char matched_file[FILE_MAX]; @@ -2004,7 +2013,7 @@ void file_filename_enter_handle(bContext *C, void *UNUSED(arg_unused), void *arg /* if directory, open it and empty filename field */ if (filelist_is_dir(sfile->files, filepath)) { - BLI_cleanup_dir(G.main->name, filepath); + BLI_cleanup_dir(BKE_main_blendfile_path(bmain), filepath); BLI_strncpy(sfile->params->dir, filepath, sizeof(sfile->params->dir)); sfile->params->file[0] = '\0'; ED_file_change_dir(C); @@ -2269,6 +2278,7 @@ static int file_delete_poll(bContext *C) int file_delete_exec(bContext *C, wmOperator *op) { char str[FILE_MAX]; + Main *bmain = CTX_data_main(C); wmWindowManager *wm = CTX_wm_manager(C); SpaceFile *sfile = CTX_wm_space_file(C); ScrArea *sa = CTX_wm_area(C); @@ -2281,7 +2291,7 @@ int file_delete_exec(bContext *C, wmOperator *op) for (i = 0; i < numfiles; i++) { if (filelist_entry_select_index_get(sfile->files, i, CHECK_FILES)) { file = filelist_file(sfile->files, i); - BLI_make_file_string(G.main->name, str, sfile->params->dir, file->relpath); + BLI_make_file_string(BKE_main_blendfile_path(bmain), str, sfile->params->dir, file->relpath); if (BLI_delete(str, false, false) != 0 || BLI_exists(str)) { diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c index c975479e402..8123bed541c 100644 --- a/source/blender/editors/space_file/filelist.c +++ b/source/blender/editors/space_file/filelist.c @@ -1419,7 +1419,7 @@ void filelist_setdir(struct FileList *filelist, char *r_dir) { BLI_assert(strlen(r_dir) < FILE_MAX_LIBEXTRA); - BLI_cleanup_dir(G.main->name, r_dir); + BLI_cleanup_dir(BKE_main_blendfile_path_from_global(), r_dir); const bool is_valid_path = filelist->checkdirf(filelist, r_dir, true); BLI_assert(is_valid_path); UNUSED_VARS_NDEBUG(is_valid_path); @@ -2313,7 +2313,7 @@ static int filelist_readjob_list_lib(const char *root, ListBase *entries, const #if 0 /* Kept for reference here, in case we want to add back that feature later. We do not need it currently. */ /* Code ***NOT*** updated for job stuff! */ -static void filelist_readjob_main_rec(struct FileList *filelist) +static void filelist_readjob_main_rec(Main *bmain, FileList *filelist) { ID *id; FileDirEntry *files, *firstlib = NULL; @@ -2375,7 +2375,7 @@ static void filelist_readjob_main_rec(struct FileList *filelist) /* make files */ idcode = groupname_to_code(filelist->filelist.root); - lb = which_libbase(G.main, idcode); + lb = which_libbase(bmain, idcode); if (lb == NULL) return; filelist->filelist.nbr_entries = 0; @@ -2700,13 +2700,14 @@ static void filelist_readjob_free(void *flrjv) void filelist_readjob_start(FileList *filelist, const bContext *C) { + Main *bmain = CTX_data_main(C); wmJob *wm_job; FileListReadJob *flrj; /* prepare job data */ flrj = MEM_callocN(sizeof(*flrj), __func__); flrj->filelist = filelist; - BLI_strncpy(flrj->main_name, G.main->name, sizeof(flrj->main_name)); + BLI_strncpy(flrj->main_name, BKE_main_blendfile_path(bmain), sizeof(flrj->main_name)); filelist->flags &= ~(FL_FORCE_RESET | FL_IS_READY); filelist->flags |= FL_IS_PENDING; diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c index 9ba3c788daf..418a9f8c16f 100644 --- a/source/blender/editors/space_file/filesel.c +++ b/source/blender/editors/space_file/filesel.c @@ -96,11 +96,13 @@ short ED_fileselect_set_params(SpaceFile *sfile) FileSelectParams *params; wmOperator *op = sfile->op; + const char *blendfile_path = BKE_main_blendfile_path_from_global(); + /* create new parameters if necessary */ if (!sfile->params) { sfile->params = MEM_callocN(sizeof(FileSelectParams), "fileselparams"); /* set path to most recently opened .blend */ - BLI_split_dirfile(G.main->name, sfile->params->dir, sfile->params->file, sizeof(sfile->params->dir), sizeof(sfile->params->file)); + BLI_split_dirfile(blendfile_path, sfile->params->dir, sfile->params->file, sizeof(sfile->params->dir), sizeof(sfile->params->file)); sfile->params->filter_glob[0] = '\0'; /* set the default thumbnails size */ sfile->params->thumbnail_size = 128; @@ -149,8 +151,8 @@ short ED_fileselect_set_params(SpaceFile *sfile) } if (params->dir[0]) { - BLI_cleanup_dir(G.main->name, params->dir); - BLI_path_abs(params->dir, G.main->name); + BLI_cleanup_dir(blendfile_path, params->dir); + BLI_path_abs(params->dir, blendfile_path); } if (is_directory == true && is_filename == false && is_filepath == false && is_files == false) { @@ -283,8 +285,8 @@ short ED_fileselect_set_params(SpaceFile *sfile) sfile->folders_prev = folderlist_new(); if (!sfile->params->dir[0]) { - if (G.main->name[0]) { - BLI_split_dir_part(G.main->name, sfile->params->dir, sizeof(sfile->params->dir)); + if (blendfile_path[0] != '\0') { + BLI_split_dir_part(blendfile_path, sfile->params->dir, sizeof(sfile->params->dir)); } else { const char *doc_path = BKE_appdir_folder_default(); diff --git a/source/blender/editors/space_graph/graph_edit.c b/source/blender/editors/space_graph/graph_edit.c index ef4bb917700..26a6e93ba57 100644 --- a/source/blender/editors/space_graph/graph_edit.c +++ b/source/blender/editors/space_graph/graph_edit.c @@ -54,10 +54,11 @@ #include "BLT_translation.h" +#include "BKE_context.h" #include "BKE_fcurve.h" #include "BKE_global.h" +#include "BKE_main.h" #include "BKE_nla.h" -#include "BKE_context.h" #include "BKE_report.h" #include "DEG_depsgraph_build.h" @@ -609,7 +610,8 @@ static void insert_graph_keys(bAnimContext *ac, eGraphKeys_InsertKey_Types mode) * up adding the keyframes on a new F-Curve in the action data instead. */ if (ale->id && !ale->owner && !fcu->driver) { - insert_keyframe(depsgraph, reports, ale->id, NULL, ((fcu->grp) ? (fcu->grp->name) : (NULL)), fcu->rna_path, fcu->array_index, cfra, ts->keyframe_type, flag); + insert_keyframe(ac->bmain, depsgraph, reports, ale->id, NULL, ((fcu->grp) ? (fcu->grp->name) : (NULL)), + fcu->rna_path, fcu->array_index, cfra, ts->keyframe_type, flag); } else { const float curval = evaluate_fcurve(fcu, cfra); diff --git a/source/blender/editors/space_graph/graph_ops.c b/source/blender/editors/space_graph/graph_ops.c index b90fdd9ac67..bae5798ca21 100644 --- a/source/blender/editors/space_graph/graph_ops.c +++ b/source/blender/editors/space_graph/graph_ops.c @@ -614,6 +614,8 @@ static void graphedit_keymap_keyframes(wmKeyConfig *keyconf, wmKeyMap *keymap) WM_keymap_add_menu(keymap, "GRAPH_MT_delete", XKEY, KM_PRESS, 0, 0); WM_keymap_add_menu(keymap, "GRAPH_MT_delete", DELKEY, KM_PRESS, 0, 0); + WM_keymap_add_menu(keymap, "GRAPH_MT_specials", WKEY, KM_PRESS, 0, 0); + WM_keymap_add_item(keymap, "GRAPH_OT_duplicate_move", DKEY, KM_PRESS, KM_SHIFT, 0); /* insertkey */ @@ -715,4 +717,3 @@ void graphedit_keymap(wmKeyConfig *keyconf) keymap = WM_keymap_find(keyconf, "Graph Editor", SPACE_IPO, 0); graphedit_keymap_keyframes(keyconf, keymap); } - diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c index 95cbc4fe4a2..d17eb357ff6 100644 --- a/source/blender/editors/space_image/image_ops.c +++ b/source/blender/editors/space_image/image_ops.c @@ -227,7 +227,7 @@ static int space_image_file_exists_poll(bContext *C) ibuf = ED_space_image_acquire_buffer(sima, &lock); if (ibuf) { BLI_strncpy(name, ibuf->name, FILE_MAX); - BLI_path_abs(name, bmain->name); + BLI_path_abs(name, BKE_main_blendfile_path(bmain)); if (BLI_exists(name) == false) { CTX_wm_operator_poll_msg_set(C, "image file not found"); @@ -1263,11 +1263,11 @@ static int image_open_exec(bContext *C, wmOperator *op) BLI_strncpy(filepath_range, frame_range->filepath, sizeof(filepath_range)); if (was_relative) { - BLI_path_rel(filepath_range, bmain->name); + BLI_path_rel(filepath_range, BKE_main_blendfile_path(bmain)); } Image *ima_range = image_open_single( - op, filepath_range, bmain->name, + op, filepath_range, BKE_main_blendfile_path(bmain), is_relative_path, use_multiview, frame_range_seq_len); /* take the first image */ @@ -1282,7 +1282,7 @@ static int image_open_exec(bContext *C, wmOperator *op) else { /* for drag & drop etc. */ ima = image_open_single( - op, filepath, bmain->name, + op, filepath, BKE_main_blendfile_path(bmain), is_relative_path, use_multiview, 1); } @@ -1692,12 +1692,12 @@ static int save_image_options_init(Main *bmain, SaveImageOptions *simopts, Space } else { BLI_strncpy(simopts->filepath, "//untitled", sizeof(simopts->filepath)); - BLI_path_abs(simopts->filepath, bmain->name); + BLI_path_abs(simopts->filepath, BKE_main_blendfile_path(bmain)); } } else { BLI_snprintf(simopts->filepath, sizeof(simopts->filepath), "//%s", ima->id.name + 2); - BLI_path_abs(simopts->filepath, is_prev_save ? G.ima : bmain->name); + BLI_path_abs(simopts->filepath, is_prev_save ? G.ima : BKE_main_blendfile_path(bmain)); } } @@ -1721,7 +1721,7 @@ static void save_image_options_from_op(Main *bmain, SaveImageOptions *simopts, w if (RNA_struct_property_is_set(op->ptr, "filepath")) { RNA_string_get(op->ptr, "filepath", simopts->filepath); - BLI_path_abs(simopts->filepath, bmain->name); + BLI_path_abs(simopts->filepath, BKE_main_blendfile_path(bmain)); } } @@ -2302,7 +2302,7 @@ static int image_save_sequence_exec(bContext *C, wmOperator *op) char name[FILE_MAX]; BLI_strncpy(name, ibuf->name, sizeof(name)); - BLI_path_abs(name, bmain->name); + BLI_path_abs(name, BKE_main_blendfile_path(bmain)); if (0 == IMB_saveiff(ibuf, name, IB_rect | IB_zbuf | IB_zbuffloat)) { BKE_reportf(op->reports, RPT_ERROR, "Could not write image: %s", strerror(errno)); diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c index 28ce88b38f5..c143ebbcd67 100644 --- a/source/blender/editors/space_image/space_image.c +++ b/source/blender/editors/space_image/space_image.c @@ -302,6 +302,8 @@ static void image_keymap(struct wmKeyConfig *keyconf) WM_keymap_add_item(keymap, "IMAGE_OT_properties", NKEY, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "IMAGE_OT_toolshelf", TKEY, KM_PRESS, 0, 0); + WM_keymap_add_menu(keymap, "IMAGE_MT_specials", WKEY, KM_PRESS, 0, 0); + WM_keymap_add_item(keymap, "IMAGE_OT_cycle_render_slot", JKEY, KM_PRESS, 0, 0); RNA_boolean_set(WM_keymap_add_item(keymap, "IMAGE_OT_cycle_render_slot", JKEY, KM_PRESS, KM_ALT, 0)->ptr, "reverse", true); @@ -1134,4 +1136,3 @@ void ED_spacetype_image(void) BKE_spacetype_register(st); } - diff --git a/source/blender/editors/space_info/info_ops.c b/source/blender/editors/space_info/info_ops.c index 981630e96f6..acd0a856f1a 100644 --- a/source/blender/editors/space_info/info_ops.c +++ b/source/blender/editors/space_info/info_ops.c @@ -364,7 +364,7 @@ static int make_paths_relative_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - BKE_bpath_relative_convert(bmain, bmain->name, op->reports); + BKE_bpath_relative_convert(bmain, BKE_main_blendfile_path(bmain), op->reports); /* redraw everything so any changed paths register */ WM_main_add_notifier(NC_WINDOW, NULL); @@ -397,7 +397,7 @@ static int make_paths_absolute_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - BKE_bpath_absolute_convert(bmain, bmain->name, op->reports); + BKE_bpath_absolute_convert(bmain, BKE_main_blendfile_path(bmain), op->reports); /* redraw everything so any changed paths register */ WM_main_add_notifier(NC_WINDOW, NULL); diff --git a/source/blender/editors/space_node/node_ops.c b/source/blender/editors/space_node/node_ops.c index 6f37c32be40..3b6cc8a89cf 100644 --- a/source/blender/editors/space_node/node_ops.c +++ b/source/blender/editors/space_node/node_ops.c @@ -274,6 +274,8 @@ void node_keymap(struct wmKeyConfig *keyconf) WM_keymap_add_item(keymap, "NODE_OT_backimage_fit", HOMEKEY, KM_PRESS, KM_ALT, 0); WM_keymap_add_item(keymap, "NODE_OT_backimage_sample", ACTIONMOUSE, KM_PRESS, KM_ALT, 0); + WM_keymap_add_menu(keymap, "NODE_MT_specials", WKEY, KM_PRESS, 0, 0); + kmi = WM_keymap_add_item(keymap, "NODE_OT_link_make", FKEY, KM_PRESS, 0, 0); RNA_boolean_set(kmi->ptr, "replace", false); kmi = WM_keymap_add_item(keymap, "NODE_OT_link_make", FKEY, KM_PRESS, KM_SHIFT, 0); diff --git a/source/blender/editors/space_node/node_relationships.c b/source/blender/editors/space_node/node_relationships.c index b0d8b51f8e2..682174ebbed 100644 --- a/source/blender/editors/space_node/node_relationships.c +++ b/source/blender/editors/space_node/node_relationships.c @@ -726,11 +726,14 @@ static int node_link_modal(bContext *C, wmOperator *op, const wmEvent *event) case RIGHTMOUSE: case MIDDLEMOUSE: { - node_link_exit(C, op, true); + if (event->val == KM_RELEASE) { + node_link_exit(C, op, true); - ED_area_headerprint(CTX_wm_area(C), NULL); - ED_region_tag_redraw(ar); - return OPERATOR_FINISHED; + ED_area_headerprint(CTX_wm_area(C), NULL); + ED_region_tag_redraw(ar); + return OPERATOR_FINISHED; + } + break; } } diff --git a/source/blender/editors/space_node/node_templates.c b/source/blender/editors/space_node/node_templates.c index bc9513a748d..5a2feacf20c 100644 --- a/source/blender/editors/space_node/node_templates.c +++ b/source/blender/editors/space_node/node_templates.c @@ -634,7 +634,7 @@ static void ui_node_draw_node(uiLayout *layout, bContext *C, bNodeTree *ntree, b if (node->typeinfo->draw_buttons) { if (node->type != NODE_GROUP) { - split = uiLayoutSplit(layout, 0.35f, false); + split = uiLayoutSplit(layout, 0.5f, false); col = uiLayoutColumn(split, false); col = uiLayoutColumn(split, false); @@ -677,10 +677,10 @@ static void ui_node_draw_input(uiLayout *layout, bContext *C, bNodeTree *ntree, label[i] = ' '; } label[indent] = '\0'; - BLI_snprintf(label + indent, UI_MAX_NAME_STR - indent, "%s:", IFACE_(input->name)); + BLI_snprintf(label + indent, UI_MAX_NAME_STR - indent, "%s", IFACE_(input->name)); /* split in label and value */ - split = uiLayoutSplit(layout, 0.35f, false); + split = uiLayoutSplit(layout, 0.5f, false); row = uiLayoutRow(split, true); @@ -702,7 +702,7 @@ static void ui_node_draw_input(uiLayout *layout, bContext *C, bNodeTree *ntree, uiItemL(row, label, ICON_NONE); bt = block->buttons.last; - bt->drawflag = UI_BUT_TEXT_LEFT; + bt->drawflag = UI_BUT_TEXT_RIGHT; if (dependency_loop) { row = uiLayoutRow(split, false); diff --git a/source/blender/editors/space_node/node_view.c b/source/blender/editors/space_node/node_view.c index 1cf377643a3..d52a6a89413 100644 --- a/source/blender/editors/space_node/node_view.c +++ b/source/blender/editors/space_node/node_view.c @@ -225,11 +225,12 @@ static int snode_bg_viewmove_modal(bContext *C, wmOperator *op, const wmEvent *e case LEFTMOUSE: case MIDDLEMOUSE: case RIGHTMOUSE: - - MEM_freeN(nvm); - op->customdata = NULL; - - return OPERATOR_FINISHED; + if (event->val == KM_RELEASE) { + MEM_freeN(nvm); + op->customdata = NULL; + return OPERATOR_FINISHED; + } + break; } return OPERATOR_RUNNING_MODAL; diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c index 454f7b0097f..3dea8dd8a9b 100644 --- a/source/blender/editors/space_outliner/outliner_draw.c +++ b/source/blender/editors/space_outliner/outliner_draw.c @@ -310,7 +310,7 @@ static void namebutton_cb(bContext *C, void *tsep, char *oldname) BKE_library_filepath_set(bmain, lib, lib->name); BLI_strncpy(expanded, lib->name, sizeof(expanded)); - BLI_path_abs(expanded, bmain->name); + BLI_path_abs(expanded, BKE_main_blendfile_path(bmain)); if (!BLI_exists(expanded)) { BKE_reportf(CTX_wm_reports(C), RPT_ERROR, "Library path '%s' does not exist, correct this before saving", expanded); @@ -340,7 +340,7 @@ static void namebutton_cb(bContext *C, void *tsep, char *oldname) /* restore bone name */ BLI_strncpy(newname, ebone->name, sizeof(ebone->name)); BLI_strncpy(ebone->name, oldname, sizeof(ebone->name)); - ED_armature_bone_rename(obedit->data, oldname, newname); + ED_armature_bone_rename(bmain, obedit->data, oldname, newname); WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL); } break; @@ -360,7 +360,7 @@ static void namebutton_cb(bContext *C, void *tsep, char *oldname) /* restore bone name */ BLI_strncpy(newname, bone->name, sizeof(bone->name)); BLI_strncpy(bone->name, oldname, sizeof(bone->name)); - ED_armature_bone_rename(arm, oldname, newname); + ED_armature_bone_rename(bmain, arm, oldname, newname); WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL); break; } @@ -380,7 +380,7 @@ static void namebutton_cb(bContext *C, void *tsep, char *oldname) /* restore bone name */ BLI_strncpy(newname, pchan->name, sizeof(pchan->name)); BLI_strncpy(pchan->name, oldname, sizeof(pchan->name)); - ED_armature_bone_rename(ob->data, oldname, newname); + ED_armature_bone_rename(bmain, ob->data, oldname, newname); WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL); break; } diff --git a/source/blender/editors/space_outliner/outliner_select.c b/source/blender/editors/space_outliner/outliner_select.c index 441765528d1..af1b11b28d2 100644 --- a/source/blender/editors/space_outliner/outliner_select.c +++ b/source/blender/editors/space_outliner/outliner_select.c @@ -47,6 +47,7 @@ #include "BKE_collection.h" #include "BKE_context.h" #include "BKE_layer.h" +#include "BKE_main.h" #include "BKE_object.h" #include "BKE_scene.h" #include "BKE_sequencer.h" @@ -74,6 +75,7 @@ static void do_outliner_activate_obdata(bContext *C, Scene *scene, ViewLayer *view_layer, Base *base) { + Main *bmain = CTX_data_main(C); Object *obact = OBACT(view_layer); bool use_all = false; @@ -95,7 +97,7 @@ static void do_outliner_activate_obdata(bContext *C, Scene *scene, ViewLayer *vi if (ob->type == obact->type) { bool ok; if (BKE_object_is_in_editmode(ob)) { - ok = ED_object_editmode_exit_ex(scene, ob, EM_FREEDATA | EM_WAITCURSOR); + ok = ED_object_editmode_exit_ex(bmain, scene, ob, EM_FREEDATA | EM_WAITCURSOR); } else { ok = ED_object_editmode_enter_ex(CTX_data_main(C), scene, ob, EM_WAITCURSOR | EM_NO_CONTEXT); diff --git a/source/blender/editors/space_sequencer/sequencer_add.c b/source/blender/editors/space_sequencer/sequencer_add.c index bf1ca68745f..a8688b26280 100644 --- a/source/blender/editors/space_sequencer/sequencer_add.c +++ b/source/blender/editors/space_sequencer/sequencer_add.c @@ -117,7 +117,7 @@ static void sequencer_generic_invoke_path__internal(bContext *C, wmOperator *op, Main *bmain = CTX_data_main(C); char path[FILE_MAX]; BLI_strncpy(path, last_seq->strip->dir, sizeof(path)); - BLI_path_abs(path, bmain->name); + BLI_path_abs(path, BKE_main_blendfile_path(bmain)); RNA_string_set(op->ptr, identifier, path); } } @@ -199,7 +199,7 @@ static void seq_load_operator_info(SeqLoadInfo *seq_load, bContext *C, wmOperato } if ((is_file != -1) && relative) - BLI_path_rel(seq_load->path, bmain->name); + BLI_path_rel(seq_load->path, BKE_main_blendfile_path(bmain)); if ((prop = RNA_struct_find_property(op->ptr, "frame_end"))) { diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c index cc0f352a51e..b24817f2af8 100644 --- a/source/blender/editors/space_sequencer/sequencer_edit.c +++ b/source/blender/editors/space_sequencer/sequencer_edit.c @@ -3753,7 +3753,7 @@ static int sequencer_change_path_exec(bContext *C, wmOperator *op) /* TODO, shouldn't this already be relative from the filesel? * (as the 'filepath' is) for now just make relative here, * but look into changing after 2.60 - campbell */ - BLI_path_rel(directory, bmain->name); + BLI_path_rel(directory, BKE_main_blendfile_path(bmain)); } BLI_strncpy(seq->strip->dir, directory, sizeof(seq->strip->dir)); @@ -3869,10 +3869,10 @@ static int sequencer_export_subtitles_invoke(bContext *C, wmOperator *op, const if (!RNA_struct_property_is_set(op->ptr, "filepath")) { char filepath[FILE_MAX]; - if (bmain->name[0] == '\0') + if (BKE_main_blendfile_path(bmain)[0] == '\0') BLI_strncpy(filepath, "untitled", sizeof(filepath)); else - BLI_strncpy(filepath, bmain->name, sizeof(filepath)); + BLI_strncpy(filepath, BKE_main_blendfile_path(bmain), sizeof(filepath)); BLI_replace_extension(filepath, sizeof(filepath), ".srt"); RNA_string_set(op->ptr, "filepath", filepath); diff --git a/source/blender/editors/space_text/text_ops.c b/source/blender/editors/space_text/text_ops.c index f7c3471f302..b3815d73c5c 100644 --- a/source/blender/editors/space_text/text_ops.c +++ b/source/blender/editors/space_text/text_ops.c @@ -234,7 +234,7 @@ static int text_open_exec(bContext *C, wmOperator *op) RNA_string_get(op->ptr, "filepath", str); - text = BKE_text_load_ex(bmain, str, bmain->name, internal); + text = BKE_text_load_ex(bmain, str, BKE_main_blendfile_path(bmain), internal); if (!text) { if (op->customdata) MEM_freeN(op->customdata); @@ -274,7 +274,7 @@ static int text_open_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(e { Main *bmain = CTX_data_main(C); Text *text = CTX_data_edit_text(C); - const char *path = (text && text->name) ? text->name : bmain->name; + const char *path = (text && text->name) ? text->name : BKE_main_blendfile_path(bmain); if (RNA_struct_property_is_set(op->ptr, "filepath")) return text_open_exec(C, op); @@ -465,7 +465,7 @@ static void txt_write_file(Main *bmain, Text *text, ReportList *reports) char filepath[FILE_MAX]; BLI_strncpy(filepath, text->name, FILE_MAX); - BLI_path_abs(filepath, bmain->name); + BLI_path_abs(filepath, BKE_main_blendfile_path(bmain)); fp = BLI_fopen(filepath, "w"); if (fp == NULL) { @@ -562,7 +562,7 @@ static int text_save_as_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSE else if (text->flags & TXT_ISMEM) str = text->id.name + 2; else - str = bmain->name; + str = BKE_main_blendfile_path(bmain); RNA_string_set(op->ptr, "filepath", str); WM_event_add_fileselect(C, op); diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c index 7de7aa77ba3..1224c284d5f 100644 --- a/source/blender/editors/space_view3d/drawobject.c +++ b/source/blender/editors/space_view3d/drawobject.c @@ -67,6 +67,7 @@ #include "BKE_lattice.h" #include "BKE_main.h" #include "BKE_mesh.h" +#include "BKE_mesh_runtime.h" #include "BKE_material.h" #include "BKE_mball.h" #include "BKE_modifier.h" diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c index d4fa98cfc88..7b395153417 100644 --- a/source/blender/editors/space_view3d/space_view3d.c +++ b/source/blender/editors/space_view3d/space_view3d.c @@ -326,9 +326,13 @@ static SpaceLink *view3d_new(const ScrArea *UNUSED(sa), const Scene *scene) v3d->shading.light = V3D_LIGHTING_STUDIO; v3d->shading.shadow_intensity = 0.5f; v3d->shading.xray_alpha = 0.5f; + v3d->shading.cavity_valley_factor = 1.0f; + v3d->shading.cavity_ridge_factor = 1.0f; copy_v3_fl(v3d->shading.single_color, 0.8f); v3d->overlay.flag = V3D_OVERLAY_LOOK_DEV; + v3d->overlay.wireframe_threshold = 0.5f; + v3d->overlay.bone_selection_alpha = 0.5f; v3d->gridflag = V3D_SHOW_X | V3D_SHOW_Y | V3D_SHOW_FLOOR; diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c index 5cd36cce31c..e199e84029e 100644 --- a/source/blender/editors/space_view3d/view3d_draw.c +++ b/source/blender/editors/space_view3d/view3d_draw.c @@ -1203,11 +1203,15 @@ void view3d_draw_region_info(const bContext *C, ARegion *ar, const int offset) BLF_batch_draw_begin(); - if (U.uiflag & USER_SHOW_ROTVIEWICON) { + if (((U.uiflag & USER_SHOW_ROTVIEWICON) != 0) && + (v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) + { draw_view_axis(rv3d, &rect); } - if ((v3d->overlay.flag & V3D_OVERLAY_HIDE_TEXT) == 0) { + if ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0 && + (v3d->overlay.flag & V3D_OVERLAY_HIDE_TEXT) == 0) + { if ((U.uiflag & USER_SHOW_FPS) && ED_screen_animation_no_scrub(wm)) { ED_scene_draw_fps(scene, &rect); } diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c index e2ff809db36..cdf2106d8bf 100644 --- a/source/blender/editors/space_view3d/view3d_edit.c +++ b/source/blender/editors/space_view3d/view3d_edit.c @@ -131,6 +131,7 @@ static void view3d_operator_properties_common(wmOperatorType *ot, const enum eV3 typedef struct ViewOpsData { /** Context pointers (assigned by #viewops_data_alloc). */ + Main *bmain; Scene *scene; ScrArea *sa; ARegion *ar; @@ -221,6 +222,7 @@ static void viewops_data_alloc(bContext *C, wmOperator *op) /* store data */ op->customdata = vod; + vod->bmain = CTX_data_main(C); vod->depsgraph = CTX_data_depsgraph(C); vod->scene = CTX_data_scene(C); vod->sa = CTX_wm_area(C); @@ -4592,6 +4594,7 @@ void ED_view3d_cursor3d_position(bContext *C, float fp[3], const int mval[2]) void ED_view3d_cursor3d_update(bContext *C, const int mval[2]) { + Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); View3D *v3d = CTX_wm_view3d(C); ARegion *ar = CTX_wm_region(C); @@ -4609,7 +4612,7 @@ void ED_view3d_cursor3d_update(bContext *C, const int mval[2]) float ray_no[3]; struct SnapObjectContext *snap_context = ED_transform_snap_object_context_create_view3d( - scene, CTX_data_depsgraph(C), 0, ar, v3d); + bmain, scene, CTX_data_depsgraph(C), 0, ar, v3d); float obmat[4][4]; Object *ob_dummy = NULL; diff --git a/source/blender/editors/space_view3d/view3d_header.c b/source/blender/editors/space_view3d/view3d_header.c index 5f07bb0fc3d..4f81fa7585c 100644 --- a/source/blender/editors/space_view3d/view3d_header.c +++ b/source/blender/editors/space_view3d/view3d_header.c @@ -259,6 +259,33 @@ void VIEW3D_OT_toggle_xray_draw_option(wmOperatorType *ot) /** \} */ +/* -------------------------------------------------------------------- */ +/** \name Toggle Bone selection Overlay Operator + * \{ */ + +static int toggle_matcap_flip(bContext *C, wmOperator *UNUSED(op)) +{ + View3D *v3d = CTX_wm_view3d(C); + v3d->shading.flag ^= V3D_SHADING_MATCAP_FLIP_X; + ED_view3d_shade_update(CTX_data_main(C), v3d, CTX_wm_area(C)); + WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d); + return OPERATOR_FINISHED; +} + +void VIEW3D_OT_toggle_matcap_flip(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Flip MatCap"; + ot->description = "Flip MatCap"; + ot->idname = "VIEW3D_OT_toggle_matcap_flip"; + + /* api callbacks */ + ot->exec = toggle_matcap_flip; + // ot->poll = toggle_show_xray_poll; +} + +/** \} */ + static void do_view3d_header_buttons(bContext *C, void *UNUSED(arg), int event) { diff --git a/source/blender/editors/space_view3d/view3d_intern.h b/source/blender/editors/space_view3d/view3d_intern.h index 6c9749e5eeb..017b31a0bf2 100644 --- a/source/blender/editors/space_view3d/view3d_intern.h +++ b/source/blender/editors/space_view3d/view3d_intern.h @@ -66,6 +66,7 @@ enum { /* view3d_header.c */ void VIEW3D_OT_layers(struct wmOperatorType *ot); void VIEW3D_OT_toggle_xray_draw_option(struct wmOperatorType *ot); +void VIEW3D_OT_toggle_matcap_flip(struct wmOperatorType *ot); /* view3d_ops.c */ void view3d_operatortypes(void); @@ -134,7 +135,8 @@ void VIEW3D_OT_ruler(struct wmOperatorType *ot); /* drawobject.c */ void draw_object_backbufsel( - struct Depsgraph *depsgraph, Scene *scene, View3D *v3d, RegionView3D *rv3d, struct Object *ob, + struct Depsgraph *depsgraph, Scene *scene, + View3D *v3d, RegionView3D *rv3d, struct Object *ob, short select_mode); int view3d_effective_drawtype(const struct View3D *v3d); diff --git a/source/blender/editors/space_view3d/view3d_iterators.c b/source/blender/editors/space_view3d/view3d_iterators.c index 145f57174fd..eae0cf8e459 100644 --- a/source/blender/editors/space_view3d/view3d_iterators.c +++ b/source/blender/editors/space_view3d/view3d_iterators.c @@ -42,6 +42,7 @@ #include "BKE_displist.h" #include "BKE_editmesh.h" #include "BKE_context.h" +#include "BKE_mesh_runtime.h" #include "DEG_depsgraph.h" #include "DEG_depsgraph_query.h" diff --git a/source/blender/editors/space_view3d/view3d_manipulator_armature.c b/source/blender/editors/space_view3d/view3d_manipulator_armature.c index 5d3d88ff2a2..abbd6c888b2 100644 --- a/source/blender/editors/space_view3d/view3d_manipulator_armature.c +++ b/source/blender/editors/space_view3d/view3d_manipulator_armature.c @@ -134,7 +134,10 @@ static bool WIDGETGROUP_armature_spline_poll(const bContext *C, wmManipulatorGro const bArmature *arm = ob->data; if (arm->drawtype == ARM_B_BONE) { if (arm->act_bone && arm->act_bone->segments > 1) { - return true; + View3D *v3d = CTX_wm_view3d(C); + if ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) { + return true; + } } } } diff --git a/source/blender/editors/space_view3d/view3d_manipulator_camera.c b/source/blender/editors/space_view3d/view3d_manipulator_camera.c index b680818dc14..49fa83e82fc 100644 --- a/source/blender/editors/space_view3d/view3d_manipulator_camera.c +++ b/source/blender/editors/space_view3d/view3d_manipulator_camera.c @@ -63,6 +63,11 @@ struct CameraWidgetGroup { static bool WIDGETGROUP_camera_poll(const bContext *C, wmManipulatorGroupType *UNUSED(wgt)) { + View3D *v3d = CTX_wm_view3d(C); + if (v3d->flag2 & V3D_RENDER_OVERRIDE) { + return false; + } + Object *ob = CTX_data_active_object(C); if (ob && ob->type == OB_CAMERA) { Camera *camera = ob->data; @@ -352,9 +357,13 @@ static bool WIDGETGROUP_camera_view_poll(const bContext *C, wmManipulatorGroupTy } } + View3D *v3d = CTX_wm_view3d(C); + if (v3d->flag2 & V3D_RENDER_OVERRIDE) { + return false; + } + ARegion *ar = CTX_wm_region(C); RegionView3D *rv3d = ar->regiondata; - View3D *v3d = CTX_wm_view3d(C); if (rv3d->persp == RV3D_CAMOB) { if (scene->r.mode & R_BORDER) { /* TODO: support overrides. */ diff --git a/source/blender/editors/space_view3d/view3d_manipulator_empty.c b/source/blender/editors/space_view3d/view3d_manipulator_empty.c index 1d56c5ee7f4..75e4a9e3314 100644 --- a/source/blender/editors/space_view3d/view3d_manipulator_empty.c +++ b/source/blender/editors/space_view3d/view3d_manipulator_empty.c @@ -106,6 +106,11 @@ static void manipulator_empty_image_prop_matrix_set( static bool WIDGETGROUP_empty_image_poll(const bContext *C, wmManipulatorGroupType *UNUSED(wgt)) { + View3D *v3d = CTX_wm_view3d(C); + if (v3d->flag2 & V3D_RENDER_OVERRIDE) { + return false; + } + Object *ob = CTX_data_active_object(C); if (ob && ob->type == OB_EMPTY) { diff --git a/source/blender/editors/space_view3d/view3d_manipulator_forcefield.c b/source/blender/editors/space_view3d/view3d_manipulator_forcefield.c index e76be448be4..2a1fdee8e8a 100644 --- a/source/blender/editors/space_view3d/view3d_manipulator_forcefield.c +++ b/source/blender/editors/space_view3d/view3d_manipulator_forcefield.c @@ -54,6 +54,11 @@ static bool WIDGETGROUP_forcefield_poll(const bContext *C, wmManipulatorGroupType *UNUSED(wgt)) { + View3D *v3d = CTX_wm_view3d(C); + if (v3d->flag2 & V3D_RENDER_OVERRIDE) { + return false; + } + Object *ob = CTX_data_active_object(C); return (ob && ob->pd && ob->pd->forcefield); diff --git a/source/blender/editors/space_view3d/view3d_manipulator_lamp.c b/source/blender/editors/space_view3d/view3d_manipulator_lamp.c index 88c36fc2c0b..01c38cfd899 100644 --- a/source/blender/editors/space_view3d/view3d_manipulator_lamp.c +++ b/source/blender/editors/space_view3d/view3d_manipulator_lamp.c @@ -54,6 +54,11 @@ static bool WIDGETGROUP_lamp_spot_poll(const bContext *C, wmManipulatorGroupType *UNUSED(wgt)) { + View3D *v3d = CTX_wm_view3d(C); + if (v3d->flag2 & V3D_RENDER_OVERRIDE) { + return false; + } + Object *ob = CTX_data_active_object(C); if (ob && ob->type == OB_LAMP) { @@ -151,8 +156,12 @@ static void manipulator_area_lamp_prop_matrix_set( static bool WIDGETGROUP_lamp_area_poll(const bContext *C, wmManipulatorGroupType *UNUSED(wgt)) { - Object *ob = CTX_data_active_object(C); + View3D *v3d = CTX_wm_view3d(C); + if (v3d->flag2 & V3D_RENDER_OVERRIDE) { + return false; + } + Object *ob = CTX_data_active_object(C); if (ob && ob->type == OB_LAMP) { Lamp *la = ob->data; return (la->type == LA_AREA); @@ -226,6 +235,11 @@ void VIEW3D_WGT_lamp_area(wmManipulatorGroupType *wgt) static bool WIDGETGROUP_lamp_target_poll(const bContext *C, wmManipulatorGroupType *UNUSED(wgt)) { + View3D *v3d = CTX_wm_view3d(C); + if (v3d->flag2 & V3D_RENDER_OVERRIDE) { + return false; + } + Object *ob = CTX_data_active_object(C); if (ob != NULL) { diff --git a/source/blender/editors/space_view3d/view3d_manipulator_navigate.c b/source/blender/editors/space_view3d/view3d_manipulator_navigate.c index d86c6595bfa..c869e23d552 100644 --- a/source/blender/editors/space_view3d/view3d_manipulator_navigate.c +++ b/source/blender/editors/space_view3d/view3d_manipulator_navigate.c @@ -176,8 +176,13 @@ struct NavigateWidgetGroup { int region_size[2]; }; -static bool WIDGETGROUP_navigate_poll(const bContext *UNUSED(C), wmManipulatorGroupType *UNUSED(wgt)) +static bool WIDGETGROUP_navigate_poll(const bContext *C, wmManipulatorGroupType *UNUSED(wgt)) { + View3D *v3d = CTX_wm_view3d(C); + if (v3d->flag2 & V3D_RENDER_OVERRIDE) { + return false; + } + if (U.manipulator_flag & USER_MANIPULATOR_DRAW_NAVIGATE) { return true; } diff --git a/source/blender/editors/space_view3d/view3d_manipulator_ruler.c b/source/blender/editors/space_view3d/view3d_manipulator_ruler.c index 9cde5ffc5e3..cd918695f60 100644 --- a/source/blender/editors/space_view3d/view3d_manipulator_ruler.c +++ b/source/blender/editors/space_view3d/view3d_manipulator_ruler.c @@ -31,8 +31,10 @@ #include "BLT_translation.h" #include "BKE_context.h" -#include "BKE_object.h" #include "BKE_gpencil.h" +#include "BKE_main.h" + +#include "BKE_object.h" #include "BKE_unit.h" #include "DNA_object_types.h" @@ -263,6 +265,7 @@ static bool view3d_ruler_pick( */ static void ruler_state_set(bContext *C, RulerInfo *ruler_info, int state) { + Main *bmain = CTX_data_main(C); if (state == ruler_info->state) { return; } @@ -278,7 +281,7 @@ static void ruler_state_set(bContext *C, RulerInfo *ruler_info, int state) } else if (state == RULER_STATE_DRAG) { ruler_info->snap_context = ED_transform_snap_object_context_create_view3d( - CTX_data_scene(C), CTX_data_depsgraph(C), 0, + bmain, CTX_data_scene(C), CTX_data_depsgraph(C), 0, ruler_info->ar, CTX_wm_view3d(C)); } else { diff --git a/source/blender/editors/space_view3d/view3d_ops.c b/source/blender/editors/space_view3d/view3d_ops.c index 3b800c20ed2..b3211ed1108 100644 --- a/source/blender/editors/space_view3d/view3d_ops.c +++ b/source/blender/editors/space_view3d/view3d_ops.c @@ -223,6 +223,7 @@ void view3d_operatortypes(void) WM_operatortype_append(VIEW3D_OT_toggle_render); WM_operatortype_append(VIEW3D_OT_toggle_xray_draw_option); + WM_operatortype_append(VIEW3D_OT_toggle_matcap_flip); WM_operatortype_append(VIEW3D_OT_ruler_add); @@ -301,6 +302,8 @@ void view3d_keymap(wmKeyConfig *keyconf) kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_view_all", CKEY, KM_PRESS, KM_SHIFT, 0); RNA_boolean_set(kmi->ptr, "center", true); + WM_keymap_add_menu_pie(keymap, "VIEW3D_PIE_view", ACCENTGRAVEKEY, KM_CLICK_DRAG, 0, 0); + /* numpad view hotkeys*/ RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", PAD0, KM_PRESS, 0, 0)->ptr, "type", RV3D_VIEW_CAMERA); RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", PAD1, KM_PRESS, 0, 0)->ptr, "type", RV3D_VIEW_FRONT); diff --git a/source/blender/editors/space_view3d/view3d_ruler.c b/source/blender/editors/space_view3d/view3d_ruler.c index 54579e93413..c30b72bfb95 100644 --- a/source/blender/editors/space_view3d/view3d_ruler.c +++ b/source/blender/editors/space_view3d/view3d_ruler.c @@ -38,8 +38,9 @@ #include "BLT_translation.h" #include "BKE_context.h" -#include "BKE_unit.h" #include "BKE_gpencil.h" +#include "BKE_main.h" +#include "BKE_unit.h" #include "BIF_gl.h" @@ -267,6 +268,7 @@ static bool view3d_ruler_pick(RulerInfo *ruler_info, const float mval[2], */ static void ruler_state_set(bContext *C, RulerInfo *ruler_info, int state) { + Main *bmain = CTX_data_main(C); if (state == ruler_info->state) { return; } @@ -282,7 +284,7 @@ static void ruler_state_set(bContext *C, RulerInfo *ruler_info, int state) } else if (state == RULER_STATE_DRAG) { ruler_info->snap_context = ED_transform_snap_object_context_create_view3d( - CTX_data_scene(C), CTX_data_depsgraph(C), 0, + bmain, CTX_data_scene(C), CTX_data_depsgraph(C), 0, ruler_info->ar, CTX_wm_view3d(C)); } else { diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c index bb12c8236cf..f4e39c7a563 100644 --- a/source/blender/editors/space_view3d/view3d_select.c +++ b/source/blender/editors/space_view3d/view3d_select.c @@ -116,6 +116,7 @@ void ED_view3d_viewcontext_init(bContext *C, ViewContext *vc) { memset(vc, 0, sizeof(ViewContext)); vc->ar = CTX_wm_region(C); + vc->bmain = CTX_data_main(C); vc->depsgraph = CTX_data_depsgraph(C); vc->scene = CTX_data_scene(C); vc->view_layer = CTX_data_view_layer(C); diff --git a/source/blender/editors/space_view3d/view3d_utils.c b/source/blender/editors/space_view3d/view3d_utils.c index 8b0b461d443..ca5375b6b54 100644 --- a/source/blender/editors/space_view3d/view3d_utils.c +++ b/source/blender/editors/space_view3d/view3d_utils.c @@ -46,6 +46,7 @@ #include "BKE_camera.h" #include "BKE_context.h" +#include "BKE_main.h" #include "BKE_object.h" #include "BKE_screen.h" @@ -899,7 +900,7 @@ static float view_autodist_depth_margin(ARegion *ar, const int mval[2], int marg * \param fallback_depth_pt: Use this points depth when no depth can be found. */ bool ED_view3d_autodist( - struct Depsgraph *depsgraph, ARegion *ar, View3D *v3d, + Depsgraph *depsgraph, ARegion *ar, View3D *v3d, const int mval[2], float mouse_worldloc[3], const bool alphaoverride, const float fallback_depth_pt[3]) { @@ -936,7 +937,7 @@ bool ED_view3d_autodist( } } -void ED_view3d_autodist_init(struct Depsgraph *depsgraph, +void ED_view3d_autodist_init(Depsgraph *depsgraph, ARegion *ar, View3D *v3d, int mode) { /* Get Z Depths, needed for perspective, nice for ortho */ diff --git a/source/blender/editors/space_view3d/view3d_walk.c b/source/blender/editors/space_view3d/view3d_walk.c index a7c97ba4d4a..352e85703bc 100644 --- a/source/blender/editors/space_view3d/view3d_walk.c +++ b/source/blender/editors/space_view3d/view3d_walk.c @@ -37,6 +37,7 @@ #include "BLI_utildefines.h" #include "BKE_context.h" +#include "BKE_main.h" #include "BKE_report.h" #include "BLT_translation.h" @@ -507,6 +508,7 @@ static float userdef_speed = -1.f; static bool initWalkInfo(bContext *C, WalkInfo *walk, wmOperator *op) { + Main *bmain = CTX_data_main(C); wmWindow *win = CTX_wm_window(C); walk->rv3d = CTX_wm_region_view3d(C); @@ -602,7 +604,7 @@ static bool initWalkInfo(bContext *C, WalkInfo *walk, wmOperator *op) walk->rv3d->rflag |= RV3D_NAVIGATING; walk->snap_context = ED_transform_snap_object_context_create_view3d( - walk->scene, CTX_data_depsgraph(C), 0, + bmain, walk->scene, CTX_data_depsgraph(C), 0, walk->ar, walk->v3d); walk->v3d_camera_control = ED_view3d_cameracontrol_acquire( diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index a4d08b15a6d..b4f7e9256a3 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -1520,7 +1520,7 @@ int transformEvent(TransInfo *t, const wmEvent *event) /* confirm transform if launch key is released after mouse move */ if (t->flag & T_RELEASE_CONFIRM) { /* XXX Keyrepeat bug in Xorg messes this up, will test when fixed */ - if (event->type == t->launch_event && (t->launch_event == LEFTMOUSE || t->launch_event == RIGHTMOUSE)) { + if ((event->type == t->launch_event) && ISMOUSE(t->launch_event)) { t->state = TRANS_CONFIRM; } } @@ -2140,14 +2140,8 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve t->mode = mode; - t->launch_event = event ? event->type : -1; - - if (t->launch_event == EVT_TWEAK_R) { - t->launch_event = RIGHTMOUSE; - } - else if (t->launch_event == EVT_TWEAK_L) { - t->launch_event = LEFTMOUSE; - } + /* Needed to translate tweak events to mouse buttons. */ + t->launch_event = event ? WM_userdef_event_type_from_keymap_type(event->type) : -1; // XXX Remove this when wm_operator_call_internal doesn't use window->eventstate (which can have type = 0) // For manipulator only, so assume LEFTMOUSE diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h index b9f42a0d9fc..419f400df53 100644 --- a/source/blender/editors/transform/transform.h +++ b/source/blender/editors/transform/transform.h @@ -722,7 +722,7 @@ int special_transform_moving(TransInfo *t); void transform_autoik_update(TransInfo *t, short mode); bool transdata_check_local_islands(TransInfo *t, short around); -int count_set_pose_transflags(int *out_mode, short around, struct Object *ob); +int count_set_pose_transflags(struct Object *ob, const int mode, const short around, bool has_translate_rotate[2]); /* auto-keying stuff used by special_aftertrans_update */ void autokeyframe_ob_cb_func( diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c index 8bfe14dc6ea..45941ba6f39 100644 --- a/source/blender/editors/transform/transform_conversions.c +++ b/source/blender/editors/transform/transform_conversions.c @@ -574,17 +574,14 @@ static short apply_targetless_ik(Object *ob) return apply; } -static void add_pose_transdata( - TransInfo *t, Object *ob, bPoseChannel *pchan, - Object *ob_eval, bPoseChannel *pchan_eval, - TransDataContainer *tc, TransData *td) +static void add_pose_transdata(TransInfo *t, bPoseChannel *pchan, Object *ob, TransDataContainer *tc, TransData *td) { - Bone *bone = pchan_eval->bone; + Bone *bone = pchan->bone; float pmat[3][3], omat[3][3]; float cmat[3][3], tmat[3][3]; float vec[3]; - copy_v3_v3(vec, pchan_eval->pose_mat[3]); + copy_v3_v3(vec, pchan->pose_mat[3]); copy_v3_v3(td->center, vec); td->ob = ob; @@ -601,10 +598,10 @@ static void add_pose_transdata( td->protectflag = pchan->protectflag; td->loc = pchan->loc; - copy_v3_v3(td->iloc, pchan_eval->loc); + copy_v3_v3(td->iloc, pchan->loc); td->ext->size = pchan->size; - copy_v3_v3(td->ext->isize, pchan_eval->size); + copy_v3_v3(td->ext->isize, pchan->size); if (pchan->rotmode > 0) { td->ext->rot = pchan->eul; @@ -612,7 +609,7 @@ static void add_pose_transdata( td->ext->rotAngle = NULL; td->ext->quat = NULL; - copy_v3_v3(td->ext->irot, pchan_eval->eul); + copy_v3_v3(td->ext->irot, pchan->eul); } else if (pchan->rotmode == ROT_MODE_AXISANGLE) { td->ext->rot = NULL; @@ -620,8 +617,8 @@ static void add_pose_transdata( td->ext->rotAngle = &pchan->rotAngle; td->ext->quat = NULL; - td->ext->irotAngle = pchan_eval->rotAngle; - copy_v3_v3(td->ext->irotAxis, pchan_eval->rotAxis); + td->ext->irotAngle = pchan->rotAngle; + copy_v3_v3(td->ext->irotAxis, pchan->rotAxis); } else { td->ext->rot = NULL; @@ -629,20 +626,20 @@ static void add_pose_transdata( td->ext->rotAngle = NULL; td->ext->quat = pchan->quat; - copy_qt_qt(td->ext->iquat, pchan_eval->quat); + copy_qt_qt(td->ext->iquat, pchan->quat); } td->ext->rotOrder = pchan->rotmode; /* proper way to get parent transform + own transform + constraints transform */ - copy_m3_m4(omat, ob_eval->obmat); + copy_m3_m4(omat, ob->obmat); /* New code, using "generic" BKE_pchan_to_pose_mat(). */ { float rotscale_mat[4][4], loc_mat[4][4]; float rpmat[3][3]; - BKE_pchan_to_pose_mat(pchan_eval, rotscale_mat, loc_mat); + BKE_pchan_to_pose_mat(pchan, rotscale_mat, loc_mat); if (t->mode == TFM_TRANSLATION) copy_m3_m4(pmat, loc_mat); else @@ -655,7 +652,7 @@ static void add_pose_transdata( copy_m3_m4(rpmat, rotscale_mat); if (constraints_list_needinv(t, &pchan->constraints)) { - copy_m3_m4(tmat, pchan_eval->constinv); + copy_m3_m4(tmat, pchan->constinv); invert_m3_m3(cmat, tmat); mul_m3_series(td->mtx, cmat, omat, pmat); mul_m3_series(td->ext->r_mtx, cmat, omat, rpmat); @@ -675,7 +672,7 @@ static void add_pose_transdata( if (pchan->parent) { /* same as td->smtx but without pchan->bone->bone_mat */ td->flag |= TD_PBONE_LOCAL_MTX_C; - mul_m3_m3m3(td->ext->l_smtx, pchan_eval->bone->bone_mat, td->smtx); + mul_m3_m3m3(td->ext->l_smtx, pchan->bone->bone_mat, td->smtx); } else { td->flag |= TD_PBONE_LOCAL_MTX_P; @@ -683,7 +680,7 @@ static void add_pose_transdata( } /* for axismat we use bone's own transform */ - copy_m3_m4(pmat, pchan_eval->pose_mat); + copy_m3_m4(pmat, pchan->pose_mat); mul_m3_m3m3(td->axismtx, omat, pmat); normalize_m3(td->axismtx); @@ -708,10 +705,10 @@ static void add_pose_transdata( bKinematicConstraint *data = has_targetless_ik(pchan); if (data) { if (data->flag & CONSTRAINT_IK_TIP) { - copy_v3_v3(data->grabtarget, pchan_eval->pose_tail); + copy_v3_v3(data->grabtarget, pchan->pose_tail); } else { - copy_v3_v3(data->grabtarget, pchan_eval->pose_head); + copy_v3_v3(data->grabtarget, pchan->pose_head); } td->loc = data->grabtarget; copy_v3_v3(td->iloc, td->loc); @@ -751,12 +748,11 @@ static void bone_children_clear_transflag(int mode, short around, ListBase *lb) /* sets transform flags in the bones * returns total number of bones with BONE_TRANSFORM */ -int count_set_pose_transflags(int *out_mode, short around, Object *ob) +int count_set_pose_transflags(Object *ob, const int mode, short around, bool has_translate_rotate[2]) { bArmature *arm = ob->data; bPoseChannel *pchan; Bone *bone; - int mode = *out_mode; int total = 0; for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { @@ -784,43 +780,30 @@ int count_set_pose_transflags(int *out_mode, short around, Object *ob) } } /* now count, and check if we have autoIK or have to switch from translate to rotate */ - bool has_translation = false, has_rotation = false; - for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { bone = pchan->bone; if (bone->flag & BONE_TRANSFORM) { total++; - if (mode == TFM_TRANSLATION) { + if (has_translate_rotate != NULL) { if (has_targetless_ik(pchan) == NULL) { if (pchan->parent && (pchan->bone->flag & BONE_CONNECTED)) { - if (pchan->bone->flag & BONE_HINGE_CHILD_TRANSFORM) - has_translation = true; + if (pchan->bone->flag & BONE_HINGE_CHILD_TRANSFORM) { + has_translate_rotate[0] = true; + } } else { - if ((pchan->protectflag & OB_LOCK_LOC) != OB_LOCK_LOC) - has_translation = true; + if ((pchan->protectflag & OB_LOCK_LOC) != OB_LOCK_LOC) { + has_translate_rotate[0] = true; + } + } + if ((pchan->protectflag & OB_LOCK_ROT) != OB_LOCK_ROT) { + has_translate_rotate[1] = true; } - if ((pchan->protectflag & OB_LOCK_ROT) != OB_LOCK_ROT) - has_rotation = true; } - else - has_translation = true; - } - } - } - - /* only modify transform mode if there are bones here that do something... - * otherwise we get problems when multiple objects are selected - */ - if (total) { - /* if there are no translatable bones, do rotation */ - if (mode == TFM_TRANSLATION && !has_translation) { - if (has_rotation) { - *out_mode = TFM_ROTATION; - } - else { - *out_mode = TFM_RESIZE; + else { + has_translate_rotate[1] = true; + } } } } @@ -868,6 +851,8 @@ static bool pchan_autoik_adjust(bPoseChannel *pchan, short chainlen) /* change the chain-length of auto-ik */ void transform_autoik_update(TransInfo *t, short mode) { + Main *bmain = CTX_data_main(t->context); + short *chainlen = &t->settings->autoik_chainlen; bPoseChannel *pchan; @@ -904,12 +889,12 @@ void transform_autoik_update(TransInfo *t, short mode) if (changed) { /* TODO(sergey): Consider doing partial update only. */ - DEG_relations_tag_update(G.main); + DEG_relations_tag_update(bmain); } } /* frees temporal IKs */ -static void pose_grab_with_ik_clear(Object *ob) +static void pose_grab_with_ik_clear(Main *bmain, Object *ob) { bKinematicConstraint *data; bPoseChannel *pchan; @@ -947,7 +932,7 @@ static void pose_grab_with_ik_clear(Object *ob) if (relations_changed) { /* TODO(sergey): Consider doing partial update only. */ - DEG_relations_tag_update(G.main); + DEG_relations_tag_update(bmain); } } @@ -1055,7 +1040,7 @@ static short pose_grab_with_ik_children(bPose *pose, Bone *bone) } /* main call which adds temporal IK chains */ -static short pose_grab_with_ik(Object *ob) +static short pose_grab_with_ik(Main *bmain, Object *ob) { bArmature *arm; bPoseChannel *pchan, *parent; @@ -1101,8 +1086,8 @@ static short pose_grab_with_ik(Object *ob) /* iTaSC needs clear for new IK constraints */ if (tot_ik) { BIK_clear_data(ob->pose); - /* TODO(sergey): Consuder doing partial update only. */ - DEG_relations_tag_update(G.main); + /* TODO(sergey): Consider doing partial update only. */ + DEG_relations_tag_update(bmain); } return (tot_ik) ? 1 : 0; @@ -1125,18 +1110,18 @@ static void createTransPose(TransInfo *t, Object **objects, uint objects_len) tc->poseobj = objects[th_index]; } } + Main *bmain = CTX_data_main(t->context); t->data_len_all = 0; + bool has_translate_rotate_buf[2] = {false, false}; + bool *has_translate_rotate = (t->mode == TFM_TRANSLATION) ? has_translate_rotate_buf : NULL; + FOREACH_TRANS_DATA_CONTAINER (t, tc) { Object *ob = tc->poseobj; bArmature *arm; - TransData *td; - TransDataExtension *tdx; short ik_on = 0; - int i; - /* check validity of state */ arm = BKE_armature_from_object(tc->poseobj); @@ -1153,16 +1138,34 @@ static void createTransPose(TransInfo *t, Object **objects, uint objects_len) /* do we need to add temporal IK chains? */ if ((arm->flag & ARM_AUTO_IK) && t->mode == TFM_TRANSLATION) { - ik_on = pose_grab_with_ik(ob); + ik_on = pose_grab_with_ik(bmain, ob); if (ik_on) t->flag |= T_AUTOIK; } /* set flags and count total (warning, can change transform to rotate) */ - tc->data_len = count_set_pose_transflags(&t->mode, t->around, ob); + tc->data_len = count_set_pose_transflags(ob, t->mode, t->around, has_translate_rotate); + /* len may be zero, skip next iteration. */ + } + + /* if there are no translatable bones, do rotation */ + if ((t->mode == TFM_TRANSLATION) && !has_translate_rotate[0]) { + if (has_translate_rotate[1]) { + t->mode = TFM_ROTATION; + } + else { + t->mode = TFM_RESIZE; + } + } + FOREACH_TRANS_DATA_CONTAINER (t, tc) { if (tc->data_len == 0) { continue; } + Object *ob = tc->poseobj; + TransData *td; + TransDataExtension *tdx; + short ik_on = 0; + int i; tc->poseobj = ob; /* we also allow non-active objects to be transformed, in weightpaint */ @@ -1178,7 +1181,7 @@ static void createTransPose(TransInfo *t, Object **objects, uint objects_len) td = tc->data; for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { if (pchan->bone->flag & BONE_TRANSFORM) { - add_pose_transdata(t, ob, pchan, ob, pchan, tc, td); + add_pose_transdata(t, pchan, ob, tc, td); td++; } } @@ -5619,18 +5622,17 @@ static bool constraints_list_needinv(TransInfo *t, ListBase *list) /* transcribe given object into TransData for Transforming */ static void ObjectToTransData(TransInfo *t, TransData *td, Object *ob) { - Depsgraph *depsgraph = t->depsgraph; Scene *scene = t->scene; bool constinv; bool skip_invert = false; if (t->mode != TFM_DUMMY && ob->rigidbody_object) { float rot[3][3], scale[3]; - float ctime = DEG_get_ctime(depsgraph); + float ctime = BKE_scene_frame_get(scene); /* only use rigid body transform if simulation is running, avoids problems with initial setup of rigid bodies */ - // XXX: This needs fixing for COW. May need rigidbody_world from scene if (BKE_rigidbody_check_sim_running(scene->rigidbody_world, ctime)) { + /* save original object transform */ copy_v3_v3(td->ext->oloc, ob->loc); @@ -5665,26 +5667,21 @@ static void ObjectToTransData(TransInfo *t, TransData *td, Object *ob) constinv = constraints_list_needinv(t, &ob->constraints); /* disable constraints inversion for dummy pass */ - // XXX: Should this use ob or ob_eval?! It's not clear! if (t->mode == TFM_DUMMY) skip_invert = true; - Scene *scene_eval = DEG_get_evaluated_scene(t->depsgraph); if (skip_invert == false && constinv == false) { - Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob); - ob_eval->transflag |= OB_NO_CONSTRAINTS; /* BKE_object_where_is_calc_time checks this */ - BKE_object_where_is_calc(t->depsgraph, scene_eval, ob_eval); - ob_eval->transflag &= ~OB_NO_CONSTRAINTS; - } - else { - Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob); - BKE_object_where_is_calc(t->depsgraph, scene_eval, ob_eval); + ob->transflag |= OB_NO_CONSTRAINTS; /* BKE_object_where_is_calc_time checks this */ + BKE_object_where_is_calc(t->depsgraph, t->scene, ob); + ob->transflag &= ~OB_NO_CONSTRAINTS; } + else + BKE_object_where_is_calc(t->depsgraph, t->scene, ob); td->ob = ob; td->loc = ob->loc; - copy_v3_v3(td->iloc, ob->loc); + copy_v3_v3(td->iloc, td->loc); if (ob->rotmode > 0) { td->ext->rot = ob->rot; @@ -5782,8 +5779,7 @@ static void trans_object_base_deps_flag_finish(ViewLayer *view_layer) /* it deselects Bases, so we have to call the clear function always after */ static void set_trans_object_base_flags(TransInfo *t) { - /* TODO(sergey): Get rid of global, use explicit main. */ - Main *bmain = G.main; + Main *bmain = CTX_data_main(t->context); ViewLayer *view_layer = t->view_layer; Scene *scene = t->scene; Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer, true); @@ -5929,6 +5925,7 @@ static void clear_trans_object_base_flags(TransInfo *t) // NOTE: context may not always be available, so must check before using it as it's a luxury for a few cases void autokeyframe_ob_cb_func(bContext *C, Scene *scene, ViewLayer *view_layer, Object *ob, int tmode) { + Main *bmain = CTX_data_main(C); ID *id = &ob->id; FCurve *fcu; @@ -5961,7 +5958,7 @@ void autokeyframe_ob_cb_func(bContext *C, Scene *scene, ViewLayer *view_layer, O if (adt && adt->action) { for (fcu = adt->action->curves.first; fcu; fcu = fcu->next) { fcu->flag &= ~FCURVE_SELECTED; - insert_keyframe(depsgraph, reports, id, adt->action, + insert_keyframe(bmain, depsgraph, reports, id, adt->action, (fcu->grp ? fcu->grp->name : NULL), fcu->rna_path, fcu->array_index, cfra, ts->keyframe_type, flag); @@ -6050,6 +6047,7 @@ void autokeyframe_ob_cb_func(bContext *C, Scene *scene, ViewLayer *view_layer, O // NOTE: context may not always be available, so must check before using it as it's a luxury for a few cases void autokeyframe_pose_cb_func(bContext *C, Scene *scene, Object *ob, int tmode, short targetless_ik) { + Main *bmain = CTX_data_main(C); ID *id = &ob->id; AnimData *adt = ob->adt; bAction *act = (adt) ? adt->action : NULL; @@ -6103,7 +6101,7 @@ void autokeyframe_pose_cb_func(bContext *C, Scene *scene, Object *ob, int tmode, * NOTE: this will do constraints too, but those are ok to do here too? */ if (pchanName && STREQ(pchanName, pchan->name)) { - insert_keyframe(depsgraph, reports, id, act, + insert_keyframe(bmain, depsgraph, reports, id, act, ((fcu->grp) ? (fcu->grp->name) : (NULL)), fcu->rna_path, fcu->array_index, cfra, ts->keyframe_type, flag); @@ -6333,6 +6331,9 @@ static void special_aftertrans_update__mesh(bContext *UNUSED(C), TransInfo *t) * */ void special_aftertrans_update(bContext *C, TransInfo *t) { + Main *bmain = CTX_data_main(t->context); + BLI_assert(bmain == CTX_data_main(C)); + Object *ob; // short redrawipo=0, resetslowpar=1; const bool canceled = (t->state == TRANS_CANCEL); @@ -6521,7 +6522,7 @@ void special_aftertrans_update(bContext *C, TransInfo *t) // XXX: BAD! this get gpencil datablocks directly from main db... // but that's how this currently works :/ - for (gpd = G.main->gpencil.first; gpd; gpd = gpd->id.next) { + for (gpd = bmain->gpencil.first; gpd; gpd = gpd->id.next) { if (ID_REAL_USERS(gpd)) posttrans_gpd_clean(gpd); } @@ -6541,7 +6542,7 @@ void special_aftertrans_update(bContext *C, TransInfo *t) // XXX: BAD! this get gpencil datablocks directly from main db... // but that's how this currently works :/ - for (mask = G.main->mask.first; mask; mask = mask->id.next) { + for (mask = bmain->mask.first; mask; mask = mask->id.next) { if (ID_REAL_USERS(mask)) posttrans_mask_clean(mask); } @@ -6690,8 +6691,9 @@ void special_aftertrans_update(bContext *C, TransInfo *t) } /* set BONE_TRANSFORM flags for autokey, manipulator draw might have changed them */ - if (!canceled && (t->mode != TFM_DUMMY)) - count_set_pose_transflags(&t->mode, t->around, ob); + if (!canceled && (t->mode != TFM_DUMMY)) { + count_set_pose_transflags(ob, t->mode, t->around, NULL); + } /* if target-less IK grabbing, we calculate the pchan transforms and clear flag */ if (!canceled && t->mode == TFM_TRANSLATION) @@ -6705,7 +6707,7 @@ void special_aftertrans_update(bContext *C, TransInfo *t) } if (t->mode == TFM_TRANSLATION) - pose_grab_with_ik_clear(ob); + pose_grab_with_ik_clear(bmain, ob); /* automatic inserting of keys and unkeyed tagging - only if transform wasn't canceled (or TFM_DUMMY) */ if (!canceled && (t->mode != TFM_DUMMY)) { @@ -8451,6 +8453,7 @@ void createTransData(bContext *C, TransInfo *t) } else if (t->spacetype == SPACE_ACTION) { t->flag |= T_POINTS | T_2D_EDIT; + t->obedit_type = -1; createTransActionData(C, t); countAndCleanTransDataContainer(t); @@ -8463,17 +8466,23 @@ void createTransData(bContext *C, TransInfo *t) } else if (t->spacetype == SPACE_NLA) { t->flag |= T_POINTS | T_2D_EDIT; + t->obedit_type = -1; + createTransNlaData(C, t); countAndCleanTransDataContainer(t); } else if (t->spacetype == SPACE_SEQ) { t->flag |= T_POINTS | T_2D_EDIT; + t->obedit_type = -1; + t->num.flag |= NUM_NO_FRACTION; /* sequencer has no use for floating point transformations */ createTransSeqData(C, t); countAndCleanTransDataContainer(t); } else if (t->spacetype == SPACE_IPO) { t->flag |= T_POINTS | T_2D_EDIT; + t->obedit_type = -1; + createTransGraphEditData(C, t); countAndCleanTransDataContainer(t); @@ -8485,6 +8494,7 @@ void createTransData(bContext *C, TransInfo *t) } else if (t->spacetype == SPACE_NODE) { t->flag |= T_POINTS | T_2D_EDIT; + t->obedit_type = -1; createTransNodeData(C, t); countAndCleanTransDataContainer(t); @@ -8497,6 +8507,8 @@ void createTransData(bContext *C, TransInfo *t) } else if (t->spacetype == SPACE_CLIP) { t->flag |= T_POINTS | T_2D_EDIT; + t->obedit_type = -1; + if (t->options & CTX_MOVIECLIP) { createTransTrackingData(C, t); countAndCleanTransDataContainer(t); @@ -8598,7 +8610,10 @@ void createTransData(bContext *C, TransInfo *t) countAndCleanTransDataContainer(t); } } - + } + /* Mark as initialized if above checks fail. */ + if (t->data_len_all == -1) { + t->data_len_all = 0; } } else if (ob && (ob->mode & OB_MODE_PARTICLE_EDIT) && PE_start_edit(PE_get_current(scene, ob))) { diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c index 576bfddd28c..d3fcd5e5911 100644 --- a/source/blender/editors/transform/transform_generics.c +++ b/source/blender/editors/transform/transform_generics.c @@ -359,6 +359,7 @@ static void recalcData_actedit(TransInfo *t) /* initialize relevant anim-context 'context' data from TransInfo data */ /* NOTE: sync this with the code in ANIM_animdata_get_context() */ + ac.bmain = CTX_data_main(t->context); ac.scene = t->scene; ac.view_layer = t->view_layer; ac.obact = OBACT(view_layer); @@ -386,7 +387,7 @@ static void recalcData_actedit(TransInfo *t) if ((saction->flag & SACTION_NOREALTIMEUPDATES) == 0) { for (ale = anim_data.first; ale; ale = ale->next) { /* set refresh tags for objects using this animation */ - ANIM_list_elem_update(t->scene, ale); + ANIM_list_elem_update(CTX_data_main(t->context), t->scene, ale); } } @@ -409,6 +410,7 @@ static void recalcData_graphedit(TransInfo *t) /* initialize relevant anim-context 'context' data from TransInfo data */ /* NOTE: sync this with the code in ANIM_animdata_get_context() */ + ac.bmain = CTX_data_main(t->context); ac.scene = t->scene; ac.view_layer = t->view_layer; ac.obact = OBACT(view_layer); @@ -445,7 +447,7 @@ static void recalcData_graphedit(TransInfo *t) * BUT only if realtime updates are enabled */ if ((sipo->flag & SIPO_NOREALTIMEUPDATES) == 0) - ANIM_list_elem_update(t->scene, ale); + ANIM_list_elem_update(CTX_data_main(t->context), t->scene, ale); } /* do resort and other updates? */ diff --git a/source/blender/editors/transform/transform_manipulator_3d.c b/source/blender/editors/transform/transform_manipulator_3d.c index b94ccf42325..b6782470f96 100644 --- a/source/blender/editors/transform/transform_manipulator_3d.c +++ b/source/blender/editors/transform/transform_manipulator_3d.c @@ -586,7 +586,6 @@ int ED_transform_calc_manipulator_stats( const struct TransformCalcParams *params, struct TransformBounds *tbounds) { - const Depsgraph *depsgraph = CTX_data_depsgraph(C); ScrArea *sa = CTX_wm_area(C); ARegion *ar = CTX_wm_region(C); Scene *scene = CTX_data_scene(C); @@ -596,8 +595,6 @@ int ED_transform_calc_manipulator_stats( RegionView3D *rv3d = ar->regiondata; Base *base; Object *ob = OBACT(view_layer); - Object *ob_eval = NULL; - Object *obedit_eval = NULL; bGPdata *gpd = CTX_data_gpencil_data(C); const bool is_gp_edit = ((gpd) && (gpd->flag & GP_DATA_STROKE_EDITMODE)); int a, totsel = 0; @@ -612,9 +609,6 @@ int ED_transform_calc_manipulator_stats( rv3d->twdrawflag = 0xFFFF; - ob_eval = DEG_get_evaluated_object(depsgraph, ob); - obedit_eval = DEG_get_evaluated_object(depsgraph, obedit); - /* global, local or normal orientation? * if we could check 'totsel' now, this should be skipped with no selection. */ if (ob && !is_gp_edit) { @@ -629,7 +623,7 @@ int ED_transform_calc_manipulator_stats( case V3D_MANIP_GIMBAL: { float mat[3][3]; - if (gimbal_axis(ob_eval, mat)) { + if (gimbal_axis(ob, mat)) { copy_m4_m3(rv3d->twmat, mat); break; } @@ -659,7 +653,7 @@ int ED_transform_calc_manipulator_stats( copy_m4_m3(rv3d->twmat, mat); break; } - copy_m4_m4(rv3d->twmat, ob_eval->obmat); + copy_m4_m4(rv3d->twmat, ob->obmat); normalize_m4(rv3d->twmat); break; } @@ -699,7 +693,7 @@ int ED_transform_calc_manipulator_stats( copy_m3_m4(tbounds->axis, rv3d->twmat); if (params->use_local_axis && (ob && ob->mode & OB_MODE_EDIT)) { float diff_mat[3][3]; - copy_m3_m4(diff_mat, ob_eval->obmat); + copy_m3_m4(diff_mat, ob->obmat); normalize_m3(diff_mat); invert_m3(diff_mat); mul_m3_m3m3(tbounds->axis, tbounds->axis, diff_mat); @@ -762,7 +756,6 @@ int ED_transform_calc_manipulator_stats( } else if (obedit) { ob = obedit; - ob_eval = obedit_eval; if (obedit->type == OB_MESH) { BMEditMesh *em = BKE_editmesh_from_object(obedit); BMEditSelection ese; @@ -937,9 +930,9 @@ int ED_transform_calc_manipulator_stats( /* selection center */ if (totsel) { mul_v3_fl(tbounds->center, 1.0f / (float)totsel); // centroid! - mul_m4_v3(obedit_eval->obmat, tbounds->center); - mul_m4_v3(obedit_eval->obmat, tbounds->min); - mul_m4_v3(obedit_eval->obmat, tbounds->max); + mul_m4_v3(obedit->obmat, tbounds->center); + mul_m4_v3(obedit->obmat, tbounds->min); + mul_m4_v3(obedit->obmat, tbounds->max); } } else if (ob && (ob->mode & OB_MODE_POSE)) { @@ -947,7 +940,7 @@ int ED_transform_calc_manipulator_stats( int mode = TFM_ROTATION; // mislead counting bones... bah. We don't know the manipulator mode, could be mixed bool ok = false; - if ((pivot_point == V3D_AROUND_ACTIVE) && (pchan = BKE_pose_channel_active(ob_eval))) { + if ((pivot_point == V3D_AROUND_ACTIVE) && (pchan = BKE_pose_channel_active(ob))) { /* doesn't check selection or visibility intentionally */ Bone *bone = pchan->bone; if (bone) { @@ -958,11 +951,11 @@ int ED_transform_calc_manipulator_stats( } } else { - totsel = count_set_pose_transflags(&mode, 0, ob_eval); + totsel = count_set_pose_transflags(ob, mode, V3D_AROUND_CENTER_BOUNDS, NULL); if (totsel) { /* use channels to get stats */ - for (pchan = ob_eval->pose->chanbase.first; pchan; pchan = pchan->next) { + for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { Bone *bone = pchan->bone; if (bone && (bone->flag & BONE_TRANSFORM)) { calc_tw_center(tbounds, pchan->pose_head); @@ -975,9 +968,9 @@ int ED_transform_calc_manipulator_stats( if (ok) { mul_v3_fl(tbounds->center, 1.0f / (float)totsel); // centroid! - mul_m4_v3(ob_eval->obmat, tbounds->center); - mul_m4_v3(ob_eval->obmat, tbounds->min); - mul_m4_v3(ob_eval->obmat, tbounds->max); + mul_m4_v3(ob->obmat, tbounds->center); + mul_m4_v3(ob->obmat, tbounds->min); + mul_m4_v3(ob->obmat, tbounds->max); } } else if (ob && (ob->mode & OB_MODE_ALL_PAINT)) { @@ -1018,18 +1011,16 @@ int ED_transform_calc_manipulator_stats( if (!TESTBASELIB(base)) { continue; } - Object *base_object_eval = DEG_get_evaluated_object(depsgraph, base->object); if (ob == NULL) { ob = base->object; - ob_eval = base_object_eval; } - if (params->use_only_center || base_object_eval->bb == NULL) { - calc_tw_center(tbounds, base_object_eval->obmat[3]); + if (params->use_only_center || base->object->bb == NULL) { + calc_tw_center(tbounds, base->object->obmat[3]); } else { for (uint j = 0; j < 8; j++) { float co[3]; - mul_v3_m4v3(co, base_object_eval->obmat, base_object_eval->bb->vec[j]); + mul_v3_m4v3(co, base->object->obmat, base->object->bb->vec[j]); calc_tw_center(tbounds, co); } } @@ -1547,12 +1538,6 @@ static void WIDGETGROUP_manipulator_draw_prepare(const bContext *C, wmManipulato static bool WIDGETGROUP_manipulator_poll(const struct bContext *C, struct wmManipulatorGroupType *wgt) { /* it's a given we only use this in 3D view */ - ScrArea *sa = CTX_wm_area(C); - View3D *v3d = sa->spacedata.first; - if (v3d && ((v3d->twflag & V3D_MANIPULATOR_DRAW)) == 0) { - return false; - } - bToolRef_Runtime *tref_rt = WM_toolsystem_runtime_from_context((bContext *)C); if ((tref_rt == NULL) || !STREQ(wgt->idname, tref_rt->manipulator_group)) @@ -1593,12 +1578,6 @@ struct XFormCageWidgetGroup { static bool WIDGETGROUP_xform_cage_poll(const bContext *C, wmManipulatorGroupType *wgt) { - ScrArea *sa = CTX_wm_area(C); - View3D *v3d = sa->spacedata.first; - if (v3d && ((v3d->twflag & V3D_MANIPULATOR_DRAW)) == 0) { - return false; - } - bToolRef_Runtime *tref_rt = WM_toolsystem_runtime_from_context((bContext *)C); if (!STREQ(wgt->idname, tref_rt->manipulator_group)) { WM_manipulator_group_type_unlink_delayed_ptr(wgt); diff --git a/source/blender/editors/transform/transform_orientations.c b/source/blender/editors/transform/transform_orientations.c index 3065007ea6b..19df46455d7 100644 --- a/source/blender/editors/transform/transform_orientations.c +++ b/source/blender/editors/transform/transform_orientations.c @@ -56,8 +56,6 @@ #include "BKE_scene.h" #include "BKE_workspace.h" -#include "DEG_depsgraph_query.h" - #include "BLT_translation.h" #include "ED_armature.h" @@ -1016,14 +1014,12 @@ int getTransformOrientation_ex(const bContext *C, float normal[3], float plane[3 } } else if (ob && (ob->mode & OB_MODE_POSE)) { - const Depsgraph *depsgraph = CTX_data_depsgraph(C); - Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob); - bArmature *arm = ob_eval->data; + bArmature *arm = ob->data; bPoseChannel *pchan; float imat[3][3], mat[3][3]; bool ok = false; - if (activeOnly && (pchan = BKE_pose_channel_active(ob_eval))) { + if (activeOnly && (pchan = BKE_pose_channel_active(ob))) { add_v3_v3(normal, pchan->pose_mat[2]); add_v3_v3(plane, pchan->pose_mat[1]); ok = true; @@ -1034,7 +1030,7 @@ int getTransformOrientation_ex(const bContext *C, float normal[3], float plane[3 totsel = count_bone_select(arm, &arm->bonebase, true); if (totsel) { /* use channels to get stats */ - for (pchan = ob_eval->pose->chanbase.first; pchan; pchan = pchan->next) { + for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { if (pchan->bone && pchan->bone->flag & BONE_TRANSFORM) { add_v3_v3(normal, pchan->pose_mat[2]); add_v3_v3(plane, pchan->pose_mat[1]); @@ -1047,7 +1043,7 @@ int getTransformOrientation_ex(const bContext *C, float normal[3], float plane[3 /* use for both active & all */ if (ok) { /* we need the transpose of the inverse for a normal... */ - copy_m3_m4(imat, ob_eval->obmat); + copy_m3_m4(imat, ob->obmat); invert_m3_m3(mat, imat); transpose_m3(mat); diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c index 10de7f3ea36..704582deaca 100644 --- a/source/blender/editors/transform/transform_snap.c +++ b/source/blender/editors/transform/transform_snap.c @@ -406,6 +406,11 @@ void applyGridAbsolute(TransInfo *t) void applySnapping(TransInfo *t, float *vec) { + if (t->tsnap.project && t->tsnap.mode == SCE_SNAP_MODE_FACE) { + /* Each Trans Data already makes the snap to face */ + return; + } + if (t->tsnap.status & SNAP_FORCED) { t->tsnap.targetSnap(t); @@ -495,6 +500,7 @@ static bool bm_face_is_snap_target(BMFace *f, void *UNUSED(user_data)) static void initSnappingMode(TransInfo *t) { + Main *bmain = CTX_data_main(t->context); ToolSettings *ts = t->settings; /* All obedit types will match. */ const int obedit_type = t->data_container->obedit ? t->data_container->obedit->type : -1; @@ -582,7 +588,7 @@ static void initSnappingMode(TransInfo *t) if (t->spacetype == SPACE_VIEW3D) { if (t->tsnap.object_context == NULL) { t->tsnap.object_context = ED_transform_snap_object_context_create_view3d( - t->scene, t->depsgraph, 0, t->ar, t->view); + bmain, t->scene, t->depsgraph, 0, t->ar, t->view); ED_transform_snap_object_context_set_editmesh_callbacks( t->tsnap.object_context, diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c index 5932a35bf2b..e19320fa220 100644 --- a/source/blender/editors/transform/transform_snap_object.c +++ b/source/blender/editors/transform/transform_snap_object.c @@ -56,6 +56,7 @@ #include "BKE_tracking.h" #include "BKE_context.h" #include "BKE_mesh.h" +#include "BKE_mesh_runtime.h" #include "DEG_depsgraph.h" #include "DEG_depsgraph_query.h" @@ -113,6 +114,7 @@ typedef struct SnapObjectData_EditMesh { } SnapObjectData_EditMesh; struct SnapObjectContext { + Main *bmain; Scene *scene; Depsgraph *depsgraph; @@ -2269,12 +2271,13 @@ static short snapObjectsRay( * \{ */ SnapObjectContext *ED_transform_snap_object_context_create( - Scene *scene, Depsgraph *depsgraph, int flag) + Main *bmain, Scene *scene, Depsgraph *depsgraph, int flag) { SnapObjectContext *sctx = MEM_callocN(sizeof(*sctx), __func__); sctx->flag = flag; + sctx->bmain = bmain; sctx->scene = scene; sctx->depsgraph = depsgraph; @@ -2285,11 +2288,11 @@ SnapObjectContext *ED_transform_snap_object_context_create( } SnapObjectContext *ED_transform_snap_object_context_create_view3d( - Scene *scene, Depsgraph *depsgraph, int flag, + Main *bmain, Scene *scene, Depsgraph *depsgraph, int flag, /* extra args for view3d */ const ARegion *ar, const View3D *v3d) { - SnapObjectContext *sctx = ED_transform_snap_object_context_create(scene, depsgraph, flag); + SnapObjectContext *sctx = ED_transform_snap_object_context_create(bmain, scene, depsgraph, flag); sctx->use_v3d = true; sctx->v3d_data.ar = ar; diff --git a/source/blender/editors/util/ed_util.c b/source/blender/editors/util/ed_util.c index 44e2fa98f53..447cff065b7 100644 --- a/source/blender/editors/util/ed_util.c +++ b/source/blender/editors/util/ed_util.c @@ -263,7 +263,7 @@ void unpack_menu(bContext *C, const char *opname, const char *id_name, const cha BLI_split_file_part(abs_name, fi, sizeof(fi)); BLI_snprintf(local_name, sizeof(local_name), "//%s/%s", folder, fi); if (!STREQ(abs_name, local_name)) { - switch (checkPackedFile(bmain->name, local_name, pf)) { + switch (checkPackedFile(BKE_main_blendfile_path(bmain), local_name, pf)) { case PF_NOFILE: BLI_snprintf(line, sizeof(line), IFACE_("Create %s"), local_name); uiItemFullO_ptr(layout, ot, line, ICON_NONE, NULL, WM_OP_EXEC_DEFAULT, 0, &props_ptr); @@ -296,7 +296,7 @@ void unpack_menu(bContext *C, const char *opname, const char *id_name, const cha } } - switch (checkPackedFile(bmain->name, abs_name, pf)) { + switch (checkPackedFile(BKE_main_blendfile_path(bmain), abs_name, pf)) { case PF_NOFILE: BLI_snprintf(line, sizeof(line), IFACE_("Create %s"), abs_name); //uiItemEnumO_ptr(layout, ot, line, 0, "method", PF_WRITE_ORIGINAL); diff --git a/source/blender/editors/uvedit/uvedit_draw.c b/source/blender/editors/uvedit/uvedit_draw.c index e467c61609d..4473922841f 100644 --- a/source/blender/editors/uvedit/uvedit_draw.c +++ b/source/blender/editors/uvedit/uvedit_draw.c @@ -87,6 +87,8 @@ void ED_image_draw_cursor(ARegion *ar, const float cursor[2]) x_fac = zoom[0]; y_fac = zoom[1]; + glLineWidth(1.0f); + gpuTranslate2fv(cursor); const uint shdr_pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c index 6d5a1925dd5..45a6ccfe28b 100644 --- a/source/blender/editors/uvedit/uvedit_ops.c +++ b/source/blender/editors/uvedit/uvedit_ops.c @@ -4437,7 +4437,7 @@ void ED_keymap_uvedit(wmKeyConfig *keyconf) WM_keymap_add_item(keymap, "UV_OT_select_pinned", PKEY, KM_PRESS, KM_SHIFT, 0); - WM_keymap_add_menu(keymap, "IMAGE_MT_uvs_weldalign", WKEY, KM_PRESS, 0, 0); + WM_keymap_add_menu(keymap, "IMAGE_MT_uvs_weldalign", WKEY, KM_PRESS, KM_SHIFT, 0); /* uv operations */ WM_keymap_add_item(keymap, "UV_OT_stitch", VKEY, KM_PRESS, 0, 0); diff --git a/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp b/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp index 6cbdca756d5..f41a9b58085 100644 --- a/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp +++ b/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp @@ -95,7 +95,7 @@ NodeGroup *BlenderFileLoader::Load() int id = 0; DEG_OBJECT_ITER_BEGIN( - depsgraph, ob, DEG_ITER_OBJECT_MODE_RENDER, + depsgraph, ob, DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY | DEG_ITER_OBJECT_FLAG_LINKED_VIA_SET | DEG_ITER_OBJECT_FLAG_VISIBLE | diff --git a/source/blender/gpu/GPU_material.h b/source/blender/gpu/GPU_material.h index 95492016f25..0805cc25d04 100644 --- a/source/blender/gpu/GPU_material.h +++ b/source/blender/gpu/GPU_material.h @@ -238,7 +238,7 @@ GPUNodeLink *GPU_uniformbuffer_link_out( void GPU_material_output_link(GPUMaterial *material, GPUNodeLink *link); GPUBuiltin GPU_get_material_builtins(GPUMaterial *material); -void GPU_material_sss_profile_create(GPUMaterial *material, float *radii, short *falloff_type, float *sharpness); +void GPU_material_sss_profile_create(GPUMaterial *material, float radii[3], short *falloff_type, float *sharpness); struct GPUUniformBuffer *GPU_material_sss_profile_get( GPUMaterial *material, int sample_ct, struct GPUTexture **tex_profile); @@ -246,22 +246,26 @@ struct GPUUniformBuffer *GPU_material_sss_profile_get( GPUMaterial *GPU_material_from_nodetree_find( struct ListBase *gpumaterials, const void *engine_type, int options); GPUMaterial *GPU_material_from_nodetree( - struct Scene *scene, struct bNodeTree *ntree, struct ListBase *gpumaterials, const void *engine_type, int options); -void GPU_material_generate_pass( - GPUMaterial *mat, const char *vert_code, const char *geom_code, const char *frag_lib, const char *defines); + struct Scene *scene, struct bNodeTree *ntree, struct ListBase *gpumaterials, const void *engine_type, int options, + const char *vert_code, const char *geom_code, const char *frag_lib, const char *defines); +void GPU_material_compile(GPUMaterial *mat); void GPU_material_free(struct ListBase *gpumaterial); void GPU_materials_free(void); +void GPU_material_orphans_init(void); +void GPU_material_orphans_exit(void); +/* This has to be called from a thread with an ogl context bound. */ +void GPU_material_orphans_delete(void); + struct Scene *GPU_material_scene(GPUMaterial *material); GPUMatType GPU_Material_get_type(GPUMaterial *material); struct GPUPass *GPU_material_get_pass(GPUMaterial *material); struct ListBase *GPU_material_get_inputs(GPUMaterial *material); GPUMaterialStatus GPU_material_status(GPUMaterial *mat); -struct GPUUniformBuffer *GPU_material_get_uniform_buffer(GPUMaterial *material); -void GPU_material_create_uniform_buffer(GPUMaterial *material, struct ListBase *inputs); -void GPU_material_uniform_buffer_tag_dirty(struct ListBase *gpumaterials); +struct GPUUniformBuffer *GPU_material_uniform_buffer_get(GPUMaterial *material); +void GPU_material_uniform_buffer_create(GPUMaterial *material, ListBase *inputs); void GPU_material_vertex_attributes(GPUMaterial *material, struct GPUVertexAttribs *attrib); @@ -270,6 +274,7 @@ bool GPU_material_do_color_management(GPUMaterial *mat); bool GPU_material_use_domain_surface(GPUMaterial *mat); bool GPU_material_use_domain_volume(GPUMaterial *mat); +void GPU_pass_cache_init(void); void GPU_pass_cache_garbage_collect(void); void GPU_pass_cache_free(void); diff --git a/source/blender/gpu/GPU_texture.h b/source/blender/gpu/GPU_texture.h index 5b125951d9d..3b4cdc21b9d 100644 --- a/source/blender/gpu/GPU_texture.h +++ b/source/blender/gpu/GPU_texture.h @@ -173,10 +173,10 @@ void GPU_invalid_tex_free(void); void GPU_texture_free(GPUTexture *tex); -void GPU_texture_init_orphans(void); -void GPU_texture_exit_orphans(void); +void GPU_texture_orphans_init(void); +void GPU_texture_orphans_exit(void); /* This has to be called from a thread with an ogl context bound. */ -void GPU_texture_delete_orphans(void); +void GPU_texture_orphans_delete(void); void GPU_texture_ref(GPUTexture *tex); void GPU_texture_bind(GPUTexture *tex, int number); diff --git a/source/blender/gpu/GPU_uniformbuffer.h b/source/blender/gpu/GPU_uniformbuffer.h index c2480f8ba03..2f422fa1a92 100644 --- a/source/blender/gpu/GPU_uniformbuffer.h +++ b/source/blender/gpu/GPU_uniformbuffer.h @@ -35,7 +35,6 @@ struct ListBase; typedef struct GPUUniformBuffer GPUUniformBuffer; -typedef struct GPUUniformBufferDynamicItem GPUUniformBufferDynamicItem; GPUUniformBuffer *GPU_uniformbuffer_create(int size, const void *data, char err_out[256]); GPUUniformBuffer *GPU_uniformbuffer_dynamic_create(struct ListBase *inputs, char err_out[256]); @@ -52,7 +51,6 @@ int GPU_uniformbuffer_bindpoint(GPUUniformBuffer *ubo); bool GPU_uniformbuffer_is_empty(GPUUniformBuffer *ubo); bool GPU_uniformbuffer_is_dirty(GPUUniformBuffer *ubo); -void GPU_uniformbuffer_tag_dirty(GPUUniformBuffer *ubo); #define GPU_UBO_BLOCK_NAME "nodeTree" diff --git a/source/blender/gpu/intern/gpu_codegen.c b/source/blender/gpu/intern/gpu_codegen.c index 22665e2c0bf..0dd9d1f0908 100644 --- a/source/blender/gpu/intern/gpu_codegen.c +++ b/source/blender/gpu/intern/gpu_codegen.c @@ -40,10 +40,11 @@ #include "BLI_blenlib.h" #include "BLI_hash_mm2a.h" -#include "BLI_linklist.h" +#include "BLI_link_utils.h" #include "BLI_utildefines.h" #include "BLI_dynstr.h" #include "BLI_ghash.h" +#include "BLI_threads.h" #include "PIL_time.h" @@ -75,39 +76,54 @@ static char *glsl_material_library = NULL; * same for 2 different Materials. Unused GPUPasses are free by Garbage collection. **/ -static LinkNode *pass_cache = NULL; /* GPUPass */ +/* Only use one linklist that contains the GPUPasses grouped by hash. */ +static GPUPass *pass_cache = NULL; +static SpinLock pass_cache_spin; -static uint32_t gpu_pass_hash(const char *vert, const char *geom, const char *frag, const char *defs) +static uint32_t gpu_pass_hash(const char *frag_gen, const char *defs) { BLI_HashMurmur2A hm2a; BLI_hash_mm2a_init(&hm2a, 0); - BLI_hash_mm2a_add(&hm2a, (unsigned char *)frag, strlen(frag)); - BLI_hash_mm2a_add(&hm2a, (unsigned char *)vert, strlen(vert)); + BLI_hash_mm2a_add(&hm2a, (unsigned char *)frag_gen, strlen(frag_gen)); if (defs) BLI_hash_mm2a_add(&hm2a, (unsigned char *)defs, strlen(defs)); - if (geom) - BLI_hash_mm2a_add(&hm2a, (unsigned char *)geom, strlen(geom)); return BLI_hash_mm2a_end(&hm2a); } -/* Search by hash then by exact string match. */ -static GPUPass *gpu_pass_cache_lookup( - const char *vert, const char *geom, const char *frag, const char *defs, uint32_t hash) +/* Search by hash only. Return first pass with the same hash. + * There is hash collision if (pass->next && pass->next->hash == hash) */ +static GPUPass *gpu_pass_cache_lookup(uint32_t hash) { - for (LinkNode *ln = pass_cache; ln; ln = ln->next) { - GPUPass *pass = (GPUPass *)ln->link; + BLI_spin_lock(&pass_cache_spin); + /* Could be optimized with a Lookup table. */ + for (GPUPass *pass = pass_cache; pass; pass = pass->next) { if (pass->hash == hash) { - /* Note: Could be made faster if that becomes a real bottleneck. */ - if ((defs != NULL) && (strcmp(pass->defines, defs) != 0)) { /* Pass */ } - else if ((geom != NULL) && (strcmp(pass->geometrycode, geom) != 0)) { /* Pass */ } - else if ((strcmp(pass->fragmentcode, frag) == 0) && - (strcmp(pass->vertexcode, vert) == 0)) - { - return pass; - } + BLI_spin_unlock(&pass_cache_spin); + return pass; } } + BLI_spin_unlock(&pass_cache_spin); + return NULL; +} + +/* Check all possible passes with the same hash. */ +static GPUPass *gpu_pass_cache_resolve_collision( + GPUPass *pass, const char *vert, const char *geom, const char *frag, const char *defs, uint32_t hash) +{ + BLI_spin_lock(&pass_cache_spin); + /* Collision, need to strcmp the whole shader. */ + for (; pass && (pass->hash == hash); pass = pass->next) { + if ((defs != NULL) && (strcmp(pass->defines, defs) != 0)) { /* Pass */ } + else if ((geom != NULL) && (strcmp(pass->geometrycode, geom) != 0)) { /* Pass */ } + else if ((strcmp(pass->fragmentcode, frag) == 0) && + (strcmp(pass->vertexcode, vert) == 0)) + { + BLI_spin_unlock(&pass_cache_spin); + return pass; + } + } + BLI_spin_unlock(&pass_cache_spin); return NULL; } @@ -656,7 +672,7 @@ static int codegen_process_uniforms_functions(GPUMaterial *material, DynStr *ds, /* Handle the UBO block separately. */ if ((material != NULL) && !BLI_listbase_is_empty(&ubo_inputs)) { - GPU_material_create_uniform_buffer(material, &ubo_inputs); + GPU_material_uniform_buffer_create(material, &ubo_inputs); /* Inputs are sorted */ BLI_dynstr_appendf(ds, "\nlayout (std140) uniform %s {\n", GPU_UBO_BLOCK_NAME); @@ -1099,12 +1115,12 @@ void GPU_code_generate_glsl_lib(void) /* GPU pass binding/unbinding */ -GPUShader *GPU_pass_shader(GPUPass *pass) +GPUShader *GPU_pass_shader_get(GPUPass *pass) { return pass->shader; } -static void gpu_nodes_extract_dynamic_inputs(GPUShader *shader, ListBase *inputs, ListBase *nodes) +void GPU_nodes_extract_dynamic_inputs(GPUShader *shader, ListBase *inputs, ListBase *nodes) { GPUNode *node; GPUInput *next, *input; @@ -1146,8 +1162,12 @@ static void gpu_nodes_extract_dynamic_inputs(GPUShader *shader, ListBase *inputs if (input->bindtex) extract = 1; } - else if (input->dynamicvec) + else if (input->dynamictype == GPU_DYNAMIC_UBO) { + /* Don't extract UBOs */ + } + else if (input->dynamicvec) { extract = 1; + } if (extract) input->shaderloc = GPU_shader_get_uniform(shader, input->shadername); @@ -1896,16 +1916,25 @@ void GPU_nodes_prune(ListBase *nodes, GPUNodeLink *outlink) } } +static bool gpu_pass_is_valid(GPUPass *pass) +{ + /* Shader is not null if compilation is successful, + * refcount is positive if compilation as not yet been done. */ + return (pass->shader != NULL || pass->refcount > 0); +} + GPUPass *GPU_generate_pass_new( GPUMaterial *material, - GPUNodeLink *frag_outlink, struct GPUVertexAttribs *attribs, - ListBase *nodes, ListBase *inputs, - const char *vert_code, const char *geom_code, - const char *frag_lib, const char *defines) + GPUNodeLink *frag_outlink, + struct GPUVertexAttribs *attribs, + ListBase *nodes, + const char *vert_code, + const char *geom_code, + const char *frag_lib, + const char *defines) { char *vertexcode, *geometrycode, *fragmentcode; - GPUShader *shader; - GPUPass *pass; + GPUPass *pass = NULL, *pass_hash = NULL; /* prune unused nodes */ GPU_nodes_prune(nodes, frag_outlink); @@ -1914,6 +1943,24 @@ GPUPass *GPU_generate_pass_new( /* generate code */ char *fragmentgen = code_generate_fragment(material, nodes, frag_outlink->output); + + /* Cache lookup: Reuse shaders already compiled */ + uint32_t hash = gpu_pass_hash(fragmentgen, defines); + pass_hash = gpu_pass_cache_lookup(hash); + + if (pass_hash && (pass_hash->next == NULL || pass_hash->next->hash != hash)) { + /* No collision, just return the pass. */ + MEM_freeN(fragmentgen); + if (!gpu_pass_is_valid(pass_hash)) { + /* Shader has already been created but failed to compile. */ + return NULL; + } + pass_hash->refcount += 1; + return pass_hash; + } + + /* Either the shader is not compiled or there is a hash collision... + * continue generating the shader strings. */ char *tmp = BLI_strdupcat(frag_lib, glsl_material_library); vertexcode = code_generate_vertex(nodes, vert_code, (geom_code != NULL)); @@ -1923,51 +1970,62 @@ GPUPass *GPU_generate_pass_new( MEM_freeN(fragmentgen); MEM_freeN(tmp); - /* Cache lookup: Reuse shaders already compiled */ - uint32_t hash = gpu_pass_hash(vertexcode, geometrycode, fragmentcode, defines); - pass = gpu_pass_cache_lookup(vertexcode, geometrycode, fragmentcode, defines, hash); + if (pass_hash) { + /* Cache lookup: Reuse shaders already compiled */ + pass = gpu_pass_cache_resolve_collision(pass_hash, vertexcode, geometrycode, fragmentcode, defines, hash); + } + if (pass) { /* Cache hit. Reuse the same GPUPass and GPUShader. */ - shader = pass->shader; - pass->refcount += 1; + if (!gpu_pass_is_valid(pass)) { + /* Shader has already been created but failed to compile. */ + return NULL; + } MEM_SAFE_FREE(vertexcode); MEM_SAFE_FREE(fragmentcode); MEM_SAFE_FREE(geometrycode); + + pass->refcount += 1; } else { - /* Cache miss. (Re)compile the shader. */ - shader = GPU_shader_create(vertexcode, - fragmentcode, - geometrycode, - NULL, - defines); - /* We still create a pass even if shader compilation * fails to avoid trying to compile again and again. */ pass = MEM_callocN(sizeof(GPUPass), "GPUPass"); - pass->shader = shader; + pass->shader = NULL; pass->refcount = 1; pass->hash = hash; pass->vertexcode = vertexcode; pass->fragmentcode = fragmentcode; pass->geometrycode = geometrycode; - pass->libcode = glsl_material_library; pass->defines = (defines) ? BLI_strdup(defines) : NULL; + pass->compiled = false; - BLI_linklist_prepend(&pass_cache, pass); + BLI_spin_lock(&pass_cache_spin); + if (pass_hash != NULL) { + /* Add after the first pass having the same hash. */ + pass->next = pass_hash->next; + pass_hash->next = pass; + } + else { + /* No other pass have same hash, just prepend to the list. */ + BLI_LINKS_PREPEND(pass_cache, pass); + } + BLI_spin_unlock(&pass_cache_spin); } - /* did compilation failed ? */ - if (!shader) { - gpu_nodes_free(nodes); - /* Pass will not be used. Don't increment refcount. */ - pass->refcount--; - return NULL; - } - else { - gpu_nodes_extract_dynamic_inputs(shader, inputs, nodes); - return pass; + return pass; +} + +void GPU_pass_compile(GPUPass *pass) +{ + if (!pass->compiled) { + pass->shader = GPU_shader_create(pass->vertexcode, + pass->fragmentcode, + pass->geometrycode, + NULL, + pass->defines); + pass->compiled = true; } } @@ -2006,23 +2064,36 @@ void GPU_pass_cache_garbage_collect(void) lasttime = ctime; - LinkNode *next, **prev_ln = &pass_cache; - for (LinkNode *ln = pass_cache; ln; ln = next) { - GPUPass *pass = (GPUPass *)ln->link; - next = ln->next; + BLI_spin_lock(&pass_cache_spin); + GPUPass *next, **prev_pass = &pass_cache; + for (GPUPass *pass = pass_cache; pass; pass = next) { + next = pass->next; if (pass->refcount == 0) { - gpu_pass_free(pass); /* Remove from list */ - MEM_freeN(ln); - *prev_ln = next; + *prev_pass = next; + gpu_pass_free(pass); } else { - prev_ln = &ln->next; + prev_pass = &pass->next; } } + BLI_spin_unlock(&pass_cache_spin); +} + +void GPU_pass_cache_init(void) +{ + BLI_spin_init(&pass_cache_spin); } void GPU_pass_cache_free(void) { - BLI_linklist_free(pass_cache, (LinkNodeFreeFP)gpu_pass_free); + BLI_spin_lock(&pass_cache_spin); + while (pass_cache) { + GPUPass *next = pass_cache->next; + gpu_pass_free(pass_cache); + pass_cache = next; + } + BLI_spin_unlock(&pass_cache_spin); + + BLI_spin_end(&pass_cache_spin); } diff --git a/source/blender/gpu/intern/gpu_codegen.h b/source/blender/gpu/intern/gpu_codegen.h index 328da36c3de..04bee545a7e 100644 --- a/source/blender/gpu/intern/gpu_codegen.h +++ b/source/blender/gpu/intern/gpu_codegen.h @@ -157,33 +157,30 @@ typedef struct GPUInput { } GPUInput; struct GPUPass { + struct GPUPass *next; + struct GPUShader *shader; char *fragmentcode; char *geometrycode; char *vertexcode; char *defines; - const char *libcode; unsigned int refcount; /* Orphaned GPUPasses gets freed by the garbage collector. */ uint32_t hash; /* Identity hash generated from all GLSL code. */ + bool compiled; /* Did we already tried to compile the attached GPUShader. */ }; - typedef struct GPUPass GPUPass; GPUPass *GPU_generate_pass_new( GPUMaterial *material, GPUNodeLink *frag_outlink, struct GPUVertexAttribs *attribs, - ListBase *nodes, ListBase *inputs, + ListBase *nodes, const char *vert_code, const char *geom_code, const char *frag_lib, const char *defines); -GPUPass *GPU_generate_pass( - ListBase *nodes, ListBase *inputs, struct GPUNodeLink *outlink, - struct GPUVertexAttribs *attribs, int *builtin, - const GPUMatType type, const char *name, - const bool use_opensubdiv); -struct GPUShader *GPU_pass_shader(GPUPass *pass); +struct GPUShader *GPU_pass_shader_get(GPUPass *pass); +void GPU_nodes_extract_dynamic_inputs(struct GPUShader *shader, ListBase *inputs, ListBase *nodes); void GPU_nodes_get_vertex_attributes(ListBase *nodes, struct GPUVertexAttribs *attribs); void GPU_nodes_prune(ListBase *nodes, struct GPUNodeLink *outlink); @@ -191,6 +188,7 @@ void GPU_pass_bind(GPUPass *pass, ListBase *inputs, double time, int mipmap); void GPU_pass_update_uniforms(GPUPass *pass, ListBase *inputs); void GPU_pass_unbind(GPUPass *pass, ListBase *inputs); +void GPU_pass_compile(GPUPass *pass); void GPU_pass_release(GPUPass *pass); void GPU_pass_free_nodes(ListBase *nodes); diff --git a/source/blender/gpu/intern/gpu_init_exit.c b/source/blender/gpu/intern/gpu_init_exit.c index 7b596e6d76b..92ad9d81b6c 100644 --- a/source/blender/gpu/intern/gpu_init_exit.c +++ b/source/blender/gpu/intern/gpu_init_exit.c @@ -57,7 +57,8 @@ void GPU_init(void) gpu_extensions_init(); /* must come first */ - GPU_texture_init_orphans(); + GPU_texture_orphans_init(); + GPU_material_orphans_init(); gpu_codegen_init(); if (G.debug & G_DEBUG_GPU) @@ -82,7 +83,8 @@ void GPU_exit(void) gpu_batch_exit(); - GPU_texture_exit_orphans(); + GPU_texture_orphans_exit(); + GPU_material_orphans_exit(); if (G.debug & G_DEBUG_GPU) gpu_debug_exit(); diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c index 7b3750c970b..302ddc62188 100644 --- a/source/blender/gpu/intern/gpu_material.c +++ b/source/blender/gpu/intern/gpu_material.c @@ -46,6 +46,7 @@ #include "BLI_blenlib.h" #include "BLI_utildefines.h" #include "BLI_rand.h" +#include "BLI_threads.h" #include "BKE_anim.h" #include "BKE_colorband.h" @@ -74,6 +75,9 @@ # include "BKE_DerivedMesh.h" #endif +static ListBase g_orphaned_mat = {NULL, NULL}; +static ThreadMutex g_orphan_lock; + /* Structs */ struct GPUMaterial { @@ -127,10 +131,11 @@ struct GPUMaterial { /* Eevee SSS */ GPUUniformBuffer *sss_profile; /* UBO containing SSS profile. */ GPUTexture *sss_tex_profile; /* Texture containing SSS profile. */ - float *sss_radii; /* UBO containing SSS profile. */ + float sss_enabled; + float sss_radii[3]; int sss_samples; - short int *sss_falloff; - float *sss_sharpness; + short int sss_falloff; + float sss_sharpness; bool sss_dirty; }; @@ -142,36 +147,70 @@ enum { /* Functions */ -void GPU_material_free(ListBase *gpumaterial) +static void gpu_material_free_single(GPUMaterial *material) { - for (LinkData *link = gpumaterial->first; link; link = link->next) { - GPUMaterial *material = link->data; + /* Cancel / wait any pending lazy compilation. */ + DRW_deferred_shader_remove(material); - /* Cancel / wait any pending lazy compilation. */ - DRW_deferred_shader_remove(material); + GPU_pass_free_nodes(&material->nodes); + GPU_inputs_free(&material->inputs); - GPU_pass_free_nodes(&material->nodes); - GPU_inputs_free(&material->inputs); + if (material->pass) + GPU_pass_release(material->pass); - if (material->pass) - GPU_pass_release(material->pass); + if (material->ubo != NULL) { + GPU_uniformbuffer_free(material->ubo); + } - if (material->ubo != NULL) { - GPU_uniformbuffer_free(material->ubo); - } + if (material->sss_tex_profile != NULL) { + GPU_texture_free(material->sss_tex_profile); + } - if (material->sss_tex_profile != NULL) { - GPU_texture_free(material->sss_tex_profile); - } + if (material->sss_profile != NULL) { + GPU_uniformbuffer_free(material->sss_profile); + } +} - if (material->sss_profile != NULL) { - GPU_uniformbuffer_free(material->sss_profile); +void GPU_material_free(ListBase *gpumaterial) +{ + for (LinkData *link = gpumaterial->first; link; link = link->next) { + GPUMaterial *material = link->data; + + /* TODO(fclem): Check if the thread has an ogl context. */ + if (BLI_thread_is_main()) { + gpu_material_free_single(material); + MEM_freeN(material); + } + else { + BLI_mutex_lock(&g_orphan_lock); + BLI_addtail(&g_orphaned_mat, BLI_genericNodeN(material)); + BLI_mutex_unlock(&g_orphan_lock); } + } + BLI_freelistN(gpumaterial); +} - MEM_freeN(material); +void GPU_material_orphans_init(void) +{ + BLI_mutex_init(&g_orphan_lock); +} + +void GPU_material_orphans_delete(void) +{ + BLI_mutex_lock(&g_orphan_lock); + LinkData *link; + while ((link = BLI_pophead(&g_orphaned_mat))) { + gpu_material_free_single((GPUMaterial *)link->data); + MEM_freeN(link->data); + MEM_freeN(link); } + BLI_mutex_unlock(&g_orphan_lock); +} - BLI_freelistN(gpumaterial); +void GPU_material_orphans_exit(void) +{ + GPU_material_orphans_delete(); + BLI_mutex_end(&g_orphan_lock); } GPUBuiltin GPU_get_material_builtins(GPUMaterial *material) @@ -199,7 +238,7 @@ ListBase *GPU_material_get_inputs(GPUMaterial *material) return &material->inputs; } -GPUUniformBuffer *GPU_material_get_uniform_buffer(GPUMaterial *material) +GPUUniformBuffer *GPU_material_uniform_buffer_get(GPUMaterial *material) { return material->ubo; } @@ -208,24 +247,11 @@ GPUUniformBuffer *GPU_material_get_uniform_buffer(GPUMaterial *material) * Create dynamic UBO from parameters * \param ListBase of BLI_genericNodeN(GPUInput) */ -void GPU_material_create_uniform_buffer(GPUMaterial *material, ListBase *inputs) +void GPU_material_uniform_buffer_create(GPUMaterial *material, ListBase *inputs) { material->ubo = GPU_uniformbuffer_dynamic_create(inputs, NULL); } -void GPU_material_uniform_buffer_tag_dirty(ListBase *gpumaterials) -{ - for (LinkData *link = gpumaterials->first; link; link = link->next) { - GPUMaterial *material = link->data; - if (material->ubo != NULL) { - GPU_uniformbuffer_tag_dirty(material->ubo); - } - if (material->sss_profile != NULL) { - material->sss_dirty = true; - } - } -} - /* Eevee Subsurface scattering. */ /* Based on Separable SSS. by Jorge Jimenez and Diego Gutierrez */ @@ -328,7 +354,7 @@ static float eval_integral(float x0, float x1, short falloff_type, float sharpne #undef INTEGRAL_RESOLUTION static void compute_sss_kernel( - GPUSssKernelData *kd, float *radii, int sample_ct, int falloff_type, float sharpness) + GPUSssKernelData *kd, float radii[3], int sample_ct, int falloff_type, float sharpness) { float rad[3]; /* Minimum radius */ @@ -483,12 +509,13 @@ static void compute_sss_translucence_kernel( } #undef INTEGRAL_RESOLUTION -void GPU_material_sss_profile_create(GPUMaterial *material, float *radii, short *falloff_type, float *sharpness) +void GPU_material_sss_profile_create(GPUMaterial *material, float radii[3], short *falloff_type, float *sharpness) { - material->sss_radii = radii; - material->sss_falloff = falloff_type; - material->sss_sharpness = sharpness; + copy_v3_v3(material->sss_radii, radii); + material->sss_falloff = (falloff_type) ? *falloff_type : 0.0; + material->sss_sharpness = (sharpness) ? *sharpness : 0.0; material->sss_dirty = true; + material->sss_enabled = true; /* Update / Create UBO */ if (material->sss_profile == NULL) { @@ -498,25 +525,25 @@ void GPU_material_sss_profile_create(GPUMaterial *material, float *radii, short struct GPUUniformBuffer *GPU_material_sss_profile_get(GPUMaterial *material, int sample_ct, GPUTexture **tex_profile) { - if (material->sss_radii == NULL) + if (!material->sss_enabled) return NULL; if (material->sss_dirty || (material->sss_samples != sample_ct)) { GPUSssKernelData kd; - float sharpness = (material->sss_sharpness != NULL) ? *material->sss_sharpness : 0.0f; + float sharpness = material->sss_sharpness; /* XXX Black magic but it seems to fit. Maybe because we integrate -1..1 */ sharpness *= 0.5f; - compute_sss_kernel(&kd, material->sss_radii, sample_ct, *material->sss_falloff, sharpness); + compute_sss_kernel(&kd, material->sss_radii, sample_ct, material->sss_falloff, sharpness); /* Update / Create UBO */ GPU_uniformbuffer_update(material->sss_profile, &kd); /* Update / Create Tex */ float *translucence_profile; - compute_sss_translucence_kernel(&kd, 64, *material->sss_falloff, sharpness, &translucence_profile); + compute_sss_translucence_kernel(&kd, 64, material->sss_falloff, sharpness, &translucence_profile); if (material->sss_tex_profile != NULL) { GPU_texture_free(material->sss_tex_profile); @@ -602,7 +629,8 @@ GPUMaterial *GPU_material_from_nodetree_find( * so only do this when they are needed. */ GPUMaterial *GPU_material_from_nodetree( - Scene *scene, struct bNodeTree *ntree, ListBase *gpumaterials, const void *engine_type, int options) + Scene *scene, struct bNodeTree *ntree, ListBase *gpumaterials, const void *engine_type, int options, + const char *vert_code, const char *geom_code, const char *frag_lib, const char *defines) { LinkData *link; bool has_volume_output, has_surface_output; @@ -631,11 +659,38 @@ GPUMaterial *GPU_material_from_nodetree( * generated VBOs are ready to accept the future shader. */ GPU_nodes_prune(&mat->nodes, mat->outlink); GPU_nodes_get_vertex_attributes(&mat->nodes, &mat->attribs); - mat->status = GPU_MAT_QUEUED; + /* Create source code and search pass cache for an already compiled version. */ + mat->pass = GPU_generate_pass_new(mat, + mat->outlink, + &mat->attribs, + &mat->nodes, + vert_code, + geom_code, + frag_lib, + defines); + + if (mat->pass == NULL) { + /* We had a cache hit and the shader has already failed to compile. */ + mat->status = GPU_MAT_FAILED; + } + else { + GPUShader *sh = GPU_pass_shader_get(mat->pass); + if (sh != NULL) { + /* We had a cache hit and the shader is already compiled. */ + mat->status = GPU_MAT_SUCCESS; + GPU_nodes_extract_dynamic_inputs(sh, &mat->inputs, &mat->nodes); + } + else { + mat->status = GPU_MAT_QUEUED; + } + } + } + else { + mat->status = GPU_MAT_FAILED; } /* note that even if building the shader fails in some way, we still keep - * it to avoid trying to compile again and again, and simple do not use + * it to avoid trying to compile again and again, and simply do not use * the actual shader on drawing */ link = MEM_callocN(sizeof(LinkData), "GPUMaterialLink"); @@ -645,17 +700,26 @@ GPUMaterial *GPU_material_from_nodetree( return mat; } -void GPU_material_generate_pass( - GPUMaterial *mat, const char *vert_code, const char *geom_code, const char *frag_lib, const char *defines) +void GPU_material_compile(GPUMaterial *mat) { - BLI_assert(mat->pass == NULL); /* Only run once! */ - if (mat->outlink) { - mat->pass = GPU_generate_pass_new( - mat, mat->outlink, &mat->attribs, &mat->nodes, &mat->inputs, vert_code, geom_code, frag_lib, defines); - mat->status = (mat->pass) ? GPU_MAT_SUCCESS : GPU_MAT_FAILED; + /* Only run once! */ + BLI_assert(mat->status == GPU_MAT_QUEUED); + BLI_assert(mat->pass); + + /* NOTE: The shader may have already been compiled here since we are + * sharing GPUShader across GPUMaterials. In this case it's a no-op. */ + GPU_pass_compile(mat->pass); + GPUShader *sh = GPU_pass_shader_get(mat->pass); + + if (sh != NULL) { + mat->status = GPU_MAT_SUCCESS; + GPU_nodes_extract_dynamic_inputs(sh, &mat->inputs, &mat->nodes); } else { mat->status = GPU_MAT_FAILED; + GPU_pass_free_nodes(&mat->nodes); + GPU_pass_release(mat->pass); + mat->pass = NULL; } } diff --git a/source/blender/gpu/intern/gpu_texture.c b/source/blender/gpu/intern/gpu_texture.c index dadd8c441f4..aac75014b3e 100644 --- a/source/blender/gpu/intern/gpu_texture.c +++ b/source/blender/gpu/intern/gpu_texture.c @@ -1124,12 +1124,12 @@ void GPU_texture_free(GPUTexture *tex) } } -void GPU_texture_init_orphans(void) +void GPU_texture_orphans_init(void) { BLI_mutex_init(&g_orphan_lock); } -void GPU_texture_delete_orphans(void) +void GPU_texture_orphans_delete(void) { BLI_mutex_lock(&g_orphan_lock); LinkData *link; @@ -1140,9 +1140,9 @@ void GPU_texture_delete_orphans(void) BLI_mutex_unlock(&g_orphan_lock); } -void GPU_texture_exit_orphans(void) +void GPU_texture_orphans_exit(void) { - GPU_texture_delete_orphans(); + GPU_texture_orphans_delete(); BLI_mutex_end(&g_orphan_lock); } diff --git a/source/blender/gpu/intern/gpu_uniformbuffer.c b/source/blender/gpu/intern/gpu_uniformbuffer.c index afd43600d9b..1e39b2ea5b7 100644 --- a/source/blender/gpu/intern/gpu_uniformbuffer.c +++ b/source/blender/gpu/intern/gpu_uniformbuffer.c @@ -62,26 +62,14 @@ struct GPUUniformBuffer { typedef struct GPUUniformBufferDynamic { GPUUniformBuffer buffer; - ListBase items; /* GPUUniformBufferDynamicItem */ - void *data; + void *data; /* Continuous memory block to copy to GPU. */ char flag; } GPUUniformBufferDynamic; -struct GPUUniformBufferDynamicItem { - struct GPUUniformBufferDynamicItem *next, *prev; - GPUType gputype; - float *data; - int size; -}; - - /* Prototypes */ static GPUType get_padded_gpu_type(struct LinkData *link); static void gpu_uniformbuffer_inputs_sort(struct ListBase *inputs); -static GPUUniformBufferDynamicItem *gpu_uniformbuffer_populate( - GPUUniformBufferDynamic *ubo, const GPUType gputype, float *num); - /* Only support up to this type, if you want to extend it, make sure the * padding logic is correct for the new types. */ #define MAX_UBO_GPU_TYPE GPU_VEC4 @@ -159,34 +147,47 @@ GPUUniformBuffer *GPU_uniformbuffer_dynamic_create(ListBase *inputs, char err_ou gpu_uniformbuffer_inputs_sort(inputs); for (LinkData *link = inputs->first; link; link = link->next) { - GPUInput *input = link->data; - GPUType gputype = get_padded_gpu_type(link); - gpu_uniformbuffer_populate(ubo, gputype, input->dynamicvec); + const GPUType gputype = get_padded_gpu_type(link); + ubo->buffer.size += gputype * sizeof(float); } + /* Allocate the data. */ ubo->data = MEM_mallocN(ubo->buffer.size, __func__); - /* Initialize buffer data. */ - GPU_uniformbuffer_dynamic_update(&ubo->buffer); + /* Now that we know the total ubo size we can start populating it. */ + float *offset = ubo->data; + for (LinkData *link = inputs->first; link; link = link->next) { + GPUInput *input = link->data; + const GPUType gputype = get_padded_gpu_type(link); + memcpy(offset, input->dynamicvec, gputype * sizeof(float)); + offset += gputype; + } + + /* Note since we may create the UBOs in the CPU in a different thread than the main drawing one, + * we don't create the UBO in the GPU here. This will happen when we first bind the UBO. + */ + return &ubo->buffer; } /** - * Free the data, and clean the items list. + * Free the data */ -static void gpu_uniformbuffer_dynamic_reset(GPUUniformBufferDynamic *ubo) +static void gpu_uniformbuffer_dynamic_free(GPUUniformBuffer *ubo_) { + BLI_assert(ubo_->type == GPU_UBO_DYNAMIC); + GPUUniformBufferDynamic *ubo = (GPUUniformBufferDynamic *)ubo_; + ubo->buffer.size = 0; if (ubo->data) { MEM_freeN(ubo->data); } - BLI_freelistN(&ubo->items); } void GPU_uniformbuffer_free(GPUUniformBuffer *ubo) { if (ubo->type == GPU_UBO_DYNAMIC) { - gpu_uniformbuffer_dynamic_reset((GPUUniformBufferDynamic *)ubo); + gpu_uniformbuffer_dynamic_free(ubo); } glDeleteBuffers(1, &ubo->bindcode); @@ -215,12 +216,6 @@ void GPU_uniformbuffer_dynamic_update(GPUUniformBuffer *ubo_) BLI_assert(ubo_->type == GPU_UBO_DYNAMIC); GPUUniformBufferDynamic *ubo = (GPUUniformBufferDynamic *)ubo_; - float *offset = ubo->data; - for (GPUUniformBufferDynamicItem *item = ubo->items.first; item; item = item->next) { - memcpy(offset, item->data, item->size); - offset += item->gputype; - } - if (ubo->flag & GPU_UBO_FLAG_INITIALIZED) { gpu_uniformbuffer_update(ubo_, ubo->data); } @@ -316,27 +311,6 @@ static void gpu_uniformbuffer_inputs_sort(ListBase *inputs) } } -/** - * This may now happen from the main thread, so we can't update the UBO - * We simply flag it as dirty - */ -static GPUUniformBufferDynamicItem *gpu_uniformbuffer_populate( - GPUUniformBufferDynamic *ubo, const GPUType gputype, float *num) -{ - BLI_assert(gputype <= MAX_UBO_GPU_TYPE); - GPUUniformBufferDynamicItem *item = MEM_callocN(sizeof(GPUUniformBufferDynamicItem), __func__); - - item->gputype = gputype; - item->data = num; - item->size = gputype * sizeof(float); - ubo->buffer.size += item->size; - - ubo->flag |= GPU_UBO_FLAG_DIRTY; - BLI_addtail(&ubo->items, item); - - return item; -} - void GPU_uniformbuffer_bind(GPUUniformBuffer *ubo, int number) { if (number >= GPU_max_ubo_binds()) { @@ -368,11 +342,4 @@ int GPU_uniformbuffer_bindpoint(GPUUniformBuffer *ubo) return ubo->bindpoint; } -void GPU_uniformbuffer_tag_dirty(GPUUniformBuffer *ubo_) -{ - BLI_assert(ubo_->type == GPU_UBO_DYNAMIC); - GPUUniformBufferDynamic *ubo = (GPUUniformBufferDynamic *)ubo_; - ubo->flag |= GPU_UBO_FLAG_DIRTY; -} - #undef MAX_UBO_GPU_TYPE diff --git a/source/blender/ikplugin/CMakeLists.txt b/source/blender/ikplugin/CMakeLists.txt index 8991e113410..eb34e50715e 100644 --- a/source/blender/ikplugin/CMakeLists.txt +++ b/source/blender/ikplugin/CMakeLists.txt @@ -25,7 +25,7 @@ remove_extra_strict_flags() -set(INC +set(INC . ../blenkernel ../blenlib diff --git a/source/blender/ikplugin/intern/ikplugin_api.c b/source/blender/ikplugin/intern/ikplugin_api.c index 216e60f5c5c..791b74e4bc9 100644 --- a/source/blender/ikplugin/intern/ikplugin_api.c +++ b/source/blender/ikplugin/intern/ikplugin_api.c @@ -105,7 +105,7 @@ void BIK_execute_tree(struct Depsgraph *depsgraph, struct Scene *scene, Object * plugin->execute_tree_func(depsgraph, scene, ob, pchan, ctime); } -void BIK_release_tree(struct Scene *scene, Object *ob, float ctime) +void BIK_release_tree(struct Scene *scene, Object *ob, float ctime) { IKPlugin *plugin = get_plugin(ob->pose); diff --git a/source/blender/ikplugin/intern/itasc_plugin.cpp b/source/blender/ikplugin/intern/itasc_plugin.cpp index af303556090..9ad98755be1 100644 --- a/source/blender/ikplugin/intern/itasc_plugin.cpp +++ b/source/blender/ikplugin/intern/itasc_plugin.cpp @@ -881,7 +881,7 @@ static int convert_channels(struct Depsgraph *depsgraph, IK_Scene *ikscene, Pose ikchan->owner = ikscene->blArmature; // the constraint and channels must be applied before we build the iTaSC scene, - // this is because some of the pose data (e.g. pose head) don't have corresponding + // this is because some of the pose data (e.g. pose head) don't have corresponding // joint angles and can't be applied to the iTaSC armature dynamically if (!(pchan->flag & POSE_DONE)) BKE_pose_where_is_bone(depsgraph, ikscene->blscene, ikscene->blArmature, pchan, ctime, 1); diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h index 6ce0c94d884..f79d3259244 100644 --- a/source/blender/makesdna/DNA_ID.h +++ b/source/blender/makesdna/DNA_ID.h @@ -381,7 +381,7 @@ typedef enum ID_Type { #define ID_CHECK_UNDO(id) ((GS((id)->name) != ID_SCR) && (GS((id)->name) != ID_WM) && (GS((id)->name) != ID_WS)) -#define ID_BLEND_PATH(_bmain, _id) ((_id)->lib ? (_id)->lib->filepath : (_bmain)->name) +#define ID_BLEND_PATH(_bmain, _id) ((_id)->lib ? (_id)->lib->filepath : BKE_main_blendfile_path((_bmain))) #define ID_MISSING(_id) (((_id)->tag & LIB_TAG_MISSING) != 0) diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h index c9db5fbbdfb..f37bccbfe4e 100644 --- a/source/blender/makesdna/DNA_object_types.h +++ b/source/blender/makesdna/DNA_object_types.h @@ -147,7 +147,7 @@ typedef struct ObjectDisplay { typedef struct Object_Runtime { /* Original mesh pointer, before object->data was changed to point * to mesh_eval. - * Is assigned by dependency craph's copy-on-write evaluation. + * Is assigned by dependency graph's copy-on-write evaluation. */ struct Mesh *mesh_orig; /* Mesh structure created during object evaluation. @@ -342,26 +342,6 @@ typedef struct ObHook { float force; } ObHook; -/* runtime only, but include here for rna access */ -typedef struct DupliObject { - struct DupliObject *next, *prev; - struct Object *ob; - float mat[4][4]; - float orco[3], uv[2]; - - short type; /* from Object.transflag */ - char no_draw, animated; - - /* persistent identifier for a dupli object, for inter-frame matching of - * objects with motion blur, or inter-update matching for syncing */ - int persistent_id[16]; /* 2*MAX_DUPLI_RECUR */ - - /* particle this dupli was generated from */ - struct ParticleSystem *particle_system; - unsigned int random_id; - unsigned int pad; -} DupliObject; - /* **************** OBJECT ********************* */ /* used many places... should be specialized */ diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h index d867e05f209..18fd17c006e 100644 --- a/source/blender/makesdna/DNA_space_types.h +++ b/source/blender/makesdna/DNA_space_types.h @@ -196,6 +196,7 @@ typedef enum eSpaceButtons_Context { BCONTEXT_CONSTRAINT = 11, BCONTEXT_BONE_CONSTRAINT = 12, BCONTEXT_VIEW_LAYER = 13, + BCONTEXT_TOOL = 14, BCONTEXT_WORKSPACE = 15, /* always as last... */ @@ -220,12 +221,6 @@ typedef enum eSpaceButtons_Align { BUT_AUTO = 3, } eSpaceButtons_Align; -/* SpaceButs.flag */ -typedef enum eSpaceButtons_SubType { - SB_SUBTYPE_DATA = 0, - SB_SUBTYPE_TOOL = 1, -} eSpaceButtons_SubType; - /** \} */ /* -------------------------------------------------------------------- */ diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h index 468436668b7..17f520fdfa9 100644 --- a/source/blender/makesdna/DNA_userdef_types.h +++ b/source/blender/makesdna/DNA_userdef_types.h @@ -617,6 +617,7 @@ typedef enum eUserPref_Section { USER_SECTION_THEME = 4, USER_SECTION_INPUT = 5, USER_SECTION_ADDONS = 6, + USER_SECTION_LIGHT = 7, } eUserPref_Section; /* UserDef.flag */ diff --git a/source/blender/makesdna/DNA_view3d_types.h b/source/blender/makesdna/DNA_view3d_types.h index be980b4fead..9794a1efbf5 100644 --- a/source/blender/makesdna/DNA_view3d_types.h +++ b/source/blender/makesdna/DNA_view3d_types.h @@ -140,6 +140,7 @@ typedef struct View3DShading { short light; char pad[2]; char studio_light[256]; /* FILE_MAXFILE */ + char matcap[256]; /* FILE_MAXFILE */ float shadow_intensity; float single_color[3]; @@ -149,6 +150,9 @@ typedef struct View3DShading { float object_outline_color[3]; float xray_alpha; + + float cavity_valley_factor; + float cavity_ridge_factor; } View3DShading; /* 3D Viewport Overlay setings */ @@ -165,6 +169,10 @@ typedef struct View3DOverlay { /* Armature edit/pose mode settings */ int arm_flag; + float bone_selection_alpha; + + /* Other settings */ + float wireframe_threshold; } View3DOverlay; /* 3D ViewPort Struct */ @@ -333,7 +341,7 @@ typedef struct View3D { enum { V3D_LIGHTING_FLAT = 0, V3D_LIGHTING_STUDIO = 1, - V3D_LIGHTING_SCENE = 2 + V3D_LIGHTING_MATCAP = 2, }; /* View3DShading->flag */ @@ -343,6 +351,8 @@ enum { V3D_SHADING_SHADOW = (1 << 2), V3D_SHADING_SCENE_LIGHT = (1 << 3), V3D_SHADING_SPECULAR_HIGHLIGHT = (1 << 4), + V3D_SHADING_CAVITY = (1 << 5), + V3D_SHADING_MATCAP_FLIP_X = (1 << 6), }; /* View3DShading->single_color_type */ diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h index 193c5a77794..125264ca03c 100644 --- a/source/blender/makesrna/RNA_access.h +++ b/source/blender/makesrna/RNA_access.h @@ -809,6 +809,7 @@ PropertyType RNA_property_type(PropertyRNA *prop); PropertySubType RNA_property_subtype(PropertyRNA *prop); PropertyUnit RNA_property_unit(PropertyRNA *prop); int RNA_property_flag(PropertyRNA *prop); +int RNA_property_override_flag(PropertyRNA *prop); int RNA_property_tags(PropertyRNA *prop); bool RNA_property_builtin(PropertyRNA *prop); void *RNA_property_py_data_get(PropertyRNA *prop); diff --git a/source/blender/makesrna/RNA_define.h b/source/blender/makesrna/RNA_define.h index 4e32651d356..d56ccbcfa01 100644 --- a/source/blender/makesrna/RNA_define.h +++ b/source/blender/makesrna/RNA_define.h @@ -149,6 +149,8 @@ void RNA_def_property_collection_sdna(PropertyRNA *prop, const char *structname, void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag); void RNA_def_property_clear_flag(PropertyRNA *prop, PropertyFlag flag); +void RNA_def_property_override_flag(PropertyRNA *prop, PropertyOverrideFlag flag); +void RNA_def_property_override_clear_flag(PropertyRNA *prop, PropertyOverrideFlag flag); void RNA_def_property_tags(PropertyRNA *prop, int tags); void RNA_def_property_subtype(PropertyRNA *prop, PropertySubType subtype); void RNA_def_property_array(PropertyRNA *prop, int length); diff --git a/source/blender/makesrna/RNA_enum_types.h b/source/blender/makesrna/RNA_enum_types.h index 788b1372fc8..da2705d4660 100644 --- a/source/blender/makesrna/RNA_enum_types.h +++ b/source/blender/makesrna/RNA_enum_types.h @@ -57,7 +57,6 @@ extern const EnumPropertyItem rna_enum_mesh_select_mode_items[]; extern const EnumPropertyItem rna_enum_mesh_delimit_mode_items[]; extern const EnumPropertyItem rna_enum_space_type_items[]; extern const EnumPropertyItem rna_enum_space_image_mode_items[]; -extern const EnumPropertyItem rna_enum_space_button_mode_items[]; extern const EnumPropertyItem rna_enum_region_type_items[]; extern const EnumPropertyItem rna_enum_object_modifier_type_items[]; extern const EnumPropertyItem rna_enum_constraint_type_items[]; diff --git a/source/blender/makesrna/RNA_types.h b/source/blender/makesrna/RNA_types.h index 5d6f309ad65..9d304018990 100644 --- a/source/blender/makesrna/RNA_types.h +++ b/source/blender/makesrna/RNA_types.h @@ -158,7 +158,7 @@ typedef enum PropertySubType { /* Make sure enums are updated with these */ /* HIGHEST FLAG IN USE: 1 << 31 - * FREE FLAGS: 11, 13, 14, 15, 30 */ + * FREE FLAGS: 2, 9, 11, 13, 14, 15, 30 */ typedef enum PropertyFlag { /* editable means the property is editable in the user * interface, properties are editable by default except @@ -176,15 +176,6 @@ typedef enum PropertyFlag { * and collections */ PROP_ANIMATABLE = (1 << 1), - /* Means the property can be overriden by a local 'proxy' of some linked datablock. */ - PROP_OVERRIDABLE_STATIC = (1 << 2), - /* The property supports insertion (collections only). */ - PROP_OVERRIDABLE_STATIC_INSERTION = (1 << 9), - - /* Forbid usage of this property in comparison (& hence override) code. - * Useful e.g. for collections of data like mesh's geometry, particles, etc. */ - PROP_NO_COMPARISON = (1 << 3), - /* This flag means when the property's widget is in 'textedit' mode, it will be updated * after every typed char, instead of waiting final validation. Used e.g. for text searchbox. * It will also cause UI_BUT_VALUE_CLEAR to be set for text buttons. We could add an own flag @@ -253,6 +244,27 @@ typedef enum PropertyFlag { PROP_ENUM_NO_TRANSLATE = (1 << 29), /* for enums not to be translated (e.g. viewlayers' names in nodes) */ } PropertyFlag; +/* Flags related to comparing and overriding RNA properties. Make sure enums are updated with these */ +/* FREE FLAGS: 2, 3, 4, 5, 6, 7, 8, 9, 12 and above. */ +typedef enum PropertyOverrideFlag { + /* Means the property can be overriden by a local 'proxy' of some linked datablock. */ + PROPOVERRIDE_OVERRIDABLE_STATIC = (1 << 0), + + /* Forbid usage of this property in comparison (& hence override) code. + * Useful e.g. for collections of data like mesh's geometry, particles, etc. */ + PROPOVERRIDE_NO_COMPARISON = (1 << 1), + + /*** Collections-related ***/ + + /* The property supports insertion (collections only). */ + PROPOVERRIDE_STATIC_INSERTION = (1 << 10), + + /* Only use indices to compare items in the property, never names (collections only). */ + /* Useful when nameprop of the items is generated from other data + * (e.g. name of material slots is actually name of assigned material). */ + PROPOVERRIDE_NO_PROP_NAME = (1 << 11), +} PropertyOverrideFlag; + /* Function parameters flags. * WARNING: 16bits only. */ typedef enum ParameterFlag { diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c index d3301eaf90e..8a50da27144 100644 --- a/source/blender/makesrna/intern/makesrna.c +++ b/source/blender/makesrna/intern/makesrna.c @@ -3056,7 +3056,7 @@ static void rna_generate_property(FILE *f, StructRNA *srna, const char *nest, Pr else fprintf(f, "NULL,\n"); fprintf(f, "\t%d, ", prop->magic); rna_print_c_string(f, prop->identifier); - fprintf(f, ", %d, %d, %d, %d, ", prop->flag, prop->flag_parameter, prop->flag_internal, prop->tags); + fprintf(f, ", %d, %d, %d, %d, %d, ", prop->flag, prop->flag_override, prop->flag_parameter, prop->flag_internal, prop->tags); rna_print_c_string(f, prop->name); fprintf(f, ",\n\t"); rna_print_c_string(f, prop->description); fprintf(f, ",\n\t"); fprintf(f, "%d, ", prop->icon); diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c index 5a0dec28324..df09e5c68b5 100644 --- a/source/blender/makesrna/intern/rna_access.c +++ b/source/blender/makesrna/intern/rna_access.c @@ -1005,6 +1005,11 @@ int RNA_property_flag(PropertyRNA *prop) return rna_ensure_property(prop)->flag; } +int RNA_property_override_flag(PropertyRNA *prop) +{ + return rna_ensure_property(prop)->flag_override; +} + /** * Get the tags set for \a prop as int bitfield. * \note Doesn't perform any validity check on the set bits. #RNA_def_property_tags does this @@ -1976,11 +1981,11 @@ bool RNA_property_overridable_get(PointerRNA *ptr, PropertyRNA *prop) } } /* If this is a RNA-defined property (real or 'virtual' IDProp), we want to use RNA prop flag. */ - return !(prop->flag & PROP_NO_COMPARISON) && (prop->flag & PROP_OVERRIDABLE_STATIC); + return !(prop->flag_override & PROPOVERRIDE_NO_COMPARISON) && (prop->flag_override & PROPOVERRIDE_OVERRIDABLE_STATIC); } else { /* If this is a real 'pure' IDProp (aka custom property), we want to use the IDProp flag. */ - return !(prop->flag & PROP_NO_COMPARISON) && (((IDProperty *)prop)->flag & IDP_FLAG_OVERRIDABLE_STATIC); + return !(prop->flag_override & PROPOVERRIDE_NO_COMPARISON) && (((IDProperty *)prop)->flag & IDP_FLAG_OVERRIDABLE_STATIC); } } @@ -2016,7 +2021,7 @@ bool RNA_property_comparable(PointerRNA *UNUSED(ptr), PropertyRNA *prop) { prop = rna_ensure_property(prop); - return !(prop->flag & PROP_NO_COMPARISON); + return !(prop->flag_override & PROPOVERRIDE_NO_COMPARISON); } /* this function is to check if its possible to create a valid path from the ID diff --git a/source/blender/makesrna/intern/rna_animation.c b/source/blender/makesrna/intern/rna_animation.c index 84764187b62..d2c719ac5d1 100644 --- a/source/blender/makesrna/intern/rna_animation.c +++ b/source/blender/makesrna/intern/rna_animation.c @@ -1027,7 +1027,7 @@ void rna_def_animdata_common(StructRNA *srna) prop = RNA_def_property(srna, "animation_data", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "adt"); RNA_def_property_clear_flag(prop, PROP_EDITABLE); - RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); RNA_def_property_override_funcs(prop, NULL, NULL, "rna_AnimaData_override_apply"); RNA_def_property_ui_text(prop, "Animation Data", "Animation data for this data-block"); } @@ -1052,7 +1052,8 @@ static void rna_def_animdata(BlenderRNA *brna) /* Active Action */ prop = RNA_def_property(srna, "action", PROP_POINTER, PROP_NONE); /* this flag as well as the dynamic test must be defined for this to be editable... */ - RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT | PROP_OVERRIDABLE_STATIC); + RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); RNA_def_property_pointer_funcs(prop, NULL, "rna_AnimData_action_set", NULL, "rna_Action_id_poll"); RNA_def_property_editable_func(prop, "rna_AnimData_action_editable"); RNA_def_property_ui_text(prop, "Action", "Active Action for this data-block"); @@ -1073,7 +1074,7 @@ static void rna_def_animdata(BlenderRNA *brna) "Method used for combining Active Action's result with result of NLA stack"); RNA_def_property_update(prop, NC_ANIMATION | ND_NLA, NULL); /* this will do? */ - prop = RNA_def_property(srna, "action_influence", PROP_FLOAT, PROP_NONE); + prop = RNA_def_property(srna, "action_influence", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "act_influence"); RNA_def_property_float_default(prop, 1.0f); RNA_def_property_range(prop, 0.0f, 1.0f); @@ -1085,7 +1086,7 @@ static void rna_def_animdata(BlenderRNA *brna) prop = RNA_def_property(srna, "drivers", PROP_COLLECTION, PROP_NONE); RNA_def_property_collection_sdna(prop, NULL, "drivers", NULL); RNA_def_property_struct_type(prop, "FCurve"); - RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); RNA_def_property_ui_text(prop, "Drivers", "The Drivers/Expressions for this data-block"); rna_api_animdata_drivers(brna, prop); diff --git a/source/blender/makesrna/intern/rna_armature.c b/source/blender/makesrna/intern/rna_armature.c index 30c643388af..69a5cc2d6b1 100644 --- a/source/blender/makesrna/intern/rna_armature.c +++ b/source/blender/makesrna/intern/rna_armature.c @@ -44,6 +44,7 @@ #ifdef RNA_RUNTIME #include "BKE_context.h" +#include "BKE_global.h" #include "BKE_idprop.h" #include "BKE_main.h" @@ -340,7 +341,7 @@ static void rna_EditBone_name_set(PointerRNA *ptr, const char *value) BLI_strncpy_utf8(newname, value, sizeof(ebone->name)); BLI_strncpy(oldname, ebone->name, sizeof(ebone->name)); - ED_armature_bone_rename(arm, oldname, newname); + ED_armature_bone_rename(G.main, arm, oldname, newname); } static void rna_Bone_name_set(PointerRNA *ptr, const char *value) @@ -353,7 +354,7 @@ static void rna_Bone_name_set(PointerRNA *ptr, const char *value) BLI_strncpy_utf8(newname, value, sizeof(bone->name)); BLI_strncpy(oldname, bone->name, sizeof(bone->name)); - ED_armature_bone_rename(arm, oldname, newname); + ED_armature_bone_rename(G.main, arm, oldname, newname); } static void rna_EditBone_layer_set(PointerRNA *ptr, const int values[]) @@ -504,9 +505,9 @@ static int rna_Armature_is_editmode_get(PointerRNA *ptr) return (arm->edbo != NULL); } -static void rna_Armature_transform(struct bArmature *arm, float *mat) +static void rna_Armature_transform(struct bArmature *arm, Main *bmain, float *mat) { - ED_armature_transform(arm, (float (*)[4])mat, true); + ED_armature_transform(bmain, arm, (float (*)[4])mat, true); } #else @@ -1034,6 +1035,7 @@ static void rna_def_armature(BlenderRNA *brna) RNA_def_struct_sdna(srna, "bArmature"); func = RNA_def_function(srna, "transform", "rna_Armature_transform"); + RNA_def_function_flag(func, FUNC_USE_MAIN); RNA_def_function_ui_description(func, "Transform armature bones by a matrix"); parm = RNA_def_float_matrix(func, "matrix", 4, 4, NULL, 0.0f, 0.0f, "", "Matrix", 0.0f, 0.0f); RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); diff --git a/source/blender/makesrna/intern/rna_color.c b/source/blender/makesrna/intern/rna_color.c index f895cfbbf0c..8e090937605 100644 --- a/source/blender/makesrna/intern/rna_color.c +++ b/source/blender/makesrna/intern/rna_color.c @@ -548,7 +548,7 @@ static const EnumPropertyItem *rna_ColorManagedColorspaceSettings_colorspace_ite return items; } -static void rna_ColorManagedColorspaceSettings_reload_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) +static void rna_ColorManagedColorspaceSettings_reload_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr) { ID *id = ptr->id.data; @@ -565,7 +565,7 @@ static void rna_ColorManagedColorspaceSettings_reload_update(Main *UNUSED(bmain) else if (GS(id->name) == ID_MC) { MovieClip *clip = (MovieClip *) id; - BKE_movieclip_reload(clip); + BKE_movieclip_reload(bmain, clip); /* all sequencers for now, we don't know which scenes are using this clip as a strip */ BKE_sequencer_cache_cleanup(); diff --git a/source/blender/makesrna/intern/rna_constraint.c b/source/blender/makesrna/intern/rna_constraint.c index 7c53a3b54c0..e01ca97dfac 100644 --- a/source/blender/makesrna/intern/rna_constraint.c +++ b/source/blender/makesrna/intern/rna_constraint.c @@ -2361,12 +2361,12 @@ void RNA_def_constraint(BlenderRNA *brna) /* flags */ prop = RNA_def_property(srna, "mute", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", CONSTRAINT_OFF); - RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); RNA_def_property_ui_text(prop, "Disable", "Enable/Disable Constraint"); prop = RNA_def_property(srna, "show_expanded", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", CONSTRAINT_EXPAND); - RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); RNA_def_property_ui_text(prop, "Expanded", "Constraint's panel is expanded in UI"); RNA_def_property_ui_icon(prop, ICON_TRIA_RIGHT, 1); diff --git a/source/blender/makesrna/intern/rna_define.c b/source/blender/makesrna/intern/rna_define.c index 03e58f8f78e..b8387263932 100644 --- a/source/blender/makesrna/intern/rna_define.c +++ b/source/blender/makesrna/intern/rna_define.c @@ -1293,6 +1293,16 @@ void RNA_def_property_clear_flag(PropertyRNA *prop, PropertyFlag flag) prop->flag &= ~flag; } +void RNA_def_property_override_flag(PropertyRNA *prop, PropertyOverrideFlag flag) +{ + prop->flag_override |= flag; +} + +void RNA_def_property_override_clear_flag(PropertyRNA *prop, PropertyOverrideFlag flag) +{ + prop->flag_override &= ~flag; +} + /** * Add the property-tags passed as \a tags to \a prop (if valid). * diff --git a/source/blender/makesrna/intern/rna_depsgraph.c b/source/blender/makesrna/intern/rna_depsgraph.c index 8bfa8b7d551..f904d4c06b1 100644 --- a/source/blender/makesrna/intern/rna_depsgraph.c +++ b/source/blender/makesrna/intern/rna_depsgraph.c @@ -44,6 +44,8 @@ #include "BLI_iterator.h" +#include "BKE_anim.h" + #include "DEG_depsgraph_build.h" #include "DEG_depsgraph_debug.h" #include "DEG_depsgraph_query.h" @@ -126,6 +128,14 @@ static int rna_DepsgraphObjectInstance_is_instance_get(PointerRNA *ptr) return (deg_iter->dupli_object_current != NULL); } +/* ******************** Sorted ***************** */ + +static int rna_Depsgraph_mode_get(PointerRNA *ptr) +{ + Depsgraph *depsgraph = ptr->data; + return DEG_get_mode(depsgraph); +} + /* ******************** Updates ***************** */ static PointerRNA rna_DepsgraphUpdate_id_get(PointerRNA *ptr) @@ -206,7 +216,6 @@ static void rna_Depsgraph_objects_begin(CollectionPropertyIterator *iter, Pointe data->flag = DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY | DEG_ITER_OBJECT_FLAG_VISIBLE | DEG_ITER_OBJECT_FLAG_LINKED_VIA_SET; - data->mode = DEG_ITER_OBJECT_MODE_RENDER; ((BLI_Iterator *)iter->internal.custom)->valid = true; DEG_iterator_objects_begin(iter->internal.custom, data); @@ -247,7 +256,6 @@ static void rna_Depsgraph_object_instances_begin(CollectionPropertyIterator *ite DEG_ITER_OBJECT_FLAG_LINKED_VIA_SET | DEG_ITER_OBJECT_FLAG_VISIBLE | DEG_ITER_OBJECT_FLAG_DUPLI; - data->mode = DEG_ITER_OBJECT_MODE_RENDER; ((BLI_Iterator *)iter->internal.custom)->valid = true; DEG_iterator_objects_begin(iter->internal.custom, data); @@ -464,9 +472,20 @@ static void rna_def_depsgraph(BlenderRNA *brna) PropertyRNA *parm; PropertyRNA *prop; + static EnumPropertyItem enum_depsgraph_mode_items[] = { + {DAG_EVAL_VIEWPORT, "VIEWPORT", 0, "Viewport", "Viewport non-rendered mode"}, + {DAG_EVAL_PREVIEW, "PREVIEW", 0, "Preview", "Viewport rendered draw mode"}, + {DAG_EVAL_RENDER, "RENDER", 0, "Render", "Render"}, + {0, NULL, 0, NULL, NULL} + }; + srna = RNA_def_struct(brna, "Depsgraph", NULL); RNA_def_struct_ui_text(srna, "Dependency Graph", ""); + prop = RNA_def_enum(srna, "mode", enum_depsgraph_mode_items, 0, "Mode", "Evaluation mode"); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_enum_funcs(prop, "rna_Depsgraph_mode_get", NULL, NULL); + /* Debug helpers. */ func = RNA_def_function(srna, "debug_relations_graphviz", "rna_Depsgraph_debug_relations_graphviz"); diff --git a/source/blender/makesrna/intern/rna_fcurve.c b/source/blender/makesrna/intern/rna_fcurve.c index 61fcc0e6654..0e382248542 100644 --- a/source/blender/makesrna/intern/rna_fcurve.c +++ b/source/blender/makesrna/intern/rna_fcurve.c @@ -1497,7 +1497,7 @@ static void rna_def_drivertarget(BlenderRNA *brna) prop = RNA_def_property(srna, "id", PROP_POINTER, PROP_NONE); RNA_def_property_struct_type(prop, "ID"); RNA_def_property_flag(prop, PROP_EDITABLE); - RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); RNA_def_property_editable_func(prop, "rna_DriverTarget_id_editable"); /* note: custom set function is ONLY to avoid rna setting a user for this. */ RNA_def_property_pointer_funcs(prop, NULL, "rna_DriverTarget_id_set", "rna_DriverTarget_id_typef", NULL); @@ -1582,7 +1582,7 @@ static void rna_def_drivervar(BlenderRNA *brna) prop = RNA_def_property(srna, "targets", PROP_COLLECTION, PROP_NONE); RNA_def_property_collection_sdna(prop, NULL, "targets", "num_targets"); RNA_def_property_struct_type(prop, "DriverTarget"); - RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); RNA_def_property_ui_text(prop, "Targets", "Sources of input data for evaluating this variable"); /* Name Validity Flags */ @@ -1659,7 +1659,7 @@ static void rna_def_channeldriver(BlenderRNA *brna) prop = RNA_def_property(srna, "variables", PROP_COLLECTION, PROP_NONE); RNA_def_property_collection_sdna(prop, NULL, "variables", NULL); RNA_def_property_struct_type(prop, "DriverVariable"); - RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); RNA_def_property_ui_text(prop, "Variables", "Properties acting as inputs for this driver"); rna_def_channeldriver_variables(brna, prop); @@ -1939,7 +1939,7 @@ static void rna_def_fcurve(BlenderRNA *brna) /* Pointers */ prop = RNA_def_property(srna, "driver", PROP_POINTER, PROP_NONE); - RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text(prop, "Driver", "Channel Driver (only set for Driver F-Curves)"); diff --git a/source/blender/makesrna/intern/rna_group.c b/source/blender/makesrna/intern/rna_group.c index 116c0bc4a26..f064e3eb630 100644 --- a/source/blender/makesrna/intern/rna_group.c +++ b/source/blender/makesrna/intern/rna_group.c @@ -227,6 +227,7 @@ void RNA_def_collections(BlenderRNA *brna) prop = RNA_def_property(srna, "objects", PROP_COLLECTION, PROP_NONE); RNA_def_property_struct_type(prop, "Object"); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); RNA_def_property_ui_text(prop, "Objects", "Objects that are directly in this collection"); RNA_def_property_collection_funcs(prop, "rna_Collection_objects_begin", "rna_iterator_listbase_next", @@ -257,21 +258,21 @@ void RNA_def_collections(BlenderRNA *brna) /* Flags */ prop = RNA_def_property(srna, "hide_select", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", COLLECTION_RESTRICT_SELECT); - RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); RNA_def_property_ui_icon(prop, ICON_RESTRICT_SELECT_OFF, 1); RNA_def_property_ui_text(prop, "Restrict Select", "Disable collection object selection in the 3D viewport"); RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_Collection_flag_update"); prop = RNA_def_property(srna, "hide_viewport", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", COLLECTION_RESTRICT_VIEW); - RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); RNA_def_property_ui_icon(prop, ICON_RESTRICT_VIEW_OFF, 1); RNA_def_property_ui_text(prop, "Restrict Viewport", "Hide collection objects in the 3D viewport"); RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_Collection_flag_update"); prop = RNA_def_property(srna, "hide_render", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", COLLECTION_RESTRICT_RENDER); - RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); RNA_def_property_ui_icon(prop, ICON_RESTRICT_RENDER_OFF, 1); RNA_def_property_ui_text(prop, "Restrict Render", "Hide collection objects in renders"); RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_Collection_flag_update"); diff --git a/source/blender/makesrna/intern/rna_image.c b/source/blender/makesrna/intern/rna_image.c index c554ab8e0fd..cd0824733b9 100644 --- a/source/blender/makesrna/intern/rna_image.c +++ b/source/blender/makesrna/intern/rna_image.c @@ -652,7 +652,7 @@ static void rna_def_image(BlenderRNA *brna) RNA_def_struct_ui_icon(srna, ICON_IMAGE_DATA); prop = RNA_def_property(srna, "filepath", PROP_STRING, PROP_FILEPATH); - RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); RNA_def_property_string_sdna(prop, NULL, "name"); RNA_def_property_ui_text(prop, "File Name", "Image/Movie file name"); RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Image_reload_update"); @@ -692,7 +692,7 @@ static void rna_def_image(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Packed Files", "Collection of packed images"); prop = RNA_def_property(srna, "field_order", PROP_ENUM, PROP_NONE); - RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag"); RNA_def_property_enum_items(prop, prop_field_order_items); RNA_def_property_ui_text(prop, "Field Order", "Order of video fields (select which lines are displayed first)"); @@ -700,7 +700,7 @@ static void rna_def_image(BlenderRNA *brna) /* booleans */ prop = RNA_def_property(srna, "use_fields", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); RNA_def_property_boolean_sdna(prop, NULL, "flag", IMA_FIELDS); RNA_def_property_ui_text(prop, "Fields", "Use fields of the image"); RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Image_fields_update"); @@ -708,43 +708,43 @@ static void rna_def_image(BlenderRNA *brna) prop = RNA_def_property(srna, "use_view_as_render", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); RNA_def_property_boolean_sdna(prop, NULL, "flag", IMA_VIEW_AS_RENDER); RNA_def_property_ui_text(prop, "View as Render", "Apply render part of display transformation when displaying this image on the screen"); RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, NULL); prop = RNA_def_property(srna, "use_alpha", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", IMA_IGNORE_ALPHA); RNA_def_property_ui_text(prop, "Use Alpha", "Use the alpha channel information from the image or make image fully opaque"); RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Image_colormanage_update"); prop = RNA_def_property(srna, "use_deinterlace", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); RNA_def_property_boolean_sdna(prop, NULL, "flag", IMA_DEINTERLACE); RNA_def_property_ui_text(prop, "Deinterlace", "Deinterlace movie file on load"); RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Image_reload_update"); prop = RNA_def_property(srna, "use_multiview", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); RNA_def_property_boolean_sdna(prop, NULL, "flag", IMA_USE_VIEWS); RNA_def_property_ui_text(prop, "Use Multi-View", "Use Multiple Views (when available)"); RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Image_views_format_update"); prop = RNA_def_property(srna, "is_stereo_3d", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); RNA_def_property_boolean_funcs(prop, "rna_Image_is_stereo_3d_get", NULL); RNA_def_property_ui_text(prop, "Stereo 3D", "Image has left and right views"); RNA_def_property_clear_flag(prop, PROP_EDITABLE); prop = RNA_def_property(srna, "is_multiview", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); RNA_def_property_boolean_funcs(prop, "rna_Image_is_multiview_get", NULL); RNA_def_property_ui_text(prop, "Multiple Views", "Image has more than one view"); RNA_def_property_clear_flag(prop, PROP_EDITABLE); prop = RNA_def_property(srna, "is_dirty", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); RNA_def_property_boolean_funcs(prop, "rna_Image_dirty_get", NULL); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text(prop, "Dirty", "Image has changed and is not saved"); @@ -787,7 +787,7 @@ static void rna_def_image(BlenderRNA *brna) RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); prop = RNA_def_property(srna, "display_aspect", PROP_FLOAT, PROP_XYZ); - RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); RNA_def_property_float_sdna(prop, NULL, "aspx"); RNA_def_property_array(prop, 2); RNA_def_property_range(prop, 0.1f, FLT_MAX); @@ -829,7 +829,7 @@ static void rna_def_image(BlenderRNA *brna) RNA_def_property_clear_flag(prop, PROP_EDITABLE); prop = RNA_def_float_vector(srna, "resolution", 2, NULL, 0, 0, "Resolution", "X/Y pixels per meter", 0, 0); - RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); RNA_def_property_float_funcs(prop, "rna_Image_resolution_get", "rna_Image_resolution_set", NULL); prop = RNA_def_property(srna, "frame_duration", PROP_INT, PROP_UNSIGNED); @@ -864,14 +864,14 @@ static void rna_def_image(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Color Space Settings", "Input color space settings"); prop = RNA_def_property(srna, "alpha_mode", PROP_ENUM, PROP_NONE); - RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); RNA_def_property_enum_items(prop, alpha_mode_items); RNA_def_property_ui_text(prop, "Alpha Mode", "Representation of alpha information in the RGBA pixels"); RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Image_colormanage_update"); /* multiview */ prop = RNA_def_property(srna, "views_format", PROP_ENUM, PROP_NONE); - RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); RNA_def_property_enum_sdna(prop, NULL, "views_format"); RNA_def_property_enum_items(prop, rna_enum_views_format_items); RNA_def_property_ui_text(prop, "Views Format", "Mode to load image views"); diff --git a/source/blender/makesrna/intern/rna_image_api.c b/source/blender/makesrna/intern/rna_image_api.c index bcac4b7e9a6..2070ea0a559 100644 --- a/source/blender/makesrna/intern/rna_image_api.c +++ b/source/blender/makesrna/intern/rna_image_api.c @@ -63,7 +63,7 @@ static void rna_ImagePackedFile_save(ImagePackedFile *imapf, Main *bmain, ReportList *reports) { - if (writePackedFile(reports, bmain->name, imapf->filepath, imapf->packedfile, 0) != RET_OK) { + if (writePackedFile(reports, BKE_main_blendfile_path(bmain), imapf->filepath, imapf->packedfile, 0) != RET_OK) { BKE_reportf(reports, RPT_ERROR, "Could not save packed file to disk as '%s'", imapf->filepath); } diff --git a/source/blender/makesrna/intern/rna_internal_types.h b/source/blender/makesrna/intern/rna_internal_types.h index 88efff30481..4536b970f91 100644 --- a/source/blender/makesrna/intern/rna_internal_types.h +++ b/source/blender/makesrna/intern/rna_internal_types.h @@ -206,6 +206,8 @@ struct PropertyRNA { const char *identifier; /* various options */ int flag; + /* various override options */ + int flag_override; /* Function parameters flags. */ short flag_parameter; /* Internal ("private") flags. */ diff --git a/source/blender/makesrna/intern/rna_layer.c b/source/blender/makesrna/intern/rna_layer.c index e7efdc27647..060b075cb29 100644 --- a/source/blender/makesrna/intern/rna_layer.c +++ b/source/blender/makesrna/intern/rna_layer.c @@ -49,6 +49,10 @@ #ifdef RNA_RUNTIME +#ifdef WITH_PYTHON +# include "BPY_extern.h" +#endif + #include "DNA_group_types.h" #include "DNA_object_types.h" @@ -163,22 +167,20 @@ static void rna_LayerObjects_selected_begin(CollectionPropertyIterator *iter, Po rna_iterator_listbase_begin(iter, &view_layer->object_bases, rna_ViewLayer_objects_selected_skip); } -static void rna_ViewLayer_update_tagged(ViewLayer *UNUSED(view_layer), bContext *C) +static void rna_ViewLayer_update_tagged(ID *id_ptr, ViewLayer *view_layer, Main *bmain) { - Depsgraph *depsgraph = CTX_data_depsgraph(C); - DEG_OBJECT_ITER_BEGIN( - depsgraph, ob, DEG_ITER_OBJECT_MODE_VIEWPORT, - DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY | - DEG_ITER_OBJECT_FLAG_LINKED_VIA_SET | - DEG_ITER_OBJECT_FLAG_LINKED_INDIRECTLY | - DEG_ITER_OBJECT_FLAG_VISIBLE | - DEG_ITER_OBJECT_FLAG_DUPLI) - { - /* Don't do anything, we just need to run the iterator to flush - * the base info to the objects. */ - UNUSED_VARS(ob); - } - DEG_OBJECT_ITER_END; +#ifdef WITH_PYTHON + /* Allow drivers to be evaluated */ + BPy_BEGIN_ALLOW_THREADS; +#endif + + Scene *scene = (Scene *)id_ptr; + Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer, true); + BKE_scene_graph_update_tagged(depsgraph, bmain); + +#ifdef WITH_PYTHON + BPy_END_ALLOW_THREADS; +#endif } static void rna_ObjectBase_select_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) @@ -351,7 +353,7 @@ void RNA_def_view_layer(BlenderRNA *brna) /* debug update routine */ func = RNA_def_function(srna, "update", "rna_ViewLayer_update_tagged"); - RNA_def_function_flag(func, FUNC_USE_CONTEXT); + RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN); RNA_def_function_ui_description(func, "Update data tagged to be updated from previous access to data or operators"); diff --git a/source/blender/makesrna/intern/rna_main_api.c b/source/blender/makesrna/intern/rna_main_api.c index 1aa6bdf9465..9b4d6ead53c 100644 --- a/source/blender/makesrna/intern/rna_main_api.c +++ b/source/blender/makesrna/intern/rna_main_api.c @@ -489,7 +489,7 @@ static Text *rna_Main_texts_load(Main *bmain, ReportList *reports, const char *f Text *txt; errno = 0; - txt = BKE_text_load_ex(bmain, filepath, bmain->name, is_internal); + txt = BKE_text_load_ex(bmain, filepath, BKE_main_blendfile_path(bmain), is_internal); if (!txt) BKE_reportf(reports, RPT_ERROR, "Cannot read '%s': %s", filepath, diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c index b8fdf4fd4b6..f0013eba1dc 100644 --- a/source/blender/makesrna/intern/rna_modifier.c +++ b/source/blender/makesrna/intern/rna_modifier.c @@ -1918,7 +1918,8 @@ static void rna_def_modifier_armature(BlenderRNA *brna) prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE); RNA_def_property_ui_text(prop, "Object", "Armature object to deform with"); RNA_def_property_pointer_funcs(prop, NULL, "rna_ArmatureModifier_object_set", NULL, "rna_Armature_object_poll"); - RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK | PROP_OVERRIDABLE_STATIC); + RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update"); prop = RNA_def_property(srna, "use_bone_envelopes", PROP_BOOLEAN, PROP_NONE); @@ -5069,13 +5070,14 @@ void RNA_def_modifier(BlenderRNA *brna) prop = RNA_def_property(srna, "show_viewport", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "mode", eModifierMode_Realtime); RNA_def_property_ui_text(prop, "Realtime", "Display modifier in viewport"); - RNA_def_property_flag(prop, PROP_LIB_EXCEPTION | PROP_OVERRIDABLE_STATIC); + RNA_def_property_flag(prop, PROP_LIB_EXCEPTION); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); RNA_def_property_update(prop, 0, "rna_Modifier_update"); RNA_def_property_ui_icon(prop, ICON_RESTRICT_VIEW_OFF, 0); prop = RNA_def_property(srna, "show_render", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "mode", eModifierMode_Render); - RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); RNA_def_property_ui_text(prop, "Render", "Use modifier during render"); RNA_def_property_ui_icon(prop, ICON_SCENE, 0); RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, NULL); @@ -5094,7 +5096,7 @@ void RNA_def_modifier(BlenderRNA *brna) prop = RNA_def_property(srna, "show_expanded", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "mode", eModifierMode_Expanded); - RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); RNA_def_property_ui_text(prop, "Expanded", "Set modifier expanded in the user interface"); RNA_def_property_ui_icon(prop, ICON_TRIA_RIGHT, 1); diff --git a/source/blender/makesrna/intern/rna_movieclip.c b/source/blender/makesrna/intern/rna_movieclip.c index c663119eb42..aa976775ad1 100644 --- a/source/blender/makesrna/intern/rna_movieclip.c +++ b/source/blender/makesrna/intern/rna_movieclip.c @@ -56,11 +56,11 @@ #include "DNA_screen_types.h" #include "DNA_space_types.h" -static void rna_MovieClip_reload_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) +static void rna_MovieClip_reload_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr) { MovieClip *clip = (MovieClip *)ptr->id.data; - BKE_movieclip_reload(clip); + BKE_movieclip_reload(bmain, clip); DEG_id_tag_update(&clip->id, 0); } diff --git a/source/blender/makesrna/intern/rna_nla.c b/source/blender/makesrna/intern/rna_nla.c index 1301762a4bc..38086a47c51 100644 --- a/source/blender/makesrna/intern/rna_nla.c +++ b/source/blender/makesrna/intern/rna_nla.c @@ -655,7 +655,7 @@ static void rna_def_nlastrip(BlenderRNA *brna) "NLA Strips that this strip acts as a container for (if it is of type Meta)"); /* Settings - Values necessary for evaluation */ - prop = RNA_def_property(srna, "influence", PROP_FLOAT, PROP_NONE); + prop = RNA_def_property(srna, "influence", PROP_FLOAT, PROP_FACTOR); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "Influence", "Amount the strip contributes to the current result"); /* XXX: Update temporarily disabled so that the property can be edited at all! diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index d2fb9d19acc..4f928a9a831 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -2307,31 +2307,13 @@ static void rna_NodeSocketStandard_vector_range(PointerRNA *ptr, float *min, flo *softmax = dval->max; } -static void rna_NodeSocket_value_update(Main *bmain, Scene *scene, PointerRNA *ptr) -{ - bNodeTree *ntree = (bNodeTree *)ptr->id.data; - bNodeSocket *sock = ptr->data; - - if (ntree->type == NTREE_SHADER) { - DEG_id_tag_update_ex(bmain, &ntree->id, DEG_TAG_SHADING_UPDATE); - WM_main_add_notifier(NC_MATERIAL | ND_SHADING, NULL); - - if (sock->type == SOCK_STRING) { - rna_NodeSocket_update(bmain, scene, ptr); - } - } - else { - rna_NodeSocket_update(bmain, scene, ptr); - } -} - /* using a context update function here, to avoid searching the node if possible */ static void rna_NodeSocketStandard_value_update(struct bContext *C, PointerRNA *ptr) { bNode *node; /* default update */ - rna_NodeSocket_value_update(CTX_data_main(C), CTX_data_scene(C), ptr); + rna_NodeSocket_update(CTX_data_main(C), CTX_data_scene(C), ptr); /* try to use node from context, faster */ node = CTX_data_pointer_get(C, "node").data; @@ -2967,7 +2949,7 @@ static void rna_ShaderNodeTexIES_mode_set(PointerRNA *ptr, int value) if (value == NODE_IES_EXTERNAL && text->name) { BLI_strncpy(nss->filepath, text->name, sizeof(nss->filepath)); - BLI_path_rel(nss->filepath, G.main->name); + BLI_path_rel(nss->filepath, BKE_main_blendfile_path_from_global()); } id_us_min(node->id); @@ -2992,7 +2974,7 @@ static void rna_ShaderNodeScript_mode_set(PointerRNA *ptr, int value) if (value == NODE_SCRIPT_EXTERNAL && text->name) { BLI_strncpy(nss->filepath, text->name, sizeof(nss->filepath)); - BLI_path_rel(nss->filepath, G.main->name); + BLI_path_rel(nss->filepath, BKE_main_blendfile_path_from_global()); } id_us_min(node->id); diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c index 10a31c9c070..9214f8530b8 100644 --- a/source/blender/makesrna/intern/rna_object.c +++ b/source/blender/makesrna/intern/rna_object.c @@ -300,7 +300,7 @@ static void rna_Object_active_shape_update(bContext *C, PointerRNA *ptr) break; case OB_CURVE: case OB_SURF: - ED_curve_editnurb_load(ob); + ED_curve_editnurb_load(bmain, ob); ED_curve_editnurb_make(ob); break; case OB_LATTICE: @@ -1566,19 +1566,23 @@ static void rna_def_material_slot(BlenderRNA *brna) RNA_def_struct_ui_text(srna, "Material Slot", "Material slot in an object"); RNA_def_struct_ui_icon(srna, ICON_MATERIAL_DATA); + /* WARNING! Order is crucial for override to work properly here... :/ + * 'link' must come before material pointer, since it defines where (in object or obdata) that one is set! */ + prop = RNA_def_property(srna, "link", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, link_items); + RNA_def_property_enum_funcs(prop, "rna_MaterialSlot_link_get", "rna_MaterialSlot_link_set", NULL); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); + RNA_def_property_ui_text(prop, "Link", "Link material to object or the object's data"); + RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_MaterialSlot_update"); + prop = RNA_def_property(srna, "material", PROP_POINTER, PROP_NONE); RNA_def_property_struct_type(prop, "Material"); RNA_def_property_flag(prop, PROP_EDITABLE); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); RNA_def_property_pointer_funcs(prop, "rna_MaterialSlot_material_get", "rna_MaterialSlot_material_set", NULL, NULL); RNA_def_property_ui_text(prop, "Material", "Material data-block used by this material slot"); RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_MaterialSlot_update"); - prop = RNA_def_property(srna, "link", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_items(prop, link_items); - RNA_def_property_enum_funcs(prop, "rna_MaterialSlot_link_get", "rna_MaterialSlot_link_set", NULL); - RNA_def_property_ui_text(prop, "Link", "Link material to object or the object's data"); - RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_MaterialSlot_update"); - prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE); RNA_def_property_string_funcs(prop, "rna_MaterialSlot_name_get", "rna_MaterialSlot_name_length", NULL); RNA_def_property_ui_text(prop, "Name", "Material slot name"); @@ -1895,6 +1899,7 @@ static void rna_def_object(BlenderRNA *brna) RNA_def_property_struct_type(prop, "ID"); RNA_def_property_pointer_funcs(prop, NULL, "rna_Object_data_set", "rna_Object_data_typef", NULL); RNA_def_property_flag(prop, PROP_EDITABLE | PROP_NEVER_UNLINK); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); RNA_def_property_ui_text(prop, "Data", "Object data"); RNA_def_property_update(prop, 0, "rna_Object_internal_update_data"); @@ -1928,7 +1933,8 @@ static void rna_def_object(BlenderRNA *brna) /* parent */ prop = RNA_def_property(srna, "parent", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_funcs(prop, NULL, "rna_Object_parent_set", NULL, NULL); - RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK | PROP_OVERRIDABLE_STATIC); + RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); RNA_def_property_ui_text(prop, "Parent", "Parent Object"); RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Object_dependency_update"); @@ -1981,6 +1987,7 @@ static void rna_def_object(BlenderRNA *brna) prop = RNA_def_property(srna, "material_slots", PROP_COLLECTION, PROP_NONE); RNA_def_property_collection_sdna(prop, NULL, "mat", "totcol"); RNA_def_property_struct_type(prop, "MaterialSlot"); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC | PROPOVERRIDE_NO_PROP_NAME); /* don't dereference pointer! */ RNA_def_property_collection_funcs(prop, NULL, NULL, NULL, "rna_iterator_array_get", NULL, NULL, NULL, NULL); RNA_def_property_ui_text(prop, "Material Slots", "Material slots in the object"); @@ -1997,6 +2004,7 @@ static void rna_def_object(BlenderRNA *brna) prop = RNA_def_property(srna, "active_material_index", PROP_INT, PROP_UNSIGNED); RNA_def_property_int_sdna(prop, NULL, "actcol"); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); RNA_def_property_int_funcs(prop, "rna_Object_active_material_index_get", "rna_Object_active_material_index_set", "rna_Object_active_material_index_range"); RNA_def_property_ui_text(prop, "Active Material Index", "Index of active material slot"); @@ -2006,7 +2014,7 @@ static void rna_def_object(BlenderRNA *brna) prop = RNA_def_property(srna, "location", PROP_FLOAT, PROP_TRANSLATION); RNA_def_property_float_sdna(prop, NULL, "loc"); RNA_def_property_editable_array_func(prop, "rna_Object_location_editable"); - RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); RNA_def_property_ui_text(prop, "Location", "Location of the object"); RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, RNA_TRANSLATION_PREC_DEFAULT); RNA_def_property_update(prop, NC_OBJECT | ND_TRANSFORM, "rna_Object_internal_update"); @@ -2014,7 +2022,7 @@ static void rna_def_object(BlenderRNA *brna) prop = RNA_def_property(srna, "rotation_quaternion", PROP_FLOAT, PROP_QUATERNION); RNA_def_property_float_sdna(prop, NULL, "quat"); RNA_def_property_editable_array_func(prop, "rna_Object_rotation_4d_editable"); - RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); RNA_def_property_float_array_default(prop, default_quat); RNA_def_property_ui_text(prop, "Quaternion Rotation", "Rotation in Quaternions"); RNA_def_property_update(prop, NC_OBJECT | ND_TRANSFORM, "rna_Object_internal_update"); @@ -2028,14 +2036,14 @@ static void rna_def_object(BlenderRNA *brna) "rna_Object_rotation_axis_angle_set", NULL); RNA_def_property_editable_array_func(prop, "rna_Object_rotation_4d_editable"); RNA_def_property_float_array_default(prop, default_axisAngle); - RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); RNA_def_property_ui_text(prop, "Axis-Angle Rotation", "Angle of Rotation for Axis-Angle rotation representation"); RNA_def_property_update(prop, NC_OBJECT | ND_TRANSFORM, "rna_Object_internal_update"); prop = RNA_def_property(srna, "rotation_euler", PROP_FLOAT, PROP_EULER); RNA_def_property_float_sdna(prop, NULL, "rot"); RNA_def_property_editable_array_func(prop, "rna_Object_rotation_euler_editable"); - RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); RNA_def_property_ui_text(prop, "Euler Rotation", "Rotation in Eulers"); RNA_def_property_update(prop, NC_OBJECT | ND_TRANSFORM, "rna_Object_internal_update"); @@ -2048,7 +2056,8 @@ static void rna_def_object(BlenderRNA *brna) prop = RNA_def_property(srna, "scale", PROP_FLOAT, PROP_XYZ); RNA_def_property_float_sdna(prop, NULL, "size"); - RNA_def_property_flag(prop, PROP_PROPORTIONAL | PROP_OVERRIDABLE_STATIC); + RNA_def_property_flag(prop, PROP_PROPORTIONAL); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); RNA_def_property_editable_array_func(prop, "rna_Object_scale_editable"); RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, 3); RNA_def_property_float_array_default(prop, default_scale); @@ -2176,13 +2185,13 @@ static void rna_def_object(BlenderRNA *brna) RNA_def_property_struct_type(prop, "Modifier"); RNA_def_property_ui_text(prop, "Modifiers", "Modifiers affecting the geometric data of the object"); RNA_def_property_override_funcs(prop, NULL, NULL, "rna_Object_modifiers_override_apply"); - RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC | PROP_OVERRIDABLE_STATIC_INSERTION); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC | PROPOVERRIDE_STATIC_INSERTION); rna_def_object_modifiers(brna, prop); /* constraints */ prop = RNA_def_property(srna, "constraints", PROP_COLLECTION, PROP_NONE); RNA_def_property_struct_type(prop, "Constraint"); - RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC | PROP_OVERRIDABLE_STATIC_INSERTION); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC | PROPOVERRIDE_STATIC_INSERTION); RNA_def_property_ui_text(prop, "Constraints", "Constraints affecting the transformation of the object"); RNA_def_property_override_funcs(prop, NULL, NULL, "rna_Object_constraints_override_apply"); /* RNA_def_property_collection_funcs(prop, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "constraints__add", "constraints__remove"); */ @@ -2460,7 +2469,7 @@ static void rna_def_object(BlenderRNA *brna) prop = RNA_def_property(srna, "pose", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "pose"); RNA_def_property_struct_type(prop, "Pose"); - RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); RNA_def_property_ui_text(prop, "Pose", "Current pose for armatures"); /* shape keys */ diff --git a/source/blender/makesrna/intern/rna_particle.c b/source/blender/makesrna/intern/rna_particle.c index 4f9ac94dec1..844e61966bb 100644 --- a/source/blender/makesrna/intern/rna_particle.c +++ b/source/blender/makesrna/intern/rna_particle.c @@ -642,7 +642,7 @@ static void rna_Particle_change_type(Main *bmain, Scene *UNUSED(scene), PointerR static void rna_Particle_change_physics_type(Main *bmain, Scene *scene, PointerRNA *ptr) { particle_recalc(bmain, scene, ptr, PSYS_RECALC_RESET | PSYS_RECALC_PHYS); - + ParticleSettings *part = (ParticleSettings *)ptr->data; if (part->phystype == PART_PHYS_BOIDS && part->boids == NULL) { @@ -655,7 +655,7 @@ static void rna_Particle_change_physics_type(Main *bmain, Scene *scene, PointerR BLI_addtail(&state->rules, boid_new_rule(eBoidRuleType_Separate)); BLI_addtail(&state->rules, boid_new_rule(eBoidRuleType_Flock)); - ((BoidRule*)state->rules.first)->flag |= BOIDRULE_CURRENT; + ((BoidRule *)state->rules.first)->flag |= BOIDRULE_CURRENT; state->flag |= BOIDSTATE_CURRENT; BLI_addtail(&part->boids->states, state); @@ -3295,13 +3295,13 @@ static void rna_def_particle_system(BlenderRNA *brna) prop = RNA_def_property(srna, "particles", PROP_COLLECTION, PROP_NONE); RNA_def_property_collection_sdna(prop, NULL, "particles", "totpart"); RNA_def_property_struct_type(prop, "Particle"); - RNA_def_property_flag(prop, PROP_NO_COMPARISON); + RNA_def_property_override_flag(prop, PROPOVERRIDE_NO_COMPARISON); RNA_def_property_ui_text(prop, "Particles", "Particles generated by the particle system"); prop = RNA_def_property(srna, "child_particles", PROP_COLLECTION, PROP_NONE); RNA_def_property_collection_sdna(prop, NULL, "child", "totchild"); RNA_def_property_struct_type(prop, "ChildParticle"); - RNA_def_property_flag(prop, PROP_NO_COMPARISON); + RNA_def_property_override_flag(prop, PROPOVERRIDE_NO_COMPARISON); RNA_def_property_ui_text(prop, "Child Particles", "Child particles generated by the particle system"); prop = RNA_def_property(srna, "seed", PROP_INT, PROP_UNSIGNED); diff --git a/source/blender/makesrna/intern/rna_pose.c b/source/blender/makesrna/intern/rna_pose.c index c25601a25fe..fb0f59a7977 100644 --- a/source/blender/makesrna/intern/rna_pose.c +++ b/source/blender/makesrna/intern/rna_pose.c @@ -106,6 +106,7 @@ const EnumPropertyItem rna_enum_color_sets_items[] = { #include "BKE_context.h" #include "BKE_constraint.h" +#include "BKE_global.h" #include "BKE_idprop.h" #include "DEG_depsgraph.h" @@ -291,7 +292,7 @@ static void rna_PoseChannel_name_set(PointerRNA *ptr, const char *value) BLI_strncpy_utf8(newname, value, sizeof(pchan->name)); BLI_strncpy(oldname, pchan->name, sizeof(pchan->name)); - ED_armature_bone_rename(ob->data, oldname, newname); + ED_armature_bone_rename(G.main, ob->data, oldname, newname); } static int rna_PoseChannel_has_ik_get(PointerRNA *ptr) @@ -857,7 +858,7 @@ static void rna_def_pose_channel(BlenderRNA *brna) /* Bone Constraints */ prop = RNA_def_property(srna, "constraints", PROP_COLLECTION, PROP_NONE); RNA_def_property_struct_type(prop, "Constraint"); - RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC | PROP_OVERRIDABLE_STATIC_INSERTION); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC | PROPOVERRIDE_STATIC_INSERTION); RNA_def_property_ui_text(prop, "Constraints", "Constraints that act on this PoseChannel"); RNA_def_property_override_funcs(prop, NULL, NULL, "rna_PoseChannel_constraints_override_apply"); @@ -896,7 +897,7 @@ static void rna_def_pose_channel(BlenderRNA *brna) /* Transformation settings */ prop = RNA_def_property(srna, "location", PROP_FLOAT, PROP_TRANSLATION); RNA_def_property_float_sdna(prop, NULL, "loc"); - RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); RNA_def_property_editable_array_func(prop, "rna_PoseChannel_location_editable"); RNA_def_property_ui_text(prop, "Location", ""); RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, RNA_TRANSLATION_PREC_DEFAULT); @@ -904,7 +905,8 @@ static void rna_def_pose_channel(BlenderRNA *brna) prop = RNA_def_property(srna, "scale", PROP_FLOAT, PROP_XYZ); RNA_def_property_float_sdna(prop, NULL, "size"); - RNA_def_property_flag(prop, PROP_PROPORTIONAL | PROP_OVERRIDABLE_STATIC); + RNA_def_property_flag(prop, PROP_PROPORTIONAL); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); RNA_def_property_editable_array_func(prop, "rna_PoseChannel_scale_editable"); RNA_def_property_float_array_default(prop, default_scale); RNA_def_property_ui_text(prop, "Scale", ""); @@ -912,7 +914,7 @@ static void rna_def_pose_channel(BlenderRNA *brna) prop = RNA_def_property(srna, "rotation_quaternion", PROP_FLOAT, PROP_QUATERNION); RNA_def_property_float_sdna(prop, NULL, "quat"); - RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); RNA_def_property_editable_array_func(prop, "rna_PoseChannel_rotation_4d_editable"); RNA_def_property_float_array_default(prop, default_quat); RNA_def_property_ui_text(prop, "Quaternion Rotation", "Rotation in Quaternions"); @@ -922,7 +924,7 @@ static void rna_def_pose_channel(BlenderRNA *brna) * having a single one is better for Keyframing and other property-management situations... */ prop = RNA_def_property(srna, "rotation_axis_angle", PROP_FLOAT, PROP_AXISANGLE); - RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); RNA_def_property_array(prop, 4); RNA_def_property_float_funcs(prop, "rna_PoseChannel_rotation_axis_angle_get", "rna_PoseChannel_rotation_axis_angle_set", NULL); @@ -933,7 +935,7 @@ static void rna_def_pose_channel(BlenderRNA *brna) prop = RNA_def_property(srna, "rotation_euler", PROP_FLOAT, PROP_EULER); RNA_def_property_float_sdna(prop, NULL, "eul"); - RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); RNA_def_property_editable_array_func(prop, "rna_PoseChannel_rotation_euler_editable"); RNA_def_property_ui_text(prop, "Euler Rotation", "Rotation in Eulers"); RNA_def_property_update(prop, NC_OBJECT | ND_POSE, "rna_Pose_update"); @@ -1460,7 +1462,7 @@ static void rna_def_pose(BlenderRNA *brna) prop = RNA_def_property(srna, "bones", PROP_COLLECTION, PROP_NONE); RNA_def_property_collection_sdna(prop, NULL, "chanbase", NULL); RNA_def_property_struct_type(prop, "PoseBone"); - RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); RNA_def_property_ui_text(prop, "Pose Bones", "Individual pose bones for the armature"); /* can be removed, only for fast lookup */ RNA_def_property_collection_funcs(prop, NULL, NULL, NULL, NULL, NULL, NULL, "rna_PoseBones_lookup_string", NULL); diff --git a/source/blender/makesrna/intern/rna_rna.c b/source/blender/makesrna/intern/rna_rna.c index f42bc1e1923..1a66174d8ce 100644 --- a/source/blender/makesrna/intern/rna_rna.c +++ b/source/blender/makesrna/intern/rna_rna.c @@ -595,7 +595,7 @@ static int rna_Property_overridable_get(PointerRNA *ptr) { PropertyRNA *prop = (PropertyRNA *)ptr->data; - return (prop->flag & PROP_OVERRIDABLE_STATIC) != 0; + return (prop->flag_override & PROPOVERRIDE_OVERRIDABLE_STATIC) != 0; } static int rna_Property_use_output_get(PointerRNA *ptr) @@ -1121,7 +1121,7 @@ static int rna_BlenderRNA_structs_lookup_string(PointerRNA *ptr, const char *key /* Ensures it makes sense to go inside the pointers to compare their content * (if they are IDs, or have different names or RNA type, then this would be meaningless). */ static bool rna_property_override_diff_propptr_validate_diffing( - PointerRNA *propptr_a, PointerRNA *propptr_b, + PointerRNA *propptr_a, PointerRNA *propptr_b, const bool no_prop_name, bool *r_is_id, bool *r_is_null, bool *r_is_type_diff, char **r_propname_a, char *propname_a_buff, size_t propname_a_buff_size, char **r_propname_b, char *propname_b_buff, size_t propname_b_buff_size) @@ -1129,7 +1129,7 @@ static bool rna_property_override_diff_propptr_validate_diffing( BLI_assert(propptr_a != NULL); bool is_valid_for_diffing = true; - const bool do_force_name = r_propname_a != NULL; + const bool do_force_name = !no_prop_name && r_propname_a != NULL; if (do_force_name) { BLI_assert(r_propname_a != NULL); @@ -1165,7 +1165,7 @@ static bool rna_property_override_diff_propptr_validate_diffing( /* We do a generic quick first comparison checking for "name" and/or "type" properties. * We assume that is any of those are false, then we are not handling the same data. * This helps a lot in static override case, especially to detect inserted items in collections. */ - if (is_valid_for_diffing || do_force_name) { + if (!no_prop_name && (is_valid_for_diffing || do_force_name)) { PropertyRNA *nameprop_a = RNA_struct_name_property(propptr_a->type); PropertyRNA *nameprop_b = (propptr_b != NULL) ? RNA_struct_name_property(propptr_b->type) : NULL; @@ -1222,7 +1222,8 @@ static bool rna_property_override_diff_propptr_validate_diffing( /* Used for both Pointer and Collection properties. */ static int rna_property_override_diff_propptr( - PointerRNA *propptr_a, PointerRNA *propptr_b, eRNACompareMode mode, const bool no_ownership, + PointerRNA *propptr_a, PointerRNA *propptr_b, + eRNACompareMode mode, const bool no_ownership, const bool no_prop_name, IDOverrideStatic *override, const char *rna_path, const int flags, bool *r_override_changed) { const bool do_create = override != NULL && (flags & RNA_OVERRIDE_COMPARE_CREATE) != 0 && rna_path != NULL; @@ -1232,7 +1233,7 @@ static int rna_property_override_diff_propptr( bool is_type_diff = false; /* If false, it means that the whole data itself is different, so no point in going inside of it at all! */ bool is_valid_for_diffing = rna_property_override_diff_propptr_validate_diffing( - propptr_a, propptr_b, &is_id, &is_null, &is_type_diff, + propptr_a, propptr_b, no_prop_name, &is_id, &is_null, &is_type_diff, NULL, NULL, 0, NULL, NULL, 0); if (is_id) { @@ -1538,8 +1539,9 @@ int rna_property_override_diff_default(PointerRNA *ptr_a, PointerRNA *ptr_b, PointerRNA propptr_a = RNA_property_pointer_get(ptr_a, prop_a); PointerRNA propptr_b = RNA_property_pointer_get(ptr_b, prop_b); const bool no_ownership = (RNA_property_flag(prop_a) & PROP_PTR_NO_OWNERSHIP) != 0; + const bool no_prop_name = (RNA_property_override_flag(prop_a) & PROPOVERRIDE_NO_PROP_NAME) != 0; return rna_property_override_diff_propptr( - &propptr_a, &propptr_b, mode, no_ownership, + &propptr_a, &propptr_b, mode, no_ownership, no_prop_name, override, rna_path, flags, r_override_changed); } break; @@ -1549,7 +1551,8 @@ int rna_property_override_diff_default(PointerRNA *ptr_a, PointerRNA *ptr_b, { /* Note: we assume we only insert in ptr_a (i.e. we can only get new items in ptr_a), * and that we never remove anything. */ - const bool use_insertion = (RNA_property_flag(prop_a) & PROP_OVERRIDABLE_STATIC_INSERTION) && do_create; + const bool use_insertion = (RNA_property_override_flag(prop_a) & PROPOVERRIDE_STATIC_INSERTION) && do_create; + const bool no_prop_name = (RNA_property_override_flag(prop_a) & PROPOVERRIDE_NO_PROP_NAME) != 0; bool equals = true; bool abort = false; bool is_first_insert = true; @@ -1590,16 +1593,18 @@ int rna_property_override_diff_default(PointerRNA *ptr_a, PointerRNA *ptr_b, /* If false, it means that the whole data itself is different, so no point in going inside of it at all! */ if (iter_b.valid) { is_valid_for_diffing = rna_property_override_diff_propptr_validate_diffing( - &iter_a.ptr, &iter_b.ptr, &is_id, &is_null, &is_type_diff, - &propname_a, buff_a, sizeof(buff_a), - &propname_b, buff_b, sizeof(buff_b)); + &iter_a.ptr, &iter_b.ptr, no_prop_name, + &is_id, &is_null, &is_type_diff, + &propname_a, buff_a, sizeof(buff_a), + &propname_b, buff_b, sizeof(buff_b)); } else { is_valid_for_diffing = false; if (is_valid_for_insertion) { /* We still need propname from 'a' item... */ rna_property_override_diff_propptr_validate_diffing( - &iter_a.ptr, NULL, &is_id, &is_null, &is_type_diff, + &iter_a.ptr, NULL, no_prop_name, + &is_id, &is_null, &is_type_diff, &propname_a, buff_a, sizeof(buff_a), &propname_b, buff_b, sizeof(buff_b)); } @@ -1615,7 +1620,7 @@ int rna_property_override_diff_default(PointerRNA *ptr_a, PointerRNA *ptr_b, printf("Checking %s, %s [%d] vs %s [%d]; diffing: %d; insert: %d (could be used: %d, do_create: %d)\n", rna_path, propname_a ? propname_a : "", idx_a, propname_b ? propname_b : "", idx_b, is_valid_for_diffing, is_valid_for_insertion, - (RNA_property_flag(prop_a) & PROP_OVERRIDABLE_STATIC_INSERTION) != 0, do_create); + (RNA_property_override_flag(prop_a) & PROPOVERRIDE_STATIC_INSERTION) != 0, do_create); } #endif @@ -1685,7 +1690,7 @@ int rna_property_override_diff_default(PointerRNA *ptr_a, PointerRNA *ptr_b, if (equals || do_create) { const bool no_ownership = (RNA_property_flag(prop_a) & PROP_PTR_NO_OWNERSHIP) != 0; const int eq = rna_property_override_diff_propptr( - &iter_a.ptr, &iter_b.ptr, mode, no_ownership, + &iter_a.ptr, &iter_b.ptr, mode, no_ownership, no_prop_name, override, extended_rna_path, flags, r_override_changed); equals = equals && eq; } diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index 1530c7fc483..8055c8fe4d6 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -5759,7 +5759,7 @@ static void rna_def_scene_display(BlenderRNA *brna) RNA_def_property_range(prop, 0.0f, 250.0f); prop = RNA_def_property(srna, "matcap_ssao_factor_edge", PROP_FLOAT, PROP_NONE); - RNA_def_property_float_default(prop, 1.0f); + RNA_def_property_float_default(prop, 1.0f); RNA_def_property_ui_text(prop, "Edge Strength", "Strength of the Edge effect"); RNA_def_property_range(prop, 0.0f, 250.0f); @@ -5837,337 +5837,337 @@ static void rna_def_scene_eevee(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Diffuse Bounces", "Number of time the light is reinjected inside light grids, " "0 disable indirect diffuse light"); RNA_def_property_range(prop, 0, INT_MAX); - RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); prop = RNA_def_property(srna, "gi_cubemap_resolution", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, eevee_shadow_size_items); RNA_def_property_enum_default(prop, 512); RNA_def_property_ui_text(prop, "Cubemap Size", "Size of every cubemaps"); - RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); prop = RNA_def_property(srna, "gi_visibility_resolution", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, eevee_gi_visibility_size_items); RNA_def_property_enum_default(prop, 32); RNA_def_property_ui_text(prop, "Irradiance Visibility Size", "Size of the shadow map applied to each irradiance sample"); - RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); /* Temporal Anti-Aliasing (super sampling) */ prop = RNA_def_property(srna, "taa_samples", PROP_INT, PROP_NONE); RNA_def_property_int_default(prop, 16); RNA_def_property_ui_text(prop, "Viewport Samples", "Number of samples, unlimited if 0"); RNA_def_property_range(prop, 0, INT_MAX); - RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); prop = RNA_def_property(srna, "taa_render_samples", PROP_INT, PROP_NONE); RNA_def_property_int_default(prop, 64); RNA_def_property_ui_text(prop, "Render Samples", "Number of samples per pixels for rendering"); RNA_def_property_range(prop, 1, INT_MAX); - RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); prop = RNA_def_property(srna, "use_taa_reprojection", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_TAA_REPROJECTION); RNA_def_property_boolean_default(prop, 1); RNA_def_property_ui_text(prop, "Viewport Denoising", "Denoise image using temporal reprojection " "(can leave some ghosting)"); - RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); /* Screen Space Subsurface Scattering */ prop = RNA_def_property(srna, "use_sss", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_SSS_ENABLED); RNA_def_property_boolean_default(prop, 0); RNA_def_property_ui_text(prop, "Subsurface Scattering", "Enable screen space subsurface scattering"); - RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); prop = RNA_def_property(srna, "sss_samples", PROP_INT, PROP_NONE); RNA_def_property_int_default(prop, 7); RNA_def_property_ui_text(prop, "Samples", "Number of samples to compute the scattering effect"); RNA_def_property_range(prop, 1, 32); - RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); prop = RNA_def_property(srna, "sss_jitter_threshold", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_default(prop, 0.3f); RNA_def_property_ui_text(prop, "Jitter Threshold", "Rotate samples that are below this threshold"); RNA_def_property_range(prop, 0.0f, 1.0f); - RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); prop = RNA_def_property(srna, "use_sss_separate_albedo", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_SSS_SEPARATE_ALBEDO); RNA_def_property_boolean_default(prop, 0); RNA_def_property_ui_text(prop, "Separate Albedo", "Avoid albedo being blured by the subsurface scattering " "but uses more video memory"); - RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); /* Screen Space Reflection */ prop = RNA_def_property(srna, "use_ssr", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_SSR_ENABLED); RNA_def_property_boolean_default(prop, 0); RNA_def_property_ui_text(prop, "Screen Space Reflections", "Enable screen space reflection"); - RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); prop = RNA_def_property(srna, "use_ssr_refraction", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_SSR_REFRACTION); RNA_def_property_boolean_default(prop, 0); RNA_def_property_ui_text(prop, "Screen Space Refractions", "Enable screen space Refractions"); - RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); prop = RNA_def_property(srna, "use_ssr_halfres", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_SSR_HALF_RESOLUTION); RNA_def_property_boolean_default(prop, 1); RNA_def_property_ui_text(prop, "Half Res Trace", "Raytrace at a lower resolution"); - RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); prop = RNA_def_property(srna, "ssr_quality", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_default(prop, 0.25f); RNA_def_property_ui_text(prop, "Trace Quality", "Quality of the screen space raytracing"); RNA_def_property_range(prop, 0.0f, 1.0f); - RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); prop = RNA_def_property(srna, "ssr_max_roughness", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_default(prop, 0.5f); RNA_def_property_ui_text(prop, "Max Roughness", "Do not raytrace reflections for roughness above this value"); RNA_def_property_range(prop, 0.0f, 1.0f); - RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); prop = RNA_def_property(srna, "ssr_thickness", PROP_FLOAT, PROP_DISTANCE); RNA_def_property_float_default(prop, 0.2f); RNA_def_property_ui_text(prop, "Thickness", "Pixel thickness used to detect intersection"); RNA_def_property_range(prop, 1e-6f, FLT_MAX); RNA_def_property_ui_range(prop, 0.001f, FLT_MAX, 5, 3); - RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); prop = RNA_def_property(srna, "ssr_border_fade", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_default(prop, 0.075f); RNA_def_property_ui_text(prop, "Edge Fading", "Screen percentage used to fade the SSR"); RNA_def_property_range(prop, 0.0f, 0.5f); - RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); prop = RNA_def_property(srna, "ssr_firefly_fac", PROP_FLOAT, PROP_NONE); RNA_def_property_float_default(prop, 10.0f); RNA_def_property_ui_text(prop, "Clamp", "Clamp pixel intensity to remove noise (0 to disabled)"); RNA_def_property_range(prop, 0.0f, FLT_MAX); - RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); /* Volumetrics */ prop = RNA_def_property(srna, "use_volumetric", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_VOLUMETRIC_ENABLED); RNA_def_property_boolean_default(prop, 0); RNA_def_property_ui_text(prop, "Volumetrics", "Enable scattering and absorbance of volumetric material"); - RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); prop = RNA_def_property(srna, "volumetric_start", PROP_FLOAT, PROP_DISTANCE); RNA_def_property_float_default(prop, 0.1f); RNA_def_property_ui_text(prop, "Start", "Start distance of the volumetric effect"); RNA_def_property_range(prop, 1e-6f, FLT_MAX); RNA_def_property_ui_range(prop, 0.001f, FLT_MAX, 10, 3); - RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); prop = RNA_def_property(srna, "volumetric_end", PROP_FLOAT, PROP_DISTANCE); RNA_def_property_float_default(prop, 100.0f); RNA_def_property_ui_text(prop, "End", "End distance of the volumetric effect"); RNA_def_property_range(prop, 1e-6f, FLT_MAX); RNA_def_property_ui_range(prop, 0.001f, FLT_MAX, 10, 3); - RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); prop = RNA_def_property(srna, "volumetric_tile_size", PROP_ENUM, PROP_NONE); RNA_def_property_enum_default(prop, 8); RNA_def_property_enum_items(prop, eevee_volumetric_tile_size_items); RNA_def_property_ui_text(prop, "Tile Size", "Control the quality of the volumetric effects " "(lower size increase vram usage and quality)"); - RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); prop = RNA_def_property(srna, "volumetric_samples", PROP_INT, PROP_NONE); RNA_def_property_int_default(prop, 64); RNA_def_property_ui_text(prop, "Samples", "Number of samples to compute volumetric effects"); RNA_def_property_range(prop, 1, 256); - RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); prop = RNA_def_property(srna, "volumetric_sample_distribution", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_default(prop, 0.8f); RNA_def_property_ui_text(prop, "Exponential Sampling", "Distribute more samples closer to the camera"); - RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); prop = RNA_def_property(srna, "use_volumetric_lights", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_VOLUMETRIC_LIGHTS); RNA_def_property_boolean_default(prop, 1); RNA_def_property_ui_text(prop, "Volumetric Lighting", "Enable scene lamps interactions with volumetrics"); - RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); prop = RNA_def_property(srna, "volumetric_light_clamp", PROP_FLOAT, PROP_NONE); RNA_def_property_float_default(prop, 0.0f); RNA_def_property_range(prop, 0.0f, FLT_MAX); RNA_def_property_ui_text(prop, "Clamp", "Maximum light contribution, reducing noise"); - RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); prop = RNA_def_property(srna, "use_volumetric_shadows", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_VOLUMETRIC_SHADOWS); RNA_def_property_boolean_default(prop, 0); RNA_def_property_ui_text(prop, "Volumetric Shadows", "Generate shadows from volumetric material (Very expensive)"); - RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); prop = RNA_def_property(srna, "volumetric_shadow_samples", PROP_INT, PROP_NONE); RNA_def_property_int_default(prop, 16); RNA_def_property_range(prop, 1, 128); RNA_def_property_ui_text(prop, "Volumetric Shadow Samples", "Number of samples to compute volumetric shadowing"); - RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); prop = RNA_def_property(srna, "use_volumetric_colored_transmittance", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_VOLUMETRIC_COLORED); RNA_def_property_boolean_default(prop, 1); RNA_def_property_ui_text(prop, "Colored Transmittance", "Enable wavelength dependent volumetric transmittance"); - RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); /* Ambient Occlusion */ prop = RNA_def_property(srna, "use_gtao", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_GTAO_ENABLED); RNA_def_property_boolean_default(prop, 0); RNA_def_property_ui_text(prop, "Ambient Occlusion", "Enable ambient occlusion to simulate medium scale indirect shadowing"); - RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); prop = RNA_def_property(srna, "use_gtao_bent_normals", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_GTAO_BENT_NORMALS); RNA_def_property_boolean_default(prop, 1); RNA_def_property_ui_text(prop, "Bent Normals", "Compute main non occluded direction to sample the environment"); - RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); prop = RNA_def_property(srna, "use_gtao_bounce", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_GTAO_BOUNCE); RNA_def_property_boolean_default(prop, 1); RNA_def_property_ui_text(prop, "Bounces Approximation", "An approximation to simulate light bounces " "giving less occlusion on brighter objects"); - RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); prop = RNA_def_property(srna, "gtao_factor", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_default(prop, 1.0f); RNA_def_property_ui_text(prop, "Factor", "Factor for ambient occlusion blending"); RNA_def_property_range(prop, 0.0f, FLT_MAX); RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.1f, 2); - RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); prop = RNA_def_property(srna, "gtao_quality", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_default(prop, 0.25f); RNA_def_property_ui_text(prop, "Trace Quality", "Quality of the horizon search"); RNA_def_property_range(prop, 0.0f, 1.0f); - RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); prop = RNA_def_property(srna, "gtao_distance", PROP_FLOAT, PROP_DISTANCE); RNA_def_property_float_default(prop, 0.2f); RNA_def_property_ui_text(prop, "Distance", "Distance of object that contribute to the ambient occlusion effect"); RNA_def_property_range(prop, 0.0f, 100000.0f); RNA_def_property_ui_range(prop, 0.0f, 100.0f, 1, 3); - RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); /* Depth of Field */ prop = RNA_def_property(srna, "use_dof", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_DOF_ENABLED); RNA_def_property_boolean_default(prop, 0); RNA_def_property_ui_text(prop, "Depth of Field", "Enable depth of field using the values from the active camera"); - RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); prop = RNA_def_property(srna, "bokeh_max_size", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_default(prop, 100.0f); RNA_def_property_ui_text(prop, "Max Size", "Max size of the bokeh shape for the depth of field (lower is faster)"); RNA_def_property_range(prop, 0.0f, 2000.0f); RNA_def_property_ui_range(prop, 2.0f, 200.0f, 1, 3); - RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); prop = RNA_def_property(srna, "bokeh_threshold", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_default(prop, 1.0f); RNA_def_property_ui_text(prop, "Sprite Threshold", "Brightness threshold for using sprite base depth of field"); RNA_def_property_range(prop, 0.0f, 100000.0f); RNA_def_property_ui_range(prop, 0.0f, 10.0f, 1, 3); - RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); /* Bloom */ prop = RNA_def_property(srna, "use_bloom", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_BLOOM_ENABLED); RNA_def_property_boolean_default(prop, 0); RNA_def_property_ui_text(prop, "Bloom", "High brighness pixels generate a glowing effect"); - RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); prop = RNA_def_property(srna, "bloom_threshold", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_default(prop, 0.8f); RNA_def_property_ui_text(prop, "Threshold", "Filters out pixels under this level of brightness"); RNA_def_property_range(prop, 0.0f, 100000.0f); RNA_def_property_ui_range(prop, 0.0f, 10.0f, 1, 3); - RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); prop = RNA_def_property(srna, "bloom_color", PROP_FLOAT, PROP_COLOR); RNA_def_property_float_array_default(prop, default_bloom_color); RNA_def_property_array(prop, 3); RNA_def_property_ui_text(prop, "Color", "Color applied to the bloom effect"); - RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); prop = RNA_def_property(srna, "bloom_knee", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_default(prop, 0.5f); RNA_def_property_ui_text(prop, "Knee", "Makes transition between under/over-threshold gradual"); RNA_def_property_range(prop, 0.0f, 1.0f); - RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); prop = RNA_def_property(srna, "bloom_radius", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_default(prop, 6.5f); RNA_def_property_ui_text(prop, "Radius", "Bloom spread distance"); RNA_def_property_range(prop, 0.0f, 100.0f); RNA_def_property_ui_range(prop, 0.0f, 10.0f, 1, 3); - RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); prop = RNA_def_property(srna, "bloom_clamp", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_default(prop, 1.0f); RNA_def_property_ui_text(prop, "Clamp", "Maximum intensity a bloom pixel can have"); RNA_def_property_range(prop, 0.0f, 1000.0f); RNA_def_property_ui_range(prop, 0.0f, 10.0f, 1, 3); - RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); prop = RNA_def_property(srna, "bloom_intensity", PROP_FLOAT, PROP_UNSIGNED); RNA_def_property_float_default(prop, 0.8f); RNA_def_property_ui_text(prop, "Intensity", "Blend factor"); RNA_def_property_range(prop, 0.0f, 10000.0f); RNA_def_property_ui_range(prop, 0.0f, 10.0f, 1, 3); - RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); /* Motion blur */ prop = RNA_def_property(srna, "use_motion_blur", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_MOTION_BLUR_ENABLED); RNA_def_property_boolean_default(prop, 0); RNA_def_property_ui_text(prop, "Motion Blur", "Enable motion blur effect (only in camera view)"); - RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); prop = RNA_def_property(srna, "motion_blur_samples", PROP_INT, PROP_UNSIGNED); RNA_def_property_int_default(prop, 8); RNA_def_property_ui_text(prop, "Samples", "Number of samples to take with motion blur"); RNA_def_property_range(prop, 1, 64); - RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); prop = RNA_def_property(srna, "motion_blur_shutter", PROP_FLOAT, PROP_UNSIGNED); RNA_def_property_float_default(prop, 1.0f); RNA_def_property_ui_text(prop, "Shutter", "Time taken in frames between shutter open and close"); RNA_def_property_ui_range(prop, 0.01f, 2.0f, 1, 2); - RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); /* Shadows */ prop = RNA_def_property(srna, "shadow_method", PROP_ENUM, PROP_NONE); RNA_def_property_enum_default(prop, SHADOW_ESM); RNA_def_property_enum_items(prop, eevee_shadow_method_items); RNA_def_property_ui_text(prop, "Method", "Technique use to compute the shadows"); - RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); prop = RNA_def_property(srna, "shadow_cube_size", PROP_ENUM, PROP_NONE); RNA_def_property_enum_default(prop, 512); RNA_def_property_enum_items(prop, eevee_shadow_size_items); RNA_def_property_ui_text(prop, "Cube Shadows Resolution", "Size of point and area lamps shadow maps"); - RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); prop = RNA_def_property(srna, "shadow_cascade_size", PROP_ENUM, PROP_NONE); RNA_def_property_enum_default(prop, 1024); RNA_def_property_enum_items(prop, eevee_shadow_size_items); RNA_def_property_ui_text(prop, "Directional Shadows Resolution", "Size of sun lamps shadow maps"); - RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); prop = RNA_def_property(srna, "use_shadow_high_bitdepth", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_SHADOW_HIGH_BITDEPTH); RNA_def_property_boolean_default(prop, 0); RNA_def_property_ui_text(prop, "High Bitdepth", "Use 32bit shadows"); - RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); } void RNA_def_scene(BlenderRNA *brna) diff --git a/source/blender/makesrna/intern/rna_scene_api.c b/source/blender/makesrna/intern/rna_scene_api.c index a307aff6e96..ba03472d8d5 100644 --- a/source/blender/makesrna/intern/rna_scene_api.c +++ b/source/blender/makesrna/intern/rna_scene_api.c @@ -158,13 +158,13 @@ static void rna_SceneRender_get_frame_path( } else { BKE_image_path_from_imformat( - name, rd->pic, bmain->name, (frame == INT_MIN) ? rd->cfra : frame, + name, rd->pic, BKE_main_blendfile_path(bmain), (frame == INT_MIN) ? rd->cfra : frame, &rd->im_format, (rd->scemode & R_EXTENSION) != 0, true, suffix); } } static void rna_Scene_ray_cast( - Scene *scene, ViewLayer *view_layer, + Scene *scene, Main *bmain, ViewLayer *view_layer, float origin[3], float direction[3], float ray_dist, int *r_success, float r_location[3], float r_normal[3], int *r_index, Object **r_ob, float r_obmat[16]) @@ -172,8 +172,7 @@ static void rna_Scene_ray_cast( normalize_v3(direction); Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer, true); - SnapObjectContext *sctx = ED_transform_snap_object_context_create( - scene, depsgraph, 0); + SnapObjectContext *sctx = ED_transform_snap_object_context_create(bmain, scene, depsgraph, 0); bool ret = ED_transform_snap_object_project_ray_ex( sctx, @@ -309,6 +308,7 @@ void RNA_api_scene(StructRNA *srna) /* Ray Cast */ func = RNA_def_function(srna, "ray_cast", "rna_Scene_ray_cast"); + RNA_def_function_flag(func, FUNC_USE_MAIN); RNA_def_function_ui_description(func, "Cast a ray onto in object space"); parm = RNA_def_pointer(func, "view_layer", "ViewLayer", "", "Scene Layer"); RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); diff --git a/source/blender/makesrna/intern/rna_sculpt_paint.c b/source/blender/makesrna/intern/rna_sculpt_paint.c index 12b080a9284..a26aceda3b9 100644 --- a/source/blender/makesrna/intern/rna_sculpt_paint.c +++ b/source/blender/makesrna/intern/rna_sculpt_paint.c @@ -162,6 +162,8 @@ static void rna_ParticleEdit_redo(bContext *C, PointerRNA *UNUSED(ptr)) if (!edit) return; + if (ob) DEG_id_tag_update(&ob->id, OB_RECALC_DATA); + BKE_particle_batch_cache_dirty(edit->psys, BKE_PARTICLE_BATCH_DIRTY_ALL); psys_free_path_cache(edit->psys, edit); DEG_id_tag_update(&CTX_data_scene(C)->id, DEG_TAG_COPY_ON_WRITE); diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index b36014370f6..3daf4ca6fe0 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -114,13 +114,6 @@ const EnumPropertyItem rna_enum_space_image_mode_items[] = { {0, NULL, 0, NULL, NULL} }; -/* Expanded into the Space.ui_type enum. */ -const EnumPropertyItem rna_enum_space_button_mode_items[] = { - {SB_SUBTYPE_DATA, "DATA_PROPERTIES", ICON_BUTS, "Data Properties", "Edit properties of active object and related data-blocks"}, - {SB_SUBTYPE_TOOL, "TOOL_PROPERTIES", ICON_PREFERENCES, "Tool Properties", "Edit tool settings"}, - {0, NULL, 0, NULL, NULL} -}; - #define V3D_S3D_CAMERA_LEFT {STEREO_LEFT_ID, "LEFT", ICON_RESTRICT_RENDER_OFF, "Left", ""}, #define V3D_S3D_CAMERA_RIGHT {STEREO_RIGHT_ID, "RIGHT", ICON_RESTRICT_RENDER_OFF, "Right", ""}, #define V3D_S3D_CAMERA_S3D {STEREO_3D_ID, "S3D", ICON_CAMERA_STEREO, "3D", ""}, @@ -194,46 +187,21 @@ const EnumPropertyItem rna_enum_shading_type_items[] = { }; const EnumPropertyItem rna_enum_viewport_lighting_items[] = { - {V3D_LIGHTING_FLAT, "FLAT", 0, "Flat Lighting", "Display using flat lighting"}, - {V3D_LIGHTING_STUDIO, "STUDIO", 0, "Studio Lighting", "Display using studio lighting"}, - /* {V3D_LIGHTING_SCENE, "SCENE", 0, "Scene Lighting", "Display using scene lighting"}, */ + {V3D_LIGHTING_FLAT, "FLAT", 0, "Flat", "Display using flat lighting"}, + {V3D_LIGHTING_STUDIO, "STUDIO", 0, "Studio", "Display using studio lighting"}, + {V3D_LIGHTING_MATCAP, "MATCAP", 0, "MatCap", "Display using matcap material and lighting"}, {0, NULL, 0, NULL, NULL} }; static const EnumPropertyItem rna_enum_studio_light_items[] = { - {0, "STUDIOLIGHT_00", 0, "", ""}, - {1, "STUDIOLIGHT_01", 0, "", ""}, - {2, "STUDIOLIGHT_02", 0, "", ""}, - {3, "STUDIOLIGHT_03", 0, "", ""}, - {4, "STUDIOLIGHT_04", 0, "", ""}, - {5, "STUDIOLIGHT_05", 0, "", ""}, - {6, "STUDIOLIGHT_06", 0, "", ""}, - {7, "STUDIOLIGHT_07", 0, "", ""}, - {8, "STUDIOLIGHT_08", 0, "", ""}, - {9, "STUDIOLIGHT_09", 0, "", ""}, - {10, "STUDIOLIGHT_10", 0, "", ""}, - {11, "STUDIOLIGHT_11", 0, "", ""}, - {12, "STUDIOLIGHT_12", 0, "", ""}, - {13, "STUDIOLIGHT_13", 0, "", ""}, - {14, "STUDIOLIGHT_14", 0, "", ""}, - {15, "STUDIOLIGHT_15", 0, "", ""}, - {16, "STUDIOLIGHT_16", 0, "", ""}, - {17, "STUDIOLIGHT_17", 0, "", ""}, - {18, "STUDIOLIGHT_18", 0, "", ""}, - {19, "STUDIOLIGHT_19", 0, "", ""}, - {20, "STUDIOLIGHT_20", 0, "", ""}, - {21, "STUDIOLIGHT_21", 0, "", ""}, - {22, "STUDIOLIGHT_22", 0, "", ""}, - {23, "STUDIOLIGHT_23", 0, "", ""}, - {24, "STUDIOLIGHT_24", 0, "", ""}, - {25, "STUDIOLIGHT_25", 0, "", ""}, - {26, "STUDIOLIGHT_26", 0, "", ""}, - {27, "STUDIOLIGHT_27", 0, "", ""}, - {28, "STUDIOLIGHT_28", 0, "", ""}, - {29, "STUDIOLIGHT_29", 0, "", ""}, + {0, "DEFAULT", 0, "Default", ""}, + {0, NULL, 0, NULL, NULL} +}; + +static const EnumPropertyItem rna_enum_matcap_items[] = { + {0, "DEFAULT", 0, "Default", ""}, {0, NULL, 0, NULL, NULL} }; -#define NUM_STUDIOLIGHT_ITEMS 30 const EnumPropertyItem rna_enum_clip_editor_mode_items[] = { {SC_MODE_TRACKING, "TRACKING", ICON_ANIM_DATA, "Tracking", "Show tracking and solving tools"}, @@ -243,6 +211,7 @@ const EnumPropertyItem rna_enum_clip_editor_mode_items[] = { /* Actually populated dynamically trough a function, but helps for context-less access (e.g. doc, i18n...). */ static const EnumPropertyItem buttons_context_items[] = { + {BCONTEXT_TOOL, "TOOL", ICON_PREFERENCES, "Tool", "Tool settings"}, {BCONTEXT_SCENE, "SCENE", ICON_SCENE_DATA, "Scene", "Scene"}, {BCONTEXT_RENDER, "RENDER", ICON_SCENE, "Render", "Render"}, {BCONTEXT_VIEW_LAYER, "VIEW_LAYER", ICON_RENDER_RESULT, "View Layer", "View layer"}, @@ -547,17 +516,6 @@ static void rna_3DViewShading_type_update(Main *bmain, Scene *UNUSED(scene), Poi ED_view3d_shade_update(bmain, v3d, sa); } -static void rna_SpaceView3D_matcap_enable(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) -{ - View3D *v3d = (View3D *)(ptr->data); - - if (v3d->matcap_icon < ICON_MATCAP_01 || - v3d->matcap_icon > ICON_MATCAP_24) - { - v3d->matcap_icon = ICON_MATCAP_01; - } -} - static PointerRNA rna_SpaceView3D_region_3d_get(PointerRNA *ptr) { View3D *v3d = (View3D *)(ptr->data); @@ -676,6 +634,9 @@ static void rna_3DViewShading_type_set(PointerRNA *ptr, int value) if (value != v3d->drawtype && value == OB_RENDER) { v3d->prev_drawtype = v3d->drawtype; } + if (value == OB_TEXTURE && v3d->shading.light == V3D_LIGHTING_MATCAP) { + v3d->shading.light = V3D_LIGHTING_STUDIO; + } v3d->drawtype = value; } @@ -713,17 +674,56 @@ static const EnumPropertyItem *rna_3DViewShading_type_itemf( static int rna_View3DShading_studio_light_orientation_get(PointerRNA *ptr) { View3D *v3d = (View3D *)ptr->data; - StudioLight *sl = BKE_studiolight_find(v3d->shading.studio_light, 0); - return sl->flag & (STUDIOLIGHT_ORIENTATION_WORLD | STUDIOLIGHT_ORIENTATION_CAMERA); + StudioLight *sl = BKE_studiolight_find(v3d->shading.studio_light, STUDIOLIGHT_FLAG_ALL); + return sl->flag & STUDIOLIGHT_FLAG_ORIENTATIONS; } static void rna_View3DShading_studio_light_orientation_set(PointerRNA *UNUSED(ptr), int UNUSED(value)) { } +/* shading.light */ +static int rna_View3DShading_light_get(PointerRNA *ptr) +{ + View3D *v3d = (View3D *)ptr->data; + return v3d->shading.light; +} + +static void rna_View3DShading_light_set(PointerRNA *ptr, int value) +{ + View3D *v3d = (View3D *)ptr->data; + v3d->shading.light = value; +} + +static const EnumPropertyItem *rna_View3DShading_light_itemf( + bContext *UNUSED(C), PointerRNA *ptr, + PropertyRNA *UNUSED(prop), bool *r_free) +{ + View3D *v3d = (View3D *)ptr->data; + + int totitem = 0; + EnumPropertyItem *item = NULL; + + if (v3d->drawtype == OB_SOLID || v3d->drawtype == OB_TEXTURE) { + RNA_enum_items_add_value(&item, &totitem, rna_enum_viewport_lighting_items, V3D_LIGHTING_FLAT); + RNA_enum_items_add_value(&item, &totitem, rna_enum_viewport_lighting_items, V3D_LIGHTING_STUDIO); + } + + if (v3d->drawtype == OB_SOLID) { + RNA_enum_items_add_value(&item, &totitem, rna_enum_viewport_lighting_items, V3D_LIGHTING_MATCAP); + } + RNA_enum_item_end(&item, &totitem); + *r_free = true; + return item; +} + +/* Studio light */ static int rna_View3DShading_studio_light_get(PointerRNA *ptr) { View3D *v3d = (View3D *)ptr->data; - const int flag = (v3d->drawtype == OB_MATERIAL) ? STUDIOLIGHT_ORIENTATION_WORLD : 0; + int flag = STUDIOLIGHT_ORIENTATIONS_SOLID; + if (v3d->drawtype == OB_MATERIAL) { + flag = STUDIOLIGHT_ORIENTATIONS_MATERIAL_MODE; + } StudioLight *sl = BKE_studiolight_find(v3d->shading.studio_light, flag); BLI_strncpy(v3d->shading.studio_light, sl->name, FILE_MAXFILE); return sl->index; @@ -732,7 +732,7 @@ static int rna_View3DShading_studio_light_get(PointerRNA *ptr) static void rna_View3DShading_studio_light_set(PointerRNA *ptr, int value) { View3D *v3d = (View3D *)ptr->data; - StudioLight *sl = BKE_studiolight_findindex(value); + StudioLight *sl = BKE_studiolight_findindex(value, STUDIOLIGHT_FLAG_ALL); BLI_strncpy(v3d->shading.studio_light, sl->name, FILE_MAXFILE); } @@ -742,15 +742,13 @@ static const EnumPropertyItem *rna_View3DShading_studio_light_itemf( { View3D *v3d = (View3D *)ptr->data; EnumPropertyItem *item = NULL; - EnumPropertyItem *lastitem; int totitem = 0; - bool show_studiolight; LISTBASE_FOREACH(StudioLight *, sl, BKE_studiolight_listbase()) { - show_studiolight = false; int icon_id = sl->irradiance_icon_id; + bool show_studiolight = false; - if ((sl->flag & STUDIOLIGHT_EXTERNAL_FILE) == 0) { + if ((sl->flag & STUDIOLIGHT_INTERNAL)) { /* always show internal lights */ show_studiolight = true; } @@ -758,8 +756,9 @@ static const EnumPropertyItem *rna_View3DShading_studio_light_itemf( switch (v3d->drawtype) { case OB_SOLID: case OB_TEXTURE: - show_studiolight = true; + show_studiolight = (sl->flag & (STUDIOLIGHT_ORIENTATION_WORLD | STUDIOLIGHT_ORIENTATION_CAMERA)) > 0; break; + case OB_MATERIAL: show_studiolight = (sl->flag & STUDIOLIGHT_ORIENTATION_WORLD) > 0; icon_id = sl->radiance_icon_id; @@ -767,12 +766,48 @@ static const EnumPropertyItem *rna_View3DShading_studio_light_itemf( } } - if (show_studiolight && totitem < NUM_STUDIOLIGHT_ITEMS) { - RNA_enum_items_add_value(&item, &totitem, rna_enum_studio_light_items, sl->index); - lastitem = &item[totitem - 1]; - lastitem->value = sl->index; - lastitem->icon = icon_id; - lastitem->name = sl->name; + if (show_studiolight) { + EnumPropertyItem tmp = {sl->index, sl->name, icon_id, sl->name, ""}; + RNA_enum_item_add(&item, &totitem, &tmp); + } + } + + RNA_enum_item_end(&item, &totitem); + *r_free = true; + return item; +} +/* Matcap studiolight */ +static int rna_View3DShading_matcap_get(PointerRNA *ptr) +{ + View3D *v3d = (View3D *)ptr->data; + StudioLight *sl = BKE_studiolight_find(v3d->shading.matcap, STUDIOLIGHT_ORIENTATION_VIEWNORMAL); + BLI_strncpy(v3d->shading.matcap, sl->name, FILE_MAXFILE); + return sl->index; +} + +static void rna_View3DShading_matcap_set(PointerRNA *ptr, int value) +{ + View3D *v3d = (View3D *)ptr->data; + StudioLight *sl = BKE_studiolight_findindex(value, STUDIOLIGHT_ORIENTATION_VIEWNORMAL); + BLI_strncpy(v3d->shading.matcap, sl->name, FILE_MAXFILE); +} + +static const EnumPropertyItem *rna_View3DShading_matcap_itemf( + bContext *UNUSED(C), PointerRNA *UNUSED(ptr), + PropertyRNA *UNUSED(prop), bool *r_free) +{ + EnumPropertyItem *item = NULL; + int totitem = 0; + + const int flags = (STUDIOLIGHT_EXTERNAL_FILE | STUDIOLIGHT_ORIENTATION_VIEWNORMAL); + + LISTBASE_FOREACH(StudioLight *, sl, BKE_studiolight_listbase()) { + int icon_id = sl->irradiance_icon_id; + bool show_studiolight = (sl->flag & flags) == flags; + + if (show_studiolight) { + EnumPropertyItem tmp = {sl->index, sl->name, icon_id, sl->name, ""}; + RNA_enum_item_add(&item, &totitem, &tmp); } } @@ -1141,6 +1176,10 @@ static const EnumPropertyItem *rna_SpaceProperties_context_itemf( EnumPropertyItem *item = NULL; int totitem = 0; + if (sbuts->pathflag & (1 << BCONTEXT_TOOL)) { + RNA_enum_items_add_value(&item, &totitem, buttons_context_items, BCONTEXT_TOOL); + } + if (sbuts->pathflag & (1 << BCONTEXT_RENDER)) { RNA_enum_items_add_value(&item, &totitem, buttons_context_items, BCONTEXT_RENDER); } @@ -2261,9 +2300,10 @@ static void rna_def_space_view3d_shading(BlenderRNA *brna) }; static const EnumPropertyItem studio_light_orientation_items[] = { - {0, "UNKNOWN", 0, "Unknown", "Studio light has no orientation"}, - {STUDIOLIGHT_ORIENTATION_CAMERA, "CAMERA", 0, "Camera", "Studio light is camera based"}, - {STUDIOLIGHT_ORIENTATION_WORLD, "WORLD", 0, "World", "Studio light is world based"}, + {0, "UNKNOWN", 0, "Unknown", "Studio light has no orientation"}, + {STUDIOLIGHT_ORIENTATION_CAMERA, "CAMERA", 0, "Camera", "Studio light is camera based"}, + {STUDIOLIGHT_ORIENTATION_WORLD, "WORLD", 0, "World", "Studio light is world based"}, + {STUDIOLIGHT_ORIENTATION_VIEWNORMAL, "VIEWNORMAL", 0, "Matcap", "Studio light is a matcap"}, {0, NULL, 0, NULL, NULL} }; @@ -2284,6 +2324,7 @@ static void rna_def_space_view3d_shading(BlenderRNA *brna) prop = RNA_def_property(srna, "light", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "shading.light"); RNA_def_property_enum_items(prop, rna_enum_viewport_lighting_items); + RNA_def_property_enum_funcs(prop, "rna_View3DShading_light_get", "rna_View3DShading_light_set", "rna_View3DShading_light_itemf"); RNA_def_property_ui_text(prop, "Lighting", "Lighting Method for Solid/Texture Viewport Shading"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); @@ -2300,6 +2341,37 @@ static void rna_def_space_view3d_shading(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Studiolight", "Studio lighting setup"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); + prop = RNA_def_property(srna, "matcap", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, rna_enum_matcap_items); + RNA_def_property_enum_default(prop, 0); + RNA_def_property_enum_funcs(prop, "rna_View3DShading_matcap_get", "rna_View3DShading_matcap_set", "rna_View3DShading_matcap_itemf"); + RNA_def_property_ui_text(prop, "Matcap", "Matcap material and lighting"); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); + + prop = RNA_def_property(srna, "show_cavity", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "shading.flag", V3D_SHADING_CAVITY); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + RNA_def_property_ui_text(prop, "Cavity", "Show Cavity"); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); + + prop = RNA_def_property(srna, "cavity_ridge_factor", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_float_sdna(prop, NULL, "shading.cavity_ridge_factor"); + RNA_def_property_float_default(prop, 1.0f); + RNA_def_property_ui_text(prop, "Ridge", "Factor for the ridges"); + RNA_def_property_range(prop, 0.0f, 250.0f); + RNA_def_property_ui_range(prop, 0.00f, 2.5f, 1, 3); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); + + prop = RNA_def_property(srna, "cavity_valley_factor", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_float_sdna(prop, NULL, "shading.cavity_valley_factor"); + RNA_def_property_float_default(prop, 1.0); + RNA_def_property_ui_text(prop, "Valley", "Factor for the valleys"); + RNA_def_property_range(prop, 0.0f, 250.0f); + RNA_def_property_ui_range(prop, 0.00f, 2.5f, 1, 3); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); + prop = RNA_def_property(srna, "studio_light_orientation", PROP_ENUM, PROP_NONE); RNA_define_verify_sdna(0); RNA_def_property_enum_sdna(prop, NULL, "shading.flag"); @@ -2347,7 +2419,6 @@ static void rna_def_space_view3d_shading(BlenderRNA *brna) RNA_def_property_float_default(prop, 0.5); RNA_def_property_ui_text(prop, "X-Ray Alpha", "Amount of alpha to use"); RNA_def_property_range(prop, 0.0f, 1.0f); - RNA_def_property_ui_range(prop, 0.04f, 1.0f, 1, 1); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); @@ -2498,6 +2569,14 @@ static void rna_def_space_view3d_overlay(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Bone Selection", "Show the Bone Selection Overlay"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); + prop = RNA_def_property(srna, "bone_selection_alpha", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_float_sdna(prop, NULL, "overlay.bone_selection_alpha"); + RNA_def_property_float_default(prop, 0.5f); + RNA_def_property_ui_text(prop, "Opacity", "Opacity to use for bone selection"); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); + prop = RNA_def_property(srna, "show_motion_paths", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_negative_sdna(prop, NULL, "overlay.flag", V3D_OVERLAY_HIDE_MOTION_PATHS); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); @@ -2516,6 +2595,14 @@ static void rna_def_space_view3d_overlay(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Wireframes", "Show face edges wires"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); + prop = RNA_def_property(srna, "wireframe_threshold", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_float_sdna(prop, NULL, "overlay.wireframe_threshold"); + RNA_def_property_float_default(prop, 0.5f); + RNA_def_property_ui_text(prop, "Wireframe Threshold", "Adjust the number of wires displayed (1 for all wires)"); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); + prop = RNA_def_property(srna, "show_paint_wire", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "overlay.paint_flag", V3D_OVERLAY_PAINT_WIRE); RNA_def_property_ui_text(prop, "Show Wire", "Use wireframe display in painting modes"); @@ -2588,34 +2675,6 @@ static void rna_def_space_view3d(BlenderRNA *brna) {0, NULL, 0, NULL, NULL} }; - static const EnumPropertyItem view3d_matcap_items[] = { - {ICON_MATCAP_01, "01", ICON_MATCAP_01, "", ""}, - {ICON_MATCAP_02, "02", ICON_MATCAP_02, "", ""}, - {ICON_MATCAP_03, "03", ICON_MATCAP_03, "", ""}, - {ICON_MATCAP_04, "04", ICON_MATCAP_04, "", ""}, - {ICON_MATCAP_05, "05", ICON_MATCAP_05, "", ""}, - {ICON_MATCAP_06, "06", ICON_MATCAP_06, "", ""}, - {ICON_MATCAP_07, "07", ICON_MATCAP_07, "", ""}, - {ICON_MATCAP_08, "08", ICON_MATCAP_08, "", ""}, - {ICON_MATCAP_09, "09", ICON_MATCAP_09, "", ""}, - {ICON_MATCAP_10, "10", ICON_MATCAP_10, "", ""}, - {ICON_MATCAP_11, "11", ICON_MATCAP_11, "", ""}, - {ICON_MATCAP_12, "12", ICON_MATCAP_12, "", ""}, - {ICON_MATCAP_13, "13", ICON_MATCAP_13, "", ""}, - {ICON_MATCAP_14, "14", ICON_MATCAP_14, "", ""}, - {ICON_MATCAP_15, "15", ICON_MATCAP_15, "", ""}, - {ICON_MATCAP_16, "16", ICON_MATCAP_16, "", ""}, - {ICON_MATCAP_17, "17", ICON_MATCAP_17, "", ""}, - {ICON_MATCAP_18, "18", ICON_MATCAP_18, "", ""}, - {ICON_MATCAP_19, "19", ICON_MATCAP_19, "", ""}, - {ICON_MATCAP_20, "20", ICON_MATCAP_20, "", ""}, - {ICON_MATCAP_21, "21", ICON_MATCAP_21, "", ""}, - {ICON_MATCAP_22, "22", ICON_MATCAP_22, "", ""}, - {ICON_MATCAP_23, "23", ICON_MATCAP_23, "", ""}, - {ICON_MATCAP_24, "24", ICON_MATCAP_24, "", ""}, - {0, NULL, 0, NULL, NULL} - }; - srna = RNA_def_struct(brna, "SpaceView3D", "Space"); RNA_def_struct_sdna(srna, "View3D"); RNA_def_struct_ui_text(srna, "3D View Space", "3D View space data"); @@ -2832,17 +2891,6 @@ static void rna_def_space_view3d(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Show 3D Marker Names", "Show names for reconstructed tracks objects"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); - prop = RNA_def_property(srna, "use_matcap", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag2", V3D_SOLID_MATCAP); - RNA_def_property_ui_text(prop, "Matcap", "Active Objects draw images mapped on normals, enhancing Solid Draw Mode"); - RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_SpaceView3D_matcap_enable"); - - prop = RNA_def_property(srna, "matcap_icon", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_sdna(prop, NULL, "matcap_icon"); - RNA_def_property_enum_items(prop, view3d_matcap_items); - RNA_def_property_ui_text(prop, "Matcap", "Image to use for Material Capture, active objects only"); - RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); - prop = RNA_def_property(srna, "fx_settings", PROP_POINTER, PROP_NONE); RNA_def_property_ui_text(prop, "FX Options", "Options used for real time compositing"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); @@ -3026,13 +3074,6 @@ static void rna_def_space_buttons(BlenderRNA *brna) RNA_def_struct_sdna(srna, "SpaceButs"); RNA_def_struct_ui_text(srna, "Properties Space", "Properties space data"); - /* Not exposed to the UI (access via space-type selector). */ - prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_sdna(prop, NULL, "space_subtype"); - RNA_def_property_enum_items(prop, rna_enum_space_button_mode_items); - RNA_def_property_ui_text(prop, "Mode", "Arrangement of the panels"); - RNA_def_property_update(prop, NC_SPACE | ND_SPACE_PROPERTIES, NULL); - prop = RNA_def_property(srna, "context", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "mainb"); RNA_def_property_enum_items(prop, buttons_context_items); diff --git a/source/blender/makesrna/intern/rna_ui.c b/source/blender/makesrna/intern/rna_ui.c index 354fa43367e..ce1f9efcf63 100644 --- a/source/blender/makesrna/intern/rna_ui.c +++ b/source/blender/makesrna/intern/rna_ui.c @@ -302,8 +302,8 @@ static StructRNA *rna_Panel_register( static StructRNA *rna_Panel_refine(PointerRNA *ptr) { - Panel *hdr = (Panel *)ptr->data; - return (hdr->type && hdr->type->ext.srna) ? hdr->type->ext.srna : &RNA_Panel; + Panel *menu = (Panel *)ptr->data; + return (menu->type && menu->type->ext.srna) ? menu->type->ext.srna : &RNA_Panel; } /* UIList */ @@ -696,7 +696,7 @@ static int menu_poll(const bContext *C, MenuType *pt) return visible; } -static void menu_draw(const bContext *C, Menu *hdr) +static void menu_draw(const bContext *C, Menu *menu) { extern FunctionRNA rna_Menu_draw_func; @@ -704,12 +704,12 @@ static void menu_draw(const bContext *C, Menu *hdr) ParameterList list; FunctionRNA *func; - RNA_pointer_create(&CTX_wm_screen(C)->id, hdr->type->ext.srna, hdr, &mtr); + RNA_pointer_create(&CTX_wm_screen(C)->id, menu->type->ext.srna, menu, &mtr); func = &rna_Menu_draw_func; /* RNA_struct_find_function(&mtr, "draw"); */ RNA_parameter_list_create(&list, &mtr, func); RNA_parameter_set_lookup(&list, "context", &C); - hdr->type->ext.call((bContext *)C, &mtr, func, &list); + menu->type->ext.call((bContext *)C, &mtr, func, &list); RNA_parameter_list_free(&list); } @@ -818,8 +818,8 @@ static StructRNA *rna_Menu_register( static StructRNA *rna_Menu_refine(PointerRNA *mtr) { - Menu *hdr = (Menu *)mtr->data; - return (hdr->type && hdr->type->ext.srna) ? hdr->type->ext.srna : &RNA_Menu; + Menu *menu = (Menu *)mtr->data; + return (menu->type && menu->type->ext.srna) ? menu->type->ext.srna : &RNA_Menu; } static void rna_Menu_bl_description_set(PointerRNA *ptr, const char *value) diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c index fc7a0ca6301..1cd3a8b83d7 100644 --- a/source/blender/makesrna/intern/rna_userdef.c +++ b/source/blender/makesrna/intern/rna_userdef.c @@ -41,6 +41,7 @@ #include "BKE_DerivedMesh.h" #include "BKE_sound.h" #include "BKE_addon.h" +#include "BKE_studiolight.h" #include "RNA_access.h" #include "RNA_define.h" @@ -77,6 +78,12 @@ const EnumPropertyItem rna_enum_navigation_mode_items[] = { {0, NULL, 0, NULL, NULL} }; +static const EnumPropertyItem rna_enum_studio_light_icons_id_items[] = { + {0, "DEFAULT", 0, "Default", ""}, + {0, NULL, 0, NULL, NULL} +}; + + #if defined(WITH_INTERNATIONAL) || !defined(RNA_RUNTIME) static const EnumPropertyItem rna_enum_language_default_items[] = { {0, "DEFAULT", 0, "Default (Default)", ""}, @@ -653,6 +660,117 @@ static void rna_ThemeUI_roundness_set(PointerRNA *ptr, float value) tui->roundness = value * 0.5f; } +/* Studio Light */ +static void rna_UserDef_studiolight_begin(CollectionPropertyIterator *iter, PointerRNA *UNUSED(ptr)) +{ + rna_iterator_listbase_begin(iter, BKE_studiolight_listbase(), NULL); +} + +static void rna_UserDef_studiolight_refresh(UserDef *UNUSED(userdef)) +{ + BKE_studiolight_refresh(); +} + +/* StudioLight.name */ +static void rna_UserDef_studiolight_name_get(PointerRNA *ptr, char *value) +{ + StudioLight *sl = (StudioLight *)ptr->data; + BLI_strncpy(value, sl->name, FILE_MAXFILE); +} + +static int rna_UserDef_studiolight_name_length(PointerRNA *ptr) +{ + StudioLight *sl = (StudioLight *)ptr->data; + return strlen(sl->name); +} + +/* StudioLight.path */ +static void rna_UserDef_studiolight_path_get(PointerRNA *ptr, char *value) +{ + StudioLight *sl = (StudioLight *)ptr->data; + BLI_strncpy(value, sl->path, FILE_MAX); +} + +static int rna_UserDef_studiolight_path_length(PointerRNA *ptr) +{ + StudioLight *sl = (StudioLight *)ptr->data; + return strlen(sl->path); +} + +/* StudioLight.index */ +static int rna_UserDef_studiolight_index_get(PointerRNA *ptr) +{ + StudioLight *sl = (StudioLight *)ptr->data; + return sl->index; +} + +/* StudioLight.icon_id */ +static int rna_UserDef_studiolight_icon_id_get(PointerRNA *ptr) +{ + StudioLight *sl = (StudioLight *)ptr->data; + if (sl->flag & (STUDIOLIGHT_ORIENTATION_VIEWNORMAL | STUDIOLIGHT_ORIENTATION_CAMERA)) { + return 1; + } + return 0; +} + +static const EnumPropertyItem *rna_UserDef_studiolight_icon_id_itemf( + bContext *UNUSED(C), PointerRNA *ptr, + PropertyRNA *UNUSED(prop), bool *r_free) +{ + EnumPropertyItem *item = NULL; + int totitem = 0; + StudioLight *sl = (StudioLight *)ptr->data; + + if ((sl->flag & (STUDIOLIGHT_ORIENTATION_VIEWNORMAL | STUDIOLIGHT_ORIENTATION_CAMERA)) == 0) + { + EnumPropertyItem tmp = {0, sl->name, sl->radiance_icon_id, sl->name, ""}; + RNA_enum_item_add(&item, &totitem, &tmp); + } + { + EnumPropertyItem tmp = {1, sl->name, sl->irradiance_icon_id, sl->name, ""}; + RNA_enum_item_add(&item, &totitem, &tmp); + } + RNA_enum_item_end(&item, &totitem); + *r_free = true; + return item; +} + +/* StudioLight.is_user_defined */ +static int rna_UserDef_studiolight_is_user_defined_get(PointerRNA *ptr) +{ + StudioLight *sl = (StudioLight *)ptr->data; + return (sl->flag & STUDIOLIGHT_USER_DEFINED) > 0; +} + +/* StudioLight.show_expanded */ +static int rna_UserDef_studiolight_show_expanded_get(PointerRNA *ptr) +{ + StudioLight *sl = (StudioLight *)ptr->data; + return (sl->flag & STUDIOLIGHT_UI_EXPANDED) > 0; +} + +static void rna_UserDef_studiolight_show_expanded_set(PointerRNA *ptr, const bool value) +{ + StudioLight *sl = (StudioLight *)ptr->data; + sl->flag ^= STUDIOLIGHT_UI_EXPANDED; + sl->flag |= value?STUDIOLIGHT_UI_EXPANDED: 0; +} + + +/* StudioLight.orientation */ + +static int rna_UserDef_studiolight_orientation_get(PointerRNA *ptr) +{ + StudioLight *sl = (StudioLight *)ptr->data; + return sl->flag & STUDIOLIGHT_FLAG_ORIENTATIONS; +} + +static void rna_UserDef_studiolight_orientation_set(PointerRNA *UNUSED(ptr), const int UNUSED(value)) +{ +} + + #else /* TODO(sergey): This technically belongs to blenlib, but we don't link @@ -3161,6 +3279,63 @@ static void rna_def_userdef_addon(BlenderRNA *brna) RNA_def_property_pointer_funcs(prop, "rna_Addon_preferences_get", NULL, NULL, NULL); } +static void rna_def_userdef_studiolight(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + static const EnumPropertyItem rna_enum_studio_light_orientation_items[] = { + {STUDIOLIGHT_ORIENTATION_CAMERA, "CAMERA", 0, "Camera", ""}, + {STUDIOLIGHT_ORIENTATION_WORLD, "WORLD", 0, "World", ""}, + {STUDIOLIGHT_ORIENTATION_VIEWNORMAL, "MATCAP", 0, "MatCap", ""}, + {0, NULL, 0, NULL, NULL} + }; + + RNA_define_verify_sdna(false); + srna = RNA_def_struct(brna, "StudioLight", NULL); + RNA_def_struct_clear_flag(srna, STRUCT_UNDO); + RNA_def_struct_ui_text(srna, "Studio Light", "Studio light"); + + prop = RNA_def_property(srna, "index", PROP_INT, PROP_NONE); + RNA_def_property_int_funcs(prop, "rna_UserDef_studiolight_index_get", NULL, NULL); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, "Index", ""); + + prop = RNA_def_property(srna, "is_user_defined", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_funcs(prop, "rna_UserDef_studiolight_is_user_defined_get", NULL); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, "User Defined", ""); + + prop = RNA_def_property(srna, "show_expanded", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_funcs(prop, "rna_UserDef_studiolight_show_expanded_get", "rna_UserDef_studiolight_show_expanded_set"); + RNA_def_property_ui_text(prop, "Show Expanded", ""); + + prop = RNA_def_property(srna, "orientation", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, rna_enum_studio_light_orientation_items); + RNA_def_property_enum_funcs(prop, "rna_UserDef_studiolight_orientation_get", "rna_UserDef_studiolight_orientation_set", NULL); + RNA_def_property_ui_text(prop, "Orientation", ""); + + prop = RNA_def_property(srna, "icon_id", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_funcs(prop, "rna_UserDef_studiolight_icon_id_get", NULL, "rna_UserDef_studiolight_icon_id_itemf"); + RNA_def_property_enum_items(prop, rna_enum_studio_light_icons_id_items); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, "Preview", "Preview of the studiolight"); + + prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE); + RNA_def_property_string_funcs(prop, "rna_UserDef_studiolight_name_get", "rna_UserDef_studiolight_name_length", NULL); + RNA_def_property_ui_text(prop, "Name", ""); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_struct_name_property(srna, prop); + + prop = RNA_def_property(srna, "path", PROP_STRING, PROP_DIRPATH); + RNA_def_property_string_funcs(prop, "rna_UserDef_studiolight_path_get", "rna_UserDef_studiolight_path_length", NULL); + RNA_def_property_ui_text(prop, "Path", ""); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + + RNA_define_verify_sdna(true); + +} + static void rna_def_userdef_pathcompare(BlenderRNA *brna) { StructRNA *srna; @@ -4665,6 +4840,7 @@ void RNA_def_userdef(BlenderRNA *brna) { StructRNA *srna; PropertyRNA *prop; + FunctionRNA *func; static const EnumPropertyItem user_pref_sections[] = { {USER_SECTION_INTERFACE, "INTERFACE", 0, "Interface", ""}, @@ -4672,6 +4848,7 @@ void RNA_def_userdef(BlenderRNA *brna) {USER_SECTION_INPUT, "INPUT", 0, "Input", ""}, {USER_SECTION_ADDONS, "ADDONS", 0, "Add-ons", ""}, {USER_SECTION_THEME, "THEMES", 0, "Themes", ""}, + {USER_SECTION_LIGHT, "LIGHTS", 0, "Lights", ""}, {USER_SECTION_FILE, "FILES", 0, "File", ""}, {USER_SECTION_SYSTEM, "SYSTEM", 0, "System", ""}, {0, NULL, 0, NULL, NULL} @@ -4757,6 +4934,17 @@ void RNA_def_userdef(BlenderRNA *brna) RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_flag(prop, PROP_THICK_WRAP); + prop = RNA_def_property(srna, "studio_lights", PROP_COLLECTION, PROP_NONE); + RNA_def_property_struct_type(prop, "StudioLight"); + RNA_def_property_collection_funcs(prop, "rna_UserDef_studiolight_begin", "rna_iterator_listbase_next", + "rna_iterator_listbase_end", "rna_iterator_listbase_get", + NULL, NULL, NULL, NULL); + + func = RNA_def_function(srna, "studio_lights_refresh", "rna_UserDef_studiolight_refresh"); + RNA_def_function_ui_description(func, "Refresh Studio Lights"); + + RNA_def_property_ui_text(prop, "Studio Lights", ""); + rna_def_userdef_view(brna); rna_def_userdef_edit(brna); rna_def_userdef_input(brna); @@ -4764,6 +4952,7 @@ void RNA_def_userdef(BlenderRNA *brna) rna_def_userdef_system(brna); rna_def_userdef_addon(brna); rna_def_userdef_addon_pref(brna); + rna_def_userdef_studiolight(brna); rna_def_userdef_pathcompare(brna); } diff --git a/source/blender/makesrna/intern/rna_wm.c b/source/blender/makesrna/intern/rna_wm.c index 0fa7f53da9b..3aa59ca564f 100644 --- a/source/blender/makesrna/intern/rna_wm.c +++ b/source/blender/makesrna/intern/rna_wm.c @@ -53,6 +53,7 @@ static const EnumPropertyItem event_keymouse_value_items[] = { {KM_RELEASE, "RELEASE", 0, "Release", ""}, {KM_CLICK, "CLICK", 0, "Click", ""}, {KM_DBL_CLICK, "DOUBLE_CLICK", 0, "Double Click", ""}, + {KM_CLICK_DRAG, "CLICK_DRAG", 0, "Click Drag", ""}, {0, NULL, 0, NULL, NULL} }; @@ -391,6 +392,7 @@ const EnumPropertyItem rna_enum_event_value_items[] = { {KM_RELEASE, "RELEASE", 0, "Release", ""}, {KM_CLICK, "CLICK", 0, "Click", ""}, {KM_DBL_CLICK, "DOUBLE_CLICK", 0, "Double Click", ""}, + {KM_CLICK_DRAG, "CLICK_DRAG", 0, "Click Drag", ""}, {EVT_GESTURE_N, "NORTH", 0, "North", ""}, {EVT_GESTURE_NE, "NORTH_EAST", 0, "North-East", ""}, {EVT_GESTURE_E, "EAST", 0, "East", ""}, diff --git a/source/blender/modifiers/intern/MOD_collision.c b/source/blender/modifiers/intern/MOD_collision.c index 036954a2774..71022f8a4ab 100644 --- a/source/blender/modifiers/intern/MOD_collision.c +++ b/source/blender/modifiers/intern/MOD_collision.c @@ -45,6 +45,7 @@ #include "BKE_global.h" #include "BKE_library.h" #include "BKE_mesh.h" +#include "BKE_mesh_runtime.h" #include "BKE_modifier.h" #include "BKE_pointcache.h" #include "BKE_scene.h" diff --git a/source/blender/modifiers/intern/MOD_laplaciandeform.c b/source/blender/modifiers/intern/MOD_laplaciandeform.c index ae4eb042444..63b4e950697 100644 --- a/source/blender/modifiers/intern/MOD_laplaciandeform.c +++ b/source/blender/modifiers/intern/MOD_laplaciandeform.c @@ -38,8 +38,8 @@ #include "BKE_deform.h" #include "BKE_editmesh.h" #include "BKE_library.h" -#include "BKE_mesh.h" #include "BKE_mesh_mapping.h" +#include "BKE_mesh_runtime.h" #include "BKE_particle.h" #include "DNA_mesh_types.h" diff --git a/source/blender/modifiers/intern/MOD_meshsequencecache.c b/source/blender/modifiers/intern/MOD_meshsequencecache.c index 595b91f25a2..abd84799457 100644 --- a/source/blender/modifiers/intern/MOD_meshsequencecache.c +++ b/source/blender/modifiers/intern/MOD_meshsequencecache.c @@ -31,13 +31,13 @@ #include "DNA_scene_types.h" #include "BKE_cachefile.h" -#include "BKE_DerivedMesh.h" #include "BKE_cdderivedmesh.h" #include "BKE_library.h" #include "BKE_library_query.h" #include "BKE_scene.h" #include "DEG_depsgraph_build.h" +#include "DEG_depsgraph_query.h" #include "MOD_modifiertypes.h" @@ -87,23 +87,23 @@ static bool isDisabled(ModifierData *md, int UNUSED(useRenderParams)) return (mcmd->cache_file == NULL) || (mcmd->object_path[0] == '\0'); } -static DerivedMesh *applyModifier( +static Mesh *applyModifier( ModifierData *md, const ModifierEvalContext *ctx, - DerivedMesh *dm) + Mesh *mesh) { #ifdef WITH_ALEMBIC MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *) md; /* Only used to check whether we are operating on org data or not... */ Mesh *me = (ctx->object->type == OB_MESH) ? ctx->object->data : NULL; - DerivedMesh *org_dm = dm; + Mesh *org_mesh = mesh; - Scene *scene = md->scene; - const float frame = BKE_scene_frame_get(scene); + Scene *scene = md->scene; /* for FPS macro */ + const float frame = DEG_get_ctime(ctx->depsgraph); const float time = BKE_cachefile_time_offset(mcmd->cache_file, frame, FPS); const char *err_str = NULL; - CacheFile *cache_file = mcmd->cache_file; + CacheFile *cache_file = (CacheFile *)DEG_get_original_id(&mcmd->cache_file->id); BKE_cachefile_ensure_handle(G.main, cache_file); @@ -114,39 +114,44 @@ static DerivedMesh *applyModifier( mcmd->object_path); if (!mcmd->reader) { modifier_setError(md, "Could not create Alembic reader for file %s", cache_file->filepath); - return dm; + return mesh; } } if (me != NULL) { - MVert *mvert = dm->getVertArray(dm); - MEdge *medge = dm->getEdgeArray(dm); - MPoly *mpoly = dm->getPolyArray(dm); + MVert *mvert = mesh->mvert; + MEdge *medge = mesh->medge; + MPoly *mpoly = mesh->mpoly; if ((me->mvert == mvert) || (me->medge == medge) || (me->mpoly == mpoly)) { /* We need to duplicate data here, otherwise we'll modify org mesh, see T51701. */ - dm = CDDM_copy(dm); + BKE_id_copy_ex(NULL, &mesh->id, (ID **)&mesh, + LIB_ID_CREATE_NO_MAIN | + LIB_ID_CREATE_NO_USER_REFCOUNT | + LIB_ID_CREATE_NO_DEG_TAG | + LIB_ID_COPY_NO_PREVIEW, + false); } } - DerivedMesh *result = ABC_read_mesh(mcmd->reader, - ctx->object, - dm, - time, - &err_str, - mcmd->read_flag); + Mesh *result = ABC_read_mesh(mcmd->reader, + ctx->object, + mesh, + time, + &err_str, + mcmd->read_flag); if (err_str) { modifier_setError(md, "%s", err_str); } - if (!ELEM(result, NULL, dm) && (dm != org_dm)) { - dm->release(dm); - dm = org_dm; + if (!ELEM(result, NULL, mesh) && (mesh != org_mesh)) { + BKE_id_free(NULL, mesh); + mesh = org_mesh; } - return result ? result : dm; + return result ? result : mesh; #else - return dm; + return mesh; UNUSED_VARS(ctx, md); #endif } @@ -190,14 +195,14 @@ ModifierTypeInfo modifierType_MeshSequenceCache = { /* deformMatrices_DM */ NULL, /* deformVertsEM_DM */ NULL, /* deformMatricesEM_DM*/NULL, - /* applyModifier_DM */ applyModifier, + /* applyModifier_DM */ NULL, /* applyModifierEM_DM */NULL, /* deformVerts */ NULL, /* deformMatrices */ NULL, /* deformVertsEM */ NULL, /* deformMatricesEM */ NULL, - /* applyModifier */ NULL, + /* applyModifier */ applyModifier, /* applyModifierEM */ NULL, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_particleinstance.c b/source/blender/modifiers/intern/MOD_particleinstance.c index eee7f0c5561..0aafcf33202 100644 --- a/source/blender/modifiers/intern/MOD_particleinstance.c +++ b/source/blender/modifiers/intern/MOD_particleinstance.c @@ -149,7 +149,7 @@ static bool particle_skip(ParticleInstanceModifierData *pimd, ParticleSystem *ps if (p >= psys->totpart) { ChildParticle *cpa = psys->child + (p - psys->totpart); - pa = psys->particles + (between? cpa->pa[0]: cpa->parent); + pa = psys->particles + (between ? cpa->pa[0] : cpa->parent); } else { pa = psys->particles + p; @@ -173,8 +173,8 @@ static bool particle_skip(ParticleInstanceModifierData *pimd, ParticleSystem *ps /* TODO make randomization optional? */ randp = (int)(psys_frand(psys, 3578 + p) * totpart) % totpart; - minp = (int)(totpart * pimd->particle_offset) % (totpart+1); - maxp = (int)(totpart * (pimd->particle_offset + pimd->particle_amount)) % (totpart+1); + minp = (int)(totpart * pimd->particle_offset) % (totpart + 1); + maxp = (int)(totpart * (pimd->particle_offset + pimd->particle_amount)) % (totpart + 1); if (maxp > minp) { return randp < minp || randp >= maxp; @@ -340,7 +340,7 @@ static Mesh *applyModifier( for (p = part_start, p_skip = 0; p < part_end; p++) { float prev_dir[3]; float frame[4]; /* frame orientation quaternion */ - float p_random = psys_frand(psys, 77091 + 283*p); + float p_random = psys_frand(psys, 77091 + 283 * p); /* skip particle? */ if (particle_skip(pimd, psys, p)) @@ -404,7 +404,7 @@ static Mesh *applyModifier( pa = psys->particles + p; else { ChildParticle *cpa = psys->child + (p - psys->totpart); - pa = psys->particles + (between? cpa->pa[0]: cpa->parent); + pa = psys->particles + (between ? cpa->pa[0] : cpa->parent); } psys_mat_hair_to_global(sim.ob, sim.psmd->mesh_final, sim.psys->part->from, pa, hairmat); copy_m3_m4(mat, hairmat); @@ -412,7 +412,7 @@ static Mesh *applyModifier( mat3_to_quat(frame, mat); if (pimd->rotation > 0.0f || pimd->random_rotation > 0.0f) { - float angle = 2.0f*M_PI * (pimd->rotation + pimd->random_rotation * (psys_frand(psys, 19957323 + p) - 0.5f)); + float angle = 2.0f * M_PI * (pimd->rotation + pimd->random_rotation * (psys_frand(psys, 19957323 + p) - 0.5f)); float eul[3] = { 0.0f, 0.0f, angle }; float rot[4]; diff --git a/source/blender/modifiers/intern/MOD_remesh.c b/source/blender/modifiers/intern/MOD_remesh.c index eff343a4906..df607c04164 100644 --- a/source/blender/modifiers/intern/MOD_remesh.c +++ b/source/blender/modifiers/intern/MOD_remesh.c @@ -38,6 +38,7 @@ #include "MOD_modifiertypes.h" #include "BKE_mesh.h" +#include "BKE_mesh_runtime.h" #include <assert.h> #include <stdlib.h> diff --git a/source/blender/modifiers/intern/MOD_surfacedeform.c b/source/blender/modifiers/intern/MOD_surfacedeform.c index c75f317e3bc..e964da0a8d1 100644 --- a/source/blender/modifiers/intern/MOD_surfacedeform.c +++ b/source/blender/modifiers/intern/MOD_surfacedeform.c @@ -9,7 +9,7 @@ #include "BLI_task.h" #include "BKE_bvhutils.h" -#include "BKE_mesh.h" +#include "BKE_mesh_runtime.h" #include "BKE_editmesh.h" #include "BKE_library.h" #include "BKE_library_query.h" diff --git a/source/blender/nodes/composite/node_composite_tree.c b/source/blender/nodes/composite/node_composite_tree.c index 87b60543853..2c123fdbf7e 100644 --- a/source/blender/nodes/composite/node_composite_tree.c +++ b/source/blender/nodes/composite/node_composite_tree.c @@ -59,7 +59,7 @@ static void composite_get_from_context(const bContext *C, bNodeTreeType *UNUSED(treetype), bNodeTree **r_ntree, ID **r_id, ID **r_from) { Scene *scene = CTX_data_scene(C); - + *r_from = NULL; *r_id = &scene->id; *r_ntree = scene->nodetree; @@ -83,7 +83,7 @@ static void foreach_nodeclass(Scene *UNUSED(scene), void *calldata, bNodeClassCa static void free_node_cache(bNodeTree *UNUSED(ntree), bNode *node) { bNodeSocket *sock; - + for (sock = node->outputs.first; sock; sock = sock->next) { if (sock->cache) { sock->cache = NULL; @@ -103,15 +103,15 @@ static void localize(bNodeTree *UNUSED(localtree), bNodeTree *ntree) { bNode *node; bNodeSocket *sock; - + for (node = ntree->nodes.first; node; node = node->next) { /* ensure new user input gets handled ok */ node->need_exec = 0; node->new_node->original = node; - + /* move over the compbufs */ /* right after ntreeCopyTree() oldsock pointers are valid */ - + if (ELEM(node->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER)) { if (node->id) { if (node->flag & NODE_DO_OUTPUT) @@ -120,7 +120,7 @@ static void localize(bNodeTree *UNUSED(localtree), bNodeTree *ntree) node->new_node->id = NULL; } } - + for (sock = node->outputs.first; sock; sock = sock->next) { sock->new_sock->cache = sock->cache; sock->cache = NULL; @@ -138,10 +138,10 @@ static void local_merge(bNodeTree *localtree, bNodeTree *ntree) { bNode *lnode; bNodeSocket *lsock; - + /* move over the compbufs and previews */ BKE_node_preview_merge_tree(ntree, localtree, true); - + for (lnode = localtree->nodes.first; lnode; lnode = lnode->next) { if (ntreeNodeExists(ntree, lnode->new_node)) { if (ELEM(lnode->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER)) { @@ -161,7 +161,7 @@ static void local_merge(bNodeTree *localtree, bNodeTree *ntree) lnode->new_node->storage = BKE_tracking_distortion_copy(lnode->storage); } } - + for (lsock = lnode->outputs.first; lsock; lsock = lsock->next) { if (ntreeOutputExists(lnode->new_node, lsock->new_sock)) { lsock->new_sock->cache = lsock->cache; @@ -176,9 +176,9 @@ static void local_merge(bNodeTree *localtree, bNodeTree *ntree) static void update(bNodeTree *ntree) { ntreeSetOutput(ntree); - + ntree_update_reroute_nodes(ntree); - + if (ntree->update & NTREE_UPDATE_NODES) { /* clean up preview cache, in case nodes have been removed */ BKE_node_preview_remove_unused(ntree); @@ -187,12 +187,12 @@ static void update(bNodeTree *ntree) static void composite_node_add_init(bNodeTree *UNUSED(bnodetree), bNode *bnode) { - /* Composite node will only show previews for input classes - * by default, other will be hidden + /* Composite node will only show previews for input classes + * by default, other will be hidden * but can be made visible with the show_preview option */ if (bnode->typeinfo->nclass != NODE_CLASS_INPUT) { bnode->flag &= ~NODE_PREVIEW; - } + } } bNodeTreeType *ntreeType_Composite; @@ -200,13 +200,13 @@ bNodeTreeType *ntreeType_Composite; void register_node_tree_type_cmp(void) { bNodeTreeType *tt = ntreeType_Composite = MEM_callocN(sizeof(bNodeTreeType), "compositor node tree type"); - + tt->type = NTREE_COMPOSIT; strcpy(tt->idname, "CompositorNodeTree"); strcpy(tt->ui_name, "Compositing"); tt->ui_icon = 0; /* defined in drawnode.c */ strcpy(tt->ui_description, "Compositing nodes"); - + tt->free_cache = free_cache; tt->free_node_cache = free_node_cache; tt->foreach_nodeclass = foreach_nodeclass; @@ -216,9 +216,9 @@ void register_node_tree_type_cmp(void) tt->update = update; tt->get_from_context = composite_get_from_context; tt->node_add_init = composite_node_add_init; - + tt->ext.srna = &RNA_CompositorNodeTree; - + ntreeTypeAdd(tt); } diff --git a/source/blender/nodes/composite/node_composite_util.c b/source/blender/nodes/composite/node_composite_util.c index faf3d994bf9..022794e8d42 100644 --- a/source/blender/nodes/composite/node_composite_util.c +++ b/source/blender/nodes/composite/node_composite_util.c @@ -52,7 +52,7 @@ void cmp_node_update_default(bNodeTree *UNUSED(ntree), bNode *node) void cmp_node_type_base(bNodeType *ntype, int type, const char *name, short nclass, short flag) { node_type_base(ntype, type, name, nclass, flag); - + ntype->poll = cmp_node_poll_default; ntype->updatefunc = cmp_node_update_default; ntype->insert_link = node_insert_link_default; diff --git a/source/blender/nodes/composite/nodes/node_composite_bokehblur.c b/source/blender/nodes/composite/nodes/node_composite_bokehblur.c index 503d1ad9a9d..acb5d100b0a 100644 --- a/source/blender/nodes/composite/nodes/node_composite_bokehblur.c +++ b/source/blender/nodes/composite/nodes/node_composite_bokehblur.c @@ -60,6 +60,6 @@ void register_node_type_cmp_bokehblur(void) cmp_node_type_base(&ntype, CMP_NODE_BOKEHBLUR, "Bokeh Blur", NODE_CLASS_OP_FILTER, 0); node_type_socket_templates(&ntype, cmp_node_bokehblur_in, cmp_node_bokehblur_out); node_type_init(&ntype, node_composit_init_bokehblur); - + nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/composite/nodes/node_composite_bokehimage.c b/source/blender/nodes/composite/nodes/node_composite_bokehimage.c index 1473212f8e1..04cdd3367e6 100644 --- a/source/blender/nodes/composite/nodes/node_composite_bokehimage.c +++ b/source/blender/nodes/composite/nodes/node_composite_bokehimage.c @@ -54,7 +54,7 @@ static void node_composit_init_bokehimage(bNodeTree *UNUSED(ntree), bNode *node) void register_node_type_cmp_bokehimage(void) { static bNodeType ntype; - + cmp_node_type_base(&ntype, CMP_NODE_BOKEHIMAGE, "Bokeh Image", NODE_CLASS_INPUT, NODE_PREVIEW); node_type_socket_templates(&ntype, NULL, cmp_node_bokehimage_out); node_type_init(&ntype, node_composit_init_bokehimage); diff --git a/source/blender/nodes/composite/nodes/node_composite_boxmask.c b/source/blender/nodes/composite/nodes/node_composite_boxmask.c index 2a47c58c33f..611cf323873 100644 --- a/source/blender/nodes/composite/nodes/node_composite_boxmask.c +++ b/source/blender/nodes/composite/nodes/node_composite_boxmask.c @@ -32,7 +32,7 @@ #include "../node_composite_util.h" -/* **************** SCALAR MATH ******************** */ +/* **************** SCALAR MATH ******************** */ static bNodeSocketTemplate cmp_node_boxmask_in[] = { { SOCK_FLOAT, 1, N_("Mask"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, { SOCK_FLOAT, 1, N_("Value"), 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, diff --git a/source/blender/nodes/composite/nodes/node_composite_brightness.c b/source/blender/nodes/composite/nodes/node_composite_brightness.c index 845e9e20c81..d44b8cd63cb 100644 --- a/source/blender/nodes/composite/nodes/node_composite_brightness.c +++ b/source/blender/nodes/composite/nodes/node_composite_brightness.c @@ -54,7 +54,7 @@ static void node_composit_init_brightcontrast(bNodeTree *UNUSED(ntree), bNode *n void register_node_type_cmp_brightcontrast(void) { static bNodeType ntype; - + cmp_node_type_base(&ntype, CMP_NODE_BRIGHTCONTRAST, "Bright/Contrast", NODE_CLASS_OP_COLOR, 0); node_type_socket_templates(&ntype, cmp_node_brightcontrast_in, cmp_node_brightcontrast_out); node_type_init(&ntype, node_composit_init_brightcontrast); diff --git a/source/blender/nodes/composite/nodes/node_composite_colorSpill.c b/source/blender/nodes/composite/nodes/node_composite_colorSpill.c index a6a7f3aa5a3..641026c3aad 100644 --- a/source/blender/nodes/composite/nodes/node_composite_colorSpill.c +++ b/source/blender/nodes/composite/nodes/node_composite_colorSpill.c @@ -57,7 +57,7 @@ static void node_composit_init_color_spill(bNodeTree *UNUSED(ntree), bNode *node void register_node_type_cmp_color_spill(void) { static bNodeType ntype; - + cmp_node_type_base(&ntype, CMP_NODE_COLOR_SPILL, "Color Spill", NODE_CLASS_MATTE, 0); node_type_socket_templates(&ntype, cmp_node_color_spill_in, cmp_node_color_spill_out); node_type_init(&ntype, node_composit_init_color_spill); diff --git a/source/blender/nodes/composite/nodes/node_composite_colorbalance.c b/source/blender/nodes/composite/nodes/node_composite_colorbalance.c index 8370ace8cb3..f9ad8c0ea5f 100644 --- a/source/blender/nodes/composite/nodes/node_composite_colorbalance.c +++ b/source/blender/nodes/composite/nodes/node_composite_colorbalance.c @@ -52,7 +52,7 @@ void ntreeCompositColorBalanceSyncFromLGG(bNodeTree *UNUSED(ntree), bNode *node) { NodeColorBalance *n = node->storage; int c; - + for (c = 0; c < 3; ++c) { n->slope[c] = (2.0f - n->lift[c]) * n->gain[c]; n->offset[c] = (n->lift[c] - 1.0f) * n->gain[c]; @@ -64,7 +64,7 @@ void ntreeCompositColorBalanceSyncFromCDL(bNodeTree *UNUSED(ntree), bNode *node) { NodeColorBalance *n = node->storage; int c; - + for (c = 0; c < 3; ++c) { float d = n->slope[c] + n->offset[c]; n->lift[c] = (d != 0.0f ? n->slope[c] + 2.0f * n->offset[c] / d : 0.0f); diff --git a/source/blender/nodes/composite/nodes/node_composite_common.c b/source/blender/nodes/composite/nodes/node_composite_common.c index 57ec0f1c7ad..de97a5beac3 100644 --- a/source/blender/nodes/composite/nodes/node_composite_common.c +++ b/source/blender/nodes/composite/nodes/node_composite_common.c @@ -43,7 +43,7 @@ void register_node_type_cmp_group(void) { static bNodeType ntype; - + /* NB: cannot use sh_node_type_base for node group, because it would map the node type * to the shared NODE_GROUP integer type id. */ @@ -56,7 +56,7 @@ void register_node_type_cmp_group(void) ntype.ext.srna = RNA_struct_find("CompositorNodeGroup"); BLI_assert(ntype.ext.srna != NULL); RNA_struct_blender_type_set(ntype.ext.srna, &ntype); - + node_type_socket_templates(&ntype, NULL, NULL); node_type_size(&ntype, 140, 60, 400); node_type_label(&ntype, node_group_label); diff --git a/source/blender/nodes/composite/nodes/node_composite_dilate.c b/source/blender/nodes/composite/nodes/node_composite_dilate.c index 4efee112438..72d12e0a643 100644 --- a/source/blender/nodes/composite/nodes/node_composite_dilate.c +++ b/source/blender/nodes/composite/nodes/node_composite_dilate.c @@ -54,7 +54,7 @@ static void node_composit_init_dilateerode(bNodeTree *UNUSED(ntree), bNode *node void register_node_type_cmp_dilateerode(void) { static bNodeType ntype; - + cmp_node_type_base(&ntype, CMP_NODE_DILATEERODE, "Dilate/Erode", NODE_CLASS_OP_FILTER, 0); node_type_socket_templates(&ntype, cmp_node_dilateerode_in, cmp_node_dilateerode_out); node_type_init(&ntype, node_composit_init_dilateerode); diff --git a/source/blender/nodes/composite/nodes/node_composite_ellipsemask.c b/source/blender/nodes/composite/nodes/node_composite_ellipsemask.c index df8ae4931e5..b72a0fb82ae 100644 --- a/source/blender/nodes/composite/nodes/node_composite_ellipsemask.c +++ b/source/blender/nodes/composite/nodes/node_composite_ellipsemask.c @@ -32,7 +32,7 @@ #include "../node_composite_util.h" -/* **************** SCALAR MATH ******************** */ +/* **************** SCALAR MATH ******************** */ static bNodeSocketTemplate cmp_node_ellipsemask_in[] = { { SOCK_FLOAT, 1, N_("Mask"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, { SOCK_FLOAT, 1, N_("Value"), 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, diff --git a/source/blender/nodes/composite/nodes/node_composite_gamma.c b/source/blender/nodes/composite/nodes/node_composite_gamma.c index 81764c97aac..30d399d3f73 100644 --- a/source/blender/nodes/composite/nodes/node_composite_gamma.c +++ b/source/blender/nodes/composite/nodes/node_composite_gamma.c @@ -47,9 +47,9 @@ static bNodeSocketTemplate cmp_node_gamma_out[] = { void register_node_type_cmp_gamma(void) { static bNodeType ntype; - + cmp_node_type_base(&ntype, CMP_NODE_GAMMA, "Gamma", NODE_CLASS_OP_COLOR, 0); node_type_socket_templates(&ntype, cmp_node_gamma_in, cmp_node_gamma_out); - + nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/composite/nodes/node_composite_huecorrect.c b/source/blender/nodes/composite/nodes/node_composite_huecorrect.c index 4ee1bccd726..70c73bcb46a 100644 --- a/source/blender/nodes/composite/nodes/node_composite_huecorrect.c +++ b/source/blender/nodes/composite/nodes/node_composite_huecorrect.c @@ -47,14 +47,14 @@ static void node_composit_init_huecorrect(bNodeTree *UNUSED(ntree), bNode *node) { CurveMapping *cumapping = node->storage = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f); int c; - + cumapping->preset = CURVE_PRESET_MID9; - + for (c = 0; c < 3; c++) { CurveMap *cuma = &cumapping->cm[c]; curvemap_reset(cuma, &cumapping->clipr, cumapping->preset, CURVEMAP_SLOPE_POSITIVE); } - + /* default to showing Saturation */ cumapping->cur = 1; } diff --git a/source/blender/nodes/composite/nodes/node_composite_image.c b/source/blender/nodes/composite/nodes/node_composite_image.c index 6a5458d6045..124b2fa72b9 100644 --- a/source/blender/nodes/composite/nodes/node_composite_image.c +++ b/source/blender/nodes/composite/nodes/node_composite_image.c @@ -150,10 +150,10 @@ static void cmp_node_image_create_outputs(bNodeTree *ntree, bNode *node, LinkNod /* make sure ima->type is correct */ ibuf = BKE_image_acquire_ibuf(ima, &load_iuser, NULL); - + if (ima->rr) { RenderLayer *rl = BLI_findlink(&ima->rr->layers, iuser->layer); - + if (rl) { RenderPass *rpass; for (rpass = rl->passes.first; rpass; rpass = rpass->next) { @@ -251,7 +251,7 @@ static void cmp_node_image_verify_outputs(bNodeTree *ntree, bNode *node, bool rl bNodeSocket *sock, *sock_next; LinkNodePair available_sockets = {NULL, NULL}; int sock_index; - + /* XXX make callback */ if (rlayer) cmp_node_rlayer_create_outputs(ntree, node, &available_sockets); @@ -307,7 +307,7 @@ static void node_composit_init_image(bNodeTree *ntree, bNode *node) iuser->fie_ima = 2; iuser->ok = 1; iuser->flag |= IMA_ANIM_ALWAYS; - + /* setup initial outputs */ cmp_node_image_verify_outputs(ntree, node, false); } @@ -315,20 +315,20 @@ static void node_composit_init_image(bNodeTree *ntree, bNode *node) static void node_composit_free_image(bNode *node) { bNodeSocket *sock; - + /* free extra socket info */ for (sock = node->outputs.first; sock; sock = sock->next) MEM_freeN(sock->storage); - + MEM_freeN(node->storage); } static void node_composit_copy_image(bNodeTree *UNUSED(dest_ntree), bNode *dest_node, bNode *src_node) { bNodeSocket *sock; - + dest_node->storage = MEM_dupallocN(src_node->storage); - + /* copy extra socket info */ for (sock = src_node->outputs.first; sock; sock = sock->next) sock->new_sock->storage = MEM_dupallocN(sock->storage); @@ -394,7 +394,7 @@ static int node_composit_poll_rlayers(bNodeType *UNUSED(ntype), bNodeTree *ntree { if (STREQ(ntree->idname, "CompositorNodeTree")) { Scene *scene; - + /* XXX ugly: check if ntree is a local scene node tree. * Render layers node can only be used in local scene->nodetree, * since it directly links to the scene. @@ -402,7 +402,7 @@ static int node_composit_poll_rlayers(bNodeType *UNUSED(ntype), bNodeTree *ntree for (scene = G.main->scene.first; scene; scene = scene->id.next) if (scene->nodetree == ntree) break; - + return (scene != NULL); } return false; diff --git a/source/blender/nodes/composite/nodes/node_composite_inpaint.c b/source/blender/nodes/composite/nodes/node_composite_inpaint.c index a0d3531dabf..f97f366d0c4 100644 --- a/source/blender/nodes/composite/nodes/node_composite_inpaint.c +++ b/source/blender/nodes/composite/nodes/node_composite_inpaint.c @@ -47,7 +47,7 @@ static bNodeSocketTemplate cmp_node_inpaint_out[] = { void register_node_type_cmp_inpaint(void) { static bNodeType ntype; - + cmp_node_type_base(&ntype, CMP_NODE_INPAINT, "Inpaint", NODE_CLASS_OP_FILTER, 0); node_type_socket_templates(&ntype, cmp_node_inpaint_in, cmp_node_inpaint_out); diff --git a/source/blender/nodes/composite/nodes/node_composite_math.c b/source/blender/nodes/composite/nodes/node_composite_math.c index 276dab27f76..e40621d3210 100644 --- a/source/blender/nodes/composite/nodes/node_composite_math.c +++ b/source/blender/nodes/composite/nodes/node_composite_math.c @@ -32,7 +32,7 @@ #include "node_composite_util.h" -/* **************** SCALAR MATH ******************** */ +/* **************** SCALAR MATH ******************** */ static bNodeSocketTemplate cmp_node_math_in[] = { { SOCK_FLOAT, 1, N_("Value"), 0.5f, 0.5f, 0.5f, 1.0f, -10000.0f, 10000.0f, PROP_NONE}, { SOCK_FLOAT, 1, N_("Value"), 0.5f, 0.5f, 0.5f, 1.0f, -10000.0f, 10000.0f, PROP_NONE}, diff --git a/source/blender/nodes/composite/nodes/node_composite_moviedistortion.c b/source/blender/nodes/composite/nodes/node_composite_moviedistortion.c index 9c54009d2f1..4149a0eec9d 100644 --- a/source/blender/nodes/composite/nodes/node_composite_moviedistortion.c +++ b/source/blender/nodes/composite/nodes/node_composite_moviedistortion.c @@ -58,7 +58,7 @@ static void init(const bContext *C, PointerRNA *ptr) { bNode *node = ptr->data; Scene *scene = CTX_data_scene(C); - + node->id = (ID *)scene->clip; } diff --git a/source/blender/nodes/composite/nodes/node_composite_normalize.c b/source/blender/nodes/composite/nodes/node_composite_normalize.c index d93c62f8229..9a5cc84797e 100644 --- a/source/blender/nodes/composite/nodes/node_composite_normalize.c +++ b/source/blender/nodes/composite/nodes/node_composite_normalize.c @@ -46,9 +46,9 @@ static bNodeSocketTemplate cmp_node_normalize_out[] = { void register_node_type_cmp_normalize(void) { static bNodeType ntype; - + cmp_node_type_base(&ntype, CMP_NODE_NORMALIZE, "Normalize", NODE_CLASS_OP_VECTOR, 0); node_type_socket_templates(&ntype, cmp_node_normalize_in, cmp_node_normalize_out); - + nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/composite/nodes/node_composite_outputFile.c b/source/blender/nodes/composite/nodes/node_composite_outputFile.c index 8b349ea8779..a2a25d5c515 100644 --- a/source/blender/nodes/composite/nodes/node_composite_outputFile.c +++ b/source/blender/nodes/composite/nodes/node_composite_outputFile.c @@ -107,16 +107,16 @@ bNodeSocket *ntreeCompositOutputFileAddSocket(bNodeTree *ntree, bNode *node, con { NodeImageMultiFile *nimf = node->storage; bNodeSocket *sock = nodeAddStaticSocket(ntree, node, SOCK_IN, SOCK_RGBA, PROP_NONE, NULL, name); - + /* create format data for the input socket */ NodeImageMultiFileSocket *sockdata = MEM_callocN(sizeof(NodeImageMultiFileSocket), "socket image format"); sock->storage = sockdata; - + BLI_strncpy_utf8(sockdata->path, name, sizeof(sockdata->path)); ntreeCompositOutputFileUniquePath(&node->inputs, sock, name, '_'); BLI_strncpy_utf8(sockdata->layer, name, sizeof(sockdata->layer)); ntreeCompositOutputFileUniqueLayer(&node->inputs, sock, name, '_'); - + if (im_format) { sockdata->format = *im_format; if (BKE_imtype_is_movie(sockdata->format.imtype)) { @@ -129,7 +129,7 @@ bNodeSocket *ntreeCompositOutputFileAddSocket(bNodeTree *ntree, bNode *node, con sockdata->use_node_format = true; nimf->active_input = BLI_findindex(&node->inputs, sock); - + return sock; } @@ -138,16 +138,16 @@ int ntreeCompositOutputFileRemoveActiveSocket(bNodeTree *ntree, bNode *node) NodeImageMultiFile *nimf = node->storage; bNodeSocket *sock = BLI_findlink(&node->inputs, nimf->active_input); int totinputs = BLI_listbase_count(&node->inputs); - + if (!sock) return 0; - + if (nimf->active_input == totinputs - 1) --nimf->active_input; - + /* free format data */ MEM_freeN(sock->storage); - + nodeRemoveSocket(ntree, node, sock); return 1; } @@ -175,7 +175,7 @@ static void init_output_file(const bContext *C, PointerRNA *ptr) NodeImageMultiFile *nimf = MEM_callocN(sizeof(NodeImageMultiFile), "node image multi file"); ImageFormatData *format = NULL; node->storage = nimf; - + if (scene) { RenderData *rd = &scene->r; @@ -184,7 +184,7 @@ static void init_output_file(const bContext *C, PointerRNA *ptr) if (BKE_imtype_is_movie(nimf->format.imtype)) { nimf->format.imtype = R_IMF_IMTYPE_OPENEXR; } - + format = &nimf->format; } else @@ -197,21 +197,21 @@ static void init_output_file(const bContext *C, PointerRNA *ptr) static void free_output_file(bNode *node) { bNodeSocket *sock; - + /* free storage data in sockets */ for (sock = node->inputs.first; sock; sock = sock->next) { MEM_freeN(sock->storage); } - + MEM_freeN(node->storage); } static void copy_output_file(bNodeTree *UNUSED(dest_ntree), bNode *dest_node, bNode *src_node) { bNodeSocket *src_sock, *dest_sock; - + dest_node->storage = MEM_dupallocN(src_node->storage); - + /* duplicate storage data in sockets */ for (src_sock = src_node->inputs.first, dest_sock = dest_node->inputs.first; src_sock && dest_sock; src_sock = src_sock->next, dest_sock = dest_sock->next) { dest_sock->storage = MEM_dupallocN(src_sock->storage); @@ -222,7 +222,7 @@ static void update_output_file(bNodeTree *ntree, bNode *node) { bNodeSocket *sock, *sock_next; PointerRNA ptr; - + /* XXX fix for #36706: remove invalid sockets added with bpy API. * This is not ideal, but prevents crashes from missing storage. * FileOutput node needs a redesign to support this properly. @@ -237,9 +237,9 @@ static void update_output_file(bNodeTree *ntree, bNode *node) sock_next = sock->next; nodeRemoveSocket(ntree, node, sock); } - + cmp_node_update_default(ntree, node); - + /* automatically update the socket type based on linked input */ for (sock = node->inputs.first; sock; sock = sock->next) { if (sock->link) { diff --git a/source/blender/nodes/composite/nodes/node_composite_splitViewer.c b/source/blender/nodes/composite/nodes/node_composite_splitViewer.c index 780ec1592bf..dbe47066f66 100644 --- a/source/blender/nodes/composite/nodes/node_composite_splitViewer.c +++ b/source/blender/nodes/composite/nodes/node_composite_splitViewer.c @@ -49,7 +49,7 @@ static void node_composit_init_splitviewer(bNodeTree *UNUSED(ntree), bNode *node iuser->fie_ima = 2; iuser->ok = 1; node->custom1 = 50; /* default 50% split */ - + node->id = (ID *)BKE_image_verify_viewer(IMA_TYPE_COMPOSITE, "Viewer Node"); } diff --git a/source/blender/nodes/composite/nodes/node_composite_stabilize2d.c b/source/blender/nodes/composite/nodes/node_composite_stabilize2d.c index 93ae6b6c4a4..16f5d340ddd 100644 --- a/source/blender/nodes/composite/nodes/node_composite_stabilize2d.c +++ b/source/blender/nodes/composite/nodes/node_composite_stabilize2d.c @@ -50,9 +50,9 @@ static void init(const bContext *C, PointerRNA *ptr) { bNode *node = ptr->data; Scene *scene = CTX_data_scene(C); - + node->id = (ID *)scene->clip; - + /* default to bilinear, see node_sampler_type_items in rna_nodetree.c */ node->custom1 = 1; } diff --git a/source/blender/nodes/composite/nodes/node_composite_valToRgb.c b/source/blender/nodes/composite/nodes/node_composite_valToRgb.c index 1b62f4e77d4..16fc98a5e85 100644 --- a/source/blender/nodes/composite/nodes/node_composite_valToRgb.c +++ b/source/blender/nodes/composite/nodes/node_composite_valToRgb.c @@ -77,10 +77,10 @@ static bNodeSocketTemplate cmp_node_rgbtobw_out[] = { void register_node_type_cmp_rgbtobw(void) { static bNodeType ntype; - + cmp_node_type_base(&ntype, CMP_NODE_RGBTOBW, "RGB to BW", NODE_CLASS_CONVERTOR, 0); node_type_socket_templates(&ntype, cmp_node_rgbtobw_in, cmp_node_rgbtobw_out); node_type_size_preset(&ntype, NODE_SIZE_SMALL); - + nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/composite/nodes/node_composite_viewer.c b/source/blender/nodes/composite/nodes/node_composite_viewer.c index 66f2e2bacbc..a10ba02b38e 100644 --- a/source/blender/nodes/composite/nodes/node_composite_viewer.c +++ b/source/blender/nodes/composite/nodes/node_composite_viewer.c @@ -52,7 +52,7 @@ static void node_composit_init_viewer(bNodeTree *UNUSED(ntree), bNode *node) iuser->ok = 1; node->custom3 = 0.5f; node->custom4 = 0.5f; - + node->id = (ID *)BKE_image_verify_viewer(IMA_TYPE_COMPOSITE, "Viewer Node"); } diff --git a/source/blender/nodes/intern/node_common.c b/source/blender/nodes/intern/node_common.c index c465f7a9be5..4a47bf7035c 100644 --- a/source/blender/nodes/intern/node_common.c +++ b/source/blender/nodes/intern/node_common.c @@ -98,16 +98,16 @@ int nodeGroupPoll(bNodeTree *nodetree, bNodeTree *grouptree) { bNode *node; int valid = 1; - + /* unspecified node group, generally allowed * (if anything, should be avoided on operator level) */ if (grouptree == NULL) return 1; - + if (nodetree == grouptree) return 0; - + for (node = grouptree->nodes.first; node; node = node->next) { if (node->typeinfo->poll_instance && !node->typeinfo->poll_instance(node, nodetree)) { valid = 0; @@ -121,27 +121,27 @@ int nodeGroupPoll(bNodeTree *nodetree, bNodeTree *grouptree) static bNodeSocket *group_verify_socket(bNodeTree *ntree, bNode *gnode, bNodeSocket *iosock, ListBase *verify_lb, int in_out) { bNodeSocket *sock; - + for (sock = verify_lb->first; sock; sock = sock->next) { if (STREQ(sock->identifier, iosock->identifier)) break; } if (sock) { strcpy(sock->name, iosock->name); - + if (iosock->typeinfo->interface_verify_socket) iosock->typeinfo->interface_verify_socket(ntree, iosock, gnode, sock, "interface"); } else { sock = nodeAddSocket(ntree, gnode, in_out, iosock->idname, iosock->identifier, iosock->name); - + if (iosock->typeinfo->interface_init_socket) iosock->typeinfo->interface_init_socket(ntree, iosock, gnode, sock, "interface"); } - + /* remove from list temporarily, to distinguish from orphaned sockets */ BLI_remlink(verify_lb, sock); - + return sock; } @@ -150,9 +150,9 @@ static void group_verify_socket_list(bNodeTree *ntree, bNode *gnode, ListBase *iosock_lb, ListBase *verify_lb, int in_out) { bNodeSocket *iosock, *sock, *nextsock; - + /* step by step compare */ - + iosock = iosock_lb->first; for (; iosock; iosock = iosock->next) { /* abusing new_sock pointer for verification here! only used inside this function */ @@ -195,9 +195,9 @@ static void node_frame_init(bNodeTree *UNUSED(ntree), bNode *node) { NodeFrame *data = (NodeFrame *)MEM_callocN(sizeof(NodeFrame), "frame node storage"); node->storage = data; - + data->flag |= NODE_FRAME_SHRINK; - + data->label_size = 20; } @@ -211,7 +211,7 @@ void register_node_type_frame(void) node_type_storage(ntype, "NodeFrame", node_free_standard_storage, node_copy_standard_storage); node_type_size(ntype, 150, 100, 0); node_type_compatibility(ntype, NODE_OLD_SHADING | NODE_NEW_SHADING); - + ntype->needs_free = 1; nodeRegisterType(ntype); } @@ -251,11 +251,11 @@ void register_node_type_reroute(void) { /* frame type is used for all tree types, needs dynamic allocation */ bNodeType *ntype = MEM_callocN(sizeof(bNodeType), "frame node type"); - + node_type_base(ntype, NODE_REROUTE, "Reroute", NODE_CLASS_LAYOUT, 0); node_type_init(ntype, node_reroute_init); node_type_internal_links(ntype, node_reroute_update_internal_links); - + ntype->needs_free = 1; nodeRegisterType(ntype); } @@ -267,14 +267,14 @@ static void node_reroute_inherit_type_recursive(bNodeTree *ntree, bNode *node, i bNodeLink *link; int type = SOCK_FLOAT; const char *type_idname = nodeStaticSocketType(type, PROP_NONE); - + /* XXX it would be a little bit more efficient to restrict actual updates * to rerout nodes connected to an updated node, but there's no reliable flag * to indicate updated nodes (node->update is not set on linking). */ - + node->done = 1; - + /* recursive update */ for (link = ntree->links.first; link; link = link->next) { bNode *fromnode = link->fromnode; @@ -283,7 +283,7 @@ static void node_reroute_inherit_type_recursive(bNodeTree *ntree, bNode *node, i continue; if (nodeLinkIsHidden(link)) continue; - + if (flag & REFINE_FORWARD) { if (tonode == node && fromnode->type == NODE_REROUTE && !fromnode->done) node_reroute_inherit_type_recursive(ntree, fromnode, REFINE_FORWARD); @@ -293,7 +293,7 @@ static void node_reroute_inherit_type_recursive(bNodeTree *ntree, bNode *node, i node_reroute_inherit_type_recursive(ntree, tonode, REFINE_BACKWARD); } } - + /* determine socket type from unambiguous input/output connection if possible */ if (input->limit == 1 && input->link) { type = input->link->fromsock->type; @@ -303,7 +303,7 @@ static void node_reroute_inherit_type_recursive(bNodeTree *ntree, bNode *node, i type = output->link->tosock->type; type_idname = nodeStaticSocketType(type, PROP_NONE); } - + if (input->type != type) { bNodeSocket *ninput = nodeAddSocket(ntree, node, SOCK_IN, type_idname, "input", "Input"); for (link = ntree->links.first; link; link = link->next) { @@ -314,7 +314,7 @@ static void node_reroute_inherit_type_recursive(bNodeTree *ntree, bNode *node, i } nodeRemoveSocket(ntree, node, input); } - + if (output->type != type) { bNodeSocket *noutput = nodeAddSocket(ntree, node, SOCK_OUT, type_idname, "output", "Output"); for (link = ntree->links.first; link; link = link->next) { @@ -324,7 +324,7 @@ static void node_reroute_inherit_type_recursive(bNodeTree *ntree, bNode *node, i } nodeRemoveSocket(ntree, node, output); } - + nodeUpdateInternalLinks(ntree, node); } @@ -334,11 +334,11 @@ static void node_reroute_inherit_type_recursive(bNodeTree *ntree, bNode *node, i void ntree_update_reroute_nodes(bNodeTree *ntree) { bNode *node; - + /* clear tags */ for (node = ntree->nodes.first; node; node = node->next) node->done = 0; - + for (node = ntree->nodes.first; node; node = node->next) if (node->type == NODE_REROUTE && !node->done) node_reroute_inherit_type_recursive(ntree, node, REFINE_FORWARD | REFINE_BACKWARD); @@ -411,7 +411,7 @@ void node_group_input_verify(bNodeTree *ntree, bNode *node, ID *id) if (id == (ID *)ntree) { /* value_in_out inverted for interface nodes to get correct socket value_property */ group_verify_socket_list(ntree, node, &ntree->inputs, &node->outputs, SOCK_OUT); - + /* add virtual extension socket */ nodeAddSocket(ntree, node, SOCK_OUT, "NodeSocketVirtual", "__extend__", ""); } @@ -426,23 +426,23 @@ static void node_group_input_update(bNodeTree *ntree, bNode *node) * so they can be recreated after verification. */ ListBase tmplinks; - + /* find links from the extension socket and store them */ BLI_listbase_clear(&tmplinks); for (link = ntree->links.first; link; link = linknext) { linknext = link->next; if (nodeLinkIsHidden(link)) continue; - + if (link->fromsock == extsock) { bNodeLink *tlink = MEM_callocN(sizeof(bNodeLink), "temporary link"); *tlink = *link; BLI_addtail(&tmplinks, tlink); - + nodeRemLink(ntree, link); } } - + /* find valid link to expose */ exposelink = NULL; for (link = tmplinks.first; link; link = link->next) { @@ -456,22 +456,22 @@ static void node_group_input_update(bNodeTree *ntree, bNode *node) break; } } - + if (exposelink) { bNodeSocket *gsock, *newsock; - + gsock = ntreeAddSocketInterfaceFromSocket(ntree, exposelink->tonode, exposelink->tosock); - + node_group_input_verify(ntree, node, (ID *)ntree); newsock = node_group_input_find_socket(node, gsock->identifier); - + /* redirect links from the extension socket */ for (link = tmplinks.first; link; link = link->next) { nodeAddLink(ntree, node, newsock, link->tonode, link->tosock); } - + } - + BLI_freelistN(&tmplinks); } @@ -479,13 +479,13 @@ void register_node_type_group_input(void) { /* used for all tree types, needs dynamic allocation */ bNodeType *ntype = MEM_callocN(sizeof(bNodeType), "node type"); - + node_type_base(ntype, NODE_GROUP_INPUT, "Group Input", NODE_CLASS_INTERFACE, 0); node_type_size(ntype, 140, 80, 400); node_type_init(ntype, node_group_input_init); node_type_update(ntype, node_group_input_update, node_group_input_verify); node_type_compatibility(ntype, NODE_OLD_SHADING | NODE_NEW_SHADING); - + ntype->needs_free = 1; nodeRegisterType(ntype); } @@ -510,7 +510,7 @@ void node_group_output_verify(bNodeTree *ntree, bNode *node, ID *id) if (id == (ID *)ntree) { /* value_in_out inverted for interface nodes to get correct socket value_property */ group_verify_socket_list(ntree, node, &ntree->outputs, &node->inputs, SOCK_IN); - + /* add virtual extension socket */ nodeAddSocket(ntree, node, SOCK_IN, "NodeSocketVirtual", "__extend__", ""); } @@ -525,23 +525,23 @@ static void node_group_output_update(bNodeTree *ntree, bNode *node) * so they can be recreated after verification. */ ListBase tmplinks; - + /* find links to the extension socket and store them */ BLI_listbase_clear(&tmplinks); for (link = ntree->links.first; link; link = linknext) { linknext = link->next; if (nodeLinkIsHidden(link)) continue; - + if (link->tosock == extsock) { bNodeLink *tlink = MEM_callocN(sizeof(bNodeLink), "temporary link"); *tlink = *link; BLI_addtail(&tmplinks, tlink); - + nodeRemLink(ntree, link); } } - + /* find valid link to expose */ exposelink = NULL; for (link = tmplinks.first; link; link = link->next) { @@ -555,22 +555,22 @@ static void node_group_output_update(bNodeTree *ntree, bNode *node) break; } } - + if (exposelink) { bNodeSocket *gsock, *newsock; - + /* XXX what if connecting virtual to virtual socket?? */ gsock = ntreeAddSocketInterfaceFromSocket(ntree, exposelink->fromnode, exposelink->fromsock); - + node_group_output_verify(ntree, node, (ID *)ntree); newsock = node_group_output_find_socket(node, gsock->identifier); - + /* redirect links to the extension socket */ for (link = tmplinks.first; link; link = link->next) { nodeAddLink(ntree, link->fromnode, link->fromsock, node, newsock); } } - + BLI_freelistN(&tmplinks); } @@ -578,13 +578,13 @@ void register_node_type_group_output(void) { /* used for all tree types, needs dynamic allocation */ bNodeType *ntype = MEM_callocN(sizeof(bNodeType), "node type"); - + node_type_base(ntype, NODE_GROUP_OUTPUT, "Group Output", NODE_CLASS_INTERFACE, 0); node_type_size(ntype, 140, 80, 400); node_type_init(ntype, node_group_output_init); node_type_update(ntype, node_group_output_update, node_group_output_verify); node_type_compatibility(ntype, NODE_OLD_SHADING | NODE_NEW_SHADING); - + ntype->needs_free = 1; nodeRegisterType(ntype); } diff --git a/source/blender/nodes/intern/node_exec.c b/source/blender/nodes/intern/node_exec.c index 5b97685fc54..3708a7663ed 100644 --- a/source/blender/nodes/intern/node_exec.c +++ b/source/blender/nodes/intern/node_exec.c @@ -61,14 +61,14 @@ bNodeStack *node_get_socket_stack(bNodeStack *stack, bNodeSocket *sock) void node_get_stack(bNode *node, bNodeStack *stack, bNodeStack **in, bNodeStack **out) { bNodeSocket *sock; - + /* build pointer stack */ if (in) { for (sock = node->inputs.first; sock; sock = sock->next) { *(in++) = node_get_socket_stack(stack, sock); } } - + if (out) { for (sock = node->outputs.first; sock; sock = sock->next) { *(out++) = node_get_socket_stack(stack, sock); @@ -127,13 +127,13 @@ static struct bNodeStack *setup_stack(bNodeStack *stack, bNodeTree *ntree, bNode bNodeStack *ns = node_get_socket_stack(stack, sock); if (!ns) return NULL; - + /* don't mess with remote socket stacks, these are initialized by other nodes! */ if (sock->link) return ns; - + ns->sockettype = sock->type; - + switch (sock->type) { case SOCK_FLOAT: ns->vec[0] = node_socket_get_float(ntree, node, sock); @@ -145,7 +145,7 @@ static struct bNodeStack *setup_stack(bNodeStack *stack, bNodeTree *ntree, bNode node_socket_get_color(ntree, node, sock, ns->vec); break; } - + return ns; } @@ -161,29 +161,29 @@ bNodeTreeExec *ntree_exec_begin(bNodeExecContext *context, bNodeTree *ntree, bNo bNode **nodelist; int totnodes, n; /* XXX texnodes have threading issues with muting, have to disable it there ... */ - + /* ensure all sock->link pointers and node levels are correct */ ntreeUpdateTree(G.main, ntree); - + /* get a dependency-sorted list of nodes */ ntreeGetDependencyList(ntree, &nodelist, &totnodes); - + /* XXX could let callbacks do this for specialized data */ exec = MEM_callocN(sizeof(bNodeTreeExec), "node tree execution data"); /* backpointer to node tree */ exec->nodetree = ntree; - + /* set stack indices */ index = 0; for (n = 0; n < totnodes; ++n) { node = nodelist[n]; - + node->stack_index = index; - + /* init node socket stack indexes */ for (sock = node->inputs.first; sock; sock = sock->next) node_init_input_index(sock, &index); - + if (node->flag & NODE_MUTED || node->type == NODE_REROUTE) { for (sock = node->outputs.first; sock; sock = sock->next) node_init_output_index(sock, &index, &node->internal_links); @@ -193,48 +193,48 @@ bNodeTreeExec *ntree_exec_begin(bNodeExecContext *context, bNodeTree *ntree, bNo node_init_output_index(sock, &index, NULL); } } - + /* allocated exec data pointers for nodes */ exec->totnodes = totnodes; exec->nodeexec = MEM_callocN(exec->totnodes * sizeof(bNodeExec), "node execution data"); /* allocate data pointer for node stack */ exec->stacksize = index; exec->stack = MEM_callocN(exec->stacksize * sizeof(bNodeStack), "bNodeStack"); - + /* all non-const results are considered inputs */ for (n = 0; n < exec->stacksize; ++n) exec->stack[n].hasinput = 1; - + /* prepare all nodes for execution */ for (n = 0, nodeexec = exec->nodeexec; n < totnodes; ++n, ++nodeexec) { node = nodeexec->node = nodelist[n]; nodeexec->freeexecfunc = node->typeinfo->freeexecfunc; - + /* tag inputs */ for (sock = node->inputs.first; sock; sock = sock->next) { /* disable the node if an input link is invalid */ if (sock->link && !(sock->link->flag & NODE_LINK_VALID)) node->need_exec = 0; - + ns = setup_stack(exec->stack, ntree, node, sock); if (ns) ns->hasoutput = 1; } - + /* tag all outputs */ for (sock = node->outputs.first; sock; sock = sock->next) { /* ns = */ setup_stack(exec->stack, ntree, node, sock); } - + nodekey = BKE_node_instance_key(parent_key, ntree, node); nodeexec->data.preview = context->previews ? BKE_node_instance_hash_lookup(context->previews, nodekey) : NULL; if (node->typeinfo->initexecfunc) nodeexec->data.data = node->typeinfo->initexecfunc(context, node, nodekey); } - + if (nodelist) MEM_freeN(nodelist); - + return exec; } @@ -242,18 +242,18 @@ void ntree_exec_end(bNodeTreeExec *exec) { bNodeExec *nodeexec; int n; - + if (exec->stack) MEM_freeN(exec->stack); - + for (n = 0, nodeexec = exec->nodeexec; n < exec->totnodes; ++n, ++nodeexec) { if (nodeexec->freeexecfunc) nodeexec->freeexecfunc(nodeexec->data.data); } - + if (exec->nodeexec) MEM_freeN(exec->nodeexec); - + MEM_freeN(exec); } @@ -263,14 +263,14 @@ bNodeThreadStack *ntreeGetThreadStack(bNodeTreeExec *exec, int thread) { ListBase *lb = &exec->threadstack[thread]; bNodeThreadStack *nts; - + for (nts = lb->first; nts; nts = nts->next) { if (!nts->used) { nts->used = true; break; } } - + if (!nts) { nts = MEM_callocN(sizeof(bNodeThreadStack), "bNodeThreadStack"); nts->stack = MEM_dupallocN(exec->stack); @@ -293,9 +293,9 @@ bool ntreeExecThreadNodes(bNodeTreeExec *exec, bNodeThreadStack *nts, void *call bNodeExec *nodeexec; bNode *node; int n; - + /* nodes are presorted, so exec is in order of list */ - + for (n = 0, nodeexec = exec->nodeexec; n < exec->totnodes; ++n, ++nodeexec) { node = nodeexec->node; if (node->need_exec) { @@ -308,7 +308,7 @@ bool ntreeExecThreadNodes(bNodeTreeExec *exec, bNodeThreadStack *nts, void *call node->typeinfo->execfunc(callerdata, thread, node, &nodeexec->data, nsin, nsout); } } - + /* signal to that all went OK, for render */ return true; } diff --git a/source/blender/nodes/intern/node_exec.h b/source/blender/nodes/intern/node_exec.h index bf4c29bad8e..6771df76bf9 100644 --- a/source/blender/nodes/intern/node_exec.h +++ b/source/blender/nodes/intern/node_exec.h @@ -51,17 +51,17 @@ struct bNodeStack; typedef struct bNodeExec { struct bNode *node; /* backpointer to node */ bNodeExecData data; - + NodeFreeExecFunction freeexecfunc; /* free function, stored in exec itself to avoid dangling node pointer access */ } bNodeExec; /* Execution Data for each instance of node tree execution */ typedef struct bNodeTreeExec { struct bNodeTree *nodetree; /* backpointer to node tree */ - + int totnodes; /* total node count */ struct bNodeExec *nodeexec; /* per-node execution data */ - + int stacksize; struct bNodeStack *stack; /* socket data stack */ /* only used by material and texture trees to keep one stack for each thread */ diff --git a/source/blender/nodes/intern/node_socket.c b/source/blender/nodes/intern/node_socket.c index e1e1e2f0854..23ba51bbe10 100644 --- a/source/blender/nodes/intern/node_socket.c +++ b/source/blender/nodes/intern/node_socket.c @@ -52,9 +52,9 @@ struct Main; struct bNodeSocket *node_add_socket_from_template(struct bNodeTree *ntree, struct bNode *node, struct bNodeSocketTemplate *stemp, int in_out) { bNodeSocket *sock = nodeAddStaticSocket(ntree, node, in_out, stemp->type, stemp->subtype, stemp->identifier, stemp->name); - + sock->flag |= stemp->flag; - + /* initialize default_value */ switch (stemp->type) { case SOCK_FLOAT: @@ -99,14 +99,14 @@ struct bNodeSocket *node_add_socket_from_template(struct bNodeTree *ntree, struc break; } } - + return sock; } static bNodeSocket *verify_socket_template(bNodeTree *ntree, bNode *node, int in_out, ListBase *socklist, bNodeSocketTemplate *stemp) { bNodeSocket *sock; - + for (sock = socklist->first; sock; sock = sock->next) { if (STREQLEN(sock->name, stemp->name, NODE_MAXSTR)) break; @@ -127,7 +127,7 @@ static bNodeSocket *verify_socket_template(bNodeTree *ntree, bNode *node, int in /* remove the new socket from the node socket list first, * will be added back after verification. */ BLI_remlink(socklist, sock); - + return sock; } @@ -135,7 +135,7 @@ static void verify_socket_template_list(bNodeTree *ntree, bNode *node, int in_ou { bNodeSocket *sock, *nextsock; bNodeSocketTemplate *stemp; - + /* no inputs anymore? */ if (stemp_first == NULL) { for (sock = (bNodeSocket *)socklist->first; sock; sock = nextsock) { @@ -155,7 +155,7 @@ static void verify_socket_template_list(bNodeTree *ntree, bNode *node, int in_ou nextsock = sock->next; nodeRemoveSocket(ntree, node, sock); } - + /* and we put back the verified sockets */ stemp = stemp_first; if (socklist->first) { @@ -199,10 +199,10 @@ void node_socket_init_default_value(bNodeSocket *sock) { int type = sock->typeinfo->type; int subtype = sock->typeinfo->subtype; - + if (sock->default_value) return; /* already initialized */ - + switch (type) { case SOCK_FLOAT: { @@ -211,7 +211,7 @@ void node_socket_init_default_value(bNodeSocket *sock) dval->value = 0.0f; dval->min = -FLT_MAX; dval->max = FLT_MAX; - + sock->default_value = dval; break; } @@ -222,7 +222,7 @@ void node_socket_init_default_value(bNodeSocket *sock) dval->value = 0; dval->min = INT_MIN; dval->max = INT_MAX; - + sock->default_value = dval; break; } @@ -230,7 +230,7 @@ void node_socket_init_default_value(bNodeSocket *sock) { bNodeSocketValueBoolean *dval = MEM_callocN(sizeof(bNodeSocketValueBoolean), "node socket value bool"); dval->value = false; - + sock->default_value = dval; break; } @@ -242,7 +242,7 @@ void node_socket_init_default_value(bNodeSocket *sock) copy_v3_v3(dval->value, default_value); dval->min = -FLT_MAX; dval->max = FLT_MAX; - + sock->default_value = dval; break; } @@ -251,7 +251,7 @@ void node_socket_init_default_value(bNodeSocket *sock) static float default_value[] = { 0.0f, 0.0f, 0.0f, 1.0f }; bNodeSocketValueRGBA *dval = MEM_callocN(sizeof(bNodeSocketValueRGBA), "node socket value color"); copy_v4_v4(dval->value, default_value); - + sock->default_value = dval; break; } @@ -260,7 +260,7 @@ void node_socket_init_default_value(bNodeSocket *sock) bNodeSocketValueString *dval = MEM_callocN(sizeof(bNodeSocketValueString), "node socket value string"); dval->subtype = subtype; dval->value[0] = '\0'; - + sock->default_value = dval; break; } @@ -272,12 +272,12 @@ void node_socket_copy_default_value(bNodeSocket *to, const bNodeSocket *from) /* sanity check */ if (to->type != from->type) return; - + /* make sure both exist */ if (!from->default_value) return; node_socket_init_default_value(to); - + switch (from->typeinfo->type) { case SOCK_FLOAT: { @@ -330,7 +330,7 @@ static void standard_node_socket_interface_init_socket(bNodeTree *UNUSED(ntree), { /* initialize the type value */ sock->type = sock->typeinfo->type; - + /* XXX socket interface 'type' value is not used really, * but has to match or the copy function will bail out */ @@ -345,12 +345,12 @@ static void standard_node_socket_interface_verify_socket(bNodeTree *UNUSED(ntree /* sanity check */ if (sock->type != stemp->typeinfo->type) return; - + /* make sure both exist */ if (!stemp->default_value) return; node_socket_init_default_value(sock); - + switch (stemp->typeinfo->type) { case SOCK_FLOAT: { @@ -389,65 +389,65 @@ static void standard_node_socket_interface_from_socket(bNodeTree *UNUSED(ntree), static bNodeSocketType *make_standard_socket_type(int type, int subtype) { extern void ED_init_standard_node_socket_type(bNodeSocketType *); - + const char *socket_idname = nodeStaticSocketType(type, subtype); const char *interface_idname = nodeStaticSocketInterfaceType(type, subtype); bNodeSocketType *stype; StructRNA *srna; - + stype = MEM_callocN(sizeof(bNodeSocketType), "node socket C type"); BLI_strncpy(stype->idname, socket_idname, sizeof(stype->idname)); - + /* set the RNA type * uses the exact same identifier as the socket type idname */ srna = stype->ext_socket.srna = RNA_struct_find(socket_idname); BLI_assert(srna != NULL); /* associate the RNA type with the socket type */ RNA_struct_blender_type_set(srna, stype); - + /* set the interface RNA type */ srna = stype->ext_interface.srna = RNA_struct_find(interface_idname); BLI_assert(srna != NULL); /* associate the RNA type with the socket type */ RNA_struct_blender_type_set(srna, stype); - + /* extra type info for standard socket types */ stype->type = type; stype->subtype = subtype; - + /* XXX bad-level call! needed for setting draw callbacks */ ED_init_standard_node_socket_type(stype); - + stype->interface_init_socket = standard_node_socket_interface_init_socket; stype->interface_from_socket = standard_node_socket_interface_from_socket; stype->interface_verify_socket = standard_node_socket_interface_verify_socket; - + return stype; } static bNodeSocketType *make_socket_type_virtual(void) { extern void ED_init_node_socket_type_virtual(bNodeSocketType *); - + const char *socket_idname = "NodeSocketVirtual"; bNodeSocketType *stype; StructRNA *srna; - + stype = MEM_callocN(sizeof(bNodeSocketType), "node socket C type"); BLI_strncpy(stype->idname, socket_idname, sizeof(stype->idname)); - + /* set the RNA type * uses the exact same identifier as the socket type idname */ srna = stype->ext_socket.srna = RNA_struct_find(socket_idname); BLI_assert(srna != NULL); /* associate the RNA type with the socket type */ RNA_struct_blender_type_set(srna, stype); - + /* extra type info for standard socket types */ stype->type = SOCK_CUSTOM; - + ED_init_node_socket_type_virtual(stype); - + return stype; } @@ -455,21 +455,21 @@ static bNodeSocketType *make_socket_type_virtual(void) void register_standard_node_socket_types(void) { /* draw callbacks are set in drawnode.c to avoid bad-level calls */ - + nodeRegisterSocketType(make_standard_socket_type(SOCK_FLOAT, PROP_NONE)); nodeRegisterSocketType(make_standard_socket_type(SOCK_FLOAT, PROP_UNSIGNED)); nodeRegisterSocketType(make_standard_socket_type(SOCK_FLOAT, PROP_PERCENTAGE)); nodeRegisterSocketType(make_standard_socket_type(SOCK_FLOAT, PROP_FACTOR)); nodeRegisterSocketType(make_standard_socket_type(SOCK_FLOAT, PROP_ANGLE)); nodeRegisterSocketType(make_standard_socket_type(SOCK_FLOAT, PROP_TIME)); - + nodeRegisterSocketType(make_standard_socket_type(SOCK_INT, PROP_NONE)); nodeRegisterSocketType(make_standard_socket_type(SOCK_INT, PROP_UNSIGNED)); nodeRegisterSocketType(make_standard_socket_type(SOCK_INT, PROP_PERCENTAGE)); nodeRegisterSocketType(make_standard_socket_type(SOCK_INT, PROP_FACTOR)); - + nodeRegisterSocketType(make_standard_socket_type(SOCK_BOOLEAN, PROP_NONE)); - + nodeRegisterSocketType(make_standard_socket_type(SOCK_VECTOR, PROP_NONE)); nodeRegisterSocketType(make_standard_socket_type(SOCK_VECTOR, PROP_TRANSLATION)); nodeRegisterSocketType(make_standard_socket_type(SOCK_VECTOR, PROP_DIRECTION)); @@ -477,12 +477,12 @@ void register_standard_node_socket_types(void) nodeRegisterSocketType(make_standard_socket_type(SOCK_VECTOR, PROP_ACCELERATION)); nodeRegisterSocketType(make_standard_socket_type(SOCK_VECTOR, PROP_EULER)); nodeRegisterSocketType(make_standard_socket_type(SOCK_VECTOR, PROP_XYZ)); - + nodeRegisterSocketType(make_standard_socket_type(SOCK_RGBA, PROP_NONE)); - + nodeRegisterSocketType(make_standard_socket_type(SOCK_STRING, PROP_NONE)); - + nodeRegisterSocketType(make_standard_socket_type(SOCK_SHADER, PROP_NONE)); - + nodeRegisterSocketType(make_socket_type_virtual()); } diff --git a/source/blender/nodes/intern/node_util.c b/source/blender/nodes/intern/node_util.c index 45409a2dfad..19529794c7c 100644 --- a/source/blender/nodes/intern/node_util.c +++ b/source/blender/nodes/intern/node_util.c @@ -165,10 +165,10 @@ static int node_count_links(bNodeTree *ntree, bNodeSocket *sock) static bNodeSocket *node_find_linkable_socket(bNodeTree *ntree, bNode *node, bNodeSocket *cur) { /* link swapping: try to find a free slot with a matching name */ - + bNodeSocket *first = cur->in_out == SOCK_IN ? node->inputs.first : node->outputs.first; bNodeSocket *sock; - + sock = cur->next ? cur->next : first; /* wrap around the list end */ while (sock != cur) { if (!nodeSocketIsHidden(sock) && node_link_socket_match(sock, cur)) { @@ -177,7 +177,7 @@ static bNodeSocket *node_find_linkable_socket(bNodeTree *ntree, bNode *node, bNo if (link_count + 1 <= sock->limit) return sock; /* found a valid free socket we can swap to */ } - + sock = sock->next ? sock->next : first; /* wrap around the list end */ } return NULL; @@ -187,18 +187,18 @@ void node_insert_link_default(bNodeTree *ntree, bNode *node, bNodeLink *link) { bNodeSocket *sock = link->tosock; bNodeLink *tlink, *tlink_next; - + /* inputs can have one link only, outputs can have unlimited links */ if (node != link->tonode) return; - + for (tlink = ntree->links.first; tlink; tlink = tlink_next) { bNodeSocket *new_sock; tlink_next = tlink->next; - + if (sock != tlink->tosock) continue; - + new_sock = node_find_linkable_socket(ntree, node, sock); if (new_sock && new_sock != sock) { /* redirect existing link */ @@ -287,12 +287,12 @@ static bNodeSocket *select_internal_link_input(bNode *node, bNodeSocket *output) int i; int sel_priority = -1; bool sel_is_linked = false; - + for (input = node->inputs.first, i = 0; input; input = input->next, ++i) { int priority = node_datatype_priority(input->type, output->type); bool is_linked = (input->link != NULL); bool preferred; - + if (nodeSocketIsHidden(input) || /* ignore hidden sockets */ input->flag & SOCK_NO_INTERNAL_LINK || /* ignore if input is not allowed for internal connections */ priority < 0 || /* ignore incompatible types */ @@ -300,18 +300,18 @@ static bNodeSocket *select_internal_link_input(bNode *node, bNodeSocket *output) { continue; } - + /* determine if this input is preferred over the currently selected */ preferred = (priority > sel_priority) || /* prefer higher datatype priority */ (is_linked && !sel_is_linked); /* prefer linked over unlinked */ - + if (preferred) { selected = input; sel_is_linked = is_linked; sel_priority = priority; } } - + return selected; } @@ -319,29 +319,29 @@ void node_update_internal_links_default(bNodeTree *ntree, bNode *node) { bNodeLink *link; bNodeSocket *output, *input; - + /* sanity check */ if (!ntree) return; - + /* use link pointer as a tag for handled sockets (for outputs is unused anyway) */ for (output = node->outputs.first; output; output = output->next) output->link = NULL; - + for (link = ntree->links.first; link; link = link->next) { if (nodeLinkIsHidden(link)) continue; - + output = link->fromsock; if (link->fromnode != node || output->link) continue; if (nodeSocketIsHidden(output) || output->flag & SOCK_NO_INTERNAL_LINK) continue; output->link = link; /* not really used, just for tagging handled sockets */ - + /* look for suitable input */ input = select_internal_link_input(node, output); - + if (input) { bNodeLink *ilink = MEM_callocN(sizeof(bNodeLink), "internal node link"); ilink->fromnode = node; @@ -353,7 +353,7 @@ void node_update_internal_links_default(bNodeTree *ntree, bNode *node) BLI_addtail(&node->internal_links, ilink); } } - + /* clean up */ for (output = node->outputs.first; output; output = output->next) output->link = NULL; diff --git a/source/blender/nodes/shader/node_shader_tree.c b/source/blender/nodes/shader/node_shader_tree.c index a5d8031f2f3..fcb21982661 100644 --- a/source/blender/nodes/shader/node_shader_tree.c +++ b/source/blender/nodes/shader/node_shader_tree.c @@ -82,7 +82,7 @@ static void shader_get_from_context(const bContext *C, bNodeTreeType *UNUSED(tre Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); Object *ob = OBACT(view_layer); - + if (snode->shaderfrom == SNODE_SHADER_OBJECT) { if (ob) { *r_from = &ob->id; @@ -136,11 +136,11 @@ static void foreach_nodeclass(Scene *UNUSED(scene), void *calldata, bNodeClassCa static void localize(bNodeTree *localtree, bNodeTree *UNUSED(ntree)) { bNode *node, *node_next; - + /* replace muted nodes and reroute nodes by internal links */ for (node = localtree->nodes.first; node; node = node_next) { node_next = node->next; - + if (node->flag & NODE_MUTED || node->type == NODE_REROUTE) { nodeInternalRelink(localtree, node); nodeFreeNode(localtree, node); @@ -161,9 +161,9 @@ static void local_merge(bNodeTree *localtree, bNodeTree *ntree) static void update(bNodeTree *ntree) { ntreeSetOutput(ntree); - + ntree_update_reroute_nodes(ntree); - + if (ntree->update & NTREE_UPDATE_NODES) { /* clean up preview cache, in case nodes have been removed */ BKE_node_preview_remove_unused(ntree); @@ -175,13 +175,13 @@ bNodeTreeType *ntreeType_Shader; void register_node_tree_type_sh(void) { bNodeTreeType *tt = ntreeType_Shader = MEM_callocN(sizeof(bNodeTreeType), "shader node tree type"); - + tt->type = NTREE_SHADER; strcpy(tt->idname, "ShaderNodeTree"); strcpy(tt->ui_name, "Shader Editor"); tt->ui_icon = 0; /* defined in drawnode.c */ strcpy(tt->ui_description, "Shader nodes"); - + tt->foreach_nodeclass = foreach_nodeclass; tt->localize = localize; tt->local_sync = local_sync; @@ -189,9 +189,9 @@ void register_node_tree_type_sh(void) tt->update = update; tt->poll = shader_tree_poll; tt->get_from_context = shader_get_from_context; - + tt->ext.srna = &RNA_ShaderNodeTree; - + ntreeTypeAdd(tt); } @@ -622,19 +622,19 @@ bNodeTreeExec *ntreeShaderBeginExecTree_internal(bNodeExecContext *context, bNod { bNodeTreeExec *exec; bNode *node; - + /* ensures only a single output node is enabled */ ntreeSetOutput(ntree); - + /* common base initialization */ exec = ntree_exec_begin(context, ntree, parent_key); - + /* allocate the thread stack listbase array */ exec->threadstack = MEM_callocN(BLENDER_MAX_THREADS * sizeof(ListBase), "thread stack array"); - + for (node = exec->nodetree->nodes.first; node; node = node->next) node->need_exec = 1; - + return exec; } @@ -642,22 +642,22 @@ bNodeTreeExec *ntreeShaderBeginExecTree(bNodeTree *ntree) { bNodeExecContext context; bNodeTreeExec *exec; - + /* XXX hack: prevent exec data from being generated twice. * this should be handled by the renderer! */ if (ntree->execdata) return ntree->execdata; - + context.previews = ntree->previews; - + exec = ntreeShaderBeginExecTree_internal(&context, ntree, NODE_INSTANCE_KEY_BASE); - + /* XXX this should not be necessary, but is still used for cmp/sha/tex nodes, * which only store the ntree pointer. Should be fixed at some point! */ ntree->execdata = exec; - + return exec; } @@ -665,18 +665,18 @@ void ntreeShaderEndExecTree_internal(bNodeTreeExec *exec) { bNodeThreadStack *nts; int a; - + if (exec->threadstack) { for (a = 0; a < BLENDER_MAX_THREADS; a++) { for (nts = exec->threadstack[a].first; nts; nts = nts->next) if (nts->stack) MEM_freeN(nts->stack); BLI_freelistN(&exec->threadstack[a]); } - + MEM_freeN(exec->threadstack); exec->threadstack = NULL; } - + ntree_exec_end(exec); } @@ -686,7 +686,7 @@ void ntreeShaderEndExecTree(bNodeTreeExec *exec) /* exec may get freed, so assign ntree */ bNodeTree *ntree = exec->nodetree; ntreeShaderEndExecTree_internal(exec); - + /* XXX clear nodetree backpointer to exec data, same problem as noted in ntreeBeginExecTree */ ntree->execdata = NULL; } @@ -699,7 +699,7 @@ bool ntreeShaderExecTree(bNodeTree *ntree, int thread) bNodeThreadStack *nts = NULL; bNodeTreeExec *exec = ntree->execdata; int compat; - + /* ensure execdata is only initialized once */ if (!exec) { BLI_thread_lock(LOCK_NODES); @@ -709,11 +709,11 @@ bool ntreeShaderExecTree(bNodeTree *ntree, int thread) exec = ntree->execdata; } - + nts = ntreeGetThreadStack(exec, thread); compat = ntreeExecThreadNodes(exec, nts, &scd, thread); ntreeReleaseThreadStack(nts); - + /* if compat is zero, it has been using non-compatible nodes */ return compat; } diff --git a/source/blender/nodes/shader/node_shader_util.c b/source/blender/nodes/shader/node_shader_util.c index 43e940d6d0a..a4b2c155675 100644 --- a/source/blender/nodes/shader/node_shader_util.c +++ b/source/blender/nodes/shader/node_shader_util.c @@ -45,7 +45,7 @@ int sh_node_poll_default(bNodeType *UNUSED(ntype), bNodeTree *ntree) void sh_node_type_base(struct bNodeType *ntype, int type, const char *name, short nclass, short flag) { node_type_base(ntype, type, name, nclass, flag); - + ntype->poll = sh_node_poll_default; ntype->insert_link = node_insert_link_default; ntype->update_internal_links = node_update_internal_links_default; @@ -56,11 +56,11 @@ void sh_node_type_base(struct bNodeType *ntype, int type, const char *name, shor void nodestack_get_vec(float *in, short type_in, bNodeStack *ns) { const float *from = ns->vec; - + if (type_in == SOCK_FLOAT) { if (ns->sockettype == SOCK_FLOAT) *in = *from; - else + else *in = (from[0] + from[1] + from[2]) / 3.0f; } else if (type_in == SOCK_VECTOR) { @@ -94,7 +94,7 @@ void nodestack_get_vec(float *in, short type_in, bNodeStack *ns) void node_gpu_stack_from_data(struct GPUNodeStack *gs, int type, bNodeStack *ns) { memset(gs, 0, sizeof(*gs)); - + if (ns == NULL) { /* node_get_stack() will generate NULL bNodeStack pointers for unknown/unsuported types of sockets... */ zero_v4(gs->vec); @@ -107,7 +107,7 @@ void node_gpu_stack_from_data(struct GPUNodeStack *gs, int type, bNodeStack *ns) else { nodestack_get_vec(gs->vec, type, ns); gs->link = ns->data; - + if (type == SOCK_FLOAT) gs->type = GPU_FLOAT; else if (type == SOCK_VECTOR) @@ -140,10 +140,10 @@ static void gpu_stack_from_data_list(GPUNodeStack *gs, ListBase *sockets, bNodeS { bNodeSocket *sock; int i; - + for (sock = sockets->first, i = 0; sock; sock = sock->next, i++) node_gpu_stack_from_data(&gs[i], sock->type, ns[i]); - + gs[i].end = true; } @@ -192,7 +192,7 @@ bNode *nodeGetActiveTexture(bNodeTree *ntree) if (activetexnode) return activetexnode; - + if (hasgroup) { /* node active texture node in this tree, look inside groups */ for (node = ntree->nodes.first; node; node = node->next) { @@ -203,7 +203,7 @@ bNode *nodeGetActiveTexture(bNodeTree *ntree) } } } - + return inactivenode; } @@ -222,7 +222,7 @@ void ntreeExecGPUNodes(bNodeTreeExec *exec, GPUMaterial *mat, int do_outputs, sh for (n = 0, nodeexec = exec->nodeexec; n < exec->totnodes; ++n, ++nodeexec) { node = nodeexec->node; - + do_it = false; /* for groups, only execute outputs for edited group */ if (node->typeinfo->nclass == NODE_CLASS_OUTPUT) { diff --git a/source/blender/nodes/shader/nodes/node_shader_brightness.c b/source/blender/nodes/shader/nodes/node_shader_brightness.c index d795575c86a..bb95ed2d32c 100644 --- a/source/blender/nodes/shader/nodes/node_shader_brightness.c +++ b/source/blender/nodes/shader/nodes/node_shader_brightness.c @@ -50,13 +50,13 @@ static int gpu_shader_brightcontrast(GPUMaterial *mat, bNode *node, bNodeExecDat void register_node_type_sh_brightcontrast(void) { static bNodeType ntype; - + sh_node_type_base(&ntype, SH_NODE_BRIGHTCONTRAST, "Bright/Contrast", NODE_CLASS_OP_COLOR, 0); node_type_compatibility(&ntype, NODE_NEW_SHADING); node_type_socket_templates(&ntype, sh_node_brightcontrast_in, sh_node_brightcontrast_out); node_type_init(&ntype, NULL); node_type_storage(&ntype, "", NULL, NULL); node_type_gpu(&ntype, gpu_shader_brightcontrast); - + nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_bump.c b/source/blender/nodes/shader/nodes/node_shader_bump.c index 6098aefc5e1..6274d132bc7 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bump.c +++ b/source/blender/nodes/shader/nodes/node_shader_bump.c @@ -31,7 +31,7 @@ #include "node_shader_util.h" -/* **************** BUMP ******************** */ +/* **************** BUMP ******************** */ static bNodeSocketTemplate sh_node_bump_in[] = { { SOCK_FLOAT, 1, N_("Strength"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR}, { SOCK_FLOAT, 1, N_("Distance"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1000.0f}, diff --git a/source/blender/nodes/shader/nodes/node_shader_common.c b/source/blender/nodes/shader/nodes/node_shader_common.c index 134319cb352..24de03dbda4 100644 --- a/source/blender/nodes/shader/nodes/node_shader_common.c +++ b/source/blender/nodes/shader/nodes/node_shader_common.c @@ -50,7 +50,7 @@ static void copy_stack(bNodeStack *to, bNodeStack *from) copy_v4_v4(to->vec, from->vec); to->data = from->data; to->datatype = from->datatype; - + /* tag as copy to prevent freeing */ to->is_copy = 1; } @@ -63,7 +63,7 @@ static void move_stack(bNodeStack *to, bNodeStack *from) to->data = from->data; to->datatype = from->datatype; to->is_copy = from->is_copy; - + from->data = NULL; from->is_copy = 0; } @@ -75,20 +75,20 @@ static void *group_initexec(bNodeExecContext *context, bNode *node, bNodeInstanc { bNodeTree *ngroup = (bNodeTree *)node->id; bNodeTreeExec *exec; - + if (!ngroup) return NULL; - + /* initialize the internal node tree execution */ exec = ntreeShaderBeginExecTree_internal(context, ngroup, key); - + return exec; } static void group_freeexec(void *nodedata) { bNodeTreeExec *gexec = (bNodeTreeExec *)nodedata; - + if (gexec) ntreeShaderEndExecTree_internal(gexec); } @@ -102,7 +102,7 @@ static void group_copy_inputs(bNode *gnode, bNodeStack **in, bNodeStack *gstack) bNodeSocket *sock; bNodeStack *ns; int a; - + for (node = ngroup->nodes.first; node; node = node->next) { if (node->type == NODE_GROUP_INPUT) { for (sock = node->outputs.first, a = 0; sock; sock = sock->next, ++a) { @@ -123,7 +123,7 @@ static void group_move_outputs(bNode *gnode, bNodeStack **out, bNodeStack *gstac bNodeSocket *sock; bNodeStack *ns; int a; - + for (node = ngroup->nodes.first; node; node = node->next) { if (node->type == NODE_GROUP_OUTPUT && (node->flag & NODE_DO_OUTPUT)) { for (sock = node->inputs.first, a = 0; sock; sock = sock->next, ++a) { @@ -140,10 +140,10 @@ static void group_execute(void *data, int thread, struct bNode *node, bNodeExecD { bNodeTreeExec *exec = execdata->data; bNodeThreadStack *nts; - + if (!exec) return; - + /* XXX same behavior as trunk: all nodes inside group are executed. * it's stupid, but just makes it work. compo redesign will do this better. */ @@ -152,13 +152,13 @@ static void group_execute(void *data, int thread, struct bNode *node, bNodeExecD for (inode = exec->nodetree->nodes.first; inode; inode = inode->next) inode->need_exec = 1; } - + nts = ntreeGetThreadStack(exec, thread); - + group_copy_inputs(node, in, nts->stack); ntreeExecThreadNodes(exec, nts, data, thread); group_move_outputs(node, out, nts->stack); - + ntreeReleaseThreadStack(nts); } @@ -169,7 +169,7 @@ static void group_gpu_copy_inputs(bNode *gnode, GPUNodeStack *in, bNodeStack *gs bNodeSocket *sock; bNodeStack *ns; int a; - + for (node = ngroup->nodes.first; node; node = node->next) { if (node->type == NODE_GROUP_INPUT) { for (sock = node->outputs.first, a = 0; sock; sock = sock->next, ++a) { @@ -192,7 +192,7 @@ static void group_gpu_move_outputs(bNode *gnode, GPUNodeStack *out, bNodeStack * bNodeSocket *sock; bNodeStack *ns; int a; - + for (node = ngroup->nodes.first; node; node = node->next) { if (node->type == NODE_GROUP_OUTPUT && (node->flag & NODE_DO_OUTPUT)) { for (sock = node->inputs.first, a = 0; sock; sock = sock->next, ++a) { @@ -210,10 +210,10 @@ static void group_gpu_move_outputs(bNode *gnode, GPUNodeStack *out, bNodeStack * static int gpu_group_execute(GPUMaterial *mat, bNode *node, bNodeExecData *execdata, GPUNodeStack *in, GPUNodeStack *out) { bNodeTreeExec *exec = execdata->data; - + if (!node->id) return 0; - + group_gpu_copy_inputs(node, in, exec->stack); #if 0 /* XXX NODE_GROUP_EDIT is deprecated, depends on node space */ ntreeExecGPUNodes(exec, mat, (node->flag & NODE_GROUP_EDIT)); @@ -221,14 +221,14 @@ static int gpu_group_execute(GPUMaterial *mat, bNode *node, bNodeExecData *execd ntreeExecGPUNodes(exec, mat, 0, NODE_NEW_SHADING | NODE_OLD_SHADING); #endif group_gpu_move_outputs(node, out, exec->stack); - + return 1; } void register_node_type_sh_group(void) { static bNodeType ntype; - + /* NB: cannot use sh_node_type_base for node group, because it would map the node type * to the shared NODE_GROUP integer type id. */ @@ -241,7 +241,7 @@ void register_node_type_sh_group(void) ntype.ext.srna = RNA_struct_find("ShaderNodeGroup"); BLI_assert(ntype.ext.srna != NULL); RNA_struct_blender_type_set(ntype.ext.srna, &ntype); - + node_type_compatibility(&ntype, NODE_OLD_SHADING | NODE_NEW_SHADING); node_type_socket_templates(&ntype, NULL, NULL); node_type_size(&ntype, 140, 60, 400); @@ -249,6 +249,6 @@ void register_node_type_sh_group(void) node_type_update(&ntype, NULL, node_group_verify); node_type_exec(&ntype, group_initexec, group_freeexec, group_execute); node_type_gpu(&ntype, gpu_group_execute); - + nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_curves.c b/source/blender/nodes/shader/nodes/node_shader_curves.c index 5dfeb883915..4f3dc92ad02 100644 --- a/source/blender/nodes/shader/nodes/node_shader_curves.c +++ b/source/blender/nodes/shader/nodes/node_shader_curves.c @@ -48,7 +48,7 @@ static bNodeSocketTemplate sh_node_curve_vec_out[] = { static void node_shader_exec_curve_vec(void *UNUSED(data), int UNUSED(thread), bNode *node, bNodeExecData *UNUSED(execdata), bNodeStack **in, bNodeStack **out) { float vec[3]; - + /* stack order input: vec */ /* stack order output: vec */ nodestack_get_vec(vec, SOCK_VECTOR, in[1]); @@ -102,7 +102,7 @@ static void node_shader_exec_curve_rgb(void *UNUSED(data), int UNUSED(thread), b { float vec[3]; float fac; - + /* stack order input: vec */ /* stack order output: vec */ nodestack_get_vec(&fac, SOCK_FLOAT, in[0]); diff --git a/source/blender/nodes/shader/nodes/node_shader_fresnel.c b/source/blender/nodes/shader/nodes/node_shader_fresnel.c index 599d0533c27..072abed6c16 100644 --- a/source/blender/nodes/shader/nodes/node_shader_fresnel.c +++ b/source/blender/nodes/shader/nodes/node_shader_fresnel.c @@ -47,7 +47,7 @@ static int node_shader_gpu_fresnel(GPUMaterial *mat, bNode *node, bNodeExecData else { GPU_link(mat, "direction_transform_m4v3", in[1].link, GPU_builtin(GPU_VIEW_MATRIX), &in[1].link); } - + return GPU_stack_link(mat, node, "node_fresnel", in, out, GPU_builtin(GPU_VIEW_POSITION)); } diff --git a/source/blender/nodes/shader/nodes/node_shader_gamma.c b/source/blender/nodes/shader/nodes/node_shader_gamma.c index 2aedba58f2c..e536d198ed0 100644 --- a/source/blender/nodes/shader/nodes/node_shader_gamma.c +++ b/source/blender/nodes/shader/nodes/node_shader_gamma.c @@ -60,7 +60,7 @@ static int node_shader_gpu_gamma(GPUMaterial *mat, bNode *node, bNodeExecData *U void register_node_type_sh_gamma(void) { static bNodeType ntype; - + sh_node_type_base(&ntype, SH_NODE_GAMMA, "Gamma", NODE_CLASS_OP_COLOR, 0); node_type_compatibility(&ntype, NODE_OLD_SHADING | NODE_NEW_SHADING); node_type_socket_templates(&ntype, sh_node_gamma_in, sh_node_gamma_out); @@ -68,6 +68,6 @@ void register_node_type_sh_gamma(void) node_type_storage(&ntype, "", NULL, NULL); node_type_exec(&ntype, NULL, NULL, node_shader_exec_gamma); node_type_gpu(&ntype, node_shader_gpu_gamma); - + nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_geom.c b/source/blender/nodes/shader/nodes/node_shader_geom.c new file mode 100644 index 00000000000..0a51ee8dc68 --- /dev/null +++ b/source/blender/nodes/shader/nodes/node_shader_geom.c @@ -0,0 +1,163 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2005 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/nodes/shader/nodes/node_shader_geom.c + * \ingroup shdnodes + */ + + +#include "node_shader_util.h" + +#include "DNA_customdata_types.h" + +/* **************** GEOMETRY ******************** */ + +/* output socket type definition */ +static bNodeSocketTemplate sh_node_geom_out[] = { + { SOCK_VECTOR, 0, N_("Global")}, + { SOCK_VECTOR, 0, N_("Local")}, + { SOCK_VECTOR, 0, N_("View")}, + { SOCK_VECTOR, 0, N_("Orco")}, + { SOCK_VECTOR, 0, N_("UV")}, + { SOCK_VECTOR, 0, N_("Normal")}, + { SOCK_RGBA, 0, N_("Vertex Color")}, + { SOCK_FLOAT, 0, N_("Vertex Alpha")}, + { SOCK_FLOAT, 0, N_("Front/Back")}, + { -1, 0, "" } +}; + +/* node execute callback */ +static void node_shader_exec_geom(void *data, int UNUSED(thread), bNode *node, bNodeExecData *UNUSED(execdata), bNodeStack **UNUSED(in), bNodeStack **out) +{ + if (data) { + ShadeInput *shi = ((ShaderCallData *)data)->shi; + NodeGeometry *ngeo = (NodeGeometry *)node->storage; + ShadeInputUV *suv = &shi->uv[shi->actuv]; + static float defaultvcol[4] = {1.0f, 1.0f, 1.0f, 1.0f}; + int i; + + if (ngeo->uvname[0]) { + /* find uv map by name */ + for (i = 0; i < shi->totuv; i++) { + if (STREQ(shi->uv[i].name, ngeo->uvname)) { + suv = &shi->uv[i]; + break; + } + } + } + + /* out: global, local, view, orco, uv, normal, vertex color */ + copy_v3_v3(out[GEOM_OUT_GLOB]->vec, shi->gl); + copy_v3_v3(out[GEOM_OUT_LOCAL]->vec, shi->co); + copy_v3_v3(out[GEOM_OUT_VIEW]->vec, shi->view); + copy_v3_v3(out[GEOM_OUT_ORCO]->vec, shi->lo); + copy_v3_v3(out[GEOM_OUT_UV]->vec, suv->uv); + copy_v3_v3(out[GEOM_OUT_NORMAL]->vec, shi->vno); + + if (shi->use_world_space_shading) { + negate_v3(out[GEOM_OUT_NORMAL]->vec); + mul_mat3_m4_v3((float (*)[4])RE_render_current_get_matrix(RE_VIEWINV_MATRIX), out[GEOM_OUT_NORMAL]->vec); + } + if (shi->totcol) { + /* find vertex color layer by name */ + ShadeInputCol *scol = &shi->col[0]; + + if (ngeo->colname[0]) { + for (i = 0; i < shi->totcol; i++) { + if (STREQ(shi->col[i].name, ngeo->colname)) { + scol = &shi->col[i]; + break; + } + } + } + + srgb_to_linearrgb_v3_v3(out[GEOM_OUT_VCOL]->vec, scol->col); + out[GEOM_OUT_VCOL]->vec[3] = scol->col[3]; + out[GEOM_OUT_VCOL_ALPHA]->vec[0] = scol->col[3]; + } + else { + memcpy(out[GEOM_OUT_VCOL]->vec, defaultvcol, sizeof(defaultvcol)); + out[GEOM_OUT_VCOL_ALPHA]->vec[0] = 1.0f; + } + + if (shi->osatex) { + out[GEOM_OUT_GLOB]->data = shi->dxgl; + out[GEOM_OUT_GLOB]->datatype = NS_OSA_VECTORS; + out[GEOM_OUT_LOCAL]->data = shi->dxco; + out[GEOM_OUT_LOCAL]->datatype = NS_OSA_VECTORS; + out[GEOM_OUT_VIEW]->data = &shi->dxview; + out[GEOM_OUT_VIEW]->datatype = NS_OSA_VALUES; + out[GEOM_OUT_ORCO]->data = shi->dxlo; + out[GEOM_OUT_ORCO]->datatype = NS_OSA_VECTORS; + out[GEOM_OUT_UV]->data = suv->dxuv; + out[GEOM_OUT_UV]->datatype = NS_OSA_VECTORS; + out[GEOM_OUT_NORMAL]->data = shi->dxno; + out[GEOM_OUT_NORMAL]->datatype = NS_OSA_VECTORS; + } + + /* front/back, normal flipping was stored */ + out[GEOM_OUT_FRONTBACK]->vec[0] = (shi->flippednor) ? 0.0f : 1.0f; + } +} + +static void node_shader_init_geometry(bNodeTree *UNUSED(ntree), bNode *node) +{ + node->storage = MEM_callocN(sizeof(NodeGeometry), "NodeGeometry"); +} + +static int gpu_shader_geom(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out) +{ + NodeGeometry *ngeo = (NodeGeometry *)node->storage; + GPUNodeLink *orco = GPU_attribute(CD_ORCO, ""); + GPUNodeLink *mtface = GPU_attribute(CD_MTFACE, ngeo->uvname); + GPUNodeLink *mcol = GPU_attribute(CD_MCOL, ngeo->colname); + + bool ret = GPU_stack_link(mat, "geom", in, out, + GPU_builtin(GPU_VIEW_POSITION), GPU_builtin(GPU_VIEW_NORMAL), + GPU_builtin(GPU_INVERSE_VIEW_MATRIX), orco, mtface, mcol); + if (GPU_material_use_world_space_shading(mat)) { + GPU_link(mat, "vec_math_negate", out[5].link, &out[5].link); + ret &= GPU_link(mat, "direction_transform_m4v3", out[5].link, GPU_builtin(GPU_INVERSE_VIEW_MATRIX), &out[5].link); + } + return ret; +} + +/* node type definition */ +void register_node_type_sh_geom(void) +{ + static bNodeType ntype; + + sh_node_type_base(&ntype, SH_NODE_GEOMETRY, "Geometry", NODE_CLASS_INPUT, 0); + node_type_compatibility(&ntype, NODE_OLD_SHADING); + node_type_socket_templates(&ntype, NULL, sh_node_geom_out); + node_type_init(&ntype, node_shader_init_geometry); + node_type_storage(&ntype, "NodeGeometry", node_free_standard_storage, node_copy_standard_storage); + node_type_exec(&ntype, NULL, NULL, node_shader_exec_geom); + node_type_gpu(&ntype, gpu_shader_geom); + + nodeRegisterType(&ntype); +} diff --git a/source/blender/nodes/shader/nodes/node_shader_hueSatVal.c b/source/blender/nodes/shader/nodes/node_shader_hueSatVal.c index 0e82c962f53..07f1e9e3233 100644 --- a/source/blender/nodes/shader/nodes/node_shader_hueSatVal.c +++ b/source/blender/nodes/shader/nodes/node_shader_hueSatVal.c @@ -52,7 +52,7 @@ static void do_hue_sat_fac(bNode *UNUSED(node), float *out, float hue, float sat { if (fac != 0.0f && (hue != 0.5f || sat != 1.0f || val != 1.0f)) { float col[3], hsv[3], mfac = 1.0f - fac; - + rgb_to_hsv(in[0], in[1], in[2], hsv, hsv + 1, hsv + 2); hsv[0] += (hue - 0.5f); if (hsv[0] > 1.0f) hsv[0] -= 1.0f; else if (hsv[0] < 0.0f) hsv[0] += 1.0f; diff --git a/source/blender/nodes/shader/nodes/node_shader_invert.c b/source/blender/nodes/shader/nodes/node_shader_invert.c index c5765ae492b..b1805946f65 100644 --- a/source/blender/nodes/shader/nodes/node_shader_invert.c +++ b/source/blender/nodes/shader/nodes/node_shader_invert.c @@ -34,7 +34,7 @@ -/* **************** INVERT ******************** */ +/* **************** INVERT ******************** */ static bNodeSocketTemplate sh_node_invert_in[] = { { SOCK_FLOAT, 1, N_("Fac"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR}, { SOCK_RGBA, 1, N_("Color"), 0.0f, 0.0f, 0.0f, 1.0f}, @@ -46,18 +46,18 @@ static bNodeSocketTemplate sh_node_invert_out[] = { { -1, 0, "" } }; -static void node_shader_exec_invert(void *UNUSED(data), int UNUSED(thread), bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), bNodeStack **in, +static void node_shader_exec_invert(void *UNUSED(data), int UNUSED(thread), bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), bNodeStack **in, bNodeStack **out) { float col[3], icol[3], fac; nodestack_get_vec(&fac, SOCK_FLOAT, in[0]); nodestack_get_vec(col, SOCK_VECTOR, in[1]); - + icol[0] = 1.0f - col[0]; icol[1] = 1.0f - col[1]; icol[2] = 1.0f - col[2]; - + /* if fac, blend result against original input */ if (fac < 1.0f) interp_v3_v3v3(out[0]->vec, col, icol, fac); diff --git a/source/blender/nodes/shader/nodes/node_shader_mapping.c b/source/blender/nodes/shader/nodes/node_shader_mapping.c index 42d957977e3..fdbf23618ef 100644 --- a/source/blender/nodes/shader/nodes/node_shader_mapping.c +++ b/source/blender/nodes/shader/nodes/node_shader_mapping.c @@ -56,7 +56,7 @@ static void node_shader_exec_mapping(void *UNUSED(data), int UNUSED(thread), bNo { TexMapping *texmap = node->storage; float *vec = out[0]->vec; - + /* stack order input: vector */ /* stack order output: vector */ nodestack_get_vec(vec, SOCK_VECTOR, in[0]); @@ -105,7 +105,7 @@ static int gpu_shader_mapping(GPUMaterial *mat, bNode *node, bNodeExecData *UNUS void register_node_type_sh_mapping(void) { static bNodeType ntype; - + sh_node_type_base(&ntype, SH_NODE_MAPPING, "Mapping", NODE_CLASS_OP_VECTOR, 0); node_type_compatibility(&ntype, NODE_OLD_SHADING | NODE_NEW_SHADING); node_type_socket_templates(&ntype, sh_node_mapping_in, sh_node_mapping_out); @@ -114,6 +114,6 @@ void register_node_type_sh_mapping(void) node_type_storage(&ntype, "TexMapping", node_free_standard_storage, node_copy_standard_storage); node_type_exec(&ntype, node_shader_initexec_mapping, NULL, node_shader_exec_mapping); node_type_gpu(&ntype, gpu_shader_mapping); - + nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_material.c b/source/blender/nodes/shader/nodes/node_shader_material.c new file mode 100644 index 00000000000..8a73ddc1194 --- /dev/null +++ b/source/blender/nodes/shader/nodes/node_shader_material.c @@ -0,0 +1,374 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2005 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/nodes/shader/nodes/node_shader_material.c + * \ingroup shdnodes + */ + +#include "node_shader_util.h" + +/* **************** MATERIAL ******************** */ + +static bNodeSocketTemplate sh_node_material_in[] = { + { SOCK_RGBA, 1, N_("Color"), 0.0f, 0.0f, 0.0f, 1.0f}, + { SOCK_RGBA, 1, N_("Spec"), 0.0f, 0.0f, 0.0f, 1.0f}, + { SOCK_FLOAT, 1, N_("DiffuseIntensity"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE}, + { SOCK_VECTOR, 1, N_("Normal"), 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_DIRECTION}, + { -1, 0, "" } +}; + +static bNodeSocketTemplate sh_node_material_out[] = { + { SOCK_RGBA, 0, N_("Color")}, + { SOCK_FLOAT, 0, N_("Alpha")}, + { SOCK_VECTOR, 0, N_("Normal")}, + { -1, 0, "" } +}; + +/* **************** EXTENDED MATERIAL ******************** */ + +static bNodeSocketTemplate sh_node_material_ext_in[] = { + { SOCK_RGBA, 1, N_("Color"), 0.0f, 0.0f, 0.0f, 1.0f}, + { SOCK_RGBA, 1, N_("Spec"), 0.0f, 0.0f, 0.0f, 1.0f}, + { SOCK_FLOAT, 1, N_("DiffuseIntensity"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE}, + { SOCK_VECTOR, 1, N_("Normal"), 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_DIRECTION}, + { SOCK_RGBA, 1, N_("Mirror"), 0.0f, 0.0f, 0.0f, 1.0f}, + { SOCK_FLOAT, 1, N_("Ambient"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE}, + { SOCK_FLOAT, 1, N_("Emit"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_UNSIGNED}, + { SOCK_FLOAT, 1, N_("SpecTra"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE}, + { SOCK_FLOAT, 1, N_("Reflectivity"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE}, + { SOCK_FLOAT, 1, N_("Alpha"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_UNSIGNED}, + { SOCK_FLOAT, 1, N_("Translucency"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE}, + { -1, 0, "" } +}; + +static bNodeSocketTemplate sh_node_material_ext_out[] = { + { SOCK_RGBA, 0, N_("Color")}, + { SOCK_FLOAT, 0, N_("Alpha")}, + { SOCK_VECTOR, 0, N_("Normal")}, + { SOCK_RGBA, 0, N_("Diffuse")}, + { SOCK_RGBA, 0, N_("Spec")}, + { SOCK_RGBA, 0, N_("AO")}, + { -1, 0, "" } +}; + +static void node_shader_exec_material(void *data, int UNUSED(thread), bNode *node, bNodeExecData *execdata, bNodeStack **in, bNodeStack **out) +{ + if (data && node->id) { + ShadeResult shrnode; + ShadeInput *shi; + ShaderCallData *shcd = data; + float col[4]; + bNodeSocket *sock; + char hasinput[NUM_MAT_IN] = {'\0'}; + int i, mode; + + /* note: cannot use the in[]->hasinput flags directly, as these are not necessarily + * the constant input stack values (e.g. in case material node is inside a group). + * we just want to know if a node input uses external data or the material setting. + * this is an ugly hack, but so is this node as a whole. + */ + for (sock = node->inputs.first, i = 0; sock; sock = sock->next, ++i) + hasinput[i] = (sock->link != NULL); + + shi = shcd->shi; + shi->mat = (Material *)node->id; + + /* copy all relevant material vars, note, keep this synced with render_types.h */ + memcpy(&shi->r, &shi->mat->r, 23 * sizeof(float)); + shi->har = shi->mat->har; + + /* write values */ + if (hasinput[MAT_IN_COLOR]) + nodestack_get_vec(&shi->r, SOCK_VECTOR, in[MAT_IN_COLOR]); + + if (hasinput[MAT_IN_SPEC]) + nodestack_get_vec(&shi->specr, SOCK_VECTOR, in[MAT_IN_SPEC]); + + if (hasinput[MAT_IN_REFL]) + nodestack_get_vec(&shi->refl, SOCK_FLOAT, in[MAT_IN_REFL]); + + /* retrieve normal */ + if (hasinput[MAT_IN_NORMAL]) { + nodestack_get_vec(shi->vn, SOCK_VECTOR, in[MAT_IN_NORMAL]); + if (shi->use_world_space_shading) { + negate_v3(shi->vn); + mul_mat3_m4_v3((float (*)[4])RE_render_current_get_matrix(RE_VIEW_MATRIX), shi->vn); + } + normalize_v3(shi->vn); + } + else + copy_v3_v3(shi->vn, shi->vno); + + /* custom option to flip normal */ + if (node->custom1 & SH_NODE_MAT_NEG) { + negate_v3(shi->vn); + } + + if (node->type == SH_NODE_MATERIAL_EXT) { + if (hasinput[MAT_IN_MIR]) + nodestack_get_vec(&shi->mirr, SOCK_VECTOR, in[MAT_IN_MIR]); + if (hasinput[MAT_IN_AMB]) + nodestack_get_vec(&shi->amb, SOCK_FLOAT, in[MAT_IN_AMB]); + if (hasinput[MAT_IN_EMIT]) + nodestack_get_vec(&shi->emit, SOCK_FLOAT, in[MAT_IN_EMIT]); + if (hasinput[MAT_IN_SPECTRA]) + nodestack_get_vec(&shi->spectra, SOCK_FLOAT, in[MAT_IN_SPECTRA]); + if (hasinput[MAT_IN_RAY_MIRROR]) + nodestack_get_vec(&shi->ray_mirror, SOCK_FLOAT, in[MAT_IN_RAY_MIRROR]); + if (hasinput[MAT_IN_ALPHA]) + nodestack_get_vec(&shi->alpha, SOCK_FLOAT, in[MAT_IN_ALPHA]); + if (hasinput[MAT_IN_TRANSLUCENCY]) + nodestack_get_vec(&shi->translucency, SOCK_FLOAT, in[MAT_IN_TRANSLUCENCY]); + } + + /* make alpha output give results even if transparency is only enabled on + * the material linked in this not and not on the parent material */ + mode = shi->mode; + if (shi->mat->mode & MA_TRANSP) + shi->mode |= MA_TRANSP; + + shi->nodes = 1; /* temp hack to prevent trashadow recursion */ + node_shader_lamp_loop(shi, &shrnode); /* clears shrnode */ + shi->nodes = 0; + + shi->mode = mode; + + /* write to outputs */ + if (node->custom1 & SH_NODE_MAT_DIFF) { + copy_v3_v3(col, shrnode.combined); + if (!(node->custom1 & SH_NODE_MAT_SPEC)) { + sub_v3_v3(col, shrnode.spec); + } + } + else if (node->custom1 & SH_NODE_MAT_SPEC) { + copy_v3_v3(col, shrnode.spec); + } + else + col[0] = col[1] = col[2] = 0.0f; + + col[3] = shrnode.alpha; + + if (shi->do_preview) + BKE_node_preview_set_pixel(execdata->preview, col, shi->xs, shi->ys, shi->do_manage); + + copy_v3_v3(out[MAT_OUT_COLOR]->vec, col); + out[MAT_OUT_ALPHA]->vec[0] = shrnode.alpha; + + if (node->custom1 & SH_NODE_MAT_NEG) { + shi->vn[0] = -shi->vn[0]; + shi->vn[1] = -shi->vn[1]; + shi->vn[2] = -shi->vn[2]; + } + + copy_v3_v3(out[MAT_OUT_NORMAL]->vec, shi->vn); + + if (shi->use_world_space_shading) { + negate_v3(out[MAT_OUT_NORMAL]->vec); + mul_mat3_m4_v3((float (*)[4])RE_render_current_get_matrix(RE_VIEWINV_MATRIX), out[MAT_OUT_NORMAL]->vec); + } + /* Extended material options */ + if (node->type == SH_NODE_MATERIAL_EXT) { + /* Shadow, Reflect, Refract, Radiosity, Speed seem to cause problems inside + * a node tree :( */ + copy_v3_v3(out[MAT_OUT_DIFFUSE]->vec, shrnode.diffshad); + copy_v3_v3(out[MAT_OUT_SPEC]->vec, shrnode.spec); + copy_v3_v3(out[MAT_OUT_AO]->vec, shrnode.ao); + } + + /* copy passes, now just active node */ + if (node->flag & NODE_ACTIVE_ID) { + float combined[4], alpha; + + copy_v4_v4(combined, shcd->shr->combined); + alpha = shcd->shr->alpha; + + *(shcd->shr) = shrnode; + + copy_v4_v4(shcd->shr->combined, combined); + shcd->shr->alpha = alpha; + } + } +} + + +static void node_shader_init_material(bNodeTree *UNUSED(ntree), bNode *node) +{ + node->custom1 = SH_NODE_MAT_DIFF | SH_NODE_MAT_SPEC; +} + +/* XXX this is also done as a local static function in gpu_codegen.c, + * but we need this to hack around the crappy material node. + */ +static GPUNodeLink *gpu_get_input_link(GPUMaterial *mat, GPUNodeStack *in) +{ + if (in->link) { + return in->link; + } + else { + GPUNodeLink *result = NULL; + + /* note GPU_uniform() is only intended to be used as a parameter to + * GPU_link(), returning it directly results in leaks or double frees */ + if (in->type == GPU_FLOAT) + GPU_link(mat, "set_value", GPU_uniform(in->vec), &result); + else if (in->type == GPU_VEC3) + GPU_link(mat, "set_rgb", GPU_uniform(in->vec), &result); + else if (in->type == GPU_VEC4) + GPU_link(mat, "set_rgba", GPU_uniform(in->vec), &result); + else + BLI_assert(0); + + return result; + } +} + +static int gpu_shader_material(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out) +{ + if (node->id) { + GPUShadeInput shi; + GPUShadeResult shr; + bNodeSocket *sock; + char hasinput[NUM_MAT_IN] = {'\0'}; + int i; + + /* note: cannot use the in[]->hasinput flags directly, as these are not necessarily + * the constant input stack values (e.g. in case material node is inside a group). + * we just want to know if a node input uses external data or the material setting. + */ + for (sock = node->inputs.first, i = 0; sock; sock = sock->next, ++i) + hasinput[i] = (sock->link != NULL); + + GPU_shadeinput_set(mat, (Material *)node->id, &shi); + + /* write values */ + if (hasinput[MAT_IN_COLOR]) + shi.rgb = gpu_get_input_link(mat, &in[MAT_IN_COLOR]); + + if (hasinput[MAT_IN_SPEC]) + shi.specrgb = gpu_get_input_link(mat, &in[MAT_IN_SPEC]); + + if (hasinput[MAT_IN_REFL]) + shi.refl = gpu_get_input_link(mat, &in[MAT_IN_REFL]); + + /* retrieve normal */ + if (hasinput[MAT_IN_NORMAL]) { + GPUNodeLink *tmp; + shi.vn = gpu_get_input_link(mat, &in[MAT_IN_NORMAL]); + if (GPU_material_use_world_space_shading(mat)) { + GPU_link(mat, "vec_math_negate", shi.vn, &shi.vn); + GPU_link(mat, "direction_transform_m4v3", shi.vn, GPU_builtin(GPU_VIEW_MATRIX), &shi.vn); + } + GPU_link(mat, "vec_math_normalize", shi.vn, &shi.vn, &tmp); + } + + /* custom option to flip normal */ + if (node->custom1 & SH_NODE_MAT_NEG) + GPU_link(mat, "vec_math_negate", shi.vn, &shi.vn); + + if (node->type == SH_NODE_MATERIAL_EXT) { + if (hasinput[MAT_IN_MIR]) + shi.mir = gpu_get_input_link(mat, &in[MAT_IN_MIR]); + if (hasinput[MAT_IN_AMB]) + shi.amb = gpu_get_input_link(mat, &in[MAT_IN_AMB]); + if (hasinput[MAT_IN_EMIT]) + shi.emit = gpu_get_input_link(mat, &in[MAT_IN_EMIT]); + if (hasinput[MAT_IN_SPECTRA]) + shi.spectra = gpu_get_input_link(mat, &in[MAT_IN_SPECTRA]); + if (hasinput[MAT_IN_ALPHA]) + shi.alpha = gpu_get_input_link(mat, &in[MAT_IN_ALPHA]); + } + + GPU_shaderesult_set(&shi, &shr); /* clears shr */ + + /* write to outputs */ + if (node->custom1 & SH_NODE_MAT_DIFF) { + out[MAT_OUT_COLOR].link = shr.combined; + + if (!(node->custom1 & SH_NODE_MAT_SPEC)) { + GPUNodeLink *link; + GPU_link(mat, "vec_math_sub", shr.combined, shr.spec, &out[MAT_OUT_COLOR].link, &link); + } + } + else if (node->custom1 & SH_NODE_MAT_SPEC) { + out[MAT_OUT_COLOR].link = shr.spec; + } + else + GPU_link(mat, "set_rgb_zero", &out[MAT_OUT_COLOR].link); + + GPU_link(mat, "mtex_alpha_to_col", out[MAT_OUT_COLOR].link, shr.alpha, &out[MAT_OUT_COLOR].link); + + out[MAT_OUT_ALPHA].link = shr.alpha; // + + if (node->custom1 & SH_NODE_MAT_NEG) + GPU_link(mat, "vec_math_negate", shi.vn, &shi.vn); + out[MAT_OUT_NORMAL].link = shi.vn; + if (GPU_material_use_world_space_shading(mat)) { + GPU_link(mat, "vec_math_negate", out[MAT_OUT_NORMAL].link, &out[MAT_OUT_NORMAL].link); + GPU_link(mat, "direction_transform_m4v3", out[MAT_OUT_NORMAL].link, GPU_builtin(GPU_INVERSE_VIEW_MATRIX), &out[MAT_OUT_NORMAL].link); + } + + if (node->type == SH_NODE_MATERIAL_EXT) { + out[MAT_OUT_DIFFUSE].link = shr.diff; + out[MAT_OUT_SPEC].link = shr.spec; + GPU_link(mat, "set_rgb_one", &out[MAT_OUT_AO].link); + } + + return 1; + } + + return 0; +} + +void register_node_type_sh_material(void) +{ + static bNodeType ntype; + + sh_node_type_base(&ntype, SH_NODE_MATERIAL, "Material", NODE_CLASS_INPUT, NODE_PREVIEW); + node_type_compatibility(&ntype, NODE_OLD_SHADING); + node_type_socket_templates(&ntype, sh_node_material_in, sh_node_material_out); + node_type_init(&ntype, node_shader_init_material); + node_type_exec(&ntype, NULL, NULL, node_shader_exec_material); + node_type_gpu(&ntype, gpu_shader_material); + + nodeRegisterType(&ntype); +} + + +void register_node_type_sh_material_ext(void) +{ + static bNodeType ntype; + + sh_node_type_base(&ntype, SH_NODE_MATERIAL_EXT, "Extended Material", NODE_CLASS_INPUT, NODE_PREVIEW); + node_type_compatibility(&ntype, NODE_OLD_SHADING); + node_type_socket_templates(&ntype, sh_node_material_ext_in, sh_node_material_ext_out); + node_type_init(&ntype, node_shader_init_material); + node_type_size_preset(&ntype, NODE_SIZE_MIDDLE); + node_type_exec(&ntype, NULL, NULL, node_shader_exec_material); + node_type_gpu(&ntype, gpu_shader_material); + + nodeRegisterType(&ntype); +} diff --git a/source/blender/nodes/shader/nodes/node_shader_math.c b/source/blender/nodes/shader/nodes/node_shader_math.c index 2be70b66b36..bf594325119 100644 --- a/source/blender/nodes/shader/nodes/node_shader_math.c +++ b/source/blender/nodes/shader/nodes/node_shader_math.c @@ -33,7 +33,7 @@ #include "node_shader_util.h" -/* **************** SCALAR MATH ******************** */ +/* **************** SCALAR MATH ******************** */ static bNodeSocketTemplate sh_node_math_in[] = { { SOCK_FLOAT, 1, N_("Value"), 0.5f, 0.5f, 0.5f, 1.0f, -10000.0f, 10000.0f, PROP_NONE}, { SOCK_FLOAT, 1, N_("Value"), 0.5f, 0.5f, 0.5f, 1.0f, -10000.0f, 10000.0f, PROP_NONE}, @@ -45,15 +45,15 @@ static bNodeSocketTemplate sh_node_math_out[] = { { -1, 0, "" } }; -static void node_shader_exec_math(void *UNUSED(data), int UNUSED(thread), bNode *node, bNodeExecData *UNUSED(execdata), bNodeStack **in, bNodeStack **out) +static void node_shader_exec_math(void *UNUSED(data), int UNUSED(thread), bNode *node, bNodeExecData *UNUSED(execdata), bNodeStack **in, bNodeStack **out) { float a, b, r = 0.0f; - + nodestack_get_vec(&a, SOCK_FLOAT, in[0]); nodestack_get_vec(&b, SOCK_FLOAT, in[1]); - + switch (node->custom1) { - + case NODE_MATH_ADD: r = a + b; break; @@ -147,7 +147,7 @@ static void node_shader_exec_math(void *UNUSED(data), int UNUSED(thread), bNode } else { float y_mod_1 = fabsf(fmodf(b, 1.0f)); - + /* if input value is not nearly an integer, fall back to zero, nicer than straight rounding */ if (y_mod_1 > 0.999f || y_mod_1 < 0.001f) { r = powf(a, floorf(b + 0.5f)); diff --git a/source/blender/nodes/shader/nodes/node_shader_mixRgb.c b/source/blender/nodes/shader/nodes/node_shader_mixRgb.c index 37ec4d46226..054b02b220d 100644 --- a/source/blender/nodes/shader/nodes/node_shader_mixRgb.c +++ b/source/blender/nodes/shader/nodes/node_shader_mixRgb.c @@ -54,7 +54,7 @@ static void node_shader_exec_mix_rgb(void *UNUSED(data), int UNUSED(thread), bNo nodestack_get_vec(&fac, SOCK_FLOAT, in[0]); CLAMP(fac, 0.0f, 1.0f); - + nodestack_get_vec(col, SOCK_VECTOR, in[1]); nodestack_get_vec(vec, SOCK_VECTOR, in[2]); diff --git a/source/blender/nodes/shader/nodes/node_shader_normal.c b/source/blender/nodes/shader/nodes/node_shader_normal.c index 4bca5add106..265f6ac6fab 100644 --- a/source/blender/nodes/shader/nodes/node_shader_normal.c +++ b/source/blender/nodes/shader/nodes/node_shader_normal.c @@ -48,12 +48,12 @@ static bNodeSocketTemplate sh_node_normal_out[] = { static void node_shader_exec_normal(void *UNUSED(data), int UNUSED(thread), bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), bNodeStack **in, bNodeStack **out) { float vec[3]; - + /* stack order input: normal */ /* stack order output: normal, value */ - + nodestack_get_vec(vec, SOCK_VECTOR, in[0]); - + /* render normals point inside... the widget points outside */ out[1]->vec[0] = -dot_v3v3(vec, out[0]->vec); } @@ -67,12 +67,12 @@ static int gpu_shader_normal(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSE void register_node_type_sh_normal(void) { static bNodeType ntype; - + sh_node_type_base(&ntype, SH_NODE_NORMAL, "Normal", NODE_CLASS_OP_VECTOR, 0); node_type_compatibility(&ntype, NODE_OLD_SHADING | NODE_NEW_SHADING); node_type_socket_templates(&ntype, sh_node_normal_in, sh_node_normal_out); node_type_exec(&ntype, NULL, NULL, node_shader_exec_normal); node_type_gpu(&ntype, gpu_shader_normal); - + nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_output.c b/source/blender/nodes/shader/nodes/node_shader_output.c new file mode 100644 index 00000000000..5b1a68b4bf9 --- /dev/null +++ b/source/blender/nodes/shader/nodes/node_shader_output.c @@ -0,0 +1,97 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2005 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/nodes/shader/nodes/node_shader_output.c + * \ingroup shdnodes + */ + + +#include "node_shader_util.h" + +/* **************** OUTPUT ******************** */ +static bNodeSocketTemplate sh_node_output_in[] = { + { SOCK_RGBA, 1, N_("Color"), 0.0f, 0.0f, 0.0f, 1.0f}, + { SOCK_FLOAT, 1, N_("Alpha"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE}, + { -1, 0, "" } +}; + +static void node_shader_exec_output(void *data, int UNUSED(thread), bNode *node, bNodeExecData *execdata, bNodeStack **in, bNodeStack **UNUSED(out)) +{ + if (data) { + ShadeInput *shi = ((ShaderCallData *)data)->shi; + float col[4]; + + /* stack order input sockets: col, alpha, normal */ + nodestack_get_vec(col, SOCK_VECTOR, in[0]); + nodestack_get_vec(col + 3, SOCK_FLOAT, in[1]); + + if (shi->do_preview) { + BKE_node_preview_set_pixel(execdata->preview, col, shi->xs, shi->ys, shi->do_manage); + node->lasty = shi->ys; + } + + if (node->flag & NODE_DO_OUTPUT) { + ShadeResult *shr = ((ShaderCallData *)data)->shr; + + copy_v4_v4(shr->combined, col); + shr->alpha = col[3]; + + // copy_v3_v3(shr->nor, in[3]->vec); + } + } +} + +static int gpu_shader_output(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out) +{ + GPUNodeLink *outlink; + +#if 0 + if (in[1].hasinput) + GPU_material_enable_alpha(mat); +#endif + + GPU_stack_link(mat, "output_node", in, out, &outlink); + GPU_material_output_link(mat, outlink); + + return 1; +} + +void register_node_type_sh_output(void) +{ + static bNodeType ntype; + + sh_node_type_base(&ntype, SH_NODE_OUTPUT, "Output", NODE_CLASS_OUTPUT, NODE_PREVIEW); + node_type_compatibility(&ntype, NODE_OLD_SHADING); + node_type_socket_templates(&ntype, sh_node_output_in, NULL); + node_type_exec(&ntype, NULL, NULL, node_shader_exec_output); + node_type_gpu(&ntype, gpu_shader_output); + + /* Do not allow muting output node. */ + node_type_internal_links(&ntype, NULL); + + nodeRegisterType(&ntype); +} diff --git a/source/blender/nodes/shader/nodes/node_shader_output_world.c b/source/blender/nodes/shader/nodes/node_shader_output_world.c index 17b4bfb6de6..2c115bdda20 100644 --- a/source/blender/nodes/shader/nodes/node_shader_output_world.c +++ b/source/blender/nodes/shader/nodes/node_shader_output_world.c @@ -56,7 +56,7 @@ void register_node_type_sh_output_world(void) node_type_init(&ntype, NULL); node_type_storage(&ntype, "", NULL, NULL); node_type_gpu(&ntype, node_shader_gpu_output_world); - + /* Do not allow muting output node. */ node_type_internal_links(&ntype, NULL); diff --git a/source/blender/nodes/shader/nodes/node_shader_sepcombHSV.c b/source/blender/nodes/shader/nodes/node_shader_sepcombHSV.c index 19f31f77989..148f8e99c8f 100644 --- a/source/blender/nodes/shader/nodes/node_shader_sepcombHSV.c +++ b/source/blender/nodes/shader/nodes/node_shader_sepcombHSV.c @@ -48,7 +48,7 @@ static void node_shader_exec_sephsv(void *UNUSED(data), int UNUSED(thread), bNod { float col[3]; nodestack_get_vec(col, SOCK_VECTOR, in[0]); - + rgb_to_hsv(col[0], col[1], col[2], &out[0]->vec[0], &out[1]->vec[0], &out[2]->vec[0]); } @@ -90,7 +90,7 @@ static void node_shader_exec_combhsv(void *UNUSED(data), int UNUSED(thread), bNo nodestack_get_vec(&h, SOCK_FLOAT, in[0]); nodestack_get_vec(&s, SOCK_FLOAT, in[1]); nodestack_get_vec(&v, SOCK_FLOAT, in[2]); - + hsv_to_rgb(h, s, v, &out[0]->vec[0], &out[0]->vec[1], &out[0]->vec[2]); } diff --git a/source/blender/nodes/shader/nodes/node_shader_sepcombRGB.c b/source/blender/nodes/shader/nodes/node_shader_sepcombRGB.c index 3f866af5de4..bd914399a28 100644 --- a/source/blender/nodes/shader/nodes/node_shader_sepcombRGB.c +++ b/source/blender/nodes/shader/nodes/node_shader_sepcombRGB.c @@ -48,7 +48,7 @@ static void node_shader_exec_seprgb(void *UNUSED(data), int UNUSED(thread), bNod { float col[3]; nodestack_get_vec(col, SOCK_VECTOR, in[0]); - + out[0]->vec[0] = col[0]; out[1]->vec[0] = col[1]; out[2]->vec[0] = col[2]; @@ -92,7 +92,7 @@ static void node_shader_exec_combrgb(void *UNUSED(data), int UNUSED(thread), bNo nodestack_get_vec(&r, SOCK_FLOAT, in[0]); nodestack_get_vec(&g, SOCK_FLOAT, in[1]); nodestack_get_vec(&b, SOCK_FLOAT, in[2]); - + out[0]->vec[0] = r; out[0]->vec[1] = g; out[0]->vec[2] = b; diff --git a/source/blender/nodes/shader/nodes/node_shader_squeeze.c b/source/blender/nodes/shader/nodes/node_shader_squeeze.c index 2175a7c564f..e46494efd34 100644 --- a/source/blender/nodes/shader/nodes/node_shader_squeeze.c +++ b/source/blender/nodes/shader/nodes/node_shader_squeeze.c @@ -32,7 +32,7 @@ #include "node_shader_util.h" -/* **************** VALUE SQUEEZE ******************** */ +/* **************** VALUE SQUEEZE ******************** */ static bNodeSocketTemplate sh_node_squeeze_in[] = { { SOCK_FLOAT, 1, N_("Value"), 0.0f, 0.0f, 0.0f, 0.0f, -100.0f, 100.0f, PROP_NONE}, { SOCK_FLOAT, 1, N_("Width"), 1.0f, 0.0f, 0.0f, 0.0f, -100.0f, 100.0f, PROP_NONE}, @@ -48,7 +48,7 @@ static bNodeSocketTemplate sh_node_squeeze_out[] = { static void node_shader_exec_squeeze(void *UNUSED(data), int UNUSED(thread), bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), bNodeStack **in, bNodeStack **out) { float vec[3]; - + nodestack_get_vec(vec, SOCK_FLOAT, in[0]); nodestack_get_vec(vec + 1, SOCK_FLOAT, in[1]); nodestack_get_vec(vec + 2, SOCK_FLOAT, in[2]); diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_brick.c b/source/blender/nodes/shader/nodes/node_shader_tex_brick.c index c919f8efa4e..67fe6d08ffd 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_brick.c +++ b/source/blender/nodes/shader/nodes/node_shader_tex_brick.c @@ -54,7 +54,7 @@ static void node_shader_init_tex_brick(bNodeTree *UNUSED(ntree), bNode *node) NodeTexBrick *tex = MEM_callocN(sizeof(NodeTexBrick), "NodeTexBrick"); BKE_texture_mapping_default(&tex->base.tex_mapping, TEXMAP_TYPE_POINT); BKE_texture_colormapping_default(&tex->base.color_mapping); - + tex->offset = 0.5f; tex->squash = 1.0f; tex->offset_freq = 2; diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_coord.c b/source/blender/nodes/shader/nodes/node_shader_tex_coord.c index 111a9cbfbc0..360b28d768a 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_coord.c +++ b/source/blender/nodes/shader/nodes/node_shader_tex_coord.c @@ -49,7 +49,7 @@ static int node_shader_gpu_tex_coord(GPUMaterial *mat, bNode *node, bNodeExecDat GPUMatType type = GPU_Material_get_type(mat); GPU_link(mat, "generated_from_orco", orco, &orco); - + if (type == GPU_MATERIAL_TYPE_WORLD) { return GPU_stack_link(mat, node, "node_tex_coord_background", in, out, GPU_builtin(GPU_VIEW_POSITION), GPU_builtin(GPU_VIEW_NORMAL), @@ -59,7 +59,7 @@ static int node_shader_gpu_tex_coord(GPUMaterial *mat, bNode *node, bNodeExecDat else { return GPU_stack_link(mat, node, "node_tex_coord", in, out, GPU_builtin(GPU_VIEW_POSITION), GPU_builtin(GPU_VIEW_NORMAL), - GPU_builtin(GPU_INVERSE_VIEW_MATRIX), GPU_builtin(GPU_INVERSE_OBJECT_MATRIX), + GPU_builtin(GPU_INVERSE_VIEW_MATRIX), GPU_builtin(GPU_INVERSE_OBJECT_MATRIX), GPU_builtin(GPU_CAMERA_TEXCO_FACTORS), orco, mtface); } } diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_environment.c b/source/blender/nodes/shader/nodes/node_shader_tex_environment.c index 378da163f64..d441a674838 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_environment.c +++ b/source/blender/nodes/shader/nodes/node_shader_tex_environment.c @@ -66,20 +66,20 @@ static int node_shader_gpu_tex_environment(GPUMaterial *mat, bNode *node, bNodeE if (!in[0].link) { GPUMatType type = GPU_Material_get_type(mat); - + if (type == GPU_MATERIAL_TYPE_MESH) in[0].link = GPU_builtin(GPU_VIEW_POSITION); else GPU_link(mat, "background_transform_to_world", GPU_builtin(GPU_VIEW_POSITION), &in[0].link); } - + node_shader_gpu_tex_mapping(mat, node, in, out); if (tex->projection == SHD_PROJ_EQUIRECTANGULAR) GPU_stack_link(mat, node, "node_tex_environment_equirectangular", in, out, GPU_image(ima, iuser, isdata)); else GPU_stack_link(mat, node, "node_tex_environment_mirror_ball", in, out, GPU_image(ima, iuser, isdata)); - + ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, NULL); if (ibuf && (ibuf->colormanage_flag & IMB_COLORMANAGE_IS_DATA) == 0 && GPU_material_do_color_management(mat)) diff --git a/source/blender/nodes/shader/nodes/node_shader_texture.c b/source/blender/nodes/shader/nodes/node_shader_texture.c new file mode 100644 index 00000000000..737ec7d1c4b --- /dev/null +++ b/source/blender/nodes/shader/nodes/node_shader_texture.c @@ -0,0 +1,166 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2005 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/nodes/shader/nodes/node_shader_texture.c + * \ingroup shdnodes + */ + +#include "DNA_texture_types.h" + +#include "node_shader_util.h" + +#include "GPU_material.h" + +/* **************** TEXTURE ******************** */ +static bNodeSocketTemplate sh_node_texture_in[] = { + { SOCK_VECTOR, 1, "Vector", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE}, /* no limit */ + { -1, 0, "" } +}; +static bNodeSocketTemplate sh_node_texture_out[] = { + { SOCK_FLOAT, 0, N_("Value"), 0, 0, 0, 0, 0, 0, PROP_NONE, SOCK_NO_INTERNAL_LINK}, + { SOCK_RGBA, 0, N_("Color"), 0, 0, 0, 0, 0, 0, PROP_NONE, SOCK_NO_INTERNAL_LINK}, + { SOCK_VECTOR, 0, N_("Normal"), 0, 0, 0, 0, 0, 0, PROP_NONE, SOCK_NO_INTERNAL_LINK}, + { -1, 0, "" } +}; + +static void node_shader_exec_texture(void *data, int UNUSED(thread), bNode *node, bNodeExecData *execdata, bNodeStack **in, bNodeStack **out) +{ + if (data && node->id) { + ShadeInput *shi = ((ShaderCallData *)data)->shi; + TexResult texres; + bNodeSocket *sock_vector = node->inputs.first; + float vec[3], nor[3] = {0.0f, 0.0f, 0.0f}; + int retval; + short which_output = node->custom1; + + short thread = shi->thread; + + /* out: value, color, normal */ + + /* we should find out if a normal as output is needed, for now we do all */ + texres.nor = nor; + texres.tr = texres.tg = texres.tb = 0.0f; + + /* don't use in[0]->hasinput, see material node for explanation */ + if (sock_vector->link) { + nodestack_get_vec(vec, SOCK_VECTOR, in[0]); + + if (in[0]->datatype == NS_OSA_VECTORS) { + float *fp = in[0]->data; + retval = multitex_nodes((Tex *)node->id, vec, fp, fp + 3, shi->osatex, &texres, thread, which_output, NULL, NULL, NULL); + } + else if (in[0]->datatype == NS_OSA_VALUES) { + const float *fp = in[0]->data; + float dxt[3], dyt[3]; + + dxt[0] = fp[0]; dxt[1] = dxt[2] = 0.0f; + dyt[0] = fp[1]; dyt[1] = dyt[2] = 0.0f; + retval = multitex_nodes((Tex *)node->id, vec, dxt, dyt, shi->osatex, &texres, thread, which_output, NULL, NULL, NULL); + } + else + retval = multitex_nodes((Tex *)node->id, vec, NULL, NULL, 0, &texres, thread, which_output, NULL, NULL, NULL); + } + else { + copy_v3_v3(vec, shi->lo); + retval = multitex_nodes((Tex *)node->id, vec, NULL, NULL, 0, &texres, thread, which_output, NULL, NULL, NULL); + } + + /* stupid exception */ + if ( ((Tex *)node->id)->type == TEX_STUCCI) { + texres.tin = 0.5f + 0.7f * texres.nor[0]; + CLAMP(texres.tin, 0.0f, 1.0f); + } + + /* intensity and color need some handling */ + if (texres.talpha) + out[0]->vec[0] = texres.ta; + else + out[0]->vec[0] = texres.tin; + + if ((retval & TEX_RGB) == 0) { + copy_v3_fl(out[1]->vec, out[0]->vec[0]); + out[1]->vec[3] = 1.0f; + } + else { + copy_v3_v3(out[1]->vec, &texres.tr); + out[1]->vec[3] = 1.0f; + } + + copy_v3_v3(out[2]->vec, nor); + + if (shi->do_preview) { + BKE_node_preview_set_pixel(execdata->preview, out[1]->vec, shi->xs, shi->ys, shi->do_manage); + } + + } +} + +static int gpu_shader_texture(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out) +{ + Tex *tex = (Tex *)node->id; + + if (tex && tex->ima && (tex->type == TEX_IMAGE || tex->type == TEX_ENVMAP)) { + if (tex->type == TEX_IMAGE) { + GPUNodeLink *texlink = GPU_image(tex->ima, &tex->iuser, false); + GPU_stack_link(mat, "texture_image", in, out, texlink); + } + else { /* TEX_ENVMAP */ + if (!in[0].link) + in[0].link = GPU_uniform(in[0].vec); + if (!GPU_material_use_world_space_shading(mat)) + GPU_link(mat, "direction_transform_m4v3", in[0].link, GPU_builtin(GPU_INVERSE_VIEW_MATRIX), &in[0].link); + GPU_link(mat, "mtex_cube_map_refl_from_refldir", + GPU_cube_map(tex->ima, &tex->iuser, false), in[0].link, &out[0].link, &out[1].link); + GPU_link(mat, "color_to_normal", out[1].link, &out[2].link); + } + + ImBuf *ibuf = BKE_image_acquire_ibuf(tex->ima, &tex->iuser, NULL); + if (ibuf && (ibuf->colormanage_flag & IMB_COLORMANAGE_IS_DATA) == 0 && + GPU_material_do_color_management(mat)) + { + GPU_link(mat, "srgb_to_linearrgb", out[1].link, &out[1].link); + } + BKE_image_release_ibuf(tex->ima, ibuf, NULL); + + return true; + } + + return false; +} + +void register_node_type_sh_texture(void) +{ + static bNodeType ntype; + + sh_node_type_base(&ntype, SH_NODE_TEXTURE, "Texture", NODE_CLASS_INPUT, NODE_PREVIEW); + node_type_compatibility(&ntype, NODE_OLD_SHADING); + node_type_socket_templates(&ntype, sh_node_texture_in, sh_node_texture_out); + node_type_exec(&ntype, NULL, NULL, node_shader_exec_texture); + node_type_gpu(&ntype, gpu_shader_texture); + + nodeRegisterType(&ntype); +} diff --git a/source/blender/nodes/shader/nodes/node_shader_valToRgb.c b/source/blender/nodes/shader/nodes/node_shader_valToRgb.c index 5041741beb1..a1879df3a18 100644 --- a/source/blender/nodes/shader/nodes/node_shader_valToRgb.c +++ b/source/blender/nodes/shader/nodes/node_shader_valToRgb.c @@ -48,7 +48,7 @@ static void node_shader_exec_valtorgb(void *UNUSED(data), int UNUSED(thread), bN { /* stack order in: fac */ /* stack order out: col, alpha */ - + if (node->storage) { float fac; nodestack_get_vec(&fac, SOCK_FLOAT, in[0]); diff --git a/source/blender/nodes/shader/nodes/node_shader_vectMath.c b/source/blender/nodes/shader/nodes/node_shader_vectMath.c index 2b060806819..ca5291e6041 100644 --- a/source/blender/nodes/shader/nodes/node_shader_vectMath.c +++ b/source/blender/nodes/shader/nodes/node_shader_vectMath.c @@ -31,7 +31,7 @@ #include "node_shader_util.h" -/* **************** VECTOR MATH ******************** */ +/* **************** VECTOR MATH ******************** */ static bNodeSocketTemplate sh_node_vect_math_in[] = { { SOCK_VECTOR, 1, N_("Vector"), 0.5f, 0.5f, 0.5f, 1.0f, -10000.0f, 10000.0f, PROP_NONE}, { SOCK_VECTOR, 1, N_("Vector"), 0.5f, 0.5f, 0.5f, 1.0f, -10000.0f, 10000.0f, PROP_NONE}, @@ -44,32 +44,32 @@ static bNodeSocketTemplate sh_node_vect_math_out[] = { { -1, 0, "" } }; -static void node_shader_exec_vect_math(void *UNUSED(data), int UNUSED(thread), bNode *node, bNodeExecData *UNUSED(execdata), bNodeStack **in, bNodeStack **out) -{ +static void node_shader_exec_vect_math(void *UNUSED(data), int UNUSED(thread), bNode *node, bNodeExecData *UNUSED(execdata), bNodeStack **in, bNodeStack **out) +{ float vec1[3], vec2[3]; - + nodestack_get_vec(vec1, SOCK_VECTOR, in[0]); nodestack_get_vec(vec2, SOCK_VECTOR, in[1]); - + if (node->custom1 == 0) { /* Add */ out[0]->vec[0] = vec1[0] + vec2[0]; out[0]->vec[1] = vec1[1] + vec2[1]; out[0]->vec[2] = vec1[2] + vec2[2]; - + out[1]->vec[0] = (fabsf(out[0]->vec[0]) + fabsf(out[0]->vec[1]) + fabsf(out[0]->vec[2])) / 3.0f; } else if (node->custom1 == 1) { /* Subtract */ out[0]->vec[0] = vec1[0] - vec2[0]; out[0]->vec[1] = vec1[1] - vec2[1]; out[0]->vec[2] = vec1[2] - vec2[2]; - + out[1]->vec[0] = (fabsf(out[0]->vec[0]) + fabsf(out[0]->vec[1]) + fabsf(out[0]->vec[2])) / 3.0f; } else if (node->custom1 == 2) { /* Average */ out[0]->vec[0] = vec1[0] + vec2[0]; out[0]->vec[1] = vec1[1] + vec2[1]; out[0]->vec[2] = vec1[2] + vec2[2]; - + out[1]->vec[0] = normalize_v3(out[0]->vec); } else if (node->custom1 == 3) { /* Dot product */ @@ -79,7 +79,7 @@ static void node_shader_exec_vect_math(void *UNUSED(data), int UNUSED(thread), b out[0]->vec[0] = (vec1[1] * vec2[2]) - (vec1[2] * vec2[1]); out[0]->vec[1] = (vec1[2] * vec2[0]) - (vec1[0] * vec2[2]); out[0]->vec[2] = (vec1[0] * vec2[1]) - (vec1[1] * vec2[0]); - + out[1]->vec[0] = normalize_v3(out[0]->vec); } else if (node->custom1 == 5) { /* Normalize */ @@ -93,10 +93,10 @@ static void node_shader_exec_vect_math(void *UNUSED(data), int UNUSED(thread), b out[0]->vec[1] = vec2[1]; out[0]->vec[2] = vec2[2]; } - + out[1]->vec[0] = normalize_v3(out[0]->vec); } - + } static int gpu_shader_vect_math(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out) @@ -132,7 +132,7 @@ static int gpu_shader_vect_math(GPUMaterial *mat, bNode *node, bNodeExecData *UN default: return false; } - + return true; } diff --git a/source/blender/nodes/shader/nodes/node_shader_vectTransform.c b/source/blender/nodes/shader/nodes/node_shader_vectTransform.c index 8183b6c45cb..d0b16dd5886 100644 --- a/source/blender/nodes/shader/nodes/node_shader_vectTransform.c +++ b/source/blender/nodes/shader/nodes/node_shader_vectTransform.c @@ -28,10 +28,10 @@ /** \file blender/nodes/shader/nodes/node_shader_vectTransform.c * \ingroup shdnodes */ - + #include "../node_shader_util.h" -/* **************** Vector Transform ******************** */ +/* **************** Vector Transform ******************** */ static bNodeSocketTemplate sh_node_vect_transform_in[] = { { SOCK_VECTOR, 1, N_("Vector"), 0.5f, 0.5f, 0.5f, 1.0f, -10000.0f, 10000.0f, PROP_NONE}, { -1, 0, "" } @@ -45,10 +45,10 @@ static bNodeSocketTemplate sh_node_vect_transform_out[] = { static void node_shader_init_vect_transform(bNodeTree *UNUSED(ntree), bNode *node) { NodeShaderVectTransform *vect = MEM_callocN(sizeof(NodeShaderVectTransform), "NodeShaderVectTransform"); - + /* Convert World into Object Space per default */ vect->convert_to = 1; - + node->storage = vect; } diff --git a/source/blender/nodes/texture/node_texture_tree.c b/source/blender/nodes/texture/node_texture_tree.c index 0d3d3f261de..5dbcece0a84 100644 --- a/source/blender/nodes/texture/node_texture_tree.c +++ b/source/blender/nodes/texture/node_texture_tree.c @@ -70,7 +70,7 @@ static void texture_get_from_context( if (snode->texfrom == SNODE_TEX_BRUSH) { struct Brush *brush = NULL; - + if (ob && (ob->mode & OB_MODE_SCULPT)) brush = BKE_paint_brush(&scene->toolsettings->sculpt->paint); else @@ -119,11 +119,11 @@ static void foreach_nodeclass(Scene *UNUSED(scene), void *calldata, bNodeClassCa static void localize(bNodeTree *localtree, bNodeTree *UNUSED(ntree)) { bNode *node, *node_next; - + /* replace muted nodes and reroute nodes by internal links */ for (node = localtree->nodes.first; node; node = node_next) { node_next = node->next; - + if (node->flag & NODE_MUTED || node->type == NODE_REROUTE) { nodeInternalRelink(localtree, node); nodeFreeNode(localtree, node); @@ -149,7 +149,7 @@ static void local_merge(bNodeTree *localtree, bNodeTree *ntree) static void update(bNodeTree *ntree) { ntree_update_reroute_nodes(ntree); - + if (ntree->update & NTREE_UPDATE_NODES) { /* clean up preview cache, in case nodes have been removed */ BKE_node_preview_remove_unused(ntree); @@ -161,31 +161,31 @@ bNodeTreeType *ntreeType_Texture; void register_node_tree_type_tex(void) { bNodeTreeType *tt = ntreeType_Texture = MEM_callocN(sizeof(bNodeTreeType), "texture node tree type"); - + tt->type = NTREE_TEXTURE; strcpy(tt->idname, "TextureNodeTree"); strcpy(tt->ui_name, "Texture Editor"); tt->ui_icon = 0; /* defined in drawnode.c */ strcpy(tt->ui_description, "Texture nodes"); - + tt->foreach_nodeclass = foreach_nodeclass; tt->update = update; tt->localize = localize; tt->local_sync = local_sync; tt->local_merge = local_merge; tt->get_from_context = texture_get_from_context; - + tt->ext.srna = &RNA_TextureNodeTree; - + ntreeTypeAdd(tt); } int ntreeTexTagAnimated(bNodeTree *ntree) { bNode *node; - + if (ntree == NULL) return 0; - + for (node = ntree->nodes.first; node; node = node->next) { if (node->type == TEX_NODE_CURVE_TIME) { nodeUpdate(ntree, node); @@ -197,7 +197,7 @@ int ntreeTexTagAnimated(bNodeTree *ntree) } } } - + return 0; } @@ -205,16 +205,16 @@ bNodeTreeExec *ntreeTexBeginExecTree_internal(bNodeExecContext *context, bNodeTr { bNodeTreeExec *exec; bNode *node; - + /* common base initialization */ exec = ntree_exec_begin(context, ntree, parent_key); - + /* allocate the thread stack listbase array */ exec->threadstack = MEM_callocN(BLENDER_MAX_THREADS * sizeof(ListBase), "thread stack array"); - + for (node = exec->nodetree->nodes.first; node; node = node->next) node->need_exec = 1; - + return exec; } @@ -222,22 +222,22 @@ bNodeTreeExec *ntreeTexBeginExecTree(bNodeTree *ntree) { bNodeExecContext context; bNodeTreeExec *exec; - + /* XXX hack: prevent exec data from being generated twice. * this should be handled by the renderer! */ if (ntree->execdata) return ntree->execdata; - + context.previews = ntree->previews; - + exec = ntreeTexBeginExecTree_internal(&context, ntree, NODE_INSTANCE_KEY_BASE); - + /* XXX this should not be necessary, but is still used for cmp/sha/tex nodes, * which only store the ntree pointer. Should be fixed at some point! */ ntree->execdata = exec; - + return exec; } @@ -247,7 +247,7 @@ static void tex_free_delegates(bNodeTreeExec *exec) bNodeThreadStack *nts; bNodeStack *ns; int th, a; - + for (th = 0; th < BLENDER_MAX_THREADS; th++) for (nts = exec->threadstack[th].first; nts; nts = nts->next) for (ns = nts->stack, a = 0; a < exec->stacksize; a++, ns++) @@ -259,20 +259,20 @@ void ntreeTexEndExecTree_internal(bNodeTreeExec *exec) { bNodeThreadStack *nts; int a; - + if (exec->threadstack) { tex_free_delegates(exec); - + for (a = 0; a < BLENDER_MAX_THREADS; a++) { for (nts = exec->threadstack[a].first; nts; nts = nts->next) if (nts->stack) MEM_freeN(nts->stack); BLI_freelistN(&exec->threadstack[a]); } - + MEM_freeN(exec->threadstack); exec->threadstack = NULL; } - + ntree_exec_end(exec); } @@ -282,7 +282,7 @@ void ntreeTexEndExecTree(bNodeTreeExec *exec) /* exec may get freed, so assign ntree */ bNodeTree *ntree = exec->nodetree; ntreeTexEndExecTree_internal(exec); - + /* XXX clear nodetree backpointer to exec data, same problem as noted in ntreeBeginExecTree */ ntree->execdata = NULL; } @@ -318,7 +318,7 @@ int ntreeTexExecTree( data.which_output = which_output; data.cfra = cfra; data.mtex = mtex; - + /* ensure execdata is only initialized once */ if (!exec) { BLI_thread_lock(LOCK_NODES); @@ -328,7 +328,7 @@ int ntreeTexExecTree( exec = nodes->execdata; } - + nts = ntreeGetThreadStack(exec, thread); ntreeExecThreadNodes(exec, nts, &data, thread); ntreeReleaseThreadStack(nts); diff --git a/source/blender/nodes/texture/node_texture_util.c b/source/blender/nodes/texture/node_texture_util.c index 8cb61478c41..a6b0d060d93 100644 --- a/source/blender/nodes/texture/node_texture_util.c +++ b/source/blender/nodes/texture/node_texture_util.c @@ -58,7 +58,7 @@ int tex_node_poll_default(bNodeType *UNUSED(ntype), bNodeTree *ntree) void tex_node_type_base(struct bNodeType *ntype, int type, const char *name, short nclass, short flag) { node_type_base(ntype, type, name, nclass, flag); - + ntype->poll = tex_node_poll_default; ntype->insert_link = node_insert_link_default; ntype->update_internal_links = node_update_internal_links_default; @@ -80,7 +80,7 @@ static void tex_input(float *out, int sz, bNodeStack *in, TexParams *params, sho TexDelegate *dg = in->data; if (dg) { tex_call_delegate(dg, in->vec, params, thread); - + if (in->hasoutput && in->sockettype == SOCK_FLOAT) in->vec[1] = in->vec[2] = in->vec[0]; } @@ -95,12 +95,12 @@ void tex_input_vec(float *out, bNodeStack *in, TexParams *params, short thread) void tex_input_rgba(float *out, bNodeStack *in, TexParams *params, short thread) { tex_input(out, 4, in, params, thread); - + if (in->hasoutput && in->sockettype == SOCK_FLOAT) { out[1] = out[2] = out[0]; out[3] = 1; } - + if (in->hasoutput && in->sockettype == SOCK_VECTOR) { out[0] = out[0] * 0.5f + 0.5f; out[1] = out[1] * 0.5f + 0.5f; @@ -132,7 +132,7 @@ void tex_do_preview(bNodePreview *preview, const float coord[2], const float col if (preview) { int xs = ((coord[0] + 1.0f) * 0.5f) * preview->xsize; int ys = ((coord[1] + 1.0f) * 0.5f) * preview->ysize; - + BKE_node_preview_set_pixel(preview, col, xs, ys, do_manage); } } @@ -140,7 +140,7 @@ void tex_do_preview(bNodePreview *preview, const float coord[2], const float col void tex_output(bNode *node, bNodeExecData *execdata, bNodeStack **in, bNodeStack *out, TexFn texfn, TexCallData *cdata) { TexDelegate *dg; - + if (node->flag & NODE_MUTED) { /* do not add a delegate if the node is muted */ return; @@ -175,9 +175,9 @@ void ntreeTexCheckCyclics(struct bNodeTree *ntree) } else { Tex *tex = (Tex *)node->id; - + node->custom2 = 0; - + node->custom1 = 1; if (tex->use_nodes && tex->nodetree) { ntreeTexCheckCyclics(tex->nodetree); diff --git a/source/blender/nodes/texture/nodes/node_texture_at.c b/source/blender/nodes/texture/nodes/node_texture_at.c index bd37a73c776..690d87b42a9 100644 --- a/source/blender/nodes/texture/nodes/node_texture_at.c +++ b/source/blender/nodes/texture/nodes/node_texture_at.c @@ -48,7 +48,7 @@ static void colorfn(float *out, TexParams *p, bNode *UNUSED(node), bNodeStack ** TexParams np = *p; float new_co[3]; np.co = new_co; - + tex_input_vec(new_co, in[1], p, thread); tex_input_rgba(out, in[0], &np, thread); } @@ -61,11 +61,11 @@ static void exec(void *data, int UNUSED(thread), bNode *node, bNodeExecData *exe void register_node_type_tex_at(void) { static bNodeType ntype; - + tex_node_type_base(&ntype, TEX_NODE_AT, "At", NODE_CLASS_DISTORT, 0); node_type_socket_templates(&ntype, inputs, outputs); node_type_size(&ntype, 140, 100, 320); node_type_exec(&ntype, NULL, NULL, exec); - + nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/texture/nodes/node_texture_bricks.c b/source/blender/nodes/texture/nodes/node_texture_bricks.c index 802cfb97533..43af02acdf2 100644 --- a/source/blender/nodes/texture/nodes/node_texture_bricks.c +++ b/source/blender/nodes/texture/nodes/node_texture_bricks.c @@ -67,43 +67,43 @@ static float noise(int n) /* fast integer noise */ static void colorfn(float *out, TexParams *p, bNode *node, bNodeStack **in, short thread) { const float *co = p->co; - + float x = co[0]; float y = co[1]; - + int bricknum, rownum; float offset = 0; float ins_x, ins_y; float tint; - + float bricks1[4]; float bricks2[4]; float mortar[4]; - + float mortar_thickness = tex_input_value(in[3], p, thread); float bias = tex_input_value(in[4], p, thread); float brick_width = tex_input_value(in[5], p, thread); float row_height = tex_input_value(in[6], p, thread); - + tex_input_rgba(bricks1, in[0], p, thread); tex_input_rgba(bricks2, in[1], p, thread); tex_input_rgba(mortar, in[2], p, thread); - + rownum = (int)floor(y / row_height); - + if (node->custom1 && node->custom2) { brick_width *= ((int)(rownum) % node->custom2) ? 1.0f : node->custom4; /* squash */ offset = ((int)(rownum) % node->custom1) ? 0 : (brick_width * node->custom3); /* offset */ } - + bricknum = (int)floor((x + offset) / brick_width); - + ins_x = (x + offset) - brick_width * bricknum; ins_y = y - row_height * rownum; - + tint = noise((rownum << 16) + (bricknum & 0xFFFF)) + bias; CLAMP(tint, 0.0f, 1.0f); - + if (ins_x < mortar_thickness || ins_y < mortar_thickness || ins_x > (brick_width - mortar_thickness) || ins_y > (row_height - mortar_thickness)) @@ -124,12 +124,12 @@ static void exec(void *data, int UNUSED(thread), bNode *node, bNodeExecData *exe void register_node_type_tex_bricks(void) { static bNodeType ntype; - + tex_node_type_base(&ntype, TEX_NODE_BRICKS, "Bricks", NODE_CLASS_PATTERN, NODE_PREVIEW); node_type_socket_templates(&ntype, inputs, outputs); node_type_size_preset(&ntype, NODE_SIZE_MIDDLE); node_type_init(&ntype, init); node_type_exec(&ntype, NULL, NULL, exec); - + nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/texture/nodes/node_texture_checker.c b/source/blender/nodes/texture/nodes/node_texture_checker.c index b38c883e3b8..d7ad642d474 100644 --- a/source/blender/nodes/texture/nodes/node_texture_checker.c +++ b/source/blender/nodes/texture/nodes/node_texture_checker.c @@ -51,12 +51,12 @@ static void colorfn(float *out, TexParams *p, bNode *UNUSED(node), bNodeStack ** float y = p->co[1]; float z = p->co[2]; float sz = tex_input_value(in[2], p, thread); - + /* 0.00001 because of unit sized stuff */ int xi = (int)fabs(floor(0.00001f + x / sz)); int yi = (int)fabs(floor(0.00001f + y / sz)); int zi = (int)fabs(floor(0.00001f + z / sz)); - + if ( (xi % 2 == yi % 2) == (zi % 2) ) { tex_input_rgba(out, in[0], p, thread); } @@ -73,10 +73,10 @@ static void exec(void *data, int UNUSED(thread), bNode *node, bNodeExecData *exe void register_node_type_tex_checker(void) { static bNodeType ntype; - + tex_node_type_base(&ntype, TEX_NODE_CHECKER, "Checker", NODE_CLASS_PATTERN, NODE_PREVIEW); node_type_socket_templates(&ntype, inputs, outputs); node_type_exec(&ntype, NULL, NULL, exec); - + nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/texture/nodes/node_texture_common.c b/source/blender/nodes/texture/nodes/node_texture_common.c index 6f9a39d7524..20b1815e436 100644 --- a/source/blender/nodes/texture/nodes/node_texture_common.c +++ b/source/blender/nodes/texture/nodes/node_texture_common.c @@ -50,7 +50,7 @@ static void copy_stack(bNodeStack *to, bNodeStack *from) copy_v4_v4(to->vec, from->vec); to->data = from->data; to->datatype = from->datatype; - + /* tag as copy to prevent freeing */ to->is_copy = 1; } @@ -62,20 +62,20 @@ static void *group_initexec(bNodeExecContext *context, bNode *node, bNodeInstanc { bNodeTree *ngroup = (bNodeTree *)node->id; void *exec; - + if (!ngroup) return NULL; - + /* initialize the internal node tree execution */ exec = ntreeTexBeginExecTree_internal(context, ngroup, key); - + return exec; } static void group_freeexec(void *nodedata) { bNodeTreeExec *gexec = (bNodeTreeExec *)nodedata; - + ntreeTexEndExecTree_internal(gexec); } @@ -89,7 +89,7 @@ static void group_copy_inputs(bNode *gnode, bNodeStack **in, bNodeStack *gstack) bNodeSocket *sock; bNodeStack *ns; int a; - + for (node = ngroup->nodes.first; node; node = node->next) { if (node->type == NODE_GROUP_INPUT) { for (sock = node->outputs.first, a = 0; sock; sock = sock->next, ++a) { @@ -113,7 +113,7 @@ static void group_copy_outputs(bNode *gnode, bNodeStack **out, bNodeStack *gstac bNodeSocket *sock; bNodeStack *ns; int a; - + for (node = ngroup->nodes.first; node; node = node->next) { if (node->type == NODE_GROUP_OUTPUT && (node->flag & NODE_DO_OUTPUT)) { for (sock = node->inputs.first, a = 0; sock; sock = sock->next, ++a) { @@ -133,10 +133,10 @@ static void group_execute(void *data, int thread, struct bNode *node, bNodeExecD { bNodeTreeExec *exec = execdata->data; bNodeThreadStack *nts; - + if (!exec) return; - + /* XXX same behavior as trunk: all nodes inside group are executed. * it's stupid, but just makes it work. compo redesign will do this better. */ @@ -145,13 +145,13 @@ static void group_execute(void *data, int thread, struct bNode *node, bNodeExecD for (inode = exec->nodetree->nodes.first; inode; inode = inode->next) inode->need_exec = 1; } - + nts = ntreeGetThreadStack(exec, thread); - + group_copy_inputs(node, in, nts->stack); ntreeExecThreadNodes(exec, nts, data, thread); group_copy_outputs(node, out, nts->stack); - + ntreeReleaseThreadStack(nts); } @@ -171,12 +171,12 @@ void register_node_type_tex_group(void) ntype.ext.srna = RNA_struct_find("TextureNodeGroup"); BLI_assert(ntype.ext.srna != NULL); RNA_struct_blender_type_set(ntype.ext.srna, &ntype); - + node_type_socket_templates(&ntype, NULL, NULL); node_type_size(&ntype, 140, 60, 400); node_type_label(&ntype, node_group_label); node_type_update(&ntype, NULL, node_group_verify); node_type_exec(&ntype, group_initexec, group_freeexec, group_execute); - + nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/texture/nodes/node_texture_compose.c b/source/blender/nodes/texture/nodes/node_texture_compose.c index 092bf919a67..002da4428cc 100644 --- a/source/blender/nodes/texture/nodes/node_texture_compose.c +++ b/source/blender/nodes/texture/nodes/node_texture_compose.c @@ -30,7 +30,7 @@ */ -#include "node_texture_util.h" +#include "node_texture_util.h" #include "NOD_texture.h" static bNodeSocketTemplate inputs[] = { @@ -60,10 +60,10 @@ static void exec(void *data, int UNUSED(thread), bNode *node, bNodeExecData *exe void register_node_type_tex_compose(void) { static bNodeType ntype; - + tex_node_type_base(&ntype, TEX_NODE_COMPOSE, "Combine RGBA", NODE_CLASS_OP_COLOR, 0); node_type_socket_templates(&ntype, inputs, outputs); node_type_exec(&ntype, NULL, NULL, exec); - + nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/texture/nodes/node_texture_coord.c b/source/blender/nodes/texture/nodes/node_texture_coord.c index e76987da61b..e698ffd0a54 100644 --- a/source/blender/nodes/texture/nodes/node_texture_coord.c +++ b/source/blender/nodes/texture/nodes/node_texture_coord.c @@ -51,11 +51,11 @@ static void exec(void *data, int UNUSED(thread), bNode *node, bNodeExecData *exe void register_node_type_tex_coord(void) { static bNodeType ntype; - + tex_node_type_base(&ntype, TEX_NODE_COORD, "Coordinates", NODE_CLASS_INPUT, 0); node_type_socket_templates(&ntype, NULL, outputs); node_type_storage(&ntype, "", NULL, NULL); node_type_exec(&ntype, NULL, NULL, exec); - + nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/texture/nodes/node_texture_curves.c b/source/blender/nodes/texture/nodes/node_texture_curves.c index c25c312626e..cc734df9586 100644 --- a/source/blender/nodes/texture/nodes/node_texture_curves.c +++ b/source/blender/nodes/texture/nodes/node_texture_curves.c @@ -45,10 +45,10 @@ static void time_colorfn(float *out, TexParams *p, bNode *node, bNodeStack **UNU { /* stack order output: fac */ float fac = 0.0f; - + if (node->custom1 < node->custom2) fac = (p->cfra - node->custom1) / (float)(node->custom2 - node->custom1); - + curvemapping_initialize(node->storage); fac = curvemapping_evaluateF(node->storage, 0, fac); out[0] = CLAMPIS(fac, 0.0f, 1.0f); @@ -70,14 +70,14 @@ static void time_init(bNodeTree *UNUSED(ntree), bNode *node) void register_node_type_tex_curve_time(void) { static bNodeType ntype; - + tex_node_type_base(&ntype, TEX_NODE_CURVE_TIME, "Time", NODE_CLASS_INPUT, 0); node_type_socket_templates(&ntype, NULL, time_outputs); node_type_size_preset(&ntype, NODE_SIZE_LARGE); node_type_init(&ntype, time_init); node_type_storage(&ntype, "CurveMapping", node_free_curves, node_copy_curves); node_type_exec(&ntype, node_initexec_curves, NULL, time_exec); - + nodeRegisterType(&ntype); } @@ -96,7 +96,7 @@ static void rgb_colorfn(float *out, TexParams *p, bNode *node, bNodeStack **in, { float cin[4]; tex_input_rgba(cin, in[0], p, thread); - + curvemapping_evaluateRGBF(node->storage, out, cin); out[3] = cin[3]; } @@ -114,13 +114,13 @@ static void rgb_init(bNodeTree *UNUSED(ntree), bNode *node) void register_node_type_tex_curve_rgb(void) { static bNodeType ntype; - + tex_node_type_base(&ntype, TEX_NODE_CURVE_RGB, "RGB Curves", NODE_CLASS_OP_COLOR, 0); node_type_socket_templates(&ntype, rgb_inputs, rgb_outputs); node_type_size_preset(&ntype, NODE_SIZE_LARGE); node_type_init(&ntype, rgb_init); node_type_storage(&ntype, "CurveMapping", node_free_curves, node_copy_curves); node_type_exec(&ntype, node_initexec_curves, NULL, rgb_exec); - + nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/texture/nodes/node_texture_decompose.c b/source/blender/nodes/texture/nodes/node_texture_decompose.c index 16938bee8e4..392cff970e7 100644 --- a/source/blender/nodes/texture/nodes/node_texture_decompose.c +++ b/source/blender/nodes/texture/nodes/node_texture_decompose.c @@ -30,7 +30,7 @@ */ -#include "node_texture_util.h" +#include "node_texture_util.h" #include "NOD_texture.h" #include <math.h> @@ -81,10 +81,10 @@ static void exec(void *data, int UNUSED(thread), bNode *node, bNodeExecData *exe void register_node_type_tex_decompose(void) { static bNodeType ntype; - + tex_node_type_base(&ntype, TEX_NODE_DECOMPOSE, "Separate RGBA", NODE_CLASS_OP_COLOR, 0); node_type_socket_templates(&ntype, inputs, outputs); node_type_exec(&ntype, NULL, NULL, exec); - + nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/texture/nodes/node_texture_distance.c b/source/blender/nodes/texture/nodes/node_texture_distance.c index 3fdcbe870a9..7cd032f7d59 100644 --- a/source/blender/nodes/texture/nodes/node_texture_distance.c +++ b/source/blender/nodes/texture/nodes/node_texture_distance.c @@ -64,11 +64,11 @@ static void exec(void *data, int UNUSED(thread), bNode *node, bNodeExecData *exe void register_node_type_tex_distance(void) { static bNodeType ntype; - + tex_node_type_base(&ntype, TEX_NODE_DISTANCE, "Distance", NODE_CLASS_CONVERTOR, 0); node_type_socket_templates(&ntype, inputs, outputs); node_type_storage(&ntype, "", NULL, NULL); node_type_exec(&ntype, NULL, NULL, exec); - + nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/texture/nodes/node_texture_hueSatVal.c b/source/blender/nodes/texture/nodes/node_texture_hueSatVal.c index 9c86f2d0a4c..8316579af93 100644 --- a/source/blender/nodes/texture/nodes/node_texture_hueSatVal.c +++ b/source/blender/nodes/texture/nodes/node_texture_hueSatVal.c @@ -51,7 +51,7 @@ static void do_hue_sat_fac(bNode *UNUSED(node), float *out, float hue, float sat { if (fac != 0 && (hue != 0.5f || sat != 1 || val != 1)) { float col[3], hsv[3], mfac = 1.0f - fac; - + rgb_to_hsv(in[0], in[1], in[2], hsv, hsv + 1, hsv + 2); hsv[0] += (hue - 0.5f); if (hsv[0] > 1.0f) hsv[0] -= 1.0f; else if (hsv[0] < 0.0f) hsv[0] += 1.0f; @@ -71,19 +71,19 @@ static void do_hue_sat_fac(bNode *UNUSED(node), float *out, float hue, float sat } static void colorfn(float *out, TexParams *p, bNode *node, bNodeStack **in, short thread) -{ +{ float hue = tex_input_value(in[0], p, thread); float sat = tex_input_value(in[1], p, thread); float val = tex_input_value(in[2], p, thread); float fac = tex_input_value(in[3], p, thread); - + float col[4]; tex_input_rgba(col, in[4], p, thread); - + hue += 0.5f; /* [-0.5, 0.5] -> [0, 1] */ - + do_hue_sat_fac(node, out, hue, sat, val, col, fac); - + out[3] = col[3]; } @@ -95,11 +95,11 @@ static void exec(void *data, int UNUSED(thread), bNode *node, bNodeExecData *exe void register_node_type_tex_hue_sat(void) { static bNodeType ntype; - + tex_node_type_base(&ntype, TEX_NODE_HUE_SAT, "Hue Saturation Value", NODE_CLASS_OP_COLOR, 0); node_type_socket_templates(&ntype, inputs, outputs); node_type_size_preset(&ntype, NODE_SIZE_MIDDLE); node_type_exec(&ntype, NULL, NULL, exec); - + nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/texture/nodes/node_texture_image.c b/source/blender/nodes/texture/nodes/node_texture_image.c index e36df01f489..0d70eff15e3 100644 --- a/source/blender/nodes/texture/nodes/node_texture_image.c +++ b/source/blender/nodes/texture/nodes/node_texture_image.c @@ -44,37 +44,37 @@ static void colorfn(float *out, TexParams *p, bNode *node, bNodeStack **UNUSED(i float y = p->co[1]; Image *ima = (Image *)node->id; ImageUser *iuser = (ImageUser *)node->storage; - + if (ima) { ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, NULL); if (ibuf) { float xsize, ysize; float xoff, yoff; int px, py; - + const float *result; xsize = ibuf->x / 2; ysize = ibuf->y / 2; xoff = yoff = -1; - + px = (int)( (x - xoff) * xsize); py = (int)( (y - yoff) * ysize); - + if ( (!xsize) || (!ysize) ) return; - + if (!ibuf->rect_float) { BLI_thread_lock(LOCK_IMAGE); if (!ibuf->rect_float) IMB_float_from_rect(ibuf); BLI_thread_unlock(LOCK_IMAGE); } - + while (px < 0) px += ibuf->x; while (py < 0) py += ibuf->y; while (px >= ibuf->x) px -= ibuf->x; while (py >= ibuf->y) py -= ibuf->y; - + result = ibuf->rect_float + py * ibuf->x * 4 + px * 4; copy_v4_v4(out, result); @@ -101,7 +101,7 @@ static void init(bNodeTree *UNUSED(ntree), bNode *node) void register_node_type_tex_image(void) { static bNodeType ntype; - + tex_node_type_base(&ntype, TEX_NODE_IMAGE, "Image", NODE_CLASS_INPUT, NODE_PREVIEW); node_type_socket_templates(&ntype, NULL, outputs); node_type_init(&ntype, init); diff --git a/source/blender/nodes/texture/nodes/node_texture_invert.c b/source/blender/nodes/texture/nodes/node_texture_invert.c index 35f5072d8a2..8ef7a7a6ad2 100644 --- a/source/blender/nodes/texture/nodes/node_texture_invert.c +++ b/source/blender/nodes/texture/nodes/node_texture_invert.c @@ -33,7 +33,7 @@ #include "node_texture_util.h" #include "NOD_texture.h" -/* **************** INVERT ******************** */ +/* **************** INVERT ******************** */ static bNodeSocketTemplate inputs[] = { { SOCK_RGBA, 1, N_("Color"), 0.0f, 0.0f, 0.0f, 1.0f}, { -1, 0, "" } @@ -47,13 +47,13 @@ static bNodeSocketTemplate outputs[] = { static void colorfn(float *out, TexParams *p, bNode *UNUSED(node), bNodeStack **in, short thread) { float col[4]; - + tex_input_rgba(col, in[0], p, thread); col[0] = 1.0f - col[0]; col[1] = 1.0f - col[1]; col[2] = 1.0f - col[2]; - + copy_v3_v3(out, col); out[3] = col[3]; } @@ -66,10 +66,10 @@ static void exec(void *data, int UNUSED(thread), bNode *node, bNodeExecData *exe void register_node_type_tex_invert(void) { static bNodeType ntype; - + tex_node_type_base(&ntype, TEX_NODE_INVERT, "Invert", NODE_CLASS_OP_COLOR, 0); node_type_socket_templates(&ntype, inputs, outputs); node_type_exec(&ntype, NULL, NULL, exec); - + nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/texture/nodes/node_texture_mixRgb.c b/source/blender/nodes/texture/nodes/node_texture_mixRgb.c index 835a49c24d4..9fb8332c61a 100644 --- a/source/blender/nodes/texture/nodes/node_texture_mixRgb.c +++ b/source/blender/nodes/texture/nodes/node_texture_mixRgb.c @@ -49,16 +49,16 @@ static void colorfn(float *out, TexParams *p, bNode *node, bNodeStack **in, shor { float fac = tex_input_value(in[0], p, thread); float col1[4], col2[4]; - + tex_input_rgba(col1, in[1], p, thread); tex_input_rgba(col2, in[2], p, thread); /* use alpha */ if (node->custom2 & 1) fac *= col2[3]; - + CLAMP(fac, 0.0f, 1.0f); - + copy_v4_v4(out, col1); ramp_blend(node->custom1, out, fac, col2); } @@ -71,11 +71,11 @@ static void exec(void *data, int UNUSED(thread), bNode *node, bNodeExecData *exe void register_node_type_tex_mix_rgb(void) { static bNodeType ntype; - + tex_node_type_base(&ntype, TEX_NODE_MIX_RGB, "Mix", NODE_CLASS_OP_COLOR, 0); node_type_socket_templates(&ntype, inputs, outputs); node_type_label(&ntype, node_blend_label); node_type_exec(&ntype, NULL, NULL, exec); - + nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/texture/nodes/node_texture_output.c b/source/blender/nodes/texture/nodes/node_texture_output.c index 664b7e4f507..412e3ffb56c 100644 --- a/source/blender/nodes/texture/nodes/node_texture_output.c +++ b/source/blender/nodes/texture/nodes/node_texture_output.c @@ -45,7 +45,7 @@ static void exec(void *data, int UNUSED(thread), bNode *node, bNodeExecData *exe { TexCallData *cdata = (TexCallData *)data; TexResult *target = cdata->target; - + if (cdata->do_preview) { TexParams params; params_from_cdata(¶ms, cdata); @@ -61,12 +61,12 @@ static void exec(void *data, int UNUSED(thread), bNode *node, bNodeExecData *exe if (cdata->which_output == node->custom1 || (cdata->which_output == 0 && node->custom1 == 1)) { TexParams params; params_from_cdata(¶ms, cdata); - + tex_input_rgba(&target->tr, in[0], ¶ms, cdata->thread); - + target->tin = (target->tr + target->tg + target->tb) / 3.0f; target->talpha = true; - + if (target->nor) { if (in[1] && in[1]->hasinput) tex_input_vec(target->nor, in[1], ¶ms, cdata->thread); @@ -85,7 +85,7 @@ static void unique_name(bNode *node) int suffix; bNode *i; const char *name = tno->name; - + new_name[0] = '\0'; i = node; while (i->prev) i = i->prev; @@ -114,7 +114,7 @@ static void unique_name(bNode *node) } sprintf(new_name + new_len - 4, ".%03d", ++suffix); } - + if (new_name[0] != '\0') { BLI_strncpy(tno->name, new_name, sizeof(tno->name)); } @@ -124,11 +124,11 @@ static void assign_index(struct bNode *node) { bNode *tnode; int index = 1; - + tnode = node; while (tnode->prev) tnode = tnode->prev; - + check_index: for (; tnode; tnode = tnode->next) if (tnode->type == TEX_NODE_OUTPUT && tnode != node) @@ -136,7 +136,7 @@ check_index: index++; goto check_index; } - + node->custom1 = index; } @@ -144,7 +144,7 @@ static void init(bNodeTree *UNUSED(ntree), bNode *node) { TexNodeOutput *tno = MEM_callocN(sizeof(TexNodeOutput), "TEX_output"); node->storage = tno; - + strcpy(tno->name, "Default"); unique_name(node); assign_index(node); @@ -160,16 +160,16 @@ static void copy(bNodeTree *dest_ntree, bNode *dest_node, bNode *src_node) void register_node_type_tex_output(void) { static bNodeType ntype; - + tex_node_type_base(&ntype, TEX_NODE_OUTPUT, "Output", NODE_CLASS_OUTPUT, NODE_PREVIEW); node_type_socket_templates(&ntype, inputs, NULL); node_type_size_preset(&ntype, NODE_SIZE_MIDDLE); node_type_init(&ntype, init); node_type_storage(&ntype, "TexNodeOutput", node_free_standard_storage, copy); node_type_exec(&ntype, NULL, NULL, exec); - + /* Do not allow muting output. */ node_type_internal_links(&ntype, NULL); - + nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/texture/nodes/node_texture_proc.c b/source/blender/nodes/texture/nodes/node_texture_proc.c index 2461a53ca2a..47f4683549f 100644 --- a/source/blender/nodes/texture/nodes/node_texture_proc.c +++ b/source/blender/nodes/texture/nodes/node_texture_proc.c @@ -35,7 +35,7 @@ #include "RE_shader_ext.h" -/* +/* * In this file: wrappers to use procedural textures as nodes */ @@ -61,19 +61,19 @@ static void do_proc(float *result, TexParams *p, const float col1[4], const floa { TexResult texres; int textype; - + if (is_normal) { texres.nor = result; } else texres.nor = NULL; - + textype = multitex_nodes(tex, p->co, p->dxt, p->dyt, p->osatex, &texres, thread, 0, p->mtex, NULL); - + if (is_normal) return; - + if (textype & TEX_RGB) { copy_v4_v4(result, &texres.tr); } @@ -86,11 +86,11 @@ static void do_proc(float *result, TexParams *p, const float col1[4], const floa typedef void (*MapFn) (Tex *tex, bNodeStack **in, TexParams *p, const short thread); static void texfn( - float *result, + float *result, TexParams *p, - bNode *node, + bNode *node, bNodeStack **in, - char is_normal, + char is_normal, MapFn map_inputs, short thread) { @@ -98,9 +98,9 @@ static void texfn( float col1[4], col2[4]; tex_input_rgba(col1, in[0], p, thread); tex_input_rgba(col2, in[1], p, thread); - + map_inputs(&tex, in, p, thread); - + do_proc(result, p, col1, col2, is_normal, &tex, thread); } @@ -144,10 +144,10 @@ static bNodeSocketTemplate voronoi_inputs[] = { { SOCK_FLOAT, 1, N_("W2"), 0.0f, 0.0f, 0.0f, 0.0f, -2.0f, 2.0f, PROP_NONE }, { SOCK_FLOAT, 1, N_("W3"), 0.0f, 0.0f, 0.0f, 0.0f, -2.0f, 2.0f, PROP_NONE }, { SOCK_FLOAT, 1, N_("W4"), 0.0f, 0.0f, 0.0f, 0.0f, -2.0f, 2.0f, PROP_NONE }, - + { SOCK_FLOAT, 1, N_("iScale"), 1.0f, 0.0f, 0.0f, 0.0f, 0.01f, 10.0f, PROP_UNSIGNED }, { SOCK_FLOAT, 1, N_("Size"), 0.25f, 0.0f, 0.0f, 0.0f, 0.0001f, 4.0f, PROP_UNSIGNED }, - + { -1, 0, "" } }; static void voronoi_map_inputs(Tex *tex, bNodeStack **in, TexParams *p, short thread) @@ -156,7 +156,7 @@ static void voronoi_map_inputs(Tex *tex, bNodeStack **in, TexParams *p, short th tex->vn_w2 = tex_input_value(in[I + 1], p, thread); tex->vn_w3 = tex_input_value(in[I + 2], p, thread); tex->vn_w4 = tex_input_value(in[I + 3], p, thread); - + tex->ns_outscale = tex_input_value(in[I + 4], p, thread); tex->noisesize = tex_input_value(in[I + 5], p, thread); } @@ -242,7 +242,7 @@ static bNodeSocketTemplate musgrave_inputs[] = { { SOCK_FLOAT, 1, N_("H"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0001f, 2.0f, PROP_UNSIGNED }, { SOCK_FLOAT, 1, N_("Lacunarity"), 2.0f, 0.0f, 0.0f, 0.0f, 0.0f, 6.0f, PROP_UNSIGNED }, { SOCK_FLOAT, 1, N_("Octaves"), 2.0f, 0.0f, 0.0f, 0.0f, 0.0f, 8.0f, PROP_UNSIGNED }, - + { SOCK_FLOAT, 1, N_("iScale"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 10.0f, PROP_UNSIGNED }, { SOCK_FLOAT, 1, N_("Size"), 0.25f, 0.0f, 0.0f, 0.0f, 0.0001f, 2.0f, PROP_UNSIGNED }, { -1, 0, "" } @@ -285,13 +285,13 @@ static void init(bNodeTree *UNUSED(ntree), bNode *node) { Tex *tex = MEM_callocN(sizeof(Tex), "Tex"); node->storage = tex; - + BKE_texture_default(tex); tex->type = node->type - TEX_NODE_PROC; - + if (tex->type == TEX_WOOD) tex->stype = TEX_BANDNOISE; - + } /* Node type definitions */ @@ -309,10 +309,10 @@ void register_node_type_tex_proc_##name(void) \ \ nodeRegisterType(&ntype); \ } - + #define C outputs_color_only #define CV outputs_both - + TexDef(TEX_VORONOI, CV, voronoi, "Voronoi" ) TexDef(TEX_BLEND, C, blend, "Blend" ) TexDef(TEX_MAGIC, C, magic, "Magic" ) diff --git a/source/blender/nodes/texture/nodes/node_texture_rotate.c b/source/blender/nodes/texture/nodes/node_texture_rotate.c index 99648ec323f..bc4e56ea81d 100644 --- a/source/blender/nodes/texture/nodes/node_texture_rotate.c +++ b/source/blender/nodes/texture/nodes/node_texture_rotate.c @@ -52,18 +52,18 @@ static void rotate(float new_co[3], float a, float ax[3], const float co[3]) float para[3]; float perp[3]; float cp[3]; - + float cos_a = cosf(a * (float)(2 * M_PI)); float sin_a = sinf(a * (float)(2 * M_PI)); - + // x' = xcosa + n(n.x)(1-cosa) + (x*n)sina - + mul_v3_v3fl(perp, co, cos_a); mul_v3_v3fl(para, ax, dot_v3v3(co, ax) * (1 - cos_a)); - + cross_v3_v3v3(cp, ax, co); mul_v3_fl(cp, sin_a); - + new_co[0] = para[0] + perp[0] + cp[0]; new_co[1] = para[1] + perp[1] + cp[1]; new_co[2] = para[2] + perp[2] + cp[2]; @@ -72,7 +72,7 @@ static void rotate(float new_co[3], float a, float ax[3], const float co[3]) static void colorfn(float *out, TexParams *p, bNode *UNUSED(node), bNodeStack **in, short thread) { float new_co[3], new_dxt[3], new_dyt[3], a, ax[3]; - + a = tex_input_value(in[1], p, thread); tex_input_vec(ax, in[2], p, thread); @@ -81,7 +81,7 @@ static void colorfn(float *out, TexParams *p, bNode *UNUSED(node), bNodeStack ** rotate(new_dxt, a, ax, p->dxt); rotate(new_dyt, a, ax, p->dyt); } - + { TexParams np = *p; np.co = new_co; @@ -90,7 +90,7 @@ static void colorfn(float *out, TexParams *p, bNode *UNUSED(node), bNodeStack ** tex_input_rgba(out, in[0], &np, thread); } } -static void exec(void *data, int UNUSED(thread), bNode *node, bNodeExecData *execdata, bNodeStack **in, bNodeStack **out) +static void exec(void *data, int UNUSED(thread), bNode *node, bNodeExecData *execdata, bNodeStack **in, bNodeStack **out) { tex_output(node, execdata, in, out[0], &colorfn, data); } @@ -98,10 +98,10 @@ static void exec(void *data, int UNUSED(thread), bNode *node, bNodeExecData *exe void register_node_type_tex_rotate(void) { static bNodeType ntype; - + tex_node_type_base(&ntype, TEX_NODE_ROTATE, "Rotate", NODE_CLASS_DISTORT, 0); node_type_socket_templates(&ntype, inputs, outputs); node_type_exec(&ntype, NULL, NULL, exec); - + nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/texture/nodes/node_texture_scale.c b/source/blender/nodes/texture/nodes/node_texture_scale.c index d623e8e159a..94ccfd01357 100644 --- a/source/blender/nodes/texture/nodes/node_texture_scale.c +++ b/source/blender/nodes/texture/nodes/node_texture_scale.c @@ -52,7 +52,7 @@ static void colorfn(float *out, TexParams *p, bNode *UNUSED(node), bNodeStack ** np.co = new_co; np.dxt = new_dxt; np.dyt = new_dyt; - + tex_input_vec(scale, in[1], p, thread); mul_v3_v3v3(new_co, p->co, scale); @@ -60,10 +60,10 @@ static void colorfn(float *out, TexParams *p, bNode *UNUSED(node), bNodeStack ** mul_v3_v3v3(new_dxt, p->dxt, scale); mul_v3_v3v3(new_dyt, p->dyt, scale); } - + tex_input_rgba(out, in[0], &np, thread); } -static void exec(void *data, int UNUSED(thread), bNode *node, bNodeExecData *execdata, bNodeStack **in, bNodeStack **out) +static void exec(void *data, int UNUSED(thread), bNode *node, bNodeExecData *execdata, bNodeStack **in, bNodeStack **out) { tex_output(node, execdata, in, out[0], &colorfn, data); } @@ -71,10 +71,10 @@ static void exec(void *data, int UNUSED(thread), bNode *node, bNodeExecData *exe void register_node_type_tex_scale(void) { static bNodeType ntype; - + tex_node_type_base(&ntype, TEX_NODE_SCALE, "Scale", NODE_CLASS_DISTORT, 0); node_type_socket_templates(&ntype, inputs, outputs); node_type_exec(&ntype, NULL, NULL, exec); - + nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/texture/nodes/node_texture_texture.c b/source/blender/nodes/texture/nodes/node_texture_texture.c index f77234ae1ae..ff405cc9f3e 100644 --- a/source/blender/nodes/texture/nodes/node_texture_texture.c +++ b/source/blender/nodes/texture/nodes/node_texture_texture.c @@ -52,7 +52,7 @@ static void colorfn(float *out, TexParams *p, bNode *node, bNodeStack **in, shor static float red[] = {1, 0, 0, 1}; static float white[] = {1, 1, 1, 1}; float co[3], dxt[3], dyt[3]; - + copy_v3_v3(co, p->co); if (p->osatex) { copy_v3_v3(dxt, p->dxt); @@ -62,7 +62,7 @@ static void colorfn(float *out, TexParams *p, bNode *node, bNodeStack **in, shor zero_v3(dxt); zero_v3(dyt); } - + if (node->custom2 || node->need_exec == 0) { /* this node refers to its own texture tree! */ copy_v4_v4(out, (fabsf(co[0] - co[1]) < 0.01f) ? white : red); @@ -72,14 +72,14 @@ static void colorfn(float *out, TexParams *p, bNode *node, bNodeStack **in, shor int textype; float nor[] = {0, 0, 0}; float col1[4], col2[4]; - + tex_input_rgba(col1, in[0], p, thread); tex_input_rgba(col2, in[1], p, thread); - + texres.nor = nor; textype = multitex_nodes(nodetex, co, dxt, dyt, p->osatex, &texres, thread, 0, p->mtex, NULL); - + if (textype & TEX_RGB) { copy_v4_v4(out, &texres.tr); } @@ -98,10 +98,10 @@ static void exec(void *data, int UNUSED(thread), bNode *node, bNodeExecData *exe void register_node_type_tex_texture(void) { static bNodeType ntype; - + tex_node_type_base(&ntype, TEX_NODE_TEXTURE, "Texture", NODE_CLASS_INPUT, NODE_PREVIEW); node_type_socket_templates(&ntype, inputs, outputs); node_type_exec(&ntype, NULL, NULL, exec); - + nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/texture/nodes/node_texture_translate.c b/source/blender/nodes/texture/nodes/node_texture_translate.c index ec90029c0bf..fa8319d077b 100644 --- a/source/blender/nodes/texture/nodes/node_texture_translate.c +++ b/source/blender/nodes/texture/nodes/node_texture_translate.c @@ -50,16 +50,16 @@ static void colorfn(float *out, TexParams *p, bNode *UNUSED(node), bNodeStack ** float offset[3], new_co[3]; TexParams np = *p; np.co = new_co; - + tex_input_vec(offset, in[1], p, thread); - + new_co[0] = p->co[0] + offset[0]; new_co[1] = p->co[1] + offset[1]; new_co[2] = p->co[2] + offset[2]; - + tex_input_rgba(out, in[0], &np, thread); } -static void exec(void *data, int UNUSED(thread), bNode *node, bNodeExecData *execdata, bNodeStack **in, bNodeStack **out) +static void exec(void *data, int UNUSED(thread), bNode *node, bNodeExecData *execdata, bNodeStack **in, bNodeStack **out) { tex_output(node, execdata, in, out[0], &colorfn, data); } @@ -67,10 +67,10 @@ static void exec(void *data, int UNUSED(thread), bNode *node, bNodeExecData *exe void register_node_type_tex_translate(void) { static bNodeType ntype; - + tex_node_type_base(&ntype, TEX_NODE_TRANSLATE, "Translate", NODE_CLASS_DISTORT, 0); node_type_socket_templates(&ntype, inputs, outputs); node_type_exec(&ntype, NULL, NULL, exec); - + nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/texture/nodes/node_texture_valToNor.c b/source/blender/nodes/texture/nodes/node_texture_valToNor.c index 995fb6c1782..b7d57b4d4cf 100644 --- a/source/blender/nodes/texture/nodes/node_texture_valToNor.c +++ b/source/blender/nodes/texture/nodes/node_texture_valToNor.c @@ -52,7 +52,7 @@ static void normalfn(float *out, TexParams *p, bNode *UNUSED(node), bNodeStack * float nabla = tex_input_value(in[1], p, thread); float val; float nor[3]; - + TexParams np = *p; np.co = new_co; @@ -66,7 +66,7 @@ static void normalfn(float *out, TexParams *p, bNode *UNUSED(node), bNodeStack * new_co[0] = co[0]; new_co[1] = co[1] + nabla; nor[1] = tex_input_value(in[0], &np, thread); - + new_co[1] = co[1]; new_co[2] = co[2] + nabla; nor[2] = tex_input_value(in[0], &np, thread); @@ -75,7 +75,7 @@ static void normalfn(float *out, TexParams *p, bNode *UNUSED(node), bNodeStack * out[1] = val - nor[1]; out[2] = val - nor[2]; } -static void exec(void *data, int UNUSED(thread), bNode *node, bNodeExecData *execdata, bNodeStack **in, bNodeStack **out) +static void exec(void *data, int UNUSED(thread), bNode *node, bNodeExecData *execdata, bNodeStack **in, bNodeStack **out) { tex_output(node, execdata, in, out[0], &normalfn, data); } @@ -83,10 +83,10 @@ static void exec(void *data, int UNUSED(thread), bNode *node, bNodeExecData *exe void register_node_type_tex_valtonor(void) { static bNodeType ntype; - + tex_node_type_base(&ntype, TEX_NODE_VALTONOR, "Value to Normal", NODE_CLASS_CONVERTOR, 0); node_type_socket_templates(&ntype, inputs, outputs); node_type_exec(&ntype, NULL, NULL, exec); - + nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/texture/nodes/node_texture_valToRgb.c b/source/blender/nodes/texture/nodes/node_texture_valToRgb.c index 4041d666811..ad3c4344f34 100644 --- a/source/blender/nodes/texture/nodes/node_texture_valToRgb.c +++ b/source/blender/nodes/texture/nodes/node_texture_valToRgb.c @@ -53,7 +53,7 @@ static void valtorgb_colorfn(float *out, TexParams *p, bNode *node, bNodeStack * } } -static void valtorgb_exec(void *data, int UNUSED(thread), bNode *node, bNodeExecData *execdata, bNodeStack **in, bNodeStack **out) +static void valtorgb_exec(void *data, int UNUSED(thread), bNode *node, bNodeExecData *execdata, bNodeStack **in, bNodeStack **out) { tex_output(node, execdata, in, out[0], &valtorgb_colorfn, data); } @@ -66,14 +66,14 @@ static void valtorgb_init(bNodeTree *UNUSED(ntree), bNode *node) void register_node_type_tex_valtorgb(void) { static bNodeType ntype; - + tex_node_type_base(&ntype, TEX_NODE_VALTORGB, "ColorRamp", NODE_CLASS_CONVERTOR, 0); node_type_socket_templates(&ntype, valtorgb_in, valtorgb_out); node_type_size_preset(&ntype, NODE_SIZE_LARGE); node_type_init(&ntype, valtorgb_init); node_type_storage(&ntype, "ColorBand", node_free_standard_storage, node_copy_standard_storage); node_type_exec(&ntype, NULL, NULL, valtorgb_exec); - + nodeRegisterType(&ntype); } @@ -103,10 +103,10 @@ static void rgbtobw_exec(void *data, int UNUSED(thread), bNode *node, bNodeExecD void register_node_type_tex_rgbtobw(void) { static bNodeType ntype; - + tex_node_type_base(&ntype, TEX_NODE_RGBTOBW, "RGB to BW", NODE_CLASS_CONVERTOR, 0); node_type_socket_templates(&ntype, rgbtobw_in, rgbtobw_out); node_type_exec(&ntype, NULL, NULL, rgbtobw_exec); - + nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/texture/nodes/node_texture_viewer.c b/source/blender/nodes/texture/nodes/node_texture_viewer.c index fefa06b0078..69f4d3ca086 100644 --- a/source/blender/nodes/texture/nodes/node_texture_viewer.c +++ b/source/blender/nodes/texture/nodes/node_texture_viewer.c @@ -59,13 +59,13 @@ static void exec(void *data, int UNUSED(thread), bNode *UNUSED(node), bNodeExecD void register_node_type_tex_viewer(void) { static bNodeType ntype; - + tex_node_type_base(&ntype, TEX_NODE_VIEWER, "Viewer", NODE_CLASS_OUTPUT, NODE_PREVIEW); node_type_socket_templates(&ntype, inputs, outputs); node_type_exec(&ntype, NULL, NULL, exec); - + /* Do not allow muting viewer node. */ node_type_internal_links(&ntype, NULL); - + nodeRegisterType(&ntype); } diff --git a/source/blender/physics/intern/BPH_mass_spring.cpp b/source/blender/physics/intern/BPH_mass_spring.cpp index e5724c97bbc..c8932045c52 100644 --- a/source/blender/physics/intern/BPH_mass_spring.cpp +++ b/source/blender/physics/intern/BPH_mass_spring.cpp @@ -60,7 +60,7 @@ static int cloth_count_nondiag_blocks(Cloth *cloth) { LinkNode *link; int nondiag = 0; - + for (link = cloth->springs; link; link = link->next) { ClothSpring *spring = (ClothSpring *)link->link; switch (spring->type) { @@ -68,14 +68,14 @@ static int cloth_count_nondiag_blocks(Cloth *cloth) /* angular bending combines 3 vertices */ nondiag += 3; break; - + default: /* all other springs depend on 2 vertices only */ nondiag += 1; break; } } - + return nondiag; } @@ -86,25 +86,25 @@ int BPH_cloth_solver_init(Object *UNUSED(ob), ClothModifierData *clmd) const float ZERO[3] = {0.0f, 0.0f, 0.0f}; Implicit_Data *id; unsigned int i, nondiag; - + nondiag = cloth_count_nondiag_blocks(cloth); cloth->implicit = id = BPH_mass_spring_solver_create(cloth->mvert_num, nondiag); - + for (i = 0; i < cloth->mvert_num; i++) { BPH_mass_spring_set_vertex_mass(id, i, verts[i].mass); } - + for (i = 0; i < cloth->mvert_num; i++) { BPH_mass_spring_set_motion_state(id, i, verts[i].x, ZERO); } - + return 1; } void BPH_cloth_solver_free(ClothModifierData *clmd) { Cloth *cloth = clmd->clothObject; - + if (cloth->implicit) { BPH_mass_spring_solver_free(cloth->implicit); cloth->implicit = NULL; @@ -118,7 +118,7 @@ void BKE_cloth_solver_set_positions(ClothModifierData *clmd) unsigned int mvert_num = cloth->mvert_num, i; ClothHairData *cloth_hairdata = clmd->hairdata; Implicit_Data *id = cloth->implicit; - + for (i = 0; i < mvert_num; i++) { if (cloth_hairdata) { ClothHairData *root = &cloth_hairdata[i]; @@ -126,7 +126,7 @@ void BKE_cloth_solver_set_positions(ClothModifierData *clmd) } else BPH_mass_spring_set_rest_transform(id, i, I3); - + BPH_mass_spring_set_motion_state(id, i, verts[i].x, verts[i].v); } } @@ -136,22 +136,22 @@ static bool collision_response(ClothModifierData *clmd, CollisionModifierData *c Cloth *cloth = clmd->clothObject; int index = collpair->ap1; bool result = false; - + float v1[3], v2_old[3], v2_new[3], v_rel_old[3], v_rel_new[3]; float epsilon2 = BLI_bvhtree_get_epsilon(collmd->bvhtree); float margin_distance = (float)collpair->distance - epsilon2; float mag_v_rel; - + zero_v3(r_impulse); - + if (margin_distance > 0.0f) return false; /* XXX tested before already? */ - + /* only handle static collisions here */ if ( collpair->flag & COLLISION_IN_FUTURE ) return false; - + /* velocity */ copy_v3_v3(v1, cloth->verts[index].v); collision_get_collider_velocity(v2_old, v2_new, collmd, collpair); @@ -160,32 +160,32 @@ static bool collision_response(ClothModifierData *clmd, CollisionModifierData *c sub_v3_v3v3(v_rel_new, v1, v2_new); /* normal component of the relative velocity */ mag_v_rel = dot_v3v3(v_rel_old, collpair->normal); - + /* only valid when moving toward the collider */ if (mag_v_rel < -ALMOST_ZERO) { float v_nor_old, v_nor_new; float v_tan_old[3], v_tan_new[3]; float bounce, repulse; - + /* Collision response based on * "Simulating Complex Hair with Robust Collision Handling" (Choe, Choi, Ko, ACM SIGGRAPH 2005) * http://graphics.snu.ac.kr/publications/2005-choe-HairSim/Choe_2005_SCA.pdf */ - + v_nor_old = mag_v_rel; v_nor_new = dot_v3v3(v_rel_new, collpair->normal); - + madd_v3_v3v3fl(v_tan_old, v_rel_old, collpair->normal, -v_nor_old); madd_v3_v3v3fl(v_tan_new, v_rel_new, collpair->normal, -v_nor_new); - + bounce = -v_nor_old * restitution; - + repulse = -margin_distance / dt; /* base repulsion velocity in normal direction */ /* XXX this clamping factor is quite arbitrary ... * not sure if there is a more scientific approach, but seems to give good results */ CLAMP(repulse, 0.0f, 4.0f * bounce); - + if (margin_distance < -epsilon2) { mul_v3_v3fl(r_impulse, collpair->normal, max_ff(repulse, bounce) - v_nor_new); } @@ -193,10 +193,10 @@ static bool collision_response(ClothModifierData *clmd, CollisionModifierData *c bounce = 0.0f; mul_v3_v3fl(r_impulse, collpair->normal, repulse - v_nor_new); } - + result = true; } - + return result; } @@ -211,17 +211,17 @@ static void cloth_setup_constraints(ClothModifierData *clmd, ColliderContacts *c ClothVertex *verts = cloth->verts; int mvert_num = cloth->mvert_num; int i, j, v; - + const float ZERO[3] = {0.0f, 0.0f, 0.0f}; - + BPH_mass_spring_clear_constraints(data); - + for (v = 0; v < mvert_num; v++) { if (verts[v].flags & CLOTH_VERT_FLAG_PINNED) { /* pinned vertex constraints */ BPH_mass_spring_add_constraint_ndof0(data, v, ZERO); /* velocity is defined externally */ } - + verts[v].impulse_count = 0; } @@ -233,21 +233,21 @@ static void cloth_setup_constraints(ClothModifierData *clmd, ColliderContacts *c float restitution = 0.0f; int v = collpair->face1; float impulse[3]; - + /* pinned verts handled separately */ if (verts[v].flags & CLOTH_VERT_FLAG_PINNED) continue; - + /* XXX cheap way of avoiding instability from multiple collisions in the same step * this should eventually be supported ... */ if (verts[v].impulse_count > 0) continue; - + /* calculate collision response */ if (!collision_response(clmd, ct->collmd, collpair, dt, restitution, impulse)) continue; - + BPH_mass_spring_add_constraint_ndof2(data, v, collpair->normal, impulse); ++verts[v].impulse_count; } @@ -267,11 +267,11 @@ static int UNUSED_FUNCTION(cloth_calc_helper_forces)(Object *UNUSED(ob), ClothMo ClothSpring *spring; ClothVertex *cv; int i, steps; - + cv = cloth->verts; for (i = 0; i < cloth->mvert_num; i++, cv++) { copy_v3_v3(cos[i], cv->tx); - + if (cv->goal == 1.0f || len_squared_v3v3(initial_cos[i], cv->tx) != 0.0f) { masses[i] = 1e+10; } @@ -279,57 +279,57 @@ static int UNUSED_FUNCTION(cloth_calc_helper_forces)(Object *UNUSED(ob), ClothMo masses[i] = cv->mass; } } - + steps = 55; for (i=0; i<steps; i++) { for (node=cloth->springs; node; node=node->next) { /* ClothVertex *cv1, *cv2; */ /* UNUSED */ int v1, v2; float len, c, l, vec[3]; - + spring = (ClothSpring *)node->link; - if (spring->type != CLOTH_SPRING_TYPE_STRUCTURAL && spring->type != CLOTH_SPRING_TYPE_SHEAR) + if (spring->type != CLOTH_SPRING_TYPE_STRUCTURAL && spring->type != CLOTH_SPRING_TYPE_SHEAR) continue; - + v1 = spring->ij; v2 = spring->kl; /* cv1 = cloth->verts + v1; */ /* UNUSED */ /* cv2 = cloth->verts + v2; */ /* UNUSED */ len = len_v3v3(cos[v1], cos[v2]); - + sub_v3_v3v3(vec, cos[v1], cos[v2]); normalize_v3(vec); - + c = (len - spring->restlen); if (c == 0.0f) continue; - + l = c / ((1.0f / masses[v1]) + (1.0f / masses[v2])); - + mul_v3_fl(vec, -(1.0f / masses[v1]) * l); add_v3_v3(cos[v1], vec); - + sub_v3_v3v3(vec, cos[v2], cos[v1]); normalize_v3(vec); - + mul_v3_fl(vec, -(1.0f / masses[v2]) * l); add_v3_v3(cos[v2], vec); } } - + cv = cloth->verts; for (i = 0; i < cloth->mvert_num; i++, cv++) { float vec[3]; - + /*compute forces*/ sub_v3_v3v3(vec, cos[i], cv->tx); mul_v3_fl(vec, cv->mass*dt*20.0f); add_v3_v3(cv->tv, vec); //copy_v3_v3(cv->tx, cos[i]); } - + MEM_freeN(cos); MEM_freeN(masses); - + return 1; } @@ -338,21 +338,21 @@ BLI_INLINE void cloth_calc_spring_force(ClothModifierData *clmd, ClothSpring *s) Cloth *cloth = clmd->clothObject; ClothSimSettings *parms = clmd->sim_parms; Implicit_Data *data = cloth->implicit; - + bool no_compress = parms->flags & CLOTH_SIMSETTINGS_FLAG_NO_SPRING_COMPRESS; - + s->flags &= ~CLOTH_SPRING_FLAG_NEEDED; - + // calculate force of structural + shear springs if ((s->type & CLOTH_SPRING_TYPE_STRUCTURAL) || (s->type & CLOTH_SPRING_TYPE_SHEAR) || (s->type & CLOTH_SPRING_TYPE_SEWING) ) { #ifdef CLOTH_FORCE_SPRING_STRUCTURAL float k, scaling; - + s->flags |= CLOTH_SPRING_FLAG_NEEDED; - + scaling = parms->structural + s->stiffness * fabsf(parms->max_struct - parms->structural); k = scaling / (parms->avg_spring_len + FLT_EPSILON); - + if (s->type & CLOTH_SPRING_TYPE_SEWING) { // TODO: verify, half verified (couldn't see error) // sewing springs usually have a large distance at first so clamp the force so we don't get tunnelling through colission objects @@ -366,50 +366,50 @@ BLI_INLINE void cloth_calc_spring_force(ClothModifierData *clmd, ClothSpring *s) else if (s->type & CLOTH_SPRING_TYPE_BENDING) { /* calculate force of bending springs */ #ifdef CLOTH_FORCE_SPRING_BEND float kb, cb, scaling; - + s->flags |= CLOTH_SPRING_FLAG_NEEDED; - + scaling = parms->bending + s->stiffness * fabsf(parms->max_bend - parms->bending); kb = scaling / (20.0f * (parms->avg_spring_len + FLT_EPSILON)); - + // Fix for [#45084] for cloth stiffness must have cb proportional to kb cb = kb * parms->bending_damping; - + BPH_mass_spring_force_spring_bending(data, s->ij, s->kl, s->restlen, kb, cb); #endif } else if (s->type & CLOTH_SPRING_TYPE_BENDING_ANG) { #ifdef CLOTH_FORCE_SPRING_BEND float kb, cb, scaling; - + s->flags |= CLOTH_SPRING_FLAG_NEEDED; - + /* XXX WARNING: angular bending springs for hair apply stiffness factor as an overall factor, unlike cloth springs! * this is crap, but needed due to cloth/hair mixing ... * max_bend factor is not even used for hair, so ... */ scaling = s->stiffness * parms->bending; kb = scaling / (20.0f * (parms->avg_spring_len + FLT_EPSILON)); - + // Fix for [#45084] for cloth stiffness must have cb proportional to kb cb = kb * parms->bending_damping; - + /* XXX assuming same restlen for ij and jk segments here, this can be done correctly for hair later */ BPH_mass_spring_force_spring_bending_angular(data, s->ij, s->kl, s->mn, s->target, kb, cb); - + #if 0 { float x_kl[3], x_mn[3], v[3], d[3]; - + BPH_mass_spring_get_motion_state(data, s->kl, x_kl, v); BPH_mass_spring_get_motion_state(data, s->mn, x_mn, v); - + BKE_sim_debug_data_add_dot(clmd->debug_data, x_kl, 0.9, 0.9, 0.9, "target", 7980, s->kl); BKE_sim_debug_data_add_line(clmd->debug_data, x_kl, x_mn, 0.8, 0.8, 0.8, "target", 7981, s->kl); - + copy_v3_v3(d, s->target); BKE_sim_debug_data_add_vector(clmd->debug_data, x_kl, d, 0.8, 0.8, 0.2, "target", 7982, s->kl); - + // copy_v3_v3(d, s->target_ij); // BKE_sim_debug_data_add_vector(clmd->debug_data, x, d, 1, 0.4, 0.4, "target", 7983, s->kl); } @@ -424,7 +424,7 @@ static void hair_get_boundbox(ClothModifierData *clmd, float gmin[3], float gmax Implicit_Data *data = cloth->implicit; unsigned int mvert_num = cloth->mvert_num; int i; - + INIT_MINMAX(gmin, gmax); for (i = 0; i < mvert_num; i++) { float x[3]; @@ -444,7 +444,7 @@ static void cloth_calc_force(ClothModifierData *clmd, float UNUSED(frame), ListB const MVertTri *tri = cloth->tri; unsigned int mvert_num = cloth->mvert_num; ClothVertex *vert; - + #ifdef CLOTH_FORCE_GRAVITY /* global acceleration (gravitation) */ if (clmd->scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY) { @@ -477,7 +477,7 @@ static void cloth_calc_force(ClothModifierData *clmd, float UNUSED(frame), ListB #ifdef CLOTH_FORCE_DRAG BPH_mass_spring_force_drag(data, drag); #endif - + /* handle external forces like wind */ if (effectors) { /* cache per-vertex forces to avoid redundant calculation */ @@ -485,12 +485,12 @@ static void cloth_calc_force(ClothModifierData *clmd, float UNUSED(frame), ListB for (i = 0; i < cloth->mvert_num; i++) { float x[3], v[3]; EffectedPoint epoint; - + BPH_mass_spring_get_motion_state(data, i, x, v); pd_point_from_loc(clmd->scene, x, v, i, &epoint); pdDoEffectors(effectors, NULL, clmd->sim_parms->effector_weights, &epoint, winvec[i], NULL); } - + for (i = 0; i < cloth->tri_num; i++) { const MVertTri *vt = &tri[i]; BPH_mass_spring_force_face_wind(data, vt->tri[0], vt->tri[1], vt->tri[2], winvec); @@ -501,7 +501,7 @@ static void cloth_calc_force(ClothModifierData *clmd, float UNUSED(frame), ListB #if 0 ClothHairData *hairdata = clmd->hairdata; ClothHairData *hair_ij, *hair_kl; - + for (LinkNode *link = cloth->springs; link; link = link->next) { ClothSpring *spring = (ClothSpring *)link->link; if (spring->type == CLOTH_SPRING_TYPE_STRUCTURAL) { @@ -516,7 +516,7 @@ static void cloth_calc_force(ClothModifierData *clmd, float UNUSED(frame), ListB } #else ClothHairData *hairdata = clmd->hairdata; - + vert = cloth->verts; for (i = 0; i < cloth->mvert_num; i++, vert++) { if (hairdata) { @@ -531,7 +531,7 @@ static void cloth_calc_force(ClothModifierData *clmd, float UNUSED(frame), ListB MEM_freeN(winvec); } - + // calculate spring forces for (LinkNode *link = cloth->springs; link; link = link->next) { ClothSpring *spring = (ClothSpring *)link->link; @@ -548,7 +548,7 @@ BLI_INLINE void cloth_get_grid_location(Implicit_Data *data, float cell_scale, c { BPH_mass_spring_get_position(data, index, x); BPH_mass_spring_get_new_velocity(data, index, v); - + mul_v3_fl(x, cell_scale); add_v3_v3(x, cell_offset); } @@ -582,41 +582,41 @@ static LinkNode *cloth_continuum_add_hair_segments(HairGrid *grid, const float c // ClothVertex *vert3, *vert4; float x1[3], v1[3], x2[3], v2[3], x3[3], v3[3], x4[3], v4[3]; float dir1[3], dir2[3], dir3[3]; - + spring1 = NULL; spring2 = NULL; spring3 = (ClothSpring *)spring_link->link; - + zero_v3(x1); zero_v3(v1); zero_v3(dir1); zero_v3(x2); zero_v3(v2); zero_v3(dir2); - + // vert3 = &verts[spring3->kl]; cloth_get_grid_location(data, cell_scale, cell_offset, spring3->kl, x3, v3); // vert4 = &verts[spring3->ij]; cloth_get_grid_location(data, cell_scale, cell_offset, spring3->ij, x4, v4); sub_v3_v3v3(dir3, x4, x3); normalize_v3(dir3); - + while (spring_link) { /* move on */ spring1 = spring2; spring2 = spring3; - + // vert3 = vert4; - + copy_v3_v3(x1, x2); copy_v3_v3(v1, v2); copy_v3_v3(x2, x3); copy_v3_v3(v2, v3); copy_v3_v3(x3, x4); copy_v3_v3(v3, v4); - + copy_v3_v3(dir1, dir2); copy_v3_v3(dir2, dir3); - + /* read next segment */ next_spring_link = spring_link->next; spring_link = hair_spring_next(spring_link); - + if (spring_link) { spring3 = (ClothSpring *)spring_link->link; // vert4 = &verts[spring3->ij]; @@ -630,13 +630,13 @@ static LinkNode *cloth_continuum_add_hair_segments(HairGrid *grid, const float c zero_v3(x4); zero_v3(v4); zero_v3(dir3); } - + BPH_hair_volume_add_segment(grid, x1, v1, x2, v2, x3, v3, x4, v4, spring1 ? dir1 : NULL, dir2, spring3 ? dir3 : NULL); } - + return next_spring_link; } @@ -647,17 +647,17 @@ static void cloth_continuum_fill_grid(HairGrid *grid, Cloth *cloth) int mvert_num = cloth->mvert_num; ClothVertex *vert; int i; - + for (i = 0, vert = cloth->verts; i < mvert_num; i++, vert++) { float x[3], v[3]; - + cloth_get_vertex_motion_state(data, vert, x, v); BPH_hair_volume_add_vertex(grid, x, v); } #else LinkNode *link; float cellsize, gmin[3], cell_scale, cell_offset[3]; - + /* scale and offset for transforming vertex locations into grid space * (cell size is 0..1, gmin becomes origin) */ @@ -665,7 +665,7 @@ static void cloth_continuum_fill_grid(HairGrid *grid, Cloth *cloth) cell_scale = cellsize > 0.0f ? 1.0f / cellsize : 0.0f; mul_v3_v3fl(cell_offset, gmin, cell_scale); negate_v3(cell_offset); - + link = cloth->springs; while (link) { ClothSpring *spring = (ClothSpring *)link->link; @@ -685,7 +685,7 @@ static void cloth_continuum_step(ClothModifierData *clmd, float dt) Implicit_Data *data = cloth->implicit; int mvert_num = cloth->mvert_num; ClothVertex *vert; - + const float fluid_factor = 0.95f; /* blend between PIC and FLIP methods */ float smoothfac = parms->velocity_smooth; /* XXX FIXME arbitrary factor!!! this should be based on some intuitive value instead, @@ -695,42 +695,42 @@ static void cloth_continuum_step(ClothModifierData *clmd, float dt) float density_strength = parms->density_strength; float gmin[3], gmax[3]; int i; - + /* clear grid info */ zero_v3_int(clmd->hair_grid_res); zero_v3(clmd->hair_grid_min); zero_v3(clmd->hair_grid_max); clmd->hair_grid_cellsize = 0.0f; - + hair_get_boundbox(clmd, gmin, gmax); - + /* gather velocities & density */ if (smoothfac > 0.0f || density_strength > 0.0f) { HairGrid *grid = BPH_hair_volume_create_vertex_grid(clmd->sim_parms->voxel_cell_size, gmin, gmax); - + cloth_continuum_fill_grid(grid, cloth); - + /* main hair continuum solver */ BPH_hair_volume_solve_divergence(grid, dt, density_target, density_strength); - + for (i = 0, vert = cloth->verts; i < mvert_num; i++, vert++) { float x[3], v[3], nv[3]; - + /* calculate volumetric velocity influence */ BPH_mass_spring_get_position(data, i, x); BPH_mass_spring_get_new_velocity(data, i, v); - + BPH_hair_volume_grid_velocity(grid, x, v, fluid_factor, nv); - + interp_v3_v3v3(nv, v, nv, smoothfac); - + /* apply on hair data */ BPH_mass_spring_set_new_velocity(data, i, nv); } - + /* store basic grid info in the modifier data */ BPH_hair_volume_grid_geometry(grid, &clmd->hair_grid_cellsize, clmd->hair_grid_res, clmd->hair_grid_min, clmd->hair_grid_max); - + #if 0 /* DEBUG hair velocity vector field */ { const int size = 64; @@ -738,26 +738,26 @@ static void cloth_continuum_step(ClothModifierData *clmd, float dt) float offset[3], a[3], b[3]; const int axis = 0; const float shift = 0.0f; - + copy_v3_v3(offset, clmd->hair_grid_min); zero_v3(a); zero_v3(b); - + offset[axis] = shift * clmd->hair_grid_cellsize; a[(axis+1) % 3] = clmd->hair_grid_max[(axis+1) % 3] - clmd->hair_grid_min[(axis+1) % 3]; b[(axis+2) % 3] = clmd->hair_grid_max[(axis+2) % 3] - clmd->hair_grid_min[(axis+2) % 3]; - + BKE_sim_debug_data_clear_category(clmd->debug_data, "grid velocity"); for (j = 0; j < size; ++j) { for (i = 0; i < size; ++i) { float x[3], v[3], gvel[3], gvel_smooth[3], gdensity; - + madd_v3_v3v3fl(x, offset, a, (float)i / (float)(size-1)); madd_v3_v3fl(x, b, (float)j / (float)(size-1)); zero_v3(v); - + BPH_hair_volume_grid_interpolate(grid, x, &gdensity, gvel, gvel_smooth, NULL, NULL); - + // BKE_sim_debug_data_add_circle(clmd->debug_data, x, gdensity, 0.7, 0.3, 1, "grid density", i, j, 3111); if (!is_zero_v3(gvel) || !is_zero_v3(gvel_smooth)) { float dvel[3]; @@ -770,7 +770,7 @@ static void cloth_continuum_step(ClothModifierData *clmd, float dt) float col0[3] = {0.0, 0.0, 0.0}; float col1[3] = {0.0, 1.0, 0.0}; float col[3]; - + interp_v3_v3v3(col, col0, col1, CLAMPIS(gdensity * clmd->sim_parms->density_strength, 0.0, 1.0)); // BKE_sim_debug_data_add_circle(clmd->debug_data, x, gdensity * clmd->sim_parms->density_strength, 0, 1, 0.4, "grid velocity", i, j, 3115); // BKE_sim_debug_data_add_dot(clmd->debug_data, x, col[0], col[1], col[2], "grid velocity", i, j, 3115); @@ -782,7 +782,7 @@ static void cloth_continuum_step(ClothModifierData *clmd, float dt) } } #endif - + BPH_hair_volume_free_vertex_grid(grid); } } @@ -795,7 +795,7 @@ static void cloth_calc_volume_force(ClothModifierData *clmd) Implicit_Data *data = cloth->implicit; int mvert_num = cloth->mvert_num; ClothVertex *vert; - + /* 2.0f is an experimental value that seems to give good results */ float smoothfac = 2.0f * parms->velocity_smooth; float collfac = 2.0f * parms->collider_friction; @@ -803,17 +803,17 @@ static void cloth_calc_volume_force(ClothModifierData *clmd) float minpress = parms->pressure_threshold; float gmin[3], gmax[3]; int i; - + hair_get_boundbox(clmd, gmin, gmax); - + /* gather velocities & density */ if (smoothfac > 0.0f || pressfac > 0.0f) { HairVertexGrid *vertex_grid = BPH_hair_volume_create_vertex_grid(clmd->sim_parms->voxel_res, gmin, gmax); - + vert = cloth->verts; for (i = 0; i < mvert_num; i++, vert++) { float x[3], v[3]; - + if (vert->solver_index < 0) { copy_v3_v3(x, vert->x); copy_v3_v3(v, vert->v); @@ -824,21 +824,21 @@ static void cloth_calc_volume_force(ClothModifierData *clmd) BPH_hair_volume_add_vertex(vertex_grid, x, v); } BPH_hair_volume_normalize_vertex_grid(vertex_grid); - + vert = cloth->verts; for (i = 0; i < mvert_num; i++, vert++) { float x[3], v[3], f[3], dfdx[3][3], dfdv[3][3]; - + if (vert->solver_index < 0) continue; - + /* calculate volumetric forces */ BPH_mass_spring_get_motion_state(data, vert->solver_index, x, v); BPH_hair_volume_vertex_grid_forces(vertex_grid, x, v, smoothfac, pressfac, minpress, f, dfdx, dfdv); /* apply on hair data */ BPH_mass_spring_force_extern(data, vert->solver_index, f, dfdx, dfdv); } - + BPH_hair_volume_free_vertex_grid(vertex_grid); } } @@ -854,33 +854,33 @@ static void cloth_collision_solve_extra(Object *ob, ClothModifierData *clmd, Lis ClothVertex *verts = cloth->verts; int mvert_num = cloth->mvert_num; const float spf = (float)clmd->sim_parms->stepsPerFrame / clmd->sim_parms->timescale; - + bool do_extra_solve; int i; - + if (!(clmd->coll_parms->flags & CLOTH_COLLSETTINGS_FLAG_ENABLED)) return; if (!clmd->clothObject->bvhtree) return; - + // update verts to current positions for (i = 0; i < mvert_num; i++) { BPH_mass_spring_get_new_position(id, i, verts[i].tx); - + sub_v3_v3v3(verts[i].tv, verts[i].tx, verts[i].txold); copy_v3_v3(verts[i].v, verts[i].tv); } - + #if 0 /* unused */ for (i=0, cv=cloth->verts; i<cloth->mvert_num; i++, cv++) { copy_v3_v3(initial_cos[i], cv->tx); } #endif - + // call collision function // TODO: check if "step" or "step+dt" is correct - dg do_extra_solve = cloth_bvh_objcollision(ob, clmd, step / clmd->sim_parms->timescale, dt / clmd->sim_parms->timescale); - + // copy corrected positions back to simulation for (i = 0; i < mvert_num; i++) { float curx[3]; @@ -888,41 +888,41 @@ static void cloth_collision_solve_extra(Object *ob, ClothModifierData *clmd, Lis // correct velocity again, just to be sure we had to change it due to adaptive collisions sub_v3_v3v3(verts[i].tv, verts[i].tx, curx); } - + if (do_extra_solve) { // cloth_calc_helper_forces(ob, clmd, initial_cos, step/clmd->sim_parms->timescale, dt/clmd->sim_parms->timescale); - + for (i = 0; i < mvert_num; i++) { - + float newv[3]; - + if ((clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL) && (verts [i].flags & CLOTH_VERT_FLAG_PINNED)) continue; - + BPH_mass_spring_set_new_position(id, i, verts[i].tx); mul_v3_v3fl(newv, verts[i].tv, spf); BPH_mass_spring_set_new_velocity(id, i, newv); } } - + // X = Xnew; BPH_mass_spring_apply_result(id); - + if (do_extra_solve) { ImplicitSolverResult result; - + /* initialize forces to zero */ BPH_mass_spring_clear_forces(id); - + // calculate forces cloth_calc_force(clmd, frame, effectors, step); - + // calculate new velocity and position BPH_mass_spring_solve_velocities(id, dt, &result); // cloth_record_result(clmd, &result, clmd->sim_parms->stepsPerFrame); - + /* note: positions are advanced only once in the main solver step! */ - + BPH_mass_spring_apply_result(id); } } @@ -930,7 +930,7 @@ static void cloth_collision_solve_extra(Object *ob, ClothModifierData *clmd, Lis static void cloth_clear_result(ClothModifierData *clmd) { ClothSolverResult *sres = clmd->solver_result; - + sres->status = 0; sres->max_error = sres->min_error = sres->avg_error = 0.0f; sres->max_iterations = sres->min_iterations = 0; @@ -940,7 +940,7 @@ static void cloth_clear_result(ClothModifierData *clmd) static void cloth_record_result(ClothModifierData *clmd, ImplicitSolverResult *result, int steps) { ClothSolverResult *sres = clmd->solver_result; - + if (sres->status) { /* already initialized ? */ /* error only makes sense for successful iterations */ if (result->status == BPH_SOLVER_SUCCESS) { @@ -948,7 +948,7 @@ static void cloth_record_result(ClothModifierData *clmd, ImplicitSolverResult *r sres->max_error = max_ff(sres->max_error, result->error); sres->avg_error += result->error / (float)steps; } - + sres->min_iterations = min_ii(sres->min_iterations, result->iterations); sres->max_iterations = max_ii(sres->max_iterations, result->iterations); sres->avg_iterations += (float)result->iterations / (float)steps; @@ -959,11 +959,11 @@ static void cloth_record_result(ClothModifierData *clmd, ImplicitSolverResult *r sres->min_error = sres->max_error = result->error; sres->avg_error += result->error / (float)steps; } - + sres->min_iterations = sres->max_iterations = result->iterations; sres->avg_iterations += (float)result->iterations / (float)steps; } - + sres->status |= result->status; } @@ -974,7 +974,7 @@ int BPH_cloth_solve(Object *ob, float frame, ClothModifierData *clmd, ListBase * * Bad design, TODO */ const bool is_hair = (clmd->hairdata != NULL); - + unsigned int i=0; float step=0.0f, tf=clmd->sim_parms->timescale; Cloth *cloth = clmd->clothObject; @@ -984,13 +984,13 @@ int BPH_cloth_solve(Object *ob, float frame, ClothModifierData *clmd, ListBase * Implicit_Data *id = cloth->implicit; ColliderContacts *contacts = NULL; int totcolliders = 0; - + BKE_sim_debug_data_clear_category("collision"); - + if (!clmd->solver_result) clmd->solver_result = (ClothSolverResult *)MEM_callocN(sizeof(ClothSolverResult), "cloth solver result"); cloth_clear_result(clmd); - + if (clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL) { /* do goal stuff */ for (i = 0; i < mvert_num; i++) { // update velocities with constrained velocities from pinned verts @@ -1004,22 +1004,22 @@ int BPH_cloth_solve(Object *ob, float frame, ClothModifierData *clmd, ListBase * } } } - + while (step < tf) { ImplicitSolverResult result; - + /* copy velocities for collision */ for (i = 0; i < mvert_num; i++) { BPH_mass_spring_get_motion_state(id, i, NULL, verts[i].tv); copy_v3_v3(verts[i].v, verts[i].tv); } - + if (is_hair) { /* determine contact points */ if (clmd->coll_parms->flags & CLOTH_COLLSETTINGS_FLAG_ENABLED) { cloth_find_point_contacts(ob, clmd, 0.0f, tf, &contacts, &totcolliders); } - + /* setup vertex constraints for pinned vertices and contacts */ cloth_setup_constraints(clmd, contacts, totcolliders, dt); } @@ -1027,10 +1027,10 @@ int BPH_cloth_solve(Object *ob, float frame, ClothModifierData *clmd, ListBase * /* setup vertex constraints for pinned vertices */ cloth_setup_constraints(clmd, NULL, 0, dt); } - + /* initialize forces to zero */ BPH_mass_spring_clear_forces(id); - + // damping velocity for artistic reasons // this is a bad way to do it, should be removed imo - lukas_t if (clmd->sim_parms->vel_damping != 1.0f) { @@ -1041,26 +1041,26 @@ int BPH_cloth_solve(Object *ob, float frame, ClothModifierData *clmd, ListBase * BPH_mass_spring_set_velocity(id, i, v); } } - + // calculate forces cloth_calc_force(clmd, frame, effectors, step); - + // calculate new velocity and position BPH_mass_spring_solve_velocities(id, dt, &result); cloth_record_result(clmd, &result, clmd->sim_parms->stepsPerFrame); - + if (is_hair) { cloth_continuum_step(clmd, dt); } - + BPH_mass_spring_solve_positions(id, dt); - + if (!is_hair) { cloth_collision_solve_extra(ob, clmd, effectors, frame, step, dt); } - + BPH_mass_spring_apply_result(id); - + /* move pinned verts to correct position */ for (i = 0; i < mvert_num; i++) { if (clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL) { @@ -1071,23 +1071,23 @@ int BPH_cloth_solve(Object *ob, float frame, ClothModifierData *clmd, ListBase * BPH_mass_spring_set_position(id, i, x); } } - + BPH_mass_spring_get_motion_state(id, i, verts[i].txold, NULL); } - + /* free contact points */ if (contacts) { cloth_free_contacts(contacts, totcolliders); } - + step += dt; } - + /* copy results back to cloth data */ for (i = 0; i < mvert_num; i++) { BPH_mass_spring_get_motion_state(id, i, verts[i].x, verts[i].v); copy_v3_v3(verts[i].txold, verts[i].x); } - + return 1; } diff --git a/source/blender/physics/intern/ConstrainedConjugateGradient.h b/source/blender/physics/intern/ConstrainedConjugateGradient.h index f9c6931fe8c..2d5fb41cc73 100644 --- a/source/blender/physics/intern/ConstrainedConjugateGradient.h +++ b/source/blender/physics/intern/ConstrainedConjugateGradient.h @@ -4,7 +4,7 @@ #include <Eigen/Core> -namespace Eigen { +namespace Eigen { namespace internal { @@ -29,16 +29,16 @@ void constrained_conjugate_gradient(const MatrixType& mat, const Rhs& rhs, Dest& typedef typename Dest::RealScalar RealScalar; typedef typename Dest::Scalar Scalar; typedef Matrix<Scalar,Dynamic,1> VectorType; - + RealScalar tol = tol_error; int maxIters = iters; - + int n = mat.cols(); VectorType residual = filter * (rhs - mat * x); //initial residual RealScalar rhsNorm2 = (filter * rhs).squaredNorm(); - if(rhsNorm2 == 0) + if(rhsNorm2 == 0) { /* XXX TODO set constrained result here */ x.setZero(); @@ -54,7 +54,7 @@ void constrained_conjugate_gradient(const MatrixType& mat, const Rhs& rhs, Dest& tol_error = sqrt(residualNorm2 / rhsNorm2); return; } - + VectorType p(n); p = filter * precond.solve(residual); //initial search direction @@ -68,11 +68,11 @@ void constrained_conjugate_gradient(const MatrixType& mat, const Rhs& rhs, Dest& Scalar alpha = absNew / p.dot(tmp); // the amount we travel on dir x += alpha * p; // update solution residual -= alpha * tmp; // update residue - + residualNorm2 = residual.squaredNorm(); if(residualNorm2 < threshold) break; - + z = precond.solve(residual); // approximately solve for "A z = residual" RealScalar absOld = absNew; @@ -95,20 +95,20 @@ struct MatrixFilter m_cmat(NULL) { } - + MatrixFilter(const MatrixType &cmat) : m_cmat(&cmat) { } - + void setMatrix(const MatrixType &cmat) { m_cmat = &cmat; } - + template <typename VectorType> void apply(VectorType v) const { v = (*m_cmat) * v; } - + protected: const MatrixType *m_cmat; }; @@ -145,7 +145,7 @@ struct traits<ConstrainedConjugateGradient<_MatrixType,_UpLo,_FilterMatrixType,_ * The maximal number of iterations and tolerance value can be controlled via the setMaxIterations() * and setTolerance() methods. The defaults are the size of the problem for the maximal number of iterations * and NumTraits<Scalar>::epsilon() for the tolerance. - * + * * This class can be used as the direct solver classes. Here is a typical usage example: * \code * int n = 10000; @@ -160,7 +160,7 @@ struct traits<ConstrainedConjugateGradient<_MatrixType,_UpLo,_FilterMatrixType,_ * // update b, and solve again * x = cg.solve(b); * \endcode - * + * * By default the iterations start with x=0 as an initial guess of the solution. * One can control the start using the solveWithGuess() method. Here is a step by * step execution example starting with a random guess and printing the evolution @@ -176,7 +176,7 @@ struct traits<ConstrainedConjugateGradient<_MatrixType,_UpLo,_FilterMatrixType,_ * } while (cg.info()!=Success && i<100); * \endcode * Note that such a step by step excution is slightly slower. - * + * * \sa class SimplicialCholesky, DiagonalPreconditioner, IdentityPreconditioner */ template< typename _MatrixType, int _UpLo, typename _FilterMatrixType, typename _Preconditioner> @@ -206,10 +206,10 @@ public: ConstrainedConjugateGradient() : Base() {} /** Initialize the solver with matrix \a A for further \c Ax=b solving. - * + * * This constructor is a shortcut for the default constructor followed * by a call to compute(). - * + * * \warning this class stores a reference to the matrix A as well as some * precomputed values that depend on it. Therefore, if \a A is changed * this class becomes invalid. Call compute() to update it with the new @@ -258,7 +258,7 @@ public: m_isInitialized = true; m_info = m_error <= Base::m_tolerance ? Success : NoConvergence; } - + /** \internal */ template<typename Rhs,typename Dest> void _solve(const Rhs& b, Dest& x) const diff --git a/source/blender/physics/intern/eigen_utils.h b/source/blender/physics/intern/eigen_utils.h index 8a5a9dbf5e9..4598d3ad3a7 100644 --- a/source/blender/physics/intern/eigen_utils.h +++ b/source/blender/physics/intern/eigen_utils.h @@ -56,24 +56,24 @@ typedef float Scalar; class Vector3 : public Eigen::Vector3f { public: typedef float *ctype; - + Vector3() { } - + Vector3(const ctype &v) { for (int k = 0; k < 3; ++k) coeffRef(k) = v[k]; } - + Vector3& operator = (const ctype &v) { for (int k = 0; k < 3; ++k) coeffRef(k) = v[k]; return *this; } - + operator ctype() { return data(); @@ -86,18 +86,18 @@ public: class Matrix3 : public Eigen::Matrix3f { public: typedef float (*ctype)[3]; - + Matrix3() { } - + Matrix3(const ctype &v) { for (int k = 0; k < 3; ++k) for (int l = 0; l < 3; ++l) coeffRef(l, k) = v[k][l]; } - + Matrix3& operator = (const ctype &v) { for (int k = 0; k < 3; ++k) @@ -105,7 +105,7 @@ public: coeffRef(l, k) = v[k][l]; return *this; } - + operator ctype() { return (ctype)data(); @@ -120,23 +120,23 @@ typedef Eigen::VectorXf lVector; class lVector3f : public Eigen::VectorXf { public: typedef Eigen::VectorXf base_t; - + lVector3f() { } - + template <typename T> lVector3f& operator = (T rhs) { base_t::operator=(rhs); return *this; } - + float* v3(int vertex) { return &coeffRef(3 * vertex); } - + const float* v3(int vertex) const { return &coeffRef(3 * vertex); @@ -157,18 +157,18 @@ struct lMatrix3fCtor { lMatrix3fCtor() { } - + void reset() { m_trips.clear(); } - + void reserve(int numverts) { /* reserve for diagonal entries */ m_trips.reserve(numverts * 9); } - + void add(int i, int j, const Matrix3 &m) { i *= 3; @@ -177,7 +177,7 @@ struct lMatrix3fCtor { for (int l = 0; l < 3; ++l) m_trips.push_back(Triplet(i + k, j + l, m.coeff(l, k))); } - + void sub(int i, int j, const Matrix3 &m) { i *= 3; @@ -186,13 +186,13 @@ struct lMatrix3fCtor { for (int l = 0; l < 3; ++l) m_trips.push_back(Triplet(i + k, j + l, -m.coeff(l, k))); } - + inline void construct(lMatrix &m) { m.setFromTriplets(m_trips.begin(), m_trips.end()); m_trips.clear(); } - + private: TripletList m_trips; }; @@ -206,7 +206,7 @@ BLI_INLINE void print_lvector(const lVector3f &v) for (int i = 0; i < v.rows(); ++i) { if (i > 0 && i % 3 == 0) printf("\n"); - + printf("%f,\n", v[i]); } } @@ -216,11 +216,11 @@ BLI_INLINE void print_lmatrix(const lMatrix &m) for (int j = 0; j < m.rows(); ++j) { if (j > 0 && j % 3 == 0) printf("\n"); - + for (int i = 0; i < m.cols(); ++i) { if (i > 0 && i % 3 == 0) printf(" "); - + implicit_print_matrix_elem(m.coeff(j, i)); } printf("\n"); diff --git a/source/blender/physics/intern/hair_volume.cpp b/source/blender/physics/intern/hair_volume.cpp index 6ab69a0050c..b59ac46abbc 100644 --- a/source/blender/physics/intern/hair_volume.cpp +++ b/source/blender/physics/intern/hair_volume.cpp @@ -82,7 +82,7 @@ typedef struct HairGridVert { int samples; float velocity[3]; float density; - + float velocity_smooth[3]; } HairGridVert; @@ -107,20 +107,20 @@ BLI_INLINE int hair_grid_offset(const float vec[3], const int res[3], const floa BLI_INLINE int hair_grid_interp_weights(const int res[3], const float gmin[3], float scale, const float vec[3], float uvw[3]) { int i, j, k, offset; - + i = HAIR_GRID_INDEX_AXIS(vec, res, gmin, scale, 0); j = HAIR_GRID_INDEX_AXIS(vec, res, gmin, scale, 1); k = HAIR_GRID_INDEX_AXIS(vec, res, gmin, scale, 2); offset = i + (j + k*res[1])*res[0]; - + uvw[0] = (vec[0] - gmin[0]) * scale - (float)i; uvw[1] = (vec[1] - gmin[1]) * scale - (float)j; uvw[2] = (vec[2] - gmin[2]) * scale - (float)k; - + // BLI_assert(0.0f <= uvw[0] && uvw[0] <= 1.0001f); // BLI_assert(0.0f <= uvw[1] && uvw[1] <= 1.0001f); // BLI_assert(0.0f <= uvw[2] && uvw[2] <= 1.0001f); - + return offset; } @@ -131,12 +131,12 @@ BLI_INLINE void hair_grid_interpolate(const HairGridVert *grid, const int res[3] float uvw[3], muvw[3]; int res2 = res[1] * res[0]; int offset; - + offset = hair_grid_interp_weights(res, gmin, scale, vec, uvw); muvw[0] = 1.0f - uvw[0]; muvw[1] = 1.0f - uvw[1]; muvw[2] = 1.0f - uvw[2]; - + data[0] = grid[offset ]; data[1] = grid[offset +1]; data[2] = grid[offset +res[0] ]; @@ -145,14 +145,14 @@ BLI_INLINE void hair_grid_interpolate(const HairGridVert *grid, const int res[3] data[5] = grid[offset+res2 +1]; data[6] = grid[offset+res2+res[0] ]; data[7] = grid[offset+res2+res[0]+1]; - + if (density) { *density = muvw[2]*( muvw[1]*( muvw[0]*data[0].density + uvw[0]*data[1].density ) + uvw[1]*( muvw[0]*data[2].density + uvw[0]*data[3].density ) ) + uvw[2]*( muvw[1]*( muvw[0]*data[4].density + uvw[0]*data[5].density ) + uvw[1]*( muvw[0]*data[6].density + uvw[0]*data[7].density ) ); } - + if (velocity) { int k; for (k = 0; k < 3; ++k) { @@ -162,7 +162,7 @@ BLI_INLINE void hair_grid_interpolate(const HairGridVert *grid, const int res[3] uvw[1]*( muvw[0]*data[6].velocity[k] + uvw[0]*data[7].velocity[k] ) ); } } - + if (vel_smooth) { int k; for (k = 0; k < 3; ++k) { @@ -172,24 +172,24 @@ BLI_INLINE void hair_grid_interpolate(const HairGridVert *grid, const int res[3] uvw[1]*( muvw[0]*data[6].velocity_smooth[k] + uvw[0]*data[7].velocity_smooth[k] ) ); } } - + if (density_gradient) { density_gradient[0] = muvw[1] * muvw[2] * ( data[0].density - data[1].density ) + uvw[1] * muvw[2] * ( data[2].density - data[3].density ) + muvw[1] * uvw[2] * ( data[4].density - data[5].density ) + uvw[1] * uvw[2] * ( data[6].density - data[7].density ); - + density_gradient[1] = muvw[2] * muvw[0] * ( data[0].density - data[2].density ) + uvw[2] * muvw[0] * ( data[4].density - data[6].density ) + muvw[2] * uvw[0] * ( data[1].density - data[3].density ) + uvw[2] * uvw[0] * ( data[5].density - data[7].density ); - + density_gradient[2] = muvw[2] * muvw[0] * ( data[0].density - data[4].density ) + uvw[2] * muvw[0] * ( data[1].density - data[5].density ) + muvw[2] * uvw[0] * ( data[2].density - data[6].density ) + uvw[2] * uvw[0] * ( data[3].density - data[7].density ); } - + if (velocity_gradient) { /* XXX TODO */ zero_m3(velocity_gradient); @@ -201,21 +201,21 @@ void BPH_hair_volume_vertex_grid_forces(HairGrid *grid, const float x[3], const float f[3], float dfdx[3][3], float dfdv[3][3]) { float gdensity, gvelocity[3], ggrad[3], gvelgrad[3][3], gradlen; - + hair_grid_interpolate(grid->verts, grid->res, grid->gmin, grid->inv_cellsize, x, &gdensity, gvelocity, NULL, ggrad, gvelgrad); - + zero_v3(f); sub_v3_v3(gvelocity, v); mul_v3_v3fl(f, gvelocity, smoothfac); - + gradlen = normalize_v3(ggrad) - minpressure; if (gradlen > 0.0f) { mul_v3_fl(ggrad, gradlen); madd_v3_v3fl(f, ggrad, pressurefac); } - + zero_m3(dfdx); - + sub_m3_m3m3(dfdv, gvelgrad, I); mul_m3_fl(dfdv, smoothfac); } @@ -232,16 +232,16 @@ void BPH_hair_volume_grid_velocity(HairGrid *grid, const float x[3], const float { float gdensity, gvelocity[3], gvel_smooth[3], ggrad[3], gvelgrad[3][3]; float v_pic[3], v_flip[3]; - + hair_grid_interpolate(grid->verts, grid->res, grid->gmin, grid->inv_cellsize, x, &gdensity, gvelocity, gvel_smooth, ggrad, gvelgrad); - + /* velocity according to PIC method (Particle-in-Cell) */ copy_v3_v3(v_pic, gvel_smooth); - + /* velocity according to FLIP method (Fluid-Implicit-Particle) */ sub_v3_v3v3(v_flip, gvel_smooth, gvelocity); add_v3_v3(v_flip, v); - + interp_v3_v3v3(r_v, v_pic, v_flip, fluid_factor); } @@ -283,16 +283,16 @@ BLI_INLINE int hair_grid_weights(const int res[3], const float gmin[3], float sc { int i, j, k, offset; float uvw[3]; - + i = HAIR_GRID_INDEX_AXIS(vec, res, gmin, scale, 0); j = HAIR_GRID_INDEX_AXIS(vec, res, gmin, scale, 1); k = HAIR_GRID_INDEX_AXIS(vec, res, gmin, scale, 2); offset = i + (j + k*res[1])*res[0]; - + uvw[0] = (vec[0] - gmin[0]) * scale; uvw[1] = (vec[1] - gmin[1]) * scale; uvw[2] = (vec[2] - gmin[2]) * scale; - + weights[0] = dist_tent_v3f3(uvw, (float)i , (float)j , (float)k ); weights[1] = dist_tent_v3f3(uvw, (float)(i+1), (float)j , (float)k ); weights[2] = dist_tent_v3f3(uvw, (float)i , (float)(j+1), (float)k ); @@ -301,9 +301,9 @@ BLI_INLINE int hair_grid_weights(const int res[3], const float gmin[3], float sc weights[5] = dist_tent_v3f3(uvw, (float)(i+1), (float)j , (float)(k+1)); weights[6] = dist_tent_v3f3(uvw, (float)i , (float)(j+1), (float)(k+1)); weights[7] = dist_tent_v3f3(uvw, (float)(i+1), (float)(j+1), (float)(k+1)); - + // BLI_assert(fabsf(weights_sum(weights) - 1.0f) < 0.0001f); - + return offset; } @@ -320,18 +320,18 @@ void BPH_hair_volume_add_vertex(HairGrid *grid, const float x[3], const float v[ float weights[8]; int di, dj, dk; int offset; - + if (!hair_grid_point_valid(x, grid->gmin, grid->gmax)) return; - + offset = hair_grid_weights(res, grid->gmin, grid->inv_cellsize, x, weights); - + for (di = 0; di < 2; ++di) { for (dj = 0; dj < 2; ++dj) { for (dk = 0; dk < 2; ++dk) { int voffset = offset + di + (dj + dk*res[1])*res[0]; int iw = di + dj*2 + dk*4; - + grid->verts[voffset].density += weights[iw]; madd_v3_v3fl(grid->verts[voffset].velocity, v, weights[iw]); } @@ -344,15 +344,15 @@ BLI_INLINE void hair_volume_eval_grid_vertex(HairGridVert *vert, const float loc const float x2[3], const float v2[3], const float x3[3], const float v3[3]) { float closest[3], lambda, dist, weight; - + lambda = closest_to_line_v3(closest, loc, x2, x3); dist = len_v3v3(closest, loc); - + weight = (radius - dist) * dist_scale; - + if (weight > 0.0f) { float vel[3]; - + interp_v3_v3v3(vel, v2, v3, lambda); madd_v3_v3fl(vert->velocity, vel, weight); vert->density += weight; @@ -378,37 +378,37 @@ BLI_INLINE void hair_volume_add_segment_2D(HairGrid *grid, { const float radius = 1.5f; const float dist_scale = grid->inv_cellsize; - + int j, k; - + /* boundary checks to be safe */ CLAMP_MIN(jmin, 0); CLAMP_MAX(jmax, resj-1); CLAMP_MIN(kmin, 0); CLAMP_MAX(kmax, resk-1); - + HairGridVert *vert_j = vert + jmin * stride_j; float loc_j[3] = { loc[0], loc[1], loc[2] }; loc_j[axis_j] += (float)jmin; for (j = jmin; j <= jmax; ++j, vert_j += stride_j, loc_j[axis_j] += 1.0f) { - + HairGridVert *vert_k = vert_j + kmin * stride_k; float loc_k[3] = { loc_j[0], loc_j[1], loc_j[2] }; loc_k[axis_k] += (float)kmin; for (k = kmin; k <= kmax; ++k, vert_k += stride_k, loc_k[axis_k] += 1.0f) { - + hair_volume_eval_grid_vertex(vert_k, loc_k, radius, dist_scale, x2, v2, x3, v3); - + #if 0 { float wloc[3], x2w[3], x3w[3]; grid_to_world(grid, wloc, loc_k); grid_to_world(grid, x2w, x2); grid_to_world(grid, x3w, x3); - + if (vert_k->samples > 0) BKE_sim_debug_data_add_circle(wloc, 0.01f, 1.0, 1.0, 0.3, "grid", 2525, debug_i, j, k); - + if (grid->debug_value) { BKE_sim_debug_data_add_dot(wloc, 1, 0, 0, "grid", 93, debug_i, j, k); BKE_sim_debug_data_add_dot(x2w, 0.1, 0.1, 0.7, "grid", 649, debug_i, j, k); @@ -435,55 +435,55 @@ void BPH_hair_volume_add_segment(HairGrid *grid, const float dir1[3], const float dir2[3], const float dir3[3]) { const int res[3] = { grid->res[0], grid->res[1], grid->res[2] }; - + /* find the primary direction from the major axis of the direction vector */ const int axis0 = major_axis_v3(dir2); const int axis1 = (axis0 + 1) % 3; const int axis2 = (axis0 + 2) % 3; - + /* vertex buffer offset factors along cardinal axes */ const int strides[3] = { 1, res[0], res[0] * res[1] }; const int stride0 = strides[axis0]; const int stride1 = strides[axis1]; const int stride2 = strides[axis2]; - + /* increment of secondary directions per step in the primary direction * note: we always go in the positive direction along axis0, so the sign can be inverted */ const float inc1 = dir2[axis1] / dir2[axis0]; const float inc2 = dir2[axis2] / dir2[axis0]; - + /* start/end points, so increment along axis0 is always positive */ const float *start = x2[axis0] < x3[axis0] ? x2 : x3; const float *end = x2[axis0] < x3[axis0] ? x3 : x2; const float start0 = start[axis0], start1 = start[axis1], start2 = start[axis2]; const float end0 = end[axis0]; - + /* range along primary direction */ const int imin = max_ii(floor_int(start[axis0]) - 1, 0); const int imax = min_ii(floor_int(end[axis0]) + 2, res[axis0]-1); - + float h = 0.0f; HairGridVert *vert0; float loc0[3]; int j0, k0, j0_prev, k0_prev; int i; - + for (i = imin; i <= imax; ++i) { float shift1, shift2; /* fraction of a full cell shift [0.0, 1.0) */ int jmin, jmax, kmin, kmax; - + h = CLAMPIS((float)i, start0, end0); - + shift1 = start1 + (h - start0) * inc1; shift2 = start2 + (h - start0) * inc2; - + j0_prev = j0; j0 = floor_int(shift1); - + k0_prev = k0; k0 = floor_int(shift2); - + if (i > imin) { jmin = min_ii(j0, j0_prev); jmax = max_ii(j0, j0_prev); @@ -494,12 +494,12 @@ void BPH_hair_volume_add_segment(HairGrid *grid, jmin = jmax = j0; kmin = kmax = k0; } - + vert0 = grid->verts + i * stride0; loc0[axis0] = (float)i; loc0[axis1] = 0.0f; loc0[axis2] = 0.0f; - + hair_volume_add_segment_2D(grid, x1, v1, x2, v2, x3, v3, x4, v4, dir1, dir2, dir3, res[axis1], res[axis2], jmin-1, jmax+2, kmin-1, kmax+2, vert0, stride1, stride2, loc0, axis1, axis2, @@ -511,11 +511,11 @@ BLI_INLINE void hair_volume_eval_grid_vertex_sample(HairGridVert *vert, const fl const float x[3], const float v[3]) { float dist, weight; - + dist = len_v3v3(x, loc); - + weight = (radius - dist) * dist_scale; - + if (weight > 0.0f) { madd_v3_v3fl(vert->velocity, v, weight); vert->density += weight; @@ -533,34 +533,34 @@ void BPH_hair_volume_add_segment(HairGrid *grid, { const float radius = 1.5f; const float dist_scale = grid->inv_cellsize; - + const int res[3] = { grid->res[0], grid->res[1], grid->res[2] }; const int stride[3] = { 1, res[0], res[0] * res[1] }; const int num_samples = 10; - + int s; - + for (s = 0; s < num_samples; ++s) { float x[3], v[3]; int i, j, k; - + float f = (float)s / (float)(num_samples-1); interp_v3_v3v3(x, x2, x3, f); interp_v3_v3v3(v, v2, v3, f); - + int imin = max_ii(floor_int(x[0]) - 2, 0); int imax = min_ii(floor_int(x[0]) + 2, res[0]-1); int jmin = max_ii(floor_int(x[1]) - 2, 0); int jmax = min_ii(floor_int(x[1]) + 2, res[1]-1); int kmin = max_ii(floor_int(x[2]) - 2, 0); int kmax = min_ii(floor_int(x[2]) + 2, res[2]-1); - + for (k = kmin; k <= kmax; ++k) { for (j = jmin; j <= jmax; ++j) { for (i = imin; i <= imax; ++i) { float loc[3] = { (float)i, (float)j, (float)k }; HairGridVert *vert = grid->verts + i * stride[0] + j * stride[1] + k * stride[2]; - + hair_volume_eval_grid_vertex_sample(vert, loc, radius, dist_scale, x, v); } } @@ -598,25 +598,25 @@ bool BPH_hair_volume_solve_divergence(HairGrid *grid, float /*dt*/, float target { const float flowfac = grid->cellsize; const float inv_flowfac = 1.0f / grid->cellsize; - + /*const int num_cells = hair_grid_size(grid->res);*/ const int res[3] = { grid->res[0], grid->res[1], grid->res[2] }; const int resA[3] = { grid->res[0] + 2, grid->res[1] + 2, grid->res[2] + 2 }; - + const int stride0 = 1; const int stride1 = grid->res[0]; const int stride2 = grid->res[1] * grid->res[0]; const int strideA0 = 1; const int strideA1 = grid->res[0] + 2; const int strideA2 = (grid->res[1] + 2) * (grid->res[0] + 2); - + const int num_cells = res[0] * res[1] * res[2]; const int num_cellsA = (res[0] + 2) * (res[1] + 2) * (res[2] + 2); - + HairGridVert *vert_start = grid->verts - (stride0 + stride1 + stride2); HairGridVert *vert; int i, j, k; - + #define MARGIN_i0 (i < 1) #define MARGIN_j0 (j < 1) #define MARGIN_k0 (k < 1) @@ -630,9 +630,9 @@ bool BPH_hair_volume_solve_divergence(HairGrid *grid, float /*dt*/, float target #define NEIGHBOR_MARGIN_i1 (i >= resA[0]-2) #define NEIGHBOR_MARGIN_j1 (j >= resA[1]-2) #define NEIGHBOR_MARGIN_k1 (k >= resA[2]-2) - + BLI_assert(num_cells >= 1); - + /* Calculate divergence */ lVector B(num_cellsA); for (k = 0; k < resA[2]; ++k) { @@ -640,14 +640,14 @@ bool BPH_hair_volume_solve_divergence(HairGrid *grid, float /*dt*/, float target for (i = 0; i < resA[0]; ++i) { int u = i * strideA0 + j * strideA1 + k * strideA2; bool is_margin = MARGIN_i0 || MARGIN_i1 || MARGIN_j0 || MARGIN_j1 || MARGIN_k0 || MARGIN_k1; - + if (is_margin) { B[u] = 0.0f; continue; } - + vert = vert_start + i * stride0 + j * stride1 + k * stride2; - + const float *v0 = vert->velocity; float dx = 0.0f, dy = 0.0f, dz = 0.0f; if (!NEIGHBOR_MARGIN_i0) @@ -662,19 +662,19 @@ bool BPH_hair_volume_solve_divergence(HairGrid *grid, float /*dt*/, float target dz += v0[2] - (vert - stride2)->velocity[2]; if (!NEIGHBOR_MARGIN_k1) dz += (vert + stride2)->velocity[2] - v0[2]; - + float divergence = -0.5f * flowfac * (dx + dy + dz); - + /* adjustment term for target density */ float target = hair_volume_density_divergence(vert->density, target_density, target_strength); - + /* B vector contains the finite difference approximation of the velocity divergence. * Note: according to the discretized Navier-Stokes equation the rhs vector * and resulting pressure gradient should be multiplied by the (inverse) density; * however, this is already included in the weighting of hair velocities on the grid! */ B[u] = divergence - target; - + #if 0 { float wloc[3], loc[3]; @@ -683,12 +683,12 @@ bool BPH_hair_volume_solve_divergence(HairGrid *grid, float /*dt*/, float target float coln[3] = {1.0, 0.0, 1.0}; float col[3]; float fac; - + loc[0] = (float)(i - 1); loc[1] = (float)(j - 1); loc[2] = (float)(k - 1); grid_to_world(grid, wloc, loc); - + if (divergence > 0.0f) { fac = CLAMPIS(divergence * target_strength, 0.0, 1.0); interp_v3_v3v3(col, col0, colp, fac); @@ -704,11 +704,11 @@ bool BPH_hair_volume_solve_divergence(HairGrid *grid, float /*dt*/, float target } } } - + /* Main Poisson equation system: * This is derived from the discretezation of the Poisson equation * div(grad(p)) = div(v) - * + * * The finite difference approximation yields the linear equation system described here: * https://en.wikipedia.org/wiki/Discrete_Poisson_equation */ @@ -718,13 +718,13 @@ bool BPH_hair_volume_solve_divergence(HairGrid *grid, float /*dt*/, float target * and up to 6 factors -1 on other places. */ A.reserve(Eigen::VectorXi::Constant(num_cellsA, 7)); - + for (k = 0; k < resA[2]; ++k) { for (j = 0; j < resA[1]; ++j) { for (i = 0; i < resA[0]; ++i) { int u = i * strideA0 + j * strideA1 + k * strideA2; bool is_margin = MARGIN_i0 || MARGIN_i1 || MARGIN_j0 || MARGIN_j1 || MARGIN_k0 || MARGIN_k1; - + vert = vert_start + i * stride0 + j * stride1 + k * stride2; if (!is_margin && vert->density > density_threshold) { int neighbors_lo = 0; @@ -733,7 +733,7 @@ bool BPH_hair_volume_solve_divergence(HairGrid *grid, float /*dt*/, float target int neighbor_lo_index[3]; int neighbor_hi_index[3]; int n; - + /* check for upper bounds in advance * to get the correct number of neighbors, * needed for the diagonal element @@ -750,10 +750,10 @@ bool BPH_hair_volume_solve_divergence(HairGrid *grid, float /*dt*/, float target neighbor_hi_index[neighbors_hi++] = u + strideA1; if (!NEIGHBOR_MARGIN_k1 && (vert + stride2)->density > density_threshold) neighbor_hi_index[neighbors_hi++] = u + strideA2; - + /*int liquid_neighbors = neighbors_lo + neighbors_hi;*/ non_solid_neighbors = 6; - + for (n = 0; n < neighbors_lo; ++n) A.insert(neighbor_lo_index[n], u) = -1.0f; A.insert(u, u) = (float)non_solid_neighbors; @@ -766,15 +766,15 @@ bool BPH_hair_volume_solve_divergence(HairGrid *grid, float /*dt*/, float target } } } - + ConjugateGradient cg; cg.setMaxIterations(100); cg.setTolerance(0.01f); - + cg.compute(A); - + lVector p = cg.solve(B); - + if (cg.info() == Eigen::Success) { /* Calculate velocity = grad(p) */ for (k = 0; k < resA[2]; ++k) { @@ -784,7 +784,7 @@ bool BPH_hair_volume_solve_divergence(HairGrid *grid, float /*dt*/, float target bool is_margin = MARGIN_i0 || MARGIN_i1 || MARGIN_j0 || MARGIN_j1 || MARGIN_k0 || MARGIN_k1; if (is_margin) continue; - + vert = vert_start + i * stride0 + j * stride1 + k * stride2; if (vert->density > density_threshold) { float p_left = p[u - strideA0]; @@ -793,14 +793,14 @@ bool BPH_hair_volume_solve_divergence(HairGrid *grid, float /*dt*/, float target float p_up = p[u + strideA1]; float p_bottom = p[u - strideA2]; float p_top = p[u + strideA2]; - + /* finite difference estimate of pressure gradient */ float dvel[3]; dvel[0] = p_right - p_left; dvel[1] = p_up - p_down; dvel[2] = p_top - p_bottom; mul_v3_fl(dvel, -0.5f * inv_flowfac); - + /* pressure gradient describes velocity delta */ add_v3_v3v3(vert->velocity_smooth, vert->velocity, dvel); } @@ -810,14 +810,14 @@ bool BPH_hair_volume_solve_divergence(HairGrid *grid, float /*dt*/, float target } } } - + #if 0 { int axis = 0; float offset = 0.0f; - + int slice = (offset - grid->gmin[axis]) / grid->cellsize; - + for (k = 0; k < resA[2]; ++k) { for (j = 0; j < resA[1]; ++j) { for (i = 0; i < resA[0]; ++i) { @@ -825,21 +825,21 @@ bool BPH_hair_volume_solve_divergence(HairGrid *grid, float /*dt*/, float target bool is_margin = MARGIN_i0 || MARGIN_i1 || MARGIN_j0 || MARGIN_j1 || MARGIN_k0 || MARGIN_k1; if (i != slice) continue; - + vert = vert_start + i * stride0 + j * stride1 + k * stride2; - + float wloc[3], loc[3]; float col0[3] = {0.0, 0.0, 0.0}; float colp[3] = {0.0, 1.0, 1.0}; float coln[3] = {1.0, 0.0, 1.0}; float col[3]; float fac; - + loc[0] = (float)(i - 1); loc[1] = (float)(j - 1); loc[2] = (float)(k - 1); grid_to_world(grid, wloc, loc); - + float pressure = p[u]; if (pressure > 0.0f) { fac = CLAMPIS(pressure * grid->debug1, 0.0, 1.0); @@ -851,19 +851,19 @@ bool BPH_hair_volume_solve_divergence(HairGrid *grid, float /*dt*/, float target } if (fac > 0.05f) BKE_sim_debug_data_add_circle(grid->debug_data, wloc, 0.01f, col[0], col[1], col[2], "grid", 5533, i, j, k); - + if (!is_margin) { float dvel[3]; sub_v3_v3v3(dvel, vert->velocity_smooth, vert->velocity); // BKE_sim_debug_data_add_vector(grid->debug_data, wloc, dvel, 1, 1, 1, "grid", 5566, i, j, k); } - + if (!is_margin) { float d = CLAMPIS(vert->density * grid->debug2, 0.0f, 1.0f); float col0[3] = {0.3, 0.3, 0.3}; float colp[3] = {0.0, 0.0, 1.0}; float col[3]; - + interp_v3_v3v3(col, col0, colp, d); // if (d > 0.05f) // BKE_sim_debug_data_add_dot(grid->debug_data, wloc, col[0], col[1], col[2], "grid", 5544, i, j, k); @@ -873,7 +873,7 @@ bool BPH_hair_volume_solve_divergence(HairGrid *grid, float /*dt*/, float target } } #endif - + return true; } else { @@ -881,7 +881,7 @@ bool BPH_hair_volume_solve_divergence(HairGrid *grid, float /*dt*/, float target for (i = 0, vert = grid->verts; i < num_cells; ++i, ++vert) { zero_v3(vert->velocity_smooth); } - + return false; } } @@ -901,20 +901,20 @@ BLI_INLINE void hair_volume_filter_box_convolute(HairVertexGrid *grid, float inv int offset, kernel_offset, kernel_dq, kernel_dr; HairGridVert *verts; float *vel_smooth; - + offset = i + (j + k*res)*res; verts = grid->verts; vel_smooth = verts[offset].velocity_smooth; - + kernel_offset = minp + (minq + minr*res)*res; kernel_dq = res; kernel_dr = res * res; for (r = minr; r <= maxr; ++r) { for (q = minq; q <= maxq; ++q) { for (p = minp; p <= maxp; ++p) { - + madd_v3_v3fl(vel_smooth, verts[kernel_offset].velocity, invD); - + kernel_offset += 1; } kernel_offset += kernel_dq; @@ -930,18 +930,18 @@ void BPH_hair_volume_vertex_grid_filter_box(HairVertexGrid *grid, int kernel_siz int tot; float invD; int i, j, k; - + if (kernel_size <= 0) return; - + tot = kernel_size * 2 + 1; invD = 1.0f / (float)(tot*tot*tot); - + /* clear values for convolution */ for (i = 0; i < size; ++i) { zero_v3(grid->verts[i].velocity_smooth); } - + for (i = 0; i < grid->res; ++i) { for (j = 0; j < grid->res; ++j) { for (k = 0; k < grid->res; ++k) { @@ -949,7 +949,7 @@ void BPH_hair_volume_vertex_grid_filter_box(HairVertexGrid *grid, int kernel_siz } } } - + /* apply as new velocity */ for (i = 0; i < size; ++i) { copy_v3_v3(grid->verts[i].velocity, grid->verts[i].velocity_smooth); @@ -966,21 +966,21 @@ HairGrid *BPH_hair_volume_create_vertex_grid(float cellsize, const float gmin[3] int size; HairGrid *grid; int i; - + /* sanity check */ if (cellsize <= 0.0f) cellsize = 1.0f; scale = 1.0f / cellsize; - + sub_v3_v3v3(extent, gmax, gmin); for (i = 0; i < 3; ++i) { resmin[i] = floor_int(gmin[i] * scale); resmax[i] = floor_int(gmax[i] * scale) + 1; - + /* add margin of 1 cell */ resmin[i] -= 1; resmax[i] += 1; - + res[i] = resmax[i] - resmin[i] + 1; /* sanity check: avoid null-sized grid */ if (res[i] < 4) { @@ -992,12 +992,12 @@ HairGrid *BPH_hair_volume_create_vertex_grid(float cellsize, const float gmin[3] res[i] = MAX_HAIR_GRID_RES; resmax[i] = resmin[i] + MAX_HAIR_GRID_RES; } - + gmin_margin[i] = (float)resmin[i] * cellsize; gmax_margin[i] = (float)resmax[i] * cellsize; } size = hair_grid_size(res); - + grid = (HairGrid *)MEM_callocN(sizeof(HairGrid), "hair grid"); grid->res[0] = res[0]; grid->res[1] = res[1]; @@ -1062,23 +1062,23 @@ static HairGridVert *hair_volume_create_collision_grid(ClothModifierData *clmd, float vel[3]; float weights[8]; int di, dj, dk; - + for (v=0; v < col->collmd->numverts; v++, loc0++, loc1++) { int offset; - + if (!hair_grid_point_valid(loc1->co, gmin, gmax)) continue; - + offset = hair_grid_weights(res, gmin, scale, lX[v], weights); - + sub_v3_v3v3(vel, loc1->co, loc0->co); - + for (di = 0; di < 2; ++di) { for (dj = 0; dj < 2; ++dj) { for (dk = 0; dk < 2; ++dk) { int voffset = offset + di + (dj + dk*res)*res; int iw = di + dj*2 + dk*4; - + collgrid[voffset].density += weights[iw]; madd_v3_v3fl(collgrid[voffset].velocity, vel, weights[iw]); } @@ -1095,7 +1095,7 @@ static HairGridVert *hair_volume_create_collision_grid(ClothModifierData *clmd, if (density > 0.0f) mul_v3_fl(collgrid[i].velocity, 1.0f/density); } - + return collgrid; } #endif diff --git a/source/blender/physics/intern/implicit.h b/source/blender/physics/intern/implicit.h index d6bf5c6b7bf..2eadd3171b0 100644 --- a/source/blender/physics/intern/implicit.h +++ b/source/blender/physics/intern/implicit.h @@ -62,7 +62,7 @@ struct Implicit_Data; typedef struct ImplicitSolverResult { int status; - + int iterations; float error; } ImplicitSolverResult; diff --git a/source/blender/physics/intern/implicit_blender.c b/source/blender/physics/intern/implicit_blender.c index 49798081cff..5fd9c6b50de 100644 --- a/source/blender/physics/intern/implicit_blender.c +++ b/source/blender/physics/intern/implicit_blender.c @@ -71,9 +71,9 @@ static float ZERO[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}; /* #define C99 #ifdef C99 -#defineDO_INLINE inline -#else -#defineDO_INLINE static +#defineDO_INLINE inline +#else +#defineDO_INLINE static #endif */ struct Cloth; @@ -90,7 +90,7 @@ typedef struct fmatrix3x3 { /* int pinned; // is this vertex allowed to move? */ float n1, n2, n3; /* three normal vectors for collision constrains */ unsigned int vcount; /* vertex count */ - unsigned int scount; /* spring count */ + unsigned int scount; /* spring count */ } fmatrix3x3; /////////////////////////// @@ -115,9 +115,9 @@ DO_INLINE void mul_fvectorT_fvector(float to[3][3], float vectorA[3], float vect /* simple v^T * v product with scalar ("outer product") */ /* STATUS: HAS TO BE verified (*should* work) */ DO_INLINE void mul_fvectorT_fvectorS(float to[3][3], float vectorA[3], float vectorB[3], float aS) -{ +{ mul_fvectorT_fvector(to, vectorA, vectorB); - + mul_fvector_S(to[0], to[0], aS); mul_fvector_S(to[1], to[1], aS); mul_fvector_S(to[2], to[2], aS); @@ -288,7 +288,7 @@ static void print_lvector(lfVector *v, int numverts) for (i = 0; i < numverts; ++i) { if (i > 0) printf("\n"); - + printf("%f,\n", v[i][0]); printf("%f,\n", v[i][1]); printf("%f,\n", v[i][2]); @@ -303,11 +303,11 @@ static void print_bfmatrix(fmatrix3x3 *m) int size = m[0].vcount * 3; float *t = MEM_callocN(sizeof(float) * size*size, "bfmatrix"); int q, i, j; - + for (q = 0; q < tot; ++q) { int k = 3 * m[q].r; int l = 3 * m[q].c; - + for (j = 0; j < 3; ++j) { for (i = 0; i < 3; ++i) { // if (t[k + i + (l + j) * size] != 0.0f) { @@ -323,20 +323,20 @@ static void print_bfmatrix(fmatrix3x3 *m) } } } - + for (j = 0; j < size; ++j) { if (j > 0 && j % 3 == 0) printf("\n"); - + for (i = 0; i < size; ++i) { if (i > 0 && i % 3 == 0) printf(" "); - + implicit_print_matrix_elem(t[i + j * size]); } printf("\n"); } - + MEM_freeN(t); } #endif @@ -354,7 +354,7 @@ DO_INLINE void cp_fmatrix(float to[3][3], float from[3][3]) DO_INLINE void initdiag_fmatrixS(float to[3][3], float aS) { cp_fmatrix(to, ZERO); - + to[0][0] = aS; to[1][1] = aS; to[2][2] = aS; @@ -532,15 +532,15 @@ DO_INLINE fmatrix3x3 *create_bfmatrix(unsigned int verts, unsigned int springs) // TODO: check if memory allocation was successful */ fmatrix3x3 *temp = (fmatrix3x3 *)MEM_callocN(sizeof(fmatrix3x3) * (verts + springs), "cloth_implicit_alloc_matrix"); int i; - + temp[0].vcount = verts; temp[0].scount = springs; - + /* vertex part of the matrix is diagonal blocks */ for (i = 0; i < verts; ++i) { init_fmatrix(temp + i, i, i); } - + return temp; } /* delete big matrix */ @@ -565,7 +565,7 @@ DO_INLINE void init_bfmatrix(fmatrix3x3 *matrix, float m3[3][3]) unsigned int i; for (i = 0; i < matrix[0].vcount+matrix[0].scount; i++) { - cp_fmatrix(matrix[i].m, m3); + cp_fmatrix(matrix[i].m, m3); } } @@ -577,10 +577,10 @@ DO_INLINE void initdiag_bfmatrix(fmatrix3x3 *matrix, float m3[3][3]) float tmatrix[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}; for (i = 0; i < matrix[0].vcount; i++) { - cp_fmatrix(matrix[i].m, m3); + cp_fmatrix(matrix[i].m, m3); } for (j = matrix[0].vcount; j < matrix[0].vcount+matrix[0].scount; j++) { - cp_fmatrix(matrix[j].m, tmatrix); + cp_fmatrix(matrix[j].m, tmatrix); } } @@ -591,7 +591,7 @@ DO_INLINE void mul_bfmatrix_lfvector( float (*to)[3], fmatrix3x3 *from, lfVector unsigned int i = 0; unsigned int vcount = from[0].vcount; lfVector *temp = create_lfvector(vcount); - + zero_lfvector(to, vcount); #pragma omp parallel sections private(i) if (vcount > CLOTH_OPENMP_LIMIT) @@ -610,10 +610,10 @@ DO_INLINE void mul_bfmatrix_lfvector( float (*to)[3], fmatrix3x3 *from, lfVector } } add_lfvector_lfvector(to, to, temp, from[0].vcount); - + del_lfvector(temp); - - + + } /* SPARSE SYMMETRIC sub big matrix with big matrix*/ @@ -642,15 +642,15 @@ typedef struct Implicit_Data { lfVector *F; /* forces */ fmatrix3x3 *dFdV, *dFdX; /* force jacobians */ int num_blocks; /* number of off-diagonal blocks (springs) */ - + /* motion state data */ lfVector *X, *Xnew; /* positions */ lfVector *V, *Vnew; /* velocities */ - + /* internal solver data */ lfVector *B; /* B for A*dV = B */ fmatrix3x3 *A; /* A for A*dV = B */ - + lfVector *dV; /* velocity change (solution of A*dV = B) */ lfVector *z; /* target velocity in constrained directions */ fmatrix3x3 *S; /* filtering matrix for constraints */ @@ -660,7 +660,7 @@ typedef struct Implicit_Data { Implicit_Data *BPH_mass_spring_solver_create(int numverts, int numsprings) { Implicit_Data *id = (Implicit_Data *)MEM_callocN(sizeof(Implicit_Data), "implicit vecmat"); - + /* process diagonal elements */ id->tfm = create_bfmatrix(numverts, 0); id->A = create_bfmatrix(numverts, numsprings); @@ -696,7 +696,7 @@ void BPH_mass_spring_solver_free(Implicit_Data *id) del_bfmatrix(id->Pinv); del_bfmatrix(id->bigI); del_bfmatrix(id->M); - + del_lfvector(id->X); del_lfvector(id->Xnew); del_lfvector(id->V); @@ -705,7 +705,7 @@ void BPH_mass_spring_solver_free(Implicit_Data *id) del_lfvector(id->B); del_lfvector(id->dV); del_lfvector(id->z); - + MEM_freeN(id); } @@ -752,7 +752,7 @@ static int cg_filtered(lfVector *ldV, fmatrix3x3 *lA, lfVector *lB, lfVector *z // Solves for unknown X in equation AX=B unsigned int conjgrad_loopcount=0, conjgrad_looplimit=100; float conjgrad_epsilon=0.0001f /* , conjgrad_lasterror=0 */ /* UNUSED */; - lfVector *q, *d, *tmp, *r; + lfVector *q, *d, *tmp, *r; float s, starget, a, s_prev; unsigned int numverts = lA[0].vcount; q = create_lfvector(numverts); @@ -818,7 +818,7 @@ static int cg_filtered(lfVector *ldV, fmatrix3x3 *lA, lfVector *lB, lfVector *z, // Solves for unknown X in equation AX=B unsigned int conjgrad_loopcount=0, conjgrad_looplimit=100; float conjgrad_epsilon=0.01f; - + unsigned int numverts = lA[0].vcount; lfVector *fB = create_lfvector(numverts); lfVector *AdV = create_lfvector(numverts); @@ -827,27 +827,27 @@ static int cg_filtered(lfVector *ldV, fmatrix3x3 *lA, lfVector *lB, lfVector *z, lfVector *q = create_lfvector(numverts); lfVector *s = create_lfvector(numverts); float bnorm2, delta_new, delta_old, delta_target, alpha; - + cp_lfvector(ldV, z, numverts); - + /* d0 = filter(B)^T * P * filter(B) */ cp_lfvector(fB, lB, numverts); filter(fB, S); bnorm2 = dot_lfvector(fB, fB, numverts); delta_target = conjgrad_epsilon*conjgrad_epsilon * bnorm2; - + /* r = filter(B - A * dV) */ mul_bfmatrix_lfvector(AdV, lA, ldV); sub_lfvector_lfvector(r, lB, AdV, numverts); filter(r, S); - + /* c = filter(P^-1 * r) */ cp_lfvector(c, r, numverts); filter(c, S); - + /* delta = r^T * c */ delta_new = dot_lfvector(r, c, numverts); - + #ifdef IMPLICIT_PRINT_SOLVER_INPUT_OUTPUT printf("==== A ====\n"); print_bfmatrix(lA); @@ -858,25 +858,25 @@ static int cg_filtered(lfVector *ldV, fmatrix3x3 *lA, lfVector *lB, lfVector *z, printf("==== S ====\n"); print_bfmatrix(S); #endif - + while (delta_new > delta_target && conjgrad_loopcount < conjgrad_looplimit) { mul_bfmatrix_lfvector(q, lA, c); filter(q, S); - + alpha = delta_new / dot_lfvector(c, q, numverts); - + add_lfvector_lfvectorS(ldV, ldV, c, alpha, numverts); - + add_lfvector_lfvectorS(r, r, q, -alpha, numverts); - + /* s = P^-1 * r */ cp_lfvector(s, r, numverts); delta_old = delta_new; delta_new = dot_lfvector(r, s, numverts); - + add_lfvector_lfvectorS(c, s, c, delta_new / delta_old, numverts); filter(c, S); - + conjgrad_loopcount++; } @@ -885,7 +885,7 @@ static int cg_filtered(lfVector *ldV, fmatrix3x3 *lA, lfVector *lB, lfVector *z, print_lvector(ldV, numverts); printf("========\n"); #endif - + del_lfvector(fB); del_lfvector(AdV); del_lfvector(r); @@ -906,14 +906,14 @@ static int cg_filtered(lfVector *ldV, fmatrix3x3 *lA, lfVector *lB, lfVector *z, DO_INLINE void BuildPPinv(fmatrix3x3 *lA, fmatrix3x3 *P, fmatrix3x3 *Pinv) { unsigned int i = 0; - + // Take only the diagonal blocks of A // #pragma omp parallel for private(i) if (lA[0].vcount > CLOTH_OPENMP_LIMIT) for (i = 0; i<lA[0].vcount; i++) { // block diagonalizer cp_fmatrix(P[i].m, lA[i].m); inverse_fmatrix(Pinv[i].m, P[i].m); - + } } /* @@ -927,65 +927,65 @@ static int cg_filtered_pre(lfVector *dv, fmatrix3x3 *lA, lfVector *lB, lfVector lfVector *p = create_lfvector(numverts); lfVector *s = create_lfvector(numverts); lfVector *h = create_lfvector(numverts); - + BuildPPinv(lA, P, Pinv); - + filter(dv, S); add_lfvector_lfvector(dv, dv, z, numverts); - + mul_bfmatrix_lfvector(r, lA, dv); sub_lfvector_lfvector(r, lB, r, numverts); filter(r, S); - + mul_prevfmatrix_lfvector(p, Pinv, r); filter(p, S); - + deltaNew = dot_lfvector(r, p, numverts); - + delta0 = deltaNew * sqrt(conjgrad_epsilon); - + #ifdef DEBUG_TIME double start = PIL_check_seconds_timer(); #endif - + while ((deltaNew > delta0) && (iterations < conjgrad_looplimit)) { iterations++; - + mul_bfmatrix_lfvector(s, lA, p); filter(s, S); - + alpha = deltaNew / dot_lfvector(p, s, numverts); - + add_lfvector_lfvectorS(dv, dv, p, alpha, numverts); - + add_lfvector_lfvectorS(r, r, s, -alpha, numverts); - + mul_prevfmatrix_lfvector(h, Pinv, r); filter(h, S); - + deltaOld = deltaNew; - + deltaNew = dot_lfvector(r, h, numverts); - + add_lfvector_lfvectorS(p, h, p, deltaNew / deltaOld, numverts); - + filter(p, S); - + } #ifdef DEBUG_TIME double end = PIL_check_seconds_timer(); printf("cg_filtered_pre time: %f\n", (float)(end - start)); #endif - + del_lfvector(h); del_lfvector(s); del_lfvector(p); del_lfvector(r); - + printf("iterations: %d\n", iterations); - + return iterations<conjgrad_looplimit; } */ @@ -1000,83 +1000,83 @@ static int cg_filtered_pre(lfVector *dv, fmatrix3x3 *lA, lfVector *lB, lfVector lfVector *h = create_lfvector(numverts); lfVector *bhat = create_lfvector(numverts); lfVector *btemp = create_lfvector(numverts); - + BuildPPinv(lA, P, Pinv); - + initdiag_bfmatrix(bigI, I); sub_bfmatrix_Smatrix(bigI, bigI, S); - + // x = Sx_0+(I-S)z filter(dv, S); add_lfvector_lfvector(dv, dv, z, numverts); - + // b_hat = S(b-A(I-S)z) mul_bfmatrix_lfvector(r, lA, z); mul_bfmatrix_lfvector(bhat, bigI, r); sub_lfvector_lfvector(bhat, lB, bhat, numverts); - + // r = S(b-Ax) mul_bfmatrix_lfvector(r, lA, dv); sub_lfvector_lfvector(r, lB, r, numverts); filter(r, S); - + // p = SP^-1r mul_prevfmatrix_lfvector(p, Pinv, r); filter(p, S); - + // delta0 = bhat^TP^-1bhat mul_prevfmatrix_lfvector(btemp, Pinv, bhat); delta0 = dot_lfvector(bhat, btemp, numverts); - + // deltaNew = r^TP deltaNew = dot_lfvector(r, p, numverts); - + /* filter(dv, S); add_lfvector_lfvector(dv, dv, z, numverts); - + mul_bfmatrix_lfvector(r, lA, dv); sub_lfvector_lfvector(r, lB, r, numverts); filter(r, S); - + mul_prevfmatrix_lfvector(p, Pinv, r); filter(p, S); - + deltaNew = dot_lfvector(r, p, numverts); - + delta0 = deltaNew * sqrt(conjgrad_epsilon); */ #ifdef DEBUG_TIME double start = PIL_check_seconds_timer(); #endif - + tol = (0.01*0.2); - + while ((deltaNew > delta0*tol*tol) && (iterations < conjgrad_looplimit)) { iterations++; - + mul_bfmatrix_lfvector(s, lA, p); filter(s, S); - + alpha = deltaNew / dot_lfvector(p, s, numverts); - + add_lfvector_lfvectorS(dv, dv, p, alpha, numverts); - + add_lfvector_lfvectorS(r, r, s, -alpha, numverts); - + mul_prevfmatrix_lfvector(h, Pinv, r); filter(h, S); - + deltaOld = deltaNew; - + deltaNew = dot_lfvector(r, h, numverts); - + add_lfvector_lfvectorS(p, h, p, deltaNew / deltaOld, numverts); - + filter(p, S); - + } #ifdef DEBUG_TIME @@ -1090,9 +1090,9 @@ static int cg_filtered_pre(lfVector *dv, fmatrix3x3 *lA, lfVector *lB, lfVector del_lfvector(s); del_lfvector(p); del_lfvector(r); - + // printf("iterations: %d\n", iterations); - + return iterations<conjgrad_looplimit; } #endif @@ -1128,17 +1128,17 @@ bool BPH_mass_spring_solve_velocities(Implicit_Data *data, float dt, ImplicitSol add_lfvector_lfvector(data->Vnew, data->V, data->dV, numverts); del_lfvector(dFdXmV); - + return result->status == BPH_SOLVER_SUCCESS; } bool BPH_mass_spring_solve_positions(Implicit_Data *data, float dt) { int numverts = data->M[0].vcount; - + // advance positions add_lfvector_lfvectorS(data->Xnew, data->X, data->Vnew, dt, numverts); - + return true; } @@ -1219,7 +1219,7 @@ static int BPH_mass_spring_add_block(Implicit_Data *data, int v1, int v2) int s = data->M[0].vcount + data->num_blocks; /* index from array start */ BLI_assert(s < data->M[0].vcount + data->M[0].scount); ++data->num_blocks; - + /* tfm and S don't have spring entries (diagonal blocks only) */ init_fmatrix(data->bigI + s, v1, v2); init_fmatrix(data->M + s, v1, v2); @@ -1228,7 +1228,7 @@ static int BPH_mass_spring_add_block(Implicit_Data *data, int v1, int v2) init_fmatrix(data->A + s, v1, v2); init_fmatrix(data->P + s, v1, v2); init_fmatrix(data->Pinv + s, v1, v2); - + return s; } @@ -1244,26 +1244,26 @@ void BPH_mass_spring_clear_constraints(Implicit_Data *data) void BPH_mass_spring_add_constraint_ndof0(Implicit_Data *data, int index, const float dV[3]) { zero_m3(data->S[index].m); - + world_to_root_v3(data, index, data->z[index], dV); } void BPH_mass_spring_add_constraint_ndof1(Implicit_Data *data, int index, const float c1[3], const float c2[3], const float dV[3]) { float m[3][3], p[3], q[3], u[3], cmat[3][3]; - + world_to_root_v3(data, index, p, c1); mul_fvectorT_fvector(cmat, p, p); sub_m3_m3m3(m, I, cmat); - + world_to_root_v3(data, index, q, c2); mul_fvectorT_fvector(cmat, q, q); sub_m3_m3m3(m, m, cmat); - + /* XXX not sure but multiplication should work here */ copy_m3_m3(data->S[index].m, m); // mul_m3_m3m3(data->S[index].m, data->S[index].m, m); - + world_to_root_v3(data, index, u, dV); add_v3_v3(data->z[index], u); } @@ -1271,14 +1271,14 @@ void BPH_mass_spring_add_constraint_ndof1(Implicit_Data *data, int index, const void BPH_mass_spring_add_constraint_ndof2(Implicit_Data *data, int index, const float c1[3], const float dV[3]) { float m[3][3], p[3], u[3], cmat[3][3]; - + world_to_root_v3(data, index, p, c1); mul_fvectorT_fvector(cmat, p, p); sub_m3_m3m3(m, I, cmat); - + copy_m3_m3(data->S[index].m, m); // mul_m3_m3m3(data->S[index].m, data->S[index].m, m); - + world_to_root_v3(data, index, u, dV); add_v3_v3(data->z[index], u); } @@ -1289,7 +1289,7 @@ void BPH_mass_spring_clear_forces(Implicit_Data *data) zero_lfvector(data->F, numverts); init_bfmatrix(data->dFdX, ZERO); init_bfmatrix(data->dFdV, ZERO); - + data->num_blocks = 0; } @@ -1300,37 +1300,37 @@ void BPH_mass_spring_force_reference_frame(Implicit_Data *data, int index, const float f[3], dfdx[3][3], dfdv[3][3]; float euler[3], coriolis[3], centrifugal[3], rotvel[3]; float deuler[3][3], dcoriolis[3][3], dcentrifugal[3][3], drotvel[3][3]; - + world_to_root_v3(data, index, acc, acceleration); world_to_root_v3(data, index, w, omega); world_to_root_v3(data, index, dwdt, domega_dt); - + cross_v3_v3v3(euler, dwdt, data->X[index]); cross_v3_v3v3(coriolis, w, data->V[index]); mul_v3_fl(coriolis, 2.0f); cross_v3_v3v3(rotvel, w, data->X[index]); cross_v3_v3v3(centrifugal, w, rotvel); - + sub_v3_v3v3(f, acc, euler); sub_v3_v3(f, coriolis); sub_v3_v3(f, centrifugal); - + mul_v3_fl(f, mass); /* F = m * a */ - + cross_v3_identity(deuler, dwdt); cross_v3_identity(dcoriolis, w); mul_m3_fl(dcoriolis, 2.0f); cross_v3_identity(drotvel, w); cross_m3_v3m3(dcentrifugal, w, drotvel); - + add_m3_m3m3(dfdx, deuler, dcentrifugal); negate_m3(dfdx); mul_m3_fl(dfdx, mass); - + copy_m3_m3(dfdv, dcoriolis); negate_m3(dfdv); mul_m3_fl(dfdv, mass); - + add_v3_v3(data->F[index], f); add_m3_m3m3(data->dFdX[index].m, data->dFdX[index].m, dfdx); add_m3_m3m3(data->dFdV[index].m, data->dFdV[index].m, dfdv); @@ -1349,7 +1349,7 @@ void BPH_mass_spring_force_gravity(Implicit_Data *data, int index, float mass, c float f[3]; world_to_root_v3(data, index, f, g); mul_v3_fl(f, mass); - + add_v3_v3(data->F[index], f); } @@ -1358,10 +1358,10 @@ void BPH_mass_spring_force_drag(Implicit_Data *data, float drag) int i, numverts = data->M[0].vcount; for (i = 0; i < numverts; i++) { float tmp[3][3]; - + /* NB: uses root space velocity, no need to transform */ madd_v3_v3fl(data->F[i], data->V[i], -drag); - + copy_m3_m3(tmp, I); mul_m3_fl(tmp, -drag); add_m3_m3m3(data->dFdV[i].m, data->dFdV[i].m, tmp); @@ -1374,7 +1374,7 @@ void BPH_mass_spring_force_extern(struct Implicit_Data *data, int i, const float world_to_root_v3(data, i, tf, f); world_to_root_m3(data, i, tdfdx, dfdx); world_to_root_m3(data, i, tdfdv, dfdv); - + add_v3_v3(data->F[i], tf); add_m3_m3m3(data->dFdX[i].m, data->dFdX[i].m, tdfdx); add_m3_m3m3(data->dFdV[i].m, data->dFdV[i].m, tdfdv); @@ -1383,10 +1383,10 @@ void BPH_mass_spring_force_extern(struct Implicit_Data *data, int i, const float static float calc_nor_area_tri(float nor[3], const float v1[3], const float v2[3], const float v3[3]) { float n1[3], n2[3]; - + sub_v3_v3v3(n1, v1, v2); sub_v3_v3v3(n2, v2, v3); - + cross_v3_v3v3(nor, n1, n2); return normalize_v3(nor); } @@ -1397,17 +1397,17 @@ void BPH_mass_spring_force_face_wind(Implicit_Data *data, int v1, int v2, int v3 const float effector_scale = 0.02f; float win[3], nor[3], area; float factor; - + /* calculate face normal and area */ area = calc_nor_area_tri(nor, data->X[v1], data->X[v2], data->X[v3]); factor = effector_scale * area / 3.0f; - + world_to_root_v3(data, v1, win, winvec[v1]); madd_v3_v3fl(data->F[v1], nor, factor * dot_v3v3(win, nor)); - + world_to_root_v3(data, v2, win, winvec[v2]); madd_v3_v3fl(data->F[v2], nor, factor * dot_v3v3(win, nor)); - + world_to_root_v3(data, v3, win, winvec[v3]); madd_v3_v3fl(data->F[v3], nor, factor * dot_v3v3(win, nor)); } @@ -1417,17 +1417,17 @@ static void edge_wind_vertex(const float dir[3], float length, float radius, con const float density = 0.01f; /* XXX arbitrary value, corresponds to effect of air density */ float cos_alpha, sin_alpha, cross_section; float windlen = len_v3(wind); - + if (windlen == 0.0f) { zero_v3(f); return; } - + /* angle of wind direction to edge */ cos_alpha = dot_v3v3(wind, dir) / windlen; sin_alpha = sqrtf(1.0f - cos_alpha * cos_alpha); cross_section = radius * ((float)M_PI * radius * sin_alpha + length * cos_alpha); - + mul_v3_v3fl(f, wind, density * cross_section); } @@ -1435,14 +1435,14 @@ void BPH_mass_spring_force_edge_wind(Implicit_Data *data, int v1, int v2, float { float win[3], dir[3], length; float f[3], dfdx[3][3], dfdv[3][3]; - + sub_v3_v3v3(dir, data->X[v1], data->X[v2]); length = normalize_v3(dir); - + world_to_root_v3(data, v1, win, winvec[v1]); edge_wind_vertex(dir, length, radius1, win, f, dfdx, dfdv); add_v3_v3(data->F[v1], f); - + world_to_root_v3(data, v2, win, winvec[v2]); edge_wind_vertex(dir, length, radius2, win, f, dfdx, dfdv); add_v3_v3(data->F[v2], f); @@ -1451,10 +1451,10 @@ void BPH_mass_spring_force_edge_wind(Implicit_Data *data, int v1, int v2, float void BPH_mass_spring_force_vertex_wind(Implicit_Data *data, int v, float UNUSED(radius), const float (*winvec)[3]) { const float density = 0.01f; /* XXX arbitrary value, corresponds to effect of air density */ - + float wind[3]; float f[3]; - + world_to_root_v3(data, v, wind, winvec[v]); mul_v3_v3fl(f, wind, density); add_v3_v3(data->F[v], f); @@ -1466,8 +1466,8 @@ BLI_INLINE void dfdx_spring(float to[3][3], const float dir[3], float length, fl //return ( (I-outerprod(dir, dir))*Min(1.0f, rest/length) - I) * -k; outerproduct(to, dir, dir); sub_m3_m3m3(to, I, to); - - mul_m3_fl(to, (L/length)); + + mul_m3_fl(to, (L/length)); sub_m3_m3m3(to, to, I); mul_m3_fl(to, k); } @@ -1476,7 +1476,7 @@ BLI_INLINE void dfdx_spring(float to[3][3], const float dir[3], float length, fl #if 0 BLI_INLINE void dfdx_damp(float to[3][3], const float dir[3], float length, const float vel[3], float rest, float damping) { - // inner spring damping vel is the relative velocity of the endpoints. + // inner spring damping vel is the relative velocity of the endpoints. // return (I-outerprod(dir, dir)) * (-damping * -(dot(dir, vel)/Max(length, rest))); mul_fvectorT_fvector(to, dir, dir); sub_fmatrix_fmatrix(to, I, to); @@ -1512,7 +1512,7 @@ BLI_INLINE float fbstar(float length, float L, float kb, float cb) { float tempfb_fl = kb * fb(length, L); float fbstar_fl = cb * (length - L); - + if (tempfb_fl < fbstar_fl) return fbstar_fl; else @@ -1539,7 +1539,7 @@ BLI_INLINE bool spring_length(Implicit_Data *data, int i, int j, float r_extent[ sub_v3_v3v3(r_extent, data->X[j], data->X[i]); sub_v3_v3v3(r_vel, data->V[j], data->V[i]); *r_length = len_v3(r_extent); - + if (*r_length > ALMOST_ZERO) { /* if (length>L) { @@ -1557,21 +1557,21 @@ BLI_INLINE bool spring_length(Implicit_Data *data, int i, int j, float r_extent[ else { zero_v3(r_dir); } - + return true; } BLI_INLINE void apply_spring(Implicit_Data *data, int i, int j, const float f[3], float dfdx[3][3], float dfdv[3][3]) { int block_ij = BPH_mass_spring_add_block(data, i, j); - + add_v3_v3(data->F[i], f); sub_v3_v3(data->F[j], f); - + add_m3_m3m3(data->dFdX[i].m, data->dFdX[i].m, dfdx); add_m3_m3m3(data->dFdX[j].m, data->dFdX[j].m, dfdx); sub_m3_m3m3(data->dFdX[block_ij].m, data->dFdX[block_ij].m, dfdx); - + add_m3_m3m3(data->dFdV[i].m, data->dFdV[i].m, dfdv); add_m3_m3m3(data->dFdV[j].m, data->dFdV[j].m, dfdv); sub_m3_m3m3(data->dFdV[block_ij].m, data->dFdV[block_ij].m, dfdv); @@ -1581,7 +1581,7 @@ bool BPH_mass_spring_force_spring_linear(Implicit_Data *data, int i, int j, floa float stiffness, float damping, bool no_compress, float clamp_force) { float extent[3], length, dir[3], vel[3]; - + // calculate elonglation spring_length(data, i, j, extent, dir, &length, vel); @@ -1590,22 +1590,22 @@ bool BPH_mass_spring_force_spring_linear(Implicit_Data *data, int i, int j, floa Thus length > restlen makes cloth unconstrained at the start of simulation. */ if ((length >= restlen && length > 0) || no_compress) { float stretch_force, f[3], dfdx[3][3], dfdv[3][3]; - + stretch_force = stiffness * (length - restlen); if (clamp_force > 0.0f && stretch_force > clamp_force) { stretch_force = clamp_force; } mul_v3_v3fl(f, dir, stretch_force); - + // Ascher & Boxman, p.21: Damping only during elonglation // something wrong with it... madd_v3_v3fl(f, dir, damping * dot_v3v3(vel, dir)); - + dfdx_spring(dfdx, dir, length, restlen, stiffness); dfdv_damp(dfdv, dir, damping); - + apply_spring(data, i, j, f, dfdx, dfdv); - + return true; } else { @@ -1617,23 +1617,23 @@ bool BPH_mass_spring_force_spring_linear(Implicit_Data *data, int i, int j, floa bool BPH_mass_spring_force_spring_bending(Implicit_Data *data, int i, int j, float restlen, float kb, float cb) { float extent[3], length, dir[3], vel[3]; - + // calculate elonglation spring_length(data, i, j, extent, dir, &length, vel); - + if (length < restlen) { float f[3], dfdx[3][3], dfdv[3][3]; - + mul_v3_v3fl(f, dir, fbstar(length, restlen, kb, cb)); - + outerproduct(dfdx, dir, dir); mul_m3_fl(dfdx, fbstar_jacobi(length, restlen, kb, cb)); - + /* XXX damping not supported */ zero_m3(dfdv); - + apply_spring(data, i, j, f, dfdx, dfdv); - + return true; } else { @@ -1650,10 +1650,10 @@ bool BPH_mass_spring_force_spring_bending(Implicit_Data *data, int i, int j, flo BLI_INLINE void spring_grad_dir(Implicit_Data *data, int i, int j, float edge[3], float dir[3], float grad_dir[3][3]) { float length; - + sub_v3_v3v3(edge, data->X[j], data->X[i]); length = normalize_v3_v3(dir, edge); - + if (length > ALMOST_ZERO) { outerproduct(grad_dir, dir, dir); sub_m3_m3m3(grad_dir, I, grad_dir); @@ -1676,39 +1676,39 @@ BLI_INLINE void spring_angbend_forces(Implicit_Data *data, int i, int j, int k, float f_bend[3], f_damp[3]; float fk[3]; float dist[3]; - + zero_v3(fk); - + sub_v3_v3v3(edge_ij, data->X[j], data->X[i]); if (q == i) sub_v3_v3(edge_ij, dx); if (q == j) add_v3_v3(edge_ij, dx); normalize_v3_v3(dir_ij, edge_ij); - + sub_v3_v3v3(edge_jk, data->X[k], data->X[j]); if (q == j) sub_v3_v3(edge_jk, dx); if (q == k) add_v3_v3(edge_jk, dx); normalize_v3_v3(dir_jk, edge_jk); - + sub_v3_v3v3(vel_ij, data->V[j], data->V[i]); if (q == i) sub_v3_v3(vel_ij, dv); if (q == j) add_v3_v3(vel_ij, dv); - + sub_v3_v3v3(vel_jk, data->V[k], data->V[j]); if (q == j) sub_v3_v3(vel_jk, dv); if (q == k) add_v3_v3(vel_jk, dv); - + /* bending force */ sub_v3_v3v3(dist, goal, edge_jk); mul_v3_v3fl(f_bend, dist, stiffness); - + add_v3_v3(fk, f_bend); - + /* damping force */ madd_v3_v3v3fl(vel_ortho, vel_jk, dir_jk, -dot_v3v3(vel_jk, dir_jk)); mul_v3_v3fl(f_damp, vel_ortho, damping); - + sub_v3_v3(fk, f_damp); - + copy_v3_v3(r_f, fk); } @@ -1722,24 +1722,24 @@ BLI_INLINE void spring_angbend_estimate_dfdx(Implicit_Data *data, int i, int j, float dvec_null[3][3], dvec_pos[3][3], dvec_neg[3][3]; float f[3]; int a, b; - + zero_m3(dvec_null); unit_m3(dvec_pos); mul_m3_fl(dvec_pos, delta * 0.5f); copy_m3_m3(dvec_neg, dvec_pos); negate_m3(dvec_neg); - + /* XXX TODO offset targets to account for position dependency */ - + for (a = 0; a < 3; ++a) { spring_angbend_forces(data, i, j, k, goal, stiffness, damping, q, dvec_pos[a], dvec_null[a], f); copy_v3_v3(dfdx[a], f); - + spring_angbend_forces(data, i, j, k, goal, stiffness, damping, q, dvec_neg[a], dvec_null[a], f); sub_v3_v3(dfdx[a], f); - + for (b = 0; b < 3; ++b) { dfdx[a][b] /= delta; } @@ -1756,24 +1756,24 @@ BLI_INLINE void spring_angbend_estimate_dfdv(Implicit_Data *data, int i, int j, float dvec_null[3][3], dvec_pos[3][3], dvec_neg[3][3]; float f[3]; int a, b; - + zero_m3(dvec_null); unit_m3(dvec_pos); mul_m3_fl(dvec_pos, delta * 0.5f); copy_m3_m3(dvec_neg, dvec_pos); negate_m3(dvec_neg); - + /* XXX TODO offset targets to account for position dependency */ - + for (a = 0; a < 3; ++a) { spring_angbend_forces(data, i, j, k, goal, stiffness, damping, q, dvec_null[a], dvec_pos[a], f); copy_v3_v3(dfdv[a], f); - + spring_angbend_forces(data, i, j, k, goal, stiffness, damping, q, dvec_null[a], dvec_neg[a], f); sub_v3_v3(dfdv[a], f); - + for (b = 0; b < 3; ++b) { dfdv[a][b] /= delta; } @@ -1790,45 +1790,45 @@ bool BPH_mass_spring_force_spring_bending_angular(Implicit_Data *data, int i, in float fj[3], fk[3]; float dfj_dxi[3][3], dfj_dxj[3][3], dfk_dxi[3][3], dfk_dxj[3][3], dfk_dxk[3][3]; float dfj_dvi[3][3], dfj_dvj[3][3], dfk_dvi[3][3], dfk_dvj[3][3], dfk_dvk[3][3]; - + const float vecnull[3] = {0.0f, 0.0f, 0.0f}; - + int block_ij = BPH_mass_spring_add_block(data, i, j); int block_jk = BPH_mass_spring_add_block(data, j, k); int block_ik = BPH_mass_spring_add_block(data, i, k); - + world_to_root_v3(data, j, goal, target); - + spring_angbend_forces(data, i, j, k, goal, stiffness, damping, k, vecnull, vecnull, fk); negate_v3_v3(fj, fk); /* counterforce */ - + spring_angbend_estimate_dfdx(data, i, j, k, goal, stiffness, damping, i, dfk_dxi); spring_angbend_estimate_dfdx(data, i, j, k, goal, stiffness, damping, j, dfk_dxj); spring_angbend_estimate_dfdx(data, i, j, k, goal, stiffness, damping, k, dfk_dxk); copy_m3_m3(dfj_dxi, dfk_dxi); negate_m3(dfj_dxi); copy_m3_m3(dfj_dxj, dfk_dxj); negate_m3(dfj_dxj); - + spring_angbend_estimate_dfdv(data, i, j, k, goal, stiffness, damping, i, dfk_dvi); spring_angbend_estimate_dfdv(data, i, j, k, goal, stiffness, damping, j, dfk_dvj); spring_angbend_estimate_dfdv(data, i, j, k, goal, stiffness, damping, k, dfk_dvk); copy_m3_m3(dfj_dvi, dfk_dvi); negate_m3(dfj_dvi); copy_m3_m3(dfj_dvj, dfk_dvj); negate_m3(dfj_dvj); - + /* add forces and jacobians to the solver data */ - + add_v3_v3(data->F[j], fj); add_v3_v3(data->F[k], fk); - + add_m3_m3m3(data->dFdX[j].m, data->dFdX[j].m, dfj_dxj); add_m3_m3m3(data->dFdX[k].m, data->dFdX[k].m, dfk_dxk); - + add_m3_m3m3(data->dFdX[block_ij].m, data->dFdX[block_ij].m, dfj_dxi); add_m3_m3m3(data->dFdX[block_jk].m, data->dFdX[block_jk].m, dfk_dxj); add_m3_m3m3(data->dFdX[block_ik].m, data->dFdX[block_ik].m, dfk_dxi); - + add_m3_m3m3(data->dFdV[j].m, data->dFdV[j].m, dfj_dvj); add_m3_m3m3(data->dFdV[k].m, data->dFdV[k].m, dfk_dvk); - + add_m3_m3m3(data->dFdV[block_ij].m, data->dFdV[block_ij].m, dfj_dvi); add_m3_m3m3(data->dFdV[block_jk].m, data->dFdV[block_jk].m, dfk_dvj); add_m3_m3m3(data->dFdV[block_ik].m, data->dFdV[block_ik].m, dfk_dvi); @@ -1847,10 +1847,10 @@ bool BPH_mass_spring_force_spring_bending_angular(Implicit_Data *data, int i, in float fi[3], fj[3], fk[3]; float dfi_dxi[3][3], dfj_dxi[3][3], dfj_dxj[3][3], dfk_dxi[3][3], dfk_dxj[3][3], dfk_dxk[3][3]; float dfdvi[3][3]; - + // TESTING damping = 0.0f; - + zero_v3(fi); zero_v3(fj); zero_v3(fk); @@ -1859,68 +1859,68 @@ bool BPH_mass_spring_force_spring_bending_angular(Implicit_Data *data, int i, in zero_m3(dfk_dxi); zero_m3(dfk_dxj); zero_m3(dfk_dxk); - + /* jacobian of direction vectors */ spring_grad_dir(data, i, j, edge_ij, dir_ij, grad_dir_ij); spring_grad_dir(data, j, k, edge_jk, dir_jk, grad_dir_jk); - + sub_v3_v3v3(vel_jk, data->V[k], data->V[j]); - + /* bending force */ mul_v3_v3fl(target, dir_ij, restlen); sub_v3_v3v3(dist, target, edge_jk); mul_v3_v3fl(fk, dist, stiffness); - + /* damping force */ madd_v3_v3v3fl(vel_jk_ortho, vel_jk, dir_jk, -dot_v3v3(vel_jk, dir_jk)); madd_v3_v3fl(fk, vel_jk_ortho, damping); - + /* XXX this only holds true as long as we assume straight rest shape! * eventually will become a bit more involved since the opposite segment * gets its own target, under condition of having equal torque on both sides. */ copy_v3_v3(fi, fk); - + /* counterforce on the middle point */ sub_v3_v3(fj, fi); sub_v3_v3(fj, fk); - + /* === derivatives === */ - + madd_m3_m3fl(dfk_dxi, grad_dir_ij, stiffness * restlen); - + madd_m3_m3fl(dfk_dxj, grad_dir_ij, -stiffness * restlen); madd_m3_m3fl(dfk_dxj, I, stiffness); - + madd_m3_m3fl(dfk_dxk, I, -stiffness); - + copy_m3_m3(dfi_dxi, dfk_dxk); negate_m3(dfi_dxi); - + /* dfj_dfi == dfi_dfj due to symmetry, * dfi_dfj == dfk_dfj due to fi == fk * XXX see comment above on future bent rest shapes */ copy_m3_m3(dfj_dxi, dfk_dxj); - + /* dfj_dxj == -(dfi_dxj + dfk_dxj) due to fj == -(fi + fk) */ sub_m3_m3m3(dfj_dxj, dfj_dxj, dfj_dxi); sub_m3_m3m3(dfj_dxj, dfj_dxj, dfk_dxj); - + /* add forces and jacobians to the solver data */ add_v3_v3(data->F[i], fi); add_v3_v3(data->F[j], fj); add_v3_v3(data->F[k], fk); - + add_m3_m3m3(data->dFdX[i].m, data->dFdX[i].m, dfi_dxi); add_m3_m3m3(data->dFdX[j].m, data->dFdX[j].m, dfj_dxj); add_m3_m3m3(data->dFdX[k].m, data->dFdX[k].m, dfk_dxk); - + add_m3_m3m3(data->dFdX[block_ij].m, data->dFdX[block_ij].m, dfj_dxi); add_m3_m3m3(data->dFdX[block_jk].m, data->dFdX[block_jk].m, dfk_dxj); add_m3_m3m3(data->dFdX[block_ik].m, data->dFdX[block_ik].m, dfk_dxi); #endif - + return true; } @@ -1929,29 +1929,29 @@ bool BPH_mass_spring_force_spring_goal(Implicit_Data *data, int i, const float g { float root_goal_x[3], root_goal_v[3], extent[3], length, dir[3], vel[3]; float f[3], dfdx[3][3], dfdv[3][3]; - + /* goal is in world space */ world_to_root_v3(data, i, root_goal_x, goal_x); world_to_root_v3(data, i, root_goal_v, goal_v); - + sub_v3_v3v3(extent, root_goal_x, data->X[i]); sub_v3_v3v3(vel, root_goal_v, data->V[i]); length = normalize_v3_v3(dir, extent); - + if (length > ALMOST_ZERO) { mul_v3_v3fl(f, dir, stiffness * length); - + // Ascher & Boxman, p.21: Damping only during elonglation // something wrong with it... madd_v3_v3fl(f, dir, damping * dot_v3v3(vel, dir)); - + dfdx_spring(dfdx, dir, length, 0.0f, stiffness); dfdv_damp(dfdv, dir, damping); - + add_v3_v3(data->F[i], f); add_m3_m3m3(data->dFdX[i].m, data->dFdX[i].m, dfdx); add_m3_m3m3(data->dFdV[i].m, data->dFdV[i].m, dfdv); - + return true; } else { diff --git a/source/blender/physics/intern/implicit_eigen.cpp b/source/blender/physics/intern/implicit_eigen.cpp index d56525f2e93..eaac63893a6 100644 --- a/source/blender/physics/intern/implicit_eigen.cpp +++ b/source/blender/physics/intern/implicit_eigen.cpp @@ -99,24 +99,24 @@ static float I[3][3] = {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}; class fVector : public Eigen::Vector3f { public: typedef float *ctype; - + fVector() { } - + fVector(const ctype &v) { for (int k = 0; k < 3; ++k) coeffRef(k) = v[k]; } - + fVector& operator = (const ctype &v) { for (int k = 0; k < 3; ++k) coeffRef(k) = v[k]; return *this; } - + operator ctype() { return data(); @@ -129,18 +129,18 @@ public: class fMatrix : public Eigen::Matrix3f { public: typedef float (*ctype)[3]; - + fMatrix() { } - + fMatrix(const ctype &v) { for (int k = 0; k < 3; ++k) for (int l = 0; l < 3; ++l) coeffRef(l, k) = v[k][l]; } - + fMatrix& operator = (const ctype &v) { for (int k = 0; k < 3; ++k) @@ -148,7 +148,7 @@ public: coeffRef(l, k) = v[k][l]; return *this; } - + operator ctype() { return (ctype)data(); @@ -161,23 +161,23 @@ public: class lVector : public Eigen::VectorXf { public: typedef Eigen::VectorXf base_t; - + lVector() { } - + template <typename T> lVector& operator = (T rhs) { base_t::operator=(rhs); return *this; } - + float* v3(int vertex) { return &coeffRef(3 * vertex); } - + const float* v3(int vertex) const { return &coeffRef(3 * vertex); @@ -198,18 +198,18 @@ struct lMatrixCtor { lMatrixCtor() { } - + void reset() { m_trips.clear(); } - + void reserve(int numverts) { /* reserve for diagonal entries */ m_trips.reserve(numverts * 9); } - + void add(int i, int j, const fMatrix &m) { i *= 3; @@ -218,7 +218,7 @@ struct lMatrixCtor { for (int l = 0; l < 3; ++l) m_trips.push_back(Triplet(i + k, j + l, m.coeff(l, k))); } - + void sub(int i, int j, const fMatrix &m) { i *= 3; @@ -227,13 +227,13 @@ struct lMatrixCtor { for (int l = 0; l < 3; ++l) m_trips.push_back(Triplet(i + k, j + l, -m.coeff(l, k))); } - + inline void construct(lMatrix &m) { m.setFromTriplets(m_trips.begin(), m_trips.end()); m_trips.clear(); } - + private: TripletList m_trips; }; @@ -253,7 +253,7 @@ static void print_lvector(const lVector &v) for (int i = 0; i < v.rows(); ++i) { if (i > 0 && i % 3 == 0) printf("\n"); - + printf("%f,\n", v[i]); } } @@ -263,11 +263,11 @@ static void print_lmatrix(const lMatrix &m) for (int j = 0; j < m.rows(); ++j) { if (j > 0 && j % 3 == 0) printf("\n"); - + for (int i = 0; i < m.cols(); ++i) { if (i > 0 && i % 3 == 0) printf(" "); - + implicit_print_matrix_elem(m.coeff(j, i)); } printf("\n"); @@ -383,63 +383,63 @@ BLI_INLINE void madd_m3_m3m3fl(float r[3][3], float a[3][3], float b[3][3], floa struct Implicit_Data { typedef std::vector<fMatrix> fMatrixVector; - + Implicit_Data(int numverts) { resize(numverts); } - + void resize(int numverts) { this->numverts = numverts; int tot = 3 * numverts; - + M.resize(tot, tot); F.resize(tot); dFdX.resize(tot, tot); dFdV.resize(tot, tot); - + tfm.resize(numverts, I); - + X.resize(tot); Xnew.resize(tot); V.resize(tot); Vnew.resize(tot); - + A.resize(tot, tot); B.resize(tot); - + dV.resize(tot); z.resize(tot); S.resize(tot, tot); - + iM.reserve(numverts); idFdX.reserve(numverts); idFdV.reserve(numverts); iS.reserve(numverts); } - + int numverts; - + /* inputs */ lMatrix M; /* masses */ lVector F; /* forces */ lMatrix dFdX, dFdV; /* force jacobians */ - + fMatrixVector tfm; /* local coordinate transform */ - + /* motion state data */ lVector X, Xnew; /* positions */ lVector V, Vnew; /* velocities */ - + /* internal solver data */ lVector B; /* B for A*dV = B */ lMatrix A; /* A for A*dV = B */ - + lVector dV; /* velocity change (solution of A*dV = B) */ lVector z; /* target velocity in constrained directions */ lMatrix S; /* filtering matrix for constraints */ - + /* temporary constructors */ lMatrixCtor iM; /* masses */ lMatrixCtor idFdX, idFdV; /* force jacobians */ @@ -502,25 +502,25 @@ bool BPH_mass_spring_solve_velocities(Implicit_Data *data, float dt, ImplicitSol #ifdef USE_EIGEN_CONSTRAINED_CG typedef ConstraintConjGrad solver_t; #endif - + data->iM.construct(data->M); data->idFdX.construct(data->dFdX); data->idFdV.construct(data->dFdV); data->iS.construct(data->S); - + solver_t cg; cg.setMaxIterations(100); cg.setTolerance(0.01f); - + #ifdef USE_EIGEN_CONSTRAINED_CG cg.filter() = data->S; #endif - + data->A = data->M - dt * data->dFdV - dt*dt * data->dFdX; cg.compute(data->A); - + data->B = dt * data->F + dt*dt * data->dFdX * data->V; - + #ifdef IMPLICIT_PRINT_SOLVER_INPUT_OUTPUT printf("==== A ====\n"); print_lmatrix(id->A); @@ -531,22 +531,22 @@ bool BPH_mass_spring_solve_velocities(Implicit_Data *data, float dt, ImplicitSol printf("==== S ====\n"); print_lmatrix(id->S); #endif - + #ifdef USE_EIGEN_CORE data->dV = cg.solve(data->B); #endif #ifdef USE_EIGEN_CONSTRAINED_CG data->dV = cg.solveWithGuess(data->B, data->z); #endif - + #ifdef IMPLICIT_PRINT_SOLVER_INPUT_OUTPUT printf("==== dV ====\n"); print_lvector(id->dV); printf("========\n"); #endif - + data->Vnew = data->V + data->dV; - + switch (cg.info()) { case Eigen::Success: result->status = BPH_SOLVER_SUCCESS; break; case Eigen::NoConvergence: result->status = BPH_SOLVER_NO_CONVERGENCE; break; @@ -556,7 +556,7 @@ bool BPH_mass_spring_solve_velocities(Implicit_Data *data, float dt, ImplicitSol result->iterations = cg.iterations(); result->error = cg.error(); - + return cg.info() == Eigen::Success; } @@ -641,26 +641,26 @@ void BPH_mass_spring_clear_constraints(Implicit_Data *data) void BPH_mass_spring_add_constraint_ndof0(Implicit_Data *data, int index, const float dV[3]) { data->iS.sub(index, index, I); - + world_to_root_v3(data, index, data->z.v3(index), dV); } void BPH_mass_spring_add_constraint_ndof1(Implicit_Data *data, int index, const float c1[3], const float c2[3], const float dV[3]) { float m[3][3], p[3], q[3], u[3], cmat[3][3]; - + world_to_root_v3(data, index, p, c1); outerproduct(cmat, p, p); copy_m3_m3(m, cmat); - + world_to_root_v3(data, index, q, c2); outerproduct(cmat, q, q); add_m3_m3m3(m, m, cmat); - + /* XXX not sure but multiplication should work here */ data->iS.sub(index, index, m); // mul_m3_m3m3(data->S[index].m, data->S[index].m, m); - + world_to_root_v3(data, index, u, dV); add_v3_v3(data->z.v3(index), u); } @@ -668,14 +668,14 @@ void BPH_mass_spring_add_constraint_ndof1(Implicit_Data *data, int index, const void BPH_mass_spring_add_constraint_ndof2(Implicit_Data *data, int index, const float c1[3], const float dV[3]) { float m[3][3], p[3], u[3], cmat[3][3]; - + world_to_root_v3(data, index, p, c1); outerproduct(cmat, p, p); copy_m3_m3(m, cmat); - + data->iS.sub(index, index, m); // mul_m3_m3m3(data->S[index].m, data->S[index].m, m); - + world_to_root_v3(data, index, u, dV); add_v3_v3(data->z.v3(index), u); } @@ -694,37 +694,37 @@ void BPH_mass_spring_force_reference_frame(Implicit_Data *data, int index, const float f[3], dfdx[3][3], dfdv[3][3]; float euler[3], coriolis[3], centrifugal[3], rotvel[3]; float deuler[3][3], dcoriolis[3][3], dcentrifugal[3][3], drotvel[3][3]; - + world_to_root_v3(data, index, acc, acceleration); world_to_root_v3(data, index, w, omega); world_to_root_v3(data, index, dwdt, domega_dt); - + cross_v3_v3v3(euler, dwdt, data->X.v3(index)); cross_v3_v3v3(coriolis, w, data->V.v3(index)); mul_v3_fl(coriolis, 2.0f); cross_v3_v3v3(rotvel, w, data->X.v3(index)); cross_v3_v3v3(centrifugal, w, rotvel); - + sub_v3_v3v3(f, acc, euler); sub_v3_v3(f, coriolis); sub_v3_v3(f, centrifugal); - + mul_v3_fl(f, mass); /* F = m * a */ - + cross_v3_identity(deuler, dwdt); cross_v3_identity(dcoriolis, w); mul_m3_fl(dcoriolis, 2.0f); cross_v3_identity(drotvel, w); cross_m3_v3m3(dcentrifugal, w, drotvel); - + add_m3_m3m3(dfdx, deuler, dcentrifugal); negate_m3(dfdx); mul_m3_fl(dfdx, mass); - + copy_m3_m3(dfdv, dcoriolis); negate_m3(dfdv); mul_m3_fl(dfdv, mass); - + add_v3_v3(data->F.v3(index), f); data->idFdX.add(index, index, dfdx); data->idFdV.add(index, index, dfdv); @@ -743,7 +743,7 @@ void BPH_mass_spring_force_gravity(Implicit_Data *data, int index, float mass, c float f[3]; world_to_root_v3(data, index, f, g); mul_v3_fl(f, mass); - + add_v3_v3(data->F.v3(index), f); } @@ -752,10 +752,10 @@ void BPH_mass_spring_force_drag(Implicit_Data *data, float drag) int numverts = data->numverts; for (int i = 0; i < numverts; i++) { float tmp[3][3]; - + /* NB: uses root space velocity, no need to transform */ madd_v3_v3fl(data->F.v3(i), data->V.v3(i), -drag); - + copy_m3_m3(tmp, I); mul_m3_fl(tmp, -drag); data->idFdV.add(i, i, tmp); @@ -768,7 +768,7 @@ void BPH_mass_spring_force_extern(struct Implicit_Data *data, int i, const float world_to_root_v3(data, i, tf, f); world_to_root_m3(data, i, tdfdx, dfdx); world_to_root_m3(data, i, tdfdv, dfdv); - + add_v3_v3(data->F.v3(i), tf); data->idFdX.add(i, i, tdfdx); data->idFdV.add(i, i, tdfdv); @@ -777,10 +777,10 @@ void BPH_mass_spring_force_extern(struct Implicit_Data *data, int i, const float static float calc_nor_area_tri(float nor[3], const float v1[3], const float v2[3], const float v3[3]) { float n1[3], n2[3]; - + sub_v3_v3v3(n1, v1, v2); sub_v3_v3v3(n2, v2, v3); - + cross_v3_v3v3(nor, n1, n2); return normalize_v3(nor); } @@ -791,17 +791,17 @@ void BPH_mass_spring_force_face_wind(Implicit_Data *data, int v1, int v2, int v3 const float effector_scale = 0.02f; float win[3], nor[3], area; float factor; - + // calculate face normal and area area = calc_nor_area_tri(nor, data->X.v3(v1), data->X.v3(v2), data->X.v3(v3)); factor = effector_scale * area / 3.0f; - + world_to_root_v3(data, v1, win, winvec[v1]); madd_v3_v3fl(data->F.v3(v1), nor, factor * dot_v3v3(win, nor)); - + world_to_root_v3(data, v2, win, winvec[v2]); madd_v3_v3fl(data->F.v3(v2), nor, factor * dot_v3v3(win, nor)); - + world_to_root_v3(data, v3, win, winvec[v3]); madd_v3_v3fl(data->F.v3(v3), nor, factor * dot_v3v3(win, nor)); } @@ -810,14 +810,14 @@ void BPH_mass_spring_force_edge_wind(Implicit_Data *data, int v1, int v2, const { const float effector_scale = 0.01; float win[3], dir[3], nor[3], length; - + sub_v3_v3v3(dir, data->X.v3(v1), data->X.v3(v2)); length = normalize_v3(dir); - + world_to_root_v3(data, v1, win, winvec[v1]); madd_v3_v3v3fl(nor, win, dir, -dot_v3v3(win, dir)); madd_v3_v3fl(data->F.v3(v1), nor, effector_scale * length); - + world_to_root_v3(data, v2, win, winvec[v2]); madd_v3_v3v3fl(nor, win, dir, -dot_v3v3(win, dir)); madd_v3_v3fl(data->F.v3(v2), nor, effector_scale * length); @@ -829,8 +829,8 @@ BLI_INLINE void dfdx_spring(float to[3][3], const float dir[3], float length, fl //return ( (I-outerprod(dir, dir))*Min(1.0f, rest/length) - I) * -k; outerproduct(to, dir, dir); sub_m3_m3m3(to, I, to); - - mul_m3_fl(to, (L/length)); + + mul_m3_fl(to, (L/length)); sub_m3_m3m3(to, to, I); mul_m3_fl(to, k); } @@ -839,7 +839,7 @@ BLI_INLINE void dfdx_spring(float to[3][3], const float dir[3], float length, fl #if 0 BLI_INLINE void dfdx_damp(float to[3][3], const float dir[3], float length, const float vel[3], float rest, float damping) { - // inner spring damping vel is the relative velocity of the endpoints. + // inner spring damping vel is the relative velocity of the endpoints. // return (I-outerprod(dir, dir)) * (-damping * -(dot(dir, vel)/Max(length, rest))); mul_fvectorT_fvector(to, dir, dir); sub_fmatrix_fmatrix(to, I, to); @@ -871,7 +871,7 @@ BLI_INLINE float fbstar(float length, float L, float kb, float cb) { float tempfb_fl = kb * fb(length, L); float fbstar_fl = cb * (length - L); - + if (tempfb_fl < fbstar_fl) return fbstar_fl; else @@ -898,7 +898,7 @@ BLI_INLINE bool spring_length(Implicit_Data *data, int i, int j, float r_extent[ sub_v3_v3v3(r_extent, data->X.v3(j), data->X.v3(i)); sub_v3_v3v3(r_vel, data->V.v3(j), data->V.v3(i)); *r_length = len_v3(r_extent); - + if (*r_length > ALMOST_ZERO) { /* if (length>L) { @@ -916,7 +916,7 @@ BLI_INLINE bool spring_length(Implicit_Data *data, int i, int j, float r_extent[ else { zero_v3(r_dir); } - + return true; } @@ -924,12 +924,12 @@ BLI_INLINE void apply_spring(Implicit_Data *data, int i, int j, const float f[3] { add_v3_v3(data->F.v3(i), f); sub_v3_v3(data->F.v3(j), f); - + data->idFdX.add(i, i, dfdx); data->idFdX.add(j, j, dfdx); data->idFdX.sub(i, j, dfdx); data->idFdX.sub(j, i, dfdx); - + data->idFdV.add(i, i, dfdv); data->idFdV.add(j, j, dfdv); data->idFdV.sub(i, j, dfdv); @@ -941,39 +941,39 @@ bool BPH_mass_spring_force_spring_linear(Implicit_Data *data, int i, int j, floa float r_f[3], float r_dfdx[3][3], float r_dfdv[3][3]) { float extent[3], length, dir[3], vel[3]; - + // calculate elonglation spring_length(data, i, j, extent, dir, &length, vel); - + if (length > restlen || no_compress) { float stretch_force, f[3], dfdx[3][3], dfdv[3][3]; - + stretch_force = stiffness * (length - restlen); if (clamp_force > 0.0f && stretch_force > clamp_force) { stretch_force = clamp_force; } mul_v3_v3fl(f, dir, stretch_force); - + // Ascher & Boxman, p.21: Damping only during elonglation // something wrong with it... madd_v3_v3fl(f, dir, damping * dot_v3v3(vel, dir)); - + dfdx_spring(dfdx, dir, length, restlen, stiffness); dfdv_damp(dfdv, dir, damping); - + apply_spring(data, i, j, f, dfdx, dfdv); - + if (r_f) copy_v3_v3(r_f, f); if (r_dfdx) copy_m3_m3(r_dfdx, dfdx); if (r_dfdv) copy_m3_m3(r_dfdv, dfdv); - + return true; } else { if (r_f) zero_v3(r_f); if (r_dfdx) zero_m3(r_dfdx); if (r_dfdv) zero_m3(r_dfdv); - + return false; } } @@ -984,34 +984,34 @@ bool BPH_mass_spring_force_spring_bending(Implicit_Data *data, int i, int j, flo float r_f[3], float r_dfdx[3][3], float r_dfdv[3][3]) { float extent[3], length, dir[3], vel[3]; - + // calculate elonglation spring_length(data, i, j, extent, dir, &length, vel); - + if (length < restlen) { float f[3], dfdx[3][3], dfdv[3][3]; - + mul_v3_v3fl(f, dir, fbstar(length, restlen, kb, cb)); - + outerproduct(dfdx, dir, dir); mul_m3_fl(dfdx, fbstar_jacobi(length, restlen, kb, cb)); - + /* XXX damping not supported */ zero_m3(dfdv); - + apply_spring(data, i, j, f, dfdx, dfdv); - + if (r_f) copy_v3_v3(r_f, f); if (r_dfdx) copy_m3_m3(r_dfdx, dfdx); if (r_dfdv) copy_m3_m3(r_dfdv, dfdv); - + return true; } else { if (r_f) zero_v3(r_f); if (r_dfdx) zero_m3(r_dfdx); if (r_dfdv) zero_m3(r_dfdv); - + return false; } } @@ -1025,10 +1025,10 @@ bool BPH_mass_spring_force_spring_bending(Implicit_Data *data, int i, int j, flo BLI_INLINE void spring_grad_dir(Implicit_Data *data, int i, int j, float edge[3], float dir[3], float grad_dir[3][3]) { float length; - + sub_v3_v3v3(edge, data->X.v3(j), data->X.v3(i)); length = normalize_v3_v3(dir, edge); - + if (length > ALMOST_ZERO) { outerproduct(grad_dir, dir, dir); sub_m3_m3m3(grad_dir, I, grad_dir); @@ -1051,39 +1051,39 @@ BLI_INLINE void spring_angbend_forces(Implicit_Data *data, int i, int j, int k, float f_bend[3], f_damp[3]; float fk[3]; float dist[3]; - + zero_v3(fk); - + sub_v3_v3v3(edge_ij, data->X.v3(j), data->X.v3(i)); if (q == i) sub_v3_v3(edge_ij, dx); if (q == j) add_v3_v3(edge_ij, dx); normalize_v3_v3(dir_ij, edge_ij); - + sub_v3_v3v3(edge_jk, data->X.v3(k), data->X.v3(j)); if (q == j) sub_v3_v3(edge_jk, dx); if (q == k) add_v3_v3(edge_jk, dx); normalize_v3_v3(dir_jk, edge_jk); - + sub_v3_v3v3(vel_ij, data->V.v3(j), data->V.v3(i)); if (q == i) sub_v3_v3(vel_ij, dv); if (q == j) add_v3_v3(vel_ij, dv); - + sub_v3_v3v3(vel_jk, data->V.v3(k), data->V.v3(j)); if (q == j) sub_v3_v3(vel_jk, dv); if (q == k) add_v3_v3(vel_jk, dv); - + /* bending force */ sub_v3_v3v3(dist, goal, edge_jk); mul_v3_v3fl(f_bend, dist, stiffness); - + add_v3_v3(fk, f_bend); - + /* damping force */ madd_v3_v3v3fl(vel_ortho, vel_jk, dir_jk, -dot_v3v3(vel_jk, dir_jk)); mul_v3_v3fl(f_damp, vel_ortho, damping); - + sub_v3_v3(fk, f_damp); - + copy_v3_v3(r_f, fk); } @@ -1097,24 +1097,24 @@ BLI_INLINE void spring_angbend_estimate_dfdx(Implicit_Data *data, int i, int j, float dvec_null[3][3], dvec_pos[3][3], dvec_neg[3][3]; float f[3]; int a, b; - + zero_m3(dvec_null); unit_m3(dvec_pos); mul_m3_fl(dvec_pos, delta * 0.5f); copy_m3_m3(dvec_neg, dvec_pos); negate_m3(dvec_neg); - + /* XXX TODO offset targets to account for position dependency */ - + for (a = 0; a < 3; ++a) { spring_angbend_forces(data, i, j, k, goal, stiffness, damping, q, dvec_pos[a], dvec_null[a], f); copy_v3_v3(dfdx[a], f); - + spring_angbend_forces(data, i, j, k, goal, stiffness, damping, q, dvec_neg[a], dvec_null[a], f); sub_v3_v3(dfdx[a], f); - + for (b = 0; b < 3; ++b) { dfdx[a][b] /= delta; } @@ -1131,24 +1131,24 @@ BLI_INLINE void spring_angbend_estimate_dfdv(Implicit_Data *data, int i, int j, float dvec_null[3][3], dvec_pos[3][3], dvec_neg[3][3]; float f[3]; int a, b; - + zero_m3(dvec_null); unit_m3(dvec_pos); mul_m3_fl(dvec_pos, delta * 0.5f); copy_m3_m3(dvec_neg, dvec_pos); negate_m3(dvec_neg); - + /* XXX TODO offset targets to account for position dependency */ - + for (a = 0; a < 3; ++a) { spring_angbend_forces(data, i, j, k, goal, stiffness, damping, q, dvec_null[a], dvec_pos[a], f); copy_v3_v3(dfdv[a], f); - + spring_angbend_forces(data, i, j, k, goal, stiffness, damping, q, dvec_null[a], dvec_neg[a], f); sub_v3_v3(dfdv[a], f); - + for (b = 0; b < 3; ++b) { dfdv[a][b] /= delta; } @@ -1165,44 +1165,44 @@ bool BPH_mass_spring_force_spring_bending_angular(Implicit_Data *data, int i, in float fj[3], fk[3]; float dfj_dxi[3][3], dfj_dxj[3][3], dfk_dxi[3][3], dfk_dxj[3][3], dfk_dxk[3][3]; float dfj_dvi[3][3], dfj_dvj[3][3], dfk_dvi[3][3], dfk_dvj[3][3], dfk_dvk[3][3]; - + const float vecnull[3] = {0.0f, 0.0f, 0.0f}; - + world_to_root_v3(data, j, goal, target); - + spring_angbend_forces(data, i, j, k, goal, stiffness, damping, k, vecnull, vecnull, fk); negate_v3_v3(fj, fk); /* counterforce */ - + spring_angbend_estimate_dfdx(data, i, j, k, goal, stiffness, damping, i, dfk_dxi); spring_angbend_estimate_dfdx(data, i, j, k, goal, stiffness, damping, j, dfk_dxj); spring_angbend_estimate_dfdx(data, i, j, k, goal, stiffness, damping, k, dfk_dxk); copy_m3_m3(dfj_dxi, dfk_dxi); negate_m3(dfj_dxi); copy_m3_m3(dfj_dxj, dfk_dxj); negate_m3(dfj_dxj); - + spring_angbend_estimate_dfdv(data, i, j, k, goal, stiffness, damping, i, dfk_dvi); spring_angbend_estimate_dfdv(data, i, j, k, goal, stiffness, damping, j, dfk_dvj); spring_angbend_estimate_dfdv(data, i, j, k, goal, stiffness, damping, k, dfk_dvk); copy_m3_m3(dfj_dvi, dfk_dvi); negate_m3(dfj_dvi); copy_m3_m3(dfj_dvj, dfk_dvj); negate_m3(dfj_dvj); - + /* add forces and jacobians to the solver data */ - + add_v3_v3(data->F.v3(j), fj); add_v3_v3(data->F.v3(k), fk); - + data->idFdX.add(j, j, dfj_dxj); data->idFdX.add(k, k, dfk_dxk); - + data->idFdX.add(i, j, dfj_dxi); data->idFdX.add(j, i, dfj_dxi); data->idFdX.add(j, k, dfk_dxj); data->idFdX.add(k, j, dfk_dxj); data->idFdX.add(i, k, dfk_dxi); data->idFdX.add(k, i, dfk_dxi); - + data->idFdV.add(j, j, dfj_dvj); data->idFdV.add(k, k, dfk_dvk); - + data->idFdV.add(i, j, dfj_dvi); data->idFdV.add(j, i, dfj_dvi); data->idFdV.add(j, k, dfk_dvj); @@ -1223,10 +1223,10 @@ bool BPH_mass_spring_force_spring_bending_angular(Implicit_Data *data, int i, in float fi[3], fj[3], fk[3]; float dfi_dxi[3][3], dfj_dxi[3][3], dfj_dxj[3][3], dfk_dxi[3][3], dfk_dxj[3][3], dfk_dxk[3][3]; float dfdvi[3][3]; - + // TESTING damping = 0.0f; - + zero_v3(fi); zero_v3(fj); zero_v3(fk); @@ -1235,68 +1235,68 @@ bool BPH_mass_spring_force_spring_bending_angular(Implicit_Data *data, int i, in zero_m3(dfk_dxi); zero_m3(dfk_dxj); zero_m3(dfk_dxk); - + /* jacobian of direction vectors */ spring_grad_dir(data, i, j, edge_ij, dir_ij, grad_dir_ij); spring_grad_dir(data, j, k, edge_jk, dir_jk, grad_dir_jk); - + sub_v3_v3v3(vel_jk, data->V[k], data->V[j]); - + /* bending force */ mul_v3_v3fl(target, dir_ij, restlen); sub_v3_v3v3(dist, target, edge_jk); mul_v3_v3fl(fk, dist, stiffness); - + /* damping force */ madd_v3_v3v3fl(vel_jk_ortho, vel_jk, dir_jk, -dot_v3v3(vel_jk, dir_jk)); madd_v3_v3fl(fk, vel_jk_ortho, damping); - + /* XXX this only holds true as long as we assume straight rest shape! * eventually will become a bit more involved since the opposite segment * gets its own target, under condition of having equal torque on both sides. */ copy_v3_v3(fi, fk); - + /* counterforce on the middle point */ sub_v3_v3(fj, fi); sub_v3_v3(fj, fk); - + /* === derivatives === */ - + madd_m3_m3fl(dfk_dxi, grad_dir_ij, stiffness * restlen); - + madd_m3_m3fl(dfk_dxj, grad_dir_ij, -stiffness * restlen); madd_m3_m3fl(dfk_dxj, I, stiffness); - + madd_m3_m3fl(dfk_dxk, I, -stiffness); - + copy_m3_m3(dfi_dxi, dfk_dxk); negate_m3(dfi_dxi); - + /* dfj_dfi == dfi_dfj due to symmetry, * dfi_dfj == dfk_dfj due to fi == fk * XXX see comment above on future bent rest shapes */ copy_m3_m3(dfj_dxi, dfk_dxj); - + /* dfj_dxj == -(dfi_dxj + dfk_dxj) due to fj == -(fi + fk) */ sub_m3_m3m3(dfj_dxj, dfj_dxj, dfj_dxi); sub_m3_m3m3(dfj_dxj, dfj_dxj, dfk_dxj); - + /* add forces and jacobians to the solver data */ add_v3_v3(data->F[i], fi); add_v3_v3(data->F[j], fj); add_v3_v3(data->F[k], fk); - + add_m3_m3m3(data->dFdX[i].m, data->dFdX[i].m, dfi_dxi); add_m3_m3m3(data->dFdX[j].m, data->dFdX[j].m, dfj_dxj); add_m3_m3m3(data->dFdX[k].m, data->dFdX[k].m, dfk_dxk); - + add_m3_m3m3(data->dFdX[block_ij].m, data->dFdX[block_ij].m, dfj_dxi); add_m3_m3m3(data->dFdX[block_jk].m, data->dFdX[block_jk].m, dfk_dxj); add_m3_m3m3(data->dFdX[block_ik].m, data->dFdX[block_ik].m, dfk_dxi); #endif - + return true; } @@ -1306,40 +1306,40 @@ bool BPH_mass_spring_force_spring_goal(Implicit_Data *data, int i, const float g { float root_goal_x[3], root_goal_v[3], extent[3], length, dir[3], vel[3]; float f[3], dfdx[3][3], dfdv[3][3]; - + /* goal is in world space */ world_to_root_v3(data, i, root_goal_x, goal_x); world_to_root_v3(data, i, root_goal_v, goal_v); - + sub_v3_v3v3(extent, root_goal_x, data->X.v3(i)); sub_v3_v3v3(vel, root_goal_v, data->V.v3(i)); length = normalize_v3_v3(dir, extent); - + if (length > ALMOST_ZERO) { mul_v3_v3fl(f, dir, stiffness * length); - + // Ascher & Boxman, p.21: Damping only during elonglation // something wrong with it... madd_v3_v3fl(f, dir, damping * dot_v3v3(vel, dir)); - + dfdx_spring(dfdx, dir, length, 0.0f, stiffness); dfdv_damp(dfdv, dir, damping); - + add_v3_v3(data->F.v3(i), f); data->idFdX.add(i, i, dfdx); data->idFdV.add(i, i, dfdv); - + if (r_f) copy_v3_v3(r_f, f); if (r_dfdx) copy_m3_m3(r_dfdx, dfdx); if (r_dfdv) copy_m3_m3(r_dfdv, dfdv); - + return true; } else { if (r_f) zero_v3(r_f); if (r_dfdx) zero_m3(r_dfdx); if (r_dfdv) zero_m3(r_dfdv); - + return false; } } diff --git a/source/blender/python/generic/CMakeLists.txt b/source/blender/python/generic/CMakeLists.txt index 77214322b88..9a5a3fddff0 100644 --- a/source/blender/python/generic/CMakeLists.txt +++ b/source/blender/python/generic/CMakeLists.txt @@ -39,12 +39,14 @@ set(SRC bpy_internal_import.c bpy_threads.c idprop_py_api.c + imbuf_py_api.c py_capi_utils.c bgl.h blf_py_api.h bpy_internal_import.h idprop_py_api.h + imbuf_py_api.h py_capi_utils.h # header-only diff --git a/source/blender/python/generic/imbuf_py_api.c b/source/blender/python/generic/imbuf_py_api.c new file mode 100644 index 00000000000..2e32829bf6c --- /dev/null +++ b/source/blender/python/generic/imbuf_py_api.c @@ -0,0 +1,447 @@ +/* + * ***** 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. + * + * Contributor(s): Campbell Barton + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/python/generic/imbuf_py_api.c + * \ingroup pygen + * + * This file defines the 'imbuf' image manipulation module. + */ + +#include <Python.h> + +#include "BLI_utildefines.h" +#include "BLI_string.h" + +#include "py_capi_utils.h" + +#include "python_utildefines.h" + +#include "imbuf_py_api.h" /* own include */ + +#include "../../imbuf/IMB_imbuf.h" +#include "../../imbuf/IMB_imbuf_types.h" + +/* File IO */ +#include <fcntl.h> +#include <errno.h> +#include "BLI_fileops.h" + +/* -------------------------------------------------------------------- */ +/** \name Type & Utilities + * \{ */ + +typedef struct Py_ImBuf { + PyObject_VAR_HEAD + /* can be NULL */ + ImBuf *ibuf; +} Py_ImBuf; + +static int py_imbuf_valid_check(Py_ImBuf *self) +{ + if (LIKELY(self->ibuf)) { + return 0; + } + else { + PyErr_Format(PyExc_ReferenceError, + "ImBuf data of type %.200s has been freed", + Py_TYPE(self)->tp_name); + return -1; + } +} + +#define PY_IMBUF_CHECK_OBJ(obj) \ + if (UNLIKELY(py_imbuf_valid_check(obj) == -1)) { return NULL; } ((void)0) +#define PY_IMBUF_CHECK_INT(obj) \ + if (UNLIKELY(py_imbuf_valid_check(obj) == -1)) { return -1; } ((void)0) + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Methods + * \{ */ + +PyDoc_STRVAR(py_imbuf_resize_doc, +".. method:: resize(size, method='FAST')\n" +"\n" +" Resize the image.\n" +"\n" +" :arg size: New size.\n" +" :type size: pair of ints\n" +" :arg method: Method of resizing (TODO)\n" +" :type method: str\n" +); +static PyObject *py_imbuf_resize(Py_ImBuf *self, PyObject *args, PyObject *kw) +{ + PY_IMBUF_CHECK_OBJ(self); + + uint size[2]; + char *method = NULL; + + static const char *_keywords[] = {"size", "method", NULL}; + static _PyArg_Parser _parser = {"(II)|s:resize", _keywords, 0}; + if (!_PyArg_ParseTupleAndKeywordsFast( + args, kw, &_parser, + &size[0], &size[1], + &method)) + { + return NULL; + } + IMB_scaleImBuf(self->ibuf, UNPACK2(size)); + Py_RETURN_NONE; +} + +PyDoc_STRVAR(py_imbuf_free_doc, +".. method:: free()\n" +"\n" +" Clear image data immediately (causing an error on re-use).\n" +); +static PyObject *py_imbuf_free(Py_ImBuf *self) +{ + if (self->ibuf) { + IMB_freeImBuf(self->ibuf); + self->ibuf = NULL; + } + Py_RETURN_NONE; +} + +static struct PyMethodDef Py_ImBuf_methods[] = { + {"resize", (PyCFunction)py_imbuf_resize, METH_VARARGS | METH_KEYWORDS, (char *)py_imbuf_resize_doc}, + {"free", (PyCFunction)py_imbuf_free, METH_NOARGS, (char *)py_imbuf_free_doc}, + {NULL, NULL, 0, NULL} +}; + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Attributes + * \{ */ + +PyDoc_STRVAR(py_imbuf_size_doc, +"size of the image in pixels.\n\n:type: pair of ints" +); +static PyObject *py_imbuf_size_get(Py_ImBuf *self, void *UNUSED(closure)) +{ + PY_IMBUF_CHECK_OBJ(self); + ImBuf *ibuf = self->ibuf; + return PyC_Tuple_Pack_I32(ibuf->x, ibuf->y); +} + +PyDoc_STRVAR(py_imbuf_ppm_doc, +"pixels per meter.\n\n:type: pair of floats" +); +static PyObject *py_imbuf_ppm_get(Py_ImBuf *self, void *UNUSED(closure)) +{ + PY_IMBUF_CHECK_OBJ(self); + ImBuf *ibuf = self->ibuf; + return PyC_Tuple_Pack_F64(ibuf->ppm[0], ibuf->ppm[1]); +} + +static int py_imbuf_ppm_set(Py_ImBuf *self, PyObject *value, void *UNUSED(closure)) +{ + PY_IMBUF_CHECK_INT(self); + double ppm[2]; + + if (PyC_AsArray(ppm, value, 2, &PyFloat_Type, true, "ppm") == -1) { + return -1; + } + + if (ppm[0] <= 0.0 || ppm[1] <= 0.0) { + PyErr_SetString(PyExc_ValueError, "invalid ppm value"); + return -1; + } + + ImBuf *ibuf = self->ibuf; + ibuf->ppm[0] = ppm[0]; + ibuf->ppm[1] = ppm[1]; + return 0; +} + +static PyGetSetDef Py_ImBuf_getseters[] = { + {(char *)"size", (getter)py_imbuf_size_get, (setter)NULL, (char *)py_imbuf_size_doc, NULL}, + {(char *)"ppm", (getter)py_imbuf_ppm_get, (setter)py_imbuf_ppm_set, (char *)py_imbuf_ppm_doc, NULL}, + {NULL, NULL, NULL, NULL, NULL} /* Sentinel */ +}; + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Type & Implementation + * \{ */ + +static void py_imbuf_dealloc(Py_ImBuf *self) +{ + ImBuf *ibuf = self->ibuf; + if (ibuf != NULL) { + IMB_freeImBuf(self->ibuf); + self->ibuf = NULL; + } + PyObject_DEL(self); +} + +static PyObject *py_imbuf_repr(Py_ImBuf *self) +{ + const ImBuf *ibuf = self->ibuf; + if (ibuf != NULL) { + return PyUnicode_FromFormat( + "<imbuf: address=%p, filename='%s', size=(%d, %d)>", + ibuf, ibuf->name, ibuf->x, ibuf->y); + } + else { + return PyUnicode_FromString( + "<imbuf: address=0x0>"); + } +} + +static Py_hash_t py_imbuf_hash(Py_ImBuf *self) +{ + return _Py_HashPointer(self->ibuf); +} + +PyTypeObject Py_ImBuf_Type = { + PyVarObject_HEAD_INIT(NULL, 0) + /* For printing, in format "<module>.<name>" */ + "ImBuf", /* tp_name */ + sizeof(Py_ImBuf), /* int tp_basicsize; */ + 0, /* tp_itemsize; For allocation */ + + /* Methods to implement standard operations */ + + (destructor)py_imbuf_dealloc, /* destructor tp_dealloc; */ + NULL, /* printfunc tp_print; */ + NULL, /* getattrfunc tp_getattr; */ + NULL, /* setattrfunc tp_setattr; */ + NULL, /* cmpfunc tp_compare; */ + (reprfunc)py_imbuf_repr, /* reprfunc tp_repr; */ + + /* Method suites for standard classes */ + + NULL, /* PyNumberMethods *tp_as_number; */ + NULL, /* PySequenceMethods *tp_as_sequence; */ + NULL, /* PyMappingMethods *tp_as_mapping; */ + + /* More standard operations (here for binary compatibility) */ + + (hashfunc)py_imbuf_hash, /* hashfunc tp_hash; */ + NULL, /* ternaryfunc tp_call; */ + NULL, /* reprfunc tp_str; */ + NULL, /* getattrofunc tp_getattro; */ + NULL, /* setattrofunc tp_setattro; */ + + /* Functions to access object as input/output buffer */ + NULL, /* PyBufferProcs *tp_as_buffer; */ + + /*** Flags to define presence of optional/expanded features ***/ + Py_TPFLAGS_DEFAULT, /* long tp_flags; */ + + NULL, /* char *tp_doc; Documentation string */ + /*** Assigned meaning in release 2.0 ***/ + /* call function for all accessible objects */ + NULL, /* traverseproc tp_traverse; */ + + /* delete references to contained objects */ + NULL, /* inquiry tp_clear; */ + + /*** Assigned meaning in release 2.1 ***/ + /*** rich comparisons ***/ + NULL, /* richcmpfunc tp_richcompare; */ + + /*** weak reference enabler ***/ + 0, /* long tp_weaklistoffset; */ + + /*** Added in release 2.2 ***/ + /* Iterators */ + NULL, /* getiterfunc tp_iter; */ + NULL, /* iternextfunc tp_iternext; */ + /*** Attribute descriptor and subclassing stuff ***/ + Py_ImBuf_methods, /* struct PyMethodDef *tp_methods; */ + NULL, /* struct PyMemberDef *tp_members; */ + Py_ImBuf_getseters, /* struct PyGetSetDef *tp_getset; */ +}; + +static PyObject *Py_ImBuf_CreatePyObject(ImBuf *ibuf) +{ + Py_ImBuf *self = PyObject_New(Py_ImBuf, &Py_ImBuf_Type); + self->ibuf = ibuf; + return (PyObject *)self; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Module Functions + * \{ */ + +PyDoc_STRVAR(M_imbuf_new_doc, +".. function:: new(size)\n" +"\n" +" Load a new image.\n" +"\n" +" :arg size: The size of the image in pixels.\n" +" :type size: pair of ints\n" +" :return: the newly loaded image.\n" +" :rtype: :class:`ImBuf`\n" +); +static PyObject *M_imbuf_new(PyObject *UNUSED(self), PyObject *args, PyObject *kw) +{ + int size[2]; + static const char *_keywords[] = {"size", NULL}; + static _PyArg_Parser _parser = {"(ii)|i:new", _keywords, 0}; + if (!_PyArg_ParseTupleAndKeywordsFast( + args, kw, &_parser, + &size[0], &size[1])) + { + return NULL; + } + + /* TODO, make options */ + uchar planes = 4; + uint flags = IB_rect; + + ImBuf *ibuf = IMB_allocImBuf(UNPACK2(size), planes, flags); + if (ibuf == NULL) { + PyErr_Format(PyExc_ValueError, "new: Unable to create image (%d, %d)", UNPACK2(size)); + return NULL; + } + return Py_ImBuf_CreatePyObject(ibuf); +} + +PyDoc_STRVAR(M_imbuf_load_doc, +".. function:: load(filename)\n" +"\n" +" Load an image from a file.\n" +"\n" +" :arg filename: the filename of the image.\n" +" :type filename: string\n" +" :return: the newly loaded image.\n" +" :rtype: :class:`ImBuf`\n" +); +static PyObject *M_imbuf_load(PyObject *UNUSED(self), PyObject *args, PyObject *kw) +{ + const char *filename; + + static const char *_keywords[] = {"filename", NULL}; + static _PyArg_Parser _parser = {"s:load", _keywords, 0}; + if (!_PyArg_ParseTupleAndKeywordsFast( + args, kw, &_parser, + &filename)) + { + return NULL; + } + + const int file = BLI_open(filename, O_BINARY | O_RDONLY, 0); + if (file == -1) { + PyErr_Format(PyExc_IOError, "load: %s, failed to open file '%s'", strerror(errno)); + return NULL; + } + + ImBuf *ibuf = IMB_loadifffile(file, filename, IB_rect, NULL, filename); + + close(file); + + if (ibuf == NULL) { + PyErr_Format(PyExc_ValueError, "load: Unable to recognize image format for file '%s'", filename); + return NULL; + } + + BLI_strncpy(ibuf->name, filename, sizeof(ibuf->name)); + + return Py_ImBuf_CreatePyObject(ibuf); +} + +PyDoc_STRVAR(M_imbuf_write_doc, +".. function:: write(image, filename)\n" +"\n" +" Write an image.\n" +"\n" +" :arg image: the image to write.\n" +" :type image: :class:`ImBuf`\n" +" :arg filename: the filename of the image.\n" +" :type filename: string\n" +); +static PyObject *M_imbuf_write(PyObject *UNUSED(self), PyObject *args, PyObject *kw) +{ + Py_ImBuf *py_imb; + const char *filename = NULL; + + static const char *_keywords[] = {"image", "filename", NULL}; + static _PyArg_Parser _parser = {"O!|s:write", _keywords, 0}; + if (!_PyArg_ParseTupleAndKeywordsFast( + args, kw, &_parser, + &Py_ImBuf_Type, &py_imb, + &filename)) + { + return NULL; + } + + if (filename == NULL) { + filename = py_imb->ibuf->name; + } + + bool ok = IMB_saveiff(py_imb->ibuf, filename, IB_rect); + if (ok == false) { + PyErr_Format(PyExc_IOError, "write: Unable to write image file (%s) '%s'", strerror(errno), filename); + return NULL; + } + + Py_RETURN_NONE; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Module Definition + * \{ */ + +static PyMethodDef IMB_methods[] = { + {"new", (PyCFunction) M_imbuf_new, METH_VARARGS | METH_KEYWORDS, M_imbuf_new_doc}, + {"load", (PyCFunction) M_imbuf_load, METH_VARARGS | METH_KEYWORDS, M_imbuf_load_doc}, + {"write", (PyCFunction) M_imbuf_write, METH_VARARGS | METH_KEYWORDS, M_imbuf_write_doc}, + {NULL, NULL, 0, NULL} +}; + +PyDoc_STRVAR(IMB_doc, +"This module provides access to Blender's image manipulation API." +); +static struct PyModuleDef IMB_module_def = { + PyModuleDef_HEAD_INIT, + "imbuf", /* m_name */ + IMB_doc, /* m_doc */ + 0, /* m_size */ + IMB_methods, /* m_methods */ + NULL, /* m_reload */ + NULL, /* m_traverse */ + NULL, /* m_clear */ + NULL, /* m_free */ +}; + +PyObject *BPyInit_imbuf(void) +{ + PyObject *submodule; + + submodule = PyModule_Create(&IMB_module_def); + + PyType_Ready(&Py_ImBuf_Type); + + return submodule; +} + +/** \} */ diff --git a/source/blender/python/generic/imbuf_py_api.h b/source/blender/python/generic/imbuf_py_api.h new file mode 100644 index 00000000000..92c1732a9c9 --- /dev/null +++ b/source/blender/python/generic/imbuf_py_api.h @@ -0,0 +1,30 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef __IMBUF_PY_API_H__ +#define __IMBUF_PY_API_H__ + +/** \file blender/python/generic/imbuf_py_api.h + * \ingroup pygen + */ + +PyObject *BPyInit_imbuf(void); + +#endif /* __IMBUF_PY_API_H__ */ diff --git a/source/blender/python/intern/bpy_interface.c b/source/blender/python/intern/bpy_interface.c index d0678911c0e..5f51f2ac152 100644 --- a/source/blender/python/intern/bpy_interface.c +++ b/source/blender/python/intern/bpy_interface.c @@ -74,6 +74,7 @@ #include "../generic/bgl.h" #include "../generic/blf_py_api.h" #include "../generic/idprop_py_api.h" +#include "../generic/imbuf_py_api.h" #include "../gawain/gwn_py_api.h" #include "../bmesh/bmesh_py_api.h" #include "../mathutils/mathutils.h" @@ -221,6 +222,7 @@ static struct _inittab bpy_internal_modules[] = { {"_gawain", BPyInit_gawain}, {"bgl", BPyInit_bgl}, {"blf", BPyInit_blf}, + {"imbuf", BPyInit_imbuf}, {"bmesh", BPyInit_bmesh}, #if 0 {"bmesh.types", BPyInit_bmesh_types}, @@ -730,7 +732,7 @@ void BPY_modules_load_user(bContext *C) G.f |= G_SCRIPT_AUTOEXEC_FAIL; BLI_snprintf(G.autoexec_fail, sizeof(G.autoexec_fail), "Text '%s'", text->id.name + 2); - printf("scripts disabled for \"%s\", skipping '%s'\n", bmain->name, text->id.name + 2); + printf("scripts disabled for \"%s\", skipping '%s'\n", BKE_main_blendfile_path(bmain), text->id.name + 2); } } else { diff --git a/source/blender/python/intern/bpy_library_load.c b/source/blender/python/intern/bpy_library_load.c index 0ca46f9b20e..d60c44e702a 100644 --- a/source/blender/python/intern/bpy_library_load.c +++ b/source/blender/python/intern/bpy_library_load.c @@ -205,7 +205,7 @@ static PyObject *bpy_lib_load(PyObject *UNUSED(self), PyObject *args, PyObject * BLI_strncpy(ret->relpath, filename, sizeof(ret->relpath)); BLI_strncpy(ret->abspath, filename, sizeof(ret->abspath)); - BLI_path_abs(ret->abspath, bmain->name); + BLI_path_abs(ret->abspath, BKE_main_blendfile_path(bmain)); ret->blo_handle = NULL; ret->flag = ((is_link ? FILE_LINK : 0) | diff --git a/source/blender/python/intern/bpy_library_write.c b/source/blender/python/intern/bpy_library_write.c index 9ca6092eab3..ead10efb212 100644 --- a/source/blender/python/intern/bpy_library_write.c +++ b/source/blender/python/intern/bpy_library_write.c @@ -107,7 +107,7 @@ static PyObject *bpy_lib_write(PyObject *UNUSED(self), PyObject *args, PyObject } BLI_strncpy(filepath_abs, filepath, FILE_MAX); - BLI_path_abs(filepath_abs, G.main->name); + BLI_path_abs(filepath_abs, BKE_main_blendfile_path_from_global()); BKE_blendfile_write_partial_begin(bmain_src); diff --git a/source/blender/python/intern/bpy_rna_anim.c b/source/blender/python/intern/bpy_rna_anim.c index 192738535b4..7903f92265b 100644 --- a/source/blender/python/intern/bpy_rna_anim.c +++ b/source/blender/python/intern/bpy_rna_anim.c @@ -40,11 +40,12 @@ #include "ED_keyframing.h" #include "ED_keyframes_edit.h" -#include "BKE_report.h" -#include "BKE_context.h" #include "BKE_animsys.h" +#include "BKE_context.h" #include "BKE_fcurve.h" +#include "BKE_global.h" #include "BKE_idcode.h" +#include "BKE_report.h" #include "RNA_access.h" #include "RNA_enum_types.h" @@ -272,7 +273,7 @@ PyObject *pyrna_struct_keyframe_insert(BPy_StructRNA *self, PyObject *args, PyOb BKE_reports_init(&reports, RPT_STORE); - result = insert_keyframe(depsgraph, &reports, (ID *)self->ptr.id.data, NULL, group_name, path_full, index, cfra, keytype, options); + result = insert_keyframe(G.main, depsgraph, &reports, (ID *)self->ptr.id.data, NULL, group_name, path_full, index, cfra, keytype, options); MEM_freeN((void *)path_full); if (BPy_reports_to_error(&reports, PyExc_RuntimeError, true) == -1) diff --git a/source/blender/python/intern/gpu_offscreen.c b/source/blender/python/intern/gpu_offscreen.c index a8ec828c13f..a65469ea739 100644 --- a/source/blender/python/intern/gpu_offscreen.c +++ b/source/blender/python/intern/gpu_offscreen.c @@ -35,6 +35,8 @@ #include "WM_types.h" +#include "BKE_global.h" + #include "ED_screen.h" #include "GPU_framebuffer.h" diff --git a/source/blender/render/CMakeLists.txt b/source/blender/render/CMakeLists.txt index 0f0060c7578..359369228f8 100644 --- a/source/blender/render/CMakeLists.txt +++ b/source/blender/render/CMakeLists.txt @@ -24,7 +24,7 @@ # ***** END GPL LICENSE BLOCK ***** -set(INC +set(INC extern/include intern/include ../blenkernel diff --git a/source/blender/render/extern/include/RE_pipeline.h b/source/blender/render/extern/include/RE_pipeline.h index 1b0707bafc0..660e81eb022 100644 --- a/source/blender/render/extern/include/RE_pipeline.h +++ b/source/blender/render/extern/include/RE_pipeline.h @@ -103,11 +103,11 @@ typedef struct RenderPass { /* after render, the Combined pass is in combined, for renderlayers read from files it is a real pass */ typedef struct RenderLayer { struct RenderLayer *next, *prev; - + /* copy of RenderData */ char name[RE_MAXNAME]; int layflag, passflag, pass_xor; - + /* MULTIVIEW_TODO: acolrect and scolrect are not supported by multiview at the moment. * If they are really required they should be in RenderView instead */ @@ -121,16 +121,16 @@ typedef struct RenderLayer { void *exrhandle; ListBase passes; - + } RenderLayer; typedef struct RenderResult { struct RenderResult *next, *prev; - + /* target image size */ int rectx, recty; short crop, sample_nr; - + /* the following rect32, rectf and rectz buffers are for temporary storage only, for RenderResult structs * created in #RE_AcquireResultImage - which do not have RenderView */ @@ -140,25 +140,25 @@ typedef struct RenderResult { float *rectf; /* if this exists, a copy of one of layers, or result of composited layers */ float *rectz; - + /* coordinates within final image (after cropping) */ rcti tilerect; /* offset to apply to get a border render in full image */ int xof, yof; - + /* the main buffers */ ListBase layers; - + /* multiView maps to a StringVector in OpenEXR */ ListBase views; /* RenderView */ /* allowing live updates: */ volatile rcti renrect; volatile RenderLayer *renlay; - + /* optional saved endresult on disk */ int do_exr_tile; - + /* for render results in Image, verify validity for sequences */ int framenr; diff --git a/source/blender/render/intern/include/envmap.h b/source/blender/render/intern/include/envmap.h new file mode 100644 index 00000000000..c66427ae788 --- /dev/null +++ b/source/blender/render/intern/include/envmap.h @@ -0,0 +1,54 @@ +/* + * envmap_ext.h + * + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/render/intern/include/envmap.h + * \ingroup render + */ + + +#ifndef __ENVMAP_H__ +#define __ENVMAP_H__ + +/** + * Make environment maps for all objects in the scene that have an + * environment map as texture. + * (initrender.c) + */ + +struct Render; +struct TexResult; +struct ImagePool; + +void make_envmaps(struct Render *re); +int envmaptex(struct Tex *tex, const float texvec[3], float dxt[3], float dyt[3], int osatex, struct TexResult *texres, struct ImagePool *pool, const bool skip_image_load); +void env_rotate_scene(struct Render *re, float mat[4][4], int do_rotate); + +#endif /* __ENVMAP_H__ */ + diff --git a/source/blender/render/intern/include/initrender.h b/source/blender/render/intern/include/initrender.h index e7ff3c7097c..b8732e7cc5c 100644 --- a/source/blender/render/intern/include/initrender.h +++ b/source/blender/render/intern/include/initrender.h @@ -31,7 +31,7 @@ #ifndef __INITRENDER_H__ -#define __INITRENDER_H__ +#define __INITRENDER_H__ /* Functions */ diff --git a/source/blender/render/intern/include/pixelblending.h b/source/blender/render/intern/include/pixelblending.h new file mode 100644 index 00000000000..022510c7132 --- /dev/null +++ b/source/blender/render/intern/include/pixelblending.h @@ -0,0 +1,65 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * Contributor(s): 2004-2006 Blender Foundation, full recode + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/** \file blender/render/intern/include/pixelblending.h + * \ingroup render + */ + + +#ifndef __PIXELBLENDING_H__ +#define __PIXELBLENDING_H__ + + +/** + * add 1 pixel to into filtered three lines + * (float vecs to float vec) + */ +void add_filt_fmask(unsigned int mask, const float col[4], float *rowbuf, int row_w); +void add_filt_fmask_pixsize(unsigned int mask, float *in, float *rowbuf, int row_w, int pixsize); +void add_filt_fmask_coord(float filt[3][3], const float col[4], float *rowbuf, int row_stride, int x, int y, rcti *mask); +void mask_array(unsigned int mask, float filt[3][3]); + +/** + * Alpha-over blending for floats. + */ +void addAlphaOverFloat(float dest[4], const float source[4]); + +/** + * Alpha-under blending for floats. + */ +void addAlphaUnderFloat(float dest[4], const float source[4]); + + +/** + * Same for floats + */ +void addalphaAddfacFloat(float dest[4], const float source[4], char addfac); + +/** + * dest = dest + source + */ +void addalphaAddFloat(float dest[4], const float source[4]); + +#endif /* __PIXELBLENDING_H__ */ diff --git a/source/blender/render/intern/include/pixelshading.h b/source/blender/render/intern/include/pixelshading.h new file mode 100644 index 00000000000..0e630eda475 --- /dev/null +++ b/source/blender/render/intern/include/pixelshading.h @@ -0,0 +1,62 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * Contributor(s): 2004-2006, Blender Foundation, full recode + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/render/intern/include/pixelshading.h + * \ingroup render + * + * These functions determine what actual color a pixel will have. + */ + +#ifndef __PIXELSHADING_H__ +#define __PIXELSHADING_H__ + + +/** + * Render the pixel at (x,y) for object ap. Apply the jitter mask. + * Output is given in float collector[4]. The type vector: + * t[0] - min. distance + * t[1] - face/halo index + * t[2] - jitter mask + * t[3] - type ZB_POLY or ZB_HALO + * t[4] - max. distance + * mask is pixel coverage in bits + * \return pointer to the object + */ +int shadeHaloFloat(HaloRen *har, + float *col, int zz, + float dist, float xn, + float yn, short flarec); + +/** + * Render the sky at pixel (x, y). + */ +void shadeSkyPixel(float collector[4], float fx, float fy, short thread); +void shadeSkyView(float col_r[3], const float rco[3], const float view[3], const float dxyview[2], short thread); +void shadeAtmPixel(struct SunSky *sunsky, float *collector, float fx, float fy, float distance); +void shadeSunView(float col_r[3], const float view[3]); +/* ------------------------------------------------------------------------- */ + +#endif + diff --git a/source/blender/render/intern/include/pointdensity.h b/source/blender/render/intern/include/pointdensity.h new file mode 100644 index 00000000000..eadf714c1ba --- /dev/null +++ b/source/blender/render/intern/include/pointdensity.h @@ -0,0 +1,51 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Matt Ebb + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/render/intern/include/pointdensity.h + * \ingroup render + */ + + +#ifndef __POINTDENSITY_H__ +#define __POINTDENSITY_H__ + +/** + * Make point density kd-trees for all point density textures in the scene + */ + +struct PointDensity; +struct Render; +struct TexResult; + +void free_pointdensity(struct PointDensity *pd); +void cache_pointdensity(struct Render *re, struct PointDensity *pd); +void make_pointdensities(struct Render *re); +void free_pointdensities(struct Render *re); +int pointdensitytex(struct Tex *tex, const float texvec[3], struct TexResult *texres); + +#endif /* __POINTDENSITY_H__ */ + diff --git a/source/blender/render/intern/include/raycounter.h b/source/blender/render/intern/include/raycounter.h new file mode 100644 index 00000000000..e16c6e13c7e --- /dev/null +++ b/source/blender/render/intern/include/raycounter.h @@ -0,0 +1,74 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2009 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): André Pinto. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/render/intern/include/raycounter.h + * \ingroup render + */ + + +#ifndef __RAYCOUNTER_H__ +#define __RAYCOUNTER_H__ + +//#define RE_RAYCOUNTER /* enable counters per ray, useful for measuring raytrace structures performance */ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef RE_RAYCOUNTER + +/* ray counter functions */ + +typedef struct RayCounter { + struct { + unsigned long long test, hit; + } faces, bb, simd_bb, raycast, raytrace_hint, rayshadow_last_hit; +} RayCounter; + +#define RE_RC_INIT(isec, shi) (isec).raycounter = &((shi).shading.raycounter) +void RE_RC_INFO(RayCounter *rc); +void RE_RC_MERGE(RayCounter *rc, RayCounter *tmp); +#define RE_RC_COUNT(var) (var)++ + +extern RayCounter re_rc_counter[]; + +#else + +/* ray counter stubs */ + +#define RE_RC_INIT(isec,shi) +#define RE_RC_INFO(rc) +#define RE_RC_MERGE(dest,src) +#define RE_RC_COUNT(var) + +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/source/blender/render/intern/include/rayintersection.h b/source/blender/render/intern/include/rayintersection.h new file mode 100644 index 00000000000..a303301ad3b --- /dev/null +++ b/source/blender/render/intern/include/rayintersection.h @@ -0,0 +1,136 @@ +/* + * ***** 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) 2007 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): André Pinto. + * + * ***** END GPL LICENSE BLOCK ***** + * RE_raytrace.h: ray tracing api, can be used independently from the renderer. + */ + +/** \file blender/render/intern/include/rayintersection.h + * \ingroup render + */ + + +#ifndef __RAYINTERSECTION_H__ +#define __RAYINTERSECTION_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "BLI_math_geom.h" + +struct RayObject; + +/* Ray Hints */ + +#define RE_RAY_LCTS_MAX_SIZE 256 +#define RT_USE_LAST_HIT /* last shadow hit is reused before raycasting on whole tree */ +//#define RT_USE_HINT /* last hit object is reused before raycasting on whole tree */ + +typedef struct LCTSHint { + int size; + struct RayObject *stack[RE_RAY_LCTS_MAX_SIZE]; +} LCTSHint; + +typedef struct RayHint { + union { LCTSHint lcts; } data; +} RayHint; + +/* Ray Intersection */ + +typedef struct Isect { + /* ray start, direction (normalized vector), and max distance. on hit, + * the distance is modified to be the distance to the hit point. */ + float start[3]; + float dir[3]; + float dist; + + /* for envmap and incremental view update renders */ + float origstart[3]; + float origdir[3]; + + /* precomputed values to accelerate bounding box intersection */ + int bv_index[6]; + float idot_axis[3]; + + /* intersection options */ + int mode; /* RE_RAY_SHADOW, RE_RAY_MIRROR, RE_RAY_SHADOW_TRA */ + int lay; /* -1 default, set for layer lamps */ + int skip; /* skip flags */ + int check; /* check flags */ + void *userdata; /* used by bake check */ + + /* hit information */ + float u, v; + int isect; /* which half of quad */ + + struct { + void *ob; + void *face; + } hit, orig; + + /* last hit optimization */ + struct RayObject *last_hit; + + /* hints */ +#ifdef RT_USE_HINT + RayTraceHint *hint, *hit_hint; +#endif + RayHint *hint; + + /* ray counter */ +#ifdef RE_RAYCOUNTER + RayCounter *raycounter; +#endif + + /* Precalculated coefficients for watertight intersection check. */ + struct IsectRayPrecalc isect_precalc; +} Isect; + +/* ray types */ +#define RE_RAY_SHADOW 0 +#define RE_RAY_MIRROR 1 +#define RE_RAY_SHADOW_TRA 2 + +/* skip options */ +#define RE_SKIP_CULLFACE (1 << 0) +/* if using this flag then *face should be a pointer to a VlakRen */ +#define RE_SKIP_VLR_NEIGHBOUR (1 << 1) + +/* check options */ +#define RE_CHECK_VLR_NONE 0 +#define RE_CHECK_VLR_RENDER 1 +#define RE_CHECK_VLR_NON_SOLID_MATERIAL 2 +#define RE_CHECK_VLR_BAKE 3 + +/* arbitrary, but can't use e.g. FLT_MAX because of precision issues */ +#define RE_RAYTRACE_MAXDIST 1e15f +#define RE_RAYTRACE_EPSILON 0.0f + +#ifdef __cplusplus +} +#endif + +#endif /* __RAYINTERSECTION_H__ */ + diff --git a/source/blender/render/intern/include/render_types.h b/source/blender/render/intern/include/render_types.h index 8308b5e76e4..fd24f4eb053 100644 --- a/source/blender/render/intern/include/render_types.h +++ b/source/blender/render/intern/include/render_types.h @@ -52,10 +52,10 @@ struct Main; /* this is handed over to threaded hiding/passes/shading engine */ typedef struct RenderPart { struct RenderPart *next, *prev; - + RenderResult *result; /* result of part rendering */ ListBase fullresult; /* optional full sample buffers */ - + rcti disprect; /* part coordinates within total picture */ int rectx, recty; /* the size */ int nr; /* nr is partnr */ @@ -74,10 +74,10 @@ struct Render { struct Render *next, *prev; char name[RE_MAXNAME]; int slot; - + /* state settings */ short flag, ok, result_ok; - + /* result of rendering */ RenderResult *result; /* if render with single-layer option, other rendered layers are stored here */ @@ -88,29 +88,29 @@ struct Render { * write lock, all external code must use a read lock. internal code is assumed * to not conflict with writes, so no lock used for that */ ThreadRWMutex resultmutex; - + /* window size, display rect, viewplane */ int winx, winy; /* buffer width and height with percentage applied * without border & crop. convert to long before multiplying together to avoid overflow. */ rcti disprect; /* part within winx winy */ rctf viewplane; /* mapped on winx winy */ - + /* final picture width and height (within disprect) */ int rectx, recty; - - /* real maximum size of parts after correction for minimum + + /* real maximum size of parts after correction for minimum * partx*xparts can be larger than rectx, in that case last part is smaller */ int partx, party; - + /* Camera transform, only used by Freestyle. */ float viewmat[4][4], viewinv[4][4]; float viewmat_orig[4][4]; /* for incremental render */ float winmat[4][4]; - + /* clippping */ float clipsta; float clipend; - + /* main, scene, and its full copy of renderdata and world */ struct Main *main; Scene *scene; @@ -119,13 +119,13 @@ struct Render { int active_view_layer; struct Object *camera_override; unsigned int lay, layer_override; - + ThreadRWMutex partsmutex; ListBase parts; - + /* render engine */ struct RenderEngine *engine; - + #ifdef WITH_FREESTYLE struct Main *freestyle_bmain; ListBase freestyle_renders; @@ -140,17 +140,17 @@ struct Render { void *duh; void (*current_scene_update)(void *handle, struct Scene *scene); void *suh; - + void (*stats_draw)(void *handle, RenderStats *ri); void *sdh; void (*progress)(void *handle, float i); void *prh; - + void (*draw_lock)(void *handle, int i); void *dlh; int (*test_break)(void *handle); void *tbh; - + RenderStats i; struct ReportList *reports; diff --git a/source/blender/render/intern/include/rendercore.h b/source/blender/render/intern/include/rendercore.h new file mode 100644 index 00000000000..aa3efca9e5b --- /dev/null +++ b/source/blender/render/intern/include/rendercore.h @@ -0,0 +1,105 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef __RENDERCORE_H__ +#define __RENDERCORE_H__ + +/** \file blender/render/intern/include/rendercore.h + * \ingroup render + */ + +#include "render_types.h" + +#include "RE_engine.h" + +#include "DNA_node_types.h" + +#include "NOD_composite.h" + +struct ShadeInput; +struct ShadeResult; +struct World; +struct RenderPart; +struct RenderLayer; +struct RayObject; + +/* ------------------------------------------------------------------------- */ + +typedef struct PixStr { + struct PixStr *next; + int obi, facenr, z, maskz; + unsigned short mask; + short shadfac; +} PixStr; + +typedef struct PixStrMain { + struct PixStrMain *next, *prev; + struct PixStr *ps; + int counter; +} PixStrMain; + +/* ------------------------------------------------------------------------- */ + + +void calc_view_vector(float view[3], float x, float y); +float mistfactor(float zcor, const float co[3]); /* dist and height, return alpha */ + +void renderspothalo(struct ShadeInput *shi, float col[4], float alpha); +void add_halo_flare(Render *re); + +void calc_renderco_zbuf(float co[3], const float view[3], int z); +void calc_renderco_ortho(float co[3], float x, float y, int z); + +int count_mask(unsigned short mask); + +void zbufshade_tile(struct RenderPart *pa); +void zbufshadeDA_tile(struct RenderPart *pa); + +void zbufshade_sss_tile(struct RenderPart *pa); + +int get_sample_layers(struct RenderPart *pa, struct RenderLayer *rl, struct RenderLayer **rlpp); + +void render_internal_update_passes(struct RenderEngine *engine, struct Scene *scene, struct SceneRenderLayer *srl); + + +/* -------- ray.c ------- */ + +struct RayObject *RE_rayobject_create(int type, int size, int octree_resolution); + +extern void freeraytree(Render *re); +extern void makeraytree(Render *re); +struct RayObject* makeraytree_object(Render *re, ObjectInstanceRen *obi); + +extern void ray_shadow(ShadeInput *shi, LampRen *lar, float shadfac[4]); +extern void ray_trace(ShadeInput *shi, ShadeResult *); +extern void ray_ao(ShadeInput *shi, float ao[3], float env[3]); +extern void init_jitter_plane(LampRen *lar); +extern void init_ao_sphere(Render *re, struct World *wrld); +extern void init_render_qmcsampler(Render *re); +extern void free_render_qmcsampler(Render *re); + +#endif /* __RENDERCORE_H__ */ diff --git a/source/blender/render/intern/include/shading.h b/source/blender/render/intern/include/shading.h new file mode 100644 index 00000000000..e306c3c075c --- /dev/null +++ b/source/blender/render/intern/include/shading.h @@ -0,0 +1,105 @@ +/* + * ***** 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) 2006 Blender Foundation + * All rights reserved. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/render/intern/include/shading.h + * \ingroup render + */ + + +struct ShadeInput; +struct ShadeResult; +struct RenderPart; +struct RenderLayer; +struct PixStr; +struct LampRen; +struct VlakRen; +struct StrandPoint; +struct ObjectInstanceRen; +struct Isect; + +/* shadeinput.c */ + +#define RE_MAX_OSA 16 + +/* needed to calculate shadow and AO for an entire pixel */ +typedef struct ShadeSample { + int tot; /* amount of shi in use, can be 1 for not FULL_OSA */ + + RenderLayer *rlpp[RE_MAX_OSA]; /* fast lookup from sample to renderlayer (fullsample buf) */ + + /* could be malloced once */ + ShadeInput shi[RE_MAX_OSA]; + ShadeResult shr[RE_MAX_OSA]; +} ShadeSample; + + + /* also the node shader callback */ +void shade_material_loop(struct ShadeInput *shi, struct ShadeResult *shr); + +void shade_input_set_triangle_i(struct ShadeInput *shi, struct ObjectInstanceRen *obi, struct VlakRen *vlr, short i1, short i2, short i3); +void shade_input_set_triangle(struct ShadeInput *shi, int obi, int facenr, int normal_flip); +void shade_input_copy_triangle(struct ShadeInput *shi, struct ShadeInput *from); +void shade_input_calc_viewco(struct ShadeInput *shi, float x, float y, float z, float view[3], float dxyview[2], float co[3], float dxco[3], float dyco[3]); +void shade_input_set_viewco(struct ShadeInput *shi, float x, float y, float sx, float sy, float z); +void shade_input_set_uv(struct ShadeInput *shi); +void shade_input_set_normals(struct ShadeInput *shi); +void shade_input_set_vertex_normals(struct ShadeInput *shi); +void shade_input_flip_normals(struct ShadeInput *shi); +void shade_input_set_shade_texco(struct ShadeInput *shi); +void shade_input_set_strand(struct ShadeInput *shi, struct StrandRen *strand, struct StrandPoint *spoint); +void shade_input_set_strand_texco(struct ShadeInput *shi, struct StrandRen *strand, struct StrandVert *svert, struct StrandPoint *spoint); +void shade_input_do_shade(struct ShadeInput *shi, struct ShadeResult *shr); + +void shade_input_init_material(struct ShadeInput *shi); +void shade_input_initialize(struct ShadeInput *shi, struct RenderPart *pa, struct RenderLayer *rl, int sample); + +void shade_sample_initialize(struct ShadeSample *ssamp, struct RenderPart *pa, struct RenderLayer *rl); +void shade_samples_do_AO(struct ShadeSample *ssamp); +void shade_samples_fill_with_ps(struct ShadeSample *ssamp, struct PixStr *ps, int x, int y); +int shade_samples(struct ShadeSample *ssamp, struct PixStr *ps, int x, int y); + +void vlr_set_uv_indices(struct VlakRen *vlr, int *i1, int *i2, int *i3); + +void calc_R_ref(struct ShadeInput *shi); + +void barycentric_differentials_from_position( + const float co[3], const float v1[3], const float v2[3], const float v3[3], + const float dxco[3], const float dyco[3], const float facenor[3], const bool differentials, + float *u, float *v, float *dx_u, float *dx_v, float *dy_u, float *dy_v); + +/* shadeoutput. */ +void shade_lamp_loop(struct ShadeInput *shi, struct ShadeResult *shr); + +void shade_color(struct ShadeInput *shi, ShadeResult *shr); + +void ambient_occlusion(struct ShadeInput *shi); +void environment_lighting_apply(struct ShadeInput *shi, struct ShadeResult *shr); + +ListBase *get_lights(struct ShadeInput *shi); +float lamp_get_visibility(struct LampRen *lar, const float co[3], float lv[3], float *dist); +void lamp_get_shadow(struct LampRen *lar, ShadeInput *shi, float inp, float shadfac[4], int do_real); + +float fresnel_fac(const float view[3], const float vn[3], float fresnel, float fac); + +/* rayshade.c */ +extern void shade_ray(struct Isect *is, struct ShadeInput *shi, struct ShadeResult *shr); diff --git a/source/blender/render/intern/include/strand.h b/source/blender/render/intern/include/strand.h new file mode 100644 index 00000000000..f4e22c78b42 --- /dev/null +++ b/source/blender/render/intern/include/strand.h @@ -0,0 +1,99 @@ +/* + * ***** 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. + * + * Contributor(s): Brecht Van Lommel. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/render/intern/include/strand.h + * \ingroup render + */ + + +#ifndef __STRAND_H__ +#define __STRAND_H__ + +struct StrandVert; +struct StrandRen; +struct StrandBuffer; +struct ShadeSample; +struct StrandPart; +struct Render; +struct ZSpan; +struct ObjectInstanceRen; +struct StrandSurface; +struct DerivedMesh; +struct ObjectRen; + +typedef struct StrandPoint { + /* position within segment */ + float t; + + /* camera space */ + float co[3]; + float nor[3]; + float tan[3]; + float strandco; + float width; + + /* derivatives */ + float dtco[3], dsco[3]; + float dtstrandco; + + /* outer points */ + float co1[3], co2[3]; + float hoco1[4], hoco2[4]; + float zco1[3], zco2[3]; + int clip1, clip2; + + /* screen space */ + float hoco[4]; + float x, y; + + /* simplification */ + float alpha; +} StrandPoint; + +typedef struct StrandSegment { + struct StrandVert *v[4]; + struct StrandRen *strand; + struct StrandBuffer *buffer; + struct ObjectInstanceRen *obi; + float sqadaptcos; + + StrandPoint point1, point2; + int shaded; +} StrandSegment; + +struct StrandShadeCache; +typedef struct StrandShadeCache StrandShadeCache; + +void strand_eval_point(StrandSegment *sseg, StrandPoint *spoint); +void render_strand_segment(struct Render *re, float winmat[4][4], struct StrandPart *spart, struct ZSpan *zspan, int totzspan, StrandSegment *sseg); +void strand_minmax(struct StrandRen *strand, float min[3], float max[3], const float width); + +struct StrandSurface *cache_strand_surface(struct Render *re, struct ObjectRen *obr, struct DerivedMesh *dm, float mat[4][4], int timeoffset); +void free_strand_surface(struct Render *re); + +struct StrandShadeCache *strand_shade_cache_create(void); +void strand_shade_cache_free(struct StrandShadeCache *cache); +void strand_shade_segment(struct Render *re, struct StrandShadeCache *cache, struct StrandSegment *sseg, struct ShadeSample *ssamp, float t, float s, int addpassflag); +void strand_shade_unref(struct StrandShadeCache *cache, struct ObjectInstanceRen *obi, struct StrandVert *svert); + +#endif + diff --git a/source/blender/render/intern/include/sunsky.h b/source/blender/render/intern/include/sunsky.h new file mode 100644 index 00000000000..c608f9fc48c --- /dev/null +++ b/source/blender/render/intern/include/sunsky.h @@ -0,0 +1,81 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): zaghaghi + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/render/intern/include/sunsky.h + * \ingroup render + */ + +#ifndef __SUNSKY_H__ +#define __SUNSKY_H__ + +// #define SPECTRUM_MAX_COMPONENTS 100 + +typedef struct SunSky { + short effect_type, skyblendtype, sky_colorspace; + float turbidity; + float theta, phi; + + float toSun[3]; + + /*float sunSpectralRaddata[SPECTRUM_MAX_COMPONENTS];*/ + float sunSolidAngle; + + float zenith_Y, zenith_x, zenith_y; + + float perez_Y[5], perez_x[5], perez_y[5]; + + /* suggested by glome in patch [#8063] */ + float horizon_brightness; + float spread; + float sun_brightness; + float sun_size; + float backscattered_light; + float skyblendfac; + float sky_exposure; + + float atm_HGg; + + float atm_SunIntensity; + float atm_InscatteringMultiplier; + float atm_ExtinctionMultiplier; + float atm_BetaRayMultiplier; + float atm_BetaMieMultiplier; + float atm_DistanceMultiplier; + + float atm_BetaRay[3]; + float atm_BetaDashRay[3]; + float atm_BetaMie[3]; + float atm_BetaDashMie[3]; + float atm_BetaRM[3]; +} SunSky; + +void InitSunSky(struct SunSky *sunsky, float turb, const float toSun[3], float horizon_brightness, + float spread, float sun_brightness, float sun_size, float back_scatter, + float skyblendfac, short skyblendtype, float sky_exposure, float sky_colorspace); + +void GetSkyXYZRadiance(struct SunSky *sunsky, float theta, float phi, float color_out[3]); +void GetSkyXYZRadiancef(struct SunSky *sunsky, const float varg[3], float color_out[3]); +void InitAtmosphere(struct SunSky *sunSky, float sun_intens, float mief, float rayf, float inscattf, float extincf, float disf); +void AtmospherePixleShader(struct SunSky *sunSky, float view[3], float s, float rgb[3]); +void ClipColor(float c[3]); + +#endif /*__SUNSKY_H__*/ diff --git a/source/blender/render/intern/include/texture_ocean.h b/source/blender/render/intern/include/texture_ocean.h new file mode 100644 index 00000000000..6d7bc6fe7b0 --- /dev/null +++ b/source/blender/render/intern/include/texture_ocean.h @@ -0,0 +1,35 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * Contributors: Matt Ebb + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef __TEXTURE_OCEAN_H__ +#define __TEXTURE_OCEAN_H__ + +/** \file blender/render/intern/include/texture_ocean.h + * \ingroup render + */ + +int ocean_texture(struct Tex *tex, const float texvec[2], struct TexResult *texres); + +#endif /* __TEXTURE_OCEAN_H__ */ diff --git a/source/blender/render/intern/include/voxeldata.h b/source/blender/render/intern/include/voxeldata.h new file mode 100644 index 00000000000..041ca78a799 --- /dev/null +++ b/source/blender/render/intern/include/voxeldata.h @@ -0,0 +1,47 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Raul Fernandez Hernandez (Farsthary), Matt Ebb. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/render/intern/include/voxeldata.h + * \ingroup render + */ + +#ifndef __VOXELDATA_H__ +#define __VOXELDATA_H__ + +struct Render; +struct TexResult; + +typedef struct VoxelDataHeader { + int resolX, resolY, resolZ; + int frames; +} VoxelDataHeader; + +void cache_voxeldata(Tex *tex, int scene_frame); +void make_voxeldata(struct Render *re); +int voxeldatatex(struct Tex *tex, const float texvec[3], struct TexResult *texres); + +#endif /* __VOXELDATA_H__ */ diff --git a/source/blender/render/intern/include/zbuf.h b/source/blender/render/intern/include/zbuf.h index 3dfcbc355c4..0654a4f8df6 100644 --- a/source/blender/render/intern/include/zbuf.h +++ b/source/blender/render/intern/include/zbuf.h @@ -36,7 +36,7 @@ /* span fill in method, is also used to localize data for zbuffering */ typedef struct ZSpan { int rectx, recty; /* range for clipping */ - + int miny1, maxy1, miny2, maxy2; /* actual filled in range */ const float *minp1, *maxp1, *minp2, *maxp2; /* vertex pointers detect min/max range in */ float *span1, *span2; diff --git a/source/blender/render/intern/raytrace/bvh.h b/source/blender/render/intern/raytrace/bvh.h new file mode 100644 index 00000000000..0f9a506762b --- /dev/null +++ b/source/blender/render/intern/raytrace/bvh.h @@ -0,0 +1,407 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2009 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): André Pinto. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/render/intern/raytrace/bvh.h + * \ingroup render + */ + + +#include "MEM_guardedalloc.h" + +#include "BLI_math.h" + +#include "raycounter.h" +#include "rayintersection.h" +#include "rayobject.h" +#include "rayobject_hint.h" +#include "rayobject_rtbuild.h" + +#include <assert.h> + +#ifdef __SSE__ +#include <xmmintrin.h> +#endif + +#ifndef __BVH_H__ +#define __BVH_H__ + +#ifdef __SSE__ +inline int test_bb_group4(__m128 *bb_group, const Isect *isec) +{ + const __m128 tmin0 = _mm_setzero_ps(); + const __m128 tmax0 = _mm_set_ps1(isec->dist); + + float start[3], idot_axis[3]; + copy_v3_v3(start, isec->start); + copy_v3_v3(idot_axis, isec->idot_axis); + + const __m128 tmin1 = _mm_max_ps(tmin0, _mm_mul_ps(_mm_sub_ps(bb_group[isec->bv_index[0]], _mm_set_ps1(start[0]) ), _mm_set_ps1(idot_axis[0])) ); + const __m128 tmax1 = _mm_min_ps(tmax0, _mm_mul_ps(_mm_sub_ps(bb_group[isec->bv_index[1]], _mm_set_ps1(start[0]) ), _mm_set_ps1(idot_axis[0])) ); + const __m128 tmin2 = _mm_max_ps(tmin1, _mm_mul_ps(_mm_sub_ps(bb_group[isec->bv_index[2]], _mm_set_ps1(start[1]) ), _mm_set_ps1(idot_axis[1])) ); + const __m128 tmax2 = _mm_min_ps(tmax1, _mm_mul_ps(_mm_sub_ps(bb_group[isec->bv_index[3]], _mm_set_ps1(start[1]) ), _mm_set_ps1(idot_axis[1])) ); + const __m128 tmin3 = _mm_max_ps(tmin2, _mm_mul_ps(_mm_sub_ps(bb_group[isec->bv_index[4]], _mm_set_ps1(start[2]) ), _mm_set_ps1(idot_axis[2])) ); + const __m128 tmax3 = _mm_min_ps(tmax2, _mm_mul_ps(_mm_sub_ps(bb_group[isec->bv_index[5]], _mm_set_ps1(start[2]) ), _mm_set_ps1(idot_axis[2])) ); + + return _mm_movemask_ps(_mm_cmpge_ps(tmax3, tmin3)); +} +#endif + +/* + * Determines the distance that the ray must travel to hit the bounding volume of the given node + * Based on Tactical Optimization of Ray/Box Intersection, by Graham Fyffe + * [http://tog.acm.org/resources/RTNews/html/rtnv21n1.html#art9] + */ +static inline int rayobject_bb_intersect_test(const Isect *isec, const float *_bb) +{ + const float *bb = _bb; + + float t1x = (bb[isec->bv_index[0]] - isec->start[0]) * isec->idot_axis[0]; + float t2x = (bb[isec->bv_index[1]] - isec->start[0]) * isec->idot_axis[0]; + float t1y = (bb[isec->bv_index[2]] - isec->start[1]) * isec->idot_axis[1]; + float t2y = (bb[isec->bv_index[3]] - isec->start[1]) * isec->idot_axis[1]; + float t1z = (bb[isec->bv_index[4]] - isec->start[2]) * isec->idot_axis[2]; + float t2z = (bb[isec->bv_index[5]] - isec->start[2]) * isec->idot_axis[2]; + + RE_RC_COUNT(isec->raycounter->bb.test); + + if (t1x > t2y || t2x < t1y || t1x > t2z || t2x < t1z || t1y > t2z || t2y < t1z) return 0; + if (t2x < 0.0f || t2y < 0.0f || t2z < 0.0f) return 0; + if (t1x > isec->dist || t1y > isec->dist || t1z > isec->dist) return 0; + RE_RC_COUNT(isec->raycounter->bb.hit); + + return 1; +} + +/* bvh tree generics */ +template<class Tree> static void bvh_add(Tree *obj, RayObject *ob) +{ + rtbuild_add(obj->builder, ob); +} + +template<class Node> +inline bool is_leaf(Node *node) +{ + return !RE_rayobject_isAligned(node); +} + +template<class Tree> static void bvh_done(Tree *obj); + +template<class Tree> +static void bvh_free(Tree *obj) +{ + if (obj->builder) + rtbuild_free(obj->builder); + + if (obj->node_arena) + BLI_memarena_free(obj->node_arena); + + MEM_freeN(obj); +} + +template<class Tree> +static void bvh_bb(Tree *obj, float *min, float *max) +{ + if (obj->root) + bvh_node_merge_bb(obj->root, min, max); +} + + +template<class Tree> +static float bvh_cost(Tree *obj) +{ + assert(obj->cost >= 0.0f); + return obj->cost; +} + + + +/* bvh tree nodes generics */ +template<class Node> static inline int bvh_node_hit_test(Node *node, Isect *isec) +{ + return rayobject_bb_intersect_test(isec, (const float *)node->bb); +} + + +template<class Node> +static inline void bvh_node_merge_bb(Node *node, float min[3], float max[3]) +{ + if (is_leaf(node)) { + RE_rayobject_merge_bb((RayObject *)node, min, max); + } + else { + DO_MIN(node->bb, min); + DO_MAX(node->bb + 3, max); + } +} + + + +/* + * recursively transverse a BVH looking for a rayhit using a local stack + */ +template<class Node> static inline void bvh_node_push_childs(Node *node, Isect *isec, Node **stack, int &stack_pos); + +template<class Node, int MAX_STACK_SIZE, bool TEST_ROOT, bool SHADOW> +static int bvh_node_stack_raycast(Node *root, Isect *isec) +{ + Node *stack[MAX_STACK_SIZE]; + int hit = 0, stack_pos = 0; + + if (!TEST_ROOT && !is_leaf(root)) + bvh_node_push_childs(root, isec, stack, stack_pos); + else + stack[stack_pos++] = root; + + while (stack_pos) { + Node *node = stack[--stack_pos]; + if (!is_leaf(node)) { + if (bvh_node_hit_test(node, isec)) { + bvh_node_push_childs(node, isec, stack, stack_pos); + assert(stack_pos <= MAX_STACK_SIZE); + } + } + else { + hit |= RE_rayobject_intersect( (RayObject *)node, isec); + if (SHADOW && hit) return hit; + } + } + return hit; +} + + +#ifdef __SSE__ +/* + * Generic SIMD bvh recursion + * this was created to be able to use any simd (with the cost of some memmoves) + * it can take advantage of any SIMD width and doens't needs any special tree care + */ +template<class Node, int MAX_STACK_SIZE, bool TEST_ROOT> +static int bvh_node_stack_raycast_simd(Node *root, Isect *isec) +{ + Node *stack[MAX_STACK_SIZE]; + + int hit = 0, stack_pos = 0; + + if (!TEST_ROOT) { + if (!is_leaf(root)) { + if (!is_leaf(root->child)) + bvh_node_push_childs(root, isec, stack, stack_pos); + else + return RE_rayobject_intersect( (RayObject *)root->child, isec); + } + else + return RE_rayobject_intersect( (RayObject *)root, isec); + } + else { + if (!is_leaf(root)) + stack[stack_pos++] = root; + else + return RE_rayobject_intersect( (RayObject *)root, isec); + } + + while (true) { + //Use SIMD 4 + if (stack_pos >= 4) { + __m128 t_bb[6]; + Node *t_node[4]; + + stack_pos -= 4; + + /* prepare the 4BB for SIMD */ + t_node[0] = stack[stack_pos + 0]->child; + t_node[1] = stack[stack_pos + 1]->child; + t_node[2] = stack[stack_pos + 2]->child; + t_node[3] = stack[stack_pos + 3]->child; + + const float *bb0 = stack[stack_pos + 0]->bb; + const float *bb1 = stack[stack_pos + 1]->bb; + const float *bb2 = stack[stack_pos + 2]->bb; + const float *bb3 = stack[stack_pos + 3]->bb; + + const __m128 x0y0x1y1 = _mm_shuffle_ps(_mm_load_ps(bb0), _mm_load_ps(bb1), _MM_SHUFFLE(1, 0, 1, 0) ); + const __m128 x2y2x3y3 = _mm_shuffle_ps(_mm_load_ps(bb2), _mm_load_ps(bb3), _MM_SHUFFLE(1, 0, 1, 0) ); + t_bb[0] = _mm_shuffle_ps(x0y0x1y1, x2y2x3y3, _MM_SHUFFLE(2, 0, 2, 0) ); + t_bb[1] = _mm_shuffle_ps(x0y0x1y1, x2y2x3y3, _MM_SHUFFLE(3, 1, 3, 1) ); + + const __m128 z0X0z1X1 = _mm_shuffle_ps(_mm_load_ps(bb0), _mm_load_ps(bb1), _MM_SHUFFLE(3, 2, 3, 2) ); + const __m128 z2X2z3X3 = _mm_shuffle_ps(_mm_load_ps(bb2), _mm_load_ps(bb3), _MM_SHUFFLE(3, 2, 3, 2) ); + t_bb[2] = _mm_shuffle_ps(z0X0z1X1, z2X2z3X3, _MM_SHUFFLE(2, 0, 2, 0) ); + t_bb[3] = _mm_shuffle_ps(z0X0z1X1, z2X2z3X3, _MM_SHUFFLE(3, 1, 3, 1) ); + + const __m128 Y0Z0Y1Z1 = _mm_shuffle_ps(_mm_load_ps(bb0 + 4), _mm_load_ps(bb1 + 4), _MM_SHUFFLE(1, 0, 1, 0) ); + const __m128 Y2Z2Y3Z3 = _mm_shuffle_ps(_mm_load_ps(bb2 + 4), _mm_load_ps(bb3 + 4), _MM_SHUFFLE(1, 0, 1, 0) ); + t_bb[4] = _mm_shuffle_ps(Y0Z0Y1Z1, Y2Z2Y3Z3, _MM_SHUFFLE(2, 0, 2, 0) ); + t_bb[5] = _mm_shuffle_ps(Y0Z0Y1Z1, Y2Z2Y3Z3, _MM_SHUFFLE(3, 1, 3, 1) ); +#if 0 + for (int i = 0; i < 4; i++) + { + Node *t = stack[stack_pos + i]; + assert(!is_leaf(t)); + + float *bb = ((float *)t_bb) + i; + bb[4 * 0] = t->bb[0]; + bb[4 * 1] = t->bb[1]; + bb[4 * 2] = t->bb[2]; + bb[4 * 3] = t->bb[3]; + bb[4 * 4] = t->bb[4]; + bb[4 * 5] = t->bb[5]; + t_node[i] = t->child; + } +#endif + RE_RC_COUNT(isec->raycounter->simd_bb.test); + int res = test_bb_group4(t_bb, isec); + + for (int i = 0; i < 4; i++) + if (res & (1 << i)) { + RE_RC_COUNT(isec->raycounter->simd_bb.hit); + if (!is_leaf(t_node[i])) { + for (Node *t = t_node[i]; t; t = t->sibling) { + assert(stack_pos < MAX_STACK_SIZE); + stack[stack_pos++] = t; + } + } + else { + hit |= RE_rayobject_intersect( (RayObject *)t_node[i], isec); + if (hit && isec->mode == RE_RAY_SHADOW) return hit; + } + } + } + else if (stack_pos > 0) { + Node *node = stack[--stack_pos]; + assert(!is_leaf(node)); + + if (bvh_node_hit_test(node, isec)) { + if (!is_leaf(node->child)) { + bvh_node_push_childs(node, isec, stack, stack_pos); + assert(stack_pos <= MAX_STACK_SIZE); + } + else { + hit |= RE_rayobject_intersect( (RayObject *)node->child, isec); + if (hit && isec->mode == RE_RAY_SHADOW) return hit; + } + } + } + else break; + } + return hit; +} +#endif + +/* + * recursively transverse a BVH looking for a rayhit using system stack + */ +#if 0 +template<class Node> +static int bvh_node_raycast(Node *node, Isect *isec) +{ + int hit = 0; + if (bvh_test_node(node, isec)) + { + if (isec->idot_axis[node->split_axis] > 0.0f) + { + int i; + for (i = 0; i < BVH_NCHILDS; i++) + if (!is_leaf(node->child[i])) + { + if (node->child[i] == 0) break; + + hit |= bvh_node_raycast(node->child[i], isec); + if (hit && isec->mode == RE_RAY_SHADOW) return hit; + } + else { + hit |= RE_rayobject_intersect( (RayObject *)node->child[i], isec); + if (hit && isec->mode == RE_RAY_SHADOW) return hit; + } + } + else { + int i; + for (i = BVH_NCHILDS - 1; i >= 0; i--) + if (!is_leaf(node->child[i])) + { + if (node->child[i]) + { + hit |= dfs_raycast(node->child[i], isec); + if (hit && isec->mode == RE_RAY_SHADOW) return hit; + } + } + else { + hit |= RE_rayobject_intersect( (RayObject *)node->child[i], isec); + if (hit && isec->mode == RE_RAY_SHADOW) return hit; + } + } + } + return hit; +} +#endif + +template<class Node, class HintObject> +static void bvh_dfs_make_hint(Node *node, LCTSHint *hint, int reserve_space, HintObject *hintObject) +{ + assert(hint->size + reserve_space + 1 <= RE_RAY_LCTS_MAX_SIZE); + + if (is_leaf(node)) { + hint->stack[hint->size++] = (RayObject *)node; + } + else { + int childs = count_childs(node); + if (hint->size + reserve_space + childs <= RE_RAY_LCTS_MAX_SIZE) { + int result = hint_test_bb(hintObject, node->bb, node->bb + 3); + if (result == HINT_RECURSE) { + /* We are 100% sure the ray will be pass inside this node */ + bvh_dfs_make_hint_push_siblings(node->child, hint, reserve_space, hintObject); + } + else if (result == HINT_ACCEPT) { + hint->stack[hint->size++] = (RayObject *)node; + } + } + else { + hint->stack[hint->size++] = (RayObject *)node; + } + } +} + + +template<class Tree> +static RayObjectAPI *bvh_get_api(int maxstacksize); + + +template<class Tree, int DFS_STACK_SIZE> +static inline RayObject *bvh_create_tree(int size) +{ + Tree *obj = (Tree *)MEM_callocN(sizeof(Tree), "BVHTree"); + assert(RE_rayobject_isAligned(obj)); /* RayObject API assumes real data to be 4-byte aligned */ + + obj->rayobj.api = bvh_get_api<Tree>(DFS_STACK_SIZE); + obj->root = NULL; + + obj->node_arena = NULL; + obj->builder = rtbuild_create(size); + + return RE_rayobject_unalignRayAPI((RayObject *) obj); +} + +#endif diff --git a/source/blender/render/intern/raytrace/rayobject.cpp b/source/blender/render/intern/raytrace/rayobject.cpp new file mode 100644 index 00000000000..fee877b311d --- /dev/null +++ b/source/blender/render/intern/raytrace/rayobject.cpp @@ -0,0 +1,534 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2009 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): André Pinto. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/render/intern/raytrace/rayobject.cpp + * \ingroup render + */ + + +#include <assert.h> + +#include "MEM_guardedalloc.h" + +#include "BLI_math.h" +#include "BLI_utildefines.h" + +#include "DNA_material_types.h" + +#include "rayintersection.h" +#include "rayobject.h" +#include "raycounter.h" +#include "render_types.h" +#include "renderdatabase.h" + +/* RayFace + * + * note we force always inline here, because compiler refuses to otherwise + * because function is too long. Since this is code that is called billions + * of times we really do want to inline. */ + +MALWAYS_INLINE RayObject *rayface_from_coords(RayFace *rayface, void *ob, void *face, + float *v1, float *v2, float *v3, float *v4) +{ + rayface->ob = ob; + rayface->face = face; + + copy_v3_v3(rayface->v1, v1); + copy_v3_v3(rayface->v2, v2); + copy_v3_v3(rayface->v3, v3); + + if (v4) { + copy_v3_v3(rayface->v4, v4); + rayface->quad = 1; + } + else { + rayface->quad = 0; + } + + return RE_rayobject_unalignRayFace(rayface); +} + +MALWAYS_INLINE void rayface_from_vlak(RayFace *rayface, ObjectInstanceRen *obi, VlakRen *vlr) +{ + rayface_from_coords(rayface, obi, vlr, vlr->v1->co, vlr->v2->co, vlr->v3->co, vlr->v4 ? vlr->v4->co : NULL); + + if (obi->transform_primitives) { + mul_m4_v3(obi->mat, rayface->v1); + mul_m4_v3(obi->mat, rayface->v2); + mul_m4_v3(obi->mat, rayface->v3); + + if (RE_rayface_isQuad(rayface)) + mul_m4_v3(obi->mat, rayface->v4); + } +} + +RayObject *RE_rayface_from_vlak(RayFace *rayface, ObjectInstanceRen *obi, VlakRen *vlr) +{ + return rayface_from_coords(rayface, obi, vlr, vlr->v1->co, vlr->v2->co, vlr->v3->co, vlr->v4 ? vlr->v4->co : NULL); +} + +RayObject *RE_rayface_from_coords(RayFace *rayface, void *ob, void *face, float *v1, float *v2, float *v3, float *v4) +{ + return rayface_from_coords(rayface, ob, face, v1, v2, v3, v4); +} + +/* VlakPrimitive */ + +RayObject *RE_vlakprimitive_from_vlak(VlakPrimitive *face, struct ObjectInstanceRen *obi, struct VlakRen *vlr) +{ + face->ob = obi; + face->face = vlr; + + return RE_rayobject_unalignVlakPrimitive(face); +} + +/* Checks for ignoring faces or materials */ + +MALWAYS_INLINE int vlr_check_intersect(Isect *is, ObjectInstanceRen *obi, VlakRen *vlr) +{ + /* for baking selected to active non-traceable materials might still + * be in the raytree */ + if (!(vlr->flag & R_TRACEBLE)) + return 0; + + /* I know... cpu cycle waste, might do smarter once */ + if (is->mode == RE_RAY_MIRROR) + return !(vlr->mat->mode & MA_ONLYCAST); + else + return (vlr->mat->mode2 & MA_CASTSHADOW) && (is->lay & obi->lay); +} + +MALWAYS_INLINE int vlr_check_intersect_solid(Isect *UNUSED(is), ObjectInstanceRen *UNUSED(obi), VlakRen *vlr) +{ + /* solid material types only */ + if (vlr->mat->material_type == MA_TYPE_SURFACE) + return 1; + else + return 0; +} + +MALWAYS_INLINE int vlr_check_bake(Isect *is, ObjectInstanceRen *obi, VlakRen *UNUSED(vlr)) +{ + return (obi->obr->ob != is->userdata) && (obi->obr->ob->flag & SELECT); +} + +/* Ray Triangle/Quad Intersection */ + +static bool isect_ray_tri_watertight_no_sign_check_v3( + const float ray_origin[3], const struct IsectRayPrecalc *isect_precalc, + const float v0[3], const float v1[3], const float v2[3], + float *r_lambda, float r_uv[2]) +{ + const int kx = isect_precalc->kx; + const int ky = isect_precalc->ky; + const int kz = isect_precalc->kz; + const float sx = isect_precalc->sx; + const float sy = isect_precalc->sy; + const float sz = isect_precalc->sz; + + /* Calculate vertices relative to ray origin. */ + const float a[3] = {v0[0] - ray_origin[0], v0[1] - ray_origin[1], v0[2] - ray_origin[2]}; + const float b[3] = {v1[0] - ray_origin[0], v1[1] - ray_origin[1], v1[2] - ray_origin[2]}; + const float c[3] = {v2[0] - ray_origin[0], v2[1] - ray_origin[1], v2[2] - ray_origin[2]}; + + const float a_kx = a[kx], a_ky = a[ky], a_kz = a[kz]; + const float b_kx = b[kx], b_ky = b[ky], b_kz = b[kz]; + const float c_kx = c[kx], c_ky = c[ky], c_kz = c[kz]; + + /* Perform shear and scale of vertices. */ + const float ax = a_kx - sx * a_kz; + const float ay = a_ky - sy * a_kz; + const float bx = b_kx - sx * b_kz; + const float by = b_ky - sy * b_kz; + const float cx = c_kx - sx * c_kz; + const float cy = c_ky - sy * c_kz; + + /* Calculate scaled barycentric coordinates. */ + const float u = cx * by - cy * bx; + const float v = ax * cy - ay * cx; + const float w = bx * ay - by * ax; + float det; + + if ((u < 0.0f || v < 0.0f || w < 0.0f) && + (u > 0.0f || v > 0.0f || w > 0.0f)) + { + return false; + } + + /* Calculate determinant. */ + det = u + v + w; + if (UNLIKELY(det == 0.0f)) { + return false; + } + else { + /* Calculate scaled z-coordinates of vertices and use them to calculate + * the hit distance. + */ + const float t = (u * a_kz + v * b_kz + w * c_kz) * sz; + /* Normalize u, v and t. */ + const float inv_det = 1.0f / det; + if (r_uv) { + r_uv[0] = u * inv_det; + r_uv[1] = v * inv_det; + } + *r_lambda = t * inv_det; + return true; + } +} + +MALWAYS_INLINE int isec_tri_quad(const float start[3], + const struct IsectRayPrecalc *isect_precalc, + const RayFace *face, + float r_uv[2], float *r_lambda) +{ + float uv[2], l; + + if (isect_ray_tri_watertight_v3(start, isect_precalc, face->v1, face->v2, face->v3, &l, uv)) { + /* check if intersection is within ray length */ + if (l > -RE_RAYTRACE_EPSILON && l < *r_lambda) { + r_uv[0] = -uv[0]; + r_uv[1] = -uv[1]; + *r_lambda = l; + return 1; + } + } + + /* intersect second triangle in quad */ + if (RE_rayface_isQuad(face)) { + if (isect_ray_tri_watertight_v3(start, isect_precalc, face->v1, face->v3, face->v4, &l, uv)) { + /* check if intersection is within ray length */ + if (l > -RE_RAYTRACE_EPSILON && l < *r_lambda) { + r_uv[0] = -uv[0]; + r_uv[1] = -uv[1]; + *r_lambda = l; + return 2; + } + } + } + + return 0; +} + +/* Simpler yes/no Ray Triangle/Quad Intersection */ + +MALWAYS_INLINE int isec_tri_quad_neighbour(const float start[3], + const float dir[3], + const RayFace *face) +{ + float r[3]; + struct IsectRayPrecalc isect_precalc; + float uv[2], l; + + negate_v3_v3(r, dir); /* note, different than above function */ + + isect_ray_tri_watertight_v3_precalc(&isect_precalc, r); + + if (isect_ray_tri_watertight_no_sign_check_v3(start, &isect_precalc, face->v1, face->v2, face->v3, &l, uv)) { + return 1; + } + + /* intersect second triangle in quad */ + if (RE_rayface_isQuad(face)) { + if (isect_ray_tri_watertight_no_sign_check_v3(start, &isect_precalc, face->v1, face->v3, face->v4, &l, uv)) { + return 2; + } + } + + return 0; +} + +/* RayFace intersection with checks and neighbor verifaction included, + * Isect is modified if the face is hit. */ + +MALWAYS_INLINE int intersect_rayface(RayObject *hit_obj, RayFace *face, Isect *is) +{ + float dist, uv[2]; + int ok = 0; + + /* avoid self-intersection */ + if (is->orig.ob == face->ob && is->orig.face == face->face) + return 0; + + /* check if we should intersect this face */ + if (is->check == RE_CHECK_VLR_RENDER) { + if (vlr_check_intersect(is, (ObjectInstanceRen *)face->ob, (VlakRen *)face->face) == 0) + return 0; + } + else if (is->check == RE_CHECK_VLR_NON_SOLID_MATERIAL) { + if (vlr_check_intersect(is, (ObjectInstanceRen *)face->ob, (VlakRen *)face->face) == 0) + return 0; + if (vlr_check_intersect_solid(is, (ObjectInstanceRen *)face->ob, (VlakRen *)face->face) == 0) + return 0; + } + else if (is->check == RE_CHECK_VLR_BAKE) { + if (vlr_check_bake(is, (ObjectInstanceRen *)face->ob, (VlakRen *)face->face) == 0) + return 0; + } + + /* ray counter */ + RE_RC_COUNT(is->raycounter->faces.test); + + dist = is->dist; + ok = isec_tri_quad(is->start, &is->isect_precalc, face, uv, &dist); + + if (ok) { + + /* when a shadow ray leaves a face, it can be little outside the edges + * of it, causing intersection to be detected in its neighbor face */ + if (is->skip & RE_SKIP_VLR_NEIGHBOUR) { + if (dist < 0.1f && is->orig.ob == face->ob) { + VlakRen *a = (VlakRen *)is->orig.face; + VlakRen *b = (VlakRen *)face->face; + ObjectRen *obr = ((ObjectInstanceRen *)face->ob)->obr; + + VertRen **va, **vb; + int *org_idx_a, *org_idx_b; + int i, j; + bool is_neighbor = false; + + /* "same" vertex means either the actual same VertRen, or the same 'final org index', if available + * (autosmooth only, currently). */ + for (i = 0, va = &a->v1; !is_neighbor && i < 4 && *va; ++i, ++va) { + org_idx_a = RE_vertren_get_origindex(obr, *va, false); + for (j = 0, vb = &b->v1; !is_neighbor && j < 4 && *vb; ++j, ++vb) { + if (*va == *vb) { + is_neighbor = true; + } + else if (org_idx_a) { + org_idx_b = RE_vertren_get_origindex(obr, *vb, 0); + if (org_idx_b && *org_idx_a == *org_idx_b) { + is_neighbor = true; + } + } + } + } + + /* So there's a shared edge or vertex, let's intersect ray with self, if that's true + * we can safely return 1, otherwise we assume the intersection is invalid, 0 */ + if (is_neighbor) { + /* create RayFace from original face, transformed if necessary */ + RayFace origface; + ObjectInstanceRen *ob = (ObjectInstanceRen *)is->orig.ob; + rayface_from_vlak(&origface, ob, (VlakRen *)is->orig.face); + + if (!isec_tri_quad_neighbour(is->start, is->dir, &origface)) { + return 0; + } + } + } + } + + RE_RC_COUNT(is->raycounter->faces.hit); + + is->isect = ok; // which half of the quad + is->dist = dist; + is->u = uv[0]; is->v = uv[1]; + + is->hit.ob = face->ob; + is->hit.face = face->face; +#ifdef RT_USE_LAST_HIT + is->last_hit = hit_obj; +#endif + return 1; + } + + return 0; +} + +/* Intersection */ + +int RE_rayobject_raycast(RayObject *r, Isect *isec) +{ + int i; + + /* Pre-calculate orientation for watertight intersection checks. */ + isect_ray_tri_watertight_v3_precalc(&isec->isect_precalc, isec->dir); + + RE_RC_COUNT(isec->raycounter->raycast.test); + + /* setup vars used on raycast */ + for (i = 0; i < 3; i++) { + isec->idot_axis[i] = 1.0f / isec->dir[i]; + + isec->bv_index[2 * i] = isec->idot_axis[i] < 0.0f ? 1 : 0; + isec->bv_index[2 * i + 1] = 1 - isec->bv_index[2 * i]; + + isec->bv_index[2 * i] = i + 3 * isec->bv_index[2 * i]; + isec->bv_index[2 * i + 1] = i + 3 * isec->bv_index[2 * i + 1]; + } + +#ifdef RT_USE_LAST_HIT + /* last hit heuristic */ + if (isec->mode == RE_RAY_SHADOW && isec->last_hit) { + RE_RC_COUNT(isec->raycounter->rayshadow_last_hit.test); + + if (RE_rayobject_intersect(isec->last_hit, isec)) { + RE_RC_COUNT(isec->raycounter->raycast.hit); + RE_RC_COUNT(isec->raycounter->rayshadow_last_hit.hit); + return 1; + } + } +#endif + +#ifdef RT_USE_HINT + isec->hit_hint = 0; +#endif + + if (RE_rayobject_intersect(r, isec)) { + RE_RC_COUNT(isec->raycounter->raycast.hit); + +#ifdef RT_USE_HINT + isec->hint = isec->hit_hint; +#endif + return 1; + } + + return 0; +} + +int RE_rayobject_intersect(RayObject *r, Isect *i) +{ + if (RE_rayobject_isRayFace(r)) { + return intersect_rayface(r, (RayFace *) RE_rayobject_align(r), i); + } + else if (RE_rayobject_isVlakPrimitive(r)) { + //TODO optimize (useless copy to RayFace to avoid duplicate code) + VlakPrimitive *face = (VlakPrimitive *) RE_rayobject_align(r); + RayFace nface; + rayface_from_vlak(&nface, face->ob, face->face); + + return intersect_rayface(r, &nface, i); + } + else if (RE_rayobject_isRayAPI(r)) { + r = RE_rayobject_align(r); + return r->api->raycast(r, i); + } + else { + assert(0); + return 0; + } +} + +/* Building */ + +void RE_rayobject_add(RayObject *r, RayObject *o) +{ + r = RE_rayobject_align(r); + return r->api->add(r, o); +} + +void RE_rayobject_done(RayObject *r) +{ + r = RE_rayobject_align(r); + r->api->done(r); +} + +void RE_rayobject_free(RayObject *r) +{ + r = RE_rayobject_align(r); + r->api->free(r); +} + +float RE_rayobject_cost(RayObject *r) +{ + if (RE_rayobject_isRayFace(r) || RE_rayobject_isVlakPrimitive(r)) { + return 1.0f; + } + else if (RE_rayobject_isRayAPI(r)) { + r = RE_rayobject_align(r); + return r->api->cost(r); + } + else { + assert(0); + return 1.0f; + } +} + +/* Bounding Boxes */ + +void RE_rayobject_merge_bb(RayObject *r, float min[3], float max[3]) +{ + if (RE_rayobject_isRayFace(r)) { + RayFace *face = (RayFace *) RE_rayobject_align(r); + + DO_MINMAX(face->v1, min, max); + DO_MINMAX(face->v2, min, max); + DO_MINMAX(face->v3, min, max); + if (RE_rayface_isQuad(face)) DO_MINMAX(face->v4, min, max); + } + else if (RE_rayobject_isVlakPrimitive(r)) { + VlakPrimitive *face = (VlakPrimitive *) RE_rayobject_align(r); + RayFace nface; + rayface_from_vlak(&nface, face->ob, face->face); + + DO_MINMAX(nface.v1, min, max); + DO_MINMAX(nface.v2, min, max); + DO_MINMAX(nface.v3, min, max); + if (RE_rayface_isQuad(&nface)) DO_MINMAX(nface.v4, min, max); + } + else if (RE_rayobject_isRayAPI(r)) { + r = RE_rayobject_align(r); + r->api->bb(r, min, max); + } + else + assert(0); +} + +/* Hints */ + +void RE_rayobject_hint_bb(RayObject *r, RayHint *hint, float *min, float *max) +{ + if (RE_rayobject_isRayFace(r) || RE_rayobject_isVlakPrimitive(r)) { + return; + } + else if (RE_rayobject_isRayAPI(r)) { + r = RE_rayobject_align(r); + return r->api->hint_bb(r, hint, min, max); + } + else + assert(0); +} + +/* RayObjectControl */ + +int RE_rayobjectcontrol_test_break(RayObjectControl *control) +{ + if (control->test_break) + return control->test_break(control->data); + + return 0; +} + +void RE_rayobject_set_control(RayObject *r, void *data, RE_rayobjectcontrol_test_break_callback test_break) +{ + if (RE_rayobject_isRayAPI(r)) { + r = RE_rayobject_align(r); + r->control.data = data; + r->control.test_break = test_break; + } +} + diff --git a/source/blender/render/intern/raytrace/rayobject_hint.h b/source/blender/render/intern/raytrace/rayobject_hint.h new file mode 100644 index 00000000000..88a32819bd2 --- /dev/null +++ b/source/blender/render/intern/raytrace/rayobject_hint.h @@ -0,0 +1,72 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2009 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): André Pinto. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/render/intern/raytrace/rayobject_hint.h + * \ingroup render + */ + + +#ifndef __RAYOBJECT_HINT_H__ +#define __RAYOBJECT_HINT_H__ + +#define HINT_RECURSE 1 +#define HINT_ACCEPT 0 +#define HINT_DISCARD -1 + +struct HintBB { + float bb[6]; +}; + +inline int hint_test_bb(HintBB *obj, float *Nmin, float *Nmax) +{ + if (bb_fits_inside(Nmin, Nmax, obj->bb, obj->bb + 3) ) + return HINT_RECURSE; + else + return HINT_ACCEPT; +} +#if 0 +struct HintFrustum { + float co[3]; + float no[4][3]; +}; + +inline int hint_test_bb(HintFrustum &obj, float *Nmin, float *Nmax) +{ + //if frustum inside BB + { + return HINT_RECURSE; + } + //if BB outside frustum + { + return HINT_DISCARD; + } + + return HINT_ACCEPT; +} +#endif + +#endif /* __RAYOBJECT_HINT_H__ */ diff --git a/source/blender/render/intern/raytrace/rayobject_instance.cpp b/source/blender/render/intern/raytrace/rayobject_instance.cpp new file mode 100644 index 00000000000..361e7963d96 --- /dev/null +++ b/source/blender/render/intern/raytrace/rayobject_instance.cpp @@ -0,0 +1,211 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2009 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): André Pinto. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/render/intern/raytrace/rayobject_instance.cpp + * \ingroup render + */ + + +#include <assert.h> + +#include "MEM_guardedalloc.h" + +#include "BLI_math.h" +#include "BLI_utildefines.h" + +#include "rayintersection.h" +#include "rayobject.h" + +#define RE_COST_INSTANCE (1.0f) + +static int RE_rayobject_instance_intersect(RayObject *o, Isect *isec); +static void RE_rayobject_instance_free(RayObject *o); +static void RE_rayobject_instance_bb(RayObject *o, float *min, float *max); +static float RE_rayobject_instance_cost(RayObject *o); + +static void RE_rayobject_instance_hint_bb(RayObject *UNUSED(o), RayHint *UNUSED(hint), + float *UNUSED(min), float *UNUSED(max)) +{} + +static RayObjectAPI instance_api = +{ + RE_rayobject_instance_intersect, + NULL, //static void RE_rayobject_instance_add(RayObject *o, RayObject *ob); + NULL, //static void RE_rayobject_instance_done(RayObject *o); + RE_rayobject_instance_free, + RE_rayobject_instance_bb, + RE_rayobject_instance_cost, + RE_rayobject_instance_hint_bb +}; + +typedef struct InstanceRayObject { + RayObject rayobj; + RayObject *target; + + void *ob; //Object represented by this instance + void *target_ob; //Object represented by the inner RayObject, needed to handle self-intersection + + float global2target[4][4]; + float target2global[4][4]; + +} InstanceRayObject; + + +RayObject *RE_rayobject_instance_create(RayObject *target, float transform[4][4], void *ob, void *target_ob) +{ + InstanceRayObject *obj = (InstanceRayObject *)MEM_callocN(sizeof(InstanceRayObject), "InstanceRayObject"); + assert(RE_rayobject_isAligned(obj) ); /* RayObject API assumes real data to be 4-byte aligned */ + + obj->rayobj.api = &instance_api; + obj->target = target; + obj->ob = ob; + obj->target_ob = target_ob; + + copy_m4_m4(obj->target2global, transform); + invert_m4_m4(obj->global2target, obj->target2global); + + return RE_rayobject_unalignRayAPI((RayObject *) obj); +} + +static int RE_rayobject_instance_intersect(RayObject *o, Isect *isec) +{ + InstanceRayObject *obj = (InstanceRayObject *)o; + float start[3], dir[3], idot_axis[3], dist; + int changed = 0, i, res; + + // TODO - this is disabling self intersection on instances + if (isec->orig.ob == obj->ob && obj->ob) { + changed = 1; + isec->orig.ob = obj->target_ob; + } + + // backup old values + copy_v3_v3(start, isec->start); + copy_v3_v3(dir, isec->dir); + copy_v3_v3(idot_axis, isec->idot_axis); + dist = isec->dist; + + // transform to target coordinates system + mul_m4_v3(obj->global2target, isec->start); + mul_mat3_m4_v3(obj->global2target, isec->dir); + isec->dist *= normalize_v3(isec->dir); + + // update idot_axis and bv_index + for (i = 0; i < 3; i++) { + isec->idot_axis[i] = 1.0f / isec->dir[i]; + + isec->bv_index[2 * i] = isec->idot_axis[i] < 0.0f ? 1 : 0; + isec->bv_index[2 * i + 1] = 1 - isec->bv_index[2 * i]; + + isec->bv_index[2 * i] = i + 3 * isec->bv_index[2 * i]; + isec->bv_index[2 * i + 1] = i + 3 * isec->bv_index[2 * i + 1]; + } + + // Pre-calculate orientation for watertight intersection checks. + isect_ray_tri_watertight_v3_precalc(&isec->isect_precalc, isec->dir); + + // raycast + res = RE_rayobject_intersect(obj->target, isec); + + // map dist into original coordinate space + if (res == 0) { + isec->dist = dist; + } + else { + // note we don't just multiply dist, because of possible + // non-uniform scaling in the transform matrix + float vec[3]; + + mul_v3_v3fl(vec, isec->dir, isec->dist); + mul_mat3_m4_v3(obj->target2global, vec); + + isec->dist = len_v3(vec); + isec->hit.ob = obj->ob; + +#ifdef RT_USE_LAST_HIT + // TODO support for last hit optimization in instances that can jump + // directly to the last hit face. + // For now it jumps directly to the last-hit instance root node. + isec->last_hit = RE_rayobject_unalignRayAPI((RayObject *) obj); +#endif + } + + // restore values + copy_v3_v3(isec->start, start); + copy_v3_v3(isec->dir, dir); + copy_v3_v3(isec->idot_axis, idot_axis); + + if (changed) + isec->orig.ob = obj->ob; + + // restore bv_index + for (i = 0; i < 3; i++) { + isec->bv_index[2 * i] = isec->idot_axis[i] < 0.0f ? 1 : 0; + isec->bv_index[2 * i + 1] = 1 - isec->bv_index[2 * i]; + + isec->bv_index[2 * i] = i + 3 * isec->bv_index[2 * i]; + isec->bv_index[2 * i + 1] = i + 3 * isec->bv_index[2 * i + 1]; + } + + // Pre-calculate orientation for watertight intersection checks. + isect_ray_tri_watertight_v3_precalc(&isec->isect_precalc, isec->dir); + + return res; +} + +static void RE_rayobject_instance_free(RayObject *o) +{ + InstanceRayObject *obj = (InstanceRayObject *)o; + MEM_freeN(obj); +} + +static float RE_rayobject_instance_cost(RayObject *o) +{ + InstanceRayObject *obj = (InstanceRayObject *)o; + return RE_rayobject_cost(obj->target) + RE_COST_INSTANCE; +} + +static void RE_rayobject_instance_bb(RayObject *o, float *min, float *max) +{ + //TODO: + // *better bb.. calculated without rotations of bb + // *maybe cache that better-fitted-BB at the InstanceRayObject + InstanceRayObject *obj = (InstanceRayObject *)o; + + float m[3], M[3], t[3]; + int i, j; + INIT_MINMAX(m, M); + RE_rayobject_merge_bb(obj->target, m, M); + + //There must be a faster way than rotating all the 8 vertexs of the BB + for (i = 0; i < 8; i++) { + for (j = 0; j < 3; j++) t[j] = (i & (1 << j)) ? M[j] : m[j]; + mul_m4_v3(obj->target2global, t); + DO_MINMAX(t, min, max); + } +} + diff --git a/source/blender/render/intern/raytrace/rayobject_octree.cpp b/source/blender/render/intern/raytrace/rayobject_octree.cpp new file mode 100644 index 00000000000..4b73e64ca45 --- /dev/null +++ b/source/blender/render/intern/raytrace/rayobject_octree.cpp @@ -0,0 +1,1101 @@ +/* + * ***** 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) 1990-1998 NeoGeo BV. + * All rights reserved. + * + * Contributors: 2004/2005 Blender Foundation, full recode + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/render/intern/raytrace/rayobject_octree.cpp + * \ingroup render + */ + + +/* IMPORTANT NOTE: this code must be independent of any other render code + * to use it outside the renderer! */ + +#include <math.h> +#include <string.h> +#include <stdlib.h> +#include <float.h> +#include <assert.h> + +#include "MEM_guardedalloc.h" + +#include "DNA_material_types.h" + +#include "BLI_math.h" +#include "BLI_utildefines.h" + +#include "rayintersection.h" +#include "rayobject.h" + +/* ********** structs *************** */ +#define BRANCH_ARRAY 1024 +#define NODE_ARRAY 4096 + +typedef struct Branch { + struct Branch *b[8]; +} Branch; + +typedef struct OcVal { + short ocx, ocy, ocz; +} OcVal; + +typedef struct Node { + struct RayFace *v[8]; + struct OcVal ov[8]; + struct Node *next; +} Node; + +typedef struct Octree { + RayObject rayobj; + + struct Branch **adrbranch; + struct Node **adrnode; + float ocsize; /* ocsize: mult factor, max size octree */ + float ocfacx, ocfacy, ocfacz; + float min[3], max[3]; + int ocres; + int branchcount, nodecount; + + /* during building only */ + char *ocface; + + RayFace **ro_nodes; + int ro_nodes_size, ro_nodes_used; + +} Octree; + +static int RE_rayobject_octree_intersect(RayObject *o, Isect *isec); +static void RE_rayobject_octree_add(RayObject *o, RayObject *ob); +static void RE_rayobject_octree_done(RayObject *o); +static void RE_rayobject_octree_free(RayObject *o); +static void RE_rayobject_octree_bb(RayObject *o, float *min, float *max); + +/* + * This function is not expected to be called by current code state. + */ +static float RE_rayobject_octree_cost(RayObject *UNUSED(o)) +{ + return 1.0; +} + +static void RE_rayobject_octree_hint_bb(RayObject *UNUSED(o), RayHint *UNUSED(hint), + float *UNUSED(min), float *UNUSED(max)) +{ + return; +} + +static RayObjectAPI octree_api = +{ + RE_rayobject_octree_intersect, + RE_rayobject_octree_add, + RE_rayobject_octree_done, + RE_rayobject_octree_free, + RE_rayobject_octree_bb, + RE_rayobject_octree_cost, + RE_rayobject_octree_hint_bb +}; + +/* **************** ocval method ******************* */ +/* within one octree node, a set of 3x15 bits defines a 'boundbox' to OR with */ + +#define OCVALRES 15 +#define BROW16(min, max) \ + (((max) >= OCVALRES ? 0xFFFF : (1 << ((max) + 1)) - 1) - (((min) > 0) ? ((1 << (min)) - 1) : 0)) + +static void calc_ocval_face(float *v1, float *v2, float *v3, float *v4, short x, short y, short z, OcVal *ov) +{ + float min[3], max[3]; + int ocmin, ocmax; + + copy_v3_v3(min, v1); + copy_v3_v3(max, v1); + DO_MINMAX(v2, min, max); + DO_MINMAX(v3, min, max); + if (v4) { + DO_MINMAX(v4, min, max); + } + + ocmin = OCVALRES * (min[0] - x); + ocmax = OCVALRES * (max[0] - x); + ov->ocx = BROW16(ocmin, ocmax); + + ocmin = OCVALRES * (min[1] - y); + ocmax = OCVALRES * (max[1] - y); + ov->ocy = BROW16(ocmin, ocmax); + + ocmin = OCVALRES * (min[2] - z); + ocmax = OCVALRES * (max[2] - z); + ov->ocz = BROW16(ocmin, ocmax); + +} + +static void calc_ocval_ray(OcVal *ov, float xo, float yo, float zo, float *vec1, float *vec2) +{ + int ocmin, ocmax; + + if (vec1[0] < vec2[0]) { + ocmin = OCVALRES * (vec1[0] - xo); + ocmax = OCVALRES * (vec2[0] - xo); + } + else { + ocmin = OCVALRES * (vec2[0] - xo); + ocmax = OCVALRES * (vec1[0] - xo); + } + ov->ocx = BROW16(ocmin, ocmax); + + if (vec1[1] < vec2[1]) { + ocmin = OCVALRES * (vec1[1] - yo); + ocmax = OCVALRES * (vec2[1] - yo); + } + else { + ocmin = OCVALRES * (vec2[1] - yo); + ocmax = OCVALRES * (vec1[1] - yo); + } + ov->ocy = BROW16(ocmin, ocmax); + + if (vec1[2] < vec2[2]) { + ocmin = OCVALRES * (vec1[2] - zo); + ocmax = OCVALRES * (vec2[2] - zo); + } + else { + ocmin = OCVALRES * (vec2[2] - zo); + ocmax = OCVALRES * (vec1[2] - zo); + } + ov->ocz = BROW16(ocmin, ocmax); +} + +/* ************* octree ************** */ + +static Branch *addbranch(Octree *oc, Branch *br, short ocb) +{ + int index; + + if (br->b[ocb]) return br->b[ocb]; + + oc->branchcount++; + index = oc->branchcount >> 12; + + if (oc->adrbranch[index] == NULL) + oc->adrbranch[index] = (Branch *)MEM_callocN(4096 * sizeof(Branch), "new oc branch"); + + if (oc->branchcount >= BRANCH_ARRAY * 4096) { + printf("error; octree branches full\n"); + oc->branchcount = 0; + } + + return br->b[ocb] = oc->adrbranch[index] + (oc->branchcount & 4095); +} + +static Node *addnode(Octree *oc) +{ + int index; + + oc->nodecount++; + index = oc->nodecount >> 12; + + if (oc->adrnode[index] == NULL) + oc->adrnode[index] = (Node *)MEM_callocN(4096 * sizeof(Node), "addnode"); + + if (oc->nodecount > NODE_ARRAY * NODE_ARRAY) { + printf("error; octree nodes full\n"); + oc->nodecount = 0; + } + + return oc->adrnode[index] + (oc->nodecount & 4095); +} + +static bool face_in_node(RayFace *face, short x, short y, short z, float rtf[4][3]) +{ + static float nor[3], d; + float fx, fy, fz; + + // init static vars + if (face) { + normal_tri_v3(nor, rtf[0], rtf[1], rtf[2]); + d = -nor[0] * rtf[0][0] - nor[1] * rtf[0][1] - nor[2] * rtf[0][2]; + return 0; + } + + fx = x; + fy = y; + fz = z; + + if ((fx) * nor[0] + (fy) * nor[1] + (fz) * nor[2] + d > 0.0f) { + if ((fx + 1) * nor[0] + (fy ) * nor[1] + (fz ) * nor[2] + d < 0.0f) return 1; + if ((fx ) * nor[0] + (fy + 1) * nor[1] + (fz ) * nor[2] + d < 0.0f) return 1; + if ((fx + 1) * nor[0] + (fy + 1) * nor[1] + (fz ) * nor[2] + d < 0.0f) return 1; + + if ((fx ) * nor[0] + (fy ) * nor[1] + (fz + 1) * nor[2] + d < 0.0f) return 1; + if ((fx + 1) * nor[0] + (fy ) * nor[1] + (fz + 1) * nor[2] + d < 0.0f) return 1; + if ((fx ) * nor[0] + (fy + 1) * nor[1] + (fz + 1) * nor[2] + d < 0.0f) return 1; + if ((fx + 1) * nor[0] + (fy + 1) * nor[1] + (fz + 1) * nor[2] + d < 0.0f) return 1; + } + else { + if ((fx + 1) * nor[0] + (fy ) * nor[1] + (fz ) * nor[2] + d > 0.0f) return 1; + if ((fx ) * nor[0] + (fy + 1) * nor[1] + (fz ) * nor[2] + d > 0.0f) return 1; + if ((fx + 1) * nor[0] + (fy + 1) * nor[1] + (fz ) * nor[2] + d > 0.0f) return 1; + + if ((fx ) * nor[0] + (fy ) * nor[1] + (fz + 1) * nor[2] + d > 0.0f) return 1; + if ((fx + 1) * nor[0] + (fy ) * nor[1] + (fz + 1) * nor[2] + d > 0.0f) return 1; + if ((fx ) * nor[0] + (fy + 1) * nor[1] + (fz + 1) * nor[2] + d > 0.0f) return 1; + if ((fx + 1) * nor[0] + (fy + 1) * nor[1] + (fz + 1) * nor[2] + d > 0.0f) return 1; + } + + return 0; +} + +static void ocwrite(Octree *oc, RayFace *face, int quad, short x, short y, short z, float rtf[4][3]) +{ + Branch *br; + Node *no; + short a, oc0, oc1, oc2, oc3, oc4, oc5; + + x <<= 2; + y <<= 1; + + br = oc->adrbranch[0]; + + if (oc->ocres == 512) { + oc0 = ((x & 1024) + (y & 512) + (z & 256)) >> 8; + br = addbranch(oc, br, oc0); + } + if (oc->ocres >= 256) { + oc0 = ((x & 512) + (y & 256) + (z & 128)) >> 7; + br = addbranch(oc, br, oc0); + } + if (oc->ocres >= 128) { + oc0 = ((x & 256) + (y & 128) + (z & 64)) >> 6; + br = addbranch(oc, br, oc0); + } + + oc0 = ((x & 128) + (y & 64) + (z & 32)) >> 5; + oc1 = ((x & 64) + (y & 32) + (z & 16)) >> 4; + oc2 = ((x & 32) + (y & 16) + (z & 8)) >> 3; + oc3 = ((x & 16) + (y & 8) + (z & 4)) >> 2; + oc4 = ((x & 8) + (y & 4) + (z & 2)) >> 1; + oc5 = ((x & 4) + (y & 2) + (z & 1)); + + br = addbranch(oc, br, oc0); + br = addbranch(oc, br, oc1); + br = addbranch(oc, br, oc2); + br = addbranch(oc, br, oc3); + br = addbranch(oc, br, oc4); + no = (Node *)br->b[oc5]; + if (no == NULL) br->b[oc5] = (Branch *)(no = addnode(oc)); + + while (no->next) no = no->next; + + a = 0; + if (no->v[7]) { /* node full */ + no->next = addnode(oc); + no = no->next; + } + else { + while (no->v[a] != NULL) a++; + } + + no->v[a] = (RayFace *) RE_rayobject_align(face); + + if (quad) + calc_ocval_face(rtf[0], rtf[1], rtf[2], rtf[3], x >> 2, y >> 1, z, &no->ov[a]); + else + calc_ocval_face(rtf[0], rtf[1], rtf[2], NULL, x >> 2, y >> 1, z, &no->ov[a]); +} + +static void d2dda(Octree *oc, short b1, short b2, short c1, short c2, char *ocface, short rts[4][3], float rtf[4][3]) +{ + int ocx1, ocx2, ocy1, ocy2; + int x, y, dx = 0, dy = 0; + float ox1, ox2, oy1, oy2; + float lambda, lambda_o, lambda_x, lambda_y, ldx, ldy; + + ocx1 = rts[b1][c1]; + ocy1 = rts[b1][c2]; + ocx2 = rts[b2][c1]; + ocy2 = rts[b2][c2]; + + if (ocx1 == ocx2 && ocy1 == ocy2) { + ocface[oc->ocres * ocx1 + ocy1] = 1; + return; + } + + ox1 = rtf[b1][c1]; + oy1 = rtf[b1][c2]; + ox2 = rtf[b2][c1]; + oy2 = rtf[b2][c2]; + + if (ox1 != ox2) { + if (ox2 - ox1 > 0.0f) { + lambda_x = (ox1 - ocx1 - 1.0f) / (ox1 - ox2); + ldx = -1.0f / (ox1 - ox2); + dx = 1; + } + else { + lambda_x = (ox1 - ocx1) / (ox1 - ox2); + ldx = 1.0f / (ox1 - ox2); + dx = -1; + } + } + else { + lambda_x = 1.0f; + ldx = 0; + } + + if (oy1 != oy2) { + if (oy2 - oy1 > 0.0f) { + lambda_y = (oy1 - ocy1 - 1.0f) / (oy1 - oy2); + ldy = -1.0f / (oy1 - oy2); + dy = 1; + } + else { + lambda_y = (oy1 - ocy1) / (oy1 - oy2); + ldy = 1.0f / (oy1 - oy2); + dy = -1; + } + } + else { + lambda_y = 1.0f; + ldy = 0; + } + + x = ocx1; y = ocy1; + lambda = MIN2(lambda_x, lambda_y); + + while (true) { + + if (x < 0 || y < 0 || x >= oc->ocres || y >= oc->ocres) { + /* pass*/ + } + else { + ocface[oc->ocres * x + y] = 1; + } + + lambda_o = lambda; + if (lambda_x == lambda_y) { + lambda_x += ldx; + x += dx; + lambda_y += ldy; + y += dy; + } + else { + if (lambda_x < lambda_y) { + lambda_x += ldx; + x += dx; + } + else { + lambda_y += ldy; + y += dy; + } + } + lambda = MIN2(lambda_x, lambda_y); + if (lambda == lambda_o) break; + if (lambda >= 1.0f) break; + } + ocface[oc->ocres * ocx2 + ocy2] = 1; +} + +static void filltriangle(Octree *oc, short c1, short c2, char *ocface, short *ocmin, short *ocmax) +{ + int a, x, y, y1, y2; + + for (x = ocmin[c1]; x <= ocmax[c1]; x++) { + a = oc->ocres * x; + for (y = ocmin[c2]; y <= ocmax[c2]; y++) { + if (ocface[a + y]) { + y++; + while (ocface[a + y] && y != ocmax[c2]) y++; + for (y1 = ocmax[c2]; y1 > y; y1--) { + if (ocface[a + y1]) { + for (y2 = y; y2 <= y1; y2++) ocface[a + y2] = 1; + y1 = 0; + } + } + y = ocmax[c2]; + } + } + } +} + +static void RE_rayobject_octree_free(RayObject *tree) +{ + Octree *oc = (Octree *)tree; + +#if 0 + printf("branches %d nodes %d\n", oc->branchcount, oc->nodecount); + printf("raycount %d\n", raycount); + printf("ray coherent %d\n", coherent_ray); + printf("accepted %d rejected %d\n", accepted, rejected); +#endif + if (oc->ocface) + MEM_freeN(oc->ocface); + + if (oc->adrbranch) { + int a = 0; + while (oc->adrbranch[a]) { + MEM_freeN(oc->adrbranch[a]); + oc->adrbranch[a] = NULL; + a++; + } + MEM_freeN(oc->adrbranch); + oc->adrbranch = NULL; + } + oc->branchcount = 0; + + if (oc->adrnode) { + int a = 0; + while (oc->adrnode[a]) { + MEM_freeN(oc->adrnode[a]); + oc->adrnode[a] = NULL; + a++; + } + MEM_freeN(oc->adrnode); + oc->adrnode = NULL; + } + oc->nodecount = 0; + + MEM_freeN(oc); +} + + +RayObject *RE_rayobject_octree_create(int ocres, int size) +{ + Octree *oc = (Octree *)MEM_callocN(sizeof(Octree), "Octree"); + assert(RE_rayobject_isAligned(oc) ); /* RayObject API assumes real data to be 4-byte aligned */ + + oc->rayobj.api = &octree_api; + + oc->ocres = ocres; + + oc->ro_nodes = (RayFace **)MEM_callocN(sizeof(RayFace *) * size, "octree rayobject nodes"); + oc->ro_nodes_size = size; + oc->ro_nodes_used = 0; + + + return RE_rayobject_unalignRayAPI((RayObject *) oc); +} + + +static void RE_rayobject_octree_add(RayObject *tree, RayObject *node) +{ + Octree *oc = (Octree *)tree; + + assert(RE_rayobject_isRayFace(node) ); + assert(oc->ro_nodes_used < oc->ro_nodes_size); + oc->ro_nodes[oc->ro_nodes_used++] = (RayFace *)RE_rayobject_align(node); +} + +static void octree_fill_rayface(Octree *oc, RayFace *face) +{ + float ocfac[3], rtf[4][3]; + float co1[3], co2[3], co3[3], co4[3]; + short rts[4][3]; + short ocmin[3], ocmax[3]; + char *ocface = oc->ocface; // front, top, size view of face, to fill in + int a, b, c, oc1, oc2, oc3, oc4, x, y, z, ocres2; + + ocfac[0] = oc->ocfacx; + ocfac[1] = oc->ocfacy; + ocfac[2] = oc->ocfacz; + + ocres2 = oc->ocres * oc->ocres; + + copy_v3_v3(co1, face->v1); + copy_v3_v3(co2, face->v2); + copy_v3_v3(co3, face->v3); + if (RE_rayface_isQuad(face)) + copy_v3_v3(co4, face->v4); + + for (c = 0; c < 3; c++) { + rtf[0][c] = (co1[c] - oc->min[c]) * ocfac[c]; + rts[0][c] = (short)rtf[0][c]; + rtf[1][c] = (co2[c] - oc->min[c]) * ocfac[c]; + rts[1][c] = (short)rtf[1][c]; + rtf[2][c] = (co3[c] - oc->min[c]) * ocfac[c]; + rts[2][c] = (short)rtf[2][c]; + if (RE_rayface_isQuad(face)) { + rtf[3][c] = (co4[c] - oc->min[c]) * ocfac[c]; + rts[3][c] = (short)rtf[3][c]; + } + } + + for (c = 0; c < 3; c++) { + oc1 = rts[0][c]; + oc2 = rts[1][c]; + oc3 = rts[2][c]; + if (!RE_rayface_isQuad(face)) { + ocmin[c] = min_iii(oc1, oc2, oc3); + ocmax[c] = max_iii(oc1, oc2, oc3); + } + else { + oc4 = rts[3][c]; + ocmin[c] = min_iiii(oc1, oc2, oc3, oc4); + ocmax[c] = max_iiii(oc1, oc2, oc3, oc4); + } + if (ocmax[c] > oc->ocres - 1) ocmax[c] = oc->ocres - 1; + if (ocmin[c] < 0) ocmin[c] = 0; + } + + if (ocmin[0] == ocmax[0] && ocmin[1] == ocmax[1] && ocmin[2] == ocmax[2]) { + ocwrite(oc, face, RE_rayface_isQuad(face), ocmin[0], ocmin[1], ocmin[2], rtf); + } + else { + + d2dda(oc, 0, 1, 0, 1, ocface + ocres2, rts, rtf); + d2dda(oc, 0, 1, 0, 2, ocface, rts, rtf); + d2dda(oc, 0, 1, 1, 2, ocface + 2 * ocres2, rts, rtf); + d2dda(oc, 1, 2, 0, 1, ocface + ocres2, rts, rtf); + d2dda(oc, 1, 2, 0, 2, ocface, rts, rtf); + d2dda(oc, 1, 2, 1, 2, ocface + 2 * ocres2, rts, rtf); + if (!RE_rayface_isQuad(face)) { + d2dda(oc, 2, 0, 0, 1, ocface + ocres2, rts, rtf); + d2dda(oc, 2, 0, 0, 2, ocface, rts, rtf); + d2dda(oc, 2, 0, 1, 2, ocface + 2 * ocres2, rts, rtf); + } + else { + d2dda(oc, 2, 3, 0, 1, ocface + ocres2, rts, rtf); + d2dda(oc, 2, 3, 0, 2, ocface, rts, rtf); + d2dda(oc, 2, 3, 1, 2, ocface + 2 * ocres2, rts, rtf); + d2dda(oc, 3, 0, 0, 1, ocface + ocres2, rts, rtf); + d2dda(oc, 3, 0, 0, 2, ocface, rts, rtf); + d2dda(oc, 3, 0, 1, 2, ocface + 2 * ocres2, rts, rtf); + } + /* nothing todo with triangle..., just fills :) */ + filltriangle(oc, 0, 1, ocface + ocres2, ocmin, ocmax); + filltriangle(oc, 0, 2, ocface, ocmin, ocmax); + filltriangle(oc, 1, 2, ocface + 2 * ocres2, ocmin, ocmax); + + /* init static vars here */ + face_in_node(face, 0, 0, 0, rtf); + + for (x = ocmin[0]; x <= ocmax[0]; x++) { + a = oc->ocres * x; + for (y = ocmin[1]; y <= ocmax[1]; y++) { + if (ocface[a + y + ocres2]) { + b = oc->ocres * y + 2 * ocres2; + for (z = ocmin[2]; z <= ocmax[2]; z++) { + if (ocface[b + z] && ocface[a + z]) { + if (face_in_node(NULL, x, y, z, rtf)) + ocwrite(oc, face, RE_rayface_isQuad(face), x, y, z, rtf); + } + } + } + } + } + + /* same loops to clear octree, doubt it can be done smarter */ + for (x = ocmin[0]; x <= ocmax[0]; x++) { + a = oc->ocres * x; + for (y = ocmin[1]; y <= ocmax[1]; y++) { + /* x-y */ + ocface[a + y + ocres2] = 0; + + b = oc->ocres * y + 2 * ocres2; + for (z = ocmin[2]; z <= ocmax[2]; z++) { + /* y-z */ + ocface[b + z] = 0; + /* x-z */ + ocface[a + z] = 0; + } + } + } + } +} + +static void RE_rayobject_octree_done(RayObject *tree) +{ + Octree *oc = (Octree *)tree; + int c; + float t00, t01, t02; + int ocres2 = oc->ocres * oc->ocres; + + INIT_MINMAX(oc->min, oc->max); + + /* Calculate Bounding Box */ + for (c = 0; c < oc->ro_nodes_used; c++) + RE_rayobject_merge_bb(RE_rayobject_unalignRayFace(oc->ro_nodes[c]), oc->min, oc->max); + + /* Alloc memory */ + oc->adrbranch = (Branch **)MEM_callocN(sizeof(void *) * BRANCH_ARRAY, "octree branches"); + oc->adrnode = (Node **)MEM_callocN(sizeof(void *) * NODE_ARRAY, "octree nodes"); + + oc->adrbranch[0] = (Branch *)MEM_callocN(4096 * sizeof(Branch), "makeoctree"); + + /* the lookup table, per face, for which nodes to fill in */ + oc->ocface = (char *)MEM_callocN(3 * ocres2 + 8, "ocface"); + memset(oc->ocface, 0, 3 * ocres2); + + for (c = 0; c < 3; c++) { /* octree enlarge, still needed? */ + oc->min[c] -= 0.01f; + oc->max[c] += 0.01f; + } + + t00 = oc->max[0] - oc->min[0]; + t01 = oc->max[1] - oc->min[1]; + t02 = oc->max[2] - oc->min[2]; + + /* this minus 0.1 is old safety... seems to be needed? */ + oc->ocfacx = (oc->ocres - 0.1f) / t00; + oc->ocfacy = (oc->ocres - 0.1f) / t01; + oc->ocfacz = (oc->ocres - 0.1f) / t02; + + oc->ocsize = sqrtf(t00 * t00 + t01 * t01 + t02 * t02); /* global, max size octree */ + + for (c = 0; c < oc->ro_nodes_used; c++) { + octree_fill_rayface(oc, oc->ro_nodes[c]); + } + + MEM_freeN(oc->ocface); + oc->ocface = NULL; + MEM_freeN(oc->ro_nodes); + oc->ro_nodes = NULL; + +#if 0 + printf("%f %f - %f\n", oc->min[0], oc->max[0], oc->ocfacx); + printf("%f %f - %f\n", oc->min[1], oc->max[1], oc->ocfacy); + printf("%f %f - %f\n", oc->min[2], oc->max[2], oc->ocfacz); +#endif +} + +static void RE_rayobject_octree_bb(RayObject *tree, float *min, float *max) +{ + Octree *oc = (Octree *)tree; + DO_MINMAX(oc->min, min, max); + DO_MINMAX(oc->max, min, max); +} + +/* check all faces in this node */ +static int testnode(Octree *UNUSED(oc), Isect *is, Node *no, OcVal ocval) +{ + short nr = 0; + + /* return on any first hit */ + if (is->mode == RE_RAY_SHADOW) { + + for (; no; no = no->next) { + for (nr = 0; nr < 8; nr++) { + RayFace *face = no->v[nr]; + OcVal *ov = no->ov + nr; + + if (!face) break; + + if ( (ov->ocx & ocval.ocx) && (ov->ocy & ocval.ocy) && (ov->ocz & ocval.ocz) ) { + if (RE_rayobject_intersect(RE_rayobject_unalignRayFace(face), is) ) + return 1; + } + } + } + } + else { + /* else mirror or glass or shadowtra, return closest face */ + int found = 0; + + for (; no; no = no->next) { + for (nr = 0; nr < 8; nr++) { + RayFace *face = no->v[nr]; + OcVal *ov = no->ov + nr; + + if (!face) break; + + if ( (ov->ocx & ocval.ocx) && (ov->ocy & ocval.ocy) && (ov->ocz & ocval.ocz) ) { + if (RE_rayobject_intersect(RE_rayobject_unalignRayFace(face), is) ) { + found = 1; + } + } + } + } + + return found; + } + + return 0; +} + +/* find the Node for the octree coord x y z */ +static Node *ocread(Octree *oc, int x, int y, int z) +{ + Branch *br; + int oc1; + + x <<= 2; + y <<= 1; + + br = oc->adrbranch[0]; + + if (oc->ocres == 512) { + oc1 = ((x & 1024) + (y & 512) + (z & 256)) >> 8; + br = br->b[oc1]; + if (br == NULL) { + return NULL; + } + } + if (oc->ocres >= 256) { + oc1 = ((x & 512) + (y & 256) + (z & 128)) >> 7; + br = br->b[oc1]; + if (br == NULL) { + return NULL; + } + } + if (oc->ocres >= 128) { + oc1 = ((x & 256) + (y & 128) + (z & 64)) >> 6; + br = br->b[oc1]; + if (br == NULL) { + return NULL; + } + } + + oc1 = ((x & 128) + (y & 64) + (z & 32)) >> 5; + br = br->b[oc1]; + if (br) { + oc1 = ((x & 64) + (y & 32) + (z & 16)) >> 4; + br = br->b[oc1]; + if (br) { + oc1 = ((x & 32) + (y & 16) + (z & 8)) >> 3; + br = br->b[oc1]; + if (br) { + oc1 = ((x & 16) + (y & 8) + (z & 4)) >> 2; + br = br->b[oc1]; + if (br) { + oc1 = ((x & 8) + (y & 4) + (z & 2)) >> 1; + br = br->b[oc1]; + if (br) { + oc1 = ((x & 4) + (y & 2) + (z & 1)); + return (Node *)br->b[oc1]; + } + } + } + } + } + + return NULL; +} + +static int cliptest(float p, float q, float *u1, float *u2) +{ + float r; + + if (p < 0.0f) { + if (q < p) return 0; + else if (q < 0.0f) { + r = q / p; + if (r > *u2) return 0; + else if (r > *u1) *u1 = r; + } + } + else { + if (p > 0.0f) { + if (q < 0.0f) return 0; + else if (q < p) { + r = q / p; + if (r < *u1) return 0; + else if (r < *u2) *u2 = r; + } + } + else if (q < 0.0f) return 0; + } + return 1; +} + +/* extensive coherence checks/storage cancels out the benefit of it, and gives errors... we + * need better methods, sample code commented out below (ton) */ + +#if 0 + +in top : static int coh_nodes[16 * 16 * 16][6]; +in makeoctree : memset(coh_nodes, 0, sizeof(coh_nodes)); + +static void add_coherence_test(int ocx1, int ocx2, int ocy1, int ocy2, int ocz1, int ocz2) +{ + short *sp; + + sp = coh_nodes[(ocx2 & 15) + 16 * (ocy2 & 15) + 256 * (ocz2 & 15)]; + sp[0] = ocx1; sp[1] = ocy1; sp[2] = ocz1; + sp[3] = ocx2; sp[4] = ocy2; sp[5] = ocz2; + +} + +static int do_coherence_test(int ocx1, int ocx2, int ocy1, int ocy2, int ocz1, int ocz2) +{ + short *sp; + + sp = coh_nodes[(ocx2 & 15) + 16 * (ocy2 & 15) + 256 * (ocz2 & 15)]; + if (sp[0] == ocx1 && sp[1] == ocy1 && sp[2] == ocz1 && + sp[3] == ocx2 && sp[4] == ocy2 && sp[5] == ocz2) return 1; + return 0; +} + +#endif + +/* return 1: found valid intersection */ +/* starts with is->orig.face */ +static int RE_rayobject_octree_intersect(RayObject *tree, Isect *is) +{ + Octree *oc = (Octree *)tree; + Node *no; + OcVal ocval; + float vec1[3], vec2[3], start[3], end[3]; + float u1, u2, ox1, ox2, oy1, oy2, oz1, oz2; + float lambda_o, lambda_x, ldx, lambda_y, ldy, lambda_z, ldz, dda_lambda; + float o_lambda = 0; + int dx, dy, dz; + int xo, yo, zo, c1 = 0; + int ocx1, ocx2, ocy1, ocy2, ocz1, ocz2; + + /* clip with octree */ + if (oc->branchcount == 0) return 0; + + /* do this before intersect calls */ +#if 0 + is->facecontr = NULL; /* to check shared edge */ + is->obcontr = 0; + is->faceisect = is->isect = 0; /* shared edge, quad half flag */ + is->userdata = oc->userdata; +#endif + + copy_v3_v3(start, is->start); + madd_v3_v3v3fl(end, is->start, is->dir, is->dist); + ldx = is->dir[0] * is->dist; + o_lambda = is->dist; + u1 = 0.0f; + u2 = 1.0f; + + /* clip with octree cube */ + if (cliptest(-ldx, start[0] - oc->min[0], &u1, &u2)) { + if (cliptest(ldx, oc->max[0] - start[0], &u1, &u2)) { + ldy = is->dir[1] * is->dist; + if (cliptest(-ldy, start[1] - oc->min[1], &u1, &u2)) { + if (cliptest(ldy, oc->max[1] - start[1], &u1, &u2)) { + ldz = is->dir[2] * is->dist; + if (cliptest(-ldz, start[2] - oc->min[2], &u1, &u2)) { + if (cliptest(ldz, oc->max[2] - start[2], &u1, &u2)) { + c1 = 1; + if (u2 < 1.0f) { + end[0] = start[0] + u2 * ldx; + end[1] = start[1] + u2 * ldy; + end[2] = start[2] + u2 * ldz; + } + + if (u1 > 0.0f) { + start[0] += u1 * ldx; + start[1] += u1 * ldy; + start[2] += u1 * ldz; + } + } + } + } + } + } + } + + if (c1 == 0) return 0; + + /* reset static variables in ocread */ + //ocread(oc, oc->ocres, 0, 0); + + /* setup 3dda to traverse octree */ + ox1 = (start[0] - oc->min[0]) * oc->ocfacx; + oy1 = (start[1] - oc->min[1]) * oc->ocfacy; + oz1 = (start[2] - oc->min[2]) * oc->ocfacz; + ox2 = (end[0] - oc->min[0]) * oc->ocfacx; + oy2 = (end[1] - oc->min[1]) * oc->ocfacy; + oz2 = (end[2] - oc->min[2]) * oc->ocfacz; + + ocx1 = (int)ox1; + ocy1 = (int)oy1; + ocz1 = (int)oz1; + ocx2 = (int)ox2; + ocy2 = (int)oy2; + ocz2 = (int)oz2; + + if (ocx1 == ocx2 && ocy1 == ocy2 && ocz1 == ocz2) { + no = ocread(oc, ocx1, ocy1, ocz1); + if (no) { + /* exact intersection with node */ + vec1[0] = ox1; vec1[1] = oy1; vec1[2] = oz1; + vec2[0] = ox2; vec2[1] = oy2; vec2[2] = oz2; + calc_ocval_ray(&ocval, (float)ocx1, (float)ocy1, (float)ocz1, vec1, vec2); + if (testnode(oc, is, no, ocval) ) return 1; + } + } + else { + int found = 0; + //static int coh_ocx1, coh_ocx2, coh_ocy1, coh_ocy2, coh_ocz1, coh_ocz2; + float dox, doy, doz; + int eqval; + + /* calc lambda en ld */ + dox = ox1 - ox2; + doy = oy1 - oy2; + doz = oz1 - oz2; + + if (dox < -FLT_EPSILON) { + ldx = -1.0f / dox; + lambda_x = (ocx1 - ox1 + 1.0f) * ldx; + dx = 1; + } + else if (dox > FLT_EPSILON) { + ldx = 1.0f / dox; + lambda_x = (ox1 - ocx1) * ldx; + dx = -1; + } + else { + lambda_x = 1.0f; + ldx = 0; + dx = 0; + } + + if (doy < -FLT_EPSILON) { + ldy = -1.0f / doy; + lambda_y = (ocy1 - oy1 + 1.0f) * ldy; + dy = 1; + } + else if (doy > FLT_EPSILON) { + ldy = 1.0f / doy; + lambda_y = (oy1 - ocy1) * ldy; + dy = -1; + } + else { + lambda_y = 1.0f; + ldy = 0; + dy = 0; + } + + if (doz < -FLT_EPSILON) { + ldz = -1.0f / doz; + lambda_z = (ocz1 - oz1 + 1.0f) * ldz; + dz = 1; + } + else if (doz > FLT_EPSILON) { + ldz = 1.0f / doz; + lambda_z = (oz1 - ocz1) * ldz; + dz = -1; + } + else { + lambda_z = 1.0f; + ldz = 0; + dz = 0; + } + + xo = ocx1; yo = ocy1; zo = ocz1; + dda_lambda = min_fff(lambda_x, lambda_y, lambda_z); + + vec2[0] = ox1; + vec2[1] = oy1; + vec2[2] = oz1; + + /* this loop has been constructed to make sure the first and last node of ray + * are always included, even when dda_lambda==1.0f or larger */ + + while (true) { + + no = ocread(oc, xo, yo, zo); + if (no) { + + /* calculate ray intersection with octree node */ + copy_v3_v3(vec1, vec2); + // dox, y, z is negative + vec2[0] = ox1 - dda_lambda * dox; + vec2[1] = oy1 - dda_lambda * doy; + vec2[2] = oz1 - dda_lambda * doz; + calc_ocval_ray(&ocval, (float)xo, (float)yo, (float)zo, vec1, vec2); + + //is->dist = (u1 + dda_lambda * (u2 - u1)) * o_lambda; + if (testnode(oc, is, no, ocval) ) + found = 1; + + if (is->dist < (u1 + dda_lambda * (u2 - u1)) * o_lambda) + return found; + } + + + lambda_o = dda_lambda; + + /* traversing octree nodes need careful detection of smallest values, with proper + * exceptions for equal lambdas */ + eqval = (lambda_x == lambda_y); + if (lambda_y == lambda_z) eqval += 2; + if (lambda_x == lambda_z) eqval += 4; + + if (eqval) { // only 4 cases exist! + if (eqval == 7) { // x=y=z + xo += dx; lambda_x += ldx; + yo += dy; lambda_y += ldy; + zo += dz; lambda_z += ldz; + } + else if (eqval == 1) { // x=y + if (lambda_y < lambda_z) { + xo += dx; lambda_x += ldx; + yo += dy; lambda_y += ldy; + } + else { + zo += dz; lambda_z += ldz; + } + } + else if (eqval == 2) { // y=z + if (lambda_x < lambda_y) { + xo += dx; lambda_x += ldx; + } + else { + yo += dy; lambda_y += ldy; + zo += dz; lambda_z += ldz; + } + } + else { // x=z + if (lambda_y < lambda_x) { + yo += dy; lambda_y += ldy; + } + else { + xo += dx; lambda_x += ldx; + zo += dz; lambda_z += ldz; + } + } + } + else { // all three different, just three cases exist + eqval = (lambda_x < lambda_y); + if (lambda_y < lambda_z) eqval += 2; + if (lambda_x < lambda_z) eqval += 4; + + if (eqval == 7 || eqval == 5) { // x smallest + xo += dx; lambda_x += ldx; + } + else if (eqval == 2 || eqval == 6) { // y smallest + yo += dy; lambda_y += ldy; + } + else { // z smallest + zo += dz; lambda_z += ldz; + } + + } + + dda_lambda = min_fff(lambda_x, lambda_y, lambda_z); + if (dda_lambda == lambda_o) break; + /* to make sure the last node is always checked */ + if (lambda_o >= 1.0f) break; + } + } + + /* reached end, no intersections found */ + return 0; +} + + + diff --git a/source/blender/render/intern/raytrace/rayobject_qbvh.cpp b/source/blender/render/intern/raytrace/rayobject_qbvh.cpp new file mode 100644 index 00000000000..8e3dd87efd1 --- /dev/null +++ b/source/blender/render/intern/raytrace/rayobject_qbvh.cpp @@ -0,0 +1,160 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2009 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): André Pinto. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/render/intern/raytrace/rayobject_qbvh.cpp + * \ingroup render + */ + + +#include "MEM_guardedalloc.h" + +#include "BLI_utildefines.h" + +#include "vbvh.h" +#include "svbvh.h" +#include "reorganize.h" + +#ifdef __SSE__ + +#define DFS_STACK_SIZE 256 + +struct QBVHTree { + RayObject rayobj; + + SVBVHNode *root; + MemArena *node_arena; + + float cost; + RTBuilder *builder; +}; + + +template<> +void bvh_done<QBVHTree>(QBVHTree *obj) +{ + rtbuild_done(obj->builder, &obj->rayobj.control); + + //TODO find a away to exactly calculate the needed memory + MemArena *arena1 = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "qbvh arena"); + BLI_memarena_use_malloc(arena1); + + MemArena *arena2 = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "qbvh arena 2"); + BLI_memarena_use_malloc(arena2); + BLI_memarena_use_align(arena2, 16); + + //Build and optimize the tree + //TODO do this in 1 pass (half memory usage during building) + VBVHNode *root = BuildBinaryVBVH<VBVHNode>(arena1, &obj->rayobj.control).transform(obj->builder); + + if (RE_rayobjectcontrol_test_break(&obj->rayobj.control)) { + BLI_memarena_free(arena1); + BLI_memarena_free(arena2); + return; + } + + if (root) { + pushup_simd<VBVHNode, 4>(root); + obj->root = Reorganize_SVBVH<VBVHNode>(arena2).transform(root); + } + else + obj->root = NULL; + + //Free data + BLI_memarena_free(arena1); + + obj->node_arena = arena2; + obj->cost = 1.0; + + rtbuild_free(obj->builder); + obj->builder = NULL; +} + +template<int StackSize> +static int intersect(QBVHTree *obj, Isect *isec) +{ + //TODO renable hint support + if (RE_rayobject_isAligned(obj->root)) { + if (isec->mode == RE_RAY_SHADOW) + return svbvh_node_stack_raycast<StackSize, true>(obj->root, isec); + else + return svbvh_node_stack_raycast<StackSize, false>(obj->root, isec); + } + else + return RE_rayobject_intersect((RayObject *)obj->root, isec); +} + +template<class Tree> +static void bvh_hint_bb(Tree *tree, LCTSHint *hint, float *UNUSED(min), float *UNUSED(max)) +{ + //TODO renable hint support + { + hint->size = 0; + hint->stack[hint->size++] = (RayObject *)tree->root; + } +} +/* the cast to pointer function is needed to workarround gcc bug: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=11407 */ +template<class Tree, int STACK_SIZE> +static RayObjectAPI make_api() +{ + static RayObjectAPI api = + { + (RE_rayobject_raycast_callback) ((int (*)(Tree *, Isect *)) & intersect<STACK_SIZE>), + (RE_rayobject_add_callback) ((void (*)(Tree *, RayObject *)) & bvh_add<Tree>), + (RE_rayobject_done_callback) ((void (*)(Tree *)) & bvh_done<Tree>), + (RE_rayobject_free_callback) ((void (*)(Tree *)) & bvh_free<Tree>), + (RE_rayobject_merge_bb_callback)((void (*)(Tree *, float *, float *)) & bvh_bb<Tree>), + (RE_rayobject_cost_callback) ((float (*)(Tree *)) & bvh_cost<Tree>), + (RE_rayobject_hint_bb_callback) ((void (*)(Tree *, LCTSHint *, float *, float *)) & bvh_hint_bb<Tree>) + }; + + return api; +} + +template<class Tree> +RayObjectAPI *bvh_get_api(int maxstacksize) +{ + static RayObjectAPI bvh_api256 = make_api<Tree, 1024>(); + + if (maxstacksize <= 1024) return &bvh_api256; + assert(maxstacksize <= 256); + return NULL; +} + +RayObject *RE_rayobject_qbvh_create(int size) +{ + return bvh_create_tree<QBVHTree, DFS_STACK_SIZE>(size); +} + +#else + +RayObject *RE_rayobject_qbvh_create(int UNUSED(size)) +{ + puts("WARNING: SSE disabled at compile time\n"); + return NULL; +} + +#endif diff --git a/source/blender/render/intern/raytrace/rayobject_raycounter.cpp b/source/blender/render/intern/raytrace/rayobject_raycounter.cpp new file mode 100644 index 00000000000..429c47f1c0f --- /dev/null +++ b/source/blender/render/intern/raytrace/rayobject_raycounter.cpp @@ -0,0 +1,91 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2009 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): André Pinto. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/render/intern/raytrace/rayobject_raycounter.cpp + * \ingroup render + */ + + +#include "rayobject.h" +#include "raycounter.h" + +#ifdef RE_RAYCOUNTER + +void RE_RC_INFO(RayCounter *info) +{ + printf("----------- Raycast counter --------\n"); + printf("Rays total: %llu\n", info->raycast.test ); + printf("Rays hit: %llu\n", info->raycast.hit ); + printf("\n"); + printf("BB tests: %llu\n", info->bb.test ); + printf("BB hits: %llu\n", info->bb.hit ); + printf("\n"); + printf("SIMD BB tests: %llu\n", info->simd_bb.test ); + printf("SIMD BB hits: %llu\n", info->simd_bb.hit ); + printf("\n"); + printf("Primitives tests: %llu\n", info->faces.test ); + printf("Primitives hits: %llu\n", info->faces.hit ); + printf("------------------------------------\n"); + printf("Shadow last-hit tests per ray: %f\n", info->rayshadow_last_hit.test / ((float)info->raycast.test) ); + printf("Shadow last-hit hits per ray: %f\n", info->rayshadow_last_hit.hit / ((float)info->raycast.test) ); + printf("\n"); + printf("Hint tests per ray: %f\n", info->raytrace_hint.test / ((float)info->raycast.test) ); + printf("Hint hits per ray: %f\n", info->raytrace_hint.hit / ((float)info->raycast.test) ); + printf("\n"); + printf("BB tests per ray: %f\n", info->bb.test / ((float)info->raycast.test) ); + printf("BB hits per ray: %f\n", info->bb.hit / ((float)info->raycast.test) ); + printf("\n"); + printf("SIMD tests per ray: %f\n", info->simd_bb.test / ((float)info->raycast.test) ); + printf("SIMD hits per ray: %f\n", info->simd_bb.hit / ((float)info->raycast.test) ); + printf("\n"); + printf("Primitives tests per ray: %f\n", info->faces.test / ((float)info->raycast.test) ); + printf("Primitives hits per ray: %f\n", info->faces.hit / ((float)info->raycast.test) ); + printf("------------------------------------\n"); +} + +void RE_RC_MERGE(RayCounter *dest, RayCounter *tmp) +{ + dest->faces.test += tmp->faces.test; + dest->faces.hit += tmp->faces.hit; + + dest->bb.test += tmp->bb.test; + dest->bb.hit += tmp->bb.hit; + + dest->simd_bb.test += tmp->simd_bb.test; + dest->simd_bb.hit += tmp->simd_bb.hit; + + dest->raycast.test += tmp->raycast.test; + dest->raycast.hit += tmp->raycast.hit; + + dest->rayshadow_last_hit.test += tmp->rayshadow_last_hit.test; + dest->rayshadow_last_hit.hit += tmp->rayshadow_last_hit.hit; + + dest->raytrace_hint.test += tmp->raytrace_hint.test; + dest->raytrace_hint.hit += tmp->raytrace_hint.hit; +} + +#endif diff --git a/source/blender/render/intern/raytrace/rayobject_rtbuild.cpp b/source/blender/render/intern/raytrace/rayobject_rtbuild.cpp new file mode 100644 index 00000000000..51f89784674 --- /dev/null +++ b/source/blender/render/intern/raytrace/rayobject_rtbuild.cpp @@ -0,0 +1,531 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2009 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): André Pinto. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/render/intern/raytrace/rayobject_rtbuild.cpp + * \ingroup render + */ + + +#include <assert.h> +#include <stdlib.h> +#include <algorithm> + +#if __cplusplus >= 201103L +#include <cmath> +using std::isfinite; +#else +#include <math.h> +#endif + +#include "rayobject_rtbuild.h" + +#include "MEM_guardedalloc.h" + +#include "BLI_math.h" +#include "BLI_utildefines.h" + +static bool selected_node(RTBuilder::Object *node) +{ + return node->selected; +} + +static void rtbuild_init(RTBuilder *b) +{ + b->split_axis = -1; + b->primitives.begin = NULL; + b->primitives.end = NULL; + b->primitives.maxsize = 0; + b->depth = 0; + + for (int i = 0; i < RTBUILD_MAX_CHILDS; i++) + b->child_offset[i] = 0; + + for (int i = 0; i < 3; i++) + b->sorted_begin[i] = b->sorted_end[i] = NULL; + + INIT_MINMAX(b->bb, b->bb + 3); +} + +RTBuilder *rtbuild_create(int size) +{ + RTBuilder *builder = (RTBuilder *) MEM_mallocN(sizeof(RTBuilder), "RTBuilder"); + RTBuilder::Object *memblock = (RTBuilder::Object *)MEM_mallocN(sizeof(RTBuilder::Object) * size, "RTBuilder.objects"); + + + rtbuild_init(builder); + + builder->primitives.begin = builder->primitives.end = memblock; + builder->primitives.maxsize = size; + + for (int i = 0; i < 3; i++) { + builder->sorted_begin[i] = (RTBuilder::Object **)MEM_mallocN(sizeof(RTBuilder::Object *) * size, "RTBuilder.sorted_objects"); + builder->sorted_end[i] = builder->sorted_begin[i]; + } + + + return builder; +} + +void rtbuild_free(RTBuilder *b) +{ + if (b->primitives.begin) MEM_freeN(b->primitives.begin); + + for (int i = 0; i < 3; i++) + if (b->sorted_begin[i]) + MEM_freeN(b->sorted_begin[i]); + + MEM_freeN(b); +} + +void rtbuild_add(RTBuilder *b, RayObject *o) +{ + float bb[6]; + + assert(b->primitives.begin + b->primitives.maxsize != b->primitives.end); + + INIT_MINMAX(bb, bb + 3); + RE_rayobject_merge_bb(o, bb, bb + 3); + + /* skip objects with invalid bounding boxes, nan causes DO_MINMAX + * to do nothing, so we get these invalid values. this shouldn't + * happen usually, but bugs earlier in the pipeline can cause it. */ + if (bb[0] > bb[3] || bb[1] > bb[4] || bb[2] > bb[5]) + return; + /* skip objects with inf bounding boxes */ + if (!isfinite(bb[0]) || !isfinite(bb[1]) || !isfinite(bb[2])) + return; + if (!isfinite(bb[3]) || !isfinite(bb[4]) || !isfinite(bb[5])) + return; + /* skip objects with zero bounding box, they are of no use, and + * will give problems in rtbuild_heuristic_object_split later */ + if (bb[0] == bb[3] && bb[1] == bb[4] && bb[2] == bb[5]) + return; + + copy_v3_v3(b->primitives.end->bb, bb); + copy_v3_v3(b->primitives.end->bb + 3, bb + 3); + b->primitives.end->obj = o; + b->primitives.end->cost = RE_rayobject_cost(o); + + for (int i = 0; i < 3; i++) { + *(b->sorted_end[i]) = b->primitives.end; + b->sorted_end[i]++; + } + b->primitives.end++; +} + +int rtbuild_size(RTBuilder *b) +{ + return b->sorted_end[0] - b->sorted_begin[0]; +} + + +template<class Obj, int Axis> +static bool obj_bb_compare(const Obj &a, const Obj &b) +{ + if (a->bb[Axis] != b->bb[Axis]) + return a->bb[Axis] < b->bb[Axis]; + return a->obj < b->obj; +} + +template<class Item> +static void object_sort(Item *begin, Item *end, int axis) +{ + if (axis == 0) return std::sort(begin, end, obj_bb_compare<Item, 0> ); + if (axis == 1) return std::sort(begin, end, obj_bb_compare<Item, 1> ); + if (axis == 2) return std::sort(begin, end, obj_bb_compare<Item, 2> ); + assert(false); +} + +void rtbuild_done(RTBuilder *b, RayObjectControl *ctrl) +{ + for (int i = 0; i < 3; i++) { + if (b->sorted_begin[i]) { + if (RE_rayobjectcontrol_test_break(ctrl)) break; + object_sort(b->sorted_begin[i], b->sorted_end[i], i); + } + } +} + +RayObject *rtbuild_get_primitive(RTBuilder *b, int index) +{ + return b->sorted_begin[0][index]->obj; +} + +RTBuilder *rtbuild_get_child(RTBuilder *b, int child, RTBuilder *tmp) +{ + rtbuild_init(tmp); + + tmp->depth = b->depth + 1; + + for (int i = 0; i < 3; i++) + if (b->sorted_begin[i]) { + tmp->sorted_begin[i] = b->sorted_begin[i] + b->child_offset[child]; + tmp->sorted_end[i] = b->sorted_begin[i] + b->child_offset[child + 1]; + } + else { + tmp->sorted_begin[i] = NULL; + tmp->sorted_end[i] = NULL; + } + + return tmp; +} + +static void rtbuild_calc_bb(RTBuilder *b) +{ + if (b->bb[0] == 1.0e30f) { + for (RTBuilder::Object **index = b->sorted_begin[0]; index != b->sorted_end[0]; index++) + RE_rayobject_merge_bb( (*index)->obj, b->bb, b->bb + 3); + } +} + +void rtbuild_merge_bb(RTBuilder *b, float min[3], float max[3]) +{ + rtbuild_calc_bb(b); + DO_MIN(b->bb, min); + DO_MAX(b->bb + 3, max); +} + +#if 0 +int rtbuild_get_largest_axis(RTBuilder *b) +{ + rtbuild_calc_bb(b); + return bb_largest_axis(b->bb, b->bb + 3); +} + +//Left balanced tree +int rtbuild_mean_split(RTBuilder *b, int nchilds, int axis) +{ + int i; + int mleafs_per_child, Mleafs_per_child; + int tot_leafs = rtbuild_size(b); + int missing_leafs; + + long long s; + + assert(nchilds <= RTBUILD_MAX_CHILDS); + + //TODO optimize calc of leafs_per_child + for (s = nchilds; s < tot_leafs; s *= nchilds) ; + Mleafs_per_child = s / nchilds; + mleafs_per_child = Mleafs_per_child / nchilds; + + //split min leafs per child + b->child_offset[0] = 0; + for (i = 1; i <= nchilds; i++) + b->child_offset[i] = mleafs_per_child; + + //split remaining leafs + missing_leafs = tot_leafs - mleafs_per_child * nchilds; + for (i = 1; i <= nchilds; i++) + { + if (missing_leafs > Mleafs_per_child - mleafs_per_child) + { + b->child_offset[i] += Mleafs_per_child - mleafs_per_child; + missing_leafs -= Mleafs_per_child - mleafs_per_child; + } + else { + b->child_offset[i] += missing_leafs; + missing_leafs = 0; + break; + } + } + + //adjust for accumulative offsets + for (i = 1; i <= nchilds; i++) + b->child_offset[i] += b->child_offset[i - 1]; + + //Count created childs + for (i = nchilds; b->child_offset[i] == b->child_offset[i - 1]; i--) ; + split_leafs(b, b->child_offset, i, axis); + + assert(b->child_offset[0] == 0 && b->child_offset[i] == tot_leafs); + return i; +} + + +int rtbuild_mean_split_largest_axis(RTBuilder *b, int nchilds) +{ + int axis = rtbuild_get_largest_axis(b); + return rtbuild_mean_split(b, nchilds, axis); +} +#endif + +/* + * "separators" is an array of dim NCHILDS-1 + * and indicates where to cut the childs + */ +#if 0 +int rtbuild_median_split(RTBuilder *b, float *separators, int nchilds, int axis) +{ + int size = rtbuild_size(b); + + assert(nchilds <= RTBUILD_MAX_CHILDS); + if (size <= nchilds) + { + return rtbuild_mean_split(b, nchilds, axis); + } + else { + int i; + + b->split_axis = axis; + + //Calculate child offsets + b->child_offset[0] = 0; + for (i = 0; i < nchilds - 1; i++) + b->child_offset[i + 1] = split_leafs_by_plane(b, b->child_offset[i], size, separators[i]); + b->child_offset[nchilds] = size; + + for (i = 0; i < nchilds; i++) + if (b->child_offset[i + 1] - b->child_offset[i] == size) + return rtbuild_mean_split(b, nchilds, axis); + + return nchilds; + } +} + +int rtbuild_median_split_largest_axis(RTBuilder *b, int nchilds) +{ + int la, i; + float separators[RTBUILD_MAX_CHILDS]; + + rtbuild_calc_bb(b); + + la = bb_largest_axis(b->bb, b->bb + 3); + for (i = 1; i < nchilds; i++) + separators[i - 1] = (b->bb[la + 3] - b->bb[la]) * i / nchilds; + + return rtbuild_median_split(b, separators, nchilds, la); +} +#endif + +//Heuristics Object Splitter + + +struct SweepCost { + float bb[6]; + float cost; +}; + +/* Object Surface Area Heuristic splitter */ +int rtbuild_heuristic_object_split(RTBuilder *b, int nchilds) +{ + int size = rtbuild_size(b); + assert(nchilds == 2); + assert(size > 1); + int baxis = -1, boffset = 0; + + if (size > nchilds) { + if (b->depth > RTBUILD_MAX_SAH_DEPTH) { + // for degenerate cases we avoid running out of stack space + // by simply splitting the children in the middle + b->child_offset[0] = 0; + b->child_offset[1] = (size+1)/2; + b->child_offset[2] = size; + return 2; + } + + float bcost = FLT_MAX; + baxis = -1; + boffset = size / 2; + + SweepCost *sweep = (SweepCost *)MEM_mallocN(sizeof(SweepCost) * size, "RTBuilder.HeuristicSweep"); + + for (int axis = 0; axis < 3; axis++) { + SweepCost sweep_left; + + RTBuilder::Object **obj = b->sorted_begin[axis]; + +// float right_cost = 0; + for (int i = size - 1; i >= 0; i--) { + if (i == size - 1) { + copy_v3_v3(sweep[i].bb, obj[i]->bb); + copy_v3_v3(sweep[i].bb + 3, obj[i]->bb + 3); + sweep[i].cost = obj[i]->cost; + } + else { + sweep[i].bb[0] = min_ff(obj[i]->bb[0], sweep[i + 1].bb[0]); + sweep[i].bb[1] = min_ff(obj[i]->bb[1], sweep[i + 1].bb[1]); + sweep[i].bb[2] = min_ff(obj[i]->bb[2], sweep[i + 1].bb[2]); + sweep[i].bb[3] = max_ff(obj[i]->bb[3], sweep[i + 1].bb[3]); + sweep[i].bb[4] = max_ff(obj[i]->bb[4], sweep[i + 1].bb[4]); + sweep[i].bb[5] = max_ff(obj[i]->bb[5], sweep[i + 1].bb[5]); + sweep[i].cost = obj[i]->cost + sweep[i + 1].cost; + } +// right_cost += obj[i]->cost; + } + + sweep_left.bb[0] = obj[0]->bb[0]; + sweep_left.bb[1] = obj[0]->bb[1]; + sweep_left.bb[2] = obj[0]->bb[2]; + sweep_left.bb[3] = obj[0]->bb[3]; + sweep_left.bb[4] = obj[0]->bb[4]; + sweep_left.bb[5] = obj[0]->bb[5]; + sweep_left.cost = obj[0]->cost; + +// right_cost -= obj[0]->cost; if (right_cost < 0) right_cost = 0; + + for (int i = 1; i < size; i++) { + //Worst case heuristic (cost of each child is linear) + float hcost, left_side, right_side; + + // not using log seems to have no impact on raytracing perf, but + // makes tree construction quicker, left out for now to test (brecht) + // left_side = bb_area(sweep_left.bb, sweep_left.bb + 3) * (sweep_left.cost + logf((float)i)); + // right_side = bb_area(sweep[i].bb, sweep[i].bb + 3) * (sweep[i].cost + logf((float)size - i)); + left_side = bb_area(sweep_left.bb, sweep_left.bb + 3) * (sweep_left.cost); + right_side = bb_area(sweep[i].bb, sweep[i].bb + 3) * (sweep[i].cost); + hcost = left_side + right_side; + + assert(left_side >= 0); + assert(right_side >= 0); + + if (left_side > bcost) break; //No way we can find a better heuristic in this axis + + assert(hcost >= 0); + // this makes sure the tree built is the same whatever is the order of the sorting axis + if (hcost < bcost || (hcost == bcost && axis < baxis)) { + bcost = hcost; + baxis = axis; + boffset = i; + } + DO_MIN(obj[i]->bb, sweep_left.bb); + DO_MAX(obj[i]->bb + 3, sweep_left.bb + 3); + + sweep_left.cost += obj[i]->cost; +// right_cost -= obj[i]->cost; if (right_cost < 0) right_cost = 0; + } + + //assert(baxis >= 0 && baxis < 3); + if (!(baxis >= 0 && baxis < 3)) + baxis = 0; + } + + + MEM_freeN(sweep); + } + else if (size == 2) { + baxis = 0; + boffset = 1; + } + else if (size == 1) { + b->child_offset[0] = 0; + b->child_offset[1] = 1; + return 1; + } + + b->child_offset[0] = 0; + b->child_offset[1] = boffset; + b->child_offset[2] = size; + + + /* Adjust sorted arrays for childs */ + for (int i = 0; i < boffset; i++) b->sorted_begin[baxis][i]->selected = true; + for (int i = boffset; i < size; i++) b->sorted_begin[baxis][i]->selected = false; + for (int i = 0; i < 3; i++) + std::stable_partition(b->sorted_begin[i], b->sorted_end[i], selected_node); + + return nchilds; +} + +/* + * Helper code + * PARTITION code / used on mean-split + * basically this a std::nth_element (like on C++ STL algorithm) + */ +#if 0 +static void split_leafs(RTBuilder *b, int *nth, int partitions, int split_axis) +{ + int i; + b->split_axis = split_axis; + + for (i = 0; i < partitions - 1; i++) + { + assert(nth[i] < nth[i + 1] && nth[i + 1] < nth[partitions]); + + if (split_axis == 0) std::nth_element(b, nth[i], nth[i + 1], nth[partitions], obj_bb_compare<RTBuilder::Object, 0>); + if (split_axis == 1) std::nth_element(b, nth[i], nth[i + 1], nth[partitions], obj_bb_compare<RTBuilder::Object, 1>); + if (split_axis == 2) std::nth_element(b, nth[i], nth[i + 1], nth[partitions], obj_bb_compare<RTBuilder::Object, 2>); + } +} +#endif + +/* + * Bounding Box utils + */ +float bb_volume(const float min[3], const float max[3]) +{ + return (max[0] - min[0]) * (max[1] - min[1]) * (max[2] - min[2]); +} + +float bb_area(const float min[3], const float max[3]) +{ + float sub[3], a; + sub[0] = max[0] - min[0]; + sub[1] = max[1] - min[1]; + sub[2] = max[2] - min[2]; + + a = (sub[0] * sub[1] + sub[0] * sub[2] + sub[1] * sub[2]) * 2.0f; + /* used to have an assert() here on negative results + * however, in this case its likely some overflow or ffast math error. + * so just return 0.0f instead. */ + return a < 0.0f ? 0.0f : a; +} + +int bb_largest_axis(const float min[3], const float max[3]) +{ + float sub[3]; + + sub[0] = max[0] - min[0]; + sub[1] = max[1] - min[1]; + sub[2] = max[2] - min[2]; + if (sub[0] > sub[1]) { + if (sub[0] > sub[2]) + return 0; + else + return 2; + } + else { + if (sub[1] > sub[2]) + return 1; + else + return 2; + } +} + +/* only returns 0 if merging inner and outerbox would create a box larger than outer box */ +int bb_fits_inside(const float outer_min[3], const float outer_max[3], + const float inner_min[3], const float inner_max[3]) +{ + int i; + for (i = 0; i < 3; i++) + if (outer_min[i] > inner_min[i]) return 0; + + for (i = 0; i < 3; i++) + if (outer_max[i] < inner_max[i]) return 0; + + return 1; +} diff --git a/source/blender/render/intern/raytrace/rayobject_rtbuild.h b/source/blender/render/intern/raytrace/rayobject_rtbuild.h new file mode 100644 index 00000000000..fc42bc36d92 --- /dev/null +++ b/source/blender/render/intern/raytrace/rayobject_rtbuild.h @@ -0,0 +1,125 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2009 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): André Pinto. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/render/intern/raytrace/rayobject_rtbuild.h + * \ingroup render + */ + +#ifndef __RAYOBJECT_RTBUILD_H__ +#define __RAYOBJECT_RTBUILD_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "rayobject.h" + + +/* + * Ray Tree Builder + * this structs helps building any type of tree + * it contains several methods to organize/split nodes + * allowing to create a given tree on the fly. + * + * Idea is that other trees BVH, BIH can use this code to + * generate with simple calls, and then convert to the theirs + * specific structure on the fly. + */ +#define RTBUILD_MAX_CHILDS 32 +#define RTBUILD_MAX_SAH_DEPTH 256 + + +typedef struct RTBuilder { + struct Object { + RayObject *obj; + float cost; + float bb[6]; + int selected; + }; + + /* list to all primitives added in this tree */ + struct { + Object *begin, *end; + int maxsize; + } primitives; + + /* sorted list of rayobjects */ + struct Object **sorted_begin[3], **sorted_end[3]; + + /* axis used (if any) on the split method */ + int split_axis; + + /* child partitions calculated during splitting */ + int child_offset[RTBUILD_MAX_CHILDS + 1]; + +// int child_sorted_axis; /* -1 if not sorted */ + + float bb[6]; + + /* current depth */ + int depth; +} RTBuilder; + +/* used during creation */ +RTBuilder *rtbuild_create(int size); +void rtbuild_free(RTBuilder *b); +void rtbuild_add(RTBuilder *b, RayObject *o); +void rtbuild_done(RTBuilder *b, RayObjectControl *c); +void rtbuild_merge_bb(RTBuilder *b, float min[3], float max[3]); +int rtbuild_size(RTBuilder *b); + +RayObject *rtbuild_get_primitive(RTBuilder *b, int offset); + +/* used during tree reorganization */ +RTBuilder *rtbuild_get_child(RTBuilder *b, int child, RTBuilder *tmp); + +/* Calculates child partitions and returns number of efectively needed partitions */ +int rtbuild_get_largest_axis(RTBuilder *b); + +//Object partition +int rtbuild_mean_split(RTBuilder *b, int nchilds, int axis); +int rtbuild_mean_split_largest_axis(RTBuilder *b, int nchilds); + +int rtbuild_heuristic_object_split(RTBuilder *b, int nchilds); + +//Space partition +int rtbuild_median_split(RTBuilder *b, float *separators, int nchilds, int axis); +int rtbuild_median_split_largest_axis(RTBuilder *b, int nchilds); + + +/* bb utils */ +float bb_area(const float min[3], const float max[3]); +float bb_volume(const float min[3], const float max[3]); +int bb_largest_axis(const float min[3], const float max[3]); +int bb_fits_inside(const float outer_min[3], const float outer_max[3], + const float inner_min[3], const float inner_max[3]); + +#ifdef __cplusplus +} +#endif + +#endif /* __RAYOBJECT_RTBUILD_H__ */ diff --git a/source/blender/render/intern/raytrace/rayobject_svbvh.cpp b/source/blender/render/intern/raytrace/rayobject_svbvh.cpp new file mode 100644 index 00000000000..fcd692fac02 --- /dev/null +++ b/source/blender/render/intern/raytrace/rayobject_svbvh.cpp @@ -0,0 +1,192 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2009 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): André Pinto. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/render/intern/raytrace/rayobject_svbvh.cpp + * \ingroup render + */ + + +#include "MEM_guardedalloc.h" + +#include "BLI_utildefines.h" + +#include "vbvh.h" +#include "svbvh.h" +#include "reorganize.h" + +#ifdef __SSE__ + +#define DFS_STACK_SIZE 256 + +struct SVBVHTree { + RayObject rayobj; + + SVBVHNode *root; + MemArena *node_arena; + + float cost; + RTBuilder *builder; +}; + +/* + * Cost to test N childs + */ +struct PackCost { + float operator()(int n) + { + return (n / 4) + ((n % 4) > 2 ? 1 : n % 4); + } +}; + + +template<> +void bvh_done<SVBVHTree>(SVBVHTree *obj) +{ + rtbuild_done(obj->builder, &obj->rayobj.control); + + //TODO find a away to exactly calculate the needed memory + MemArena *arena1 = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "svbvh arena"); + BLI_memarena_use_malloc(arena1); + + MemArena *arena2 = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "svbvh arena2"); + BLI_memarena_use_malloc(arena2); + BLI_memarena_use_align(arena2, 16); + + //Build and optimize the tree + if (0) { + VBVHNode *root = BuildBinaryVBVH<VBVHNode>(arena1, &obj->rayobj.control).transform(obj->builder); + + if (RE_rayobjectcontrol_test_break(&obj->rayobj.control)) { + BLI_memarena_free(arena1); + BLI_memarena_free(arena2); + return; + } + + reorganize(root); + remove_useless(root, &root); + bvh_refit(root); + + pushup(root); + pushdown(root); + pushup_simd<VBVHNode, 4>(root); + + obj->root = Reorganize_SVBVH<VBVHNode>(arena2).transform(root); + } + else { + //Finds the optimal packing of this tree using a given cost model + //TODO this uses quite a lot of memory, find ways to reduce memory usage during building + OVBVHNode *root = BuildBinaryVBVH<OVBVHNode>(arena1, &obj->rayobj.control).transform(obj->builder); + + if (RE_rayobjectcontrol_test_break(&obj->rayobj.control)) { + BLI_memarena_free(arena1); + BLI_memarena_free(arena2); + return; + } + + if (root) { + VBVH_optimalPackSIMD<OVBVHNode, PackCost>(PackCost()).transform(root); + obj->root = Reorganize_SVBVH<OVBVHNode>(arena2).transform(root); + } + else + obj->root = NULL; + } + + //Free data + BLI_memarena_free(arena1); + + obj->node_arena = arena2; + obj->cost = 1.0; + + rtbuild_free(obj->builder); + obj->builder = NULL; +} + +template<int StackSize> +static int intersect(SVBVHTree *obj, Isect *isec) +{ + //TODO renable hint support + if (RE_rayobject_isAligned(obj->root)) { + if (isec->mode == RE_RAY_SHADOW) + return svbvh_node_stack_raycast<StackSize, true>(obj->root, isec); + else + return svbvh_node_stack_raycast<StackSize, false>(obj->root, isec); + } + else + return RE_rayobject_intersect( (RayObject *) obj->root, isec); +} + +template<class Tree> +static void bvh_hint_bb(Tree *tree, LCTSHint *hint, float *UNUSED(min), float *UNUSED(max)) +{ + //TODO renable hint support + { + hint->size = 0; + hint->stack[hint->size++] = (RayObject *)tree->root; + } +} +/* the cast to pointer function is needed to workarround gcc bug: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=11407 */ +template<class Tree, int STACK_SIZE> +static RayObjectAPI make_api() +{ + static RayObjectAPI api = + { + (RE_rayobject_raycast_callback) ((int (*)(Tree *, Isect *)) & intersect<STACK_SIZE>), + (RE_rayobject_add_callback) ((void (*)(Tree *, RayObject *)) & bvh_add<Tree>), + (RE_rayobject_done_callback) ((void (*)(Tree *)) & bvh_done<Tree>), + (RE_rayobject_free_callback) ((void (*)(Tree *)) & bvh_free<Tree>), + (RE_rayobject_merge_bb_callback)((void (*)(Tree *, float *, float *)) & bvh_bb<Tree>), + (RE_rayobject_cost_callback) ((float (*)(Tree *)) & bvh_cost<Tree>), + (RE_rayobject_hint_bb_callback) ((void (*)(Tree *, LCTSHint *, float *, float *)) & bvh_hint_bb<Tree>) + }; + + return api; +} + +template<class Tree> +static RayObjectAPI *bvh_get_api(int maxstacksize) +{ + static RayObjectAPI bvh_api256 = make_api<Tree, 1024>(); + + if (maxstacksize <= 1024) return &bvh_api256; + assert(maxstacksize <= 256); + return NULL; +} + +RayObject *RE_rayobject_svbvh_create(int size) +{ + return bvh_create_tree<SVBVHTree, DFS_STACK_SIZE>(size); +} + +#else + +RayObject *RE_rayobject_svbvh_create(int UNUSED(size)) +{ + puts("WARNING: SSE disabled at compile time\n"); + return NULL; +} + +#endif diff --git a/source/blender/render/intern/raytrace/rayobject_vbvh.cpp b/source/blender/render/intern/raytrace/rayobject_vbvh.cpp new file mode 100644 index 00000000000..b63a11047dd --- /dev/null +++ b/source/blender/render/intern/raytrace/rayobject_vbvh.cpp @@ -0,0 +1,206 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2009 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): André Pinto. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/render/intern/raytrace/rayobject_vbvh.cpp + * \ingroup render + */ + + +int tot_pushup = 0; +int tot_pushdown = 0; +int tot_hints = 0; + +#include <assert.h> + +#include "MEM_guardedalloc.h" + +#include "BLI_math.h" +#include "BLI_memarena.h" +#include "BLI_utildefines.h" + +#include "BKE_global.h" + +#include "rayintersection.h" +#include "rayobject.h" +#include "rayobject_rtbuild.h" + +#include "reorganize.h" +#include "bvh.h" +#include "vbvh.h" + +#include <queue> +#include <algorithm> + +#define DFS_STACK_SIZE 256 + +struct VBVHTree { + RayObject rayobj; + VBVHNode *root; + MemArena *node_arena; + float cost; + RTBuilder *builder; +}; + +/* + * Cost to test N childs + */ +struct PackCost { + float operator()(int n) + { + return n; + } +}; + +template<> +void bvh_done<VBVHTree>(VBVHTree *obj) +{ + rtbuild_done(obj->builder, &obj->rayobj.control); + + //TODO find a away to exactly calculate the needed memory + MemArena *arena1 = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "vbvh arena"); + BLI_memarena_use_malloc(arena1); + + //Build and optimize the tree + if (1) { + VBVHNode *root = BuildBinaryVBVH<VBVHNode>(arena1, &obj->rayobj.control).transform(obj->builder); + if (RE_rayobjectcontrol_test_break(&obj->rayobj.control)) { + BLI_memarena_free(arena1); + return; + } + + if (root) { + reorganize(root); + remove_useless(root, &root); + bvh_refit(root); + + pushup(root); + pushdown(root); + obj->root = root; + } + else + obj->root = NULL; + } + else { + /* TODO */ +#if 0 + MemArena *arena2 = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "vbvh arena2"); + BLI_memarena_use_malloc(arena2); + + //Finds the optimal packing of this tree using a given cost model + //TODO this uses quite a lot of memory, find ways to reduce memory usage during building + OVBVHNode *root = BuildBinaryVBVH<OVBVHNode>(arena2).transform(obj->builder); + VBVH_optimalPackSIMD<OVBVHNode, PackCost>(PackCost()).transform(root); + obj->root = Reorganize_VBVH<OVBVHNode>(arena1).transform(root); + + BLI_memarena_free(arena2); +#endif + } + + //Cleanup + rtbuild_free(obj->builder); + obj->builder = NULL; + + obj->node_arena = arena1; + obj->cost = 1.0; +} + +template<int StackSize> +static int intersect(VBVHTree *obj, Isect *isec) +{ + //TODO renable hint support + if (RE_rayobject_isAligned(obj->root)) { + if (isec->mode == RE_RAY_SHADOW) + return bvh_node_stack_raycast<VBVHNode, StackSize, false, true>(obj->root, isec); + else + return bvh_node_stack_raycast<VBVHNode, StackSize, false, false>(obj->root, isec); + } + else + return RE_rayobject_intersect( (RayObject *) obj->root, isec); +} + +template<class Tree> +static void bvh_hint_bb(Tree *tree, LCTSHint *hint, float *UNUSED(min), float *UNUSED(max)) +{ + //TODO renable hint support + { + hint->size = 0; + hint->stack[hint->size++] = (RayObject *)tree->root; + } +} + +#if 0 /* UNUSED */ +static void bfree(VBVHTree *tree) +{ + if (tot_pushup + tot_pushdown + tot_hints + tot_moves) { + if (G.debug & G_DEBUG) { + printf("tot pushups: %d\n", tot_pushup); + printf("tot pushdowns: %d\n", tot_pushdown); + printf("tot moves: %d\n", tot_moves); + printf("tot hints created: %d\n", tot_hints); + } + + tot_pushup = 0; + tot_pushdown = 0; + tot_hints = 0; + tot_moves = 0; + } + bvh_free(tree); +} +#endif + +/* the cast to pointer function is needed to workarround gcc bug: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=11407 */ +template<class Tree, int STACK_SIZE> +static RayObjectAPI make_api() +{ + static RayObjectAPI api = + { + (RE_rayobject_raycast_callback) ((int (*)(Tree *, Isect *)) & intersect<STACK_SIZE>), + (RE_rayobject_add_callback) ((void (*)(Tree *, RayObject *)) & bvh_add<Tree>), + (RE_rayobject_done_callback) ((void (*)(Tree *)) & bvh_done<Tree>), + (RE_rayobject_free_callback) ((void (*)(Tree *)) & bvh_free<Tree>), + (RE_rayobject_merge_bb_callback)((void (*)(Tree *, float *, float *)) & bvh_bb<Tree>), + (RE_rayobject_cost_callback) ((float (*)(Tree *)) & bvh_cost<Tree>), + (RE_rayobject_hint_bb_callback) ((void (*)(Tree *, LCTSHint *, float *, float *)) & bvh_hint_bb<Tree>) + }; + + return api; +} + +template<class Tree> +RayObjectAPI *bvh_get_api(int maxstacksize) +{ + static RayObjectAPI bvh_api256 = make_api<Tree, 1024>(); + + if (maxstacksize <= 1024) return &bvh_api256; + assert(maxstacksize <= 256); + return 0; +} + +RayObject *RE_rayobject_vbvh_create(int size) +{ + return bvh_create_tree<VBVHTree, DFS_STACK_SIZE>(size); +} diff --git a/source/blender/render/intern/raytrace/reorganize.h b/source/blender/render/intern/raytrace/reorganize.h new file mode 100644 index 00000000000..3fdd3363edb --- /dev/null +++ b/source/blender/render/intern/raytrace/reorganize.h @@ -0,0 +1,513 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2009 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): André Pinto. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/render/intern/raytrace/reorganize.h + * \ingroup render + */ + + +#include <float.h> +#include <math.h> +#include <stdio.h> + +#include <algorithm> +#include <queue> +#include <vector> + +#include "BKE_global.h" + +#ifdef _WIN32 +# ifdef INFINITY +# undef INFINITY +# endif +# define INFINITY FLT_MAX // in mingw math.h: (1.0F/0.0F). This generates compile error, though. +#endif + +extern int tot_pushup; +extern int tot_pushdown; + +#if !defined(INFINITY) && defined(HUGE_VAL) +#define INFINITY HUGE_VAL +#endif + +template<class Node> +static bool node_fits_inside(Node *a, Node *b) +{ + return bb_fits_inside(b->bb, b->bb + 3, a->bb, a->bb + 3); +} + +template<class Node> +static void reorganize_find_fittest_parent(Node *tree, Node *node, std::pair<float, Node *> &cost) +{ + std::queue<Node *> q; + q.push(tree); + + while (!q.empty()) { + Node *parent = q.front(); + q.pop(); + + if (parent == node) continue; + if (node_fits_inside(node, parent) && RE_rayobject_isAligned(parent->child) ) { + float pcost = bb_area(parent->bb, parent->bb + 3); + cost = std::min(cost, std::make_pair(pcost, parent) ); + for (Node *child = parent->child; child; child = child->sibling) + q.push(child); + } + } +} + +template<class Node> +static void reorganize(Node *root) +{ + std::queue<Node *> q; + + q.push(root); + while (!q.empty()) { + Node *node = q.front(); + q.pop(); + + if (RE_rayobject_isAligned(node->child)) { + for (Node **prev = &node->child; *prev; ) { + assert(RE_rayobject_isAligned(*prev)); + q.push(*prev); + + std::pair<float, Node *> best(FLT_MAX, root); + reorganize_find_fittest_parent(root, *prev, best); + + if (best.second == node) { + //Already inside the fitnest BB + prev = &(*prev)->sibling; + } + else { + Node *tmp = *prev; + *prev = (*prev)->sibling; + + tmp->sibling = best.second->child; + best.second->child = tmp; + } + + + } + } + if (node != root) { + } + } +} + +/* + * Prunes useless nodes from trees: + * erases nodes with total amount of primitives = 0 + * prunes nodes with only one child (except if that child is a primitive) + */ +template<class Node> +static void remove_useless(Node *node, Node **new_node) +{ + if (RE_rayobject_isAligned(node->child) ) { + + for (Node **prev = &node->child; *prev; ) { + Node *next = (*prev)->sibling; + remove_useless(*prev, prev); + if (*prev == NULL) + *prev = next; + else { + (*prev)->sibling = next; + prev = &((*prev)->sibling); + } + } + } + if (node->child) { + if (RE_rayobject_isAligned(node->child) && node->child->sibling == 0) + *new_node = node->child; + } + else if (node->child == NULL) { + *new_node = NULL; + } +} + +/* + * Minimizes expected number of BBtest by colapsing nodes + * it uses surface area heuristic for determining whether a node should be colapsed + */ +template<class Node> +static void pushup(Node *parent) +{ + if (is_leaf(parent)) return; + + float p_area = bb_area(parent->bb, parent->bb + 3); + Node **prev = &parent->child; + for (Node *child = parent->child; RE_rayobject_isAligned(child) && child; ) { + const float c_area = bb_area(child->bb, child->bb + 3); + const int nchilds = count_childs(child); + float original_cost = ((p_area != 0.0f) ? (c_area / p_area) * nchilds : 1.0f) + 1; + float flatten_cost = nchilds; + if (flatten_cost < original_cost && nchilds >= 2) { + append_sibling(child, child->child); + child = child->sibling; + *prev = child; + +// *prev = child->child; +// append_sibling( *prev, child->sibling ); +// child = *prev; + tot_pushup++; + } + else { + *prev = child; + prev = &(*prev)->sibling; + child = *prev; + } + } + + for (Node *child = parent->child; RE_rayobject_isAligned(child) && child; child = child->sibling) + pushup(child); +} + +/* + * try to optimize number of childs to be a multiple of SSize + */ +template<class Node, int SSize> +static void pushup_simd(Node *parent) +{ + if (is_leaf(parent)) return; + + int n = count_childs(parent); + + Node **prev = &parent->child; + for (Node *child = parent->child; RE_rayobject_isAligned(child) && child; ) { + int cn = count_childs(child); + if (cn - 1 <= (SSize - (n % SSize) ) % SSize && RE_rayobject_isAligned(child->child) ) { + n += (cn - 1); + append_sibling(child, child->child); + child = child->sibling; + *prev = child; + } + else { + *prev = child; + prev = &(*prev)->sibling; + child = *prev; + } + } + + for (Node *child = parent->child; RE_rayobject_isAligned(child) && child; child = child->sibling) + pushup_simd<Node, SSize>(child); +} + + +/* + * Pushdown + * makes sure no child fits inside any of its sibling + */ +template<class Node> +static void pushdown(Node *parent) +{ + Node **s_child = &parent->child; + Node *child = parent->child; + + while (child && RE_rayobject_isAligned(child)) { + Node *next = child->sibling; + Node **next_s_child = &child->sibling; + + //assert(bb_fits_inside(parent->bb, parent->bb+3, child->bb, child->bb+3)); + + for (Node *i = parent->child; RE_rayobject_isAligned(i) && i; i = i->sibling) + if (child != i && bb_fits_inside(i->bb, i->bb + 3, child->bb, child->bb + 3) && RE_rayobject_isAligned(i->child)) { +// todo optimize (should the one with the smallest area?) +// float ia = bb_area(i->bb, i->bb+3) +// if (child->i) + *s_child = child->sibling; + child->sibling = i->child; + i->child = child; + next_s_child = s_child; + + tot_pushdown++; + break; + } + child = next; + s_child = next_s_child; + } + + for (Node *i = parent->child; RE_rayobject_isAligned(i) && i; i = i->sibling) { + pushdown(i); + } +} + + +/* + * BVH refit + * readjust nodes BB (useful if nodes childs where modified) + */ +template<class Node> +static float bvh_refit(Node *node) +{ + if (is_leaf(node)) return 0; + if (is_leaf(node->child)) return 0; + + float total = 0; + + for (Node *child = node->child; child; child = child->sibling) + total += bvh_refit(child); + + float old_area = bb_area(node->bb, node->bb + 3); + INIT_MINMAX(node->bb, node->bb + 3); + for (Node *child = node->child; child; child = child->sibling) { + DO_MIN(child->bb, node->bb); + DO_MAX(child->bb + 3, node->bb + 3); + } + total += old_area - bb_area(node->bb, node->bb + 3); + return total; +} + + +/* + * this finds the best way to packing a tree according to a given test cost function + * with the purpose to reduce the expected cost (eg.: number of BB tests). + */ +#include <vector> +#define MAX_CUT_SIZE 4 /* svbvh assumes max 4 children! */ +#define MAX_OPTIMIZE_CHILDS MAX_CUT_SIZE + +#define CUT_SIZE_IS_VALID(cut_size) ((cut_size) < MAX_CUT_SIZE && (cut_size) >= 0) +#define CUT_SIZE_INVALID -1 + + +struct OVBVHNode { + float bb[6]; + + OVBVHNode *child; + OVBVHNode *sibling; + + /* + * Returns min cost to represent the subtree starting at the given node, + * allowing it to have a given cutsize + */ + float cut_cost[MAX_CUT_SIZE]; + float get_cost(int cutsize) + { + assert(CUT_SIZE_IS_VALID(cutsize - 1)); + return cut_cost[cutsize - 1]; + } + + /* + * This saves the cut size of this child, when parent is reaching + * its minimum cut with the given cut size + */ + int cut_size[MAX_CUT_SIZE]; + int get_cut_size(int parent_cut_size) + { + assert(CUT_SIZE_IS_VALID(parent_cut_size - 1)); + return cut_size[parent_cut_size - 1]; + } + + /* + * Reorganize the node based on calculated cut costs + */ + int best_cutsize; + void set_cut(int cutsize, OVBVHNode ***cut) + { + if (cutsize == 1) { + **cut = this; + *cut = &(**cut)->sibling; + } + else { + if (cutsize > MAX_CUT_SIZE) { + for (OVBVHNode *child = this->child; child && RE_rayobject_isAligned(child); child = child->sibling) { + child->set_cut(1, cut); + cutsize--; + } + assert(cutsize == 0); + } + else { + for (OVBVHNode *child = this->child; child && RE_rayobject_isAligned(child); child = child->sibling) { + child->set_cut(child->get_cut_size(cutsize), cut); + } + } + } + } + + void optimize() + { + if (RE_rayobject_isAligned(this->child)) { + //Calc new childs + if (this->best_cutsize != CUT_SIZE_INVALID) { + OVBVHNode **cut = &(this->child); + set_cut(this->best_cutsize, &cut); + *cut = NULL; + } + + //Optimize new childs + for (OVBVHNode *child = this->child; child && RE_rayobject_isAligned(child); child = child->sibling) + child->optimize(); + } + } +}; + +/* + * Calculates an optimal SIMD packing + * + */ +template<class Node, class TestCost> +struct VBVH_optimalPackSIMD { + TestCost testcost; + + VBVH_optimalPackSIMD(TestCost testcost) + { + this->testcost = testcost; + } + + /* + * calc best cut on a node + */ + struct calc_best { + Node *child[MAX_OPTIMIZE_CHILDS]; + float child_hit_prob[MAX_OPTIMIZE_CHILDS]; + + calc_best(Node *node) + { + int nchilds = 0; + //Fetch childs and needed data + { + float parent_area = bb_area(node->bb, node->bb + 3); + for (Node *child = node->child; child && RE_rayobject_isAligned(child); child = child->sibling) { + this->child[nchilds] = child; + this->child_hit_prob[nchilds] = (parent_area != 0.0f) ? bb_area(child->bb, child->bb + 3) / parent_area : 1.0f; + nchilds++; + } + + assert(nchilds >= 2 && nchilds <= MAX_OPTIMIZE_CHILDS); + } + + + //Build DP table to find minimum cost to represent this node with a given cutsize + int bt[MAX_OPTIMIZE_CHILDS + 1][MAX_CUT_SIZE + 1]; //backtrace table + float cost[MAX_OPTIMIZE_CHILDS + 1][MAX_CUT_SIZE + 1]; //cost table (can be reduced to float[2][MAX_CUT_COST]) + + for (int i = 0; i <= nchilds; i++) { + for (int j = 0; j <= MAX_CUT_SIZE; j++) { + cost[i][j] = INFINITY; + } + } + + cost[0][0] = 0; + + for (int i = 1; i <= nchilds; i++) { + for (int size = i - 1; size /*+(nchilds-i)*/ <= MAX_CUT_SIZE; size++) { + for (int cut = 1; cut + size /*+(nchilds-i)*/ <= MAX_CUT_SIZE; cut++) { + float new_cost = cost[i - 1][size] + child_hit_prob[i - 1] * child[i - 1]->get_cost(cut); + if (new_cost < cost[i][size + cut]) { + cost[i][size + cut] = new_cost; + bt[i][size + cut] = cut; + } + } + } + } + + /* Save the ways to archive the minimum cost with a given cutsize */ + for (int i = nchilds; i <= MAX_CUT_SIZE; i++) { + node->cut_cost[i - 1] = cost[nchilds][i]; + if (cost[nchilds][i] < INFINITY) { + int current_size = i; + for (int j = nchilds; j > 0; j--) { + child[j - 1]->cut_size[i - 1] = bt[j][current_size]; + current_size -= bt[j][current_size]; + } + } + } + } + }; + + void calc_costs(Node *node) + { + + if (RE_rayobject_isAligned(node->child) ) { + int nchilds = 0; + for (Node *child = node->child; child && RE_rayobject_isAligned(child); child = child->sibling) { + calc_costs(child); + nchilds++; + } + + for (int i = 0; i < MAX_CUT_SIZE; i++) + node->cut_cost[i] = INFINITY; + + //We are not allowed to look on nodes with with so many childs + if (nchilds > MAX_CUT_SIZE) { + float cost = 0; + + float parent_area = bb_area(node->bb, node->bb + 3); + for (Node *child = node->child; child && RE_rayobject_isAligned(child); child = child->sibling) { + cost += ((parent_area != 0.0f) ? (bb_area(child->bb, child->bb + 3) / parent_area) : 1.0f) * child->get_cost(1); + } + + cost += testcost(nchilds); + node->cut_cost[0] = cost; + node->best_cutsize = nchilds; + } + else { + calc_best calc(node); + + //calc expected cost if we optimaly pack this node + for (int cutsize = nchilds; cutsize <= MAX_CUT_SIZE; cutsize++) { + float m = node->get_cost(cutsize) + testcost(cutsize); + if (m < node->cut_cost[0]) { + node->cut_cost[0] = m; + node->best_cutsize = cutsize; + } + } + } + + if (node->cut_cost[0] == INFINITY) { + node->best_cutsize = CUT_SIZE_INVALID; + } + } + else { + node->cut_cost[0] = 1.0f; + for (int i = 1; i < MAX_CUT_SIZE; i++) + node->cut_cost[i] = INFINITY; + + /* node->best_cutsize can remain unset here */ + } + } + + Node *transform(Node *node) + { + if (RE_rayobject_isAligned(node->child)) { +#ifdef DEBUG + static int num = 0; + bool first = false; + if (num == 0) { num++; first = true; } +#endif + + calc_costs(node); + +#ifdef DEBUG + if (first && G.debug) { + printf("expected cost = %f (%d)\n", node->cut_cost[0], node->best_cutsize); + } +#endif + node->optimize(); + } + return node; + } +}; diff --git a/source/blender/render/intern/raytrace/svbvh.h b/source/blender/render/intern/raytrace/svbvh.h new file mode 100644 index 00000000000..0a5690deb46 --- /dev/null +++ b/source/blender/render/intern/raytrace/svbvh.h @@ -0,0 +1,317 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2009 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): André Pinto. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/render/intern/raytrace/svbvh.h + * \ingroup render + */ + +#ifndef __SVBVH_H__ +#define __SVBVH_H__ + +#ifdef __SSE__ + +#include "bvh.h" +#include "BLI_memarena.h" +#include <algorithm> + +struct SVBVHNode { + float child_bb[24]; + SVBVHNode *child[4]; + int nchilds; +}; + +static int svbvh_bb_intersect_test_simd4(const Isect *isec, const __m128 *bb_group) +{ + const __m128 tmin0 = _mm_setzero_ps(); + const __m128 tmax0 = _mm_set_ps1(isec->dist); + + const __m128 start0 = _mm_set_ps1(isec->start[0]); + const __m128 start1 = _mm_set_ps1(isec->start[1]); + const __m128 start2 = _mm_set_ps1(isec->start[2]); + const __m128 sub0 = _mm_sub_ps(bb_group[isec->bv_index[0]], start0); + const __m128 sub1 = _mm_sub_ps(bb_group[isec->bv_index[1]], start0); + const __m128 sub2 = _mm_sub_ps(bb_group[isec->bv_index[2]], start1); + const __m128 sub3 = _mm_sub_ps(bb_group[isec->bv_index[3]], start1); + const __m128 sub4 = _mm_sub_ps(bb_group[isec->bv_index[4]], start2); + const __m128 sub5 = _mm_sub_ps(bb_group[isec->bv_index[5]], start2); + const __m128 idot_axis0 = _mm_set_ps1(isec->idot_axis[0]); + const __m128 idot_axis1 = _mm_set_ps1(isec->idot_axis[1]); + const __m128 idot_axis2 = _mm_set_ps1(isec->idot_axis[2]); + const __m128 mul0 = _mm_mul_ps(sub0, idot_axis0); + const __m128 mul1 = _mm_mul_ps(sub1, idot_axis0); + const __m128 mul2 = _mm_mul_ps(sub2, idot_axis1); + const __m128 mul3 = _mm_mul_ps(sub3, idot_axis1); + const __m128 mul4 = _mm_mul_ps(sub4, idot_axis2); + const __m128 mul5 = _mm_mul_ps(sub5, idot_axis2); + const __m128 tmin1 = _mm_max_ps(tmin0, mul0); + const __m128 tmax1 = _mm_min_ps(tmax0, mul1); + const __m128 tmin2 = _mm_max_ps(tmin1, mul2); + const __m128 tmax2 = _mm_min_ps(tmax1, mul3); + const __m128 tmin3 = _mm_max_ps(tmin2, mul4); + const __m128 tmax3 = _mm_min_ps(tmax2, mul5); + + return _mm_movemask_ps(_mm_cmpge_ps(tmax3, tmin3)); +} + +static int svbvh_bb_intersect_test(const Isect *isec, const float *_bb) +{ + const float *bb = _bb; + + float t1x = (bb[isec->bv_index[0]] - isec->start[0]) * isec->idot_axis[0]; + float t2x = (bb[isec->bv_index[1]] - isec->start[0]) * isec->idot_axis[0]; + float t1y = (bb[isec->bv_index[2]] - isec->start[1]) * isec->idot_axis[1]; + float t2y = (bb[isec->bv_index[3]] - isec->start[1]) * isec->idot_axis[1]; + float t1z = (bb[isec->bv_index[4]] - isec->start[2]) * isec->idot_axis[2]; + float t2z = (bb[isec->bv_index[5]] - isec->start[2]) * isec->idot_axis[2]; + + RE_RC_COUNT(isec->raycounter->bb.test); + + if (t1x > t2y || t2x < t1y || t1x > t2z || t2x < t1z || t1y > t2z || t2y < t1z) return 0; + if (t2x < 0.0f || t2y < 0.0f || t2z < 0.0f) return 0; + if (t1x > isec->dist || t1y > isec->dist || t1z > isec->dist) return 0; + + RE_RC_COUNT(isec->raycounter->bb.hit); + + return 1; +} + +static bool svbvh_node_is_leaf(const SVBVHNode *node) +{ + return !RE_rayobject_isAligned(node); +} + +template<int MAX_STACK_SIZE, bool SHADOW> +static int svbvh_node_stack_raycast(SVBVHNode *root, Isect *isec) +{ + SVBVHNode *stack[MAX_STACK_SIZE], *node; + int hit = 0, stack_pos = 0; + + stack[stack_pos++] = root; + + while (stack_pos) { + node = stack[--stack_pos]; + + if (!svbvh_node_is_leaf(node)) { + int nchilds = node->nchilds; + + if (nchilds == 4) { + float *child_bb = node->child_bb; + int res = svbvh_bb_intersect_test_simd4(isec, ((__m128 *) (child_bb))); + SVBVHNode **child = node->child; + + RE_RC_COUNT(isec->raycounter->simd_bb.test); + + if (res & 1) { stack[stack_pos++] = child[0]; RE_RC_COUNT(isec->raycounter->simd_bb.hit); } + if (res & 2) { stack[stack_pos++] = child[1]; RE_RC_COUNT(isec->raycounter->simd_bb.hit); } + if (res & 4) { stack[stack_pos++] = child[2]; RE_RC_COUNT(isec->raycounter->simd_bb.hit); } + if (res & 8) { stack[stack_pos++] = child[3]; RE_RC_COUNT(isec->raycounter->simd_bb.hit); } + } + else { + float *child_bb = node->child_bb; + SVBVHNode **child = node->child; + int i; + + for (i = 0; i < nchilds; i++) { + if (svbvh_bb_intersect_test(isec, (float *)child_bb + 6 * i)) { + stack[stack_pos++] = child[i]; + } + } + } + } + else { + hit |= RE_rayobject_intersect((RayObject *)node, isec); + if (SHADOW && hit) break; + } + } + + return hit; +} + + +template<> +inline void bvh_node_merge_bb<SVBVHNode>(SVBVHNode *node, float min[3], float max[3]) +{ + if (is_leaf(node)) { + RE_rayobject_merge_bb((RayObject *)node, min, max); + } + else { + int i; + for (i = 0; i + 4 <= node->nchilds; i += 4) { + float *res = node->child_bb + 6 * i; + for (int j = 0; j < 3; j++) { + min[j] = min_ff(min[j], + min_ffff(res[4 * j + 0], + res[4 * j + 1], + res[4 * j + 2], + res[4 * j + 3])); + } + for (int j = 0; j < 3; j++) { + max[j] = max_ff(max[j], + max_ffff(res[4 * (j + 3) + 0], + res[4 * (j + 3) + 1], + res[4 * (j + 3) + 2], + res[4 * (j + 3) + 3])); + } + } + + for (; i < node->nchilds; i++) { + DO_MIN(node->child_bb + 6 * i, min); + DO_MAX(node->child_bb + 3 + 6 * i, max); + } + } +} + + + +/* + * Builds a SVBVH tree form a VBVHTree + */ +template<class OldNode> +struct Reorganize_SVBVH { + MemArena *arena; + + float childs_per_node; + int nodes_with_childs[16]; + int useless_bb; + int nodes; + + Reorganize_SVBVH(MemArena *a) + { + arena = a; + nodes = 0; + childs_per_node = 0; + useless_bb = 0; + + for (int i = 0; i < 16; i++) { + nodes_with_childs[i] = 0; + } + } + + ~Reorganize_SVBVH() + { +#if 0 + { + printf("%f childs per node\n", childs_per_node / nodes); + printf("%d childs BB are useless\n", useless_bb); + for (int i = 0; i < 16; i++) { + printf("%i childs per node: %d/%d = %f\n", i, nodes_with_childs[i], nodes, nodes_with_childs[i] / float(nodes)); + } + } +#endif + } + + SVBVHNode *create_node(int nchilds) + { + SVBVHNode *node = (SVBVHNode *)BLI_memarena_alloc(arena, sizeof(SVBVHNode)); + node->nchilds = nchilds; + + return node; + } + + void copy_bb(float bb[6], const float old_bb[6]) + { + std::copy(old_bb, old_bb + 6, bb); + } + + void prepare_for_simd(SVBVHNode *node) + { + int i = 0; + while (i + 4 <= node->nchilds) { + float vec_tmp[4 * 6]; + float *res = node->child_bb + 6 * i; + std::copy(res, res + 6 * 4, vec_tmp); + + for (int j = 0; j < 6; j++) { + res[4 * j + 0] = vec_tmp[6 * 0 + j]; + res[4 * j + 1] = vec_tmp[6 * 1 + j]; + res[4 * j + 2] = vec_tmp[6 * 2 + j]; + res[4 * j + 3] = vec_tmp[6 * 3 + j]; + } + + i += 4; + } + } + + /* amt must be power of two */ + inline int padup(int num, int amt) + { + return ((num + (amt - 1)) & ~(amt - 1)); + } + + SVBVHNode *transform(OldNode *old) + { + if (is_leaf(old)) + return (SVBVHNode *)old; + if (is_leaf(old->child)) + return (SVBVHNode *)old->child; + + int nchilds = count_childs(old); + int alloc_childs = nchilds; + if (nchilds % 4 > 2) + alloc_childs = padup(nchilds, 4); + + SVBVHNode *node = create_node(alloc_childs); + + childs_per_node += nchilds; + nodes++; + if (nchilds < 16) + nodes_with_childs[nchilds]++; + + useless_bb += alloc_childs - nchilds; + while (alloc_childs > nchilds) { + const static float def_bb[6] = {FLT_MAX, FLT_MAX, FLT_MAX, -FLT_MAX, -FLT_MAX, -FLT_MAX}; + alloc_childs--; + node->child[alloc_childs] = NULL; + copy_bb(node->child_bb + alloc_childs * 6, def_bb); + } + + int i = nchilds; + for (OldNode *o_child = old->child; o_child; o_child = o_child->sibling) { + i--; + node->child[i] = transform(o_child); + if (is_leaf(o_child)) { + float bb[6]; + INIT_MINMAX(bb, bb + 3); + RE_rayobject_merge_bb((RayObject *)o_child, bb, bb + 3); + copy_bb(node->child_bb + i * 6, bb); + break; + } + else { + copy_bb(node->child_bb + i * 6, o_child->bb); + } + } + assert(i == 0); + + prepare_for_simd(node); + + return node; + } +}; + +#endif /* __SSE__ */ + +#endif /* __SVBVH_H__ */ diff --git a/source/blender/render/intern/raytrace/vbvh.h b/source/blender/render/intern/raytrace/vbvh.h new file mode 100644 index 00000000000..0b0bbd19116 --- /dev/null +++ b/source/blender/render/intern/raytrace/vbvh.h @@ -0,0 +1,238 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2009 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): André Pinto. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/render/intern/raytrace/vbvh.h + * \ingroup render + */ + + +#include <assert.h> +#include <algorithm> + +#include "BLI_memarena.h" + +#include "rayobject_rtbuild.h" + +/* + * VBVHNode represents a BVHNode with support for a variable number of childrens + */ +struct VBVHNode { + float bb[6]; + + VBVHNode *child; + VBVHNode *sibling; +}; + + +/* + * Push nodes (used on dfs) + */ +template<class Node> +inline static void bvh_node_push_childs(Node *node, Isect *UNUSED(isec), Node **stack, int &stack_pos) +{ + Node *child = node->child; + + if (is_leaf(child)) { + stack[stack_pos++] = child; + } + else { + while (child) { + /* Skips BB tests on primitives */ +#if 0 + if (is_leaf(child->child)) { + stack[stack_pos++] = child->child; + } + else +#endif + { + stack[stack_pos++] = child; + } + + child = child->sibling; + } + } +} + + +template<class Node> +static int count_childs(Node *parent) +{ + int n = 0; + for (Node *i = parent->child; i; i = i->sibling) { + n++; + if (is_leaf(i)) + break; + } + + return n; +} + + +template<class Node> +static void append_sibling(Node *node, Node *sibling) +{ + while (node->sibling) + node = node->sibling; + + node->sibling = sibling; +} + + +/* + * Builds a binary VBVH from a rtbuild + */ +template<class Node> +struct BuildBinaryVBVH { + MemArena *arena; + RayObjectControl *control; + + void test_break() + { + if (RE_rayobjectcontrol_test_break(control)) + throw "Stop"; + } + + BuildBinaryVBVH(MemArena *a, RayObjectControl *c) + { + arena = a; + control = c; + } + + Node *create_node() + { + Node *node = (Node *)BLI_memarena_alloc(arena, sizeof(Node) ); + assert(RE_rayobject_isAligned(node)); + + node->sibling = NULL; + node->child = NULL; + + return node; + } + + int rtbuild_split(RTBuilder *builder) + { + return ::rtbuild_heuristic_object_split(builder, 2); + } + + Node *transform(RTBuilder *builder) + { + try + { + return _transform(builder); + + } catch (...) + { + } + return NULL; + } + + Node *_transform(RTBuilder *builder) + { + int size = rtbuild_size(builder); + + if (size == 0) { + return NULL; + } + else if (size == 1) { + Node *node = create_node(); + INIT_MINMAX(node->bb, node->bb + 3); + rtbuild_merge_bb(builder, node->bb, node->bb + 3); + node->child = (Node *) rtbuild_get_primitive(builder, 0); + return node; + } + else { + test_break(); + + Node *node = create_node(); + + Node **child = &node->child; + + int nc = rtbuild_split(builder); + INIT_MINMAX(node->bb, node->bb + 3); + + assert(nc == 2); + for (int i = 0; i < nc; i++) { + RTBuilder tmp; + rtbuild_get_child(builder, i, &tmp); + + *child = _transform(&tmp); + DO_MIN((*child)->bb, node->bb); + DO_MAX((*child)->bb + 3, node->bb + 3); + child = &((*child)->sibling); + } + + *child = NULL; + return node; + } + } +}; + +#if 0 +template<class Tree, class OldNode> +struct Reorganize_VBVH { + Tree *tree; + + Reorganize_VBVH(Tree *t) + { + tree = t; + } + + VBVHNode *create_node() + { + VBVHNode *node = (VBVHNode *)BLI_memarena_alloc(tree->node_arena, sizeof(VBVHNode)); + return node; + } + + void copy_bb(VBVHNode *node, OldNode *old) + { + std::copy(old->bb, old->bb + 6, node->bb); + } + + VBVHNode *transform(OldNode *old) + { + if (is_leaf(old)) + return (VBVHNode *)old; + + VBVHNode *node = create_node(); + VBVHNode **child_ptr = &node->child; + node->sibling = 0; + + copy_bb(node, old); + + for (OldNode *o_child = old->child; o_child; o_child = o_child->sibling) + { + VBVHNode *n_child = transform(o_child); + *child_ptr = n_child; + if (is_leaf(n_child)) return node; + child_ptr = &n_child->sibling; + } + *child_ptr = 0; + + return node; + } +}; +#endif diff --git a/source/blender/render/intern/source/bake.c b/source/blender/render/intern/source/bake.c new file mode 100644 index 00000000000..4a7962b1776 --- /dev/null +++ b/source/blender/render/intern/source/bake.c @@ -0,0 +1,1342 @@ +/* + * ***** 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. + * + * Contributors: 2004/2005/2006 Blender Foundation, full recode + * Contributors: Vertex color baking, Copyright 2011 AutoCRC + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/render/intern/source/bake.c + * \ingroup render + */ + + +/* system includes */ +#include <stdio.h> +#include <string.h> + +/* External modules: */ +#include "MEM_guardedalloc.h" + +#include "BLI_math.h" +#include "BLI_rand.h" +#include "BLI_threads.h" +#include "BLI_utildefines.h" + +#include "DNA_image_types.h" +#include "DNA_material_types.h" +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" + +#include "BKE_customdata.h" +#include "BKE_global.h" +#include "BKE_image.h" +#include "BKE_main.h" +#include "BKE_node.h" +#include "BKE_scene.h" +#include "BKE_library.h" + +#include "IMB_imbuf_types.h" +#include "IMB_imbuf.h" +#include "IMB_colormanagement.h" + +/* local include */ +#include "rayintersection.h" +#include "rayobject.h" +#include "render_types.h" +#include "renderdatabase.h" +#include "shading.h" +#include "zbuf.h" + +#include "PIL_time.h" + +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ +/* defined in pipeline.c, is hardcopy of active dynamic allocated Render */ +/* only to be used here in this file, it's for speed */ +extern struct Render R; +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ + + +/* ************************* bake ************************ */ + + +typedef struct BakeShade { + int thread; + + ShadeSample ssamp; + ObjectInstanceRen *obi; + VlakRen *vlr; + + ZSpan *zspan; + Image *ima; + ImBuf *ibuf; + + int rectx, recty, quad, type, vdone; + bool ready; + + float dir[3]; + Object *actob; + + /* Output: vertex color or image data. If vcol is not NULL, rect and + * rect_float should be NULL. */ + MPoly *mpoly; + MLoop *mloop; + MLoopCol *vcol; + + unsigned int *rect; + float *rect_float; + + /* displacement buffer used for normalization with unknown maximal distance */ + bool use_displacement_buffer; + float *displacement_buffer; + float displacement_min, displacement_max; + + bool use_mask; + char *rect_mask; /* bake pixel mask */ + + float dxco[3], dyco[3]; + + short *do_update; + + struct ColorSpace *rect_colorspace; +} BakeShade; + +static void bake_set_shade_input(ObjectInstanceRen *obi, VlakRen *vlr, ShadeInput *shi, int quad, int UNUSED(isect), int x, int y, float u, float v) +{ + if (quad) + shade_input_set_triangle_i(shi, obi, vlr, 0, 2, 3); + else + shade_input_set_triangle_i(shi, obi, vlr, 0, 1, 2); + + /* cache for shadow */ + shi->samplenr = R.shadowsamplenr[shi->thread]++; + + shi->mask = 0xFFFF; /* all samples */ + + shi->u = -u; + shi->v = -v; + shi->xs = x; + shi->ys = y; + + shade_input_set_uv(shi); + shade_input_set_normals(shi); + + /* no normal flip */ + if (shi->flippednor) + shade_input_flip_normals(shi); + + /* set up view vector to look right at the surface (note that the normal + * is negated in the renderer so it does not need to be done here) */ + shi->view[0] = shi->vn[0]; + shi->view[1] = shi->vn[1]; + shi->view[2] = shi->vn[2]; +} + +static void bake_shade(void *handle, Object *ob, ShadeInput *shi, int UNUSED(quad), int x, int y, float UNUSED(u), float UNUSED(v), float *tvn, float *ttang) +{ + BakeShade *bs = handle; + ShadeSample *ssamp = &bs->ssamp; + ShadeResult shr; + VlakRen *vlr = shi->vlr; + + shade_input_init_material(shi); + + if (bs->type == RE_BAKE_AO) { + ambient_occlusion(shi); + + if (R.r.bake_flag & R_BAKE_NORMALIZE) { + copy_v3_v3(shr.combined, shi->ao); + } + else { + zero_v3(shr.combined); + environment_lighting_apply(shi, &shr); + } + } + else { + if (bs->type == RE_BAKE_SHADOW) /* Why do shadows set the color anyhow?, ignore material color for baking */ + shi->r = shi->g = shi->b = 1.0f; + + shade_input_set_shade_texco(shi); + + /* only do AO for a full bake (and obviously AO bakes) + * AO for light bakes is a leftover and might not be needed */ + if (ELEM(bs->type, RE_BAKE_ALL, RE_BAKE_AO, RE_BAKE_LIGHT)) + shade_samples_do_AO(ssamp); + + if (shi->mat->nodetree && shi->mat->use_nodes) { + ntreeShaderExecTree(shi->mat->nodetree, shi, &shr); + shi->mat = vlr->mat; /* shi->mat is being set in nodetree */ + } + else + shade_material_loop(shi, &shr); + + if (bs->type == RE_BAKE_NORMALS) { + float nor[3]; + + copy_v3_v3(nor, shi->vn); + + if (R.r.bake_normal_space == R_BAKE_SPACE_CAMERA) { + /* pass */ + } + else if (R.r.bake_normal_space == R_BAKE_SPACE_TANGENT) { + float mat[3][3], imat[3][3]; + + /* bitangent */ + if (tvn && ttang) { + copy_v3_v3(mat[0], ttang); + cross_v3_v3v3(mat[1], tvn, ttang); + mul_v3_fl(mat[1], ttang[3]); + copy_v3_v3(mat[2], tvn); + } + else { + copy_v3_v3(mat[0], shi->nmaptang); + cross_v3_v3v3(mat[1], shi->nmapnorm, shi->nmaptang); + mul_v3_fl(mat[1], shi->nmaptang[3]); + copy_v3_v3(mat[2], shi->nmapnorm); + } + + invert_m3_m3(imat, mat); + mul_m3_v3(imat, nor); + } + else if (R.r.bake_normal_space == R_BAKE_SPACE_OBJECT) + mul_mat3_m4_v3(ob->imat_ren, nor); /* ob->imat_ren includes viewinv! */ + else if (R.r.bake_normal_space == R_BAKE_SPACE_WORLD) + mul_mat3_m4_v3(R.viewinv, nor); + + normalize_v3(nor); /* in case object has scaling */ + + /* The invert of the red channel is to make + * the normal map compliant with the outside world. + * It needs to be done because in Blender + * the normal used in the renderer points inward. It is generated + * this way in calc_vertexnormals(). Should this ever change + * this negate must be removed. + * + * there is also a small 1e-5f bias for precision issues. otherwise + * we randomly get 127 or 128 for neutral colors. we choose 128 + * because it is the convention flat color. * */ + shr.combined[0] = (-nor[0]) / 2.0f + 0.5f + 1e-5f; + shr.combined[1] = nor[1] / 2.0f + 0.5f + 1e-5f; + shr.combined[2] = nor[2] / 2.0f + 0.5f + 1e-5f; + } + else if (bs->type == RE_BAKE_TEXTURE) { + copy_v3_v3(shr.combined, &shi->r); + shr.alpha = shi->alpha; + } + else if (bs->type == RE_BAKE_SHADOW) { + copy_v3_v3(shr.combined, shr.shad); + shr.alpha = shi->alpha; + } + else if (bs->type == RE_BAKE_SPEC_COLOR) { + copy_v3_v3(shr.combined, &shi->specr); + shr.alpha = 1.0f; + } + else if (bs->type == RE_BAKE_SPEC_INTENSITY) { + copy_v3_fl(shr.combined, shi->spec); + shr.alpha = 1.0f; + } + else if (bs->type == RE_BAKE_MIRROR_COLOR) { + copy_v3_v3(shr.combined, &shi->mirr); + shr.alpha = 1.0f; + } + else if (bs->type == RE_BAKE_MIRROR_INTENSITY) { + copy_v3_fl(shr.combined, shi->ray_mirror); + shr.alpha = 1.0f; + } + else if (bs->type == RE_BAKE_ALPHA) { + copy_v3_fl(shr.combined, shi->alpha); + shr.alpha = 1.0f; + } + else if (bs->type == RE_BAKE_EMIT) { + copy_v3_fl(shr.combined, shi->emit); + shr.alpha = 1.0f; + } + else if (bs->type == RE_BAKE_VERTEX_COLORS) { + copy_v3_v3(shr.combined, shi->vcol); + shr.alpha = shi->vcol[3]; + } + } + + if (bs->rect_float && !bs->vcol) { + float *col = bs->rect_float + 4 * (bs->rectx * y + x); + copy_v3_v3(col, shr.combined); + if (bs->type == RE_BAKE_ALL || bs->type == RE_BAKE_TEXTURE || bs->type == RE_BAKE_VERTEX_COLORS) { + col[3] = shr.alpha; + } + else { + col[3] = 1.0; + } + } + else { + /* Target is char (LDR). */ + unsigned char col[4]; + + if (ELEM(bs->type, RE_BAKE_ALL, RE_BAKE_TEXTURE)) { + float rgb[3]; + + copy_v3_v3(rgb, shr.combined); + if (R.scene_color_manage) { + /* Vertex colors have no way to specify color space, so they + * default to sRGB. */ + if (!bs->vcol) + IMB_colormanagement_scene_linear_to_colorspace_v3(rgb, bs->rect_colorspace); + else + linearrgb_to_srgb_v3_v3(rgb, rgb); + } + rgb_float_to_uchar(col, rgb); + } + else { + rgb_float_to_uchar(col, shr.combined); + } + + if (ELEM(bs->type, RE_BAKE_ALL, RE_BAKE_TEXTURE, RE_BAKE_VERTEX_COLORS)) { + col[3] = unit_float_to_uchar_clamp(shr.alpha); + } + else { + col[3] = 255; + } + + if (bs->vcol) { + /* Vertex color baking. Vcol has no useful alpha channel (it exists + * but is used only for vertex painting). */ + bs->vcol->r = col[0]; + bs->vcol->g = col[1]; + bs->vcol->b = col[2]; + } + else { + unsigned char *imcol = (unsigned char *)(bs->rect + bs->rectx * y + x); + copy_v4_v4_uchar(imcol, col); + } + + } + + if (bs->rect_mask) { + bs->rect_mask[bs->rectx * y + x] = FILTER_MASK_USED; + } + + if (bs->do_update) { + *bs->do_update = true; + } +} + +static void bake_displacement(void *handle, ShadeInput *UNUSED(shi), float dist, int x, int y) +{ + BakeShade *bs = handle; + float disp; + + if (R.r.bake_flag & R_BAKE_NORMALIZE) { + if (R.r.bake_maxdist) + disp = (dist + R.r.bake_maxdist) / (R.r.bake_maxdist * 2); /* alter the range from [-bake_maxdist, bake_maxdist] to [0, 1]*/ + else + disp = dist; + } + else { + disp = 0.5f + dist; /* alter the range from [-0.5,0.5] to [0,1]*/ + } + + if (bs->displacement_buffer) { + float *displacement = bs->displacement_buffer + (bs->rectx * y + x); + *displacement = disp; + bs->displacement_min = min_ff(bs->displacement_min, disp); + bs->displacement_max = max_ff(bs->displacement_max, disp); + } + + if (bs->rect_float && !bs->vcol) { + float *col = bs->rect_float + 4 * (bs->rectx * y + x); + col[0] = col[1] = col[2] = disp; + col[3] = 1.0f; + } + else { + /* Target is char (LDR). */ + unsigned char col[4]; + col[0] = col[1] = col[2] = unit_float_to_uchar_clamp(disp); + col[3] = 255; + + if (bs->vcol) { + /* Vertex color baking. Vcol has no useful alpha channel (it exists + * but is used only for vertex painting). */ + bs->vcol->r = col[0]; + bs->vcol->g = col[1]; + bs->vcol->b = col[2]; + } + else { + unsigned char *imcol = (unsigned char *)(bs->rect + bs->rectx * y + x); + copy_v4_v4_uchar(imcol, col); + } + } + if (bs->rect_mask) { + bs->rect_mask[bs->rectx * y + x] = FILTER_MASK_USED; + } +} + +static int bake_intersect_tree(RayObject *raytree, Isect *isect, float *start, float *dir, float sign, float *hitco, float *dist) +{ + float maxdist; + int hit; + + /* might be useful to make a user setting for maxsize*/ + if (R.r.bake_maxdist > 0.0f) + maxdist = R.r.bake_maxdist; + else + maxdist = RE_RAYTRACE_MAXDIST + R.r.bake_biasdist; + + /* 'dir' is always normalized */ + madd_v3_v3v3fl(isect->start, start, dir, -R.r.bake_biasdist); + + mul_v3_v3fl(isect->dir, dir, sign); + + isect->dist = maxdist; + + hit = RE_rayobject_raycast(raytree, isect); + if (hit) { + madd_v3_v3v3fl(hitco, isect->start, isect->dir, isect->dist); + + *dist = isect->dist; + } + + return hit; +} + +static void bake_set_vlr_dxyco(BakeShade *bs, float *uv1, float *uv2, float *uv3) +{ + VlakRen *vlr = bs->vlr; + float A, d1, d2, d3, *v1, *v2, *v3; + + if (bs->quad) { + v1 = vlr->v1->co; + v2 = vlr->v3->co; + v3 = vlr->v4->co; + } + else { + v1 = vlr->v1->co; + v2 = vlr->v2->co; + v3 = vlr->v3->co; + } + + /* formula derived from barycentric coordinates: + * (uvArea1*v1 + uvArea2*v2 + uvArea3*v3)/uvArea + * then taking u and v partial derivatives to get dxco and dyco */ + A = (uv2[0] - uv1[0]) * (uv3[1] - uv1[1]) - (uv3[0] - uv1[0]) * (uv2[1] - uv1[1]); + + if (fabsf(A) > FLT_EPSILON) { + A = 0.5f / A; + + d1 = uv2[1] - uv3[1]; + d2 = uv3[1] - uv1[1]; + d3 = uv1[1] - uv2[1]; + bs->dxco[0] = (v1[0] * d1 + v2[0] * d2 + v3[0] * d3) * A; + bs->dxco[1] = (v1[1] * d1 + v2[1] * d2 + v3[1] * d3) * A; + bs->dxco[2] = (v1[2] * d1 + v2[2] * d2 + v3[2] * d3) * A; + + d1 = uv3[0] - uv2[0]; + d2 = uv1[0] - uv3[0]; + d3 = uv2[0] - uv1[0]; + bs->dyco[0] = (v1[0] * d1 + v2[0] * d2 + v3[0] * d3) * A; + bs->dyco[1] = (v1[1] * d1 + v2[1] * d2 + v3[1] * d3) * A; + bs->dyco[2] = (v1[2] * d1 + v2[2] * d2 + v3[2] * d3) * A; + } + else { + bs->dxco[0] = bs->dxco[1] = bs->dxco[2] = 0.0f; + bs->dyco[0] = bs->dyco[1] = bs->dyco[2] = 0.0f; + } + + if (bs->obi->flag & R_TRANSFORMED) { + mul_m3_v3(bs->obi->nmat, bs->dxco); + mul_m3_v3(bs->obi->nmat, bs->dyco); + } +} + +static void do_bake_shade(void *handle, int x, int y, float u, float v) +{ + BakeShade *bs = handle; + VlakRen *vlr = bs->vlr; + ObjectInstanceRen *obi = bs->obi; + Object *ob = obi->obr->ob; + float l, *v1, *v2, *v3, tvn[3], ttang[4]; + int quad; + ShadeSample *ssamp = &bs->ssamp; + ShadeInput *shi = ssamp->shi; + + /* fast threadsafe break test */ + if (R.test_break(R.tbh)) + return; + + /* setup render coordinates */ + if (bs->quad) { + v1 = vlr->v1->co; + v2 = vlr->v3->co; + v3 = vlr->v4->co; + } + else { + v1 = vlr->v1->co; + v2 = vlr->v2->co; + v3 = vlr->v3->co; + } + + l = 1.0f - u - v; + + /* shrink barycentric coordinates inwards slightly to avoid some issues + * where baking selected to active might just miss the other face at the + * near the edge of a face */ + if (bs->actob) { + const float eps = 1.0f - 1e-4f; + float invsum; + + u = (u - 0.5f) * eps + 0.5f; + v = (v - 0.5f) * eps + 0.5f; + l = (l - 0.5f) * eps + 0.5f; + + invsum = 1.0f / (u + v + l); + + u *= invsum; + v *= invsum; + l *= invsum; + } + + /* renderco */ + shi->co[0] = l * v3[0] + u * v1[0] + v * v2[0]; + shi->co[1] = l * v3[1] + u * v1[1] + v * v2[1]; + shi->co[2] = l * v3[2] + u * v1[2] + v * v2[2]; + + /* avoid self shadow with vertex bake from adjacent faces [#33729] */ + if ((bs->vcol != NULL) && (bs->actob == NULL)) { + madd_v3_v3fl(shi->co, vlr->n, 0.0001f); + } + + if (obi->flag & R_TRANSFORMED) + mul_m4_v3(obi->mat, shi->co); + + copy_v3_v3(shi->dxco, bs->dxco); + copy_v3_v3(shi->dyco, bs->dyco); + + quad = bs->quad; + bake_set_shade_input(obi, vlr, shi, quad, 0, x, y, u, v); + + if (bs->type == RE_BAKE_NORMALS && R.r.bake_normal_space == R_BAKE_SPACE_TANGENT) { + shade_input_set_shade_texco(shi); + copy_v3_v3(tvn, shi->nmapnorm); + copy_v4_v4(ttang, shi->nmaptang); + } + + /* if we are doing selected to active baking, find point on other face */ + if (bs->actob) { + Isect isec, minisec; + float co[3], minco[3], dist, mindist = 0.0f; + int hit, sign, dir = 1; + + /* intersect with ray going forward and backward*/ + hit = 0; + memset(&minisec, 0, sizeof(minisec)); + minco[0] = minco[1] = minco[2] = 0.0f; + + copy_v3_v3(bs->dir, shi->vn); + + for (sign = -1; sign <= 1; sign += 2) { + memset(&isec, 0, sizeof(isec)); + isec.mode = RE_RAY_MIRROR; + + isec.orig.ob = obi; + isec.orig.face = vlr; + isec.userdata = bs->actob; + isec.check = RE_CHECK_VLR_BAKE; + isec.skip = RE_SKIP_VLR_NEIGHBOUR; + + if (bake_intersect_tree(R.raytree, &isec, shi->co, shi->vn, sign, co, &dist)) { + if (!hit || len_squared_v3v3(shi->co, co) < len_squared_v3v3(shi->co, minco)) { + minisec = isec; + mindist = dist; + copy_v3_v3(minco, co); + hit = 1; + dir = sign; + } + } + } + + if (ELEM(bs->type, RE_BAKE_DISPLACEMENT, RE_BAKE_DERIVATIVE)) { + if (hit) + bake_displacement(handle, shi, (dir == -1) ? mindist : -mindist, x, y); + else + bake_displacement(handle, shi, 0.0f, x, y); + return; + } + + /* if hit, we shade from the new point, otherwise from point one starting face */ + if (hit) { + obi = (ObjectInstanceRen *)minisec.hit.ob; + vlr = (VlakRen *)minisec.hit.face; + quad = (minisec.isect == 2); + copy_v3_v3(shi->co, minco); + + u = -minisec.u; + v = -minisec.v; + bake_set_shade_input(obi, vlr, shi, quad, 1, x, y, u, v); + } + } + + if (bs->type == RE_BAKE_NORMALS && R.r.bake_normal_space == R_BAKE_SPACE_TANGENT) + bake_shade(handle, ob, shi, quad, x, y, u, v, tvn, ttang); + else + bake_shade(handle, ob, shi, quad, x, y, u, v, NULL, NULL); +} + +static int get_next_bake_face(BakeShade *bs) +{ + ObjectRen *obr; + VlakRen *vlr; + MTFace *tface; + static int v = 0, vdone = false; + static ObjectInstanceRen *obi = NULL; + + if (bs == NULL) { + vlr = NULL; + v = vdone = false; + obi = R.instancetable.first; + return 0; + } + + BLI_thread_lock(LOCK_CUSTOM1); + + for (; obi; obi = obi->next, v = 0) { + obr = obi->obr; + + /* only allow non instances here */ + if (obr->flag & R_INSTANCEABLE) + continue; + + for (; v < obr->totvlak; v++) { + vlr = RE_findOrAddVlak(obr, v); + + if ((bs->actob && bs->actob == obr->ob) || (!bs->actob && (obr->ob->flag & SELECT))) { + if (R.r.bake_flag & R_BAKE_VCOL) { + /* Gather face data for vertex color bake */ + Mesh *me; + int *origindex, vcollayer; + CustomDataLayer *cdl; + + if (obr->ob->type != OB_MESH) + continue; + me = obr->ob->data; + + origindex = RE_vlakren_get_origindex(obr, vlr, 0); + if (origindex == NULL) + continue; + if (*origindex >= me->totpoly) { + /* Small hack for Array modifier, which gives false + * original indices - z0r */ + continue; + } +#if 0 + /* Only shade selected faces. */ + if ((me->mface[*origindex].flag & ME_FACE_SEL) == 0) + continue; +#endif + + vcollayer = CustomData_get_render_layer_index(&me->ldata, CD_MLOOPCOL); + if (vcollayer == -1) + continue; + + cdl = &me->ldata.layers[vcollayer]; + bs->mpoly = me->mpoly + *origindex; + bs->vcol = ((MLoopCol *)cdl->data) + bs->mpoly->loopstart; + bs->mloop = me->mloop + bs->mpoly->loopstart; + + /* Tag mesh for reevaluation. */ + me->id.tag |= LIB_TAG_DOIT; + } + else { + Image *ima = NULL; + ImBuf *ibuf = NULL; + const float vec_alpha[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + const float vec_solid[4] = {0.0f, 0.0f, 0.0f, 1.0f}; + const float nor_alpha[4] = {0.5f, 0.5f, 1.0f, 0.0f}; + const float nor_solid[4] = {0.5f, 0.5f, 1.0f, 1.0f}; + const float disp_alpha[4] = {0.5f, 0.5f, 0.5f, 0.0f}; + const float disp_solid[4] = {0.5f, 0.5f, 0.5f, 1.0f}; + + tface = RE_vlakren_get_tface(obr, vlr, obr->bakemtface, NULL, 0); + + if (!tface || !tface->tpage) + continue; + + ima = tface->tpage; + ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL); + + if (ibuf == NULL) + continue; + + if (ibuf->rect == NULL && ibuf->rect_float == NULL) { + BKE_image_release_ibuf(ima, ibuf, NULL); + continue; + } + + if (ibuf->rect_float && !(ibuf->channels == 0 || ibuf->channels == 4)) { + BKE_image_release_ibuf(ima, ibuf, NULL); + continue; + } + + if (ima->flag & IMA_USED_FOR_RENDER) { + ima->id.tag &= ~LIB_TAG_DOIT; + BKE_image_release_ibuf(ima, ibuf, NULL); + continue; + } + + /* find the image for the first time? */ + if (ima->id.tag & LIB_TAG_DOIT) { + ima->id.tag &= ~LIB_TAG_DOIT; + + /* we either fill in float or char, this ensures things go fine */ + if (ibuf->rect_float) + imb_freerectImBuf(ibuf); + /* clear image */ + if (R.r.bake_flag & R_BAKE_CLEAR) { + if (R.r.bake_mode == RE_BAKE_NORMALS && R.r.bake_normal_space == R_BAKE_SPACE_TANGENT) + IMB_rectfill(ibuf, (ibuf->planes == R_IMF_PLANES_RGBA) ? nor_alpha : nor_solid); + else if (ELEM(R.r.bake_mode, RE_BAKE_DISPLACEMENT, RE_BAKE_DERIVATIVE)) + IMB_rectfill(ibuf, (ibuf->planes == R_IMF_PLANES_RGBA) ? disp_alpha : disp_solid); + else + IMB_rectfill(ibuf, (ibuf->planes == R_IMF_PLANES_RGBA) ? vec_alpha : vec_solid); + } + /* might be read by UI to set active image for display */ + R.bakebuf = ima; + } + + /* Tag image for redraw. */ + ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID; + BKE_image_release_ibuf(ima, ibuf, NULL); + } + + bs->obi = obi; + bs->vlr = vlr; + bs->vdone++; /* only for error message if nothing was rendered */ + v++; + BLI_thread_unlock(LOCK_CUSTOM1); + return 1; + } + } + } + + BLI_thread_unlock(LOCK_CUSTOM1); + return 0; +} + +static void bake_single_vertex(BakeShade *bs, VertRen *vert, float u, float v) +{ + int *origindex, i; + MLoopCol *basevcol; + MLoop *mloop; + + /* per vertex fixed seed */ + BLI_thread_srandom(bs->thread, vert->index); + + origindex = RE_vertren_get_origindex(bs->obi->obr, vert, 0); + if (!origindex || *origindex == ORIGINDEX_NONE) + return; + + /* Search for matching vertex index and apply shading. */ + for (i = 0; i < bs->mpoly->totloop; i++) { + mloop = bs->mloop + i; + if (mloop->v != *origindex) + continue; + basevcol = bs->vcol; + bs->vcol = basevcol + i; + do_bake_shade(bs, 0, 0, u, v); + bs->vcol = basevcol; + break; + } +} + +/* Bake all vertices of a face. Actually, this still works on a face-by-face + * basis, and each vertex on each face is shaded. Vertex colors are a property + * of loops, not vertices. */ +static void shade_verts(BakeShade *bs) +{ + VlakRen *vlr = bs->vlr; + + /* Disable baking to image; write to vcol instead. vcol pointer is set in + * bake_single_vertex. */ + bs->ima = NULL; + bs->rect = NULL; + bs->rect_float = NULL; + bs->displacement_buffer = NULL; + bs->displacement_min = FLT_MAX; + bs->displacement_max = -FLT_MAX; + + bs->quad = 0; + + /* No anti-aliasing for vertices. */ + zero_v3(bs->dxco); + zero_v3(bs->dyco); + + /* Shade each vertex of the face. u and v are barycentric coordinates; since + * we're only interested in vertices, these will be 0 or 1. */ + if ((vlr->flag & R_FACE_SPLIT) == 0) { + /* Processing triangle face, whole quad, or first half of split quad. */ + + bake_single_vertex(bs, bs->vlr->v1, 1.0f, 0.0f); + bake_single_vertex(bs, bs->vlr->v2, 0.0f, 1.0f); + bake_single_vertex(bs, bs->vlr->v3, 0.0f, 0.0f); + + if (vlr->v4) { + bs->quad = 1; + bake_single_vertex(bs, bs->vlr->v4, 0.0f, 0.0f); + } + } + else { + /* Processing second half of split quad. Only one vertex to go. */ + if (vlr->flag & R_DIVIDE_24) { + bake_single_vertex(bs, bs->vlr->v2, 0.0f, 1.0f); + } + else { + bake_single_vertex(bs, bs->vlr->v3, 0.0f, 0.0f); + } + } +} + +/* already have tested for tface and ima and zspan */ +static void shade_tface(BakeShade *bs) +{ + VlakRen *vlr = bs->vlr; + ObjectInstanceRen *obi = bs->obi; + ObjectRen *obr = obi->obr; + MTFace *tface = RE_vlakren_get_tface(obr, vlr, obr->bakemtface, NULL, 0); + Image *ima = tface->tpage; + float vec[4][2]; + int a, i1, i2, i3; + + /* per face fixed seed */ + BLI_thread_srandom(bs->thread, vlr->index); + + /* check valid zspan */ + if (ima != bs->ima) { + BKE_image_release_ibuf(bs->ima, bs->ibuf, NULL); + + bs->ima = ima; + bs->ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL); + /* note, these calls only free/fill contents of zspan struct, not zspan itself */ + zbuf_free_span(bs->zspan); + zbuf_alloc_span(bs->zspan, bs->ibuf->x, bs->ibuf->y, R.clipcrop); + } + + bs->rectx = bs->ibuf->x; + bs->recty = bs->ibuf->y; + bs->rect = bs->ibuf->rect; + bs->rect_colorspace = bs->ibuf->rect_colorspace; + bs->rect_float = bs->ibuf->rect_float; + bs->vcol = NULL; + bs->quad = 0; + bs->rect_mask = NULL; + bs->displacement_buffer = NULL; + + if (bs->use_mask || bs->use_displacement_buffer) { + BakeImBufuserData *userdata = bs->ibuf->userdata; + if (userdata == NULL) { + BLI_thread_lock(LOCK_CUSTOM1); + userdata = bs->ibuf->userdata; + if (userdata == NULL) /* since the thread was locked, its possible another thread alloced the value */ + userdata = MEM_callocN(sizeof(BakeImBufuserData), "BakeImBufuserData"); + + if (bs->use_mask) { + if (userdata->mask_buffer == NULL) { + userdata->mask_buffer = MEM_callocN(sizeof(char) * bs->rectx * bs->recty, "BakeMask"); + } + } + + if (bs->use_displacement_buffer) { + if (userdata->displacement_buffer == NULL) { + userdata->displacement_buffer = MEM_callocN(sizeof(float) * bs->rectx * bs->recty, "BakeDisp"); + } + } + + bs->ibuf->userdata = userdata; + + BLI_thread_unlock(LOCK_CUSTOM1); + } + + bs->rect_mask = userdata->mask_buffer; + bs->displacement_buffer = userdata->displacement_buffer; + } + + /* get pixel level vertex coordinates */ + for (a = 0; a < 4; a++) { + /* Note, workaround for pixel aligned UVs which are common and can screw up our intersection tests + * where a pixel gets in between 2 faces or the middle of a quad, + * camera aligned quads also have this problem but they are less common. + * Add a small offset to the UVs, fixes bug #18685 - Campbell */ + vec[a][0] = tface->uv[a][0] * (float)bs->rectx - (0.5f + 0.001f); + vec[a][1] = tface->uv[a][1] * (float)bs->recty - (0.5f + 0.002f); + } + + /* UV indices have to be corrected for possible quad->tria splits */ + i1 = 0; i2 = 1; i3 = 2; + vlr_set_uv_indices(vlr, &i1, &i2, &i3); + bake_set_vlr_dxyco(bs, vec[i1], vec[i2], vec[i3]); + zspan_scanconvert(bs->zspan, bs, vec[i1], vec[i2], vec[i3], do_bake_shade); + + if (vlr->v4) { + bs->quad = 1; + bake_set_vlr_dxyco(bs, vec[0], vec[2], vec[3]); + zspan_scanconvert(bs->zspan, bs, vec[0], vec[2], vec[3], do_bake_shade); + } +} + +static void *do_bake_thread(void *bs_v) +{ + BakeShade *bs = bs_v; + + while (get_next_bake_face(bs)) { + if (R.r.bake_flag & R_BAKE_VCOL) { + shade_verts(bs); + } + else { + shade_tface(bs); + } + + /* fast threadsafe break test */ + if (R.test_break(R.tbh)) + break; + + /* access is not threadsafe but since its just true/false probably ok + * only used for interactive baking */ + if (bs->do_update) { + *bs->do_update = true; + } + } + bs->ready = true; + + BKE_image_release_ibuf(bs->ima, bs->ibuf, NULL); + + return NULL; +} + +void RE_bake_ibuf_filter(ImBuf *ibuf, char *mask, const int filter) +{ + /* must check before filtering */ + const bool is_new_alpha = (ibuf->planes != R_IMF_PLANES_RGBA) && BKE_imbuf_alpha_test(ibuf); + + /* Margin */ + if (filter) { + IMB_filter_extend(ibuf, mask, filter); + } + + /* if the bake results in new alpha then change the image setting */ + if (is_new_alpha) { + ibuf->planes = R_IMF_PLANES_RGBA; + } + else { + if (filter && ibuf->planes != R_IMF_PLANES_RGBA) { + /* clear alpha added by filtering */ + IMB_rectfill_alpha(ibuf, 1.0f); + } + } +} + +void RE_bake_ibuf_normalize_displacement(ImBuf *ibuf, float *displacement, char *mask, float displacement_min, float displacement_max) +{ + int i; + const float *current_displacement = displacement; + const char *current_mask = mask; + float max_distance; + + max_distance = max_ff(fabsf(displacement_min), fabsf(displacement_max)); + + for (i = 0; i < ibuf->x * ibuf->y; i++) { + if (*current_mask == FILTER_MASK_USED) { + float normalized_displacement; + + if (max_distance > 1e-5f) + normalized_displacement = (*current_displacement + max_distance) / (max_distance * 2); + else + normalized_displacement = 0.5f; + + if (ibuf->rect_float) { + /* currently baking happens to RGBA only */ + float *fp = ibuf->rect_float + i * 4; + fp[0] = fp[1] = fp[2] = normalized_displacement; + fp[3] = 1.0f; + } + + if (ibuf->rect) { + unsigned char *cp = (unsigned char *) (ibuf->rect + i); + cp[0] = cp[1] = cp[2] = unit_float_to_uchar_clamp(normalized_displacement); + cp[3] = 255; + } + } + + current_displacement++; + current_mask++; + } +} + +/* using object selection tags, the faces with UV maps get baked */ +/* render should have been setup */ +/* returns 0 if nothing was handled */ +int RE_bake_shade_all_selected(Render *re, int type, Object *actob, short *do_update, float *progress) +{ + BakeShade *handles; + ListBase threads; + Image *ima; + int a, vdone = false, result = BAKE_RESULT_OK; + bool use_mask = false; + bool use_displacement_buffer = false; + bool do_manage = false; + + if (ELEM(type, RE_BAKE_ALL, RE_BAKE_TEXTURE)) { + do_manage = BKE_scene_check_color_management_enabled(re->scene); + } + + re->scene_color_manage = BKE_scene_check_color_management_enabled(re->scene); + + /* initialize render global */ + R = *re; + R.bakebuf = NULL; + + /* initialize static vars */ + get_next_bake_face(NULL); + + /* do we need a mask? */ + if (re->r.bake_filter) + use_mask = true; + + /* do we need buffer to store displacements */ + if (ELEM(type, RE_BAKE_DISPLACEMENT, RE_BAKE_DERIVATIVE)) { + if (((R.r.bake_flag & R_BAKE_NORMALIZE) && R.r.bake_maxdist == 0.0f) || + (type == RE_BAKE_DERIVATIVE)) + { + use_displacement_buffer = true; + use_mask = true; + } + } + + /* baker uses this flag to detect if image was initialized */ + if ((R.r.bake_flag & R_BAKE_VCOL) == 0) { + for (ima = G.main->image.first; ima; ima = ima->id.next) { + ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL); + ima->id.tag |= LIB_TAG_DOIT; + ima->flag &= ~IMA_USED_FOR_RENDER; + if (ibuf) { + ibuf->userdata = NULL; /* use for masking if needed */ + } + BKE_image_release_ibuf(ima, ibuf, NULL); + } + } + + if (R.r.bake_flag & R_BAKE_VCOL) { + /* untag all meshes */ + BKE_main_id_tag_listbase(&G.main->mesh, LIB_TAG_DOIT, false); + } + + BLI_threadpool_init(&threads, do_bake_thread, re->r.threads); + + handles = MEM_callocN(sizeof(BakeShade) * re->r.threads, "BakeShade"); + + /* get the threads running */ + for (a = 0; a < re->r.threads; a++) { + handles[a].thread = a; + + /* set defaults in handles */ + handles[a].ssamp.shi[0].lay = re->lay; + + if (type == RE_BAKE_SHADOW) { + handles[a].ssamp.shi[0].passflag = SCE_PASS_SHADOW; + } + else { + handles[a].ssamp.shi[0].passflag = SCE_PASS_COMBINED; + } + handles[a].ssamp.shi[0].combinedflag = ~(SCE_PASS_SPEC); + handles[a].ssamp.shi[0].thread = a; + handles[a].ssamp.shi[0].do_manage = do_manage; + handles[a].ssamp.tot = 1; + + handles[a].type = type; + handles[a].actob = actob; + if (R.r.bake_flag & R_BAKE_VCOL) + handles[a].zspan = NULL; + else + handles[a].zspan = MEM_callocN(sizeof(ZSpan), "zspan for bake"); + + handles[a].use_mask = use_mask; + handles[a].use_displacement_buffer = use_displacement_buffer; + + handles[a].do_update = do_update; /* use to tell the view to update */ + + handles[a].displacement_min = FLT_MAX; + handles[a].displacement_max = -FLT_MAX; + + BLI_threadpool_insert(&threads, &handles[a]); + } + + /* wait for everything to be done */ + a = 0; + while (a != re->r.threads) { + PIL_sleep_ms(50); + + /* calculate progress */ + for (vdone = false, a = 0; a < re->r.threads; a++) + vdone += handles[a].vdone; + if (progress) + *progress = (float)(vdone / (float)re->totvlak); + + for (a = 0; a < re->r.threads; a++) { + if (handles[a].ready == false) { + break; + } + } + } + + /* filter and refresh images */ + if ((R.r.bake_flag & R_BAKE_VCOL) == 0) { + float displacement_min = FLT_MAX, displacement_max = -FLT_MAX; + + if (use_displacement_buffer) { + for (a = 0; a < re->r.threads; a++) { + displacement_min = min_ff(displacement_min, handles[a].displacement_min); + displacement_max = max_ff(displacement_max, handles[a].displacement_max); + } + } + + for (ima = G.main->image.first; ima; ima = ima->id.next) { + if ((ima->id.tag & LIB_TAG_DOIT) == 0) { + ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL); + BakeImBufuserData *userdata; + + if (ima->flag & IMA_USED_FOR_RENDER) + result = BAKE_RESULT_FEEDBACK_LOOP; + + if (!ibuf) + continue; + + userdata = (BakeImBufuserData *)ibuf->userdata; + if (userdata) { + if (use_displacement_buffer) { + if (type == RE_BAKE_DERIVATIVE) { + float user_scale = (R.r.bake_flag & R_BAKE_USERSCALE) ? R.r.bake_user_scale : -1.0f; + RE_bake_make_derivative(ibuf, userdata->displacement_buffer, userdata->mask_buffer, + displacement_min, displacement_max, user_scale); + } + else { + RE_bake_ibuf_normalize_displacement(ibuf, userdata->displacement_buffer, userdata->mask_buffer, + displacement_min, displacement_max); + } + } + + RE_bake_ibuf_filter(ibuf, userdata->mask_buffer, re->r.bake_filter); + } + + ibuf->userflags |= IB_BITMAPDIRTY; + BKE_image_release_ibuf(ima, ibuf, NULL); + } + } + + /* calculate return value */ + for (a = 0; a < re->r.threads; a++) { + zbuf_free_span(handles[a].zspan); + MEM_freeN(handles[a].zspan); + } + } + + MEM_freeN(handles); + + BLI_threadpool_end(&threads); + + if (vdone == 0) { + result = BAKE_RESULT_NO_OBJECTS; + } + + return result; +} + +struct Image *RE_bake_shade_get_image(void) +{ + return R.bakebuf; +} + +/* **************** Derivative Maps Baker **************** */ + +static void add_single_heights_margin(const ImBuf *ibuf, const char *mask, float *heights_buffer) +{ + int x, y; + + for (y = 0; y < ibuf->y; y++) { + for (x = 0; x < ibuf->x; x++) { + int index = ibuf->x * y + x; + + /* If unassigned pixel, look for neighbors. */ + if (mask[index] != FILTER_MASK_USED) { + float height_acc = 0; + int denom = 0; + int i, j; + + for (j = -1; j <= 1; j++) + for (i = -1; i <= 1; i++) { + int w = (i == 0 ? 1 : 0) + (j == 0 ? 1 : 0) + 1; + + if (i != 0 || j != 0) { + int index2 = 0; + int x0 = x + i; + int y0 = y + j; + + CLAMP(x0, 0, ibuf->x - 1); + CLAMP(y0, 0, ibuf->y - 1); + + index2 = ibuf->x * y0 + x0; + + if (mask[index2] == FILTER_MASK_USED) { + height_acc += w * heights_buffer[index2]; + denom += w; + } + } + } + + /* Insert final value. */ + if (denom > 0) { + heights_buffer[index] = height_acc / denom; + } + } + } + } +} + +/* returns user-scale */ +float RE_bake_make_derivative(ImBuf *ibuf, float *heights_buffer, const char *mask, + const float height_min, const float height_max, + const float fmult) +{ + const float delta_height = height_max - height_min; + const float denom = delta_height > 0.0f ? (8 * delta_height) : 1.0f; + bool auto_range_fit = fmult <= 0.0f; + float max_num_deriv = -1.0f; + int x, y, index; + + /* Need a single margin to calculate good derivatives. */ + add_single_heights_margin(ibuf, mask, heights_buffer); + + if (auto_range_fit) { + /* If automatic range fitting is enabled. */ + for (y = 0; y < ibuf->y; y++) { + const int Yu = y == (ibuf->y - 1) ? (ibuf->y - 1) : (y + 1); + const int Yc = y; + const int Yd = y == 0 ? 0 : (y - 1); + + for (x = 0; x < ibuf->x; x++) { + const int Xl = x == 0 ? 0 : (x - 1); + const int Xc = x; + const int Xr = x == (ibuf->x - 1) ? (ibuf->x - 1) : (x + 1); + + const float Hcy = heights_buffer[Yc * ibuf->x + Xr] - heights_buffer[Yc * ibuf->x + Xl]; + const float Hu = heights_buffer[Yu * ibuf->x + Xr] - heights_buffer[Yu * ibuf->x + Xl]; + const float Hd = heights_buffer[Yd * ibuf->x + Xr] - heights_buffer[Yd * ibuf->x + Xl]; + + const float Hl = heights_buffer[Yu * ibuf->x + Xl] - heights_buffer[Yd * ibuf->x + Xl]; + const float Hcx = heights_buffer[Yu * ibuf->x + Xc] - heights_buffer[Yd * ibuf->x + Xc]; + const float Hr = heights_buffer[Yu * ibuf->x + Xr] - heights_buffer[Yd * ibuf->x + Xr]; + + /* This corresponds to using the sobel kernel on the heights buffer + * to obtain the derivative multiplied by 8. + */ + const float deriv_x = Hu + 2 * Hcy + Hd; + const float deriv_y = Hr + 2 * Hcx + Hl; + + /* early out */ + index = ibuf->x * y + x; + if (mask[index] != FILTER_MASK_USED) { + continue; + } + + /* Widen bound. */ + if (fabsf(deriv_x) > max_num_deriv) { + max_num_deriv = fabsf(deriv_x); + } + + if (fabsf(deriv_y) > max_num_deriv) { + max_num_deriv = fabsf(deriv_y); + } + } + } + } + + /* Output derivatives. */ + auto_range_fit &= (max_num_deriv > 0); + for (y = 0; y < ibuf->y; y++) { + const int Yu = y == (ibuf->y - 1) ? (ibuf->y - 1) : (y + 1); + const int Yc = y; + const int Yd = y == 0 ? 0 : (y - 1); + + for (x = 0; x < ibuf->x; x++) { + const int Xl = x == 0 ? 0 : (x - 1); + const int Xc = x; + const int Xr = x == (ibuf->x - 1) ? (ibuf->x - 1) : (x + 1); + + const float Hcy = heights_buffer[Yc * ibuf->x + Xr] - heights_buffer[Yc * ibuf->x + Xl]; + const float Hu = heights_buffer[Yu * ibuf->x + Xr] - heights_buffer[Yu * ibuf->x + Xl]; + const float Hd = heights_buffer[Yd * ibuf->x + Xr] - heights_buffer[Yd * ibuf->x + Xl]; + + const float Hl = heights_buffer[Yu * ibuf->x + Xl] - heights_buffer[Yd * ibuf->x + Xl]; + const float Hcx = heights_buffer[Yu * ibuf->x + Xc] - heights_buffer[Yd * ibuf->x + Xc]; + const float Hr = heights_buffer[Yu * ibuf->x + Xr] - heights_buffer[Yd * ibuf->x + Xr]; + + /* This corresponds to using the sobel kernel on the heights buffer + * to obtain the derivative multiplied by 8. + */ + float deriv_x = Hu + 2 * Hcy + Hd; + float deriv_y = Hr + 2 * Hcx + Hl; + + /* Early out. */ + index = ibuf->x * y + x; + if (mask[index] != FILTER_MASK_USED) { + continue; + } + + if (auto_range_fit) { + deriv_x /= max_num_deriv; + deriv_y /= max_num_deriv; + } + else { + deriv_x *= (fmult / denom); + deriv_y *= (fmult / denom); + } + + deriv_x = deriv_x * 0.5f + 0.5f; + deriv_y = deriv_y * 0.5f + 0.5f; + + /* Clamp. */ + CLAMP(deriv_x, 0.0f, 1.0f); + CLAMP(deriv_y, 0.0f, 1.0f); + + /* Write out derivatives. */ + if (ibuf->rect_float) { + float *rrgbf = ibuf->rect_float + index * 4; + + rrgbf[0] = deriv_x; + rrgbf[1] = deriv_y; + rrgbf[2] = 0.0f; + rrgbf[3] = 1.0f; + } + else { + char *rrgb = (char *)ibuf->rect + index * 4; + + rrgb[0] = unit_float_to_uchar_clamp(deriv_x); + rrgb[1] = unit_float_to_uchar_clamp(deriv_y); + rrgb[2] = 0; + rrgb[3] = 255; + } + } + } + + /* Eeturn user-scale (for rendering). */ + return auto_range_fit ? (max_num_deriv / denom) : (fmult > 0.0f ? (1.0f / fmult) : 0.0f); +} diff --git a/source/blender/render/intern/source/convertblender.c b/source/blender/render/intern/source/convertblender.c new file mode 100644 index 00000000000..8675ffec313 --- /dev/null +++ b/source/blender/render/intern/source/convertblender.c @@ -0,0 +1,6014 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * Contributors: 2004/2005/2006 Blender Foundation, full recode + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/render/intern/source/convertblender.c + * \ingroup render + */ + +#include <math.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <limits.h> + +#include "MEM_guardedalloc.h" + +#include "BLI_math.h" +#include "BLI_blenlib.h" +#include "BLI_utildefines.h" +#include "BLI_rand.h" +#include "BLI_memarena.h" +#ifdef WITH_FREESTYLE +# include "BLI_edgehash.h" +#endif + +#include "BLT_translation.h" + +#include "DNA_material_types.h" +#include "DNA_curve_types.h" +#include "DNA_group_types.h" +#include "DNA_lamp_types.h" +#include "DNA_image_types.h" +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_modifier_types.h" +#include "DNA_node_types.h" +#include "DNA_object_types.h" +#include "DNA_object_fluidsim_types.h" +#include "DNA_particle_types.h" +#include "DNA_scene_types.h" +#include "DNA_texture_types.h" + +#include "BKE_anim.h" +#include "BKE_curve.h" +#include "BKE_customdata.h" +#include "BKE_colortools.h" +#include "BKE_displist.h" +#include "BKE_depsgraph.h" +#include "BKE_DerivedMesh.h" +#include "BKE_global.h" +#include "BKE_key.h" +#include "BKE_image.h" +#include "BKE_lattice.h" +#include "BKE_material.h" +#include "BKE_main.h" +#include "BKE_mball.h" +#include "BKE_mesh.h" +#include "BKE_modifier.h" +#include "BKE_node.h" +#include "BKE_object.h" +#include "BKE_particle.h" +#include "BKE_scene.h" + +#include "PIL_time.h" + +#include "envmap.h" +#include "occlusion.h" +#include "pointdensity.h" +#include "voxeldata.h" +#include "render_types.h" +#include "rendercore.h" +#include "renderdatabase.h" +#include "renderpipeline.h" +#include "shadbuf.h" +#include "shading.h" +#include "strand.h" +#include "texture.h" +#include "volume_precache.h" +#include "sss.h" +#include "zbuf.h" +#include "sunsky.h" + +/* 10 times larger than normal epsilon, test it on default nurbs sphere with ray_transp (for quad detection) */ +/* or for checking vertex normal flips */ +#define FLT_EPSILON10 1.19209290e-06F + +/* could enable at some point but for now there are far too many conversions */ +#ifdef __GNUC__ +# pragma GCC diagnostic ignored "-Wdouble-promotion" +#endif + +/* ------------------------------------------------------------------------- */ +/* tool functions/defines for ad hoc simplification and possible future + * cleanup */ +/* ------------------------------------------------------------------------- */ + +#define UVTOINDEX(u, v) (startvlak + (u) * sizev + (v)) +/* + * + * NOTE THAT U/V COORDINATES ARE SOMETIMES SWAPPED !! + * + * ^ ()----p4----p3----() + * | | | | | + * u | | F1 | F2 | + * | | | | + * ()----p1----p2----() + * v -> + */ + +/* ------------------------------------------------------------------------- */ + +#define CD_MASK_RENDER_INTERNAL \ + (CD_MASK_BAREMESH | CD_MASK_MFACE | CD_MASK_MTFACE | CD_MASK_MCOL) + +static void split_v_renderfaces(ObjectRen *obr, int startvlak, int UNUSED(startvert), int UNUSED(usize), int vsize, int uIndex, int UNUSED(cyclu), int cyclv) +{ + int vLen = vsize-1+(!!cyclv); + int v; + + for (v=0; v<vLen; v++) { + VlakRen *vlr = RE_findOrAddVlak(obr, startvlak + vLen*uIndex + v); + VlakRen *vlr_other; + VertRen *vert = RE_vertren_copy(obr, vlr->v2); + + if (cyclv) { + vlr->v2 = vert; + + if (v == vLen - 1) { + vlr_other = RE_findOrAddVlak(obr, startvlak + vLen*uIndex + 0); + vlr_other->v1 = vert; + } + else { + vlr_other = RE_findOrAddVlak(obr, startvlak + vLen*uIndex + v+1); + vlr_other->v1 = vert; + } + } + else { + vlr->v2 = vert; + + if (v < vLen - 1) { + vlr_other = RE_findOrAddVlak(obr, startvlak + vLen*uIndex + v+1); + vlr_other->v1 = vert; + } + + if (v == 0) { + vlr->v1 = RE_vertren_copy(obr, vlr->v1); + } + } + } +} + +/* ------------------------------------------------------------------------- */ +/* Stress, tangents and normals */ +/* ------------------------------------------------------------------------- */ + +static void calc_edge_stress_add(float *accum, VertRen *v1, VertRen *v2) +{ + float len= len_v3v3(v1->co, v2->co)/len_v3v3(v1->orco, v2->orco); + float *acc; + + acc= accum + 2*v1->index; + acc[0]+= len; + acc[1]+= 1.0f; + + acc= accum + 2*v2->index; + acc[0]+= len; + acc[1]+= 1.0f; +} + +static void calc_edge_stress(Render *UNUSED(re), ObjectRen *obr, Mesh *me) +{ + float loc[3], size[3], *accum, *acc, *accumoffs, *stress; + int a; + + if (obr->totvert==0) return; + + BKE_mesh_texspace_get(me, loc, NULL, size); + + accum= MEM_callocN(2*sizeof(float)*obr->totvert, "temp accum for stress"); + + /* de-normalize orco */ + for (a=0; a<obr->totvert; a++) { + VertRen *ver= RE_findOrAddVert(obr, a); + if (ver->orco) { + ver->orco[0]= ver->orco[0]*size[0] +loc[0]; + ver->orco[1]= ver->orco[1]*size[1] +loc[1]; + ver->orco[2]= ver->orco[2]*size[2] +loc[2]; + } + } + + /* add stress values */ + accumoffs= accum; /* so we can use vertex index */ + for (a=0; a<obr->totvlak; a++) { + VlakRen *vlr= RE_findOrAddVlak(obr, a); + + if (vlr->v1->orco && vlr->v4) { + calc_edge_stress_add(accumoffs, vlr->v1, vlr->v2); + calc_edge_stress_add(accumoffs, vlr->v2, vlr->v3); + calc_edge_stress_add(accumoffs, vlr->v3, vlr->v1); + if (vlr->v4) { + calc_edge_stress_add(accumoffs, vlr->v3, vlr->v4); + calc_edge_stress_add(accumoffs, vlr->v4, vlr->v1); + calc_edge_stress_add(accumoffs, vlr->v2, vlr->v4); + } + } + } + + for (a=0; a<obr->totvert; a++) { + VertRen *ver= RE_findOrAddVert(obr, a); + if (ver->orco) { + /* find stress value */ + acc= accumoffs + 2*ver->index; + if (acc[1]!=0.0f) + acc[0]/= acc[1]; + stress= RE_vertren_get_stress(obr, ver, 1); + *stress= *acc; + + /* restore orcos */ + ver->orco[0] = (ver->orco[0]-loc[0])/size[0]; + ver->orco[1] = (ver->orco[1]-loc[1])/size[1]; + ver->orco[2] = (ver->orco[2]-loc[2])/size[2]; + } + } + + MEM_freeN(accum); +} + +/* gets tangent from tface or orco */ +static void calc_tangent_vector(ObjectRen *obr, VlakRen *vlr, int do_tangent) +{ + MTFace *tface= RE_vlakren_get_tface(obr, vlr, obr->actmtface, NULL, 0); + VertRen *v1=vlr->v1, *v2=vlr->v2, *v3=vlr->v3, *v4=vlr->v4; + float tang[3], *tav; + float *uv1, *uv2, *uv3, *uv4; + float uv[4][2]; + + if (tface) { + uv1= tface->uv[0]; + uv2= tface->uv[1]; + uv3= tface->uv[2]; + uv4= tface->uv[3]; + } + else if (v1->orco) { + uv1= uv[0]; uv2= uv[1]; uv3= uv[2]; uv4= uv[3]; + map_to_sphere(&uv[0][0], &uv[0][1], v1->orco[0], v1->orco[1], v1->orco[2]); + map_to_sphere(&uv[1][0], &uv[1][1], v2->orco[0], v2->orco[1], v2->orco[2]); + map_to_sphere(&uv[2][0], &uv[2][1], v3->orco[0], v3->orco[1], v3->orco[2]); + if (v4) + map_to_sphere(&uv[3][0], &uv[3][1], v4->orco[0], v4->orco[1], v4->orco[2]); + } + else return; + + tangent_from_uv_v3(uv1, uv2, uv3, v1->co, v2->co, v3->co, vlr->n, tang); + + if (do_tangent) { + tav= RE_vertren_get_tangent(obr, v1, 1); + add_v3_v3(tav, tang); + tav= RE_vertren_get_tangent(obr, v2, 1); + add_v3_v3(tav, tang); + tav= RE_vertren_get_tangent(obr, v3, 1); + add_v3_v3(tav, tang); + } + + if (v4) { + tangent_from_uv_v3(uv1, uv3, uv4, v1->co, v3->co, v4->co, vlr->n, tang); + + if (do_tangent) { + tav= RE_vertren_get_tangent(obr, v1, 1); + add_v3_v3(tav, tang); + tav= RE_vertren_get_tangent(obr, v3, 1); + add_v3_v3(tav, tang); + tav= RE_vertren_get_tangent(obr, v4, 1); + add_v3_v3(tav, tang); + } + } +} + + + +/**************************************************************** + ************ tangent space generation interface **************** + ****************************************************************/ + +typedef struct { + ObjectRen *obr; + int mtface_index; +} SRenderMeshToTangent; + +/* interface */ +#include "mikktspace.h" + +static int GetNumFaces(const SMikkTSpaceContext *pContext) +{ + SRenderMeshToTangent *pMesh = (SRenderMeshToTangent *) pContext->m_pUserData; + return pMesh->obr->totvlak; +} + +static int GetNumVertsOfFace(const SMikkTSpaceContext *pContext, const int face_num) +{ + SRenderMeshToTangent *pMesh = (SRenderMeshToTangent *) pContext->m_pUserData; + VlakRen *vlr= RE_findOrAddVlak(pMesh->obr, face_num); + return vlr->v4!=NULL ? 4 : 3; +} + +static void GetPosition(const SMikkTSpaceContext *pContext, float r_co[3], const int face_num, const int vert_index) +{ + //assert(vert_index>=0 && vert_index<4); + SRenderMeshToTangent *pMesh = (SRenderMeshToTangent *) pContext->m_pUserData; + VlakRen *vlr= RE_findOrAddVlak(pMesh->obr, face_num); + const float *co = (&vlr->v1)[vert_index]->co; + copy_v3_v3(r_co, co); +} + +static void GetTextureCoordinate(const SMikkTSpaceContext *pContext, float r_uv[2], const int face_num, const int vert_index) +{ + //assert(vert_index>=0 && vert_index<4); + SRenderMeshToTangent *pMesh = (SRenderMeshToTangent *) pContext->m_pUserData; + VlakRen *vlr= RE_findOrAddVlak(pMesh->obr, face_num); + MTFace *tface= RE_vlakren_get_tface(pMesh->obr, vlr, pMesh->mtface_index, NULL, 0); + const float *coord; + + if (tface != NULL) { + coord= tface->uv[vert_index]; + copy_v2_v2(r_uv, coord); + } + else if ((coord = (&vlr->v1)[vert_index]->orco)) { + map_to_sphere(&r_uv[0], &r_uv[1], coord[0], coord[1], coord[2]); + } + else { /* else we get un-initialized value, 0.0 ok default? */ + zero_v2(r_uv); + } +} + +static void GetNormal(const SMikkTSpaceContext *pContext, float r_no[3], const int face_num, const int vert_index) +{ + //assert(vert_index>=0 && vert_index<4); + SRenderMeshToTangent *pMesh = (SRenderMeshToTangent *) pContext->m_pUserData; + VlakRen *vlr= RE_findOrAddVlak(pMesh->obr, face_num); + + if (vlr->flag & ME_SMOOTH) { + const float *n = (&vlr->v1)[vert_index]->n; + copy_v3_v3(r_no, n); + } + else { + negate_v3_v3(r_no, vlr->n); + } +} +static void SetTSpace(const SMikkTSpaceContext *pContext, const float fvTangent[3], const float fSign, const int face_num, const int iVert) +{ + //assert(vert_index>=0 && vert_index<4); + SRenderMeshToTangent *pMesh = (SRenderMeshToTangent *) pContext->m_pUserData; + VlakRen *vlr = RE_findOrAddVlak(pMesh->obr, face_num); + float *ftang = RE_vlakren_get_nmap_tangent(pMesh->obr, vlr, pMesh->mtface_index, true); + if (ftang!=NULL) { + copy_v3_v3(&ftang[iVert*4+0], fvTangent); + ftang[iVert*4+3]=fSign; + } +} + +static void calc_vertexnormals(Render *UNUSED(re), ObjectRen *obr, bool do_vertex_normal, bool do_tangent, bool do_nmap_tangent) +{ + int a; + + /* clear all vertex normals */ + if (do_vertex_normal) { + for (a=0; a<obr->totvert; a++) { + VertRen *ver= RE_findOrAddVert(obr, a); + ver->n[0]=ver->n[1]=ver->n[2]= 0.0f; + } + } + + /* calculate cos of angles and point-masses, use as weight factor to + * add face normal to vertex */ + for (a=0; a<obr->totvlak; a++) { + VlakRen *vlr= RE_findOrAddVlak(obr, a); + if (do_vertex_normal && vlr->flag & ME_SMOOTH) { + float *n4= (vlr->v4)? vlr->v4->n: NULL; + const float *c4= (vlr->v4)? vlr->v4->co: NULL; + + accumulate_vertex_normals_v3(vlr->v1->n, vlr->v2->n, vlr->v3->n, n4, + vlr->n, vlr->v1->co, vlr->v2->co, vlr->v3->co, c4); + } + if (do_tangent) { + /* tangents still need to be calculated for flat faces too */ + /* weighting removed, they are not vertexnormals */ + calc_tangent_vector(obr, vlr, do_tangent); + } + } + + /* do solid faces */ + for (a=0; a<obr->totvlak; a++) { + VlakRen *vlr= RE_findOrAddVlak(obr, a); + + if (do_vertex_normal && (vlr->flag & ME_SMOOTH)==0) { + if (is_zero_v3(vlr->v1->n)) copy_v3_v3(vlr->v1->n, vlr->n); + if (is_zero_v3(vlr->v2->n)) copy_v3_v3(vlr->v2->n, vlr->n); + if (is_zero_v3(vlr->v3->n)) copy_v3_v3(vlr->v3->n, vlr->n); + if (vlr->v4 && is_zero_v3(vlr->v4->n)) copy_v3_v3(vlr->v4->n, vlr->n); + } + } + + /* normalize vertex normals */ + for (a=0; a<obr->totvert; a++) { + VertRen *ver= RE_findOrAddVert(obr, a); + normalize_v3(ver->n); + if (do_tangent) { + float *tav= RE_vertren_get_tangent(obr, ver, 0); + if (tav) { + /* orthonorm. */ + const float tdn = dot_v3v3(tav, ver->n); + tav[0] -= ver->n[0]*tdn; + tav[1] -= ver->n[1]*tdn; + tav[2] -= ver->n[2]*tdn; + normalize_v3(tav); + } + } + } + + /* normal mapping tangent with mikktspace */ + if (do_nmap_tangent != false) { + SRenderMeshToTangent mesh2tangent; + SMikkTSpaceContext sContext; + SMikkTSpaceInterface sInterface; + memset(&mesh2tangent, 0, sizeof(SRenderMeshToTangent)); + memset(&sContext, 0, sizeof(SMikkTSpaceContext)); + memset(&sInterface, 0, sizeof(SMikkTSpaceInterface)); + + mesh2tangent.obr = obr; + + sContext.m_pUserData = &mesh2tangent; + sContext.m_pInterface = &sInterface; + sInterface.m_getNumFaces = GetNumFaces; + sInterface.m_getNumVerticesOfFace = GetNumVertsOfFace; + sInterface.m_getPosition = GetPosition; + sInterface.m_getTexCoord = GetTextureCoordinate; + sInterface.m_getNormal = GetNormal; + sInterface.m_setTSpaceBasic = SetTSpace; + + for (a = 0; a < MAX_MTFACE; a++) { + if (obr->tangent_mask & 1 << a) { + mesh2tangent.mtface_index = a; + genTangSpaceDefault(&sContext); + } + } + } +} + +/* ------------------------------------------------------------------------- */ +/* Autosmoothing: */ +/* ------------------------------------------------------------------------- */ + +typedef struct ASvert { + int totface; + ListBase faces; +} ASvert; + +typedef struct ASface { + struct ASface *next, *prev; + VlakRen *vlr[4]; + VertRen *nver[4]; +} ASface; + +static int as_addvert(ASvert *asv, VertRen *v1, VlakRen *vlr) +{ + ASface *asf; + int a = -1; + + if (v1 == NULL) + return a; + + asf = asv->faces.last; + if (asf) { + for (a = 0; a < 4 && asf->vlr[a]; a++) { + } + } + else { + a = 4; + } + + /* new face struct */ + if (a == 4) { + a = 0; + asf = MEM_callocN(sizeof(ASface), "asface"); + BLI_addtail(&asv->faces, asf); + } + + asf->vlr[a] = vlr; + asv->totface++; + + return a; +} + +static VertRen *as_findvertex_lnor(VlakRen *vlr, VertRen *ver, ASvert *asv, const float lnor[3]) +{ + /* return when new vertex already was made, or existing one is OK */ + ASface *asf; + int a; + + /* First face, we can use existing vert and assign it current lnor! */ + if (asv->totface == 1) { + copy_v3_v3(ver->n, lnor); + return ver; + } + + /* In case existing ver has same normal as current lnor, we can simply use it! */ + if (equals_v3v3(lnor, ver->n)) { + return ver; + } + + asf = asv->faces.first; + while (asf) { + for (a = 0; a < 4; a++) { + if (asf->vlr[a] && asf->vlr[a] != vlr) { + /* this face already made a copy for this vertex! */ + if (asf->nver[a]) { + if (equals_v3v3(lnor, asf->nver[a]->n)) { + return asf->nver[a]; + } + } + } + } + asf = asf->next; + } + + return NULL; +} + +static void as_addvert_lnor(ObjectRen *obr, ASvert *asv, VertRen *ver, VlakRen *vlr, const short _lnor[3]) +{ + VertRen *v1; + ASface *asf; + int asf_idx; + float lnor[3]; + + normal_short_to_float_v3(lnor, _lnor); + + asf_idx = as_addvert(asv, ver, vlr); + if (asf_idx < 0) { + return; + } + asf = asv->faces.last; + + /* already made a new vertex within threshold? */ + v1 = as_findvertex_lnor(vlr, ver, asv, lnor); + if (v1 == NULL) { + /* make a new vertex */ + v1 = RE_vertren_copy(obr, ver); + copy_v3_v3(v1->n, lnor); + } + if (v1 != ver) { + asf->nver[asf_idx] = v1; + if (vlr->v1 == ver) vlr->v1 = v1; + if (vlr->v2 == ver) vlr->v2 = v1; + if (vlr->v3 == ver) vlr->v3 = v1; + if (vlr->v4 == ver) vlr->v4 = v1; + } +} + +/* note; autosmooth happens in object space still, after applying autosmooth we rotate */ +/* note2; actually, when original mesh and displist are equal sized, face normals are from original mesh */ +static void autosmooth(Render *UNUSED(re), ObjectRen *obr, float mat[4][4], short (*lnors)[4][3]) +{ + ASvert *asverts; + VertRen *ver; + VlakRen *vlr; + int a, totvert; + + float rot[3][3]; + + /* Note: For normals, we only want rotation, not scaling component. + * Negative scales (aka mirroring) give wrong results, see T44102. */ + if (lnors) { + float mat3[3][3], size[3]; + + copy_m3_m4(mat3, mat); + mat3_to_rot_size(rot, size, mat3); + } + + if (obr->totvert == 0) + return; + + totvert = obr->totvert; + asverts = MEM_callocN(sizeof(ASvert) * totvert, "all smooth verts"); + + if (lnors) { + /* We construct listbase of all vertices and pointers to faces, and add new verts when needed + * (i.e. when existing ones do not share the same (loop)normal). + */ + for (a = 0; a < obr->totvlak; a++, lnors++) { + vlr = RE_findOrAddVlak(obr, a); + /* skip wire faces */ + if (vlr->v2 != vlr->v3) { + as_addvert_lnor(obr, asverts+vlr->v1->index, vlr->v1, vlr, (const short*)lnors[0][0]); + as_addvert_lnor(obr, asverts+vlr->v2->index, vlr->v2, vlr, (const short*)lnors[0][1]); + as_addvert_lnor(obr, asverts+vlr->v3->index, vlr->v3, vlr, (const short*)lnors[0][2]); + if (vlr->v4) + as_addvert_lnor(obr, asverts+vlr->v4->index, vlr->v4, vlr, (const short*)lnors[0][3]); + } + } + } + + /* free */ + for (a = 0; a < totvert; a++) { + BLI_freelistN(&asverts[a].faces); + } + MEM_freeN(asverts); + + /* rotate vertices and calculate normal of faces */ + for (a = 0; a < obr->totvert; a++) { + ver = RE_findOrAddVert(obr, a); + mul_m4_v3(mat, ver->co); + if (lnors) { + mul_m3_v3(rot, ver->n); + negate_v3(ver->n); + } + } + for (a = 0; a < obr->totvlak; a++) { + vlr = RE_findOrAddVlak(obr, a); + + /* skip wire faces */ + if (vlr->v2 != vlr->v3) { + if (vlr->v4) + normal_quad_v3(vlr->n, vlr->v4->co, vlr->v3->co, vlr->v2->co, vlr->v1->co); + else + normal_tri_v3(vlr->n, vlr->v3->co, vlr->v2->co, vlr->v1->co); + } + } +} + +/* ------------------------------------------------------------------------- */ +/* Orco hash and Materials */ +/* ------------------------------------------------------------------------- */ + +static float *get_object_orco(Render *re, void *ob) +{ + if (!re->orco_hash) { + return NULL; + } + + return BLI_ghash_lookup(re->orco_hash, ob); +} + +static void set_object_orco(Render *re, void *ob, float *orco) +{ + if (!re->orco_hash) + re->orco_hash = BLI_ghash_ptr_new("set_object_orco gh"); + + BLI_ghash_insert(re->orco_hash, ob, orco); +} + +static void free_mesh_orco_hash(Render *re) +{ + if (re->orco_hash) { + BLI_ghash_free(re->orco_hash, NULL, MEM_freeN); + re->orco_hash = NULL; + } +} + +static void check_material_mapto(Material *ma) +{ + int a; + ma->mapto_textured = 0; + + /* cache which inputs are actually textured. + * this can avoid a bit of time spent iterating through all the texture slots, map inputs and map tos + * every time a property which may or may not be textured is accessed */ + + for (a=0; a<MAX_MTEX; a++) { + if (ma->mtex[a] && ma->mtex[a]->tex) { + /* currently used only in volume render, so we'll check for those flags */ + if (ma->mtex[a]->mapto & MAP_DENSITY) ma->mapto_textured |= MAP_DENSITY; + if (ma->mtex[a]->mapto & MAP_EMISSION) ma->mapto_textured |= MAP_EMISSION; + if (ma->mtex[a]->mapto & MAP_EMISSION_COL) ma->mapto_textured |= MAP_EMISSION_COL; + if (ma->mtex[a]->mapto & MAP_SCATTERING) ma->mapto_textured |= MAP_SCATTERING; + if (ma->mtex[a]->mapto & MAP_TRANSMISSION_COL) ma->mapto_textured |= MAP_TRANSMISSION_COL; + if (ma->mtex[a]->mapto & MAP_REFLECTION) ma->mapto_textured |= MAP_REFLECTION; + if (ma->mtex[a]->mapto & MAP_REFLECTION_COL) ma->mapto_textured |= MAP_REFLECTION_COL; + } + } +} +static void flag_render_node_material(Render *re, bNodeTree *ntree) +{ + bNode *node; + + for (node = ntree->nodes.first; node; node = node->next) { + if (node->id) { + if (GS(node->id->name)==ID_MA) { + Material *ma= (Material *)node->id; + + if ((ma->mode & MA_TRANSP) && (ma->mode & MA_ZTRANSP)) + re->flag |= R_ZTRA; + + ma->flag |= MA_IS_USED; + } + else if (node->type==NODE_GROUP) + flag_render_node_material(re, (bNodeTree *)node->id); + } + } +} + +static Material *give_render_material(Render *re, Object *ob, short nr) +{ + extern Material defmaterial; /* material.c */ + Material *ma; + + ma= give_current_material(ob, nr); + if (ma==NULL) + ma= &defmaterial; + + if (re->r.mode & R_SPEED) ma->texco |= NEED_UV; + + if (ma->material_type == MA_TYPE_VOLUME) { + ma->mode |= MA_TRANSP; + ma->mode &= ~MA_SHADBUF; + } + if ((ma->mode & MA_TRANSP) && (ma->mode & MA_ZTRANSP)) + re->flag |= R_ZTRA; + + /* for light groups and SSS */ + ma->flag |= MA_IS_USED; + + if (ma->nodetree && ma->use_nodes) + flag_render_node_material(re, ma->nodetree); + + check_material_mapto(ma); + + return ma; +} + +/* ------------------------------------------------------------------------- */ +/* Particles */ +/* ------------------------------------------------------------------------- */ +typedef struct ParticleStrandData { + struct MCol *mcol; + float *orco, *uvco, *surfnor; + float time, adapt_angle, adapt_pix, size; + int totuv, totcol; + int first, line, adapt, override_uv; +} +ParticleStrandData; +/* future thread problem... */ +static void static_particle_strand(Render *re, ObjectRen *obr, Material *ma, ParticleStrandData *sd, const float vec[3], const float vec1[3]) +{ + static VertRen *v1= NULL, *v2= NULL; + VlakRen *vlr= NULL; + float nor[3], cross[3], crosslen, w, dx, dy, width; + static float anor[3], avec[3]; + int flag, i; + static int second=0; + + sub_v3_v3v3(nor, vec, vec1); + normalize_v3(nor); /* nor needed as tangent */ + cross_v3_v3v3(cross, vec, nor); + + /* turn cross in pixelsize */ + w= vec[2]*re->winmat[2][3] + re->winmat[3][3]; + dx= re->winx*cross[0]*re->winmat[0][0]; + dy= re->winy*cross[1]*re->winmat[1][1]; + w = sqrtf(dx * dx + dy * dy) / w; + + if (w!=0.0f) { + float fac; + if (ma->strand_ease!=0.0f) { + if (ma->strand_ease<0.0f) + fac= pow(sd->time, 1.0f+ma->strand_ease); + else + fac= pow(sd->time, 1.0f/(1.0f-ma->strand_ease)); + } + else fac= sd->time; + + width= ((1.0f-fac)*ma->strand_sta + (fac)*ma->strand_end); + + /* use actual Blender units for strand width and fall back to minimum width */ + if (ma->mode & MA_STR_B_UNITS) { + crosslen= len_v3(cross); + w= 2.0f*crosslen*ma->strand_min/w; + + if (width < w) + width= w; + + /*cross is the radius of the strand so we want it to be half of full width */ + mul_v3_fl(cross, 0.5f/crosslen); + } + else + width/=w; + + mul_v3_fl(cross, width); + } + + if (ma->mode & MA_TANGENT_STR) + flag= R_SMOOTH|R_TANGENT; + else + flag= R_SMOOTH; + + /* only 1 pixel wide strands filled in as quads now, otherwise zbuf errors */ + if (ma->strand_sta==1.0f) + flag |= R_STRAND; + + /* single face line */ + if (sd->line) { + vlr= RE_findOrAddVlak(obr, obr->totvlak++); + vlr->flag= flag; + vlr->v1= RE_findOrAddVert(obr, obr->totvert++); + vlr->v2= RE_findOrAddVert(obr, obr->totvert++); + vlr->v3= RE_findOrAddVert(obr, obr->totvert++); + vlr->v4= RE_findOrAddVert(obr, obr->totvert++); + + copy_v3_v3(vlr->v1->co, vec); + add_v3_v3(vlr->v1->co, cross); + copy_v3_v3(vlr->v1->n, nor); + vlr->v1->orco= sd->orco; + vlr->v1->accum = -1.0f; /* accum abuse for strand texco */ + + copy_v3_v3(vlr->v2->co, vec); + sub_v3_v3v3(vlr->v2->co, vlr->v2->co, cross); + copy_v3_v3(vlr->v2->n, nor); + vlr->v2->orco= sd->orco; + vlr->v2->accum= vlr->v1->accum; + + copy_v3_v3(vlr->v4->co, vec1); + add_v3_v3(vlr->v4->co, cross); + copy_v3_v3(vlr->v4->n, nor); + vlr->v4->orco= sd->orco; + vlr->v4->accum = 1.0f; /* accum abuse for strand texco */ + + copy_v3_v3(vlr->v3->co, vec1); + sub_v3_v3v3(vlr->v3->co, vlr->v3->co, cross); + copy_v3_v3(vlr->v3->n, nor); + vlr->v3->orco= sd->orco; + vlr->v3->accum= vlr->v4->accum; + + normal_quad_v3(vlr->n, vlr->v4->co, vlr->v3->co, vlr->v2->co, vlr->v1->co); + + vlr->mat= ma; + vlr->ec= ME_V2V3; + + if (sd->surfnor) { + float *snor= RE_vlakren_get_surfnor(obr, vlr, 1); + copy_v3_v3(snor, sd->surfnor); + } + + if (sd->uvco) { + for (i=0; i<sd->totuv; i++) { + MTFace *mtf; + mtf=RE_vlakren_get_tface(obr, vlr, i, NULL, 1); + mtf->uv[0][0]=mtf->uv[1][0]= + mtf->uv[2][0]=mtf->uv[3][0]=(sd->uvco+2*i)[0]; + mtf->uv[0][1]=mtf->uv[1][1]= + mtf->uv[2][1]=mtf->uv[3][1]=(sd->uvco+2*i)[1]; + } + if (sd->override_uv>=0) { + MTFace *mtf; + mtf=RE_vlakren_get_tface(obr, vlr, sd->override_uv, NULL, 0); + + mtf->uv[0][0]=mtf->uv[3][0]=0.0f; + mtf->uv[1][0]=mtf->uv[2][0]=1.0f; + + mtf->uv[0][1]=mtf->uv[1][1]=0.0f; + mtf->uv[2][1]=mtf->uv[3][1]=1.0f; + } + } + if (sd->mcol) { + for (i=0; i<sd->totcol; i++) { + MCol *mc; + mc=RE_vlakren_get_mcol(obr, vlr, i, NULL, 1); + mc[0]=mc[1]=mc[2]=mc[3]=sd->mcol[i]; + mc[0]=mc[1]=mc[2]=mc[3]=sd->mcol[i]; + } + } + } + /* first two vertices of a strand */ + else if (sd->first) { + if (sd->adapt) { + copy_v3_v3(anor, nor); + copy_v3_v3(avec, vec); + second=1; + } + + v1= RE_findOrAddVert(obr, obr->totvert++); + v2= RE_findOrAddVert(obr, obr->totvert++); + + copy_v3_v3(v1->co, vec); + add_v3_v3(v1->co, cross); + copy_v3_v3(v1->n, nor); + v1->orco= sd->orco; + v1->accum = -1.0f; /* accum abuse for strand texco */ + + copy_v3_v3(v2->co, vec); + sub_v3_v3v3(v2->co, v2->co, cross); + copy_v3_v3(v2->n, nor); + v2->orco= sd->orco; + v2->accum= v1->accum; + } + /* more vertices & faces to strand */ + else { + if (sd->adapt==0 || second) { + vlr= RE_findOrAddVlak(obr, obr->totvlak++); + vlr->flag= flag; + vlr->v1= v1; + vlr->v2= v2; + vlr->v3= RE_findOrAddVert(obr, obr->totvert++); + vlr->v4= RE_findOrAddVert(obr, obr->totvert++); + + v1= vlr->v4; /* cycle */ + v2= vlr->v3; /* cycle */ + + + if (sd->adapt) { + second=0; + copy_v3_v3(anor, nor); + copy_v3_v3(avec, vec); + } + + } + else if (sd->adapt) { + float dvec[3], pvec[3]; + sub_v3_v3v3(dvec, avec, vec); + project_v3_v3v3(pvec, dvec, vec); + sub_v3_v3v3(dvec, dvec, pvec); + + w= vec[2]*re->winmat[2][3] + re->winmat[3][3]; + dx= re->winx*dvec[0]*re->winmat[0][0]/w; + dy= re->winy*dvec[1]*re->winmat[1][1]/w; + w = sqrtf(dx * dx + dy * dy); + if (dot_v3v3(anor, nor)<sd->adapt_angle && w>sd->adapt_pix) { + vlr= RE_findOrAddVlak(obr, obr->totvlak++); + vlr->flag= flag; + vlr->v1= v1; + vlr->v2= v2; + vlr->v3= RE_findOrAddVert(obr, obr->totvert++); + vlr->v4= RE_findOrAddVert(obr, obr->totvert++); + + v1= vlr->v4; /* cycle */ + v2= vlr->v3; /* cycle */ + + copy_v3_v3(anor, nor); + copy_v3_v3(avec, vec); + } + else { + vlr= RE_findOrAddVlak(obr, obr->totvlak-1); + } + } + + copy_v3_v3(vlr->v4->co, vec); + add_v3_v3(vlr->v4->co, cross); + copy_v3_v3(vlr->v4->n, nor); + vlr->v4->orco= sd->orco; + vlr->v4->accum= -1.0f + 2.0f * sd->time; /* accum abuse for strand texco */ + + copy_v3_v3(vlr->v3->co, vec); + sub_v3_v3v3(vlr->v3->co, vlr->v3->co, cross); + copy_v3_v3(vlr->v3->n, nor); + vlr->v3->orco= sd->orco; + vlr->v3->accum= vlr->v4->accum; + + normal_quad_v3(vlr->n, vlr->v4->co, vlr->v3->co, vlr->v2->co, vlr->v1->co); + + vlr->mat= ma; + vlr->ec= ME_V2V3; + + if (sd->surfnor) { + float *snor= RE_vlakren_get_surfnor(obr, vlr, 1); + copy_v3_v3(snor, sd->surfnor); + } + + if (sd->uvco) { + for (i=0; i<sd->totuv; i++) { + MTFace *mtf; + mtf=RE_vlakren_get_tface(obr, vlr, i, NULL, 1); + mtf->uv[0][0]=mtf->uv[1][0]= + mtf->uv[2][0]=mtf->uv[3][0]=(sd->uvco+2*i)[0]; + mtf->uv[0][1]=mtf->uv[1][1]= + mtf->uv[2][1]=mtf->uv[3][1]=(sd->uvco+2*i)[1]; + } + if (sd->override_uv>=0) { + MTFace *mtf; + mtf=RE_vlakren_get_tface(obr, vlr, sd->override_uv, NULL, 0); + + mtf->uv[0][0]=mtf->uv[3][0]=0.0f; + mtf->uv[1][0]=mtf->uv[2][0]=1.0f; + + mtf->uv[0][1]=mtf->uv[1][1]=(vlr->v1->accum+1.0f)/2.0f; + mtf->uv[2][1]=mtf->uv[3][1]=(vlr->v3->accum+1.0f)/2.0f; + } + } + if (sd->mcol) { + for (i=0; i<sd->totcol; i++) { + MCol *mc; + mc=RE_vlakren_get_mcol(obr, vlr, i, NULL, 1); + mc[0]=mc[1]=mc[2]=mc[3]=sd->mcol[i]; + mc[0]=mc[1]=mc[2]=mc[3]=sd->mcol[i]; + } + } + } +} + +static void static_particle_wire(ObjectRen *obr, Material *ma, const float vec[3], const float vec1[3], int first, int line) +{ + VlakRen *vlr; + static VertRen *v1; + + if (line) { + vlr= RE_findOrAddVlak(obr, obr->totvlak++); + vlr->v1= RE_findOrAddVert(obr, obr->totvert++); + vlr->v2= RE_findOrAddVert(obr, obr->totvert++); + vlr->v3= vlr->v2; + vlr->v4= NULL; + + copy_v3_v3(vlr->v1->co, vec); + copy_v3_v3(vlr->v2->co, vec1); + + sub_v3_v3v3(vlr->n, vec, vec1); + normalize_v3(vlr->n); + copy_v3_v3(vlr->v1->n, vlr->n); + copy_v3_v3(vlr->v2->n, vlr->n); + + vlr->mat= ma; + vlr->ec= ME_V1V2; + + } + else if (first) { + v1= RE_findOrAddVert(obr, obr->totvert++); + copy_v3_v3(v1->co, vec); + } + else { + vlr= RE_findOrAddVlak(obr, obr->totvlak++); + vlr->v1= v1; + vlr->v2= RE_findOrAddVert(obr, obr->totvert++); + vlr->v3= vlr->v2; + vlr->v4= NULL; + + v1= vlr->v2; /* cycle */ + copy_v3_v3(v1->co, vec); + + sub_v3_v3v3(vlr->n, vec, vec1); + normalize_v3(vlr->n); + copy_v3_v3(v1->n, vlr->n); + + vlr->mat= ma; + vlr->ec= ME_V1V2; + } + +} + +static void particle_curve(Render *re, ObjectRen *obr, DerivedMesh *dm, Material *ma, ParticleStrandData *sd, + const float loc[3], const float loc1[3], int seed, float *pa_co) +{ + HaloRen *har = NULL; + + if (ma->material_type == MA_TYPE_WIRE) + static_particle_wire(obr, ma, loc, loc1, sd->first, sd->line); + else if (ma->material_type == MA_TYPE_HALO) { + har= RE_inithalo_particle(re, obr, dm, ma, loc, loc1, sd->orco, sd->uvco, sd->size, 1.0, seed, pa_co); + if (har) har->lay= obr->ob->lay; + } + else + static_particle_strand(re, obr, ma, sd, loc, loc1); +} +static void particle_billboard(Render *re, ObjectRen *obr, Material *ma, ParticleBillboardData *bb) +{ + VlakRen *vlr; + MTFace *mtf; + float xvec[3], yvec[3], zvec[3], bb_center[3]; + /* Number of tiles */ + int totsplit = bb->uv_split * bb->uv_split; + int tile, x, y; + /* Tile offsets */ + float uvx = 0.0f, uvy = 0.0f, uvdx = 1.0f, uvdy = 1.0f, time = 0.0f; + + vlr= RE_findOrAddVlak(obr, obr->totvlak++); + vlr->v1= RE_findOrAddVert(obr, obr->totvert++); + vlr->v2= RE_findOrAddVert(obr, obr->totvert++); + vlr->v3= RE_findOrAddVert(obr, obr->totvert++); + vlr->v4= RE_findOrAddVert(obr, obr->totvert++); + + psys_make_billboard(bb, xvec, yvec, zvec, bb_center); + + add_v3_v3v3(vlr->v1->co, bb_center, xvec); + add_v3_v3(vlr->v1->co, yvec); + mul_m4_v3(re->viewmat, vlr->v1->co); + + sub_v3_v3v3(vlr->v2->co, bb_center, xvec); + add_v3_v3(vlr->v2->co, yvec); + mul_m4_v3(re->viewmat, vlr->v2->co); + + sub_v3_v3v3(vlr->v3->co, bb_center, xvec); + sub_v3_v3v3(vlr->v3->co, vlr->v3->co, yvec); + mul_m4_v3(re->viewmat, vlr->v3->co); + + add_v3_v3v3(vlr->v4->co, bb_center, xvec); + sub_v3_v3(vlr->v4->co, yvec); + mul_m4_v3(re->viewmat, vlr->v4->co); + + normal_quad_v3(vlr->n, vlr->v4->co, vlr->v3->co, vlr->v2->co, vlr->v1->co); + copy_v3_v3(vlr->v1->n, vlr->n); + copy_v3_v3(vlr->v2->n, vlr->n); + copy_v3_v3(vlr->v3->n, vlr->n); + copy_v3_v3(vlr->v4->n, vlr->n); + + vlr->mat= ma; + vlr->ec= ME_V2V3; + + if (bb->uv_split > 1) { + uvdx = uvdy = 1.0f / (float)bb->uv_split; + + if (ELEM(bb->anim, PART_BB_ANIM_AGE, PART_BB_ANIM_FRAME)) { + if (bb->anim == PART_BB_ANIM_FRAME) + time = ((int)(bb->time * bb->lifetime) % totsplit)/(float)totsplit; + else + time = bb->time; + } + else if (bb->anim == PART_BB_ANIM_ANGLE) { + if (bb->align == PART_BB_VIEW) { + time = (float)fmod((bb->tilt + 1.0f) / 2.0f, 1.0); + } + else { + float axis1[3] = {0.0f, 0.0f, 0.0f}; + float axis2[3] = {0.0f, 0.0f, 0.0f}; + + axis1[(bb->align + 1) % 3] = 1.0f; + axis2[(bb->align + 2) % 3] = 1.0f; + + if (bb->lock == 0) { + zvec[bb->align] = 0.0f; + normalize_v3(zvec); + } + + time = saacos(dot_v3v3(zvec, axis1)) / (float)M_PI; + + if (dot_v3v3(zvec, axis2) < 0.0f) + time = 1.0f - time / 2.0f; + else + time /= 2.0f; + } + } + + if (bb->split_offset == PART_BB_OFF_LINEAR) + time = (float)fmod(time + (float)bb->num / (float)totsplit, 1.0f); + else if (bb->split_offset==PART_BB_OFF_RANDOM) + time = (float)fmod(time + bb->random, 1.0f); + + /* Find the coordinates in tile space (integer), then convert to UV + * space (float). Note that Y is flipped. */ + tile = (int)((time + FLT_EPSILON10) * totsplit); + x = tile % bb->uv_split; + y = tile / bb->uv_split; + y = (bb->uv_split - 1) - y; + uvx = uvdx * x; + uvy = uvdy * y; + } + + /* normal UVs */ + if (bb->uv[0] >= 0) { + mtf = RE_vlakren_get_tface(obr, vlr, bb->uv[0], NULL, 1); + mtf->uv[0][0] = 1.0f; + mtf->uv[0][1] = 1.0f; + mtf->uv[1][0] = 0.0f; + mtf->uv[1][1] = 1.0f; + mtf->uv[2][0] = 0.0f; + mtf->uv[2][1] = 0.0f; + mtf->uv[3][0] = 1.0f; + mtf->uv[3][1] = 0.0f; + } + + /* time-index UVs */ + if (bb->uv[1] >= 0) { + mtf = RE_vlakren_get_tface(obr, vlr, bb->uv[1], NULL, 1); + mtf->uv[0][0] = mtf->uv[1][0] = mtf->uv[2][0] = mtf->uv[3][0] = bb->time; + mtf->uv[0][1] = mtf->uv[1][1] = mtf->uv[2][1] = mtf->uv[3][1] = (float)bb->num/(float)bb->totnum; + } + + /* split UVs */ + if (bb->uv_split > 1 && bb->uv[2] >= 0) { + mtf = RE_vlakren_get_tface(obr, vlr, bb->uv[2], NULL, 1); + mtf->uv[0][0] = uvx + uvdx; + mtf->uv[0][1] = uvy + uvdy; + mtf->uv[1][0] = uvx; + mtf->uv[1][1] = uvy + uvdy; + mtf->uv[2][0] = uvx; + mtf->uv[2][1] = uvy; + mtf->uv[3][0] = uvx + uvdx; + mtf->uv[3][1] = uvy; + } +} +static void particle_normal_ren(short ren_as, ParticleSettings *part, Render *re, ObjectRen *obr, DerivedMesh *dm, Material *ma, ParticleStrandData *sd, ParticleBillboardData *bb, ParticleKey *state, int seed, float hasize, float *pa_co) +{ + float loc[3], loc0[3], loc1[3], vel[3]; + + copy_v3_v3(loc, state->co); + + if (ren_as != PART_DRAW_BB) + mul_m4_v3(re->viewmat, loc); + + switch (ren_as) { + case PART_DRAW_LINE: + sd->line = 1; + sd->time = 0.0f; + sd->size = hasize; + + mul_v3_mat3_m4v3(vel, re->viewmat, state->vel); + normalize_v3(vel); + + if (part->draw & PART_DRAW_VEL_LENGTH) + mul_v3_fl(vel, len_v3(state->vel)); + + madd_v3_v3v3fl(loc0, loc, vel, -part->draw_line[0]); + madd_v3_v3v3fl(loc1, loc, vel, part->draw_line[1]); + + particle_curve(re, obr, dm, ma, sd, loc0, loc1, seed, pa_co); + + break; + + case PART_DRAW_BB: + + copy_v3_v3(bb->vec, loc); + copy_v3_v3(bb->vel, state->vel); + + particle_billboard(re, obr, ma, bb); + + break; + + default: + { + HaloRen *har = NULL; + + har = RE_inithalo_particle(re, obr, dm, ma, loc, NULL, sd->orco, sd->uvco, hasize, 0.0, seed, pa_co); + + if (har) har->lay= obr->ob->lay; + + break; + } + } +} +static void get_particle_uvco_mcol(short from, DerivedMesh *dm, float *fuv, int num, ParticleStrandData *sd) +{ + int i; + + /* get uvco */ + if (sd->uvco && ELEM(from, PART_FROM_FACE, PART_FROM_VOLUME)) { + for (i=0; i<sd->totuv; i++) { + if (!ELEM(num, DMCACHE_NOTFOUND, DMCACHE_ISCHILD)) { + MFace *mface = dm->getTessFaceData(dm, num, CD_MFACE); + MTFace *mtface = (MTFace*)CustomData_get_layer_n(&dm->faceData, CD_MTFACE, i); + mtface += num; + + psys_interpolate_uvs(mtface, mface->v4, fuv, sd->uvco + 2 * i); + } + else { + sd->uvco[2*i] = 0.0f; + sd->uvco[2*i + 1] = 0.0f; + } + } + } + + /* get mcol */ + if (sd->mcol && ELEM(from, PART_FROM_FACE, PART_FROM_VOLUME)) { + for (i=0; i<sd->totcol; i++) { + if (!ELEM(num, DMCACHE_NOTFOUND, DMCACHE_ISCHILD)) { + MFace *mface = dm->getTessFaceData(dm, num, CD_MFACE); + MCol *mc = (MCol*)CustomData_get_layer_n(&dm->faceData, CD_MCOL, i); + mc += num * 4; + + psys_interpolate_mcol(mc, mface->v4, fuv, sd->mcol + i); + } + else + memset(&sd->mcol[i], 0, sizeof(MCol)); + } + } +} +static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem *psys, int timeoffset) +{ + Object *ob= obr->ob; +// Object *tob=0; + Material *ma = NULL; + ParticleSystemModifierData *psmd; + ParticleSystem *tpsys = NULL; + ParticleSettings *part, *tpart = NULL; + ParticleData *pars, *pa = NULL, *tpa = NULL; + ParticleKey *states = NULL; + ParticleKey state; + ParticleCacheKey *cache = NULL; + ParticleBillboardData bb; + ParticleSimulationData sim = {NULL}; + ParticleStrandData sd; + StrandBuffer *strandbuf = NULL; + StrandVert *svert = NULL; + StrandBound *sbound = NULL; + StrandRen *strand = NULL; + RNG *rng = NULL; + float loc[3], loc1[3], loc0[3], mat[4][4], nmat[3][3], co[3], nor[3], duplimat[4][4]; + float strandlen=0.0f, curlen=0.0f; + float hasize, pa_size, r_tilt, r_length; + float pa_time, pa_birthtime, pa_dietime; + float random, simplify[2], pa_co[3]; + const float cfra= BKE_scene_frame_get(re->scene); + int i, a, k, max_k=0, totpart; + bool do_simplify = false, do_surfacecache = false, use_duplimat = false; + int totchild=0, step_nbr; + int seed, path_nbr=0, orco1=0, num; + int totface; + + const int *index_mf_to_mpoly = NULL; + const int *index_mp_to_orig = NULL; + +/* 1. check that everything is ok & updated */ + if (psys==NULL) + return 0; + + part=psys->part; + pars=psys->particles; + + if (part==NULL || pars==NULL || !psys_check_enabled(ob, psys, G.is_rendering)) + return 0; + + if (part->ren_as==PART_DRAW_OB || part->ren_as==PART_DRAW_GR || part->ren_as==PART_DRAW_NOT) + return 1; + + if ((re->r.scemode & R_VIEWPORT_PREVIEW) && (ob->mode & OB_MODE_PARTICLE_EDIT)) + return 0; + + if (part->ren_as == PART_DRAW_BB && part->bb_ob == NULL && RE_GetCamera(re) == NULL) + return 0; + +/* 2. start initializing things */ + + /* last possibility to bail out! */ + psmd = psys_get_modifier(ob, psys); + if (!(psmd->modifier.mode & eModifierMode_Render)) + return 0; + + sim.scene= re->scene; + sim.ob= ob; + sim.psys= psys; + sim.psmd= psmd; + + if (part->phystype==PART_PHYS_KEYED) + psys_count_keyed_targets(&sim); + + totchild=psys->totchild; + + /* can happen for disconnected/global hair */ + if (part->type==PART_HAIR && !psys->childcache) + totchild= 0; + + if (re->r.scemode & R_VIEWPORT_PREVIEW) { /* preview render */ + totchild = (int)((float)totchild * (float)part->disp / 100.0f); + step_nbr = 1 << part->draw_step; + } + else { + step_nbr = 1 << part->ren_step; + } + if (ELEM(part->kink, PART_KINK_SPIRAL)) + step_nbr += part->kink_extra_steps; + + psys->flag |= PSYS_DRAWING; + + rng= BLI_rng_new(psys->seed); + + totpart=psys->totpart; + + memset(&sd, 0, sizeof(ParticleStrandData)); + sd.override_uv = -1; + +/* 2.1 setup material stff */ + ma= give_render_material(re, ob, part->omat); + +#if 0 /* XXX old animation system */ + if (ma->ipo) { + calc_ipo(ma->ipo, cfra); + execute_ipo((ID *)ma, ma->ipo); + } +#endif /* XXX old animation system */ + + hasize = ma->hasize; + seed = ma->seed1; + + re->flag |= R_HALO; + + RE_set_customdata_names(obr, &psmd->dm_final->faceData); + sd.totuv = CustomData_number_of_layers(&psmd->dm_final->faceData, CD_MTFACE); + sd.totcol = CustomData_number_of_layers(&psmd->dm_final->faceData, CD_MCOL); + + if (ma->texco & TEXCO_UV && sd.totuv) { + sd.uvco = MEM_callocN(sd.totuv * 2 * sizeof(float), "particle_uvs"); + + if (ma->strand_uvname[0]) { + sd.override_uv = CustomData_get_named_layer_index(&psmd->dm_final->faceData, CD_MTFACE, ma->strand_uvname); + sd.override_uv -= CustomData_get_layer_index(&psmd->dm_final->faceData, CD_MTFACE); + } + } + else + sd.uvco = NULL; + + if (sd.totcol) + sd.mcol = MEM_callocN(sd.totcol * sizeof(MCol), "particle_mcols"); + +/* 2.2 setup billboards */ + if (part->ren_as == PART_DRAW_BB) { + int first_uv = CustomData_get_layer_index(&psmd->dm_final->faceData, CD_MTFACE); + + bb.uv[0] = CustomData_get_named_layer_index(&psmd->dm_final->faceData, CD_MTFACE, psys->bb_uvname[0]); + if (bb.uv[0] < 0) + bb.uv[0] = CustomData_get_active_layer_index(&psmd->dm_final->faceData, CD_MTFACE); + + bb.uv[1] = CustomData_get_named_layer_index(&psmd->dm_final->faceData, CD_MTFACE, psys->bb_uvname[1]); + + bb.uv[2] = CustomData_get_named_layer_index(&psmd->dm_final->faceData, CD_MTFACE, psys->bb_uvname[2]); + + if (first_uv >= 0) { + bb.uv[0] -= first_uv; + bb.uv[1] -= first_uv; + bb.uv[2] -= first_uv; + } + + bb.align = part->bb_align; + bb.anim = part->bb_anim; + bb.lock = part->draw & PART_DRAW_BB_LOCK; + bb.ob = (part->bb_ob ? part->bb_ob : RE_GetCamera(re)); + bb.split_offset = part->bb_split_offset; + bb.totnum = totpart+totchild; + bb.uv_split = part->bb_uv_split; + } + +/* 2.5 setup matrices */ + mul_m4_m4m4(mat, re->viewmat, ob->obmat); + invert_m4_m4(ob->imat, mat); /* need to be that way, for imat texture */ + transpose_m3_m4(nmat, ob->imat); + + if (psys->flag & PSYS_USE_IMAT) { + /* psys->imat is the original emitter's inverse matrix, ob->obmat is the duplicated object's matrix */ + mul_m4_m4m4(duplimat, ob->obmat, psys->imat); + use_duplimat = true; + } + +/* 2.6 setup strand rendering */ + if (part->ren_as == PART_DRAW_PATH && psys->pathcache) { + path_nbr = step_nbr; + + if (path_nbr) { + if (!ELEM(ma->material_type, MA_TYPE_HALO, MA_TYPE_WIRE)) { + sd.orco = get_object_orco(re, psys); + if (!sd.orco) { + sd.orco = MEM_mallocN(3*sizeof(float)*(totpart+totchild), "particle orcos"); + set_object_orco(re, psys, sd.orco); + } + } + } + + if (part->draw & PART_DRAW_REN_ADAPT) { + sd.adapt = 1; + sd.adapt_pix = (float)part->adapt_pix; + sd.adapt_angle = cosf(DEG2RADF((float)part->adapt_angle)); + } + + if (part->draw & PART_DRAW_REN_STRAND) { + strandbuf= RE_addStrandBuffer(obr, (totpart+totchild)*(path_nbr+1)); + strandbuf->ma= ma; + strandbuf->lay= ob->lay; + copy_m4_m4(strandbuf->winmat, re->winmat); + strandbuf->winx= re->winx; + strandbuf->winy= re->winy; + strandbuf->maxdepth= 2; + strandbuf->adaptcos= cosf(DEG2RADF((float)part->adapt_angle)); + strandbuf->overrideuv= sd.override_uv; + strandbuf->minwidth= ma->strand_min; + + if (ma->strand_widthfade == 0.0f) + strandbuf->widthfade= -1.0f; + else if (ma->strand_widthfade >= 1.0f) + strandbuf->widthfade= 2.0f - ma->strand_widthfade; + else + strandbuf->widthfade= 1.0f/MAX2(ma->strand_widthfade, 1e-5f); + + if (part->flag & PART_HAIR_BSPLINE) + strandbuf->flag |= R_STRAND_BSPLINE; + if (ma->mode & MA_STR_B_UNITS) + strandbuf->flag |= R_STRAND_B_UNITS; + + svert= strandbuf->vert; + + if (re->r.mode & R_SPEED) + do_surfacecache = true; + else if ((re->wrld.mode & (WO_AMB_OCC|WO_ENV_LIGHT|WO_INDIRECT_LIGHT)) && (re->wrld.ao_gather_method == WO_AOGATHER_APPROX)) + if (ma->amb != 0.0f) + do_surfacecache = true; + + totface= psmd->dm_final->getNumTessFaces(psmd->dm_final); + index_mf_to_mpoly = psmd->dm_final->getTessFaceDataArray(psmd->dm_final, CD_ORIGINDEX); + index_mp_to_orig = psmd->dm_final->getPolyDataArray(psmd->dm_final, CD_ORIGINDEX); + if (index_mf_to_mpoly == NULL) { + index_mp_to_orig = NULL; + } + for (a=0; a<totface; a++) + strandbuf->totbound = max_ii(strandbuf->totbound, (index_mf_to_mpoly) ? DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, a): a); + + strandbuf->totbound++; + strandbuf->bound= MEM_callocN(sizeof(StrandBound)*strandbuf->totbound, "StrandBound"); + sbound= strandbuf->bound; + sbound->start= sbound->end= 0; + } + } + + if (sd.orco == NULL) { + sd.orco = MEM_mallocN(3 * sizeof(float), "particle orco"); + orco1 = 1; + } + + if (path_nbr == 0) + psys->lattice_deform_data = psys_create_lattice_deform_data(&sim); + +/* 3. start creating renderable things */ + for (a=0, pa=pars; a<totpart+totchild; a++, pa++, seed++) { + random = BLI_rng_get_float(rng); + /* setup per particle individual stuff */ + if (a<totpart) { + if (pa->flag & PARS_UNEXIST) continue; + + pa_time=(cfra-pa->time)/pa->lifetime; + pa_birthtime = pa->time; + pa_dietime = pa->dietime; + + hasize = ma->hasize; + + /* XXX 'tpsys' is alwyas NULL, this code won't run! */ + /* get orco */ + if (tpsys && part->phystype == PART_PHYS_NO) { + tpa = tpsys->particles + pa->num; + psys_particle_on_emitter( + psmd, + tpart->from, tpa->num, pa->num_dmcache, tpa->fuv, + tpa->foffset, co, nor, NULL, NULL, sd.orco, NULL); + } + else { + psys_particle_on_emitter( + psmd, + part->from, pa->num, pa->num_dmcache, + pa->fuv, pa->foffset, co, nor, NULL, NULL, sd.orco, NULL); + } + + /* get uvco & mcol */ + num= pa->num_dmcache; + + if (num == DMCACHE_NOTFOUND) + if (pa->num < psmd->dm_final->getNumTessFaces(psmd->dm_final)) + num= pa->num; + + get_particle_uvco_mcol(part->from, psmd->dm_final, pa->fuv, num, &sd); + + pa_size = pa->size; + + r_tilt = 2.0f*(psys_frand(psys, a) - 0.5f); + r_length = psys_frand(psys, a+1); + + if (path_nbr) { + cache = psys->pathcache[a]; + max_k = (int)cache->segments; + } + + if (totchild && (part->draw&PART_DRAW_PARENT)==0) continue; + } + else { + ChildParticle *cpa= psys->child+a-totpart; + + if (path_nbr) { + cache = psys->childcache[a-totpart]; + + if (cache->segments < 0) + continue; + + max_k = (int)cache->segments; + } + + pa_time = psys_get_child_time(psys, cpa, cfra, &pa_birthtime, &pa_dietime); + pa_size = psys_get_child_size(psys, cpa, cfra, &pa_time); + + r_tilt = 2.0f*(psys_frand(psys, a + 21) - 0.5f); + r_length = psys_frand(psys, a + 22); + + num = cpa->num; + + /* get orco */ + if (part->childtype == PART_CHILD_FACES) { + psys_particle_on_emitter( + psmd, + PART_FROM_FACE, cpa->num, DMCACHE_ISCHILD, + cpa->fuv, cpa->foffset, co, nor, NULL, NULL, sd.orco, NULL); + } + else { + ParticleData *par = psys->particles + cpa->parent; + psys_particle_on_emitter( + psmd, + part->from, par->num, DMCACHE_ISCHILD, par->fuv, + par->foffset, co, nor, NULL, NULL, sd.orco, NULL); + } + + /* get uvco & mcol */ + if (part->childtype==PART_CHILD_FACES) { + get_particle_uvco_mcol(PART_FROM_FACE, psmd->dm_final, cpa->fuv, cpa->num, &sd); + } + else { + ParticleData *parent = psys->particles + cpa->parent; + num = parent->num_dmcache; + + if (num == DMCACHE_NOTFOUND) + if (parent->num < psmd->dm_final->getNumTessFaces(psmd->dm_final)) + num = parent->num; + + get_particle_uvco_mcol(part->from, psmd->dm_final, parent->fuv, num, &sd); + } + + do_simplify = psys_render_simplify_params(psys, cpa, simplify); + + if (strandbuf) { + int orignum = (index_mf_to_mpoly) ? DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, cpa->num) : cpa->num; + + if ((orignum > sbound - strandbuf->bound) && + (orignum < strandbuf->totbound)) + { + sbound = &strandbuf->bound[orignum]; + sbound->start = sbound->end = obr->totstrand; + } + } + } + + /* TEXCO_PARTICLE */ + pa_co[0] = pa_time; + pa_co[1] = 0.f; + pa_co[2] = 0.f; + + /* surface normal shading setup */ + if (ma->mode_l & MA_STR_SURFDIFF) { + mul_m3_v3(nmat, nor); + sd.surfnor= nor; + } + else + sd.surfnor= NULL; + + /* strand render setup */ + if (strandbuf) { + strand= RE_findOrAddStrand(obr, obr->totstrand++); + strand->buffer= strandbuf; + strand->vert= svert; + copy_v3_v3(strand->orco, sd.orco); + + if (do_simplify) { + float *ssimplify= RE_strandren_get_simplify(obr, strand, 1); + ssimplify[0]= simplify[0]; + ssimplify[1]= simplify[1]; + } + + if (sd.surfnor) { + float *snor= RE_strandren_get_surfnor(obr, strand, 1); + copy_v3_v3(snor, sd.surfnor); + } + + if (do_surfacecache && num >= 0) { + int *facenum= RE_strandren_get_face(obr, strand, 1); + *facenum= num; + } + + if (sd.uvco) { + for (i=0; i<sd.totuv; i++) { + if (i != sd.override_uv) { + float *uv= RE_strandren_get_uv(obr, strand, i, NULL, 1); + + uv[0]= sd.uvco[2*i]; + uv[1]= sd.uvco[2*i+1]; + } + } + } + if (sd.mcol) { + for (i=0; i<sd.totcol; i++) { + MCol *mc= RE_strandren_get_mcol(obr, strand, i, NULL, 1); + *mc = sd.mcol[i]; + } + } + + sbound->end++; + } + + /* strandco computation setup */ + if (path_nbr) { + strandlen= 0.0f; + curlen= 0.0f; + for (k=1; k<=path_nbr; k++) + if (k<=max_k) + strandlen += len_v3v3((cache+k-1)->co, (cache+k)->co); + } + + if (path_nbr) { + /* render strands */ + for (k=0; k<=path_nbr; k++) { + float time; + + if (k<=max_k) { + copy_v3_v3(state.co, (cache+k)->co); + copy_v3_v3(state.vel, (cache+k)->vel); + } + else + continue; + + if (k > 0) + curlen += len_v3v3((cache+k-1)->co, (cache+k)->co); + time= curlen/strandlen; + + copy_v3_v3(loc, state.co); + mul_m4_v3(re->viewmat, loc); + + if (strandbuf) { + copy_v3_v3(svert->co, loc); + svert->strandco= -1.0f + 2.0f*time; + svert++; + strand->totvert++; + } + else { + sd.size = hasize; + + if (k==1) { + sd.first = 1; + sd.time = 0.0f; + sub_v3_v3v3(loc0, loc1, loc); + add_v3_v3v3(loc0, loc1, loc0); + + particle_curve(re, obr, psmd->dm_final, ma, &sd, loc1, loc0, seed, pa_co); + } + + sd.first = 0; + sd.time = time; + + if (k) + particle_curve(re, obr, psmd->dm_final, ma, &sd, loc, loc1, seed, pa_co); + + copy_v3_v3(loc1, loc); + } + } + + } + else { + /* render normal particles */ + if (part->trail_count > 1) { + float length = part->path_end * (1.0f - part->randlength * r_length); + int trail_count = part->trail_count * (1.0f - part->randlength * r_length); + float ct = (part->draw & PART_ABS_PATH_TIME) ? cfra : pa_time; + float dt = length / (trail_count ? (float)trail_count : 1.0f); + + /* make sure we have pointcache in memory before getting particle on path */ + psys_make_temp_pointcache(ob, psys); + + for (i=0; i < trail_count; i++, ct -= dt) { + if (part->draw & PART_ABS_PATH_TIME) { + if (ct < pa_birthtime || ct > pa_dietime) + continue; + } + else if (ct < 0.0f || ct > 1.0f) + continue; + + state.time = (part->draw & PART_ABS_PATH_TIME) ? -ct : ct; + psys_get_particle_on_path(&sim, a, &state, 1); + + if (psys->parent) + mul_m4_v3(psys->parent->obmat, state.co); + + if (use_duplimat) + mul_m4_v4(duplimat, state.co); + + if (part->ren_as == PART_DRAW_BB) { + bb.random = random; + bb.offset[0] = part->bb_offset[0]; + bb.offset[1] = part->bb_offset[1]; + bb.size[0] = part->bb_size[0] * pa_size; + if (part->bb_align==PART_BB_VEL) { + float pa_vel = len_v3(state.vel); + float head = part->bb_vel_head*pa_vel; + float tail = part->bb_vel_tail*pa_vel; + bb.size[1] = part->bb_size[1]*pa_size + head + tail; + /* use offset to adjust the particle center. this is relative to size, so need to divide! */ + if (bb.size[1] > 0.0f) + bb.offset[1] += (head-tail) / bb.size[1]; + } + else + bb.size[1] = part->bb_size[1] * pa_size; + bb.tilt = part->bb_tilt * (1.0f - part->bb_rand_tilt * r_tilt); + bb.time = ct; + bb.num = a; + } + + pa_co[0] = (part->draw & PART_ABS_PATH_TIME) ? (ct-pa_birthtime)/(pa_dietime-pa_birthtime) : ct; + pa_co[1] = (float)i/(float)(trail_count-1); + + particle_normal_ren(part->ren_as, part, re, obr, psmd->dm_final, ma, &sd, &bb, &state, seed, hasize, pa_co); + } + } + else { + state.time=cfra; + if (psys_get_particle_state(&sim, a, &state, 0)==0) + continue; + + if (psys->parent) + mul_m4_v3(psys->parent->obmat, state.co); + + if (use_duplimat) + mul_m4_v3(duplimat, state.co); + + if (part->ren_as == PART_DRAW_BB) { + bb.random = random; + bb.offset[0] = part->bb_offset[0]; + bb.offset[1] = part->bb_offset[1]; + bb.size[0] = part->bb_size[0] * pa_size; + if (part->bb_align==PART_BB_VEL) { + float pa_vel = len_v3(state.vel); + float head = part->bb_vel_head*pa_vel; + float tail = part->bb_vel_tail*pa_vel; + bb.size[1] = part->bb_size[1]*pa_size + head + tail; + /* use offset to adjust the particle center. this is relative to size, so need to divide! */ + if (bb.size[1] > 0.0f) + bb.offset[1] += (head-tail) / bb.size[1]; + } + else + bb.size[1] = part->bb_size[1] * pa_size; + bb.tilt = part->bb_tilt * (1.0f - part->bb_rand_tilt * r_tilt); + bb.time = pa_time; + bb.num = a; + bb.lifetime = pa_dietime-pa_birthtime; + } + + particle_normal_ren(part->ren_as, part, re, obr, psmd->dm_final, ma, &sd, &bb, &state, seed, hasize, pa_co); + } + } + + if (orco1==0) + sd.orco+=3; + + if (re->test_break(re->tbh)) + break; + } + + if (do_surfacecache) + strandbuf->surface= cache_strand_surface(re, obr, psmd->dm_final, mat, timeoffset); + +/* 4. clean up */ +#if 0 /* XXX old animation system */ + if (ma) do_mat_ipo(re->scene, ma); +#endif /* XXX old animation system */ + + if (orco1) + MEM_freeN(sd.orco); + + if (sd.uvco) + MEM_freeN(sd.uvco); + + if (sd.mcol) + MEM_freeN(sd.mcol); + + if (states) + MEM_freeN(states); + + BLI_rng_free(rng); + + psys->flag &= ~PSYS_DRAWING; + + if (psys->lattice_deform_data) { + end_latt_deform(psys->lattice_deform_data); + psys->lattice_deform_data = NULL; + } + + if (path_nbr && (ma->mode_l & MA_TANGENT_STR)==0) + calc_vertexnormals(re, obr, 1, 0, 0); + + return 1; +} + +/* ------------------------------------------------------------------------- */ +/* Halo's */ +/* ------------------------------------------------------------------------- */ + +static void make_render_halos(Render *re, ObjectRen *obr, Mesh *UNUSED(me), int totvert, MVert *mvert, Material *ma, float *orco) +{ + Object *ob= obr->ob; + HaloRen *har; + float xn, yn, zn, nor[3], view[3]; + float vec[3], hasize, mat[4][4], imat[3][3]; + int a, ok, seed= ma->seed1; + + mul_m4_m4m4(mat, re->viewmat, ob->obmat); + copy_m3_m4(imat, ob->imat); + + re->flag |= R_HALO; + + for (a=0; a<totvert; a++, mvert++) { + ok= 1; + + if (ok) { + hasize= ma->hasize; + + copy_v3_v3(vec, mvert->co); + mul_m4_v3(mat, vec); + + if (ma->mode & MA_HALOPUNO) { + xn= mvert->no[0]; + yn= mvert->no[1]; + zn= mvert->no[2]; + + /* transpose ! */ + nor[0]= imat[0][0]*xn+imat[0][1]*yn+imat[0][2]*zn; + nor[1]= imat[1][0]*xn+imat[1][1]*yn+imat[1][2]*zn; + nor[2]= imat[2][0]*xn+imat[2][1]*yn+imat[2][2]*zn; + normalize_v3(nor); + + copy_v3_v3(view, vec); + normalize_v3(view); + + zn = dot_v3v3(nor, view); + if (zn>=0.0f) hasize= 0.0f; + else hasize*= zn*zn*zn*zn; + } + + if (orco) har= RE_inithalo(re, obr, ma, vec, NULL, orco, hasize, 0.0, seed); + else har= RE_inithalo(re, obr, ma, vec, NULL, mvert->co, hasize, 0.0, seed); + if (har) har->lay= ob->lay; + } + if (orco) orco+= 3; + seed++; + } +} + +static int verghalo(const void *a1, const void *a2) +{ + const HaloRen *har1= *(const HaloRen**)a1; + const HaloRen *har2= *(const HaloRen**)a2; + + if (har1->zs < har2->zs) return 1; + else if (har1->zs > har2->zs) return -1; + return 0; +} + +static void sort_halos(Render *re, int totsort) +{ + ObjectRen *obr; + HaloRen *har= NULL, **haso; + int a; + + if (re->tothalo==0) return; + + re->sortedhalos= MEM_callocN(sizeof(HaloRen*)*re->tothalo, "sorthalos"); + haso= re->sortedhalos; + + for (obr=re->objecttable.first; obr; obr=obr->next) { + for (a=0; a<obr->tothalo; a++) { + if ((a & 255)==0) har= obr->bloha[a>>8]; + else har++; + + *(haso++)= har; + } + } + + qsort(re->sortedhalos, totsort, sizeof(HaloRen*), verghalo); +} + +/* ------------------------------------------------------------------------- */ +/* Displacement Mapping */ +/* ------------------------------------------------------------------------- */ + +static short test_for_displace(Render *re, Object *ob) +{ + /* return 1 when this object uses displacement textures. */ + Material *ma; + int i; + + for (i=1; i<=ob->totcol; i++) { + ma=give_render_material(re, ob, i); + /* ma->mapto is ORed total of all mapto channels */ + if (ma && (ma->mapto & MAP_DISPLACE)) return 1; + } + return 0; +} + +static void displace_render_vert(Render *re, ObjectRen *obr, ShadeInput *shi, VertRen *vr, int vindex, float *scale) +{ + MTFace *tface; + short texco= shi->mat->texco; + float sample=0, displace[3]; + char *name; + int i; + + /* shi->co is current render coord, just make sure at least some vector is here */ + copy_v3_v3(shi->co, vr->co); + /* vertex normal is used for textures type 'col' and 'var' */ + copy_v3_v3(shi->vn, vr->n); + + if (texco & TEXCO_UV) { + shi->totuv= 0; + shi->actuv= obr->actmtface; + + for (i=0; (tface=RE_vlakren_get_tface(obr, shi->vlr, i, &name, 0)); i++) { + ShadeInputUV *suv= &shi->uv[i]; + + /* shi.uv needs scale correction from tface uv */ + suv->uv[0]= 2*tface->uv[vindex][0]-1.0f; + suv->uv[1]= 2*tface->uv[vindex][1]-1.0f; + suv->uv[2]= 0.0f; + suv->name= name; + shi->totuv++; + } + } + + /* set all rendercoords, 'texco' is an ORed value for all textures needed */ + if ((texco & TEXCO_ORCO) && (vr->orco)) { + copy_v3_v3(shi->lo, vr->orco); + } + if (texco & TEXCO_GLOB) { + copy_v3_v3(shi->gl, shi->co); + mul_m4_v3(re->viewinv, shi->gl); + } + if (texco & TEXCO_NORM) { + copy_v3_v3(shi->orn, shi->vn); + } + if (texco & TEXCO_REFL) { + /* not (yet?) */ + } + if (texco & TEXCO_STRESS) { + const float *s= RE_vertren_get_stress(obr, vr, 0); + + if (s) { + shi->stress= *s; + if (shi->stress<1.0f) shi->stress-= 1.0f; + else shi->stress= (shi->stress-1.0f)/shi->stress; + } + else + shi->stress= 0.0f; + } + + shi->displace[0]= shi->displace[1]= shi->displace[2]= 0.0; + + do_material_tex(shi, re); + + //printf("no=%f, %f, %f\nbefore co=%f, %f, %f\n", vr->n[0], vr->n[1], vr->n[2], + //vr->co[0], vr->co[1], vr->co[2]); + + displace[0]= shi->displace[0] * scale[0]; + displace[1]= shi->displace[1] * scale[1]; + displace[2]= shi->displace[2] * scale[2]; + + /* 0.5 could become button once? */ + vr->co[0] += displace[0]; + vr->co[1] += displace[1]; + vr->co[2] += displace[2]; + + //printf("after co=%f, %f, %f\n", vr->co[0], vr->co[1], vr->co[2]); + + /* we just don't do this vertex again, bad luck for other face using same vertex with + * different material... */ + vr->flag |= 1; + + /* Pass sample back so displace_face can decide which way to split the quad */ + sample = shi->displace[0]*shi->displace[0]; + sample += shi->displace[1]*shi->displace[1]; + sample += shi->displace[2]*shi->displace[2]; + + vr->accum=sample; + /* Should be sqrt(sample), but I'm only looking for "bigger". Save the cycles. */ + return; +} + +static void displace_render_face(Render *re, ObjectRen *obr, VlakRen *vlr, float *scale) +{ + ShadeInput shi; + + /* Warning, This is not that nice, and possibly a bit slow, + * however some variables were not initialized properly in, unless using shade_input_initialize(...), we need to do a memset */ + memset(&shi, 0, sizeof(ShadeInput)); + /* end warning! - Campbell */ + + /* set up shadeinput struct for multitex() */ + + /* memset above means we don't need this */ + /*shi.osatex= 0;*/ /* signal not to use dx[] and dy[] texture AA vectors */ + + shi.obr= obr; + shi.vlr= vlr; /* current render face */ + shi.mat= vlr->mat; /* current input material */ + shi.thread= 0; + + /* TODO, assign these, displacement with new bumpmap is skipped without - campbell */ +#if 0 + /* order is not known ? */ + shi.v1= vlr->v1; + shi.v2= vlr->v2; + shi.v3= vlr->v3; +#endif + + /* Displace the verts, flag is set when done */ + if (!vlr->v1->flag) + displace_render_vert(re, obr, &shi, vlr->v1, 0, scale); + + if (!vlr->v2->flag) + displace_render_vert(re, obr, &shi, vlr->v2, 1, scale); + + if (!vlr->v3->flag) + displace_render_vert(re, obr, &shi, vlr->v3, 2, scale); + + if (vlr->v4) { + if (!vlr->v4->flag) + displace_render_vert(re, obr, &shi, vlr->v4, 3, scale); + + /* closest in displace value. This will help smooth edges. */ + if (fabsf(vlr->v1->accum - vlr->v3->accum) > fabsf(vlr->v2->accum - vlr->v4->accum)) vlr->flag |= R_DIVIDE_24; + else vlr->flag &= ~R_DIVIDE_24; + } + + /* Recalculate the face normal - if flipped before, flip now */ + if (vlr->v4) { + normal_quad_v3(vlr->n, vlr->v4->co, vlr->v3->co, vlr->v2->co, vlr->v1->co); + } + else { + normal_tri_v3(vlr->n, vlr->v3->co, vlr->v2->co, vlr->v1->co); + } +} + +static void displace(Render *re, ObjectRen *obr) +{ + VertRen *vr; + VlakRen *vlr; +// float min[3]={1e30, 1e30, 1e30}, max[3]={-1e30, -1e30, -1e30}; + float scale[3]={1.0f, 1.0f, 1.0f}, temp[3];//, xn + int i; //, texflag=0; + Object *obt; + + /* Object Size with parenting */ + obt=obr->ob; + while (obt) { + mul_v3_v3v3(temp, obt->size, obt->dscale); + scale[0]*=temp[0]; scale[1]*=temp[1]; scale[2]*=temp[2]; + obt=obt->parent; + } + + /* Clear all flags */ + for (i=0; i<obr->totvert; i++) { + vr= RE_findOrAddVert(obr, i); + vr->flag= 0; + } + + for (i=0; i<obr->totvlak; i++) { + vlr=RE_findOrAddVlak(obr, i); + displace_render_face(re, obr, vlr, scale); + } + + /* Recalc vertex normals */ + calc_vertexnormals(re, obr, 1, 0, 0); +} + +/* ------------------------------------------------------------------------- */ +/* Metaball */ +/* ------------------------------------------------------------------------- */ + +static void init_render_mball(Render *re, ObjectRen *obr) +{ + Object *ob= obr->ob; + DispList *dl; + VertRen *ver; + VlakRen *vlr, *vlr1; + Material *ma; + float *data, *nors, *orco=NULL, mat[4][4], imat[3][3], xn, yn, zn; + int a, need_orco, vlakindex, *index, negative_scale; + ListBase dispbase= {NULL, NULL}; + + if (ob!=BKE_mball_basis_find(re->eval_ctx, re->scene, ob)) + return; + + mul_m4_m4m4(mat, re->viewmat, ob->obmat); + invert_m4_m4(ob->imat, mat); + copy_m3_m4(imat, ob->imat); + negative_scale = is_negative_m4(mat); + + ma= give_render_material(re, ob, 1); + + need_orco= 0; + if (ma->texco & TEXCO_ORCO) { + need_orco= 1; + } + + BKE_displist_make_mball_forRender(re->eval_ctx, re->scene, ob, &dispbase); + dl= dispbase.first; + if (dl == NULL) return; + + data= dl->verts; + nors= dl->nors; + if (need_orco) { + orco= get_object_orco(re, ob); + + if (!orco) { + /* orco hasn't been found in cache - create new one and add to cache */ + orco= BKE_mball_make_orco(ob, &dispbase); + set_object_orco(re, ob, orco); + } + } + + for (a=0; a<dl->nr; a++, data+=3, nors+=3) { + + ver= RE_findOrAddVert(obr, obr->totvert++); + copy_v3_v3(ver->co, data); + mul_m4_v3(mat, ver->co); + + /* render normals are inverted */ + xn= -nors[0]; + yn= -nors[1]; + zn= -nors[2]; + + /* transpose ! */ + ver->n[0]= imat[0][0]*xn+imat[0][1]*yn+imat[0][2]*zn; + ver->n[1]= imat[1][0]*xn+imat[1][1]*yn+imat[1][2]*zn; + ver->n[2]= imat[2][0]*xn+imat[2][1]*yn+imat[2][2]*zn; + normalize_v3(ver->n); + //if (ob->transflag & OB_NEG_SCALE) negate_v3(ver->n); + + if (need_orco) { + ver->orco= orco; + orco+=3; + } + } + + index= dl->index; + for (a=0; a<dl->parts; a++, index+=4) { + + vlr= RE_findOrAddVlak(obr, obr->totvlak++); + vlr->v1= RE_findOrAddVert(obr, index[0]); + vlr->v2= RE_findOrAddVert(obr, index[1]); + vlr->v3= RE_findOrAddVert(obr, index[2]); + vlr->v4 = NULL; + + if (negative_scale) + normal_tri_v3(vlr->n, vlr->v1->co, vlr->v2->co, vlr->v3->co); + else + normal_tri_v3(vlr->n, vlr->v3->co, vlr->v2->co, vlr->v1->co); + + vlr->mat= ma; + vlr->flag= ME_SMOOTH; + vlr->ec= 0; + + /* mball -too bad- always has triangles, because quads can be non-planar */ + if (index[3] && index[3]!=index[2]) { + vlr1= RE_findOrAddVlak(obr, obr->totvlak++); + vlakindex= vlr1->index; + *vlr1= *vlr; + vlr1->index= vlakindex; + vlr1->v2= vlr1->v3; + vlr1->v3= RE_findOrAddVert(obr, index[3]); + if (negative_scale) + normal_tri_v3(vlr1->n, vlr1->v1->co, vlr1->v2->co, vlr1->v3->co); + else + normal_tri_v3(vlr1->n, vlr1->v3->co, vlr1->v2->co, vlr1->v1->co); + } + } + + /* enforce display lists remade */ + BKE_displist_free(&dispbase); +} + +/* ------------------------------------------------------------------------- */ +/* Surfaces and Curves */ +/* ------------------------------------------------------------------------- */ + +/* returns amount of vertices added for orco */ +static int dl_surf_to_renderdata(ObjectRen *obr, DispList *dl, Material **matar, float *orco, float mat[4][4]) +{ + VertRen *v1, *v2, *v3, *v4, *ver; + VlakRen *vlr, *vlr1, *vlr2, *vlr3; + float *data, n1[3]; + int u, v, orcoret= 0; + int p1, p2, p3, p4, a; + int sizeu, nsizeu, sizev, nsizev; + int startvert, startvlak; + + startvert= obr->totvert; + nsizeu = sizeu = dl->parts; nsizev = sizev = dl->nr; + + data= dl->verts; + for (u = 0; u < sizeu; u++) { + v1 = RE_findOrAddVert(obr, obr->totvert++); /* save this for possible V wrapping */ + copy_v3_v3(v1->co, data); data += 3; + if (orco) { + v1->orco= orco; orco+= 3; orcoret++; + } + mul_m4_v3(mat, v1->co); + + for (v = 1; v < sizev; v++) { + ver= RE_findOrAddVert(obr, obr->totvert++); + copy_v3_v3(ver->co, data); data += 3; + if (orco) { + ver->orco= orco; orco+= 3; orcoret++; + } + mul_m4_v3(mat, ver->co); + } + /* if V-cyclic, add extra vertices at end of the row */ + if (dl->flag & DL_CYCL_U) { + ver= RE_findOrAddVert(obr, obr->totvert++); + copy_v3_v3(ver->co, v1->co); + if (orco) { + ver->orco= orco; orco+=3; orcoret++; //orcobase + 3*(u*sizev + 0); + } + } + } + + /* Done before next loop to get corner vert */ + if (dl->flag & DL_CYCL_U) nsizev++; + if (dl->flag & DL_CYCL_V) nsizeu++; + + /* if U cyclic, add extra row at end of column */ + if (dl->flag & DL_CYCL_V) { + for (v = 0; v < nsizev; v++) { + v1= RE_findOrAddVert(obr, startvert + v); + ver= RE_findOrAddVert(obr, obr->totvert++); + copy_v3_v3(ver->co, v1->co); + if (orco) { + ver->orco= orco; orco+=3; orcoret++; //ver->orco= orcobase + 3*(0*sizev + v); + } + } + } + + sizeu = nsizeu; + sizev = nsizev; + + startvlak= obr->totvlak; + + for (u = 0; u < sizeu - 1; u++) { + p1 = startvert + u * sizev; /* walk through face list */ + p2 = p1 + 1; + p3 = p2 + sizev; + p4 = p3 - 1; + + for (v = 0; v < sizev - 1; v++) { + v1= RE_findOrAddVert(obr, p1); + v2= RE_findOrAddVert(obr, p2); + v3= RE_findOrAddVert(obr, p3); + v4= RE_findOrAddVert(obr, p4); + + vlr= RE_findOrAddVlak(obr, obr->totvlak++); + vlr->v1= v1; vlr->v2= v2; vlr->v3= v3; vlr->v4= v4; + + normal_quad_v3(n1, vlr->v4->co, vlr->v3->co, vlr->v2->co, vlr->v1->co); + + copy_v3_v3(vlr->n, n1); + + vlr->mat= matar[ dl->col]; + vlr->ec= ME_V1V2+ME_V2V3; + vlr->flag= dl->rt; + + add_v3_v3(v1->n, n1); + add_v3_v3(v2->n, n1); + add_v3_v3(v3->n, n1); + add_v3_v3(v4->n, n1); + + p1++; p2++; p3++; p4++; + } + } + /* fix normals for U resp. V cyclic faces */ + sizeu--; sizev--; /* dec size for face array */ + if (dl->flag & DL_CYCL_V) { + + for (v = 0; v < sizev; v++) { + /* optimize! :*/ + vlr= RE_findOrAddVlak(obr, UVTOINDEX(sizeu - 1, v)); + vlr1= RE_findOrAddVlak(obr, UVTOINDEX(0, v)); + add_v3_v3(vlr1->v1->n, vlr->n); + add_v3_v3(vlr1->v2->n, vlr->n); + add_v3_v3(vlr->v3->n, vlr1->n); + add_v3_v3(vlr->v4->n, vlr1->n); + } + } + if (dl->flag & DL_CYCL_U) { + + for (u = 0; u < sizeu; u++) { + /* optimize! :*/ + vlr= RE_findOrAddVlak(obr, UVTOINDEX(u, 0)); + vlr1= RE_findOrAddVlak(obr, UVTOINDEX(u, sizev-1)); + add_v3_v3(vlr1->v2->n, vlr->n); + add_v3_v3(vlr1->v3->n, vlr->n); + add_v3_v3(vlr->v1->n, vlr1->n); + add_v3_v3(vlr->v4->n, vlr1->n); + } + } + + /* last vertex is an extra case: + * + * ^ ()----()----()----() + * | | | || | + * u | |(0,n)||(0,0)| + * | | || | + * ()====()====[]====() + * | | || | + * | |(m,n)||(m,0)| + * | | || | + * ()----()----()----() + * v -> + * + * vertex [] is no longer shared, therefore distribute + * normals of the surrounding faces to all of the duplicates of [] + */ + + if ((dl->flag & DL_CYCL_V) && (dl->flag & DL_CYCL_U)) { + vlr= RE_findOrAddVlak(obr, UVTOINDEX(sizeu - 1, sizev - 1)); /* (m, n) */ + vlr1= RE_findOrAddVlak(obr, UVTOINDEX(0, 0)); /* (0, 0) */ + add_v3_v3v3(n1, vlr->n, vlr1->n); + vlr2= RE_findOrAddVlak(obr, UVTOINDEX(0, sizev-1)); /* (0, n) */ + add_v3_v3(n1, vlr2->n); + vlr3= RE_findOrAddVlak(obr, UVTOINDEX(sizeu-1, 0)); /* (m, 0) */ + add_v3_v3(n1, vlr3->n); + copy_v3_v3(vlr->v3->n, n1); + copy_v3_v3(vlr1->v1->n, n1); + copy_v3_v3(vlr2->v2->n, n1); + copy_v3_v3(vlr3->v4->n, n1); + } + for (a = startvert; a < obr->totvert; a++) { + ver= RE_findOrAddVert(obr, a); + normalize_v3(ver->n); + } + + + return orcoret; +} + +static void init_render_dm(DerivedMesh *dm, Render *re, ObjectRen *obr, + int timeoffset, float *orco, float mat[4][4]) +{ + Object *ob= obr->ob; + int a, end, totvert, vertofs; + short mat_iter; + VertRen *ver; + VlakRen *vlr; + MVert *mvert = NULL; + MFace *mface; + Material *ma; +#ifdef WITH_FREESTYLE + const int *index_mf_to_mpoly = NULL; + const int *index_mp_to_orig = NULL; + FreestyleFace *ffa = NULL; +#endif + /* Curve *cu= ELEM(ob->type, OB_FONT, OB_CURVE) ? ob->data : NULL; */ + + mvert= dm->getVertArray(dm); + totvert= dm->getNumVerts(dm); + + for (a=0; a<totvert; a++, mvert++) { + ver= RE_findOrAddVert(obr, obr->totvert++); + copy_v3_v3(ver->co, mvert->co); + mul_m4_v3(mat, ver->co); + + if (orco) { + ver->orco= orco; + orco+=3; + } + } + + if (!timeoffset) { + /* store customdata names, because DerivedMesh is freed */ + RE_set_customdata_names(obr, &dm->faceData); + + /* still to do for keys: the correct local texture coordinate */ + + /* faces in order of color blocks */ + vertofs= obr->totvert - totvert; + for (mat_iter= 0; (mat_iter < ob->totcol || (mat_iter==0 && ob->totcol==0)); mat_iter++) { + + ma= give_render_material(re, ob, mat_iter+1); + end= dm->getNumTessFaces(dm); + mface= dm->getTessFaceArray(dm); + +#ifdef WITH_FREESTYLE + if (ob->type == OB_MESH) { + Mesh *me= ob->data; + index_mf_to_mpoly= dm->getTessFaceDataArray(dm, CD_ORIGINDEX); + index_mp_to_orig= dm->getPolyDataArray(dm, CD_ORIGINDEX); + ffa= CustomData_get_layer(&me->pdata, CD_FREESTYLE_FACE); + } +#endif + + for (a=0; a<end; a++, mface++) { + int v1, v2, v3, v4, flag; + + if (mface->mat_nr == mat_iter) { + float len; + + v1= mface->v1; + v2= mface->v2; + v3= mface->v3; + v4= mface->v4; + flag= mface->flag & ME_SMOOTH; + + vlr= RE_findOrAddVlak(obr, obr->totvlak++); + vlr->v1= RE_findOrAddVert(obr, vertofs+v1); + vlr->v2= RE_findOrAddVert(obr, vertofs+v2); + vlr->v3= RE_findOrAddVert(obr, vertofs+v3); + if (v4) vlr->v4= RE_findOrAddVert(obr, vertofs+v4); + else vlr->v4 = NULL; + + /* render normals are inverted in render */ + if (vlr->v4) + len= normal_quad_v3(vlr->n, vlr->v4->co, vlr->v3->co, vlr->v2->co, vlr->v1->co); + else + len= normal_tri_v3(vlr->n, vlr->v3->co, vlr->v2->co, vlr->v1->co); + + vlr->mat= ma; + vlr->flag= flag; + vlr->ec= 0; /* mesh edges rendered separately */ +#ifdef WITH_FREESTYLE + if (ffa) { + int index = (index_mf_to_mpoly) ? DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, a) : a; + vlr->freestyle_face_mark= (ffa[index].flag & FREESTYLE_FACE_MARK) ? 1 : 0; + } + else { + vlr->freestyle_face_mark= 0; + } +#endif + + if (len==0) obr->totvlak--; + else { + CustomDataLayer *layer; + MTFace *mtface, *mtf; + MCol *mcol, *mc; + int index, mtfn= 0, mcn= 0; + char *name; + + for (index=0; index<dm->faceData.totlayer; index++) { + layer= &dm->faceData.layers[index]; + name= layer->name; + + if (layer->type == CD_MTFACE && mtfn < MAX_MTFACE) { + mtf= RE_vlakren_get_tface(obr, vlr, mtfn++, &name, 1); + mtface= (MTFace*)layer->data; + *mtf= mtface[a]; + } + else if (layer->type == CD_MCOL && mcn < MAX_MCOL) { + mc= RE_vlakren_get_mcol(obr, vlr, mcn++, &name, 1); + mcol= (MCol*)layer->data; + memcpy(mc, &mcol[a*4], sizeof(MCol)*4); + } + } + } + } + } + } + + /* Normals */ + calc_vertexnormals(re, obr, 1, 0, 0); + } + +} + +static void init_render_surf(Render *re, ObjectRen *obr, int timeoffset) +{ + Object *ob= obr->ob; + Nurb *nu = NULL; + Curve *cu; + ListBase displist= {NULL, NULL}; + DispList *dl; + Material **matar; + float *orco=NULL, mat[4][4]; + int a, totmat; + bool need_orco = false; + DerivedMesh *dm= NULL; + + cu= ob->data; + nu= cu->nurb.first; + if (nu == NULL) return; + + mul_m4_m4m4(mat, re->viewmat, ob->obmat); + invert_m4_m4(ob->imat, mat); + + /* material array */ + totmat= ob->totcol+1; + matar= MEM_callocN(sizeof(Material*)*totmat, "init_render_surf matar"); + + for (a=0; a<totmat; a++) { + matar[a]= give_render_material(re, ob, a+1); + + if (matar[a] && matar[a]->texco & TEXCO_ORCO) + need_orco= 1; + } + + if (ob->parent && (ob->parent->type==OB_LATTICE)) need_orco= 1; + + BKE_displist_make_surf(re->scene, ob, &displist, &dm, 1, 0, 1); + + if (dm) { + if (need_orco) { + orco = get_object_orco(re, ob); + if (!orco) { + orco= BKE_displist_make_orco(re->scene, ob, dm, true, true); + if (orco) { + set_object_orco(re, ob, orco); + } + } + } + + init_render_dm(dm, re, obr, timeoffset, orco, mat); + dm->release(dm); + } + else { + if (need_orco) { + orco = get_object_orco(re, ob); + if (!orco) { + orco = BKE_curve_surf_make_orco(ob); + set_object_orco(re, ob, orco); + } + } + + /* walk along displaylist and create rendervertices/-faces */ + for (dl=displist.first; dl; dl=dl->next) { + /* watch out: u ^= y, v ^= x !! */ + if (dl->type==DL_SURF) + orco+= 3*dl_surf_to_renderdata(obr, dl, matar, orco, mat); + } + } + + BKE_displist_free(&displist); + + MEM_freeN(matar); +} + +static void init_render_curve(Render *re, ObjectRen *obr, int timeoffset) +{ + Object *ob= obr->ob; + Curve *cu; + VertRen *ver; + VlakRen *vlr; + DispList *dl; + DerivedMesh *dm = NULL; + ListBase disp={NULL, NULL}; + Material **matar; + float *data, *fp, *orco=NULL; + float n[3], mat[4][4], nmat[4][4]; + int nr, startvert, a, b, negative_scale; + bool need_orco = false; + int totmat; + + cu= ob->data; + if (ob->type==OB_FONT && cu->str==NULL) return; + else if (ob->type==OB_CURVE && cu->nurb.first==NULL) return; + + BKE_displist_make_curveTypes_forRender(re->scene, ob, &disp, &dm, false, true); + dl= disp.first; + if (dl==NULL) return; + + mul_m4_m4m4(mat, re->viewmat, ob->obmat); + invert_m4_m4(ob->imat, mat); + negative_scale = is_negative_m4(mat); + + /* local object -> world space transform for normals */ + transpose_m4_m4(nmat, mat); + invert_m4(nmat); + + /* material array */ + totmat= ob->totcol+1; + matar= MEM_callocN(sizeof(Material*)*totmat, "init_render_surf matar"); + + for (a=0; a<totmat; a++) { + matar[a]= give_render_material(re, ob, a+1); + + if (matar[a] && matar[a]->texco & TEXCO_ORCO) + need_orco= 1; + } + + if (dm) { + if (need_orco) { + orco = get_object_orco(re, ob); + if (!orco) { + orco = BKE_displist_make_orco(re->scene, ob, dm, true, true); + if (orco) { + set_object_orco(re, ob, orco); + } + } + } + + init_render_dm(dm, re, obr, timeoffset, orco, mat); + dm->release(dm); + } + else { + if (need_orco) { + orco = get_object_orco(re, ob); + if (!orco) { + orco = BKE_curve_make_orco(re->scene, ob, NULL); + set_object_orco(re, ob, orco); + } + } + + while (dl) { + if (dl->col > ob->totcol) { + /* pass */ + } + else if (dl->type==DL_INDEX3) { + const int *index; + + startvert= obr->totvert; + data= dl->verts; + + for (a=0; a<dl->nr; a++, data+=3) { + ver= RE_findOrAddVert(obr, obr->totvert++); + copy_v3_v3(ver->co, data); + + mul_m4_v3(mat, ver->co); + + if (orco) { + ver->orco = orco; + orco += 3; + } + } + + if (timeoffset==0) { + float tmp[3]; + const int startvlak= obr->totvlak; + + zero_v3(n); + index= dl->index; + for (a=0; a<dl->parts; a++, index+=3) { + int v1 = index[0], v2 = index[2], v3 = index[1]; + float *co1 = &dl->verts[v1 * 3], + *co2 = &dl->verts[v2 * 3], + *co3 = &dl->verts[v3 * 3]; + + vlr= RE_findOrAddVlak(obr, obr->totvlak++); + vlr->v1= RE_findOrAddVert(obr, startvert + v1); + vlr->v2= RE_findOrAddVert(obr, startvert + v2); + vlr->v3= RE_findOrAddVert(obr, startvert + v3); + vlr->v4= NULL; + + /* to prevent float accuracy issues, we calculate normal in local object space (not world) */ + if (normal_tri_v3(tmp, co1, co2, co3) > FLT_EPSILON) { + if (negative_scale == false) { + add_v3_v3(n, tmp); + } + else { + sub_v3_v3(n, tmp); + } + } + + vlr->mat= matar[ dl->col ]; + vlr->flag= 0; + vlr->ec= 0; + } + + /* transform normal to world space */ + mul_m4_v3(nmat, n); + normalize_v3(n); + + /* vertex normals */ + for (a= startvlak; a<obr->totvlak; a++) { + vlr= RE_findOrAddVlak(obr, a); + + copy_v3_v3(vlr->n, n); + add_v3_v3(vlr->v1->n, vlr->n); + add_v3_v3(vlr->v3->n, vlr->n); + add_v3_v3(vlr->v2->n, vlr->n); + } + for (a=startvert; a<obr->totvert; a++) { + ver= RE_findOrAddVert(obr, a); + normalize_v3(ver->n); + } + } + } + else if (dl->type==DL_SURF) { + + /* cyclic U means an extruded full circular curve, we skip bevel splitting then */ + if (dl->flag & DL_CYCL_U) { + orco+= 3*dl_surf_to_renderdata(obr, dl, matar, orco, mat); + } + else { + int p1, p2, p3, p4; + + fp= dl->verts; + startvert= obr->totvert; + nr= dl->nr*dl->parts; + + while (nr--) { + ver= RE_findOrAddVert(obr, obr->totvert++); + + copy_v3_v3(ver->co, fp); + mul_m4_v3(mat, ver->co); + fp+= 3; + + if (orco) { + ver->orco = orco; + orco += 3; + } + } + + if (dl->flag & DL_CYCL_V && orco) { + fp = dl->verts; + nr = dl->nr; + while (nr--) { + ver = RE_findOrAddVert(obr, obr->totvert++); + copy_v3_v3(ver->co, fp); + mul_m4_v3(mat, ver->co); + ver->orco = orco; + fp += 3; + orco += 3; + } + } + + if (dl->bevel_split || timeoffset == 0) { + const int startvlak= obr->totvlak; + + for (a=0; a<dl->parts; a++) { + + if (BKE_displist_surfindex_get(dl, a, &b, &p1, &p2, &p3, &p4)==0) + break; + + p1+= startvert; + p2+= startvert; + p3+= startvert; + p4+= startvert; + + if (dl->flag & DL_CYCL_V && orco && a == dl->parts - 1) { + p3 = p1 + dl->nr; + p4 = p2 + dl->nr; + } + + for (; b<dl->nr; b++) { + vlr= RE_findOrAddVlak(obr, obr->totvlak++); + /* important 1 offset in order is kept [#24913] */ + vlr->v1= RE_findOrAddVert(obr, p2); + vlr->v2= RE_findOrAddVert(obr, p1); + vlr->v3= RE_findOrAddVert(obr, p3); + vlr->v4= RE_findOrAddVert(obr, p4); + vlr->ec= ME_V2V3+ME_V3V4; + if (a==0) vlr->ec+= ME_V1V2; + + vlr->flag= dl->rt; + + normal_quad_v3(vlr->n, vlr->v4->co, vlr->v3->co, vlr->v2->co, vlr->v1->co); + vlr->mat= matar[ dl->col ]; + + p4= p3; + p3++; + p2= p1; + p1++; + } + } + + if (dl->bevel_split) { + for (a = 0; a < dl->parts - 1 + !!(dl->flag & DL_CYCL_V); a++) { + if (BLI_BITMAP_TEST(dl->bevel_split, a)) { + split_v_renderfaces( + obr, startvlak, startvert, dl->parts, dl->nr, a, + /* intentionally swap (v, u) --> (u, v) */ + dl->flag & DL_CYCL_V, dl->flag & DL_CYCL_U); + } + } + } + + /* vertex normals */ + for (a= startvlak; a<obr->totvlak; a++) { + vlr= RE_findOrAddVlak(obr, a); + + add_v3_v3(vlr->v1->n, vlr->n); + add_v3_v3(vlr->v3->n, vlr->n); + add_v3_v3(vlr->v2->n, vlr->n); + add_v3_v3(vlr->v4->n, vlr->n); + } + for (a=startvert; a<obr->totvert; a++) { + ver= RE_findOrAddVert(obr, a); + normalize_v3(ver->n); + } + } + } + } + + dl= dl->next; + } + } + + BKE_displist_free(&disp); + + MEM_freeN(matar); +} + +/* ------------------------------------------------------------------------- */ +/* Mesh */ +/* ------------------------------------------------------------------------- */ + +struct edgesort { + unsigned int v1, v2; + int f; + unsigned int i1, i2; +}; + +/* edges have to be added with lowest index first for sorting */ +static void to_edgesort(struct edgesort *ed, + unsigned int i1, unsigned int i2, + unsigned int v1, unsigned int v2, int f) +{ + if (v1 > v2) { + SWAP(unsigned int, v1, v2); + SWAP(unsigned int, i1, i2); + } + + ed->v1= v1; + ed->v2= v2; + ed->i1= i1; + ed->i2= i2; + ed->f = f; +} + +static int vergedgesort(const void *v1, const void *v2) +{ + const struct edgesort *x1=v1, *x2=v2; + + if ( x1->v1 > x2->v1) return 1; + else if ( x1->v1 < x2->v1) return -1; + else if ( x1->v2 > x2->v2) return 1; + else if ( x1->v2 < x2->v2) return -1; + + return 0; +} + +static struct edgesort *make_mesh_edge_lookup(DerivedMesh *dm, int *totedgesort) +{ + MFace *mf, *mface; + MTFace *tface=NULL; + struct edgesort *edsort, *ed; + unsigned int *mcol=NULL; + int a, totedge=0, totface; + + mface= dm->getTessFaceArray(dm); + totface= dm->getNumTessFaces(dm); + tface= dm->getTessFaceDataArray(dm, CD_MTFACE); + mcol= dm->getTessFaceDataArray(dm, CD_MCOL); + + if (mcol==NULL && tface==NULL) return NULL; + + /* make sorted table with edges and face indices in it */ + for (a= totface, mf= mface; a>0; a--, mf++) { + totedge += mf->v4 ? 4 : 3; + } + + if (totedge==0) + return NULL; + + ed= edsort= MEM_callocN(totedge*sizeof(struct edgesort), "edgesort"); + + for (a=0, mf=mface; a<totface; a++, mf++) { + to_edgesort(ed++, 0, 1, mf->v1, mf->v2, a); + to_edgesort(ed++, 1, 2, mf->v2, mf->v3, a); + if (mf->v4) { + to_edgesort(ed++, 2, 3, mf->v3, mf->v4, a); + to_edgesort(ed++, 3, 0, mf->v4, mf->v1, a); + } + else { + to_edgesort(ed++, 2, 3, mf->v3, mf->v1, a); + } + } + + qsort(edsort, totedge, sizeof(struct edgesort), vergedgesort); + + *totedgesort= totedge; + + return edsort; +} + +static void use_mesh_edge_lookup(ObjectRen *obr, DerivedMesh *dm, MEdge *medge, VlakRen *vlr, struct edgesort *edgetable, int totedge) +{ + struct edgesort ed, *edp; + CustomDataLayer *layer; + MTFace *mtface, *mtf; + MCol *mcol, *mc; + int index, mtfn, mcn; + char *name; + + if (medge->v1 < medge->v2) { + ed.v1= medge->v1; + ed.v2= medge->v2; + } + else { + ed.v1= medge->v2; + ed.v2= medge->v1; + } + + edp= bsearch(&ed, edgetable, totedge, sizeof(struct edgesort), vergedgesort); + + /* since edges have different index ordering, we have to duplicate mcol and tface */ + if (edp) { + mtfn= mcn= 0; + + for (index=0; index<dm->faceData.totlayer; index++) { + layer= &dm->faceData.layers[index]; + name= layer->name; + + if (layer->type == CD_MTFACE && mtfn < MAX_MTFACE) { + mtface= &((MTFace*)layer->data)[edp->f]; + mtf= RE_vlakren_get_tface(obr, vlr, mtfn++, &name, 1); + + *mtf= *mtface; + + memcpy(mtf->uv[0], mtface->uv[edp->i1], sizeof(float)*2); + memcpy(mtf->uv[1], mtface->uv[edp->i2], sizeof(float)*2); + memcpy(mtf->uv[2], mtface->uv[1], sizeof(float)*2); + memcpy(mtf->uv[3], mtface->uv[1], sizeof(float)*2); + } + else if (layer->type == CD_MCOL && mcn < MAX_MCOL) { + mcol= &((MCol*)layer->data)[edp->f*4]; + mc= RE_vlakren_get_mcol(obr, vlr, mcn++, &name, 1); + + mc[0]= mcol[edp->i1]; + mc[1]= mc[2]= mc[3]= mcol[edp->i2]; + } + } + } +} + +static void free_camera_inside_volumes(Render *re) +{ + BLI_freelistN(&re->render_volumes_inside); +} + +static void init_camera_inside_volumes(Render *re) +{ + ObjectInstanceRen *obi; + VolumeOb *vo; + /* coordinates are all in camera space, so camera coordinate is zero. we also + * add an offset for the clip start, however note that with clip start it's + * actually impossible to do a single 'inside' test, since there will not be + * a single point where all camera rays start from, though for small clip start + * they will be close together. */ + float co[3] = {0.f, 0.f, -re->clipsta}; + + for (vo= re->volumes.first; vo; vo= vo->next) { + for (obi= re->instancetable.first; obi; obi= obi->next) { + if (obi->obr == vo->obr) { + if (point_inside_volume_objectinstance(re, obi, co)) { + MatInside *mi; + + mi = MEM_mallocN(sizeof(MatInside), "camera inside material"); + mi->ma = vo->ma; + mi->obi = obi; + + BLI_addtail(&(re->render_volumes_inside), mi); + } + } + } + } + + +#if 0 /* debug */ + { + MatInside *m; + for (m = re->render_volumes_inside.first; m; m = m->next) { + printf("matinside: ma: %s\n", m->ma->id.name + 2); + } + } +#endif +} + +static void add_volume(Render *re, ObjectRen *obr, Material *ma) +{ + struct VolumeOb *vo; + + vo = MEM_mallocN(sizeof(VolumeOb), "volume object"); + + vo->ma = ma; + vo->obr = obr; + + BLI_addtail(&re->volumes, vo); +} + +#ifdef WITH_FREESTYLE +static EdgeHash *make_freestyle_edge_mark_hash(DerivedMesh *dm) +{ + EdgeHash *edge_hash= NULL; + FreestyleEdge *fed; + MEdge *medge; + int totedge, a; + + medge = dm->getEdgeArray(dm); + totedge = dm->getNumEdges(dm); + fed = dm->getEdgeDataArray(dm, CD_FREESTYLE_EDGE); + if (fed) { + edge_hash = BLI_edgehash_new(__func__); + for (a = 0; a < totedge; a++) { + if (fed[a].flag & FREESTYLE_EDGE_MARK) + BLI_edgehash_insert(edge_hash, medge[a].v1, medge[a].v2, medge+a); + } + } + return edge_hash; +} + +static bool has_freestyle_edge_mark(EdgeHash *edge_hash, int v1, int v2) +{ + MEdge *medge= BLI_edgehash_lookup(edge_hash, v1, v2); + return (!medge) ? 0 : 1; +} +#endif + +static void init_render_mesh(Render *re, ObjectRen *obr, int timeoffset) +{ + Object *ob= obr->ob; + Mesh *me; + MVert *mvert = NULL; + MFace *mface; + VlakRen *vlr; //, *vlr1; + VertRen *ver; + Material *ma; + DerivedMesh *dm; + CustomDataMask mask; + float xn, yn, zn, imat[3][3], mat[4][4]; //nor[3], + float *orco = NULL; + short (*loop_nors)[4][3] = NULL; + bool need_orco = false, need_stress = false, need_tangent = false, need_origindex = false; + bool need_nmap_tangent_concrete = false; + int a, a1, ok, vertofs; + int end, totvert = 0; + bool do_autosmooth = false, do_displace = false; + bool use_original_normals = false; + int recalc_normals = 0; /* false by default */ + int negative_scale; +#ifdef WITH_FREESTYLE + FreestyleFace *ffa; +#endif + + me= ob->data; + + mul_m4_m4m4(mat, re->viewmat, ob->obmat); + invert_m4_m4(ob->imat, mat); + copy_m3_m4(imat, ob->imat); + negative_scale= is_negative_m4(mat); + + need_orco= 0; + for (a=1; a<=ob->totcol; a++) { + ma= give_render_material(re, ob, a); + if (ma) { + if (ma->texco & (TEXCO_ORCO|TEXCO_STRESS)) + need_orco= 1; + if (ma->texco & TEXCO_STRESS) + need_stress= 1; + /* normalmaps, test if tangents needed, separated from shading */ + if (ma->mode_l & MA_TANGENT_V) { + need_tangent= 1; + if (me->mtpoly==NULL) + need_orco= 1; + } + if (ma->mode_l & MA_NORMAP_TANG) { + if (me->mtpoly==NULL) { + need_orco= 1; + } + need_tangent= 1; + } + if (ma->mode2_l & MA_TANGENT_CONCRETE) { + need_nmap_tangent_concrete = true; + } + } + } + + if (re->flag & R_NEED_TANGENT) { + /* exception for tangent space baking */ + if (me->mtpoly==NULL) { + need_orco= 1; + } + need_tangent= 1; + } + + /* check autosmooth and displacement, we then have to skip only-verts optimize + * Note: not sure what we want to give higher priority, currently do_displace + * takes precedence over do_autosmooth. + */ + do_displace = test_for_displace(re, ob); + do_autosmooth = ((me->flag & ME_AUTOSMOOTH) != 0) && !do_displace; + if (do_autosmooth || do_displace) + timeoffset = 0; + + /* origindex currently used when using autosmooth, or baking to vertex colors. */ + need_origindex = (do_autosmooth || ((re->flag & R_BAKING) && (re->r.bake_flag & R_BAKE_VCOL))); + + mask = CD_MASK_RENDER_INTERNAL; + if (!timeoffset) + if (need_orco) + mask |= CD_MASK_ORCO; + +#ifdef WITH_FREESTYLE + mask |= CD_MASK_ORIGINDEX | CD_MASK_FREESTYLE_EDGE | CD_MASK_FREESTYLE_FACE; +#endif + + if (re->r.scemode & R_VIEWPORT_PREVIEW) + dm= mesh_create_derived_view(re->scene, ob, mask); + else + dm= mesh_create_derived_render(re->scene, ob, mask); + if (dm==NULL) return; /* in case duplicated object fails? */ + + mvert= dm->getVertArray(dm); + totvert= dm->getNumVerts(dm); + + if (totvert == 0) { + dm->release(dm); + return; + } + + if (mask & CD_MASK_ORCO) { + orco = get_object_orco(re, ob); + if (!orco) { + orco= dm->getVertDataArray(dm, CD_ORCO); + if (orco) { + orco= MEM_dupallocN(orco); + set_object_orco(re, ob, orco); + } + } + } + + /* attempt to autsmooth on original mesh, only without subsurf */ + if (do_autosmooth && me->totvert==totvert && me->totface==dm->getNumTessFaces(dm)) + use_original_normals= true; + + ma= give_render_material(re, ob, 1); + + + if (ma->material_type == MA_TYPE_HALO) { + make_render_halos(re, obr, me, totvert, mvert, ma, orco); + } + else { + const int *index_vert_orig = NULL; + const int *index_mf_to_mpoly = NULL; + const int *index_mp_to_orig = NULL; + if (need_origindex) { + index_vert_orig = dm->getVertDataArray(dm, CD_ORIGINDEX); + /* double lookup for faces -> polys */ +#ifdef WITH_FREESTYLE + index_mf_to_mpoly = dm->getTessFaceDataArray(dm, CD_ORIGINDEX); + index_mp_to_orig = dm->getPolyDataArray(dm, CD_ORIGINDEX); +#endif + } + + for (a=0; a<totvert; a++, mvert++) { + ver= RE_findOrAddVert(obr, obr->totvert++); + copy_v3_v3(ver->co, mvert->co); + if (do_autosmooth == false) { /* autosmooth on original unrotated data to prevent differences between frames */ + normal_short_to_float_v3(ver->n, mvert->no); + mul_m4_v3(mat, ver->co); + mul_transposed_m3_v3(imat, ver->n); + normalize_v3(ver->n); + negate_v3(ver->n); + } + + if (orco) { + ver->orco= orco; + orco+=3; + } + + if (need_origindex) { + int *origindex; + origindex = RE_vertren_get_origindex(obr, ver, 1); + + /* Use orig index array if it's available (e.g. in the presence + * of modifiers). */ + if (index_vert_orig) + *origindex = index_vert_orig[a]; + else + *origindex = a; + } + } + + if (!timeoffset) { + short (*lnp)[4][3] = NULL; +#ifdef WITH_FREESTYLE + EdgeHash *edge_hash; + + /* create a hash table of Freestyle edge marks */ + edge_hash = make_freestyle_edge_mark_hash(dm); +#endif + + /* store customdata names, because DerivedMesh is freed */ + RE_set_customdata_names(obr, &dm->faceData); + + /* add tangent layers if we need */ + if ((ma->nmap_tangent_names_count && need_nmap_tangent_concrete) || need_tangent) { + dm->calcLoopTangents( + dm, need_tangent, + (const char (*)[MAX_NAME])ma->nmap_tangent_names, ma->nmap_tangent_names_count); + obr->tangent_mask = dm->tangent_mask; + DM_generate_tangent_tessface_data(dm, need_nmap_tangent_concrete || need_tangent); + } + + /* still to do for keys: the correct local texture coordinate */ + + /* faces in order of color blocks */ + vertofs= obr->totvert - totvert; + for (a1=0; (a1<ob->totcol || (a1==0 && ob->totcol==0)); a1++) { + + ma= give_render_material(re, ob, a1+1); + + /* test for 100% transparent */ + ok = 1; + if ((ma->alpha == 0.0f) && + (ma->spectra == 0.0f) && + /* No need to test filter here, it's only active with MA_RAYTRANSP and we check against it below. */ + /* (ma->filter == 0.0f) && */ + (ma->mode & MA_TRANSP) && + (ma->mode & (MA_RAYTRANSP | MA_RAYMIRROR)) == 0) + { + ok = 0; + /* texture on transparency? */ + for (a=0; a<MAX_MTEX; a++) { + if (ma->mtex[a] && ma->mtex[a]->tex) { + if (ma->mtex[a]->mapto & MAP_ALPHA) ok= 1; + } + } + } + + /* if wire material, and we got edges, don't do the faces */ + if (ma->material_type == MA_TYPE_WIRE) { + end= dm->getNumEdges(dm); + if (end) ok= 0; + } + + if (ok) { + end= dm->getNumTessFaces(dm); + mface= dm->getTessFaceArray(dm); + if (!loop_nors && do_autosmooth && + (dm->getTessFaceDataArray(dm, CD_TESSLOOPNORMAL) != NULL)) + { + lnp = loop_nors = MEM_mallocN(sizeof(*loop_nors) * end, __func__); + } +#ifdef WITH_FREESTYLE + index_mf_to_mpoly= dm->getTessFaceDataArray(dm, CD_ORIGINDEX); + index_mp_to_orig= dm->getPolyDataArray(dm, CD_ORIGINDEX); + ffa= CustomData_get_layer(&me->pdata, CD_FREESTYLE_FACE); +#endif + + for (a=0; a<end; a++, mface++) { + int v1, v2, v3, v4, flag; + + if ( mface->mat_nr==a1 ) { + float len; + bool reverse_verts = (negative_scale != 0 && do_autosmooth == false); + int rev_tab[] = {reverse_verts==0 ? 0 : 2, 1, reverse_verts==0 ? 2 : 0, 3}; + v1= reverse_verts==0 ? mface->v1 : mface->v3; + v2= mface->v2; + v3= reverse_verts==0 ? mface->v3 : mface->v1; + v4= mface->v4; + flag = do_autosmooth ? ME_SMOOTH : mface->flag & ME_SMOOTH; + + vlr= RE_findOrAddVlak(obr, obr->totvlak++); + vlr->v1= RE_findOrAddVert(obr, vertofs+v1); + vlr->v2= RE_findOrAddVert(obr, vertofs+v2); + vlr->v3= RE_findOrAddVert(obr, vertofs+v3); + if (v4) vlr->v4 = RE_findOrAddVert(obr, vertofs+v4); + else vlr->v4 = NULL; + +#ifdef WITH_FREESTYLE + /* Freestyle edge/face marks */ + if (edge_hash) { + int edge_mark = 0; + + if (has_freestyle_edge_mark(edge_hash, v1, v2)) edge_mark |= R_EDGE_V1V2; + if (has_freestyle_edge_mark(edge_hash, v2, v3)) edge_mark |= R_EDGE_V2V3; + if (!v4) { + if (has_freestyle_edge_mark(edge_hash, v3, v1)) edge_mark |= R_EDGE_V3V1; + } + else { + if (has_freestyle_edge_mark(edge_hash, v3, v4)) edge_mark |= R_EDGE_V3V4; + if (has_freestyle_edge_mark(edge_hash, v4, v1)) edge_mark |= R_EDGE_V4V1; + } + vlr->freestyle_edge_mark= edge_mark; + } + if (ffa) { + int index = (index_mf_to_mpoly) ? DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, a) : a; + vlr->freestyle_face_mark= (ffa[index].flag & FREESTYLE_FACE_MARK) ? 1 : 0; + } + else { + vlr->freestyle_face_mark= 0; + } +#endif + + /* render normals are inverted in render */ + if (use_original_normals) { + MFace *mf= me->mface+a; + MVert *mv= me->mvert; + + if (vlr->v4) + len= normal_quad_v3(vlr->n, mv[mf->v4].co, mv[mf->v3].co, mv[mf->v2].co, mv[mf->v1].co); + else + len= normal_tri_v3(vlr->n, mv[mf->v3].co, mv[mf->v2].co, mv[mf->v1].co); + } + else { + if (vlr->v4) + len= normal_quad_v3(vlr->n, vlr->v4->co, vlr->v3->co, vlr->v2->co, vlr->v1->co); + else + len= normal_tri_v3(vlr->n, vlr->v3->co, vlr->v2->co, vlr->v1->co); + } + + vlr->mat= ma; + vlr->flag= flag; + vlr->ec= 0; /* mesh edges rendered separately */ + + if (len==0) obr->totvlak--; + else { + CustomDataLayer *layer; + MTFace *mtface, *mtf; + MCol *mcol, *mc; + int index, mtfn= 0, mcn= 0, mln = 0, vindex; + char *name; + int nr_verts = v4!=0 ? 4 : 3; + + for (index=0; index<dm->faceData.totlayer; index++) { + layer= &dm->faceData.layers[index]; + name= layer->name; + + if (layer->type == CD_MTFACE && mtfn < MAX_MTFACE) { + int t; + mtf= RE_vlakren_get_tface(obr, vlr, mtfn++, &name, 1); + mtface= (MTFace*)layer->data; + *mtf = mtface[a]; /* copy face info */ + for (vindex=0; vindex<nr_verts; vindex++) + for (t=0; t<2; t++) + mtf->uv[vindex][t]=mtface[a].uv[rev_tab[vindex]][t]; + } + else if (layer->type == CD_MCOL && mcn < MAX_MCOL) { + mc= RE_vlakren_get_mcol(obr, vlr, mcn++, &name, 1); + mcol= (MCol*)layer->data; + for (vindex=0; vindex<nr_verts; vindex++) + mc[vindex]=mcol[a*4+rev_tab[vindex]]; + } + else if (layer->type == CD_TANGENT) { + if (need_nmap_tangent_concrete || need_tangent) { + int uv_start = CustomData_get_layer_index(&dm->faceData, CD_MTFACE); + int uv_index = CustomData_get_named_layer_index(&dm->faceData, CD_MTFACE, layer->name); + + /* if there are no UVs, orco tangents are in first slot */ + int n = (uv_start >= 0 && uv_index >= 0) ? uv_index - uv_start : 0; + + const float *tangent = (const float *) layer->data; + float *ftang = RE_vlakren_get_nmap_tangent(obr, vlr, n, true); + + for (vindex=0; vindex<nr_verts; vindex++) { + copy_v4_v4(ftang+vindex*4, tangent+a*16+rev_tab[vindex]*4); + mul_mat3_m4_v3(mat, ftang+vindex*4); + normalize_v3(ftang+vindex*4); + } + } + } + else if (layer->type == CD_TESSLOOPNORMAL && mln < 1) { + if (loop_nors) { + const short (*lnors)[4][3] = (const short (*)[4][3])layer->data; + for (vindex = 0; vindex < 4; vindex++) { + //print_v3("lnors[a][rev_tab[vindex]]", lnors[a][rev_tab[vindex]]); + copy_v3_v3_short((short *)lnp[0][vindex], lnors[a][rev_tab[vindex]]); + /* If we copy loop normals, we are doing autosmooth, so we are still + * in object space, no need to multiply with mat! + */ + } + lnp++; + } + mln++; + } + } + + if (need_origindex) { + /* Find original index of mpoly for this tessface. Options: + * - Modified mesh; two-step look up from tessface -> modified mpoly -> original mpoly + * - OR Tesselated mesh; look up from tessface -> mpoly + * - OR Failsafe; tessface == mpoly. Could probably assert(false) in this case? */ + int *origindex; + origindex = RE_vlakren_get_origindex(obr, vlr, 1); + if (index_mf_to_mpoly && index_mp_to_orig) + *origindex = DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, a); + else if (index_mf_to_mpoly) + *origindex = index_mf_to_mpoly[a]; + else + *origindex = a; + } + } + } + } + } + } + +#ifdef WITH_FREESTYLE + /* release the hash table of Freestyle edge marks */ + if (edge_hash) + BLI_edgehash_free(edge_hash, NULL); +#endif + + /* exception... we do edges for wire mode. potential conflict when faces exist... */ + end= dm->getNumEdges(dm); + mvert= dm->getVertArray(dm); + ma= give_render_material(re, ob, 1); + if (end && (ma->material_type == MA_TYPE_WIRE)) { + MEdge *medge; + struct edgesort *edgetable; + int totedge= 0; + recalc_normals= 1; + + medge= dm->getEdgeArray(dm); + + /* we want edges to have UV and vcol too... */ + edgetable= make_mesh_edge_lookup(dm, &totedge); + + for (a1=0; a1<end; a1++, medge++) { + if (medge->flag&ME_EDGERENDER) { + MVert *v0 = &mvert[medge->v1]; + MVert *v1 = &mvert[medge->v2]; + + vlr= RE_findOrAddVlak(obr, obr->totvlak++); + vlr->v1= RE_findOrAddVert(obr, vertofs+medge->v1); + vlr->v2= RE_findOrAddVert(obr, vertofs+medge->v2); + vlr->v3= vlr->v2; + vlr->v4= NULL; + + if (edgetable) + use_mesh_edge_lookup(obr, dm, medge, vlr, edgetable, totedge); + + xn= -(v0->no[0]+v1->no[0]); + yn= -(v0->no[1]+v1->no[1]); + zn= -(v0->no[2]+v1->no[2]); + /* transpose ! */ + vlr->n[0]= imat[0][0]*xn+imat[0][1]*yn+imat[0][2]*zn; + vlr->n[1]= imat[1][0]*xn+imat[1][1]*yn+imat[1][2]*zn; + vlr->n[2]= imat[2][0]*xn+imat[2][1]*yn+imat[2][2]*zn; + normalize_v3(vlr->n); + + vlr->mat= ma; + vlr->flag= 0; + vlr->ec= ME_V1V2; + } + } + if (edgetable) + MEM_freeN(edgetable); + } + } + } + + if (!timeoffset) { + if (need_stress) + calc_edge_stress(re, obr, me); + + if (do_displace) { + calc_vertexnormals(re, obr, 1, 0, 0); + displace(re, obr); + recalc_normals = 0; /* Already computed by displace! */ + } + else if (do_autosmooth) { + recalc_normals = (loop_nors == NULL); /* Should never happen, but better be safe than sorry. */ + autosmooth(re, obr, mat, loop_nors); + } + + if (recalc_normals!=0 || need_tangent!=0) + calc_vertexnormals(re, obr, recalc_normals, need_tangent, need_nmap_tangent_concrete); + } + + MEM_SAFE_FREE(loop_nors); + + dm->release(dm); +} + +/* ------------------------------------------------------------------------- */ +/* Lamps and Shadowbuffers */ +/* ------------------------------------------------------------------------- */ + +static void initshadowbuf(Render *re, LampRen *lar, float mat[4][4]) +{ + struct ShadBuf *shb; + float viewinv[4][4]; + + /* if (la->spsi<16) return; */ + + /* memory alloc */ + shb= (struct ShadBuf *)MEM_callocN(sizeof(struct ShadBuf), "initshadbuf"); + lar->shb= shb; + + if (shb==NULL) return; + + VECCOPY(shb->co, lar->co); /* int copy */ + + /* percentage render: keep track of min and max */ + shb->size= (lar->bufsize*re->r.size)/100; + + if (shb->size<512) shb->size= 512; + else if (shb->size > lar->bufsize) shb->size= lar->bufsize; + + shb->size &= ~15; /* make sure its multiples of 16 */ + + shb->samp= lar->samp; + shb->soft= lar->soft; + shb->shadhalostep= lar->shadhalostep; + + normalize_m4(mat); + invert_m4_m4(shb->winmat, mat); /* winmat is temp */ + + /* matrix: combination of inverse view and lampmat */ + /* calculate again: the ortho-render has no correct viewinv */ + invert_m4_m4(viewinv, re->viewmat); + mul_m4_m4m4(shb->viewmat, shb->winmat, viewinv); + + /* projection */ + shb->d= lar->clipsta; + shb->clipend= lar->clipend; + + /* bias is percentage, made 2x larger because of correction for angle of incidence */ + /* when a ray is closer to parallel of a face, bias value is increased during render */ + shb->bias= (0.02f*lar->bias)*0x7FFFFFFF; + + /* halfway method (average of first and 2nd z) reduces bias issues */ + if (ELEM(lar->buftype, LA_SHADBUF_HALFWAY, LA_SHADBUF_DEEP)) + shb->bias= 0.1f*shb->bias; + + shb->compressthresh= lar->compressthresh; +} + +void area_lamp_vectors(LampRen *lar) +{ + float xsize= 0.5f*lar->area_size, ysize= 0.5f*lar->area_sizey, multifac; + + /* make it smaller, so area light can be multisampled */ + multifac= 1.0f/sqrtf((float)lar->ray_totsamp); + xsize *= multifac; + ysize *= multifac; + + /* corner vectors */ + lar->area[0][0]= lar->co[0] - xsize*lar->mat[0][0] - ysize*lar->mat[1][0]; + lar->area[0][1]= lar->co[1] - xsize*lar->mat[0][1] - ysize*lar->mat[1][1]; + lar->area[0][2]= lar->co[2] - xsize*lar->mat[0][2] - ysize*lar->mat[1][2]; + + /* corner vectors */ + lar->area[1][0]= lar->co[0] - xsize*lar->mat[0][0] + ysize*lar->mat[1][0]; + lar->area[1][1]= lar->co[1] - xsize*lar->mat[0][1] + ysize*lar->mat[1][1]; + lar->area[1][2]= lar->co[2] - xsize*lar->mat[0][2] + ysize*lar->mat[1][2]; + + /* corner vectors */ + lar->area[2][0]= lar->co[0] + xsize*lar->mat[0][0] + ysize*lar->mat[1][0]; + lar->area[2][1]= lar->co[1] + xsize*lar->mat[0][1] + ysize*lar->mat[1][1]; + lar->area[2][2]= lar->co[2] + xsize*lar->mat[0][2] + ysize*lar->mat[1][2]; + + /* corner vectors */ + lar->area[3][0]= lar->co[0] + xsize*lar->mat[0][0] - ysize*lar->mat[1][0]; + lar->area[3][1]= lar->co[1] + xsize*lar->mat[0][1] - ysize*lar->mat[1][1]; + lar->area[3][2]= lar->co[2] + xsize*lar->mat[0][2] - ysize*lar->mat[1][2]; + /* only for correction button size, matrix size works on energy */ + lar->areasize= lar->dist*lar->dist/(4.0f*xsize*ysize); +} + +/* If lar takes more lamp data, the decoupling will be better. */ +static GroupObject *add_render_lamp(Render *re, Object *ob) +{ + Lamp *la= ob->data; + LampRen *lar; + GroupObject *go; + float mat[4][4], angle, xn, yn; + float vec[3]; + int c; + + /* previewrender sets this to zero... prevent accidents */ + if (la==NULL) return NULL; + + /* prevent only shadow from rendering light */ + if (la->mode & LA_ONLYSHADOW) + if ((re->r.mode & R_SHADOW)==0) + return NULL; + + re->totlamp++; + + /* groups is used to unify support for lightgroups, this is the global lightgroup */ + go= MEM_callocN(sizeof(GroupObject), "groupobject"); + BLI_addtail(&re->lights, go); + go->ob= ob; + /* lamprens are in own list, for freeing */ + lar= (LampRen *)MEM_callocN(sizeof(LampRen), "lampren"); + BLI_addtail(&re->lampren, lar); + go->lampren= lar; + + mul_m4_m4m4(mat, re->viewmat, ob->obmat); + invert_m4_m4(ob->imat, mat); + + copy_m4_m4(lar->lampmat, ob->obmat); + copy_m3_m4(lar->mat, mat); + copy_m3_m4(lar->imat, ob->imat); + + lar->bufsize = la->bufsize; + lar->samp = la->samp; + lar->buffers= la->buffers; + if (lar->buffers==0) lar->buffers= 1; + lar->buftype= la->buftype; + lar->filtertype= la->filtertype; + lar->soft = la->soft; + lar->shadhalostep = la->shadhalostep; + lar->clipsta = la->clipsta; + lar->clipend = la->clipend; + + lar->bias = la->bias; + lar->compressthresh = la->compressthresh; + + lar->type= la->type; + lar->mode= la->mode; + + lar->energy= la->energy; + if (la->mode & LA_NEG) lar->energy= -lar->energy; + + lar->vec[0]= -mat[2][0]; + lar->vec[1]= -mat[2][1]; + lar->vec[2]= -mat[2][2]; + normalize_v3(lar->vec); + lar->co[0]= mat[3][0]; + lar->co[1]= mat[3][1]; + lar->co[2]= mat[3][2]; + lar->dist= la->dist; + lar->haint= la->haint; + lar->distkw= lar->dist*lar->dist; + lar->r= lar->energy*la->r; + lar->g= lar->energy*la->g; + lar->b= lar->energy*la->b; + lar->shdwr= la->shdwr; + lar->shdwg= la->shdwg; + lar->shdwb= la->shdwb; + lar->k= la->k; + + /* area */ + lar->ray_samp= la->ray_samp; + lar->ray_sampy= la->ray_sampy; + lar->ray_sampz= la->ray_sampz; + + lar->area_size= la->area_size; + lar->area_sizey= la->area_sizey; + lar->area_sizez= la->area_sizez; + + lar->area_shape= la->area_shape; + + /* Annoying, lamp UI does this, but the UI might not have been used? - add here too. + * make sure this matches buttons_shading.c's logic */ + if (ELEM(la->type, LA_AREA, LA_SPOT, LA_SUN, LA_LOCAL) && (la->mode & LA_SHAD_RAY)) + if (ELEM(la->type, LA_SPOT, LA_SUN, LA_LOCAL)) + if (la->ray_samp_method == LA_SAMP_CONSTANT) la->ray_samp_method = LA_SAMP_HALTON; + + lar->ray_samp_method= la->ray_samp_method; + lar->ray_samp_type= la->ray_samp_type; + + lar->adapt_thresh= la->adapt_thresh; + lar->sunsky = NULL; + + if ( ELEM(lar->type, LA_SPOT, LA_LOCAL)) { + lar->ray_totsamp= lar->ray_samp*lar->ray_samp; + lar->area_shape = LA_AREA_SQUARE; + lar->area_sizey= lar->area_size; + } + else if (lar->type==LA_AREA) { + switch (lar->area_shape) { + case LA_AREA_SQUARE: + lar->ray_totsamp= lar->ray_samp*lar->ray_samp; + lar->ray_sampy= lar->ray_samp; + lar->area_sizey= lar->area_size; + break; + case LA_AREA_RECT: + lar->ray_totsamp= lar->ray_samp*lar->ray_sampy; + break; + case LA_AREA_CUBE: + lar->ray_totsamp= lar->ray_samp*lar->ray_samp*lar->ray_samp; + lar->ray_sampy= lar->ray_samp; + lar->ray_sampz= lar->ray_samp; + lar->area_sizey= lar->area_size; + lar->area_sizez= lar->area_size; + break; + case LA_AREA_BOX: + lar->ray_totsamp= lar->ray_samp*lar->ray_sampy*lar->ray_sampz; + break; + } + + area_lamp_vectors(lar); + init_jitter_plane(lar); /* subsamples */ + } + else if (lar->type==LA_SUN) { + lar->ray_totsamp= lar->ray_samp*lar->ray_samp; + lar->area_shape = LA_AREA_SQUARE; + lar->area_sizey= lar->area_size; + + if ((la->sun_effect_type & LA_SUN_EFFECT_SKY) || + (la->sun_effect_type & LA_SUN_EFFECT_AP)) + { + lar->sunsky = (struct SunSky*)MEM_callocN(sizeof(struct SunSky), "sunskyren"); + lar->sunsky->effect_type = la->sun_effect_type; + + copy_v3_v3(vec, ob->obmat[2]); + normalize_v3(vec); + + InitSunSky( + lar->sunsky, la->atm_turbidity, vec, la->horizon_brightness, + la->spread, la->sun_brightness, la->sun_size, la->backscattered_light, + la->skyblendfac, la->skyblendtype, la->sky_exposure, la->sky_colorspace); + InitAtmosphere( + lar->sunsky, la->sun_intensity, 1.0, 1.0, la->atm_inscattering_factor, la->atm_extinction_factor, + la->atm_distance_factor); + } + } + else lar->ray_totsamp= 0; + + lar->spotsi= la->spotsize; + if (lar->mode & LA_HALO) { + if (lar->spotsi > DEG2RADF(170.0f)) lar->spotsi = DEG2RADF(170.0f); + } + lar->spotsi= cosf(lar->spotsi * 0.5f); + lar->spotbl= (1.0f-lar->spotsi)*la->spotblend; + + memcpy(lar->mtex, la->mtex, MAX_MTEX*sizeof(void *)); + + lar->lay = ob->lay & 0xFFFFFF; /* higher 8 bits are localview layers */ + + lar->falloff_type = la->falloff_type; + lar->ld1= la->att1; + lar->ld2= la->att2; + lar->coeff_const= la->coeff_const; + lar->coeff_lin= la->coeff_lin; + lar->coeff_quad= la->coeff_quad; + lar->curfalloff = curvemapping_copy(la->curfalloff); + + if (lar->curfalloff) { + /* so threads don't conflict on init */ + curvemapping_initialize(lar->curfalloff); + } + + if (lar->type==LA_SPOT) { + + normalize_v3(lar->imat[0]); + normalize_v3(lar->imat[1]); + normalize_v3(lar->imat[2]); + + xn = saacos(lar->spotsi); + xn = sinf(xn) / cosf(xn); + lar->spottexfac= 1.0f/(xn); + + if (lar->mode & LA_ONLYSHADOW) { + if ((lar->mode & (LA_SHAD_BUF|LA_SHAD_RAY))==0) lar->mode -= LA_ONLYSHADOW; + } + + } + + /* set flag for spothalo en initvars */ + if ((la->type == LA_SPOT) && (la->mode & LA_HALO) && + (!(la->mode & LA_SHAD_BUF) || la->buftype != LA_SHADBUF_DEEP)) + { + if (la->haint>0.0f) { + re->flag |= R_LAMPHALO; + + /* camera position (0, 0, 0) rotate around lamp */ + lar->sh_invcampos[0]= -lar->co[0]; + lar->sh_invcampos[1]= -lar->co[1]; + lar->sh_invcampos[2]= -lar->co[2]; + mul_m3_v3(lar->imat, lar->sh_invcampos); + + /* z factor, for a normalized volume */ + angle= saacos(lar->spotsi); + xn= lar->spotsi; + yn = sinf(angle); + lar->sh_zfac= yn/xn; + /* pre-scale */ + lar->sh_invcampos[2]*= lar->sh_zfac; + + /* halfway shadow buffer doesn't work for volumetric effects */ + if (ELEM(lar->buftype, LA_SHADBUF_HALFWAY, LA_SHADBUF_DEEP)) + lar->buftype = LA_SHADBUF_REGULAR; + + } + } + else if (la->type==LA_HEMI) { + lar->mode &= ~(LA_SHAD_RAY|LA_SHAD_BUF); + } + + for (c=0; c<MAX_MTEX; c++) { + if (la->mtex[c] && la->mtex[c]->tex) { + if (la->mtex[c]->mapto & LAMAP_COL) + lar->mode |= LA_TEXTURE; + if (la->mtex[c]->mapto & LAMAP_SHAD) + lar->mode |= LA_SHAD_TEX; + + if (G.is_rendering) { + if (re->osa) { + if (la->mtex[c]->tex->type==TEX_IMAGE) lar->mode |= LA_OSATEX; + } + } + } + } + + /* old code checked for internal render (aka not yafray) */ + { + /* to make sure we can check ray shadow easily in the render code */ + if (lar->mode & LA_SHAD_RAY) { + if ( (re->r.mode & R_RAYTRACE)==0) + lar->mode &= ~LA_SHAD_RAY; + } + + + if (re->r.mode & R_SHADOW) { + + if (la->type==LA_AREA && (lar->mode & LA_SHAD_RAY) && (lar->ray_samp_method == LA_SAMP_CONSTANT)) { + init_jitter_plane(lar); + } + else if (la->type==LA_SPOT && (lar->mode & LA_SHAD_BUF) ) { + /* Per lamp, one shadow buffer is made. */ + lar->bufflag= la->bufflag; + copy_m4_m4(mat, ob->obmat); + initshadowbuf(re, lar, mat); /* mat is altered */ + } + + + /* this is the way used all over to check for shadow */ + if (lar->shb || (lar->mode & LA_SHAD_RAY)) { + LampShadowSample *ls; + LampShadowSubSample *lss; + int a, b; + + memset(re->shadowsamplenr, 0, sizeof(re->shadowsamplenr)); + + lar->shadsamp= MEM_mallocN(re->r.threads*sizeof(LampShadowSample), "lamp shadow sample"); + ls= lar->shadsamp; + + /* shadfacs actually mean light, let's put them to 1 to prevent unitialized accidents */ + for (a=0; a<re->r.threads; a++, ls++) { + lss= ls->s; + for (b=0; b<re->r.osa; b++, lss++) { + lss->samplenr= -1; /* used to detect whether we store or read */ + lss->shadfac[0]= 1.0f; + lss->shadfac[1]= 1.0f; + lss->shadfac[2]= 1.0f; + lss->shadfac[3]= 1.0f; + } + } + } + } + } + + return go; +} + +static bool is_object_restricted(Render *re, Object *ob) +{ + if (re->r.scemode & R_VIEWPORT_PREVIEW) + return (ob->restrictflag & OB_RESTRICT_VIEW) != 0; + else + return (ob->restrictflag & OB_RESTRICT_RENDER) != 0; +} + +static bool is_object_hidden(Render *re, Object *ob) +{ + if (is_object_restricted(re, ob)) + return true; + + if (re->r.scemode & R_VIEWPORT_PREVIEW) { + /* Mesh deform cages and so on mess up the preview. To avoid the problem, + * viewport doesn't show mesh object if its draw type is bounding box or wireframe. + * Unless it's an active smoke domain! + */ + ModifierData *md = NULL; + + if ((md = modifiers_findByType(ob, eModifierType_Smoke)) && + (modifier_isEnabled(re->scene, md, eModifierMode_Realtime))) + { + return false; + } + return ELEM(ob->dt, OB_BOUNDBOX, OB_WIRE); + } + else { + return false; + } +} + +/* layflag: allows material group to ignore layerflag */ +static void add_lightgroup(Render *re, Group *group, int exclusive) +{ + GroupObject *go, *gol; + + group->id.tag &= ~LIB_TAG_DOIT; + + /* it's a bit too many loops in loops... but will survive */ + /* note that 'exclusive' will remove it from the global list */ + for (go= group->gobject.first; go; go= go->next) { + go->lampren= NULL; + + if (is_object_hidden(re, go->ob)) + continue; + + if (go->ob->lay & re->lay) { + if (go->ob && go->ob->type==OB_LAMP) { + for (gol= re->lights.first; gol; gol= gol->next) { + if (gol->ob==go->ob) { + go->lampren= gol->lampren; + break; + } + } + if (go->lampren==NULL) + gol= add_render_lamp(re, go->ob); + if (gol && exclusive) { + BLI_remlink(&re->lights, gol); + MEM_freeN(gol); + } + } + } + } +} + +static void set_material_lightgroups(Render *re) +{ + Group *group; + Material *ma; + + /* not for preview render */ + if (re->scene->r.scemode & (R_BUTS_PREVIEW|R_VIEWPORT_PREVIEW)) + return; + + for (group= re->main->group.first; group; group=group->id.next) + group->id.tag |= LIB_TAG_DOIT; + + /* it's a bit too many loops in loops... but will survive */ + /* hola! materials not in use...? */ + for (ma= re->main->mat.first; ma; ma=ma->id.next) { + if (ma->group && (ma->group->id.tag & LIB_TAG_DOIT)) + add_lightgroup(re, ma->group, ma->mode & MA_GROUP_NOLAY); + } +} + +static void set_renderlayer_lightgroups(Render *re, Scene *sce) +{ + SceneRenderLayer *srl; + + for (srl= sce->r.layers.first; srl; srl= srl->next) { + if (srl->light_override) + add_lightgroup(re, srl->light_override, 0); + } +} + +/* ------------------------------------------------------------------------- */ +/* World */ +/* ------------------------------------------------------------------------- */ + +void init_render_world(Render *re) +{ + void *wrld_prev[2] = { + re->wrld.aotables, + re->wrld.aosphere, + }; + + int a; + + if (re->scene && re->scene->world) { + re->wrld = *(re->scene->world); + + copy_v3_v3(re->grvec, re->viewmat[2]); + normalize_v3(re->grvec); + copy_m3_m4(re->imat, re->viewinv); + + for (a=0; a<MAX_MTEX; a++) + if (re->wrld.mtex[a] && re->wrld.mtex[a]->tex) re->wrld.skytype |= WO_SKYTEX; + + /* AO samples should be OSA minimum */ + if (re->osa) + while (re->wrld.aosamp*re->wrld.aosamp < re->osa) + re->wrld.aosamp++; + if (!(re->r.mode & R_RAYTRACE) && (re->wrld.ao_gather_method == WO_AOGATHER_RAYTRACE)) + re->wrld.mode &= ~(WO_AMB_OCC|WO_ENV_LIGHT|WO_INDIRECT_LIGHT); + } + else { + memset(&re->wrld, 0, sizeof(World)); + re->wrld.exp= 0.0f; + re->wrld.range= 1.0f; + + /* for mist pass */ + re->wrld.miststa= re->clipsta; + re->wrld.mistdist= re->clipend-re->clipsta; + re->wrld.misi= 1.0f; + } + + re->wrld.linfac= 1.0f + powf((2.0f*re->wrld.exp + 0.5f), -10); + re->wrld.logfac= logf((re->wrld.linfac-1.0f)/re->wrld.linfac) / re->wrld.range; + + /* restore runtime vars, needed for viewport rendering [#36005] */ + re->wrld.aotables = wrld_prev[0]; + re->wrld.aosphere = wrld_prev[1]; +} + + + +/* ------------------------------------------------------------------------- */ +/* Object Finalization */ +/* ------------------------------------------------------------------------- */ + +/* prevent phong interpolation for giving ray shadow errors (terminator problem) */ +static void set_phong_threshold(ObjectRen *obr) +{ +// VertRen *ver; + VlakRen *vlr; + float thresh= 0.0, dot; + int tot=0, i; + + /* Added check for 'pointy' situations, only dotproducts of 0.9 and larger + * are taken into account. This threshold is meant to work on smooth geometry, not + * for extreme cases (ton) */ + + for (i=0; i<obr->totvlak; i++) { + vlr= RE_findOrAddVlak(obr, i); + if ((vlr->flag & R_SMOOTH) && (vlr->flag & R_STRAND)==0) { + dot= dot_v3v3(vlr->n, vlr->v1->n); + dot= ABS(dot); + if (dot>0.9f) { + thresh+= dot; tot++; + } + dot= dot_v3v3(vlr->n, vlr->v2->n); + dot= ABS(dot); + if (dot>0.9f) { + thresh+= dot; tot++; + } + + dot= dot_v3v3(vlr->n, vlr->v3->n); + dot= ABS(dot); + if (dot>0.9f) { + thresh+= dot; tot++; + } + + if (vlr->v4) { + dot= dot_v3v3(vlr->n, vlr->v4->n); + dot= ABS(dot); + if (dot>0.9f) { + thresh+= dot; tot++; + } + } + } + } + + if (tot) { + thresh/= (float)tot; + obr->ob->smoothresh= cosf(0.5f*(float)M_PI-saacos(thresh)); + } +} + +/* per face check if all samples should be taken. + * if raytrace or multisample, do always for raytraced material, or when material full_osa set */ +static void set_fullsample_trace_flag(Render *re, ObjectRen *obr) +{ + VlakRen *vlr; + int a, trace, mode, osa; + + osa= re->osa; + trace= re->r.mode & R_RAYTRACE; + + for (a=obr->totvlak-1; a>=0; a--) { + vlr= RE_findOrAddVlak(obr, a); + mode= vlr->mat->mode; + + if (trace && (mode & MA_TRACEBLE)) + vlr->flag |= R_TRACEBLE; + + if (osa) { + if (mode & MA_FULL_OSA) { + vlr->flag |= R_FULL_OSA; + } + else if (trace) { + if (mode & MA_SHLESS) { + /* pass */ + } + else if (vlr->mat->material_type == MA_TYPE_VOLUME) { + /* pass */ + } + else if ((mode & MA_RAYMIRROR) || ((mode & MA_TRANSP) && (mode & MA_RAYTRANSP))) { + /* for blurry reflect/refract, better to take more samples + * inside the raytrace than as OSA samples */ + if ((vlr->mat->gloss_mir == 1.0f) && (vlr->mat->gloss_tra == 1.0f)) + vlr->flag |= R_FULL_OSA; + } + } + } + } +} + +/* split quads for predictable baking + * dir 1 == (0, 1, 2) (0, 2, 3), 2 == (1, 3, 0) (1, 2, 3) + */ +static void split_quads(ObjectRen *obr, int dir) +{ + VlakRen *vlr, *vlr1; + int a; + + for (a=obr->totvlak-1; a>=0; a--) { + vlr= RE_findOrAddVlak(obr, a); + + /* test if rendering as a quad or triangle, skip wire */ + if ((vlr->flag & R_STRAND)==0 && (vlr->mat->material_type != MA_TYPE_WIRE)) { + + if (vlr->v4) { + + vlr1= RE_vlakren_copy(obr, vlr); + vlr1->flag |= R_FACE_SPLIT; + + if ( dir==2 ) vlr->flag |= R_DIVIDE_24; + else vlr->flag &= ~R_DIVIDE_24; + + /* new vertex pointers */ + if (vlr->flag & R_DIVIDE_24) { + vlr1->v1= vlr->v2; + vlr1->v2= vlr->v3; + vlr1->v3= vlr->v4; + + vlr->v3 = vlr->v4; + + vlr1->flag |= R_DIVIDE_24; + } + else { + vlr1->v1= vlr->v1; + vlr1->v2= vlr->v3; + vlr1->v3= vlr->v4; + + vlr1->flag &= ~R_DIVIDE_24; + } + vlr->v4 = vlr1->v4 = NULL; + +#ifdef WITH_FREESTYLE + /* Freestyle edge marks */ + if (vlr->flag & R_DIVIDE_24) { + vlr1->freestyle_edge_mark= + ((vlr->freestyle_edge_mark & R_EDGE_V2V3) ? R_EDGE_V1V2 : 0) | + ((vlr->freestyle_edge_mark & R_EDGE_V3V4) ? R_EDGE_V2V3 : 0); + vlr->freestyle_edge_mark= + ((vlr->freestyle_edge_mark & R_EDGE_V1V2) ? R_EDGE_V1V2 : 0) | + ((vlr->freestyle_edge_mark & R_EDGE_V4V1) ? R_EDGE_V3V1 : 0); + } + else { + vlr1->freestyle_edge_mark= + ((vlr->freestyle_edge_mark & R_EDGE_V3V4) ? R_EDGE_V2V3 : 0) | + ((vlr->freestyle_edge_mark & R_EDGE_V4V1) ? R_EDGE_V3V1 : 0); + vlr->freestyle_edge_mark= + ((vlr->freestyle_edge_mark & R_EDGE_V1V2) ? R_EDGE_V1V2 : 0) | + ((vlr->freestyle_edge_mark & R_EDGE_V2V3) ? R_EDGE_V2V3 : 0); + } +#endif + + /* new normals */ + normal_tri_v3(vlr->n, vlr->v3->co, vlr->v2->co, vlr->v1->co); + normal_tri_v3(vlr1->n, vlr1->v3->co, vlr1->v2->co, vlr1->v1->co); + } + /* clear the flag when not divided */ + else vlr->flag &= ~R_DIVIDE_24; + } + } +} + +static void check_non_flat_quads(ObjectRen *obr) +{ + VlakRen *vlr, *vlr1; + VertRen *v1, *v2, *v3, *v4; + float nor[3], xn, flen; + int a; + + for (a=obr->totvlak-1; a>=0; a--) { + vlr= RE_findOrAddVlak(obr, a); + + /* test if rendering as a quad or triangle, skip wire */ + if (vlr->v4 && (vlr->flag & R_STRAND)==0 && (vlr->mat->material_type != MA_TYPE_WIRE)) { + + /* check if quad is actually triangle */ + v1= vlr->v1; + v2= vlr->v2; + v3= vlr->v3; + v4= vlr->v4; + sub_v3_v3v3(nor, v1->co, v2->co); + if ( ABS(nor[0])<FLT_EPSILON10 && ABS(nor[1])<FLT_EPSILON10 && ABS(nor[2])<FLT_EPSILON10 ) { + vlr->v1= v2; + vlr->v2= v3; + vlr->v3= v4; + vlr->v4= NULL; + vlr->flag |= (R_DIVIDE_24 | R_FACE_SPLIT); + } + else { + sub_v3_v3v3(nor, v2->co, v3->co); + if ( ABS(nor[0])<FLT_EPSILON10 && ABS(nor[1])<FLT_EPSILON10 && ABS(nor[2])<FLT_EPSILON10 ) { + vlr->v2= v3; + vlr->v3= v4; + vlr->v4= NULL; + vlr->flag |= R_FACE_SPLIT; + } + else { + sub_v3_v3v3(nor, v3->co, v4->co); + if ( ABS(nor[0])<FLT_EPSILON10 && ABS(nor[1])<FLT_EPSILON10 && ABS(nor[2])<FLT_EPSILON10 ) { + vlr->v4= NULL; + } + else { + sub_v3_v3v3(nor, v4->co, v1->co); + if ( ABS(nor[0])<FLT_EPSILON10 && ABS(nor[1])<FLT_EPSILON10 && ABS(nor[2])<FLT_EPSILON10 ) { + vlr->v4= NULL; + } + } + } + } + + if (vlr->v4) { + + /* Face is divided along edge with the least gradient */ + /* Flagged with R_DIVIDE_24 if divide is from vert 2 to 4 */ + /* 4---3 4---3 */ + /* |\ 1| or |1 /| */ + /* |0\ | |/ 0| */ + /* 1---2 1---2 0 = orig face, 1 = new face */ + + /* render normals are inverted in render! we calculate normal of single tria here */ + flen= normal_tri_v3(nor, vlr->v4->co, vlr->v3->co, vlr->v1->co); + if (flen==0.0f) normal_tri_v3(nor, vlr->v4->co, vlr->v2->co, vlr->v1->co); + + xn = dot_v3v3(nor, vlr->n); + + if (ABS(xn) < 0.999995f ) { /* checked on noisy fractal grid */ + + float d1, d2; + + vlr1= RE_vlakren_copy(obr, vlr); + vlr1->flag |= R_FACE_SPLIT; + + /* split direction based on vnorms */ + normal_tri_v3(nor, vlr->v1->co, vlr->v2->co, vlr->v3->co); + d1 = dot_v3v3(nor, vlr->v1->n); + + normal_tri_v3(nor, vlr->v2->co, vlr->v3->co, vlr->v4->co); + d2 = dot_v3v3(nor, vlr->v2->n); + + if (fabsf(d1) < fabsf(d2) ) vlr->flag |= R_DIVIDE_24; + else vlr->flag &= ~R_DIVIDE_24; + + /* new vertex pointers */ + if (vlr->flag & R_DIVIDE_24) { + vlr1->v1= vlr->v2; + vlr1->v2= vlr->v3; + vlr1->v3= vlr->v4; + + vlr->v3 = vlr->v4; + + vlr1->flag |= R_DIVIDE_24; + } + else { + vlr1->v1= vlr->v1; + vlr1->v2= vlr->v3; + vlr1->v3= vlr->v4; + + vlr1->flag &= ~R_DIVIDE_24; + } + vlr->v4 = vlr1->v4 = NULL; + + /* new normals */ + normal_tri_v3(vlr->n, vlr->v3->co, vlr->v2->co, vlr->v1->co); + normal_tri_v3(vlr1->n, vlr1->v3->co, vlr1->v2->co, vlr1->v1->co); + +#ifdef WITH_FREESTYLE + /* Freestyle edge marks */ + if (vlr->flag & R_DIVIDE_24) { + vlr1->freestyle_edge_mark= + ((vlr->freestyle_edge_mark & R_EDGE_V2V3) ? R_EDGE_V1V2 : 0) | + ((vlr->freestyle_edge_mark & R_EDGE_V3V4) ? R_EDGE_V2V3 : 0); + vlr->freestyle_edge_mark= + ((vlr->freestyle_edge_mark & R_EDGE_V1V2) ? R_EDGE_V1V2 : 0) | + ((vlr->freestyle_edge_mark & R_EDGE_V4V1) ? R_EDGE_V3V1 : 0); + } + else { + vlr1->freestyle_edge_mark= + ((vlr->freestyle_edge_mark & R_EDGE_V3V4) ? R_EDGE_V2V3 : 0) | + ((vlr->freestyle_edge_mark & R_EDGE_V4V1) ? R_EDGE_V3V1 : 0); + vlr->freestyle_edge_mark= + ((vlr->freestyle_edge_mark & R_EDGE_V1V2) ? R_EDGE_V1V2 : 0) | + ((vlr->freestyle_edge_mark & R_EDGE_V2V3) ? R_EDGE_V2V3 : 0); + } +#endif + } + /* clear the flag when not divided */ + else vlr->flag &= ~R_DIVIDE_24; + } + } + } +} + +static void finalize_render_object(Render *re, ObjectRen *obr, int timeoffset) +{ + Object *ob= obr->ob; + VertRen *ver= NULL; + StrandRen *strand= NULL; + StrandBound *sbound= NULL; + float min[3], max[3], smin[3], smax[3]; + int a, b; + + if (obr->totvert || obr->totvlak || obr->tothalo || obr->totstrand) { + /* the exception below is because displace code now is in init_render_mesh call, + * I will look at means to have autosmooth enabled for all object types + * and have it as general postprocess, like displace */ + if (ob->type!=OB_MESH && test_for_displace(re, ob)) + displace(re, obr); + + if (!timeoffset) { + /* phong normal interpolation can cause error in tracing + * (terminator problem) */ + ob->smoothresh= 0.0; + if ((re->r.mode & R_RAYTRACE) && (re->r.mode & R_SHADOW)) + set_phong_threshold(obr); + + if (re->flag & R_BAKING && re->r.bake_quad_split != 0) { + /* Baking lets us define a quad split order */ + split_quads(obr, re->r.bake_quad_split); + } + else if (BKE_object_is_animated(re->scene, ob)) + split_quads(obr, 1); + else { + if ((re->r.mode & R_SIMPLIFY && re->r.simplify_flag & R_SIMPLE_NO_TRIANGULATE) == 0) + check_non_flat_quads(obr); + } + + set_fullsample_trace_flag(re, obr); + + /* compute bounding boxes for clipping */ + INIT_MINMAX(min, max); + for (a=0; a<obr->totvert; a++) { + if ((a & 255)==0) ver= obr->vertnodes[a>>8].vert; + else ver++; + + minmax_v3v3_v3(min, max, ver->co); + } + + if (obr->strandbuf) { + float width; + + /* compute average bounding box of strandpoint itself (width) */ + if (obr->strandbuf->flag & R_STRAND_B_UNITS) + obr->strandbuf->maxwidth = max_ff(obr->strandbuf->ma->strand_sta, obr->strandbuf->ma->strand_end); + else + obr->strandbuf->maxwidth= 0.0f; + + width= obr->strandbuf->maxwidth; + sbound= obr->strandbuf->bound; + for (b=0; b<obr->strandbuf->totbound; b++, sbound++) { + + INIT_MINMAX(smin, smax); + + for (a=sbound->start; a<sbound->end; a++) { + strand= RE_findOrAddStrand(obr, a); + strand_minmax(strand, smin, smax, width); + } + + copy_v3_v3(sbound->boundbox[0], smin); + copy_v3_v3(sbound->boundbox[1], smax); + + minmax_v3v3_v3(min, max, smin); + minmax_v3v3_v3(min, max, smax); + } + } + + copy_v3_v3(obr->boundbox[0], min); + copy_v3_v3(obr->boundbox[1], max); + } + } +} + +/* ------------------------------------------------------------------------- */ +/* Database */ +/* ------------------------------------------------------------------------- */ + +static int render_object_type(short type) +{ + return OB_TYPE_SUPPORT_MATERIAL(type); +} + +static void find_dupli_instances(Render *re, ObjectRen *obr, DupliObject *dob) +{ + ObjectInstanceRen *obi; + float imat[4][4], obmat[4][4], obimat[4][4], nmat[3][3]; + int first = 1; + + mul_m4_m4m4(obmat, re->viewmat, obr->obmat); + invert_m4_m4(imat, obmat); + + /* for objects instanced by dupliverts/faces/particles, we go over the + * list of instances to find ones that instance obr, and setup their + * matrices and obr pointer */ + for (obi=re->instancetable.last; obi; obi=obi->prev) { + if (!obi->obr && obi->ob == obr->ob && obi->psysindex == obr->psysindex) { + obi->obr= obr; + + /* compute difference between object matrix and + * object matrix with dupli transform, in viewspace */ + copy_m4_m4(obimat, obi->mat); + mul_m4_m4m4(obi->mat, obimat, imat); + + copy_m3_m4(nmat, obi->mat); + invert_m3_m3(obi->nmat, nmat); + transpose_m3(obi->nmat); + + if (dob) { + copy_v3_v3(obi->dupliorco, dob->orco); + obi->dupliuv[0]= dob->uv[0]; + obi->dupliuv[1]= dob->uv[1]; + } + + if (!first) { + re->totvert += obr->totvert; + re->totvlak += obr->totvlak; + re->tothalo += obr->tothalo; + re->totstrand += obr->totstrand; + } + else + first= 0; + } + } +} + +static void assign_dupligroup_dupli(Render *re, ObjectInstanceRen *obi, ObjectRen *obr, DupliObject *dob) +{ + float imat[4][4], obmat[4][4], obimat[4][4], nmat[3][3]; + + mul_m4_m4m4(obmat, re->viewmat, obr->obmat); + invert_m4_m4(imat, obmat); + + obi->obr= obr; + + /* compute difference between object matrix and + * object matrix with dupli transform, in viewspace */ + copy_m4_m4(obimat, obi->mat); + mul_m4_m4m4(obi->mat, obimat, imat); + + copy_m3_m4(nmat, obi->mat); + invert_m3_m3(obi->nmat, nmat); + transpose_m3(obi->nmat); + + if (dob) { + copy_v3_v3(obi->dupliorco, dob->orco); + obi->dupliuv[0]= dob->uv[0]; + obi->dupliuv[1]= dob->uv[1]; + } + + re->totvert += obr->totvert; + re->totvlak += obr->totvlak; + re->tothalo += obr->tothalo; + re->totstrand += obr->totstrand; +} + +static ObjectRen *find_dupligroup_dupli(Render *re, Object *ob, int psysindex) +{ + ObjectRen *obr; + + /* if the object is itself instanced, we don't want to create an instance + * for it */ + if (ob->transflag & OB_RENDER_DUPLI) + return NULL; + + /* try to find an object that was already created so we can reuse it + * and save memory */ + for (obr=re->objecttable.first; obr; obr=obr->next) + if (obr->ob == ob && obr->psysindex == psysindex && (obr->flag & R_INSTANCEABLE)) + return obr; + + return NULL; +} + +static void set_dupli_tex_mat(Render *re, ObjectInstanceRen *obi, DupliObject *dob, float omat[4][4]) +{ + /* For duplis we need to have a matrix that transform the coordinate back + * to it's original position, without the dupli transforms. We also check + * the matrix is actually needed, to save memory on lots of dupliverts for + * example */ + static Object *lastob= NULL; + static int needtexmat= 0; + + /* init */ + if (!re) { + lastob= NULL; + needtexmat= 0; + return; + } + + /* check if we actually need it */ + if (lastob != dob->ob) { + Material ***material; + short a, *totmaterial; + + lastob= dob->ob; + needtexmat= 0; + + totmaterial= give_totcolp(dob->ob); + material= give_matarar(dob->ob); + + if (totmaterial && material) + for (a= 0; a<*totmaterial; a++) + if ((*material)[a] && (*material)[a]->texco & TEXCO_OBJECT) + needtexmat= 1; + } + + if (needtexmat) { + float imat[4][4]; + + obi->duplitexmat= BLI_memarena_alloc(re->memArena, sizeof(float)*4*4); + invert_m4_m4(imat, dob->mat); + mul_m4_series(obi->duplitexmat, re->viewmat, omat, imat, re->viewinv); + } + + copy_v3_v3(obi->dupliorco, dob->orco); + copy_v2_v2(obi->dupliuv, dob->uv); +} + +static void init_render_object_data(Render *re, ObjectRen *obr, int timeoffset) +{ + Object *ob= obr->ob; + ParticleSystem *psys; + int i; + + if (obr->psysindex) { + if ((!obr->prev || obr->prev->ob != ob || (obr->prev->flag & R_INSTANCEABLE)==0) && ob->type==OB_MESH) { + /* the emitter mesh wasn't rendered so the modifier stack wasn't + * evaluated with render settings */ + DerivedMesh *dm; + const CustomDataMask mask = CD_MASK_RENDER_INTERNAL; + + if (re->r.scemode & R_VIEWPORT_PREVIEW) + dm = mesh_create_derived_view(re->scene, ob, mask); + else + dm = mesh_create_derived_render(re->scene, ob, mask); + dm->release(dm); + } + + for (psys=ob->particlesystem.first, i=0; i<obr->psysindex-1; i++) + psys= psys->next; + + render_new_particle_system(re, obr, psys, timeoffset); + } + else { + if (ELEM(ob->type, OB_FONT, OB_CURVE)) + init_render_curve(re, obr, timeoffset); + else if (ob->type==OB_SURF) + init_render_surf(re, obr, timeoffset); + else if (ob->type==OB_MESH) + init_render_mesh(re, obr, timeoffset); + else if (ob->type==OB_MBALL) + init_render_mball(re, obr); + } + + finalize_render_object(re, obr, timeoffset); + + re->totvert += obr->totvert; + re->totvlak += obr->totvlak; + re->tothalo += obr->tothalo; + re->totstrand += obr->totstrand; +} + +static void add_render_object(Render *re, Object *ob, Object *par, DupliObject *dob, float omat[4][4], int timeoffset) +{ + ObjectRen *obr; + ObjectInstanceRen *obi; + ParticleSystem *psys; + int show_emitter, allow_render= 1, index, psysindex, i; + + index= (dob)? dob->persistent_id[0]: 0; + + /* It seems that we may generate psys->renderdata recursively in some nasty intricated cases of + * several levels of bupliobject (see T51524). + * For now, basic rule is, do not restore psys if it was already in 'render state'. + * Another, more robust solution could be to add some reference counting to that renderdata... */ + bool psys_has_renderdata = false; + + /* the emitter has to be processed first (render levels of modifiers) */ + /* so here we only check if the emitter should be rendered */ + if (ob->particlesystem.first) { + show_emitter= 0; + for (psys=ob->particlesystem.first; psys; psys=psys->next) { + show_emitter += psys->part->draw & PART_DRAW_EMITTER; + if (!(re->r.scemode & R_VIEWPORT_PREVIEW)) { + psys_has_renderdata |= (psys->renderdata != NULL); + psys_render_set(ob, psys, re->viewmat, re->winmat, re->winx, re->winy, timeoffset); + } + } + + /* if no psys has "show emitter" selected don't render emitter */ + if (show_emitter == 0) + allow_render= 0; + } + + /* one render object for the data itself */ + if (allow_render) { + obr= RE_addRenderObject(re, ob, par, index, 0, ob->lay); + if ((dob && !dob->animated) || (ob->transflag & OB_RENDER_DUPLI)) { + obr->flag |= R_INSTANCEABLE; + copy_m4_m4(obr->obmat, ob->obmat); + } + init_render_object_data(re, obr, timeoffset); + + /* only add instance for objects that have not been used for dupli */ + if (!(ob->transflag & OB_RENDER_DUPLI)) { + obi = RE_addRenderInstance(re, obr, ob, par, index, 0, NULL, ob->lay, dob); + if (dob) set_dupli_tex_mat(re, obi, dob, omat); + } + else + find_dupli_instances(re, obr, dob); + + for (i=1; i<=ob->totcol; i++) { + Material* ma = give_render_material(re, ob, i); + if (ma && ma->material_type == MA_TYPE_VOLUME) + add_volume(re, obr, ma); + } + } + + /* and one render object per particle system */ + if (ob->particlesystem.first) { + psysindex= 1; + for (psys=ob->particlesystem.first; psys; psys=psys->next, psysindex++) { + if (!psys_check_enabled(ob, psys, G.is_rendering)) + continue; + + obr= RE_addRenderObject(re, ob, par, index, psysindex, ob->lay); + if ((dob && !dob->animated) || (ob->transflag & OB_RENDER_DUPLI)) { + obr->flag |= R_INSTANCEABLE; + copy_m4_m4(obr->obmat, ob->obmat); + } + if (dob) + psys->flag |= PSYS_USE_IMAT; + init_render_object_data(re, obr, timeoffset); + if (!(re->r.scemode & R_VIEWPORT_PREVIEW) && !psys_has_renderdata) { + psys_render_restore(ob, psys); + } + psys->flag &= ~PSYS_USE_IMAT; + + /* only add instance for objects that have not been used for dupli */ + if (!(ob->transflag & OB_RENDER_DUPLI)) { + obi = RE_addRenderInstance(re, obr, ob, par, index, psysindex, NULL, ob->lay, dob); + if (dob) set_dupli_tex_mat(re, obi, dob, omat); + } + else + find_dupli_instances(re, obr, dob); + } + } +} + +/* par = pointer to duplicator parent, needed for object lookup table */ +/* index = when duplicater copies same object (particle), the counter */ +static void init_render_object(Render *re, Object *ob, Object *par, DupliObject *dob, float omat[4][4], int timeoffset) +{ + static double lasttime= 0.0; + double time; + float mat[4][4]; + + if (ob->type==OB_LAMP) + add_render_lamp(re, ob); + else if (render_object_type(ob->type)) + add_render_object(re, ob, par, dob, omat, timeoffset); + else { + mul_m4_m4m4(mat, re->viewmat, ob->obmat); + invert_m4_m4(ob->imat, mat); + } + + time= PIL_check_seconds_timer(); + if (time - lasttime > 1.0) { + lasttime= time; + /* clumsy copying still */ + re->i.totvert= re->totvert; + re->i.totface= re->totvlak; + re->i.totstrand= re->totstrand; + re->i.tothalo= re->tothalo; + re->i.totlamp= re->totlamp; + re->stats_draw(re->sdh, &re->i); + } + + ob->flag |= OB_DONE; +} + +void RE_Database_Free(Render *re) +{ + LampRen *lar; + + /* will crash if we try to free empty database */ + if (!re->i.convertdone) + return; + + /* statistics for debugging render memory usage */ + if ((G.debug & G_DEBUG) && (G.is_rendering)) { + if ((re->r.scemode & (R_BUTS_PREVIEW|R_VIEWPORT_PREVIEW))==0) { + BKE_image_print_memlist(); + MEM_printmemlist_stats(); + } + } + + /* FREE */ + + for (lar= re->lampren.first; lar; lar= lar->next) { + freeshadowbuf(lar); + if (lar->jitter) MEM_freeN(lar->jitter); + if (lar->shadsamp) MEM_freeN(lar->shadsamp); + if (lar->sunsky) MEM_freeN(lar->sunsky); + curvemapping_free(lar->curfalloff); + } + + free_volume_precache(re); + + BLI_freelistN(&re->lampren); + BLI_freelistN(&re->lights); + + free_renderdata_tables(re); + + /* free orco */ + free_mesh_orco_hash(re); + + if (re->main) { + end_render_materials(re->main); + end_render_textures(re); + free_pointdensities(re); + } + + free_camera_inside_volumes(re); + + if (re->wrld.aosphere) { + MEM_freeN(re->wrld.aosphere); + re->wrld.aosphere= NULL; + if (re->scene && re->scene->world) + re->scene->world->aosphere= NULL; + } + if (re->wrld.aotables) { + MEM_freeN(re->wrld.aotables); + re->wrld.aotables= NULL; + if (re->scene && re->scene->world) + re->scene->world->aotables= NULL; + } + if (re->r.mode & R_RAYTRACE) + free_render_qmcsampler(re); + + if (re->r.mode & R_RAYTRACE) freeraytree(re); + + free_sss(re); + free_occ(re); + free_strand_surface(re); + + re->totvlak=re->totvert=re->totstrand=re->totlamp=re->tothalo= 0; + re->i.convertdone = false; + + re->bakebuf= NULL; + + if (re->scene) + if (re->scene->r.scemode & R_FREE_IMAGE) + if ((re->r.scemode & (R_BUTS_PREVIEW|R_VIEWPORT_PREVIEW))==0) + BKE_image_free_all_textures(); + + if (re->memArena) { + BLI_memarena_free(re->memArena); + re->memArena = NULL; + } +} + +static int allow_render_object(Render *re, Object *ob, int nolamps, int onlyselected, Object *actob) +{ + if (is_object_hidden(re, ob)) + return 0; + + /* Only handle dupli-hiding here if there is no particle systems. Else, let those handle show/noshow. */ + if (!ob->particlesystem.first) { + if ((ob->transflag & OB_DUPLI) && !(ob->transflag & OB_DUPLIFRAMES)) { + return 0; + } + } + + /* don't add non-basic meta objects, ends up having renderobjects with no geometry */ + if (ob->type == OB_MBALL && ob!=BKE_mball_basis_find(re->eval_ctx, re->scene, ob)) + return 0; + + if (nolamps && (ob->type==OB_LAMP)) + return 0; + + if (onlyselected && (ob!=actob && !(ob->flag & SELECT))) + return 0; + + return 1; +} + +static int allow_render_dupli_instance(Render *UNUSED(re), DupliObject *dob, Object *obd) +{ + ParticleSystem *psys; + Material *ma; + short a, *totmaterial; + + /* don't allow objects with halos. we need to have + * all halo's to sort them globally in advance */ + totmaterial= give_totcolp(obd); + + if (totmaterial) { + for (a= 0; a<*totmaterial; a++) { + ma= give_current_material(obd, a + 1); + if (ma && (ma->material_type == MA_TYPE_HALO)) + return 0; + } + } + + for (psys=obd->particlesystem.first; psys; psys=psys->next) + if (!ELEM(psys->part->ren_as, PART_DRAW_BB, PART_DRAW_LINE, PART_DRAW_PATH, PART_DRAW_OB, PART_DRAW_GR)) + return 0; + + /* don't allow lamp, animated duplis, or radio render */ + return (render_object_type(obd->type) && + (!(dob->type == OB_DUPLIGROUP) || !dob->animated)); +} + +static void dupli_render_particle_set(Render *re, Object *ob, int timeoffset, int level, int enable) +{ + /* ugly function, but we need to set particle systems to their render + * settings before calling object_duplilist, to get render level duplis */ + Group *group; + GroupObject *go; + ParticleSystem *psys; + DerivedMesh *dm; + + if (re->r.scemode & R_VIEWPORT_PREVIEW) + return; + + if (level >= MAX_DUPLI_RECUR) + return; + + if (ob->transflag & OB_DUPLIPARTS) { + for (psys=ob->particlesystem.first; psys; psys=psys->next) { + if (ELEM(psys->part->ren_as, PART_DRAW_OB, PART_DRAW_GR)) { + if (enable) + psys_render_set(ob, psys, re->viewmat, re->winmat, re->winx, re->winy, timeoffset); + else + psys_render_restore(ob, psys); + } + } + + if (enable) { + /* this is to make sure we get render level duplis in groups: + * the derivedmesh must be created before init_render_mesh, + * since object_duplilist does dupliparticles before that */ + dm = mesh_create_derived_render(re->scene, ob, CD_MASK_RENDER_INTERNAL); + dm->release(dm); + + for (psys=ob->particlesystem.first; psys; psys=psys->next) + psys_get_modifier(ob, psys)->flag &= ~eParticleSystemFlag_psys_updated; + } + } + + if (ob->dup_group==NULL) return; + group= ob->dup_group; + + for (go= group->gobject.first; go; go= go->next) + dupli_render_particle_set(re, go->ob, timeoffset, level+1, enable); +} + +static int get_vector_renderlayers(Scene *sce) +{ + SceneRenderLayer *srl; + unsigned int lay= 0; + + for (srl= sce->r.layers.first; srl; srl= srl->next) + if (srl->passflag & SCE_PASS_VECTOR) + lay |= srl->lay; + + return lay; +} + +static void add_group_render_dupli_obs(Render *re, Group *group, int nolamps, int onlyselected, Object *actob, int timeoffset, int level) +{ + GroupObject *go; + Object *ob; + + /* simple preventing of too deep nested groups */ + if (level>MAX_DUPLI_RECUR) return; + + /* recursively go into dupligroups to find objects with OB_RENDER_DUPLI + * that were not created yet */ + for (go= group->gobject.first; go; go= go->next) { + ob= go->ob; + + if (ob->flag & OB_DONE) { + if (ob->transflag & OB_RENDER_DUPLI) { + if (allow_render_object(re, ob, nolamps, onlyselected, actob)) { + init_render_object(re, ob, NULL, NULL, NULL, timeoffset); + ob->transflag &= ~OB_RENDER_DUPLI; + + if (ob->dup_group) + add_group_render_dupli_obs(re, ob->dup_group, nolamps, onlyselected, actob, timeoffset, level+1); + } + } + } + } +} + +static void database_init_objects(Render *re, unsigned int renderlay, int nolamps, int onlyselected, Object *actob, int timeoffset) +{ + Base *base; + Object *ob; + Group *group; + ObjectInstanceRen *obi; + Scene *sce_iter; + int lay, vectorlay; + + /* for duplis we need the Object texture mapping to work as if + * untransformed, set_dupli_tex_mat sets the matrix to allow that + * NULL is just for init */ + set_dupli_tex_mat(NULL, NULL, NULL, NULL); + + /* loop over all objects rather then using SETLOOPER because we may + * reference an mtex-mapped object which isn't rendered or is an + * empty in a dupli group. We could scan all render material/lamp/world + * mtex's for mapto objects but its easier just to set the + * 'imat' / 'imat_ren' on all and unlikely to be a performance hit + * See bug: [#28744] - campbell */ + for (ob= re->main->object.first; ob; ob= ob->id.next) { + float mat[4][4]; + + /* imat objects has to be done here, since displace can have texture using Object map-input */ + mul_m4_m4m4(mat, re->viewmat, ob->obmat); + invert_m4_m4(ob->imat_ren, mat); + copy_m4_m4(ob->imat, ob->imat_ren); + /* each object should only be rendered once */ + ob->flag &= ~OB_DONE; + ob->transflag &= ~OB_RENDER_DUPLI; + } + + for (SETLOOPER(re->scene, sce_iter, base)) { + ob= base->object; + + /* in the prev/next pass for making speed vectors, avoid creating + * objects that are not on a renderlayer with a vector pass, can + * save a lot of time in complex scenes */ + vectorlay= get_vector_renderlayers(re->scene); + lay= (timeoffset)? renderlay & vectorlay: renderlay; + + /* if the object has been restricted from rendering in the outliner, ignore it */ + if (is_object_restricted(re, ob)) continue; + + /* OB_DONE means the object itself got duplicated, so was already converted */ + if (ob->flag & OB_DONE) { + /* OB_RENDER_DUPLI means instances for it were already created, now + * it still needs to create the ObjectRen containing the data */ + if (ob->transflag & OB_RENDER_DUPLI) { + if (allow_render_object(re, ob, nolamps, onlyselected, actob)) { + init_render_object(re, ob, NULL, NULL, NULL, timeoffset); + ob->transflag &= ~OB_RENDER_DUPLI; + } + } + } + else if ((base->lay & lay) || (ob->type==OB_LAMP && (base->lay & re->lay)) ) { + if ((ob->transflag & OB_DUPLI) && (ob->type!=OB_MBALL)) { + DupliObject *dob; + ListBase *duplilist; + DupliApplyData *duplilist_apply_data = NULL; + int i; + + /* create list of duplis generated by this object, particle + * system need to have render settings set for dupli particles */ + dupli_render_particle_set(re, ob, timeoffset, 0, 1); + duplilist = object_duplilist(re->eval_ctx, re->scene, ob); + duplilist_apply_data = duplilist_apply(ob, NULL, duplilist); + /* postpone 'dupli_render_particle_set', since RE_addRenderInstance reads + * index values from 'dob->persistent_id[0]', referencing 'psys->child' which + * may be smaller once the particle system is restored, see: T45563. */ + + for (dob= duplilist->first, i = 0; dob; dob= dob->next, ++i) { + DupliExtraData *dob_extra = &duplilist_apply_data->extra[i]; + Object *obd= dob->ob; + + copy_m4_m4(obd->obmat, dob->mat); + + /* group duplis need to set ob matrices correct, for deform. so no_draw is part handled */ + if (!(obd->transflag & OB_RENDER_DUPLI) && dob->no_draw) + continue; + + if (is_object_hidden(re, obd)) + continue; + + if (obd->type==OB_MBALL) + continue; + + if (!allow_render_object(re, obd, nolamps, onlyselected, actob)) + continue; + + if (allow_render_dupli_instance(re, dob, obd)) { + ParticleSystem *psys; + ObjectRen *obr = NULL; + int psysindex; + float mat[4][4]; + + obi=NULL; + + /* instances instead of the actual object are added in two cases, either + * this is a duplivert/face/particle, or it is a non-animated object in + * a dupligroup that has already been created before */ + if (dob->type != OB_DUPLIGROUP || (obr=find_dupligroup_dupli(re, obd, 0))) { + mul_m4_m4m4(mat, re->viewmat, dob->mat); + /* ob = particle system, use that layer */ + obi = RE_addRenderInstance(re, NULL, obd, ob, dob->persistent_id[0], 0, mat, ob->lay, dob); + + /* fill in instance variables for texturing */ + set_dupli_tex_mat(re, obi, dob, dob_extra->obmat); + if (dob->type != OB_DUPLIGROUP) { + copy_v3_v3(obi->dupliorco, dob->orco); + obi->dupliuv[0]= dob->uv[0]; + obi->dupliuv[1]= dob->uv[1]; + } + else { + /* for the second case, setup instance to point to the already + * created object, and possibly setup instances if this object + * itself was duplicated. for the first case find_dupli_instances + * will be called later. */ + assign_dupligroup_dupli(re, obi, obr, dob); + if (obd->transflag & OB_RENDER_DUPLI) + find_dupli_instances(re, obr, dob); + } + } + + /* same logic for particles, each particle system has it's own object, so + * need to go over them separately */ + psysindex= 1; + for (psys=obd->particlesystem.first; psys; psys=psys->next) { + if (dob->type != OB_DUPLIGROUP || (obr=find_dupligroup_dupli(re, obd, psysindex))) { + if (obi == NULL) + mul_m4_m4m4(mat, re->viewmat, dob->mat); + obi = RE_addRenderInstance(re, NULL, obd, ob, dob->persistent_id[0], psysindex++, mat, obd->lay, dob); + + set_dupli_tex_mat(re, obi, dob, dob_extra->obmat); + if (dob->type != OB_DUPLIGROUP) { + copy_v3_v3(obi->dupliorco, dob->orco); + obi->dupliuv[0]= dob->uv[0]; + obi->dupliuv[1]= dob->uv[1]; + } + else { + assign_dupligroup_dupli(re, obi, obr, dob); + if (obd->transflag & OB_RENDER_DUPLI) + find_dupli_instances(re, obr, dob); + } + } + } + + if (obi==NULL) + /* can't instance, just create the object */ + init_render_object(re, obd, ob, dob, dob_extra->obmat, timeoffset); + + if (dob->type != OB_DUPLIGROUP) { + obd->flag |= OB_DONE; + obd->transflag |= OB_RENDER_DUPLI; + } + } + else + init_render_object(re, obd, ob, dob, dob_extra->obmat, timeoffset); + + if (re->test_break(re->tbh)) break; + } + + /* restore particle system */ + dupli_render_particle_set(re, ob, timeoffset, 0, false); + + if (duplilist_apply_data) { + duplilist_restore(duplilist, duplilist_apply_data); + duplilist_free_apply_data(duplilist_apply_data); + } + free_object_duplilist(duplilist); + + if (allow_render_object(re, ob, nolamps, onlyselected, actob)) + init_render_object(re, ob, NULL, NULL, NULL, timeoffset); + } + else if (allow_render_object(re, ob, nolamps, onlyselected, actob)) + init_render_object(re, ob, NULL, NULL, NULL, timeoffset); + } + + if (re->test_break(re->tbh)) break; + } + + /* objects in groups with OB_RENDER_DUPLI set still need to be created, + * since they may not be part of the scene */ + for (group= re->main->group.first; group; group=group->id.next) + add_group_render_dupli_obs(re, group, nolamps, onlyselected, actob, timeoffset, 0); + + if (!re->test_break(re->tbh)) + RE_makeRenderInstances(re); +} + +/* used to be 'rotate scene' */ +void RE_Database_FromScene(Render *re, Main *bmain, Scene *scene, unsigned int lay, int use_camera_view) +{ + Scene *sce; + Object *camera; + float mat[4][4]; + float amb[3]; + + re->main= bmain; + re->scene= scene; + re->lay= lay; + + if (re->r.scemode & R_VIEWPORT_PREVIEW) + re->scene_color_manage = BKE_scene_check_color_management_enabled(scene); + + /* scene needs to be set to get camera */ + camera= RE_GetCamera(re); + + /* per second, per object, stats print this */ + re->i.infostr= "Preparing Scene data"; + re->i.cfra= scene->r.cfra; + BLI_strncpy(re->i.scene_name, scene->id.name + 2, sizeof(re->i.scene_name)); + + /* XXX add test if dbase was filled already? */ + + re->memArena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "render db arena"); + re->totvlak=re->totvert=re->totstrand=re->totlamp=re->tothalo= 0; + re->lights.first= re->lights.last= NULL; + re->lampren.first= re->lampren.last= NULL; + + re->i.partsdone = false; /* signal now in use for previewrender */ + + /* in localview, lamps are using normal layers, objects only local bits */ + if (re->lay & 0xFF000000) + lay &= 0xFF000000; + + /* applies changes fully */ + if ((re->r.scemode & (R_NO_FRAME_UPDATE|R_BUTS_PREVIEW|R_VIEWPORT_PREVIEW))==0) { + BKE_scene_update_for_newframe(re->eval_ctx, re->main, re->scene, lay); + render_update_anim_renderdata(re, &re->scene->r); + } + + /* if no camera, viewmat should have been set! */ + if (use_camera_view && camera) { + /* called before but need to call again in case of lens animation from the + * above call to BKE_scene_update_for_newframe, fixes bug. [#22702]. + * following calls don't depend on 'RE_SetCamera' */ + RE_SetCamera(re, camera); + RE_GetCameraModelMatrix(re, camera, mat); + invert_m4(mat); + RE_SetView(re, mat); + + /* force correct matrix for scaled cameras */ + DAG_id_tag_update_ex(re->main, &camera->id, OB_RECALC_OB); + } + + /* store for incremental render, viewmat rotates dbase */ + copy_m4_m4(re->viewmat_orig, re->viewmat); + + init_render_world(re); /* do first, because of ambient. also requires re->osa set correct */ + if (re->r.mode & R_RAYTRACE) { + init_render_qmcsampler(re); + + if (re->wrld.mode & (WO_AMB_OCC|WO_ENV_LIGHT|WO_INDIRECT_LIGHT)) + if (re->wrld.ao_samp_method == WO_AOSAMP_CONSTANT) + init_ao_sphere(re, &re->wrld); + } + + /* still bad... doing all */ + init_render_textures(re); + copy_v3_v3(amb, &re->wrld.ambr); + init_render_materials(re->main, re->r.mode, amb, (re->r.scemode & R_BUTS_PREVIEW) == 0); + set_node_shader_lamp_loop(shade_material_loop); + + /* MAKE RENDER DATA */ + database_init_objects(re, lay, 0, 0, NULL, 0); + + if (!re->test_break(re->tbh)) { + set_material_lightgroups(re); + for (sce= re->scene; sce; sce= sce->set) + set_renderlayer_lightgroups(re, sce); + + /* for now some clumsy copying still */ + re->i.totvert= re->totvert; + re->i.totface= re->totvlak; + re->i.totstrand= re->totstrand; + re->i.tothalo= re->tothalo; + re->i.totlamp= re->totlamp; + re->stats_draw(re->sdh, &re->i); + } +} + +void RE_Database_Preprocess(Render *re) +{ + if (!re->test_break(re->tbh)) { + int tothalo; + + tothalo= re->tothalo; + sort_halos(re, tothalo); + + init_camera_inside_volumes(re); + + re->i.infostr = IFACE_("Creating Shadowbuffers"); + re->stats_draw(re->sdh, &re->i); + + /* SHADOW BUFFER */ + threaded_makeshadowbufs(re); + + /* old code checked for internal render (aka not yafray) */ + { + /* raytree */ + if (!re->test_break(re->tbh)) { + if (re->r.mode & R_RAYTRACE) { + makeraytree(re); + } + } + /* ENVIRONMENT MAPS */ + if (!re->test_break(re->tbh)) + make_envmaps(re); + + /* point density texture */ + if (!re->test_break(re->tbh)) + make_pointdensities(re); + /* voxel data texture */ + if (!re->test_break(re->tbh)) + make_voxeldata(re); + } + + if (!re->test_break(re->tbh)) + project_renderdata(re, projectverto, (re->r.mode & R_PANORAMA) != 0, 0, 1); + + /* Occlusion */ + if ((re->wrld.mode & (WO_AMB_OCC|WO_ENV_LIGHT|WO_INDIRECT_LIGHT)) && !re->test_break(re->tbh)) + if (re->wrld.ao_gather_method == WO_AOGATHER_APPROX) + if (re->r.mode & R_SHADOW) + make_occ_tree(re); + + /* SSS */ + if ((re->r.mode & R_SSS) && !re->test_break(re->tbh)) + make_sss_tree(re); + + if (!re->test_break(re->tbh)) + if (re->r.mode & R_RAYTRACE) + volume_precache(re); + } + + re->i.convertdone = true; + + if (re->test_break(re->tbh)) + RE_Database_Free(re); + + re->i.infostr = NULL; + re->stats_draw(re->sdh, &re->i); +} + +/* exported call to recalculate hoco for vertices, when winmat changed */ +void RE_DataBase_ApplyWindow(Render *re) +{ + project_renderdata(re, projectverto, 0, 0, 0); +} + +/* exported call to rotate render data again, when viewmat changed */ +void RE_DataBase_IncrementalView(Render *re, float viewmat[4][4], int restore) +{ + float oldviewinv[4][4], tmat[4][4]; + + invert_m4_m4(oldviewinv, re->viewmat_orig); + + /* we have to correct for the already rotated vertexcoords */ + mul_m4_m4m4(tmat, viewmat, oldviewinv); + + copy_m4_m4(re->viewmat, viewmat); + invert_m4_m4(re->viewinv, re->viewmat); + + init_camera_inside_volumes(re); + + env_rotate_scene(re, tmat, !restore); + + /* SSS points distribution depends on view */ + if ((re->r.mode & R_SSS) && !re->test_break(re->tbh)) + make_sss_tree(re); +} + + +void RE_DataBase_GetView(Render *re, float mat[4][4]) +{ + copy_m4_m4(mat, re->viewmat); +} + +/* ------------------------------------------------------------------------- */ +/* Speed Vectors */ +/* ------------------------------------------------------------------------- */ + +static void database_fromscene_vectors(Render *re, Scene *scene, unsigned int lay, int timeoffset) +{ + Object *camera= RE_GetCamera(re); + float mat[4][4]; + + re->scene= scene; + re->lay= lay; + + /* XXX add test if dbase was filled already? */ + + re->memArena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "vector render db arena"); + re->totvlak=re->totvert=re->totstrand=re->totlamp=re->tothalo= 0; + re->i.totface=re->i.totvert=re->i.totstrand=re->i.totlamp=re->i.tothalo= 0; + re->lights.first= re->lights.last= NULL; + + /* in localview, lamps are using normal layers, objects only local bits */ + if (re->lay & 0xFF000000) + lay &= 0xFF000000; + + /* applies changes fully */ + scene->r.cfra += timeoffset; + BKE_scene_update_for_newframe(re->eval_ctx, re->main, re->scene, lay); + + /* if no camera, viewmat should have been set! */ + if (camera) { + RE_GetCameraModelMatrix(re, camera, mat); + normalize_m4(mat); + invert_m4(mat); + RE_SetView(re, mat); + } + + /* MAKE RENDER DATA */ + database_init_objects(re, lay, 0, 0, NULL, timeoffset); + + if (!re->test_break(re->tbh)) + project_renderdata(re, projectverto, (re->r.mode & R_PANORAMA) != 0, 0, 1); + + /* do this in end, particles for example need cfra */ + scene->r.cfra -= timeoffset; +} + +/* choose to use static, to prevent giving too many args to this call */ +static void speedvector_project(Render *re, float zco[2], const float co[3], const float ho[4]) +{ + static float pixelphix=0.0f, pixelphiy=0.0f, zmulx=0.0f, zmuly=0.0f; + static int pano= 0; + float div; + + /* initialize */ + if (re) { + pano= re->r.mode & R_PANORAMA; + + /* precalculate amount of radians 1 pixel rotates */ + if (pano) { + /* size of 1 pixel mapped to viewplane coords */ + float psize; + + psize = BLI_rctf_size_x(&re->viewplane) / (float)re->winx; + /* x angle of a pixel */ + pixelphix = atan(psize / re->clipsta); + + psize = BLI_rctf_size_y(&re->viewplane) / (float)re->winy; + /* y angle of a pixel */ + pixelphiy = atan(psize / re->clipsta); + } + zmulx= re->winx/2; + zmuly= re->winy/2; + + return; + } + + /* now map hocos to screenspace, uses very primitive clip still */ + if (ho[3]<0.1f) div= 10.0f; + else div= 1.0f/ho[3]; + + /* use cylinder projection */ + if (pano) { + float vec[3], ang; + /* angle between (0, 0, -1) and (co) */ + copy_v3_v3(vec, co); + + ang= saacos(-vec[2]/sqrtf(vec[0]*vec[0] + vec[2]*vec[2])); + if (vec[0]<0.0f) ang= -ang; + zco[0]= ang/pixelphix + zmulx; + + ang= 0.5f*(float)M_PI - saacos(vec[1] / len_v3(vec)); + zco[1]= ang/pixelphiy + zmuly; + + } + else { + zco[0]= zmulx*(1.0f+ho[0]*div); + zco[1]= zmuly*(1.0f+ho[1]*div); + } +} + +static void calculate_speedvector(const float vectors[2], int step, float winsq, float winroot, const float co[3], const float ho[4], float speed[4]) +{ + float zco[2], len; + + speedvector_project(NULL, zco, co, ho); + + zco[0]= vectors[0] - zco[0]; + zco[1]= vectors[1] - zco[1]; + + /* enable nice masks for hardly moving stuff or float inaccuracy */ + if (zco[0]<0.1f && zco[0]>-0.1f && zco[1]<0.1f && zco[1]>-0.1f ) { + zco[0]= 0.0f; + zco[1]= 0.0f; + } + + /* maximize speed for image width, otherwise it never looks good */ + len= zco[0]*zco[0] + zco[1]*zco[1]; + if (len > winsq) { + len= winroot/sqrtf(len); + zco[0]*= len; + zco[1]*= len; + } + + /* note; in main vecblur loop speedvec is negated again */ + if (step) { + speed[2]= -zco[0]; + speed[3]= -zco[1]; + } + else { + speed[0]= zco[0]; + speed[1]= zco[1]; + } +} + +static float *calculate_strandsurface_speedvectors(Render *re, ObjectInstanceRen *obi, StrandSurface *mesh) +{ + if (mesh->co && mesh->prevco && mesh->nextco) { + float winsq= (float)re->winx*(float)re->winy; /* int's can wrap on large images */ + float winroot= sqrtf(winsq); + float (*winspeed)[4]; + float ho[4], prevho[4], nextho[4], winmat[4][4], vec[2]; + int a; + + if (obi->flag & R_TRANSFORMED) + mul_m4_m4m4(winmat, re->winmat, obi->mat); + else + copy_m4_m4(winmat, re->winmat); + + winspeed= MEM_callocN(sizeof(float)*4*mesh->totvert, "StrandSurfWin"); + + for (a=0; a<mesh->totvert; a++) { + projectvert(mesh->co[a], winmat, ho); + + projectvert(mesh->prevco[a], winmat, prevho); + speedvector_project(NULL, vec, mesh->prevco[a], prevho); + calculate_speedvector(vec, 0, winsq, winroot, mesh->co[a], ho, winspeed[a]); + + projectvert(mesh->nextco[a], winmat, nextho); + speedvector_project(NULL, vec, mesh->nextco[a], nextho); + calculate_speedvector(vec, 1, winsq, winroot, mesh->co[a], ho, winspeed[a]); + } + + return (float *)winspeed; + } + + return NULL; +} + +static void calculate_speedvectors(Render *re, ObjectInstanceRen *obi, float *vectors, int step) +{ + ObjectRen *obr= obi->obr; + VertRen *ver= NULL; + StrandRen *strand= NULL; + StrandBuffer *strandbuf; + StrandSurface *mesh= NULL; + float *speed, (*winspeed)[4]=NULL, ho[4], winmat[4][4]; + float *co1, *co2, *co3, *co4, w[4]; + float winsq = (float)re->winx * (float)re->winy, winroot = sqrtf(winsq); /* int's can wrap on large images */ + int a, *face, *index; + + if (obi->flag & R_TRANSFORMED) + mul_m4_m4m4(winmat, re->winmat, obi->mat); + else + copy_m4_m4(winmat, re->winmat); + + if (obr->vertnodes) { + for (a=0; a<obr->totvert; a++, vectors+=2) { + if ((a & 255)==0) ver= obr->vertnodes[a>>8].vert; + else ver++; + + speed= RE_vertren_get_winspeed(obi, ver, 1); + projectvert(ver->co, winmat, ho); + calculate_speedvector(vectors, step, winsq, winroot, ver->co, ho, speed); + } + } + + if (obr->strandnodes) { + strandbuf= obr->strandbuf; + mesh= (strandbuf)? strandbuf->surface: NULL; + + /* compute speed vectors at surface vertices */ + if (mesh) + winspeed= (float(*)[4])calculate_strandsurface_speedvectors(re, obi, mesh); + + if (winspeed) { + for (a=0; a<obr->totstrand; a++, vectors+=2) { + if ((a & 255)==0) strand= obr->strandnodes[a>>8].strand; + else strand++; + + index= RE_strandren_get_face(obr, strand, 0); + if (index && *index < mesh->totface) { + speed= RE_strandren_get_winspeed(obi, strand, 1); + + /* interpolate speed vectors from strand surface */ + face= mesh->face[*index]; + + co1 = mesh->co[face[0]]; + co2 = mesh->co[face[1]]; + co3 = mesh->co[face[2]]; + + if (face[3]) { + co4 = mesh->co[face[3]]; + interp_weights_quad_v3(w, co1, co2, co3, co4, strand->vert->co); + } + else { + interp_weights_tri_v3(w, co1, co2, co3, strand->vert->co); + } + + zero_v4(speed); + madd_v4_v4fl(speed, winspeed[face[0]], w[0]); + madd_v4_v4fl(speed, winspeed[face[1]], w[1]); + madd_v4_v4fl(speed, winspeed[face[2]], w[2]); + if (face[3]) + madd_v4_v4fl(speed, winspeed[face[3]], w[3]); + } + } + + MEM_freeN(winspeed); + } + } +} + +static int load_fluidsimspeedvectors(Render *re, ObjectInstanceRen *obi, float *vectors, int step) +{ + ObjectRen *obr= obi->obr; + Object *fsob= obr->ob; + VertRen *ver= NULL; + float *speed, div, zco[2], avgvel[4] = {0.0, 0.0, 0.0, 0.0}; + float zmulx= re->winx/2, zmuly= re->winy/2, len; + float winsq = (float)re->winx * (float)re->winy, winroot= sqrtf(winsq); /* int's can wrap on large images */ + int a, j; + float hoco[4], ho[4], fsvec[4], camco[4]; + float mat[4][4], winmat[4][4]; + float imat[4][4]; + FluidsimModifierData *fluidmd = (FluidsimModifierData *)modifiers_findByType(fsob, eModifierType_Fluidsim); + FluidsimSettings *fss; + FluidVertexVelocity *velarray = NULL; + + /* only one step needed */ + if (step) return 1; + + if (fluidmd) + fss = fluidmd->fss; + else + return 0; + + copy_m4_m4(mat, re->viewmat); + invert_m4_m4(imat, mat); + + /* set first vertex OK */ + if (!fss->meshVelocities) return 0; + + if ( obr->totvert != fss->totvert) { + //fprintf(stderr, "load_fluidsimspeedvectors - modified fluidsim mesh, not using speed vectors (%d,%d)...\n", obr->totvert, fsob->fluidsimSettings->meshSurface->totvert); // DEBUG + return 0; + } + + velarray = fss->meshVelocities; + + if (obi->flag & R_TRANSFORMED) + mul_m4_m4m4(winmat, re->winmat, obi->mat); + else + copy_m4_m4(winmat, re->winmat); + + /* (bad) HACK calculate average velocity */ + /* better solution would be fixing getVelocityAt() in intern/elbeem/intern/solver_util.cpp + * so that also small drops/little water volumes return a velocity != 0. + * But I had no luck in fixing that function - DG */ + for (a=0; a<obr->totvert; a++) { + for (j=0;j<3;j++) avgvel[j] += velarray[a].vel[j]; + + } + for (j=0;j<3;j++) avgvel[j] /= (float)(obr->totvert); + + + for (a=0; a<obr->totvert; a++, vectors+=2) { + if ((a & 255)==0) + ver= obr->vertnodes[a>>8].vert; + else + ver++; + + /* get fluid velocity */ + fsvec[3] = 0.0f; + //fsvec[0] = fsvec[1] = fsvec[2] = fsvec[3] = 0.0; fsvec[2] = 2.0f; // NT fixed test + for (j=0;j<3;j++) fsvec[j] = velarray[a].vel[j]; + + /* (bad) HACK insert average velocity if none is there (see previous comment) */ + if ((fsvec[0] == 0.0f) && (fsvec[1] == 0.0f) && (fsvec[2] == 0.0f)) { + fsvec[0] = avgvel[0]; + fsvec[1] = avgvel[1]; + fsvec[2] = avgvel[2]; + } + + /* transform (=rotate) to cam space */ + camco[0] = dot_v3v3(imat[0], fsvec); + camco[1] = dot_v3v3(imat[1], fsvec); + camco[2] = dot_v3v3(imat[2], fsvec); + + /* get homogeneous coordinates */ + projectvert(camco, winmat, hoco); + projectvert(ver->co, winmat, ho); + + /* now map hocos to screenspace, uses very primitive clip still */ + /* use ho[3] of original vertex, xy component of vel. direction */ + if (ho[3]<0.1f) div= 10.0f; + else div= 1.0f/ho[3]; + zco[0]= zmulx*hoco[0]*div; + zco[1]= zmuly*hoco[1]*div; + + /* maximize speed as usual */ + len= zco[0]*zco[0] + zco[1]*zco[1]; + if (len > winsq) { + len= winroot/sqrtf(len); + zco[0]*= len; zco[1]*= len; + } + + speed= RE_vertren_get_winspeed(obi, ver, 1); + /* set both to the same value */ + speed[0]= speed[2]= zco[0]; + speed[1]= speed[3]= zco[1]; + //if (a < 20) fprintf(stderr,"speed %d %f,%f | camco %f,%f,%f | hoco %f,%f,%f,%f\n", a, speed[0], speed[1], camco[0],camco[1], camco[2], hoco[0],hoco[1], hoco[2],hoco[3]); // NT DEBUG + } + + return 1; +} + +/* makes copy per object of all vectors */ +/* result should be that we can free entire database */ +static void copy_dbase_object_vectors(Render *re, ListBase *lb) +{ + ObjectInstanceRen *obi, *obilb; + ObjectRen *obr; + VertRen *ver= NULL; + float *vec, ho[4], winmat[4][4]; + int a, totvector; + + for (obi= re->instancetable.first; obi; obi= obi->next) { + obr= obi->obr; + + obilb= MEM_mallocN(sizeof(ObjectInstanceRen), "ObInstanceVector"); + memcpy(obilb, obi, sizeof(ObjectInstanceRen)); + BLI_addtail(lb, obilb); + + obilb->totvector= totvector= obr->totvert; + + if (totvector > 0) { + vec= obilb->vectors= MEM_mallocN(2*sizeof(float)*totvector, "vector array"); + + if (obi->flag & R_TRANSFORMED) + mul_m4_m4m4(winmat, re->winmat, obi->mat); + else + copy_m4_m4(winmat, re->winmat); + + for (a=0; a<obr->totvert; a++, vec+=2) { + if ((a & 255)==0) ver= obr->vertnodes[a>>8].vert; + else ver++; + + projectvert(ver->co, winmat, ho); + speedvector_project(NULL, vec, ver->co, ho); + } + } + } +} + +static void free_dbase_object_vectors(ListBase *lb) +{ + ObjectInstanceRen *obi; + + for (obi= lb->first; obi; obi= obi->next) + if (obi->vectors) + MEM_freeN(obi->vectors); + BLI_freelistN(lb); +} + +void RE_Database_FromScene_Vectors(Render *re, Main *bmain, Scene *sce, unsigned int lay) +{ + ObjectInstanceRen *obi, *oldobi; + StrandSurface *mesh; + ListBase *table; + ListBase oldtable= {NULL, NULL}, newtable= {NULL, NULL}; + ListBase strandsurface; + int step; + + re->i.infostr = IFACE_("Calculating previous frame vectors"); + re->r.mode |= R_SPEED; + + speedvector_project(re, NULL, NULL, NULL); /* initializes projection code */ + + /* creates entire dbase */ + database_fromscene_vectors(re, sce, lay, -1); + + /* copy away vertex info */ + copy_dbase_object_vectors(re, &oldtable); + + /* free dbase and make the future one */ + strandsurface= re->strandsurface; + memset(&re->strandsurface, 0, sizeof(ListBase)); + re->i.convertdone = true; + RE_Database_Free(re); + re->strandsurface= strandsurface; + + if (!re->test_break(re->tbh)) { + /* creates entire dbase */ + re->i.infostr = IFACE_("Calculating next frame vectors"); + + database_fromscene_vectors(re, sce, lay, +1); + } + /* copy away vertex info */ + copy_dbase_object_vectors(re, &newtable); + + /* free dbase and make the real one */ + strandsurface= re->strandsurface; + memset(&re->strandsurface, 0, sizeof(ListBase)); + re->i.convertdone = true; + RE_Database_Free(re); + re->strandsurface= strandsurface; + + if (!re->test_break(re->tbh)) { + RE_Database_FromScene(re, bmain, sce, lay, 1); + RE_Database_Preprocess(re); + } + + if (!re->test_break(re->tbh)) { + int vectorlay= get_vector_renderlayers(re->scene); + + for (step= 0; step<2; step++) { + + if (step) + table= &newtable; + else + table= &oldtable; + + oldobi= table->first; + for (obi= re->instancetable.first; obi && oldobi; obi= obi->next) { + int ok= 1; + FluidsimModifierData *fluidmd; + + if (!(obi->lay & vectorlay)) + continue; + + obi->totvector= obi->obr->totvert; + + /* find matching object in old table */ + if (oldobi->ob!=obi->ob || oldobi->par!=obi->par || oldobi->index!=obi->index || oldobi->psysindex!=obi->psysindex) { + ok= 0; + for (oldobi= table->first; oldobi; oldobi= oldobi->next) + if (oldobi->ob==obi->ob && oldobi->par==obi->par && oldobi->index==obi->index && oldobi->psysindex==obi->psysindex) + break; + if (oldobi==NULL) + oldobi= table->first; + else + ok= 1; + } + if (ok==0) { + printf("speed table: missing object %s\n", obi->ob->id.name + 2); + continue; + } + + /* NT check for fluidsim special treatment */ + fluidmd = (FluidsimModifierData *)modifiers_findByType(obi->ob, eModifierType_Fluidsim); + if (fluidmd && fluidmd->fss && (fluidmd->fss->type & OB_FLUIDSIM_DOMAIN)) { + /* use preloaded per vertex simulation data, only does calculation for step=1 */ + /* NOTE/FIXME - velocities and meshes loaded unnecessarily often during the database_fromscene_vectors calls... */ + load_fluidsimspeedvectors(re, obi, oldobi->vectors, step); + } + else { + /* check if both have same amounts of vertices */ + if (obi->totvector==oldobi->totvector) + calculate_speedvectors(re, obi, oldobi->vectors, step); + else + printf("Warning: object %s has different amount of vertices or strands on other frame\n", obi->ob->id.name + 2); + } /* not fluidsim */ + + oldobi= oldobi->next; + } + } + } + + free_dbase_object_vectors(&oldtable); + free_dbase_object_vectors(&newtable); + + for (mesh=re->strandsurface.first; mesh; mesh=mesh->next) { + if (mesh->prevco) { + MEM_freeN(mesh->prevco); + mesh->prevco= NULL; + } + if (mesh->nextco) { + MEM_freeN(mesh->nextco); + mesh->nextco= NULL; + } + } + + re->i.infostr = NULL; + re->stats_draw(re->sdh, &re->i); +} + + +/* ------------------------------------------------------------------------- */ +/* Baking */ +/* ------------------------------------------------------------------------- */ + +/* setup for shaded view or bake, so only lamps and materials are initialized */ +/* type: + * RE_BAKE_LIGHT: for shaded view, only add lamps + * RE_BAKE_ALL: for baking, all lamps and objects + * RE_BAKE_NORMALS:for baking, no lamps and only selected objects + * RE_BAKE_AO: for baking, no lamps, but all objects + * RE_BAKE_TEXTURE:for baking, no lamps, only selected objects + * RE_BAKE_VERTEX_COLORS:for baking, no lamps, only selected objects + * RE_BAKE_DISPLACEMENT:for baking, no lamps, only selected objects + * RE_BAKE_DERIVATIVE:for baking, no lamps, only selected objects + * RE_BAKE_SHADOW: for baking, only shadows, but all objects + */ +void RE_Database_Baking(Render *re, Main *bmain, Scene *scene, unsigned int lay, const int type, Object *actob) +{ + Object *camera; + float mat[4][4]; + float amb[3]; + const short onlyselected= !ELEM(type, RE_BAKE_LIGHT, RE_BAKE_ALL, RE_BAKE_SHADOW, RE_BAKE_AO, RE_BAKE_VERTEX_COLORS); + const short nolamps= ELEM(type, RE_BAKE_NORMALS, RE_BAKE_TEXTURE, RE_BAKE_DISPLACEMENT, RE_BAKE_DERIVATIVE, RE_BAKE_VERTEX_COLORS); + + re->main= bmain; + re->scene= scene; + re->lay= lay; + + /* renderdata setup and exceptions */ + render_copy_renderdata(&re->r, &scene->r); + + RE_init_threadcount(re); + + re->flag |= R_BAKING; + re->excludeob= actob; + if (actob) + re->flag |= R_BAKE_TRACE; + + if (type==RE_BAKE_NORMALS && re->r.bake_normal_space==R_BAKE_SPACE_TANGENT) + re->flag |= R_NEED_TANGENT; + + if (type==RE_BAKE_VERTEX_COLORS) + re->flag |= R_NEED_VCOL; + + if (!actob && ELEM(type, RE_BAKE_LIGHT, RE_BAKE_NORMALS, RE_BAKE_TEXTURE, RE_BAKE_DISPLACEMENT, RE_BAKE_DERIVATIVE, RE_BAKE_VERTEX_COLORS)) { + re->r.mode &= ~R_SHADOW; + re->r.mode &= ~R_RAYTRACE; + } + + if (!actob && (type==RE_BAKE_SHADOW)) { + re->r.mode |= R_SHADOW; + } + + /* setup render stuff */ + re->memArena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "bake db arena"); + + re->totvlak=re->totvert=re->totstrand=re->totlamp=re->tothalo= 0; + re->lights.first= re->lights.last= NULL; + re->lampren.first= re->lampren.last= NULL; + + /* in localview, lamps are using normal layers, objects only local bits */ + if (re->lay & 0xFF000000) + lay &= 0xFF000000; + + camera= RE_GetCamera(re); + + /* if no camera, set unit */ + if (camera) { + normalize_m4_m4(mat, camera->obmat); + invert_m4(mat); + RE_SetView(re, mat); + } + else { + unit_m4(mat); + RE_SetView(re, mat); + } + copy_m3_m4(re->imat, re->viewinv); + + /* TODO: deep shadow maps + baking + strands */ + /* strands use the window matrix and view size, there is to correct + * window matrix but at least avoids malloc and crash loop [#27807] */ + unit_m4(re->winmat); + re->winx= re->winy= 256; + /* done setting dummy values */ + + init_render_world(re); /* do first, because of ambient. also requires re->osa set correct */ + if (re->r.mode & R_RAYTRACE) { + init_render_qmcsampler(re); + + if (re->wrld.mode & (WO_AMB_OCC|WO_ENV_LIGHT|WO_INDIRECT_LIGHT)) + if (re->wrld.ao_samp_method == WO_AOSAMP_CONSTANT) + init_ao_sphere(re, &re->wrld); + } + + /* still bad... doing all */ + init_render_textures(re); + + copy_v3_v3(amb, &re->wrld.ambr); + init_render_materials(re->main, re->r.mode, amb, true); + + set_node_shader_lamp_loop(shade_material_loop); + + /* MAKE RENDER DATA */ + database_init_objects(re, lay, nolamps, onlyselected, actob, 0); + + set_material_lightgroups(re); + + /* SHADOW BUFFER */ + if (type!=RE_BAKE_LIGHT) + if (re->r.mode & R_SHADOW) + threaded_makeshadowbufs(re); + + /* raytree */ + if (!re->test_break(re->tbh)) + if (re->r.mode & R_RAYTRACE) + makeraytree(re); + + /* point density texture */ + if (!re->test_break(re->tbh)) + make_pointdensities(re); + + /* voxel data texture */ + if (!re->test_break(re->tbh)) + make_voxeldata(re); + + /* occlusion */ + if ((re->wrld.mode & (WO_AMB_OCC|WO_ENV_LIGHT|WO_INDIRECT_LIGHT)) && !re->test_break(re->tbh)) + if (re->wrld.ao_gather_method == WO_AOGATHER_APPROX) + if (re->r.mode & R_SHADOW) + make_occ_tree(re); + + re->i.convertdone = true; +} diff --git a/source/blender/render/intern/source/envmap.c b/source/blender/render/intern/source/envmap.c new file mode 100644 index 00000000000..85a6af92a28 --- /dev/null +++ b/source/blender/render/intern/source/envmap.c @@ -0,0 +1,822 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * Contributors: 2004/2005/2006 Blender Foundation, full recode + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/render/intern/source/envmap.c + * \ingroup render + */ + +#include <math.h> +#include <string.h> + +/* external modules: */ + +#include "BLI_math.h" +#include "BLI_blenlib.h" +#include "BLI_threads.h" +#include "BLI_utildefines.h" + +#include "BLT_translation.h" + +#include "IMB_imbuf_types.h" +#include "IMB_imbuf.h" /* for rectcpy */ + +#include "DNA_group_types.h" +#include "DNA_image_types.h" +#include "DNA_lamp_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" +#include "DNA_texture_types.h" + +#include "BKE_main.h" +#include "BKE_image.h" /* BKE_imbuf_write */ +#include "BKE_texture.h" +#include "BKE_scene.h" + +/* this module */ +#include "render_types.h" +#include "envmap.h" +#include "renderdatabase.h" +#include "renderpipeline.h" +#include "texture.h" +#include "zbuf.h" +#include "render_result.h" + +/* ------------------------------------------------------------------------- */ + +static void envmap_split_ima(EnvMap *env, ImBuf *ibuf) +{ + int dx, part; + + /* after lock we test cube[1], if set the other thread has done it fine */ + BLI_thread_lock(LOCK_IMAGE); + if (env->cube[1] == NULL) { + + BKE_texture_envmap_free_data(env); + + dx = ibuf->y; + dx /= 2; + if (3 * dx == ibuf->x) { + env->type = ENV_CUBE; + env->ok = ENV_OSA; + } + else if (ibuf->x == ibuf->y) { + env->type = ENV_PLANE; + env->ok = ENV_OSA; + } + else { + printf("Incorrect envmap size\n"); + env->ok = 0; + env->ima->ok = 0; + } + + if (env->ok) { + if (env->type == ENV_CUBE) { + for (part = 0; part < 6; part++) { + env->cube[part] = IMB_allocImBuf(dx, dx, 24, IB_rect | IB_rectfloat); + } + IMB_float_from_rect(ibuf); + + IMB_rectcpy(env->cube[0], ibuf, + 0, 0, 0, 0, dx, dx); + IMB_rectcpy(env->cube[1], ibuf, + 0, 0, dx, 0, dx, dx); + IMB_rectcpy(env->cube[2], ibuf, + 0, 0, 2 * dx, 0, dx, dx); + IMB_rectcpy(env->cube[3], ibuf, + 0, 0, 0, dx, dx, dx); + IMB_rectcpy(env->cube[4], ibuf, + 0, 0, dx, dx, dx, dx); + IMB_rectcpy(env->cube[5], ibuf, + 0, 0, 2 * dx, dx, dx, dx); + + } + else { /* ENV_PLANE */ + env->cube[1] = IMB_dupImBuf(ibuf); + IMB_float_from_rect(env->cube[1]); + } + } + } + BLI_thread_unlock(LOCK_IMAGE); +} + +/* ------------------------------------------------------------------------- */ +/* ****************** RENDER ********************** */ + +/* copy current render */ +static Render *envmap_render_copy(Render *re, EnvMap *env) +{ + Render *envre; + float viewscale; + int cuberes; + + envre = RE_NewRender("Envmap"); + + env->lastsize = re->r.size; + cuberes = (env->cuberes * re->r.size) / 100; + cuberes &= 0xFFFC; + + /* this flag has R_ZTRA in it for example */ + envre->flag = re->flag; + + /* set up renderdata */ + render_copy_renderdata(&envre->r, &re->r); + envre->r.mode &= ~(R_BORDER | R_PANORAMA | R_ORTHO | R_MBLUR); + BLI_freelistN(&envre->r.layers); + BLI_freelistN(&envre->r.views); + envre->r.filtertype = 0; + envre->r.tilex = envre->r.xsch / 2; + envre->r.tiley = envre->r.ysch / 2; + envre->r.size = 100; + envre->r.yasp = envre->r.xasp = 1; + + RE_InitState(envre, NULL, &envre->r, NULL, cuberes, cuberes, NULL); + envre->main = re->main; + envre->scene = re->scene; /* unsure about this... */ + envre->scene_color_manage = re->scene_color_manage; + envre->lay = re->lay; + + /* view stuff in env render */ + viewscale = (env->type == ENV_PLANE) ? env->viewscale : 1.0f; + RE_SetEnvmapCamera(envre, env->object, viewscale, env->clipsta, env->clipend); + copy_m4_m4(envre->viewmat_orig, re->viewmat_orig); + + /* callbacks */ + envre->display_update = re->display_update; + envre->duh = re->duh; + envre->test_break = re->test_break; + envre->tbh = re->tbh; + envre->current_scene_update = re->current_scene_update; + envre->suh = re->suh; + + /* and for the evil stuff; copy the database... */ + envre->totvlak = re->totvlak; + envre->totvert = re->totvert; + envre->tothalo = re->tothalo; + envre->totstrand = re->totstrand; + envre->totlamp = re->totlamp; + envre->sortedhalos = re->sortedhalos; + envre->lights = re->lights; + envre->objecttable = re->objecttable; + envre->customdata_names = re->customdata_names; + envre->raytree = re->raytree; + envre->totinstance = re->totinstance; + envre->instancetable = re->instancetable; + envre->objectinstance = re->objectinstance; + envre->qmcsamplers = re->qmcsamplers; + + return envre; +} + +static void envmap_free_render_copy(Render *envre) +{ + + envre->totvlak = 0; + envre->totvert = 0; + envre->tothalo = 0; + envre->totstrand = 0; + envre->totlamp = 0; + envre->totinstance = 0; + envre->sortedhalos = NULL; + BLI_listbase_clear(&envre->lights); + BLI_listbase_clear(&envre->objecttable); + BLI_listbase_clear(&envre->customdata_names); + envre->raytree = NULL; + BLI_listbase_clear(&envre->instancetable); + envre->objectinstance = NULL; + envre->qmcsamplers = NULL; + + RE_FreeRender(envre); +} + +/* ------------------------------------------------------------------------- */ + +static void envmap_transmatrix(float mat[4][4], int part) +{ + float tmat[4][4], eul[3], rotmat[4][4]; + + eul[0] = eul[1] = eul[2] = 0.0; + + if (part == 0) { /* neg z */ + /* pass */ + } + else if (part == 1) { /* pos z */ + eul[0] = M_PI; + } + else if (part == 2) { /* pos y */ + eul[0] = M_PI / 2.0; + } + else if (part == 3) { /* neg x */ + eul[0] = M_PI / 2.0; + eul[2] = M_PI / 2.0; + } + else if (part == 4) { /* neg y */ + eul[0] = M_PI / 2.0; + eul[2] = M_PI; + } + else { /* pos x */ + eul[0] = M_PI / 2.0; + eul[2] = -M_PI / 2.0; + } + + copy_m4_m4(tmat, mat); + eul_to_mat4(rotmat, eul); + mul_m4_m4m4(mat, tmat, rotmat); +} +/* ------------------------------------------------------------------------- */ + +static void env_set_imats(Render *re) +{ + Base *base; + float mat[4][4]; + + base = re->scene->base.first; + while (base) { + mul_m4_m4m4(mat, re->viewmat, base->object->obmat); + invert_m4_m4(base->object->imat, mat); + + base = base->next; + } + +} + +/* ------------------------------------------------------------------------- */ + +void env_rotate_scene(Render *re, float mat[4][4], int do_rotate) +{ + ObjectRen *obr; + ObjectInstanceRen *obi; + LampRen *lar = NULL; + HaloRen *har = NULL; + float imat[3][3], mat_inverse[4][4], smat[4][4], tmat[4][4], cmat[3][3], tmpmat[4][4]; + int a; + + if (do_rotate == 0) { + invert_m4_m4(tmat, mat); + copy_m3_m4(imat, tmat); + + copy_m4_m4(mat_inverse, mat); + } + else { + copy_m4_m4(tmat, mat); + copy_m3_m4(imat, mat); + + invert_m4_m4(mat_inverse, tmat); + } + + for (obi = re->instancetable.first; obi; obi = obi->next) { + /* append or set matrix depending on dupli */ + if (obi->flag & R_DUPLI_TRANSFORMED) { + copy_m4_m4(tmpmat, obi->mat); + mul_m4_m4m4(obi->mat, tmat, tmpmat); + } + else if (do_rotate == 1) + copy_m4_m4(obi->mat, tmat); + else + unit_m4(obi->mat); + + copy_m3_m4(cmat, obi->mat); + invert_m3_m3(obi->nmat, cmat); + transpose_m3(obi->nmat); + + /* indicate the renderer has to use transform matrices */ + if (do_rotate == 0) + obi->flag &= ~R_ENV_TRANSFORMED; + else { + obi->flag |= R_ENV_TRANSFORMED; + copy_m4_m4(obi->imat, mat_inverse); + } + } + + + for (obr = re->objecttable.first; obr; obr = obr->next) { + for (a = 0; a < obr->tothalo; a++) { + if ((a & 255) == 0) har = obr->bloha[a >> 8]; + else har++; + + mul_m4_v3(tmat, har->co); + } + + /* imat_ren is needed for correct texture coordinates */ + mul_m4_m4m4(obr->ob->imat_ren, re->viewmat, obr->ob->obmat); + invert_m4(obr->ob->imat_ren); + } + + for (lar = re->lampren.first; lar; lar = lar->next) { + float lamp_imat[4][4]; + + /* copy from add_render_lamp */ + if (do_rotate == 1) + mul_m4_m4m4(tmpmat, re->viewmat, lar->lampmat); + else + mul_m4_m4m4(tmpmat, re->viewmat_orig, lar->lampmat); + + invert_m4_m4(lamp_imat, tmpmat); + copy_m3_m4(lar->mat, tmpmat); + copy_m3_m4(lar->imat, lamp_imat); + + lar->vec[0]= -tmpmat[2][0]; + lar->vec[1]= -tmpmat[2][1]; + lar->vec[2]= -tmpmat[2][2]; + normalize_v3(lar->vec); + lar->co[0]= tmpmat[3][0]; + lar->co[1]= tmpmat[3][1]; + lar->co[2]= tmpmat[3][2]; + + if (lar->type == LA_AREA) { + area_lamp_vectors(lar); + } + else if (lar->type == LA_SPOT) { + normalize_v3(lar->imat[0]); + normalize_v3(lar->imat[1]); + normalize_v3(lar->imat[2]); + + lar->sh_invcampos[0] = -lar->co[0]; + lar->sh_invcampos[1] = -lar->co[1]; + lar->sh_invcampos[2] = -lar->co[2]; + mul_m3_v3(lar->imat, lar->sh_invcampos); + lar->sh_invcampos[2] *= lar->sh_zfac; + + if (lar->shb) { + if (do_rotate == 1) { + mul_m4_m4m4(smat, lar->shb->viewmat, mat_inverse); + mul_m4_m4m4(lar->shb->persmat, lar->shb->winmat, smat); + } + else mul_m4_m4m4(lar->shb->persmat, lar->shb->winmat, lar->shb->viewmat); + } + } + } + + if (do_rotate) { + init_render_world(re); + env_set_imats(re); + } +} + +/* ------------------------------------------------------------------------- */ + +static void env_layerflags(Render *re, unsigned int notlay) +{ + ObjectRen *obr; + VlakRen *vlr = NULL; + int a; + + /* invert notlay, so if face is in multiple layers it will still be visible, + * unless all 'notlay' bits match the face bits. + * face: 0110 + * not: 0100 + * ~not: 1011 + * now (face & ~not) is true + */ + + notlay = ~notlay; + + for (obr = re->objecttable.first; obr; obr = obr->next) { + if ((obr->lay & notlay) == 0) { + for (a = 0; a < obr->totvlak; a++) { + if ((a & 255) == 0) vlr = obr->vlaknodes[a >> 8].vlak; + else vlr++; + + vlr->flag |= R_HIDDEN; + } + } + } +} + +static void env_hideobject(Render *re, Object *ob) +{ + ObjectRen *obr; + VlakRen *vlr = NULL; + int a; + + for (obr = re->objecttable.first; obr; obr = obr->next) { + for (a = 0; a < obr->totvlak; a++) { + if ((a & 255) == 0) vlr = obr->vlaknodes[a >> 8].vlak; + else vlr++; + + if (obr->ob == ob) + vlr->flag |= R_HIDDEN; + } + } +} + +static void env_showobjects(Render *re) +{ + ObjectRen *obr; + VlakRen *vlr = NULL; + int a; + + for (obr = re->objecttable.first; obr; obr = obr->next) { + for (a = 0; a < obr->totvlak; a++) { + if ((a & 255) == 0) vlr = obr->vlaknodes[a >> 8].vlak; + else vlr++; + + vlr->flag &= ~R_HIDDEN; + } + } +} + +/* ------------------------------------------------------------------------- */ + +static void render_envmap(Render *re, EnvMap *env) +{ + /* only the cubemap and planar map is implemented */ + Render *envre; + ImBuf *ibuf; + float orthmat[4][4]; + float oldviewinv[4][4], mat[4][4], tmat[4][4]; + short part; + + /* need a recalc: ortho-render has no correct viewinv */ + invert_m4_m4(oldviewinv, re->viewmat); + + envre = envmap_render_copy(re, env); + + /* precalc orthmat for object */ + copy_m4_m4(orthmat, env->object->obmat); + normalize_m4(orthmat); + + /* need imat later for texture imat */ + mul_m4_m4m4(mat, re->viewmat, orthmat); + invert_m4_m4(tmat, mat); + copy_m3_m4(env->obimat, tmat); + + for (part = 0; part < 6; part++) { + if (env->type == ENV_PLANE && part != 1) + continue; + + re->display_clear(re->dch, envre->result); + + copy_m4_m4(tmat, orthmat); + envmap_transmatrix(tmat, part); + invert_m4_m4(mat, tmat); + /* mat now is the camera 'viewmat' */ + + copy_m4_m4(envre->viewmat, mat); + copy_m4_m4(envre->viewinv, tmat); + + /* we have to correct for the already rotated vertexcoords */ + mul_m4_m4m4(tmat, envre->viewmat, oldviewinv); + invert_m4_m4(env->imat, tmat); + + env_rotate_scene(envre, tmat, 1); + project_renderdata(envre, projectverto, 0, 0, 1); + env_layerflags(envre, env->notlay); + env_hideobject(envre, env->object); + + if (re->test_break(re->tbh) == 0) { + RE_TileProcessor(envre); + } + + /* rotate back */ + env_showobjects(envre); + env_rotate_scene(envre, tmat, 0); + + if (re->test_break(re->tbh) == 0) { + int y; + float *alpha; + float *rect; + + if (envre->result->do_exr_tile) { + BLI_rw_mutex_lock(&envre->resultmutex, THREAD_LOCK_WRITE); + render_result_exr_file_end(envre); + BLI_rw_mutex_unlock(&envre->resultmutex); + } + + RenderLayer *rl = envre->result->layers.first; + + /* envmap is rendered independently of multiview */ + rect = RE_RenderLayerGetPass(rl, RE_PASSNAME_COMBINED, ""); + ibuf = IMB_allocImBuf(envre->rectx, envre->recty, 24, IB_rect | IB_rectfloat); + memcpy(ibuf->rect_float, rect, ibuf->channels * ibuf->x * ibuf->y * sizeof(float)); + + /* envmap renders without alpha */ + alpha = ibuf->rect_float + 3; + for (y = ibuf->x * ibuf->y - 1; y >= 0; y--, alpha += 4) + *alpha = 1.0; + + env->cube[part] = ibuf; + } + + if (re->test_break(re->tbh)) break; + + } + + if (re->test_break(re->tbh)) BKE_texture_envmap_free_data(env); + else { + if (envre->r.mode & R_OSA) env->ok = ENV_OSA; + else env->ok = ENV_NORMAL; + env->lastframe = re->scene->r.cfra; + } + + /* restore */ + envmap_free_render_copy(envre); + env_set_imats(re); + +} + +/* ------------------------------------------------------------------------- */ + +void make_envmaps(Render *re) +{ + Tex *tex; + bool do_init = false; + int depth = 0, trace; + + if (!(re->r.mode & R_ENVMAP)) return; + + /* we don't raytrace, disabling the flag will cause ray_transp render solid */ + trace = (re->r.mode & R_RAYTRACE); + re->r.mode &= ~R_RAYTRACE; + + re->i.infostr = IFACE_("Creating Environment maps"); + re->stats_draw(re->sdh, &re->i); + + /* 5 = hardcoded max recursion level */ + while (depth < 5) { + tex = re->main->tex.first; + while (tex) { + if (tex->id.us && tex->type == TEX_ENVMAP) { + if (tex->env && tex->env->object) { + EnvMap *env = tex->env; + + if (env->object->lay & re->lay) { + if (env->stype == ENV_LOAD) { + float orthmat[4][4], mat[4][4], tmat[4][4]; + + /* precalc orthmat for object */ + copy_m4_m4(orthmat, env->object->obmat); + normalize_m4(orthmat); + + /* need imat later for texture imat */ + mul_m4_m4m4(mat, re->viewmat, orthmat); + invert_m4_m4(tmat, mat); + copy_m3_m4(env->obimat, tmat); + } + else { + + /* decide if to render an envmap (again) */ + if (env->depth >= depth) { + + /* set 'recalc' to make sure it does an entire loop of recalcs */ + + if (env->ok) { + /* free when OSA, and old one isn't OSA */ + if ((re->r.mode & R_OSA) && env->ok == ENV_NORMAL) + BKE_texture_envmap_free_data(env); + /* free when size larger */ + else if (env->lastsize < re->r.size) + BKE_texture_envmap_free_data(env); + /* free when env is in recalcmode */ + else if (env->recalc) + BKE_texture_envmap_free_data(env); + } + + if (env->ok == 0 && depth == 0) env->recalc = 1; + + if (env->ok == 0) { + do_init = true; + render_envmap(re, env); + + if (depth == env->depth) env->recalc = 0; + } + } + } + } + } + } + tex = tex->id.next; + } + depth++; + } + + if (do_init) { + re->display_init(re->dih, re->result); + re->display_clear(re->dch, re->result); + // re->flag |= R_REDRAW_PRV; + } + /* restore */ + re->r.mode |= trace; + +} + +/* ------------------------------------------------------------------------- */ + +static int envcube_isect(EnvMap *env, const float vec[3], float answ[2]) +{ + float lambda; + int face; + + if (env->type == ENV_PLANE) { + face = 1; + + lambda = 1.0f / vec[2]; + answ[0] = env->viewscale * lambda * vec[0]; + answ[1] = -env->viewscale * lambda * vec[1]; + } + else { + /* which face */ + if (vec[2] <= -fabsf(vec[0]) && vec[2] <= -fabsf(vec[1]) ) { + face = 0; + lambda = -1.0f / vec[2]; + answ[0] = lambda * vec[0]; + answ[1] = lambda * vec[1]; + } + else if (vec[2] >= fabsf(vec[0]) && vec[2] >= fabsf(vec[1])) { + face = 1; + lambda = 1.0f / vec[2]; + answ[0] = lambda * vec[0]; + answ[1] = -lambda * vec[1]; + } + else if (vec[1] >= fabsf(vec[0])) { + face = 2; + lambda = 1.0f / vec[1]; + answ[0] = lambda * vec[0]; + answ[1] = lambda * vec[2]; + } + else if (vec[0] <= -fabsf(vec[1])) { + face = 3; + lambda = -1.0f / vec[0]; + answ[0] = lambda * vec[1]; + answ[1] = lambda * vec[2]; + } + else if (vec[1] <= -fabsf(vec[0])) { + face = 4; + lambda = -1.0f / vec[1]; + answ[0] = -lambda * vec[0]; + answ[1] = lambda * vec[2]; + } + else { + face = 5; + lambda = 1.0f / vec[0]; + answ[0] = -lambda * vec[1]; + answ[1] = lambda * vec[2]; + } + } + + answ[0] = 0.5f + 0.5f * answ[0]; + answ[1] = 0.5f + 0.5f * answ[1]; + return face; +} + +/* ------------------------------------------------------------------------- */ + +static void set_dxtdyt(float r_dxt[3], float r_dyt[3], const float dxt[3], const float dyt[3], int face) +{ + if (face == 2 || face == 4) { + r_dxt[0] = dxt[0]; + r_dyt[0] = dyt[0]; + r_dxt[1] = dxt[2]; + r_dyt[1] = dyt[2]; + } + else if (face == 3 || face == 5) { + r_dxt[0] = dxt[1]; + r_dxt[1] = dxt[2]; + r_dyt[0] = dyt[1]; + r_dyt[1] = dyt[2]; + } + else { + r_dxt[0] = dxt[0]; + r_dyt[0] = dyt[0]; + r_dxt[1] = dxt[1]; + r_dyt[1] = dyt[1]; + } +} + +/* ------------------------------------------------------------------------- */ + +int envmaptex(Tex *tex, const float texvec[3], float dxt[3], float dyt[3], int osatex, TexResult *texres, struct ImagePool *pool, const bool skip_load_image) +{ + extern Render R; /* only in this call */ + /* texvec should be the already reflected normal */ + EnvMap *env; + ImBuf *ibuf; + float fac, vec[3], sco[3], dxts[3], dyts[3]; + int face, face1; + + env = tex->env; + if (env == NULL || (env->stype != ENV_LOAD && env->object == NULL)) { + texres->tin = 0.0; + return 0; + } + + if (env->stype == ENV_LOAD) { + env->ima = tex->ima; + if (env->ima && env->ima->ok) { + if (env->cube[1] == NULL) { + ImBuf *ibuf_ima = BKE_image_pool_acquire_ibuf(env->ima, NULL, pool); + if (ibuf_ima) + envmap_split_ima(env, ibuf_ima); + else + env->ok = 0; + + if (env->type == ENV_PLANE) + tex->extend = TEX_EXTEND; + + BKE_image_pool_release_ibuf(env->ima, ibuf_ima, pool); + } + } + } + + if (env->ok == 0) { + texres->tin = 0.0; + return 0; + } + + /* rotate to envmap space, if object is set */ + copy_v3_v3(vec, texvec); + if (env->object) { + mul_m3_v3(env->obimat, vec); + if (osatex) { + mul_m3_v3(env->obimat, dxt); + mul_m3_v3(env->obimat, dyt); + } + } + else { + if (!BKE_scene_use_world_space_shading(R.scene)) { + // texvec is in view space + mul_mat3_m4_v3(R.viewinv, vec); + if (osatex) { + mul_mat3_m4_v3(R.viewinv, dxt); + mul_mat3_m4_v3(R.viewinv, dyt); + } + } + } + + face = envcube_isect(env, vec, sco); + ibuf = env->cube[face]; + + if (osatex) { + set_dxtdyt(dxts, dyts, dxt, dyt, face); + imagewraposa(tex, NULL, ibuf, sco, dxts, dyts, texres, pool, skip_load_image); + + /* edges? */ + + if (texres->ta < 1.0f) { + TexResult texr1, texr2; + + texr1.nor = texr2.nor = NULL; + texr1.talpha = texr2.talpha = texres->talpha; /* boxclip expects this initialized */ + + add_v3_v3(vec, dxt); + face1 = envcube_isect(env, vec, sco); + sub_v3_v3(vec, dxt); + + if (face != face1) { + ibuf = env->cube[face1]; + set_dxtdyt(dxts, dyts, dxt, dyt, face1); + imagewraposa(tex, NULL, ibuf, sco, dxts, dyts, &texr1, pool, skip_load_image); + } + else texr1.tr = texr1.tg = texr1.tb = texr1.ta = 0.0; + + /* here was the nasty bug! results were not zero-ed. FPE! */ + + add_v3_v3(vec, dyt); + face1 = envcube_isect(env, vec, sco); + sub_v3_v3(vec, dyt); + + if (face != face1) { + ibuf = env->cube[face1]; + set_dxtdyt(dxts, dyts, dxt, dyt, face1); + imagewraposa(tex, NULL, ibuf, sco, dxts, dyts, &texr2, pool, skip_load_image); + } + else texr2.tr = texr2.tg = texr2.tb = texr2.ta = 0.0; + + fac = (texres->ta + texr1.ta + texr2.ta); + if (fac != 0.0f) { + fac = 1.0f / fac; + + texres->tr = fac * (texres->ta * texres->tr + texr1.ta * texr1.tr + texr2.ta * texr2.tr); + texres->tg = fac * (texres->ta * texres->tg + texr1.ta * texr1.tg + texr2.ta * texr2.tg); + texres->tb = fac * (texres->ta * texres->tb + texr1.ta * texr1.tb + texr2.ta * texr2.tb); + } + texres->ta = 1.0; + } + } + else { + imagewrap(tex, NULL, ibuf, sco, texres, pool, skip_load_image); + } + + return 1; +} diff --git a/source/blender/render/intern/source/external_engine.c b/source/blender/render/intern/source/external_engine.c index b541c993bc7..6e4336f80ea 100644 --- a/source/blender/render/intern/source/external_engine.c +++ b/source/blender/render/intern/source/external_engine.c @@ -112,11 +112,11 @@ void RE_engines_register(RenderEngineType *render_type) RenderEngineType *RE_engines_find(const char *idname) { RenderEngineType *type; - + type = BLI_findstring(&R_engines, idname, offsetof(RenderEngineType, idname)); if (!type) type = BLI_findstring(&R_engines, "BLENDER_EEVEE", offsetof(RenderEngineType, idname)); - + return type; } @@ -320,7 +320,7 @@ int RE_engine_test_break(RenderEngine *engine) if (re) return re->test_break(re->tbh); - + return 0; } @@ -497,7 +497,7 @@ static void engine_depsgraph_init(RenderEngine *engine, ViewLayer *view_layer) engine->depsgraph = DEG_graph_new(scene, view_layer, DAG_EVAL_RENDER); DEG_debug_name_set(engine->depsgraph, "RENDER"); - BKE_scene_graph_update_tagged(engine->depsgraph, bmain); + BKE_scene_graph_update_for_newframe(engine->depsgraph, bmain); } static void engine_depsgraph_free(RenderEngine *engine) @@ -776,7 +776,7 @@ int RE_engine_render(Render *re, int do_all) if (BKE_reports_contain(re->reports, RPT_ERROR)) G.is_break = true; - + #ifdef WITH_FREESTYLE if (re->r.mode & R_EDGE_FRS) RE_RenderFreestyleExternal(re); diff --git a/source/blender/render/intern/source/imagetexture.c b/source/blender/render/intern/source/imagetexture.c index b9d55916f51..1e9ad79e599 100644 --- a/source/blender/render/intern/source/imagetexture.c +++ b/source/blender/render/intern/source/imagetexture.c @@ -32,7 +32,7 @@ #include <fcntl.h> #include <math.h> #include <float.h> -#ifndef WIN32 +#ifndef WIN32 #include <unistd.h> #else #include <io.h> @@ -67,7 +67,7 @@ static void boxsample(ImBuf *ibuf, float minx, float miny, float maxx, float max static void ibuf_get_color(float col[4], struct ImBuf *ibuf, int x, int y) { int ofs = y * ibuf->x + x; - + if (ibuf->rect_float) { if (ibuf->channels==4) { const float *fp= ibuf->rect_float + 4*ofs; @@ -105,15 +105,15 @@ int imagewrap(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], TexResul int xi, yi; /* original values */ texres->tin= texres->ta= texres->tr= texres->tg= texres->tb= 0.0f; - + /* we need to set retval OK, otherwise texture code generates normals itself... */ retval= texres->nor ? 3 : 1; - + /* quick tests */ if (ibuf==NULL && ima==NULL) return retval; if (ima) { - + /* hack for icon render */ if (skip_load_image && !BKE_image_has_loaded_ibuf(ima)) return retval; @@ -127,7 +127,7 @@ int imagewrap(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], TexResul BKE_image_pool_release_ibuf(ima, ibuf, pool); return retval; } - + /* setup mapping */ if (tex->imaflag & TEX_IMAROT) { fy= texvec[0]; @@ -137,10 +137,10 @@ int imagewrap(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], TexResul fx= texvec[0]; fy= texvec[1]; } - + if (tex->extend == TEX_CHECKER) { int xs, ys; - + xs= (int)floor(fx); ys= (int)floor(fy); fx-= xs; @@ -205,7 +205,7 @@ int imagewrap(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], TexResul if (y<0) y+= ibuf->y; } } - + /* keep this before interpolation [#29761] */ if (ima) { if ((tex->imaflag & TEX_USEALPHA) && (ima->flag & IMA_IGNORE_ALPHA) == 0) { @@ -232,7 +232,7 @@ int imagewrap(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], TexResul else { /* no filtering */ ibuf_get_color(&texres->tr, ibuf, x, y); } - + if (texres->nor) { if (tex->imaflag & TEX_NORMALMAP) { /* qdn: normal from color @@ -283,7 +283,7 @@ int imagewrap(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], TexResul else { texres->ta = texres->tin = 1.0; } - + if (tex->flag & TEX_NEGALPHA) { texres->ta = 1.0f - texres->ta; } @@ -301,7 +301,7 @@ int imagewrap(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], TexResul BKE_image_pool_release_ibuf(ima, ibuf, pool); BRICONTRGB; - + return retval; } @@ -327,9 +327,9 @@ static void clipx_rctf_swap(rctf *stack, short *count, float x1, float x2) newrct->xmin = rf->xmin+(x2-x1); newrct->ymin = rf->ymin; newrct->ymax = rf->ymax; - + if (newrct->xmin ==newrct->xmax) (*count)--; - + rf->xmin = x1; } } @@ -489,7 +489,7 @@ static void boxsampleclip(struct ImBuf *ibuf, rctf *rf, TexResult *texres) else { div= texres->tr= texres->tg= texres->tb= texres->ta= 0.0; for (y=starty; y<=endy; y++) { - + muly= 1.0; if (starty==endy) { @@ -499,10 +499,10 @@ static void boxsampleclip(struct ImBuf *ibuf, rctf *rf, TexResult *texres) if (y==starty) muly= 1.0f-(rf->ymin - y); if (y==endy) muly= (rf->ymax - y); } - + if (startx==endx) { mulx= muly; - + ibuf_get_color(col, ibuf, startx, y); texres->ta+= mulx*col[3]; @@ -518,7 +518,7 @@ static void boxsampleclip(struct ImBuf *ibuf, rctf *rf, TexResult *texres) if (x==endx) mulx*= (rf->xmax - x); ibuf_get_color(col, ibuf, x, y); - + if (mulx==1.0f) { texres->ta+= col[3]; texres->tr+= col[0]; @@ -573,7 +573,7 @@ static void boxsample(ImBuf *ibuf, float minx, float miny, float maxx, float max rf->ymax = maxy*(ibuf->y); texr.talpha= texres->talpha; /* is read by boxsample_clip */ - + if (imapextend) { CLAMP(rf->xmin, 0.0f, ibuf->x-1); CLAMP(rf->xmax, 0.0f, ibuf->x-1); @@ -608,7 +608,7 @@ static void boxsample(ImBuf *ibuf, float minx, float miny, float maxx, float max tot= texres->tr= texres->tb= texres->tg= texres->ta= 0.0; while (count--) { boxsampleclip(ibuf, rf, &texr); - + opp= square_rctf(rf); tot+= opp; @@ -629,7 +629,7 @@ static void boxsample(ImBuf *ibuf, float minx, float miny, float maxx, float max boxsampleclip(ibuf, rf, texres); if (texres->talpha==0) texres->ta= 1.0; - + if (alphaclip!=1.0f) { /* premul it all */ texres->tr*= alphaclip; @@ -637,7 +637,7 @@ static void boxsample(ImBuf *ibuf, float minx, float miny, float maxx, float max texres->tb*= alphaclip; texres->ta*= alphaclip; } -} +} /*----------------------------------------------------------------------------------------------------------------- * from here, some functions only used for the new filtering */ @@ -874,7 +874,7 @@ static void image_mipmap_test(Tex *tex, ImBuf *ibuf) { if (tex->imaflag & TEX_MIPMAP) { if ((ibuf->flags & IB_fields) == 0) { - + if (ibuf->mipmap[0] && (ibuf->userflags & IB_MIPMAP_INVALID)) { BLI_thread_lock(LOCK_IMAGE); if (ibuf->userflags & IB_MIPMAP_INVALID) { @@ -885,7 +885,7 @@ static void image_mipmap_test(Tex *tex, ImBuf *ibuf) } if (ibuf->mipmap[0] == NULL) { BLI_thread_lock(LOCK_IMAGE); - if (ibuf->mipmap[0] == NULL) + if (ibuf->mipmap[0] == NULL) IMB_makemipmap(ibuf, tex->imaflag & TEX_GAUSS_MIP); BLI_thread_unlock(LOCK_IMAGE); } @@ -895,7 +895,7 @@ static void image_mipmap_test(Tex *tex, ImBuf *ibuf) } } } - + } static int imagewraposa_aniso(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], float dxt[2], float dyt[2], TexResult *texres, struct ImagePool *pool, const bool skip_load_image) @@ -946,7 +946,7 @@ static int imagewraposa_aniso(Tex *tex, Image *ima, ImBuf *ibuf, const float tex /* mipmap test */ image_mipmap_test(tex, ibuf); - + if (ima) { if ((tex->imaflag & TEX_USEALPHA) && (ima->flag & IMA_IGNORE_ALPHA) == 0) { if ((tex->imaflag & TEX_CALCALPHA) == 0) { @@ -1281,7 +1281,7 @@ static int imagewraposa_aniso(Tex *tex, Image *ima, ImBuf *ibuf, const float tex else texres->tin = texres->ta; if (tex->flag & TEX_NEGALPHA) texres->ta = 1.f - texres->ta; - + if (texres->nor && (tex->imaflag & TEX_NORMALMAP)) { /* normal from color */ /* The invert of the red channel is to make * the normal map compliant with the outside world. @@ -1312,7 +1312,7 @@ static int imagewraposa_aniso(Tex *tex, Image *ima, ImBuf *ibuf, const float tex BKE_image_pool_release_ibuf(ima, ibuf, pool); BRICONTRGB; - + return retval; } @@ -1334,10 +1334,10 @@ int imagewraposa(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], const return imagewraposa_aniso(tex, ima, ibuf, texvec, dxt, dyt, texres, pool, skip_load_image); texres->tin= texres->ta= texres->tr= texres->tg= texres->tb= 0.0f; - + /* we need to set retval OK, otherwise texture code generates normals itself... */ retval = texres->nor ? 3 : 1; - + /* quick tests */ if (ibuf==NULL && ima==NULL) return retval; @@ -1346,7 +1346,7 @@ int imagewraposa(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], const /* hack for icon render */ if (skip_load_image && !BKE_image_has_loaded_ibuf(ima)) return retval; - + ibuf = BKE_image_pool_acquire_ibuf(ima, &tex->iuser, pool); ima->flag|= IMA_USED_FOR_RENDER; @@ -1356,7 +1356,7 @@ int imagewraposa(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], const BKE_image_pool_release_ibuf(ima, ibuf, pool); return retval; } - + /* mipmap test */ image_mipmap_test(tex, ibuf); @@ -1367,9 +1367,9 @@ int imagewraposa(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], const } } } - + texr.talpha= texres->talpha; - + if (tex->imaflag & TEX_IMAROT) { fy= texvec[0]; fx= texvec[1]; @@ -1378,7 +1378,7 @@ int imagewraposa(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], const fx= texvec[0]; fy= texvec[1]; } - + /* pixel coordinates */ minx = min_fff(dxt[0], dyt[0], dxt[0] + dyt[0]); @@ -1389,7 +1389,7 @@ int imagewraposa(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], const /* tex_sharper has been removed */ minx= (maxx-minx)/2.0f; miny= (maxy-miny)/2.0f; - + if (tex->imaflag & TEX_FILTER_MIN) { /* make sure the filtersize is minimal in pixels (normal, ref map can have miniature pixel dx/dy) */ float addval= (0.5f * tex->filtersize) / (float) MIN2(ibuf->x, ibuf->y); @@ -1402,7 +1402,7 @@ int imagewraposa(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], const else if (tex->filtersize!=1.0f) { minx*= tex->filtersize; miny*= tex->filtersize; - + dxt[0]*= tex->filtersize; dxt[1]*= tex->filtersize; dyt[0]*= tex->filtersize; @@ -1410,13 +1410,13 @@ int imagewraposa(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], const } if (tex->imaflag & TEX_IMAROT) SWAP(float, minx, miny); - + if (minx>0.25f) minx= 0.25f; else if (minx<0.00001f) minx= 0.00001f; /* side faces of unit-cube */ if (miny>0.25f) miny= 0.25f; else if (miny<0.00001f) miny= 0.00001f; - + /* repeat and clip */ imaprepeat= (tex->extend==TEX_REPEAT); imapextend= (tex->extend==TEX_EXTEND); @@ -1430,10 +1430,10 @@ int imagewraposa(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], const if (tex->extend == TEX_CHECKER) { int xs, ys, xs1, ys1, xs2, ys2, boundary; - + xs= (int)floor(fx); ys= (int)floor(fy); - + /* both checkers available, no boundary exceptions, checkerdist will eat aliasing */ if ( (tex->flag & TEX_CHECKER_ODD) && (tex->flag & TEX_CHECKER_EVEN) ) { fx-= xs; @@ -1447,7 +1447,7 @@ int imagewraposa(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], const return retval; } else { - + xs1= (int)floor(fx-minx); ys1= (int)floor(fy-miny); xs2= (int)floor(fx+minx); @@ -1479,14 +1479,14 @@ int imagewraposa(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], const if (tex->flag & TEX_CHECKER_ODD) { if ((xs1+ys) & 1) fx-= xs2; else fx-= xs1; - + if ((ys1+xs) & 1) fy-= ys2; else fy-= ys1; } if (tex->flag & TEX_CHECKER_EVEN) { if ((xs1+ys) & 1) fx-= xs1; else fx-= xs2; - + if ((ys1+xs) & 1) fy-= ys1; else fy-= ys2; } @@ -1525,7 +1525,7 @@ int imagewraposa(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], const if (fx>1.0f) fx -= (int)(fx); else if (fx<0.0f) fx+= 1-(int)(fx); } - + if (imapextend) { if (fy>1.0f) fy = 1.0f; else if (fy<0.0f) fy= 0.0f; @@ -1540,18 +1540,18 @@ int imagewraposa(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], const if (tex->imaflag & TEX_MIPMAP) { ImBuf *previbuf, *curibuf; float bumpscale; - + dx = minx; dy = miny; maxd = max_ff(dx, dy); if (maxd > 0.5f) maxd = 0.5f; pixsize = 1.0f / (float) MIN2(ibuf->x, ibuf->y); - + bumpscale= pixsize/maxd; if (bumpscale>1.0f) bumpscale= 1.0f; else bumpscale*=bumpscale; - + curmap= 0; previbuf= curibuf= ibuf; while (curmap < IMB_MIPMAP_LEVELS && ibuf->mipmap[curmap]) { @@ -1567,12 +1567,12 @@ int imagewraposa(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], const if (minx < 0.5f / ibuf->x) minx = 0.5f / ibuf->x; if (miny < 0.5f / ibuf->y) miny = 0.5f / ibuf->y; } - + if (texres->nor && (tex->imaflag & TEX_NORMALMAP)==0) { /* a bit extra filter */ //minx*= 1.35f; //miny*= 1.35f; - + boxsample(curibuf, fx-minx, fy-miny, fx+minx, fy+miny, texres, imaprepeat, imapextend); val1= texres->tr+texres->tg+texres->tb; boxsample(curibuf, fx-minx+dxt[0], fy-miny+dxt[1], fx+minx+dxt[0], fy+miny+dxt[1], &texr, imaprepeat, imapextend); @@ -1583,11 +1583,11 @@ int imagewraposa(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], const /* don't switch x or y! */ texres->nor[0]= (val1-val2); texres->nor[1]= (val1-val3); - + if (previbuf!=curibuf) { /* interpolate */ - + boxsample(previbuf, fx-minx, fy-miny, fx+minx, fy+miny, &texr, imaprepeat, imapextend); - + /* calc rgb */ dx= 2.0f*(pixsize-maxd)/pixsize; if (dx>=1.0f) { @@ -1601,16 +1601,16 @@ int imagewraposa(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], const texres->tr= dy*texres->tr+ dx*texr.tr; texres->ta= dy*texres->ta+ dx*texr.ta; } - + val1= dy*val1+ dx*(texr.tr + texr.tg + texr.tb); boxsample(previbuf, fx-minx+dxt[0], fy-miny+dxt[1], fx+minx+dxt[0], fy+miny+dxt[1], &texr, imaprepeat, imapextend); val2= dy*val2+ dx*(texr.tr + texr.tg + texr.tb); boxsample(previbuf, fx-minx+dyt[0], fy-miny+dyt[1], fx+minx+dyt[0], fy+miny+dyt[1], &texr, imaprepeat, imapextend); val3= dy*val3+ dx*(texr.tr + texr.tg + texr.tb); - + texres->nor[0]= (val1-val2); /* vals have been interpolated above! */ texres->nor[1]= (val1-val3); - + if (dx<1.0f) { dy= 1.0f-dx; texres->tb= dy*texres->tb+ dx*texr.tb; @@ -1632,9 +1632,9 @@ int imagewraposa(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], const if (previbuf!=curibuf) { /* interpolate */ boxsample(previbuf, minx, miny, maxx, maxy, &texr, imaprepeat, imapextend); - + fx= 2.0f*(pixsize-maxd)/pixsize; - + if (fx>=1.0f) { texres->ta= texr.ta; texres->tb= texr.tb; texres->tg= texr.tg; texres->tr= texr.tr; @@ -1672,7 +1672,7 @@ int imagewraposa(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], const else boxsample(ibuf, fx-minx, fy-miny, fx+minx, fy+miny, texres, imaprepeat, imapextend); } - + if (tex->imaflag & TEX_CALCALPHA) { texres->ta = texres->tin = texres->ta * max_fff(texres->tr, texres->tg, texres->tb); } @@ -1681,7 +1681,7 @@ int imagewraposa(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], const } if (tex->flag & TEX_NEGALPHA) texres->ta= 1.0f-texres->ta; - + if (texres->nor && (tex->imaflag & TEX_NORMALMAP)) { /* qdn: normal from color * The invert of the red channel is to make @@ -1705,7 +1705,7 @@ int imagewraposa(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], const BKE_image_pool_release_ibuf(ima, ibuf, pool); BRICONTRGB; - + return retval; } @@ -1713,16 +1713,16 @@ void image_sample(Image *ima, float fx, float fy, float dx, float dy, float resu { TexResult texres; ImBuf *ibuf = BKE_image_pool_acquire_ibuf(ima, NULL, pool); - + if (UNLIKELY(ibuf == NULL)) { zero_v4(result); return; } - + texres.talpha = true; /* boxsample expects to be initialized */ boxsample(ibuf, fx, fy, fx + dx, fy + dy, &texres, 0, 1); copy_v4_v4(result, &texres.tr); - + ima->flag|= IMA_USED_FOR_RENDER; BKE_image_pool_release_ibuf(ima, ibuf, pool); @@ -1737,11 +1737,11 @@ void ibuf_sample(ImBuf *ibuf, float fx, float fy, float dx, float dy, float resu AFD.dyt[0] = dy; AFD.dyt[1] = dy; //copy_v2_v2(AFD.dxt, dx); //copy_v2_v2(AFD.dyt, dy); - + AFD.intpol = 1; AFD.extflag = TXC_EXTD; ewa_eval(&texres, ibuf, fx, fy, &AFD); - + copy_v4_v4(result, &texres.tr); } diff --git a/source/blender/render/intern/source/initrender.c b/source/blender/render/intern/source/initrender.c index 4274d641674..9611a8a7452 100644 --- a/source/blender/render/intern/source/initrender.c +++ b/source/blender/render/intern/source/initrender.c @@ -66,9 +66,9 @@ static float filt_quadratic(float x) static float filt_cubic(float x) { float x2 = x * x; - + if (x < 0.0f) x = -x; - + if (x < 1.0f) return 0.5f * x * x2 - x2 + 2.0f / 3.0f; if (x < 2.0f) return (2.0f - x) * (2.0f - x) * (2.0f - x) / 6.0f; return 0.0f; @@ -78,7 +78,7 @@ static float filt_cubic(float x) static float filt_catrom(float x) { float x2 = x * x; - + if (x < 0.0f) x = -x; if (x < 1.0f) return 1.5f * x2 * x - 2.5f * x2 + 1.0f; if (x < 2.0f) return -0.5f * x2 * x + 2.5f * x2 - 4.0f * x + 2.0f; @@ -108,34 +108,34 @@ static float filt_mitchell(float x) /* Mitchell & Netravali's two-param cubic */ float RE_filter_value(int type, float x) { float gaussfac = 1.6f; - + x = ABS(x); - + switch (type) { case R_FILTER_BOX: if (x > 1.0f) return 0.0f; return 1.0f; - + case R_FILTER_TENT: if (x > 1.0f) return 0.0f; return 1.0f - x; - + case R_FILTER_GAUSS: { const float two_gaussfac2 = 2.0f * gaussfac * gaussfac; x *= 3.0f * gaussfac; return 1.0f / sqrtf((float)M_PI * two_gaussfac2) * expf(-x*x / two_gaussfac2); } - + case R_FILTER_MITCH: return filt_mitchell(x * gaussfac); - + case R_FILTER_QUAD: return filt_quadratic(x * gaussfac); - + case R_FILTER_CUBIC: return filt_cubic(x * gaussfac); - + case R_FILTER_CATROM: return filt_catrom(x * gaussfac); } @@ -221,20 +221,20 @@ void RE_parts_init(Render *re) { int nr, xd, yd, partx, party, xparts, yparts; int xminb, xmaxb, yminb, ymaxb; - + RE_parts_free(re); - + /* this is render info for caller, is not reset when parts are freed! */ re->i.totpart = 0; re->i.curpart = 0; re->i.partsdone = 0; - + /* just for readable code.. */ xminb = re->disprect.xmin; yminb = re->disprect.ymin; xmaxb = re->disprect.xmax; ymaxb = re->disprect.ymax; - + RE_parts_clamp(re); partx = re->partx; @@ -242,17 +242,17 @@ void RE_parts_init(Render *re) /* part count */ xparts = (re->rectx + partx - 1) / partx; yparts = (re->recty + party - 1) / party; - + for (nr = 0; nr < xparts * yparts; nr++) { rcti disprect; int rectx, recty; - + xd = (nr % xparts); yd = (nr - xd) / xparts; - + disprect.xmin = xminb + xd * partx; disprect.ymin = yminb + yd * party; - + /* ensure we cover the entire picture, so last parts go to end */ if (xd < xparts - 1) { disprect.xmax = disprect.xmin + partx; @@ -260,21 +260,21 @@ void RE_parts_init(Render *re) disprect.xmax = xmaxb; } else disprect.xmax = xmaxb; - + if (yd < yparts - 1) { disprect.ymax = disprect.ymin + party; if (disprect.ymax > ymaxb) disprect.ymax = ymaxb; } else disprect.ymax = ymaxb; - + rectx = BLI_rcti_size_x(&disprect); recty = BLI_rcti_size_y(&disprect); - + /* so, now can we add this part? */ if (rectx > 0 && recty > 0) { RenderPart *pa = MEM_callocN(sizeof(RenderPart), "new part"); - + pa->disprect = disprect; pa->rectx = rectx; pa->recty = recty; diff --git a/source/blender/render/intern/source/occlusion.c b/source/blender/render/intern/source/occlusion.c new file mode 100644 index 00000000000..8aa90a390b3 --- /dev/null +++ b/source/blender/render/intern/source/occlusion.c @@ -0,0 +1,1533 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2008 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Brecht Van Lommel. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/render/intern/source/occlusion.c + * \ingroup render + */ + +#include <math.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "MEM_guardedalloc.h" + +#include "DNA_material_types.h" + +#include "BLI_math.h" +#include "BLI_memarena.h" +#include "BLI_threads.h" +#include "BLI_utildefines.h" + +#include "BLT_translation.h" + +#include "BKE_node.h" +#include "BKE_scene.h" + + +#include "RE_shader_ext.h" + +/* local includes */ +#include "occlusion.h" +#include "render_types.h" +#include "rendercore.h" +#include "renderdatabase.h" +#include "shading.h" + +/* ------------------------- Declarations --------------------------- */ + +#define INVPI ((float)M_1_PI) +#define TOTCHILD 8 +#define CACHE_STEP 3 + +typedef struct OcclusionCacheSample { + float co[3], n[3], ao[3], env[3], indirect[3], intensity, dist2; + int x, y, filled; +} OcclusionCacheSample; + +typedef struct OcclusionCache { + OcclusionCacheSample *sample; + int x, y, w, h, step; +} OcclusionCache; + +typedef struct OccFace { + int obi; + int facenr; +} OccFace; + +typedef struct OccNode { + float co[3], area; + float sh[9], dco; + float occlusion, rad[3]; + int childflag; + union { + //OccFace face; + int face; + struct OccNode *node; + } child[TOTCHILD]; +} OccNode; + +typedef struct OcclusionTree { + MemArena *arena; + + float (*co)[3]; /* temporary during build */ + + OccFace *face; /* instance and face indices */ + float *occlusion; /* occlusion for faces */ + float (*rad)[3]; /* radiance for faces */ + + OccNode *root; + + OccNode **stack[BLENDER_MAX_THREADS]; + int maxdepth; + + int totface; + + float error; + float distfac; + + int dothreadedbuild; + int totbuildthread; + int doindirect; + + OcclusionCache *cache; + + int num_threads; +} OcclusionTree; + +typedef struct OcclusionThread { + Render *re; + StrandSurface *mesh; + float (*faceao)[3]; + float (*faceenv)[3]; + float (*faceindirect)[3]; + int begin, end; + int thread; +} OcclusionThread; + +typedef struct OcclusionBuildThread { + OcclusionTree *tree; + int begin, end, depth; + OccNode *node; +} OcclusionBuildThread; + +/* ------------------------- Shading --------------------------- */ + +extern Render R; /* meh */ + +static void occ_shade(ShadeSample *ssamp, ObjectInstanceRen *obi, VlakRen *vlr, float *rad) +{ + ShadeInput *shi = ssamp->shi; + ShadeResult *shr = ssamp->shr; + float l, u, v, *v1, *v2, *v3; + + /* init */ + if (vlr->v4) { + shi->u = u = 0.5f; + shi->v = v = 0.5f; + } + else { + shi->u = u = 1.0f / 3.0f; + shi->v = v = 1.0f / 3.0f; + } + + /* setup render coordinates */ + v1 = vlr->v1->co; + v2 = vlr->v2->co; + v3 = vlr->v3->co; + + /* renderco */ + l = 1.0f - u - v; + + shi->co[0] = l * v3[0] + u * v1[0] + v * v2[0]; + shi->co[1] = l * v3[1] + u * v1[1] + v * v2[1]; + shi->co[2] = l * v3[2] + u * v1[2] + v * v2[2]; + + shade_input_set_triangle_i(shi, obi, vlr, 0, 1, 2); + + /* set up view vector */ + copy_v3_v3(shi->view, shi->co); + normalize_v3(shi->view); + + /* cache for shadow */ + shi->samplenr++; + + shi->xs = 0; /* TODO */ + shi->ys = 0; + + shade_input_set_normals(shi); + + /* no normal flip */ + if (shi->flippednor) + shade_input_flip_normals(shi); + + madd_v3_v3fl(shi->co, shi->facenor, -0.0001f); /* ugly.. */ + + /* not a pretty solution, but fixes common cases */ + if (shi->obr->ob && shi->obr->ob->transflag & OB_NEG_SCALE) { + negate_v3(shi->vn); + negate_v3(shi->vno); + negate_v3(shi->nmapnorm); + } + + /* init material vars */ + shade_input_init_material(shi); + + /* render */ + shade_input_set_shade_texco(shi); + + if (shi->mat->nodetree && shi->mat->use_nodes) { + ntreeShaderExecTree(shi->mat->nodetree, shi, shr); + shi->mat = vlr->mat; /* shi->mat is being set in nodetree */ + } + else { + shade_material_loop(shi, shr); + } + + copy_v3_v3(rad, shr->combined); +} + +static void occ_build_shade(Render *re, OcclusionTree *tree) +{ + ShadeSample ssamp; + ObjectInstanceRen *obi; + VlakRen *vlr; + int a; + + R = *re; + + /* setup shade sample with correct passes */ + memset(&ssamp, 0, sizeof(ShadeSample)); + ssamp.shi[0].lay = re->lay; + ssamp.shi[0].passflag = SCE_PASS_DIFFUSE | SCE_PASS_RGBA; + ssamp.shi[0].combinedflag = ~(SCE_PASS_SPEC); + ssamp.tot = 1; + + for (a = 0; a < tree->totface; a++) { + obi = &R.objectinstance[tree->face[a].obi]; + vlr = RE_findOrAddVlak(obi->obr, tree->face[a].facenr); + + occ_shade(&ssamp, obi, vlr, tree->rad[a]); + + if (re->test_break(re->tbh)) + break; + } +} + +/* ------------------------- Spherical Harmonics --------------------------- */ + +/* Use 2nd order SH => 9 coefficients, stored in this order: + * 0 = (0,0), + * 1 = (1,-1), 2 = (1,0), 3 = (1,1), + * 4 = (2,-2), 5 = (2,-1), 6 = (2,0), 7 = (2,1), 8 = (2,2) */ + +static void sh_copy(float *shresult, float *sh) +{ + memcpy(shresult, sh, sizeof(float) * 9); +} + +static void sh_mul(float *sh, float f) +{ + int i; + + for (i = 0; i < 9; i++) + sh[i] *= f; +} + +static void sh_add(float *shresult, float *sh1, float *sh2) +{ + int i; + + for (i = 0; i < 9; i++) + shresult[i] = sh1[i] + sh2[i]; +} + +static void sh_from_disc(float *n, float area, float *shresult) +{ + /* See formula (3) in: + * "An Efficient Representation for Irradiance Environment Maps" */ + float sh[9], x, y, z; + + x = n[0]; + y = n[1]; + z = n[2]; + + sh[0] = 0.282095f; + + sh[1] = 0.488603f * y; + sh[2] = 0.488603f * z; + sh[3] = 0.488603f * x; + + sh[4] = 1.092548f * x * y; + sh[5] = 1.092548f * y * z; + sh[6] = 0.315392f * (3.0f * z * z - 1.0f); + sh[7] = 1.092548f * x * z; + sh[8] = 0.546274f * (x * x - y * y); + + sh_mul(sh, area); + sh_copy(shresult, sh); +} + +static float sh_eval(float *sh, float *v) +{ + /* See formula (13) in: + * "An Efficient Representation for Irradiance Environment Maps" */ + static const float c1 = 0.429043f, c2 = 0.511664f, c3 = 0.743125f; + static const float c4 = 0.886227f, c5 = 0.247708f; + float x, y, z, sum; + + x = v[0]; + y = v[1]; + z = v[2]; + + sum = c1 * sh[8] * (x * x - y * y); + sum += c3 * sh[6] * z * z; + sum += c4 * sh[0]; + sum += -c5 * sh[6]; + sum += 2.0f * c1 * (sh[4] * x * y + sh[7] * x * z + sh[5] * y * z); + sum += 2.0f * c2 * (sh[3] * x + sh[1] * y + sh[2] * z); + + return sum; +} + +/* ------------------------------ Building --------------------------------- */ + +static void occ_face(const OccFace *face, float co[3], float normal[3], float *area) +{ + ObjectInstanceRen *obi; + VlakRen *vlr; + float v1[3], v2[3], v3[3], v4[3]; + + obi = &R.objectinstance[face->obi]; + vlr = RE_findOrAddVlak(obi->obr, face->facenr); + + if (co) { + if (vlr->v4) + mid_v3_v3v3(co, vlr->v1->co, vlr->v3->co); + else + mid_v3_v3v3v3(co, vlr->v1->co, vlr->v2->co, vlr->v3->co); + + if (obi->flag & R_TRANSFORMED) + mul_m4_v3(obi->mat, co); + } + + if (normal) { + normal[0] = -vlr->n[0]; + normal[1] = -vlr->n[1]; + normal[2] = -vlr->n[2]; + + if (obi->flag & R_TRANSFORMED) + mul_m3_v3(obi->nmat, normal); + } + + if (area) { + copy_v3_v3(v1, vlr->v1->co); + copy_v3_v3(v2, vlr->v2->co); + copy_v3_v3(v3, vlr->v3->co); + if (vlr->v4) copy_v3_v3(v4, vlr->v4->co); + + if (obi->flag & R_TRANSFORMED) { + mul_m4_v3(obi->mat, v1); + mul_m4_v3(obi->mat, v2); + mul_m4_v3(obi->mat, v3); + if (vlr->v4) mul_m4_v3(obi->mat, v4); + } + + /* todo: correct area for instances */ + if (vlr->v4) + *area = area_quad_v3(v1, v2, v3, v4); + else + *area = area_tri_v3(v1, v2, v3); + } +} + +static void occ_sum_occlusion(OcclusionTree *tree, OccNode *node) +{ + OccNode *child; + float occ, area, totarea, rad[3]; + int a, b, indirect = tree->doindirect; + + occ = 0.0f; + totarea = 0.0f; + if (indirect) zero_v3(rad); + + for (b = 0; b < TOTCHILD; b++) { + if (node->childflag & (1 << b)) { + a = node->child[b].face; + occ_face(&tree->face[a], NULL, NULL, &area); + occ += area * tree->occlusion[a]; + if (indirect) madd_v3_v3fl(rad, tree->rad[a], area); + totarea += area; + } + else if (node->child[b].node) { + child = node->child[b].node; + occ_sum_occlusion(tree, child); + + occ += child->area * child->occlusion; + if (indirect) madd_v3_v3fl(rad, child->rad, child->area); + totarea += child->area; + } + } + + if (totarea != 0.0f) { + occ /= totarea; + if (indirect) mul_v3_fl(rad, 1.0f / totarea); + } + + node->occlusion = occ; + if (indirect) copy_v3_v3(node->rad, rad); +} + +static int occ_find_bbox_axis(OcclusionTree *tree, int begin, int end, float *min, float *max) +{ + float len, maxlen = -1.0f; + int a, axis = 0; + + INIT_MINMAX(min, max); + + for (a = begin; a < end; a++) { + minmax_v3v3_v3(min, max, tree->co[a]); + } + + for (a = 0; a < 3; a++) { + len = max[a] - min[a]; + + if (len > maxlen) { + maxlen = len; + axis = a; + } + } + + return axis; +} + +static void occ_node_from_face(OccFace *face, OccNode *node) +{ + float n[3]; + + occ_face(face, node->co, n, &node->area); + node->dco = 0.0f; + sh_from_disc(n, node->area, node->sh); +} + +static void occ_build_dco(OcclusionTree *tree, OccNode *node, const float co[3], float *dco) +{ + int b; + for (b = 0; b < TOTCHILD; b++) { + float dist, d[3], nco[3]; + + if (node->childflag & (1 << b)) { + occ_face(tree->face + node->child[b].face, nco, NULL, NULL); + } + else if (node->child[b].node) { + OccNode *child = node->child[b].node; + occ_build_dco(tree, child, co, dco); + copy_v3_v3(nco, child->co); + } + else { + continue; + } + + sub_v3_v3v3(d, nco, co); + dist = dot_v3v3(d, d); + if (dist > *dco) + *dco = dist; + } +} + +static void occ_build_split(OcclusionTree *tree, int begin, int end, int *split) +{ + float min[3], max[3], mid; + int axis, a, enda; + + /* split in middle of boundbox. this seems faster than median split + * on complex scenes, possibly since it avoids two distant faces to + * be in the same node better? */ + axis = occ_find_bbox_axis(tree, begin, end, min, max); + mid = 0.5f * (min[axis] + max[axis]); + + a = begin; + enda = end; + while (a < enda) { + if (tree->co[a][axis] > mid) { + enda--; + SWAP(OccFace, tree->face[a], tree->face[enda]); + swap_v3_v3(tree->co[a], tree->co[enda]); + } + else + a++; + } + + *split = enda; +} + +static void occ_build_8_split(OcclusionTree *tree, int begin, int end, int *offset, int *count) +{ + /* split faces into eight groups */ + int b, splitx, splity[2], splitz[4]; + + occ_build_split(tree, begin, end, &splitx); + + /* force split if none found, to deal with degenerate geometry */ + if (splitx == begin || splitx == end) + splitx = (begin + end) / 2; + + occ_build_split(tree, begin, splitx, &splity[0]); + occ_build_split(tree, splitx, end, &splity[1]); + + occ_build_split(tree, begin, splity[0], &splitz[0]); + occ_build_split(tree, splity[0], splitx, &splitz[1]); + occ_build_split(tree, splitx, splity[1], &splitz[2]); + occ_build_split(tree, splity[1], end, &splitz[3]); + + offset[0] = begin; + offset[1] = splitz[0]; + offset[2] = splity[0]; + offset[3] = splitz[1]; + offset[4] = splitx; + offset[5] = splitz[2]; + offset[6] = splity[1]; + offset[7] = splitz[3]; + + for (b = 0; b < 7; b++) + count[b] = offset[b + 1] - offset[b]; + count[7] = end - offset[7]; +} + +static void occ_build_recursive(OcclusionTree *tree, OccNode *node, int begin, int end, int depth); + +static void *exec_occ_build(void *data) +{ + OcclusionBuildThread *othread = (OcclusionBuildThread *)data; + + occ_build_recursive(othread->tree, othread->node, othread->begin, othread->end, othread->depth); + + return NULL; +} + +static void occ_build_recursive(OcclusionTree *tree, OccNode *node, int begin, int end, int depth) +{ + ListBase threads; + OcclusionBuildThread othreads[BLENDER_MAX_THREADS]; + OccNode *child, tmpnode; + /* OccFace *face; */ + int a, b, totthread = 0, offset[TOTCHILD], count[TOTCHILD]; + + /* add a new node */ + node->occlusion = 1.0f; + + /* leaf node with only children */ + if (end - begin <= TOTCHILD) { + for (a = begin, b = 0; a < end; a++, b++) { + /* face= &tree->face[a]; */ + node->child[b].face = a; + node->childflag |= (1 << b); + } + } + else { + /* order faces */ + occ_build_8_split(tree, begin, end, offset, count); + + if (depth == 1 && tree->dothreadedbuild) + BLI_threadpool_init(&threads, exec_occ_build, tree->totbuildthread); + + for (b = 0; b < TOTCHILD; b++) { + if (count[b] == 0) { + node->child[b].node = NULL; + } + else if (count[b] == 1) { + /* face= &tree->face[offset[b]]; */ + node->child[b].face = offset[b]; + node->childflag |= (1 << b); + } + else { + if (tree->dothreadedbuild) + BLI_thread_lock(LOCK_CUSTOM1); + + child = BLI_memarena_alloc(tree->arena, sizeof(OccNode)); + node->child[b].node = child; + + /* keep track of maximum depth for stack */ + if (depth >= tree->maxdepth) + tree->maxdepth = depth + 1; + + if (tree->dothreadedbuild) + BLI_thread_unlock(LOCK_CUSTOM1); + + if (depth == 1 && tree->dothreadedbuild) { + othreads[totthread].tree = tree; + othreads[totthread].node = child; + othreads[totthread].begin = offset[b]; + othreads[totthread].end = offset[b] + count[b]; + othreads[totthread].depth = depth + 1; + BLI_threadpool_insert(&threads, &othreads[totthread]); + totthread++; + } + else + occ_build_recursive(tree, child, offset[b], offset[b] + count[b], depth + 1); + } + } + + if (depth == 1 && tree->dothreadedbuild) + BLI_threadpool_end(&threads); + } + + /* combine area, position and sh */ + for (b = 0; b < TOTCHILD; b++) { + if (node->childflag & (1 << b)) { + child = &tmpnode; + occ_node_from_face(tree->face + node->child[b].face, &tmpnode); + } + else { + child = node->child[b].node; + } + + if (child) { + node->area += child->area; + sh_add(node->sh, node->sh, child->sh); + madd_v3_v3fl(node->co, child->co, child->area); + } + } + + if (node->area != 0.0f) + mul_v3_fl(node->co, 1.0f / node->area); + + /* compute maximum distance from center */ + node->dco = 0.0f; + if (node->area > 0.0f) + occ_build_dco(tree, node, node->co, &node->dco); +} + +static void occ_build_sh_normalize(OccNode *node) +{ + /* normalize spherical harmonics to not include area, so + * we can clamp the dot product and then multiply by area */ + int b; + + if (node->area != 0.0f) + sh_mul(node->sh, 1.0f / node->area); + + for (b = 0; b < TOTCHILD; b++) { + if (node->childflag & (1 << b)) { + /* pass */ + } + else if (node->child[b].node) { + occ_build_sh_normalize(node->child[b].node); + } + } +} + +static OcclusionTree *occ_tree_build(Render *re) +{ + const int num_threads = re->r.threads; + OcclusionTree *tree; + ObjectInstanceRen *obi; + ObjectRen *obr; + Material *ma; + VlakRen *vlr = NULL; + int a, b, c, totface; + + /* count */ + totface = 0; + for (obi = re->instancetable.first; obi; obi = obi->next) { + obr = obi->obr; + for (a = 0; a < obr->totvlak; a++) { + if ((a & 255) == 0) vlr = obr->vlaknodes[a >> 8].vlak; + else vlr++; + + ma = vlr->mat; + + if ((ma->shade_flag & MA_APPROX_OCCLUSION) && (ma->material_type == MA_TYPE_SURFACE)) + totface++; + } + } + + if (totface == 0) + return NULL; + + tree = MEM_callocN(sizeof(OcclusionTree), "OcclusionTree"); + tree->totface = totface; + + /* parameters */ + tree->error = get_render_aosss_error(&re->r, re->wrld.ao_approx_error); + tree->distfac = (re->wrld.aomode & WO_AODIST) ? re->wrld.aodistfac : 0.0f; + tree->doindirect = (re->wrld.ao_indirect_energy > 0.0f && re->wrld.ao_indirect_bounces > 0); + + /* allocation */ + tree->arena = BLI_memarena_new(0x8000 * sizeof(OccNode), "occ tree arena"); + BLI_memarena_use_calloc(tree->arena); + + if (re->wrld.aomode & WO_AOCACHE) + tree->cache = MEM_callocN(sizeof(OcclusionCache) * num_threads, "OcclusionCache"); + + tree->face = MEM_callocN(sizeof(OccFace) * totface, "OcclusionFace"); + tree->co = MEM_callocN(sizeof(float) * 3 * totface, "OcclusionCo"); + tree->occlusion = MEM_callocN(sizeof(float) * totface, "OcclusionOcclusion"); + + if (tree->doindirect) + tree->rad = MEM_callocN(sizeof(float) * 3 * totface, "OcclusionRad"); + + /* make array of face pointers */ + for (b = 0, c = 0, obi = re->instancetable.first; obi; obi = obi->next, c++) { + obr = obi->obr; + for (a = 0; a < obr->totvlak; a++) { + if ((a & 255) == 0) vlr = obr->vlaknodes[a >> 8].vlak; + else vlr++; + + ma = vlr->mat; + + if ((ma->shade_flag & MA_APPROX_OCCLUSION) && (ma->material_type == MA_TYPE_SURFACE)) { + tree->face[b].obi = c; + tree->face[b].facenr = a; + tree->occlusion[b] = 1.0f; + occ_face(&tree->face[b], tree->co[b], NULL, NULL); + b++; + } + } + } + + /* threads */ + tree->totbuildthread = (re->r.threads > 1 && totface > 10000) ? 8 : 1; + tree->dothreadedbuild = (tree->totbuildthread > 1); + + /* recurse */ + tree->root = BLI_memarena_alloc(tree->arena, sizeof(OccNode)); + tree->maxdepth = 1; + occ_build_recursive(tree, tree->root, 0, totface, 1); + + if (tree->doindirect) { + if (!(re->test_break(re->tbh))) + occ_build_shade(re, tree); + + if (!(re->test_break(re->tbh))) + occ_sum_occlusion(tree, tree->root); + } + + MEM_freeN(tree->co); + tree->co = NULL; + + if (!(re->test_break(re->tbh))) + occ_build_sh_normalize(tree->root); + + for (a = 0; a < num_threads; a++) + tree->stack[a] = MEM_callocN(sizeof(OccNode) * TOTCHILD * (tree->maxdepth + 1), "OccStack"); + + tree->num_threads = num_threads; + + return tree; +} + +static void occ_free_tree(OcclusionTree *tree) +{ + int a; + + if (tree) { + if (tree->arena) BLI_memarena_free(tree->arena); + for (a = 0; a < tree->num_threads; a++) + if (tree->stack[a]) + MEM_freeN(tree->stack[a]); + if (tree->occlusion) MEM_freeN(tree->occlusion); + if (tree->cache) MEM_freeN(tree->cache); + if (tree->face) MEM_freeN(tree->face); + if (tree->rad) MEM_freeN(tree->rad); + MEM_freeN(tree); + } +} + +/* ------------------------- Traversal --------------------------- */ + +static float occ_solid_angle(OccNode *node, const float v[3], float d2, float invd2, const float receivenormal[3]) +{ + float dotreceive, dotemit; + float ev[3]; + + ev[0] = -v[0] * invd2; + ev[1] = -v[1] * invd2; + ev[2] = -v[2] * invd2; + dotemit = sh_eval(node->sh, ev); + dotreceive = dot_v3v3(receivenormal, v) * invd2; + + CLAMP(dotemit, 0.0f, 1.0f); + CLAMP(dotreceive, 0.0f, 1.0f); + + return ((node->area * dotemit * dotreceive) / (d2 + node->area * INVPI)) * INVPI; +} + +static float occ_form_factor(OccFace *face, float *p, float *n) +{ + ObjectInstanceRen *obi; + VlakRen *vlr; + float v1[3], v2[3], v3[3], v4[3], q0[3], q1[3], q2[3], q3[3], contrib = 0.0f; + + obi = &R.objectinstance[face->obi]; + vlr = RE_findOrAddVlak(obi->obr, face->facenr); + + copy_v3_v3(v1, vlr->v1->co); + copy_v3_v3(v2, vlr->v2->co); + copy_v3_v3(v3, vlr->v3->co); + + if (obi->flag & R_TRANSFORMED) { + mul_m4_v3(obi->mat, v1); + mul_m4_v3(obi->mat, v2); + mul_m4_v3(obi->mat, v3); + } + + if (form_factor_visible_quad(p, n, v1, v2, v3, q0, q1, q2, q3)) + contrib += form_factor_quad(p, n, q0, q1, q2, q3); + + if (vlr->v4) { + copy_v3_v3(v4, vlr->v4->co); + if (obi->flag & R_TRANSFORMED) + mul_m4_v3(obi->mat, v4); + + if (form_factor_visible_quad(p, n, v1, v3, v4, q0, q1, q2, q3)) + contrib += form_factor_quad(p, n, q0, q1, q2, q3); + } + + return contrib; +} + +static void occ_lookup(OcclusionTree *tree, int thread, OccFace *exclude, + const float pp[3], const float pn[3], float *occ, float rad[3], float bentn[3]) +{ + OccNode *node, **stack; + OccFace *face; + float resultocc, resultrad[3], v[3], p[3], n[3], co[3], invd2; + float distfac, fac, error, d2, weight, emitarea; + int b, f, totstack; + + /* init variables */ + copy_v3_v3(p, pp); + copy_v3_v3(n, pn); + madd_v3_v3fl(p, n, 1e-4f); + + if (bentn) + copy_v3_v3(bentn, n); + + error = tree->error; + distfac = tree->distfac; + + resultocc = 0.0f; + zero_v3(resultrad); + + /* init stack */ + stack = tree->stack[thread]; + stack[0] = tree->root; + totstack = 1; + + while (totstack) { + /* pop point off the stack */ + node = stack[--totstack]; + + sub_v3_v3v3(v, node->co, p); + d2 = dot_v3v3(v, v) + 1e-16f; + emitarea = MAX2(node->area, node->dco); + + if (d2 * error > emitarea) { + if (distfac != 0.0f) { + fac = 1.0f / (1.0f + distfac * d2); + if (fac < 0.01f) + continue; + } + else + fac = 1.0f; + + /* accumulate occlusion from spherical harmonics */ + invd2 = 1.0f / sqrtf(d2); + weight = occ_solid_angle(node, v, d2, invd2, n); + + if (rad) + madd_v3_v3fl(resultrad, node->rad, weight * fac); + + weight *= node->occlusion; + + if (bentn) { + bentn[0] -= weight * invd2 * v[0]; + bentn[1] -= weight * invd2 * v[1]; + bentn[2] -= weight * invd2 * v[2]; + } + + resultocc += weight * fac; + } + else { + /* traverse into children */ + for (b = 0; b < TOTCHILD; b++) { + if (node->childflag & (1 << b)) { + f = node->child[b].face; + face = &tree->face[f]; + + /* accumulate occlusion with face form factor */ + if (!exclude || !(face->obi == exclude->obi && face->facenr == exclude->facenr)) { + if (bentn || distfac != 0.0f) { + occ_face(face, co, NULL, NULL); + sub_v3_v3v3(v, co, p); + d2 = dot_v3v3(v, v) + 1e-16f; + + fac = (distfac == 0.0f) ? 1.0f : 1.0f / (1.0f + distfac * d2); + if (fac < 0.01f) + continue; + } + else + fac = 1.0f; + + weight = occ_form_factor(face, p, n); + + if (rad) + madd_v3_v3fl(resultrad, tree->rad[f], weight * fac); + + weight *= tree->occlusion[f]; + + if (bentn) { + invd2 = 1.0f / sqrtf(d2); + bentn[0] -= weight * invd2 * v[0]; + bentn[1] -= weight * invd2 * v[1]; + bentn[2] -= weight * invd2 * v[2]; + } + + resultocc += weight * fac; + } + } + else if (node->child[b].node) { + /* push child on the stack */ + stack[totstack++] = node->child[b].node; + } + } + } + } + + if (occ) *occ = resultocc; + if (rad) copy_v3_v3(rad, resultrad); +#if 0 + if (rad && exclude) { + int a; + for (a = 0; a < tree->totface; a++) + if ((tree->face[a].obi == exclude->obi && tree->face[a].facenr == exclude->facenr)) + copy_v3_v3(rad, tree->rad[a]); + } +#endif + if (bentn) normalize_v3(bentn); +} + +static void occ_compute_bounces(Render *re, OcclusionTree *tree, int totbounce) +{ + float (*rad)[3], (*sum)[3], (*tmp)[3], co[3], n[3], occ; + int bounce, i; + + rad = MEM_callocN(sizeof(float) * 3 * tree->totface, "OcclusionBounceRad"); + sum = MEM_dupallocN(tree->rad); + + for (bounce = 1; bounce < totbounce; bounce++) { + for (i = 0; i < tree->totface; i++) { + occ_face(&tree->face[i], co, n, NULL); + madd_v3_v3fl(co, n, 1e-8f); + + occ_lookup(tree, 0, &tree->face[i], co, n, &occ, rad[i], NULL); + rad[i][0] = MAX2(rad[i][0], 0.0f); + rad[i][1] = MAX2(rad[i][1], 0.0f); + rad[i][2] = MAX2(rad[i][2], 0.0f); + add_v3_v3(sum[i], rad[i]); + + if (re->test_break(re->tbh)) + break; + } + + if (re->test_break(re->tbh)) + break; + + tmp = tree->rad; + tree->rad = rad; + rad = tmp; + + occ_sum_occlusion(tree, tree->root); + } + + MEM_freeN(rad); + MEM_freeN(tree->rad); + tree->rad = sum; + + if (!re->test_break(re->tbh)) + occ_sum_occlusion(tree, tree->root); +} + +static void occ_compute_passes(Render *re, OcclusionTree *tree, int totpass) +{ + float *occ, co[3], n[3]; + int pass, i; + + occ = MEM_callocN(sizeof(float) * tree->totface, "OcclusionPassOcc"); + + for (pass = 0; pass < totpass; pass++) { + for (i = 0; i < tree->totface; i++) { + occ_face(&tree->face[i], co, n, NULL); + negate_v3(n); + madd_v3_v3fl(co, n, 1e-8f); + + occ_lookup(tree, 0, &tree->face[i], co, n, &occ[i], NULL, NULL); + if (re->test_break(re->tbh)) + break; + } + + if (re->test_break(re->tbh)) + break; + + for (i = 0; i < tree->totface; i++) { + tree->occlusion[i] -= occ[i]; //MAX2(1.0f-occ[i], 0.0f); + if (tree->occlusion[i] < 0.0f) + tree->occlusion[i] = 0.0f; + } + + occ_sum_occlusion(tree, tree->root); + } + + MEM_freeN(occ); +} + +static void sample_occ_tree(Render *re, OcclusionTree *tree, OccFace *exclude, + const float co[3], const float n[3], int thread, int onlyshadow, + float *ao, float *env, float *indirect) +{ + float nn[3], bn[3], fac, occ, occlusion, correction, rad[3]; + int envcolor; + + envcolor = re->wrld.aocolor; + if (onlyshadow) + envcolor = WO_AOPLAIN; + + negate_v3_v3(nn, n); + + occ_lookup(tree, thread, exclude, co, nn, &occ, (tree->doindirect) ? rad : NULL, (env && envcolor) ? bn : NULL); + + correction = re->wrld.ao_approx_correction; + + occlusion = (1.0f - correction) * (1.0f - occ); + CLAMP(occlusion, 0.0f, 1.0f); + if (correction != 0.0f) + occlusion += correction * expf(-occ); + + if (env) { + /* sky shading using bent normal */ + if (ELEM(envcolor, WO_AOSKYCOL, WO_AOSKYTEX)) { + fac = 0.5f * (1.0f + dot_v3v3(bn, re->grvec)); + env[0] = (1.0f - fac) * re->wrld.horr + fac * re->wrld.zenr; + env[1] = (1.0f - fac) * re->wrld.horg + fac * re->wrld.zeng; + env[2] = (1.0f - fac) * re->wrld.horb + fac * re->wrld.zenb; + + mul_v3_fl(env, occlusion); + } + else { + env[0] = occlusion; + env[1] = occlusion; + env[2] = occlusion; + } +#if 0 + else { /* WO_AOSKYTEX */ + float dxyview[3]; + bn[0] = -bn[0]; + bn[1] = -bn[1]; + bn[2] = -bn[2]; + dxyview[0] = 1.0f; + dxyview[1] = 1.0f; + dxyview[2] = 0.0f; + shadeSkyView(ao, co, bn, dxyview); + } +#endif + } + + if (ao) { + ao[0] = occlusion; + ao[1] = occlusion; + ao[2] = occlusion; + } + + if (tree->doindirect) copy_v3_v3(indirect, rad); + else zero_v3(indirect); +} + +/* ---------------------------- Caching ------------------------------- */ + +static OcclusionCacheSample *find_occ_sample(OcclusionCache *cache, int x, int y) +{ + x -= cache->x; + y -= cache->y; + + x /= cache->step; + y /= cache->step; + x *= cache->step; + y *= cache->step; + + if (x < 0 || x >= cache->w || y < 0 || y >= cache->h) + return NULL; + else + return &cache->sample[y * cache->w + x]; +} + +static int sample_occ_cache(OcclusionTree *tree, float *co, float *n, int x, int y, int thread, float *ao, float *env, float *indirect) +{ + OcclusionCache *cache; + OcclusionCacheSample *samples[4], *sample; + float wn[4], wz[4], wb[4], tx, ty, w, totw, mino, maxo; + float d[3], dist2; + int i, x1, y1, x2, y2; + + if (!tree->cache) + return 0; + + /* first try to find a sample in the same pixel */ + cache = &tree->cache[thread]; + + if (cache->sample && cache->step) { + sample = &cache->sample[(y - cache->y) * cache->w + (x - cache->x)]; + if (sample->filled) { + sub_v3_v3v3(d, sample->co, co); + dist2 = dot_v3v3(d, d); + if (dist2 < 0.5f * sample->dist2 && dot_v3v3(sample->n, n) > 0.98f) { + copy_v3_v3(ao, sample->ao); + copy_v3_v3(env, sample->env); + copy_v3_v3(indirect, sample->indirect); + return 1; + } + } + } + else + return 0; + + /* try to interpolate between 4 neighboring pixels */ + samples[0] = find_occ_sample(cache, x, y); + samples[1] = find_occ_sample(cache, x + cache->step, y); + samples[2] = find_occ_sample(cache, x, y + cache->step); + samples[3] = find_occ_sample(cache, x + cache->step, y + cache->step); + + for (i = 0; i < 4; i++) + if (!samples[i] || !samples[i]->filled) + return 0; + + /* require intensities not being too different */ + mino = min_ffff(samples[0]->intensity, samples[1]->intensity, samples[2]->intensity, samples[3]->intensity); + maxo = max_ffff(samples[0]->intensity, samples[1]->intensity, samples[2]->intensity, samples[3]->intensity); + + if (maxo - mino > 0.05f) + return 0; + + /* compute weighted interpolation between samples */ + zero_v3(ao); + zero_v3(env); + zero_v3(indirect); + totw = 0.0f; + + x1 = samples[0]->x; + y1 = samples[0]->y; + x2 = samples[3]->x; + y2 = samples[3]->y; + + tx = (float)(x2 - x) / (float)(x2 - x1); + ty = (float)(y2 - y) / (float)(y2 - y1); + + wb[3] = (1.0f - tx) * (1.0f - ty); + wb[2] = (tx) * (1.0f - ty); + wb[1] = (1.0f - tx) * (ty); + wb[0] = tx * ty; + + for (i = 0; i < 4; i++) { + sub_v3_v3v3(d, samples[i]->co, co); + //dist2 = dot_v3v3(d, d); + + wz[i] = 1.0f; //(samples[i]->dist2/(1e-4f + dist2)); + wn[i] = pow(dot_v3v3(samples[i]->n, n), 32.0f); + + w = wb[i] * wn[i] * wz[i]; + + totw += w; + madd_v3_v3fl(ao, samples[i]->ao, w); + madd_v3_v3fl(env, samples[i]->env, w); + madd_v3_v3fl(indirect, samples[i]->indirect, w); + } + + if (totw >= 0.9f) { + totw = 1.0f / totw; + mul_v3_fl(ao, totw); + mul_v3_fl(env, totw); + mul_v3_fl(indirect, totw); + return 1; + } + + return 0; +} + +static void sample_occ_surface(ShadeInput *shi) +{ + StrandRen *strand = shi->strand; + StrandSurface *mesh = strand->buffer->surface; + const int *face, *index = RE_strandren_get_face(shi->obr, strand, 0); + float w[4], *co1, *co2, *co3, *co4; + + if (mesh && mesh->face && mesh->co && mesh->ao && index) { + face = mesh->face[*index]; + + co1 = mesh->co[face[0]]; + co2 = mesh->co[face[1]]; + co3 = mesh->co[face[2]]; + + if (face[3]) { + co4 = mesh->co[face[3]]; + interp_weights_quad_v3(w, co1, co2, co3, co4, strand->vert->co); + } + else { + interp_weights_tri_v3(w, co1, co2, co3, strand->vert->co); + } + + zero_v3(shi->ao); + zero_v3(shi->env); + zero_v3(shi->indirect); + + madd_v3_v3fl(shi->ao, mesh->ao[face[0]], w[0]); + madd_v3_v3fl(shi->env, mesh->env[face[0]], w[0]); + madd_v3_v3fl(shi->indirect, mesh->indirect[face[0]], w[0]); + madd_v3_v3fl(shi->ao, mesh->ao[face[1]], w[1]); + madd_v3_v3fl(shi->env, mesh->env[face[1]], w[1]); + madd_v3_v3fl(shi->indirect, mesh->indirect[face[1]], w[1]); + madd_v3_v3fl(shi->ao, mesh->ao[face[2]], w[2]); + madd_v3_v3fl(shi->env, mesh->env[face[2]], w[2]); + madd_v3_v3fl(shi->indirect, mesh->indirect[face[2]], w[2]); + if (face[3]) { + madd_v3_v3fl(shi->ao, mesh->ao[face[3]], w[3]); + madd_v3_v3fl(shi->env, mesh->env[face[3]], w[3]); + madd_v3_v3fl(shi->indirect, mesh->indirect[face[3]], w[3]); + } + } + else { + shi->ao[0] = 1.0f; + shi->ao[1] = 1.0f; + shi->ao[2] = 1.0f; + zero_v3(shi->env); + zero_v3(shi->indirect); + } +} + +/* ------------------------- External Functions --------------------------- */ + +static void *exec_strandsurface_sample(void *data) +{ + OcclusionThread *othread = (OcclusionThread *)data; + Render *re = othread->re; + StrandSurface *mesh = othread->mesh; + float ao[3], env[3], indirect[3], co[3], n[3], *co1, *co2, *co3, *co4; + int a, *face; + + for (a = othread->begin; a < othread->end; a++) { + face = mesh->face[a]; + co1 = mesh->co[face[0]]; + co2 = mesh->co[face[1]]; + co3 = mesh->co[face[2]]; + + if (face[3]) { + co4 = mesh->co[face[3]]; + + mid_v3_v3v3(co, co1, co3); + normal_quad_v3(n, co1, co2, co3, co4); + } + else { + mid_v3_v3v3v3(co, co1, co2, co3); + normal_tri_v3(n, co1, co2, co3); + } + negate_v3(n); + + sample_occ_tree(re, re->occlusiontree, NULL, co, n, othread->thread, 0, ao, env, indirect); + copy_v3_v3(othread->faceao[a], ao); + copy_v3_v3(othread->faceenv[a], env); + copy_v3_v3(othread->faceindirect[a], indirect); + } + + return NULL; +} + +void make_occ_tree(Render *re) +{ + OcclusionThread othreads[BLENDER_MAX_THREADS]; + OcclusionTree *tree; + StrandSurface *mesh; + ListBase threads; + float ao[3], env[3], indirect[3], (*faceao)[3], (*faceenv)[3], (*faceindirect)[3]; + int a, totface, totthread, *face, *count; + + /* ugly, needed for occ_face */ + R = *re; + + re->i.infostr = IFACE_("Occlusion preprocessing"); + re->stats_draw(re->sdh, &re->i); + + re->occlusiontree = tree = occ_tree_build(re); + + if (tree && !re->test_break(re->tbh)) { + if (re->wrld.ao_approx_passes > 0) + occ_compute_passes(re, tree, re->wrld.ao_approx_passes); + if (tree->doindirect && (re->wrld.mode & WO_INDIRECT_LIGHT)) + occ_compute_bounces(re, tree, re->wrld.ao_indirect_bounces); + + for (mesh = re->strandsurface.first; mesh; mesh = mesh->next) { + if (!mesh->face || !mesh->co || !mesh->ao) + continue; + + count = MEM_callocN(sizeof(int) * mesh->totvert, "OcclusionCount"); + faceao = MEM_callocN(sizeof(float) * 3 * mesh->totface, "StrandSurfFaceAO"); + faceenv = MEM_callocN(sizeof(float) * 3 * mesh->totface, "StrandSurfFaceEnv"); + faceindirect = MEM_callocN(sizeof(float) * 3 * mesh->totface, "StrandSurfFaceIndirect"); + + totthread = (mesh->totface > 10000) ? re->r.threads : 1; + totface = mesh->totface / totthread; + for (a = 0; a < totthread; a++) { + othreads[a].re = re; + othreads[a].faceao = faceao; + othreads[a].faceenv = faceenv; + othreads[a].faceindirect = faceindirect; + othreads[a].thread = a; + othreads[a].mesh = mesh; + othreads[a].begin = a * totface; + othreads[a].end = (a == totthread - 1) ? mesh->totface : (a + 1) * totface; + } + + if (totthread == 1) { + exec_strandsurface_sample(&othreads[0]); + } + else { + BLI_threadpool_init(&threads, exec_strandsurface_sample, totthread); + + for (a = 0; a < totthread; a++) + BLI_threadpool_insert(&threads, &othreads[a]); + + BLI_threadpool_end(&threads); + } + + for (a = 0; a < mesh->totface; a++) { + face = mesh->face[a]; + + copy_v3_v3(ao, faceao[a]); + copy_v3_v3(env, faceenv[a]); + copy_v3_v3(indirect, faceindirect[a]); + + add_v3_v3(mesh->ao[face[0]], ao); + add_v3_v3(mesh->env[face[0]], env); + add_v3_v3(mesh->indirect[face[0]], indirect); + count[face[0]]++; + add_v3_v3(mesh->ao[face[1]], ao); + add_v3_v3(mesh->env[face[1]], env); + add_v3_v3(mesh->indirect[face[1]], indirect); + count[face[1]]++; + add_v3_v3(mesh->ao[face[2]], ao); + add_v3_v3(mesh->env[face[2]], env); + add_v3_v3(mesh->indirect[face[2]], indirect); + count[face[2]]++; + + if (face[3]) { + add_v3_v3(mesh->ao[face[3]], ao); + add_v3_v3(mesh->env[face[3]], env); + add_v3_v3(mesh->indirect[face[3]], indirect); + count[face[3]]++; + } + } + + for (a = 0; a < mesh->totvert; a++) { + if (count[a]) { + mul_v3_fl(mesh->ao[a], 1.0f / count[a]); + mul_v3_fl(mesh->env[a], 1.0f / count[a]); + mul_v3_fl(mesh->indirect[a], 1.0f / count[a]); + } + } + + MEM_freeN(count); + MEM_freeN(faceao); + MEM_freeN(faceenv); + MEM_freeN(faceindirect); + } + } +} + +void free_occ(Render *re) +{ + if (re->occlusiontree) { + occ_free_tree(re->occlusiontree); + re->occlusiontree = NULL; + } +} + +void sample_occ(Render *re, ShadeInput *shi) +{ + OcclusionTree *tree = re->occlusiontree; + OcclusionCache *cache; + OcclusionCacheSample *sample; + OccFace exclude; + int onlyshadow; + + if (tree) { + if (shi->strand) { + sample_occ_surface(shi); + } + /* try to get result from the cache if possible */ + else if (shi->depth != 0 || !sample_occ_cache(tree, shi->co, shi->vno, shi->xs, shi->ys, shi->thread, shi->ao, shi->env, shi->indirect)) { + /* no luck, let's sample the occlusion */ + exclude.obi = shi->obi - re->objectinstance; + exclude.facenr = shi->vlr->index; + onlyshadow = (shi->mat->mode & MA_ONLYSHADOW); + sample_occ_tree(re, tree, &exclude, shi->co, shi->vno, shi->thread, onlyshadow, shi->ao, shi->env, shi->indirect); + + /* fill result into sample, each time */ + if (tree->cache) { + cache = &tree->cache[shi->thread]; + + if (cache->sample && cache->step) { + sample = &cache->sample[(shi->ys - cache->y) * cache->w + (shi->xs - cache->x)]; + copy_v3_v3(sample->co, shi->co); + copy_v3_v3(sample->n, shi->vno); + copy_v3_v3(sample->ao, shi->ao); + copy_v3_v3(sample->env, shi->env); + copy_v3_v3(sample->indirect, shi->indirect); + sample->intensity = max_fff(sample->ao[0], sample->ao[1], sample->ao[2]); + sample->intensity = max_ff(sample->intensity, max_fff(sample->env[0], sample->env[1], sample->env[2])); + sample->intensity = max_ff(sample->intensity, max_fff(sample->indirect[0], sample->indirect[1], sample->indirect[2])); + sample->dist2 = dot_v3v3(shi->dxco, shi->dxco) + dot_v3v3(shi->dyco, shi->dyco); + sample->filled = 1; + } + } + } + } + else { + shi->ao[0] = 1.0f; + shi->ao[1] = 1.0f; + shi->ao[2] = 1.0f; + + shi->env[0] = 0.0f; + shi->env[1] = 0.0f; + shi->env[2] = 0.0f; + + shi->indirect[0] = 0.0f; + shi->indirect[1] = 0.0f; + shi->indirect[2] = 0.0f; + } +} + +void cache_occ_samples(Render *re, RenderPart *pa, ShadeSample *ssamp) +{ + OcclusionTree *tree = re->occlusiontree; + PixStr ps; + OcclusionCache *cache; + OcclusionCacheSample *sample; + OccFace exclude; + ShadeInput *shi; + intptr_t *rd = NULL; + int *ro = NULL, *rp = NULL, *rz = NULL, onlyshadow; + int x, y, step = CACHE_STEP; + + if (!tree->cache) + return; + + cache = &tree->cache[pa->thread]; + cache->w = pa->rectx; + cache->h = pa->recty; + cache->x = pa->disprect.xmin; + cache->y = pa->disprect.ymin; + cache->step = step; + cache->sample = MEM_callocN(sizeof(OcclusionCacheSample) * cache->w * cache->h, "OcclusionCacheSample"); + sample = cache->sample; + + if (re->osa) { + rd = pa->rectdaps; + } + else { + /* fake pixel struct for non-osa */ + ps.next = NULL; + ps.mask = 0xFFFF; + + ro = pa->recto; + rp = pa->rectp; + rz = pa->rectz; + } + + /* compute a sample at every step pixels */ + for (y = pa->disprect.ymin; y < pa->disprect.ymax; y++) { + for (x = pa->disprect.xmin; x < pa->disprect.xmax; x++, sample++, rd++, ro++, rp++, rz++) { + if (!(((x - pa->disprect.xmin + step) % step) == 0 || x == pa->disprect.xmax - 1)) + continue; + if (!(((y - pa->disprect.ymin + step) % step) == 0 || y == pa->disprect.ymax - 1)) + continue; + + if (re->osa) { + if (!*rd) continue; + + shade_samples_fill_with_ps(ssamp, (PixStr *)(*rd), x, y); + } + else { + if (!*rp) continue; + + ps.obi = *ro; + ps.facenr = *rp; + ps.z = *rz; + shade_samples_fill_with_ps(ssamp, &ps, x, y); + } + + shi = ssamp->shi; + if (shi->vlr) { + onlyshadow = (shi->mat->mode & MA_ONLYSHADOW); + exclude.obi = shi->obi - re->objectinstance; + exclude.facenr = shi->vlr->index; + sample_occ_tree(re, tree, &exclude, shi->co, shi->vno, shi->thread, onlyshadow, shi->ao, shi->env, shi->indirect); + + copy_v3_v3(sample->co, shi->co); + copy_v3_v3(sample->n, shi->vno); + copy_v3_v3(sample->ao, shi->ao); + copy_v3_v3(sample->env, shi->env); + copy_v3_v3(sample->indirect, shi->indirect); + sample->intensity = max_fff(sample->ao[0], sample->ao[1], sample->ao[2]); + sample->intensity = max_ff(sample->intensity, max_fff(sample->env[0], sample->env[1], sample->env[2])); + sample->intensity = max_ff(sample->intensity, max_fff(sample->indirect[0], sample->indirect[1], sample->indirect[2])); + sample->dist2 = dot_v3v3(shi->dxco, shi->dxco) + dot_v3v3(shi->dyco, shi->dyco); + sample->x = shi->xs; + sample->y = shi->ys; + sample->filled = 1; + } + + if (re->test_break(re->tbh)) + break; + } + } +} + +void free_occ_samples(Render *re, RenderPart *pa) +{ + OcclusionTree *tree = re->occlusiontree; + OcclusionCache *cache; + + if (tree->cache) { + cache = &tree->cache[pa->thread]; + + if (cache->sample) + MEM_freeN(cache->sample); + + cache->w = 0; + cache->h = 0; + cache->step = 0; + } +} + diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c index 595640489c8..c9f13004836 100644 --- a/source/blender/render/intern/source/pipeline.c +++ b/source/blender/render/intern/source/pipeline.c @@ -137,7 +137,7 @@ /* here we store all renders */ static struct { ListBase renderlist; -} RenderGlobal = {{NULL, NULL}}; +} RenderGlobal = {{NULL, NULL}}; /* ********* alloc and free ******** */ @@ -424,10 +424,10 @@ void RE_AcquireResultImage(Render *re, RenderResult *rr, const int view_id) if (re->result) { RenderLayer *rl; RenderView *rv; - + rr->rectx = re->result->rectx; rr->recty = re->result->recty; - + /* actview view */ rv = RE_RenderViewGetById(re->result, view_id); rr->have_combined = (rv->rectf != NULL); @@ -494,7 +494,7 @@ Render *RE_NewRender(const char *name) /* only one render per name exists */ re = RE_GetRender(name); if (re == NULL) { - + /* new render data struct */ re = MEM_callocN(sizeof(Render), "new render"); BLI_addtail(&RenderGlobal.renderlist, re); @@ -502,7 +502,7 @@ Render *RE_NewRender(const char *name) BLI_rw_mutex_init(&re->resultmutex); BLI_rw_mutex_init(&re->partsmutex); } - + RE_InitRenderCB(re); return re; @@ -574,10 +574,10 @@ void RE_FreeRender(Render *re) /* main dbase can already be invalid now, some database-free code checks it */ re->main = NULL; re->scene = NULL; - + render_result_free(re->result); render_result_free(re->pushedresult); - + BLI_remlink(&RenderGlobal.renderlist, re); MEM_freeN(re); } @@ -715,7 +715,7 @@ void RE_InitState(Render *re, Render *source, RenderData *rd, bool had_freestyle = (re->r.mode & R_EDGE_FRS) != 0; re->ok = true; /* maybe flag */ - + re->i.starttime = PIL_check_seconds_timer(); /* copy render data and render layers for thread safety */ @@ -753,7 +753,7 @@ void RE_InitState(Render *re, Render *source, RenderData *rd, } re->r.scemode = check_mode_full_sample(&re->r); - + if (single_layer) { int index = BLI_findindex(render_layers, single_layer); if (index != -1) { @@ -761,7 +761,7 @@ void RE_InitState(Render *re, Render *source, RenderData *rd, re->r.scemode |= R_SINGLE_LAYER; } } - + /* if preview render, we try to keep old result */ BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE); @@ -794,7 +794,7 @@ void RE_InitState(Render *re, Render *source, RenderData *rd, } } else { - + /* make empty render result, so display callbacks can initialize */ render_result_free(re->result); re->result = MEM_callocN(sizeof(RenderResult), "new render result"); @@ -811,7 +811,7 @@ void RE_InitState(Render *re, Render *source, RenderData *rd, RE_parts_clamp(re); BLI_rw_mutex_unlock(&re->resultmutex); - + RE_init_threadcount(re); RE_point_density_fix_linking(); @@ -925,7 +925,7 @@ void render_update_anim_renderdata(Render *re, RenderData *rd, ListBase *render_ void RE_SetWindow(Render *re, const rctf *viewplane, float clipsta, float clipend) { /* re->ok flag? */ - + re->viewplane = *viewplane; re->clipsta = clipsta; re->clipend = clipend; @@ -934,13 +934,13 @@ void RE_SetWindow(Render *re, const rctf *viewplane, float clipsta, float clipen perspective_m4(re->winmat, re->viewplane.xmin, re->viewplane.xmax, re->viewplane.ymin, re->viewplane.ymax, re->clipsta, re->clipend); - + } void RE_SetOrtho(Render *re, const rctf *viewplane, float clipsta, float clipend) { /* re->ok flag? */ - + re->viewplane = *viewplane; re->clipsta = clipsta; re->clipend = clipend; @@ -961,7 +961,7 @@ void RE_SetView(Render *re, float mat[4][4]) void RE_GetViewPlane(Render *re, rctf *r_viewplane, rcti *r_disprect) { *r_viewplane = re->viewplane; - + /* make disprect zero when no border render, is needed to detect changes in 3d view render */ if (re->r.mode & R_BORDER) { *r_disprect = re->disprect; @@ -1028,7 +1028,7 @@ void RE_test_break_cb(Render *re, void *handle, int (*f)(void *handle)) #if 0 void RE_AddObject(Render *UNUSED(re), Object *UNUSED(ob)) { - + } #endif @@ -1121,9 +1121,9 @@ static void do_render(Render *re) /* now use renderdata and camera to set viewplane */ RE_SetCamera(re, camera); - + do_render_3d(re); - + /* when border render, check if we have to insert it in black */ render_result_uncrop(re); } @@ -1136,7 +1136,7 @@ static void render_scene(Render *re, Scene *sce, int cfra) { Render *resc = RE_NewSceneRender(sce); int winx = re->winx, winy = re->winy; - + sce->r.cfra = cfra; BKE_scene_camera_switch_update(sce); @@ -1146,7 +1146,7 @@ static void render_scene(Render *re, Scene *sce, int cfra) winx = (sce->r.size * sce->r.xsch) / 100; winy = (sce->r.size * sce->r.ysch) / 100; } - + /* initial setup */ RE_InitState(resc, re, &sce->r, &sce->view_layers, NULL, winx, winy, &re->disprect); @@ -1157,7 +1157,7 @@ static void render_scene(Render *re, Scene *sce, int cfra) resc->main = re->main; resc->scene = sce; resc->lay = sce->lay; - + /* ensure scene has depsgraph, base flags etc OK */ BKE_scene_set_background(re->main, sce); @@ -1170,7 +1170,7 @@ static void render_scene(Render *re, Scene *sce, int cfra) resc->sdh = re->sdh; resc->current_scene_update = re->current_scene_update; resc->suh = re->suh; - + do_render(resc); } @@ -1179,11 +1179,11 @@ static int composite_needs_render(Scene *sce, int this_scene) { bNodeTree *ntree = sce->nodetree; bNode *node; - + if (ntree == NULL) return 1; if (sce->use_nodes == false) return 1; if ((sce->r.scemode & R_DOCOMP) == 0) return 1; - + for (node = ntree->nodes.first; node; node = node->next) { if (node->type == CMP_NODE_R_LAYERS && (node->flag & NODE_MUTED) == 0) if (this_scene == 0 || node->id == NULL || node->id == &sce->id) @@ -1334,14 +1334,14 @@ static void tag_scenes_for_render(Render *re) { bNode *node; Scene *sce; - + for (sce = re->main->scene.first; sce; sce = sce->id.next) { sce->id.tag &= ~LIB_TAG_DOIT; #ifdef DEPSGRAPH_WORKAROUND_HACK tag_dependend_objects_for_render(re->main, sce); #endif } - + #ifdef WITH_FREESTYLE if (re->freestyle_bmain) { for (sce = re->freestyle_bmain->scene.first; sce; sce = sce->id.next) { @@ -1359,9 +1359,9 @@ static void tag_scenes_for_render(Render *re) tag_dependend_objects_for_render(re->main, re->scene); #endif } - + if (re->scene->nodetree == NULL) return; - + /* check for render-layers nodes using other scenes, we tag them LIB_TAG_DOIT */ for (node = re->scene->nodetree->nodes.first; node; node = node->next) { node->flag &= ~NODE_TEST; @@ -1397,7 +1397,7 @@ static void tag_scenes_for_render(Render *re) } } } - + } static void ntree_render_scenes(Render *re) @@ -1406,15 +1406,15 @@ static void ntree_render_scenes(Render *re) int cfra = re->scene->r.cfra; Scene *restore_scene = re->scene; bool scene_changed = false; - + if (re->scene->nodetree == NULL) return; - + tag_scenes_for_render(re); #ifdef DEPSGRAPH_WORKAROUND_GROUP_HACK tag_collections_for_render(re); #endif - + /* now foreach render-result node tagged we do a full render */ /* results are stored in a way compisitor will find it */ for (node = re->scene->nodetree->nodes.first; node; node = node->next) { @@ -1426,7 +1426,7 @@ static void ntree_render_scenes(Render *re) scene_changed |= scene != restore_scene; render_scene(re, scene, cfra); node->flag &= ~NODE_TEST; - + nodeUpdate(restore_scene->nodetree, node); } } @@ -1531,10 +1531,10 @@ static void do_render_composite(Render *re) { bNodeTree *ntree = re->scene->nodetree; int update_newframe = 0; - + /* INIT seeding, compositor can use random texture */ BLI_srandom(re->r.cfra); - + if (composite_needs_render(re->scene, 1)) { /* save memory... free all cached images */ ntreeFreeCache(ntree); @@ -1550,7 +1550,7 @@ static void do_render_composite(Render *re) /* ensure new result gets added, like for regular renders */ BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE); - + render_result_free(re->result); if ((re->r.mode & R_CROP) == 0) { render_result_disprect_to_full_resolution(re); @@ -1558,30 +1558,30 @@ static void do_render_composite(Render *re) re->result = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS, RR_ALL_VIEWS); BLI_rw_mutex_unlock(&re->resultmutex); - + /* scene render process already updates animsys */ update_newframe = 1; } - + /* swap render result */ if (re->r.scemode & R_SINGLE_LAYER) { BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE); render_result_single_layer_end(re); BLI_rw_mutex_unlock(&re->resultmutex); } - + if (!re->test_break(re->tbh)) { - + if (ntree) { ntreeCompositTagRender(re->scene); ntreeCompositTagAnimated(ntree); } - + if (ntree && re->scene->use_nodes && re->r.scemode & R_DOCOMP) { /* checks if there are render-result nodes that need scene */ if ((re->r.scemode & R_SINGLE_LAYER) == 0) ntree_render_scenes(re); - + if (!re->test_break(re->tbh)) { ntree->stats_draw = render_composit_stats; ntree->test_break = re->test_break; @@ -1589,16 +1589,16 @@ static void do_render_composite(Render *re) ntree->sdh = re; ntree->tbh = re->tbh; ntree->prh = re->prh; - + if (update_newframe) { /* If we have consistent depsgraph now would be a time to update them. */ } - + RenderView *rv; for (rv = re->result->views.first; rv; rv = rv->next) { ntreeCompositExecTree(re->scene, ntree, &re->r, true, G.background == 0, &re->scene->view_settings, &re->scene->display_settings, rv->name); } - + ntree->stats_draw = NULL; ntree->test_break = NULL; ntree->progress = NULL; @@ -1651,15 +1651,15 @@ int RE_seq_render_active(Scene *scene, RenderData *rd) Sequence *seq; ed = scene->ed; - + if (!(rd->scemode & R_DOSEQ) || !ed || !ed->seqbase.first) return 0; - + for (seq = ed->seqbase.first; seq; seq = seq->next) { if (seq->type != SEQ_TYPE_SOUND_RAM) return 1; } - + return 0; } @@ -1810,18 +1810,18 @@ static void do_render_all_options(Render *re) do_render_seq(re); render_seq = true; } - + re->stats_draw(re->sdh, &re->i); re->display_update(re->duh, re->result, NULL); } else { do_render_composite(re); } - + re->i.lastframetime = PIL_check_seconds_timer() - re->i.starttime; - + re->stats_draw(re->sdh, &re->i); - + /* save render result stamp if needed */ if (re->result != NULL) { camera = RE_GetCamera(re); @@ -1975,7 +1975,7 @@ static int check_composite_output(Scene *scene) bool RE_is_rendering_allowed(Scene *scene, ViewLayer *single_layer, Object *camera_override, ReportList *reports) { int scemode = check_mode_full_sample(&scene->r); - + if (scene->r.mode & R_BORDER) { if (scene->r.border.xmax <= scene->r.border.xmin || scene->r.border.ymax <= scene->r.border.ymin) @@ -1984,30 +1984,30 @@ bool RE_is_rendering_allowed(Scene *scene, ViewLayer *single_layer, Object *came return 0; } } - + if (scemode & (R_EXR_TILE_FILE | R_FULL_SAMPLE)) { char str[FILE_MAX]; - + render_result_exr_file_path(scene, "", 0, str); - + if (!BLI_file_is_writable(str)) { BKE_report(reports, RPT_ERROR, "Cannot save render buffers, check the temp default path"); return 0; } } - + if (scemode & R_DOCOMP) { if (scene->use_nodes) { if (!scene->nodetree) { BKE_report(reports, RPT_ERROR, "No node tree in scene"); return 0; } - + if (!check_composite_output(scene)) { BKE_report(reports, RPT_ERROR, "No render output node in scene"); return 0; } - + if (scemode & R_FULL_SAMPLE) { if (composite_needs_render(scene, 0) == 0) { BKE_report(reports, RPT_ERROR, "Full sample AA not supported without 3D rendering"); @@ -2016,12 +2016,12 @@ bool RE_is_rendering_allowed(Scene *scene, ViewLayer *single_layer, Object *came } } } - + /* check valid camera, without camera render is OK (compo, seq) */ if (!check_valid_camera(scene, camera_override, reports)) { return 0; } - + /* get panorama & ortho, only after camera is set */ BKE_camera_object_mode(&scene->r, camera_override ? camera_override : scene->camera); @@ -2098,19 +2098,19 @@ static int render_initialize_from_main(Render *re, RenderData *rd, Main *bmain, { int winx, winy; rcti disprect; - + /* r.xsch and r.ysch has the actual view window size * r.border is the clipping rect */ - + /* calculate actual render result and display size */ winx = (rd->size * rd->xsch) / 100; winy = (rd->size * rd->ysch) / 100; - + /* we always render smaller part, inserting it in larger image is compositor bizz, it uses disprect for it */ if (scene->r.mode & R_BORDER) { disprect.xmin = rd->border.xmin * winx; disprect.xmax = rd->border.xmax * winx; - + disprect.ymin = rd->border.ymin * winy; disprect.ymax = rd->border.ymax * winy; } @@ -2119,7 +2119,7 @@ static int render_initialize_from_main(Render *re, RenderData *rd, Main *bmain, disprect.xmax = winx; disprect.ymax = winy; } - + re->main = bmain; re->scene = scene; re->camera_override = camera_override; @@ -2134,7 +2134,7 @@ static int render_initialize_from_main(Render *re, RenderData *rd, Main *bmain, re->disprect = disprect; return 1; } - + /* check all scenes involved */ tag_scenes_for_render(re); @@ -2153,17 +2153,17 @@ static int render_initialize_from_main(Render *re, RenderData *rd, Main *bmain, ViewLayer *view_layer = BKE_view_layer_context_active_PLACEHOLDER(scene); update_physics_cache(re, scene, view_layer, anim_init); } - + if (single_layer || scene->r.scemode & R_SINGLE_LAYER) { BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE); render_result_single_layer_begin(re); BLI_rw_mutex_unlock(&re->resultmutex); } - + RE_InitState(re, NULL, &scene->r, &scene->view_layers, single_layer, winx, winy, &disprect); if (!re->ok) /* if an error was printed, abort */ return 0; - + /* initstate makes new result, have to send changed tags around */ ntreeCompositTagRender(re->scene); @@ -2171,7 +2171,7 @@ static int render_initialize_from_main(Render *re, RenderData *rd, Main *bmain, re->display_init(re->dih, re->result); re->display_clear(re->dch, re->result); - + return 1; } @@ -2188,9 +2188,9 @@ void RE_BlenderFrame(Render *re, Main *bmain, Scene *scene, ViewLayer *single_la /* ugly global still... is to prevent preview events and signal subsurfs etc to make full resol */ G.is_rendering = true; - + scene->r.cfra = frame; - + if (render_initialize_from_main(re, &scene->r, bmain, scene, single_layer, camera_override, lay_override, 0, 0)) { @@ -2208,7 +2208,7 @@ void RE_BlenderFrame(Render *re, Main *bmain, Scene *scene, ViewLayer *single_la else { char name[FILE_MAX]; BKE_image_path_from_imformat( - name, scene->r.pic, bmain->name, scene->r.cfra, + name, scene->r.pic, BKE_main_blendfile_path(bmain), scene->r.cfra, &scene->r.im_format, (scene->r.scemode & R_EXTENSION) != 0, false, NULL); /* reports only used for Movie */ @@ -2467,18 +2467,18 @@ static int do_write_image_or_movie(Render *re, Main *bmain, Scene *scene, bMovie BLI_strncpy(name, name_override, sizeof(name)); else BKE_image_path_from_imformat( - name, scene->r.pic, bmain->name, scene->r.cfra, + name, scene->r.pic, BKE_main_blendfile_path(bmain), scene->r.cfra, &scene->r.im_format, (scene->r.scemode & R_EXTENSION) != 0, true, NULL); /* write images as individual images or stereo */ ok = RE_WriteRenderViewsImage(re->reports, &rres, scene, true, name); } - + RE_ReleaseResultImageViews(re, &rres); render_time = re->i.lastframetime; re->i.lastframetime = PIL_check_seconds_timer() - re->i.starttime; - + BLI_timecode_string_from_time_simple(name, sizeof(name), re->i.lastframetime); printf(" Time: %s", name); @@ -2489,7 +2489,7 @@ static int do_write_image_or_movie(Render *re, Main *bmain, Scene *scene, bMovie BLI_timecode_string_from_time_simple(name, sizeof(name), re->i.lastframetime - render_time); printf(" (Saving: %s)\n", name); - + fputc('\n', stdout); fflush(stdout); /* needed for renderd !! (not anymore... (ton)) */ @@ -2647,7 +2647,7 @@ void RE_BlenderAnim(Render *re, Main *bmain, Scene *scene, Object *camera_overri if (is_movie == false) { if (scene->r.mode & (R_NO_OVERWRITE | R_TOUCH)) BKE_image_path_from_imformat( - name, scene->r.pic, bmain->name, scene->r.cfra, + name, scene->r.pic, BKE_main_blendfile_path(bmain), scene->r.cfra, &scene->r.im_format, (scene->r.scemode & R_EXTENSION) != 0, true, NULL); if (scene->r.mode & R_NO_OVERWRITE) { @@ -2713,10 +2713,10 @@ void RE_BlenderAnim(Render *re, Main *bmain, Scene *scene, Object *camera_overri /* run callbacs before rendering, before the scene is updated */ BLI_callback_exec(re->main, (ID *)scene, BLI_CB_EVT_RENDER_PRE); - + do_render_all_options(re); totrendered++; - + if (re->test_break(re->tbh) == 0) { if (!G.is_break) if (!do_write_image_or_movie(re, bmain, scene, mh, totvideos, NULL)) @@ -2724,7 +2724,7 @@ void RE_BlenderAnim(Render *re, Main *bmain, Scene *scene, Object *camera_overri } else G.is_break = true; - + if (G.is_break == true) { /* remove touched file */ if (is_movie == false) { @@ -2753,7 +2753,7 @@ void RE_BlenderAnim(Render *re, Main *bmain, Scene *scene, Object *camera_overri } } } - + break; } @@ -2763,12 +2763,12 @@ void RE_BlenderAnim(Render *re, Main *bmain, Scene *scene, Object *camera_overri } } } - + /* end movie */ if (is_movie) { re_movie_free_all(re, mh, totvideos); } - + if (totskipped && totrendered == 0) BKE_report(re->reports, RPT_INFO, "No frames rendered, skipped to not overwrite"); @@ -2812,16 +2812,16 @@ bool RE_ReadRenderResult(Scene *scene, Scene *scenode) int winx, winy; bool success; rcti disprect; - + /* calculate actual render result and display size */ winx = (scene->r.size * scene->r.xsch) / 100; winy = (scene->r.size * scene->r.ysch) / 100; - + /* only in movie case we render smaller part */ if (scene->r.mode & R_BORDER) { disprect.xmin = scene->r.border.xmin * winx; disprect.xmax = scene->r.border.xmax * winx; - + disprect.ymin = scene->r.border.ymin * winy; disprect.ymax = scene->r.border.ymax * winy; } @@ -2830,17 +2830,17 @@ bool RE_ReadRenderResult(Scene *scene, Scene *scenode) disprect.xmax = winx; disprect.ymax = winy; } - + if (scenode) scene = scenode; - + /* get render: it can be called from UI with draw callbacks */ re = RE_GetSceneRender(scene); if (re == NULL) re = RE_NewSceneRender(scene); RE_InitState(re, NULL, &scene->r, &scene->view_layers, NULL, winx, winy, &disprect); re->scene = scene; - + BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE); success = render_result_exr_file_cache_read(re); BLI_rw_mutex_unlock(&re->resultmutex); @@ -2850,7 +2850,7 @@ bool RE_ReadRenderResult(Scene *scene, Scene *scenode) return success; } -void RE_init_threadcount(Render *re) +void RE_init_threadcount(Render *re) { re->r.threads = BKE_render_num_threads(&re->r); } @@ -3014,7 +3014,7 @@ RenderPass *RE_create_gp_pass(RenderResult *rr, const char *layername, const cha rl->rectx = rr->rectx; rl->recty = rr->recty; } - + /* clear previous pass if exist or the new image will be over previous one*/ RenderPass *rp = RE_pass_find_by_name(rl, RE_PASSNAME_COMBINED, viewname); if (rp) { diff --git a/source/blender/render/intern/source/pixelblending.c b/source/blender/render/intern/source/pixelblending.c new file mode 100644 index 00000000000..c7cfe765f5b --- /dev/null +++ b/source/blender/render/intern/source/pixelblending.c @@ -0,0 +1,400 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * Contributor(s): Full recode, 2004-2006 Blender Foundation + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/render/intern/source/pixelblending.c + * \ingroup render + * + * Functions to blend pixels with or without alpha, in various formats + * nzc - June 2000 + */ + + +#include <math.h> +#include <string.h> + +/* global includes */ + +/* own includes */ +#include "render_types.h" +#include "pixelblending.h" + +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ +/* defined in pipeline.c, is hardcopy of active dynamic allocated Render */ +/* only to be used here in this file, it's for speed */ +extern struct Render R; +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ + + +/* ------------------------------------------------------------------------- */ +/* Debug/behavior defines */ +/* if defined: alpha blending with floats clips color, as with shorts */ +/* #define RE_FLOAT_COLOR_CLIPPING */ +/* if defined: alpha values are clipped */ +/* For now, we just keep alpha clipping. We run into thresholding and */ +/* blending difficulties otherwise. Be careful here. */ +#define RE_ALPHA_CLIPPING + + + +/* Threshold for a 'full' pixel: pixels with alpha above this level are */ +/* considered opaque This is the decimal value for 0xFFF0 / 0xFFFF */ +#define RE_FULL_COLOR_FLOAT 0.9998f +/* Threshold for an 'empty' pixel: pixels with alpha above this level are */ +/* considered completely transparent. This is the decimal value */ +/* for 0x000F / 0xFFFF */ +#define RE_EMPTY_COLOR_FLOAT 0.0002f + + +/* ------------------------------------------------------------------------- */ + +void addAlphaOverFloat(float dest[4], const float source[4]) +{ + /* d = s + (1-alpha_s)d*/ + float mul; + + mul = 1.0f - source[3]; + + dest[0] = (mul * dest[0]) + source[0]; + dest[1] = (mul * dest[1]) + source[1]; + dest[2] = (mul * dest[2]) + source[2]; + dest[3] = (mul * dest[3]) + source[3]; + +} + + +/* ------------------------------------------------------------------------- */ + +void addAlphaUnderFloat(float dest[4], const float source[4]) +{ + float mul; + + mul = 1.0f - dest[3]; + + dest[0] += (mul * source[0]); + dest[1] += (mul * source[1]); + dest[2] += (mul * source[2]); + dest[3] += (mul * source[3]); +} + + +/* ------------------------------------------------------------------------- */ +void addalphaAddfacFloat(float dest[4], const float source[4], char addfac) +{ + float m; /* weiging factor of destination */ + float c; /* intermediate color */ + + /* Addfac is a number between 0 and 1: rescale */ + /* final target is to diminish the influence of dest when addfac rises */ + m = 1.0f - (source[3] * ((255 - addfac) / 255.0f)); + + /* blend colors*/ + c = (m * dest[0]) + source[0]; +#ifdef RE_FLOAT_COLOR_CLIPPING + if (c >= RE_FULL_COLOR_FLOAT) dest[0] = RE_FULL_COLOR_FLOAT; + else +#endif + dest[0] = c; + + c = (m * dest[1]) + source[1]; +#ifdef RE_FLOAT_COLOR_CLIPPING + if (c >= RE_FULL_COLOR_FLOAT) dest[1] = RE_FULL_COLOR_FLOAT; + else +#endif + dest[1] = c; + + c = (m * dest[2]) + source[2]; +#ifdef RE_FLOAT_COLOR_CLIPPING + if (c >= RE_FULL_COLOR_FLOAT) dest[2] = RE_FULL_COLOR_FLOAT; + else +#endif + dest[2] = c; + + c = (m * dest[3]) + source[3]; +#ifdef RE_ALPHA_CLIPPING + if (c >= RE_FULL_COLOR_FLOAT) dest[3] = RE_FULL_COLOR_FLOAT; + else +#endif + dest[3] = c; + +} + + +/* ------------------------------------------------------------------------- */ + +/* filtered adding to scanlines */ +void add_filt_fmask(unsigned int mask, const float col[4], float *rowbuf, int row_w) +{ + /* calc the value of mask */ + float **fmask1 = R.samples->fmask1, **fmask2 = R.samples->fmask2; + float *rb1, *rb2, *rb3; + float val, r, g, b, al; + unsigned int a, maskand, maskshift; + int j; + + r = col[0]; + g = col[1]; + b = col[2]; + al = col[3]; + + rb2 = rowbuf - 4; + rb3 = rb2 - 4 * row_w; + rb1 = rb2 + 4 * row_w; + + maskand = (mask & 255); + maskshift = (mask >> 8); + + for (j = 2; j >= 0; j--) { + + a = j; + + val = *(fmask1[a] + maskand) + *(fmask2[a] + maskshift); + if (val != 0.0f) { + rb1[0] += val * r; + rb1[1] += val * g; + rb1[2] += val * b; + rb1[3] += val * al; + } + a += 3; + + val = *(fmask1[a] + maskand) + *(fmask2[a] + maskshift); + if (val != 0.0f) { + rb2[0] += val * r; + rb2[1] += val * g; + rb2[2] += val * b; + rb2[3] += val * al; + } + a += 3; + + val = *(fmask1[a] + maskand) + *(fmask2[a] + maskshift); + if (val != 0.0f) { + rb3[0] += val * r; + rb3[1] += val * g; + rb3[2] += val * b; + rb3[3] += val * al; + } + + rb1 += 4; + rb2 += 4; + rb3 += 4; + } +} + + +void mask_array(unsigned int mask, float filt[3][3]) +{ + float **fmask1 = R.samples->fmask1, **fmask2 = R.samples->fmask2; + unsigned int maskand = (mask & 255); + unsigned int maskshift = (mask >> 8); + int a, j; + + for (j = 2; j >= 0; j--) { + + a = j; + + filt[2][2 - j] = *(fmask1[a] + maskand) + *(fmask2[a] + maskshift); + + a += 3; + + filt[1][2 - j] = *(fmask1[a] + maskand) + *(fmask2[a] + maskshift); + + a += 3; + + filt[0][2 - j] = *(fmask1[a] + maskand) + *(fmask2[a] + maskshift); + } +} + + +/** + * Index ordering, scanline based: + * + * <pre> + * --- --- --- + * | 2,0 | 2,1 | 2,2 | + * --- --- --- + * | 1,0 | 1,1 | 1,2 | + * --- --- --- + * | 0,0 | 0,1 | 0,2 | + * --- --- --- + * </pre> + */ + +void add_filt_fmask_coord(float filt[3][3], const float col[4], float *rowbuf, int row_stride, int x, int y, rcti *mask) +{ + float *fpoin[3][3]; + float val, r, g, b, al, lfilt[3][3]; + + r = col[0]; + g = col[1]; + b = col[2]; + al = col[3]; + + memcpy(lfilt, filt, sizeof(lfilt)); + + fpoin[0][1] = rowbuf - 4 * row_stride; + fpoin[1][1] = rowbuf; + fpoin[2][1] = rowbuf + 4 * row_stride; + + fpoin[0][0] = fpoin[0][1] - 4; + fpoin[1][0] = fpoin[1][1] - 4; + fpoin[2][0] = fpoin[2][1] - 4; + + fpoin[0][2] = fpoin[0][1] + 4; + fpoin[1][2] = fpoin[1][1] + 4; + fpoin[2][2] = fpoin[2][1] + 4; + + /* limit filtering to withing a mask for border rendering, so pixels don't + * leak outside of the border */ + if (y <= mask->ymin) { + fpoin[0][0] = fpoin[1][0]; + fpoin[0][1] = fpoin[1][1]; + fpoin[0][2] = fpoin[1][2]; + /* filter needs the opposite value yes! */ + lfilt[0][0] = filt[2][0]; + lfilt[0][1] = filt[2][1]; + lfilt[0][2] = filt[2][2]; + } + else if (y >= mask->ymax - 1) { + fpoin[2][0] = fpoin[1][0]; + fpoin[2][1] = fpoin[1][1]; + fpoin[2][2] = fpoin[1][2]; + + lfilt[2][0] = filt[0][0]; + lfilt[2][1] = filt[0][1]; + lfilt[2][2] = filt[0][2]; + } + + if (x <= mask->xmin) { + fpoin[2][0] = fpoin[2][1]; + fpoin[1][0] = fpoin[1][1]; + fpoin[0][0] = fpoin[0][1]; + + lfilt[2][0] = filt[2][2]; + lfilt[1][0] = filt[1][2]; + lfilt[0][0] = filt[0][2]; + } + else if (x >= mask->xmax - 1) { + fpoin[2][2] = fpoin[2][1]; + fpoin[1][2] = fpoin[1][1]; + fpoin[0][2] = fpoin[0][1]; + + lfilt[2][2] = filt[2][0]; + lfilt[1][2] = filt[1][0]; + lfilt[0][2] = filt[0][0]; + } + + + /* loop unroll */ +#define MASKFILT(i, j) \ + val = lfilt[i][j]; \ + if (val != 0.0f) { \ + float *fp = fpoin[i][j]; \ + fp[0] += val * r; \ + fp[1] += val * g; \ + fp[2] += val * b; \ + fp[3] += val * al; \ + } (void)0 + + MASKFILT(0, 0); + MASKFILT(0, 1); + MASKFILT(0, 2); + MASKFILT(1, 0); + MASKFILT(1, 1); + MASKFILT(1, 2); + MASKFILT(2, 0); + MASKFILT(2, 1); + MASKFILT(2, 2); + +#undef MASKFILT +} + +void add_filt_fmask_pixsize(unsigned int mask, float *in, float *rowbuf, int row_w, int pixsize) +{ + /* calc the value of mask */ + float **fmask1 = R.samples->fmask1, **fmask2 = R.samples->fmask2; + float *rb1, *rb2, *rb3; + float val; + unsigned int a, maskand, maskshift; + int i, j; + + rb2 = rowbuf - pixsize; + rb3 = rb2 - pixsize * row_w; + rb1 = rb2 + pixsize * row_w; + + maskand = (mask & 255); + maskshift = (mask >> 8); + + for (j = 2; j >= 0; j--) { + + a = j; + + val = *(fmask1[a] + maskand) + *(fmask2[a] + maskshift); + if (val != 0.0f) { + for (i = 0; i < pixsize; i++) + rb1[i] += val * in[i]; + } + a += 3; + + val = *(fmask1[a] + maskand) + *(fmask2[a] + maskshift); + if (val != 0.0f) { + for (i = 0; i < pixsize; i++) + rb2[i] += val * in[i]; + } + a += 3; + + val = *(fmask1[a] + maskand) + *(fmask2[a] + maskshift); + if (val != 0.0f) { + for (i = 0; i < pixsize; i++) + rb3[i] += val * in[i]; + } + + rb1 += pixsize; + rb2 += pixsize; + rb3 += pixsize; + } +} + +/* ------------------------------------------------------------------------- */ +void addalphaAddFloat(float dest[4], const float source[4]) +{ + + /* Makes me wonder whether this is required... */ + if (dest[3] < RE_EMPTY_COLOR_FLOAT) { + dest[0] = source[0]; + dest[1] = source[1]; + dest[2] = source[2]; + dest[3] = source[3]; + return; + } + + /* no clipping! */ + dest[0] = dest[0] + source[0]; + dest[1] = dest[1] + source[1]; + dest[2] = dest[2] + source[2]; + dest[3] = dest[3] + source[3]; + +} + + +/* ---------------------------------------------------------------------------- */ diff --git a/source/blender/render/intern/source/pixelshading.c b/source/blender/render/intern/source/pixelshading.c new file mode 100644 index 00000000000..7f202629ce4 --- /dev/null +++ b/source/blender/render/intern/source/pixelshading.c @@ -0,0 +1,650 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * Contributor(s): 2004-2006, Blender Foundation, full recode + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/render/intern/source/pixelshading.c + * \ingroup render + */ + + +#include <float.h> +#include <math.h> +#include <string.h> + +#include "BLI_math.h" +#include "BLI_utildefines.h" + +/* External modules: */ + +#include "DNA_group_types.h" +#include "DNA_material_types.h" +#include "DNA_object_types.h" +#include "DNA_image_types.h" +#include "DNA_texture_types.h" +#include "DNA_lamp_types.h" + +#include "BKE_material.h" + + +/* own module */ +#include "render_types.h" +#include "renderdatabase.h" +#include "texture.h" +#include "rendercore.h" +#include "shadbuf.h" +#include "pixelshading.h" +#include "sunsky.h" + +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ +/* defined in pipeline.c, is hardcopy of active dynamic allocated Render */ +/* only to be used here in this file, it's for speed */ +extern struct Render R; +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ + + +extern const float hashvectf[]; + +static void render_lighting_halo(HaloRen *har, float col_r[3]) +{ + GroupObject *go; + LampRen *lar; + float i, inp, inpr, rco[3], dco[3], lv[3], lampdist, ld, t, *vn; + float ir, ig, ib, shadfac, soft, lacol[3]; + + ir= ig= ib= 0.0; + + copy_v3_v3(rco, har->co); + dco[0]=dco[1]=dco[2]= 1.0f/har->rad; + + vn= har->no; + + for (go=R.lights.first; go; go= go->next) { + lar= go->lampren; + + /* test for lamplayer */ + if (lar->mode & LA_LAYER) if ((lar->lay & har->lay)==0) continue; + + /* lampdist cacluation */ + if (lar->type==LA_SUN || lar->type==LA_HEMI) { + copy_v3_v3(lv, lar->vec); + lampdist= 1.0; + } + else { + lv[0]= rco[0]-lar->co[0]; + lv[1]= rco[1]-lar->co[1]; + lv[2]= rco[2]-lar->co[2]; + ld = len_v3(lv); + lv[0]/= ld; + lv[1]/= ld; + lv[2]/= ld; + + /* ld is re-used further on (texco's) */ + + if (lar->mode & LA_QUAD) { + t= 1.0; + if (lar->ld1>0.0f) + t= lar->dist/(lar->dist+lar->ld1*ld); + if (lar->ld2>0.0f) + t*= lar->distkw/(lar->distkw+lar->ld2*ld*ld); + + lampdist= t; + } + else { + lampdist= (lar->dist/(lar->dist+ld)); + } + + if (lar->mode & LA_SPHERE) { + t= lar->dist - ld; + if (t<0.0f) continue; + + t/= lar->dist; + lampdist*= (t); + } + + } + + lacol[0]= lar->r; + lacol[1]= lar->g; + lacol[2]= lar->b; + + if (lar->mode & LA_TEXTURE) { + ShadeInput shi; + + /* Warning, This is not that nice, and possibly a bit slow, + * however some variables were not initialized properly in, unless using shade_input_initialize(...), + * we need to do a memset */ + memset(&shi, 0, sizeof(ShadeInput)); + /* end warning! - Campbell */ + + copy_v3_v3(shi.co, rco); + shi.osatex= 0; + do_lamp_tex(lar, lv, &shi, lacol, LA_TEXTURE); + } + + if (lar->type==LA_SPOT) { + + if (lar->mode & LA_SQUARE) { + if (lv[0]*lar->vec[0]+lv[1]*lar->vec[1]+lv[2]*lar->vec[2]>0.0f) { + float x, lvrot[3]; + + /* rotate view to lampspace */ + copy_v3_v3(lvrot, lv); + mul_m3_v3(lar->imat, lvrot); + + x = max_ff(fabsf(lvrot[0]/lvrot[2]), fabsf(lvrot[1]/lvrot[2])); + /* 1.0/(sqrt(1+x*x)) is equivalent to cos(atan(x)) */ + + inpr = 1.0f / (sqrtf(1.0f + x * x)); + } + else inpr= 0.0; + } + else { + inpr= lv[0]*lar->vec[0]+lv[1]*lar->vec[1]+lv[2]*lar->vec[2]; + } + + t= lar->spotsi; + if (inpr<t) continue; + else { + t= inpr-t; + soft= 1.0; + if (t<lar->spotbl && lar->spotbl!=0.0f) { + /* soft area */ + i= t/lar->spotbl; + t= i*i; + soft= (3.0f*t-2.0f*t*i); + inpr*= soft; + } + if (lar->mode & LA_ONLYSHADOW) { + /* if (ma->mode & MA_SHADOW) { */ + /* dot product positive: front side face! */ + inp= vn[0]*lv[0] + vn[1]*lv[1] + vn[2]*lv[2]; + if (inp>0.0f) { + /* testshadowbuf==0.0 : 100% shadow */ + shadfac = testshadowbuf(&R, lar->shb, rco, dco, dco, inp, 0.0f); + if ( shadfac>0.0f ) { + shadfac*= inp*soft*lar->energy; + ir -= shadfac; + ig -= shadfac; + ib -= shadfac; + + continue; + } + } + /* } */ + } + lampdist*=inpr; + } + if (lar->mode & LA_ONLYSHADOW) continue; + + } + + /* dot product and reflectivity*/ + + inp = 1.0f - fabsf(dot_v3v3(vn, lv)); + + /* inp= cos(0.5*M_PI-acos(inp)); */ + + i= inp; + + if (lar->type==LA_HEMI) { + i= 0.5f*i+0.5f; + } + if (i>0.0f) { + i*= lampdist; + } + + /* shadow */ + if (i> -0.41f) { /* heuristic valua! */ + if (lar->shb) { + shadfac = testshadowbuf(&R, lar->shb, rco, dco, dco, inp, 0.0f); + if (shadfac==0.0f) continue; + i*= shadfac; + } + } + + if (i>0.0f) { + ir+= i*lacol[0]; + ig+= i*lacol[1]; + ib+= i*lacol[2]; + } + } + + if (ir<0.0f) ir= 0.0f; + if (ig<0.0f) ig= 0.0f; + if (ib<0.0f) ib= 0.0f; + + col_r[0]*= ir; + col_r[1]*= ig; + col_r[2]*= ib; + +} + + +/** + * Converts a halo z-buffer value to distance from the camera's near plane + * \param z The z-buffer value to convert + * \return a distance from the camera's near plane in blender units + */ +static float haloZtoDist(int z) +{ + float zco = 0; + + if (z >= 0x7FFFFF) + return 10e10; + else { + zco = (float)z/(float)0x7FFFFF; + if (R.r.mode & R_ORTHO) + return (R.winmat[3][2] - zco*R.winmat[3][3])/(R.winmat[2][2]); + else + return (R.winmat[3][2])/(R.winmat[2][2] - R.winmat[2][3]*zco); + } +} + +/** + * \param col (float[4]) Store the rgb color here (with alpha) + * The alpha is used to blend the color to the background + * color_new = (1-alpha)*color_background + color + * \param zz The current zbuffer value at the place of this pixel + * \param dist Distance of the pixel from the center of the halo squared. Given in pixels + * \param xn The x coordinate of the pixel relaticve to the center of the halo. given in pixels + * \param yn The y coordinate of the pixel relaticve to the center of the halo. given in pixels + */ +int shadeHaloFloat(HaloRen *har, float col[4], int zz, + float dist, float xn, float yn, short flarec) +{ + /* fill in col */ + float t, zn, radist, ringf=0.0f, linef=0.0f, alpha, si, co; + int a; + + if (R.wrld.mode & WO_MIST) { + if (har->type & HA_ONLYSKY) { + alpha= har->alfa; + } + else { + /* a bit patchy... */ + alpha= mistfactor(-har->co[2], har->co)*har->alfa; + } + } + else alpha= har->alfa; + + if (alpha==0.0f) + return 0; + + /* soften the halo if it intersects geometry */ + if (har->mat && har->mat->mode & MA_HALO_SOFT) { + float segment_length, halo_depth, distance_from_z /* , visible_depth */ /* UNUSED */, soften; + + /* calculate halo depth */ + segment_length= har->hasize*sasqrt(1.0f - dist/(har->rad*har->rad)); + halo_depth= 2.0f*segment_length; + + if (halo_depth < FLT_EPSILON) + return 0; + + /* calculate how much of this depth is visible */ + distance_from_z = haloZtoDist(zz) - haloZtoDist(har->zs); + /* visible_depth = halo_depth; */ /* UNUSED */ + if (distance_from_z < segment_length) { + soften= (segment_length + distance_from_z)/halo_depth; + + /* apply softening to alpha */ + if (soften < 1.0f) + alpha *= soften; + if (alpha <= 0.0f) + return 0; + } + } + else { + /* not a soft halo. use the old softening code */ + /* halo being intersected? */ + if (har->zs> zz-har->zd) { + t= ((float)(zz-har->zs))/(float)har->zd; + alpha*= sqrtf(sqrtf(t)); + } + } + + radist = sqrtf(dist); + + /* watch it: not used nicely: flarec is set at zero in pixstruct */ + if (flarec) har->pixels+= (int)(har->rad-radist); + + if (har->ringc) { + const float *rc; + float fac; + int ofs; + + /* per ring an antialised circle */ + ofs= har->seed; + + for (a= har->ringc; a>0; a--, ofs+=2) { + + rc= hashvectf + (ofs % 768); + + fac = fabsf(rc[1] * (har->rad * fabsf(rc[0]) - radist)); + + if (fac< 1.0f) { + ringf+= (1.0f-fac); + } + } + } + + if (har->type & HA_VECT) { + dist= fabsf(har->cos * (yn) - har->sin * (xn)) / har->rad; + if (dist>1.0f) dist= 1.0f; + if (har->tex) { + zn= har->sin*xn - har->cos*yn; + yn= har->cos*xn + har->sin*yn; + xn= zn; + } + } + else dist= dist/har->radsq; + + if (har->type & HA_FLARECIRC) { + dist = 0.5f + fabsf(dist - 0.5f); + } + + if (har->hard>=30) { + dist = sqrtf(dist); + if (har->hard>=40) { + dist = sinf(dist*(float)M_PI_2); + if (har->hard>=50) { + dist = sqrtf(dist); + } + } + } + else if (har->hard<20) dist*=dist; + + if (dist < 1.0f) + dist= (1.0f-dist); + else + dist= 0.0f; + + if (har->linec) { + const float *rc; + float fac; + int ofs; + + /* per starpoint an antialiased line */ + ofs= har->seed; + + for (a= har->linec; a>0; a--, ofs+=3) { + + rc= hashvectf + (ofs % 768); + + fac = fabsf((xn) * rc[0] + (yn) * rc[1]); + + if (fac< 1.0f ) + linef+= (1.0f-fac); + } + + linef*= dist; + } + + if (har->starpoints) { + float ster, angle; + /* rotation */ + angle = atan2f(yn, xn); + angle *= (1.0f+0.25f*har->starpoints); + + co= cosf(angle); + si= sinf(angle); + + angle= (co*xn+si*yn)*(co*yn-si*xn); + + ster = fabsf(angle); + if (ster>1.0f) { + ster= (har->rad)/(ster); + + if (ster<1.0f) dist*= sqrtf(ster); + } + } + + /* disputable optimize... (ton) */ + if (dist<=0.00001f) + return 0; + + dist*= alpha; + ringf*= dist; + linef*= alpha; + + /* The color is either the rgb spec-ed by the user, or extracted from */ + /* the texture */ + if (har->tex) { + col[0]= har->r; + col[1]= har->g; + col[2]= har->b; + col[3]= dist; + + do_halo_tex(har, xn, yn, col); + + col[0]*= col[3]; + col[1]*= col[3]; + col[2]*= col[3]; + + } + else { + col[0]= dist*har->r; + col[1]= dist*har->g; + col[2]= dist*har->b; + if (har->type & HA_XALPHA) col[3]= dist*dist; + else col[3]= dist; + } + + if (har->mat) { + if (har->mat->mode & MA_HALO_SHADE) { + /* we test for lights because of preview... */ + if (R.lights.first) render_lighting_halo(har, col); + } + + /* Next, we do the line and ring factor modifications. */ + if (linef!=0.0f) { + Material *ma= har->mat; + + col[0]+= linef * ma->specr; + col[1]+= linef * ma->specg; + col[2]+= linef * ma->specb; + + if (har->type & HA_XALPHA) col[3]+= linef*linef; + else col[3]+= linef; + } + if (ringf!=0.0f) { + Material *ma= har->mat; + + col[0]+= ringf * ma->mirr; + col[1]+= ringf * ma->mirg; + col[2]+= ringf * ma->mirb; + + if (har->type & HA_XALPHA) col[3]+= ringf*ringf; + else col[3]+= ringf; + } + } + + /* alpha requires clip, gives black dots */ + if (col[3] > 1.0f) + col[3]= 1.0f; + + return 1; +} + +/* ------------------------------------------------------------------------- */ + +/* Only view vector is important here. Result goes to col_r[3] */ +void shadeSkyView(float col_r[3], const float rco[3], const float view[3], const float dxyview[2], short thread) +{ + float zen[3], hor[3], blend, blendm; + int skyflag; + + /* flag indicating if we render the top hemisphere */ + skyflag = WO_ZENUP; + + /* Some view vector stuff. */ + if (R.wrld.skytype & WO_SKYREAL) { + + blend = dot_v3v3(view, R.grvec); + + if (blend<0.0f) skyflag= 0; + + blend = fabsf(blend); + } + else if (R.wrld.skytype & WO_SKYPAPER) { + blend= 0.5f + 0.5f * view[1]; + } + else { + /* the fraction of how far we are above the bottom of the screen */ + blend = fabsf(0.5f + view[1]); + } + + copy_v3_v3(hor, &R.wrld.horr); + copy_v3_v3(zen, &R.wrld.zenr); + + /* Careful: SKYTEX and SKYBLEND are NOT mutually exclusive! If */ + /* SKYBLEND is active, the texture and color blend are added. */ + if (R.wrld.skytype & WO_SKYTEX) { + float lo[3]; + copy_v3_v3(lo, view); + if (R.wrld.skytype & WO_SKYREAL) { + + mul_m3_v3(R.imat, lo); + + SWAP(float, lo[1], lo[2]); + + } + do_sky_tex(rco, view, lo, dxyview, hor, zen, &blend, skyflag, thread); + } + + if (blend>1.0f) blend= 1.0f; + blendm= 1.0f-blend; + + /* No clipping, no conversion! */ + if (R.wrld.skytype & WO_SKYBLEND) { + col_r[0] = (blendm*hor[0] + blend*zen[0]); + col_r[1] = (blendm*hor[1] + blend*zen[1]); + col_r[2] = (blendm*hor[2] + blend*zen[2]); + } + else { + /* Done when a texture was grabbed. */ + col_r[0]= hor[0]; + col_r[1]= hor[1]; + col_r[2]= hor[2]; + } +} + +/* shade sky according to sun lamps, all parameters are like shadeSkyView except sunsky*/ +void shadeSunView(float col_r[3], const float view[3]) +{ + GroupObject *go; + LampRen *lar; + float sview[3]; + bool do_init = true; + + for (go=R.lights.first; go; go= go->next) { + lar= go->lampren; + if (lar->type==LA_SUN && lar->sunsky && (lar->sunsky->effect_type & LA_SUN_EFFECT_SKY)) { + float sun_collector[3]; + float colorxyz[3]; + + if (do_init) { + + normalize_v3_v3(sview, view); + mul_m3_v3(R.imat, sview); + if (sview[2] < 0.0f) + sview[2] = 0.0f; + normalize_v3(sview); + do_init = false; + } + + GetSkyXYZRadiancef(lar->sunsky, sview, colorxyz); + xyz_to_rgb(colorxyz[0], colorxyz[1], colorxyz[2], &sun_collector[0], &sun_collector[1], &sun_collector[2], + lar->sunsky->sky_colorspace); + + ramp_blend(lar->sunsky->skyblendtype, col_r, lar->sunsky->skyblendfac, sun_collector); + } + } +} + + +/* + * Stuff the sky color into the collector. + */ +void shadeSkyPixel(float collector[4], float fx, float fy, short thread) +{ + float view[3], dxyview[2]; + + /* + * The rules for sky: + * 1. Draw an image, if a background image was provided. Stop + * 2. get texture and color blend, and combine these. + */ + + float fac; + + if ((R.wrld.skytype & (WO_SKYBLEND+WO_SKYTEX))==0) { + /* 1. solid color */ + copy_v3_v3(collector, &R.wrld.horr); + + collector[3] = 0.0f; + } + else { + /* 2. */ + + /* This one true because of the context of this routine */ + if (R.wrld.skytype & WO_SKYPAPER) { + view[0]= -1.0f + 2.0f*(fx/(float)R.winx); + view[1]= -1.0f + 2.0f*(fy/(float)R.winy); + view[2]= 0.0; + + dxyview[0]= 1.0f/(float)R.winx; + dxyview[1]= 1.0f/(float)R.winy; + } + else { + calc_view_vector(view, fx, fy); + fac= normalize_v3(view); + + if (R.wrld.skytype & WO_SKYTEX) { + dxyview[0]= -R.viewdx/fac; + dxyview[1]= -R.viewdy/fac; + } + } + + /* get sky color in the collector */ + shadeSkyView(collector, NULL, view, dxyview, thread); + collector[3] = 0.0f; + } + + calc_view_vector(view, fx, fy); + shadeSunView(collector, view); +} + +/* aerial perspective */ +void shadeAtmPixel(struct SunSky *sunsky, float collector[3], float fx, float fy, float distance) +{ + float view[3]; + + calc_view_vector(view, fx, fy); + normalize_v3(view); + /*mul_m3_v3(R.imat, view);*/ + AtmospherePixleShader(sunsky, view, distance, collector); +} + +/* eof */ diff --git a/source/blender/render/intern/source/pointdensity.c b/source/blender/render/intern/source/pointdensity.c index 53359c305dc..c025a1fdef7 100644 --- a/source/blender/render/intern/source/pointdensity.c +++ b/source/blender/render/intern/source/pointdensity.c @@ -102,7 +102,7 @@ static void point_data_pointers(PointDensity *pd, const int totpoint = pd->totpoints; float *data = pd->point_data; int offset = 0; - + if (data_used & POINT_DATA_VEL) { if (r_data_velocity) *r_data_velocity = data + offset; @@ -112,7 +112,7 @@ static void point_data_pointers(PointDensity *pd, if (r_data_velocity) *r_data_velocity = NULL; } - + if (data_used & POINT_DATA_LIFE) { if (r_data_life) *r_data_life = data + offset; @@ -122,7 +122,7 @@ static void point_data_pointers(PointDensity *pd, if (r_data_life) *r_data_life = NULL; } - + if (data_used & POINT_DATA_COLOR) { if (r_data_color) *r_data_color = data + offset; @@ -283,19 +283,19 @@ static void pointdensity_cache_vertex_color(PointDensity *pd, Object *UNUSED(ob) const MLoopCol *mcol; char layername[MAX_CUSTOMDATA_LAYER_NAME]; int i; - + BLI_assert(data_color); - + if (!CustomData_has_layer(&mesh->ldata, CD_MLOOPCOL)) return; CustomData_validate_layer_name(&mesh->ldata, CD_MLOOPCOL, pd->vertex_attribute_name, layername); mcol = CustomData_get_layer_named(&mesh->ldata, CD_MLOOPCOL, layername); if (!mcol) return; - + /* Stores the number of MLoops using the same vertex, so we can normalize colors. */ int *mcorners = MEM_callocN(sizeof(int) * pd->totpoints, "point density corner count"); - + for (i = 0; i < totloop; i++) { int v = mloop[i].v; @@ -310,7 +310,7 @@ static void pointdensity_cache_vertex_color(PointDensity *pd, Object *UNUSED(ob) ++mcorners[v]; } - + /* Normalize colors by averaging over mcorners. * All the corners share the same vertex, ie. occupy the same point in space. */ @@ -318,7 +318,7 @@ static void pointdensity_cache_vertex_color(PointDensity *pd, Object *UNUSED(ob) if (mcorners[i] > 0) mul_v3_fl(&data_color[i*3], 1.0f / mcorners[i]); } - + MEM_freeN(mcorners); } @@ -328,9 +328,9 @@ static void pointdensity_cache_vertex_weight(PointDensity *pd, Object *ob, Mesh const MDeformVert *mdef, *dv; int mdef_index; int i; - + BLI_assert(data_color); - + mdef = CustomData_get_layer(&mesh->vdata, CD_MDEFORMVERT); if (!mdef) return; @@ -339,11 +339,11 @@ static void pointdensity_cache_vertex_weight(PointDensity *pd, Object *ob, Mesh mdef_index = ob->actdef - 1; if (mdef_index < 0) return; - + for (i = 0, dv = mdef; i < totvert; ++i, ++dv, data_color += 3) { MDeformWeight *dw; int j; - + for (j = 0, dw = dv->dw; j < dv->totweight; ++j, ++dw) { if (dw->def_nr == mdef_index) { copy_v3_fl(data_color, dw->weight); @@ -357,9 +357,9 @@ static void pointdensity_cache_vertex_normal(PointDensity *pd, Object *UNUSED(ob { MVert *mvert = mesh->mvert, *mv; int i; - + BLI_assert(data_color); - + for (i = 0, mv = mvert; i < pd->totpoints; i++, mv++, data_color += 3) { normal_short_to_float_v3(data_color, mv->no); } @@ -413,7 +413,7 @@ static void pointdensity_cache_object(PointDensity *pd, BLI_bvhtree_insert(pd->point_tree, i, co, 1); } - + switch (pd->ob_color_source) { case TEX_PD_COLOR_VERTCOL: pointdensity_cache_vertex_color(pd, ob, mesh, data_color); @@ -506,7 +506,7 @@ static float density_falloff(PointDensityRangeData *pdr, int index, float square { const float dist = (pdr->squared_radius - squared_dist) / pdr->squared_radius * 0.5f; float density = 0.0f; - + switch (pdr->falloff_type) { case TEX_PD_FALLOFF_STD: density = dist; @@ -536,12 +536,12 @@ static float density_falloff(PointDensityRangeData *pdr, int index, float square density = dist; break; } - + if (pdr->density_curve && dist != 0.0f) { curvemapping_initialize(pdr->density_curve); density = curvemapping_evaluateF(pdr->density_curve, 0, density / dist) * dist; } - + return density; } @@ -666,7 +666,7 @@ static void pointdensity_color(PointDensity *pd, TexResult *texres, float age, c if (pd->source == TEX_PD_PSYS) { float rgba[4]; - + switch (pd->color_source) { case TEX_PD_COLOR_PARTAGE: if (pd->coba) { @@ -681,7 +681,7 @@ static void pointdensity_color(PointDensity *pd, TexResult *texres, float age, c case TEX_PD_COLOR_PARTSPEED: { float speed = len_v3(vec) * pd->speed_scale; - + if (pd->coba) { if (BKE_colorband_evaluate(pd->coba, speed, rgba)) { texres->talpha = true; @@ -704,7 +704,7 @@ static void pointdensity_color(PointDensity *pd, TexResult *texres, float age, c } else { float rgba[4]; - + switch (pd->ob_color_source) { case TEX_PD_COLOR_VERTCOL: texres->talpha = true; diff --git a/source/blender/render/intern/source/rayshade.c b/source/blender/render/intern/source/rayshade.c new file mode 100644 index 00000000000..df1cb868230 --- /dev/null +++ b/source/blender/render/intern/source/rayshade.c @@ -0,0 +1,2503 @@ +/* + * ***** 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) 1990-1998 NeoGeo BV. + * All rights reserved. + * + * Contributors: 2004/2005 Blender Foundation, full recode + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/render/intern/source/rayshade.c + * \ingroup render + */ + +#include <stdio.h> +#include <math.h> +#include <string.h> +#include <stdlib.h> +#include <float.h> +#include <assert.h> + +#include "MEM_guardedalloc.h" + +#include "DNA_material_types.h" +#include "DNA_lamp_types.h" + +#include "BLI_blenlib.h" +#include "BLI_system.h" +#include "BLI_math.h" +#include "BLI_rand.h" +#include "BLI_utildefines.h" + +#include "BLT_translation.h" + +#include "BKE_node.h" + +#include "render_result.h" +#include "render_types.h" +#include "rendercore.h" +#include "renderdatabase.h" +#include "pixelshading.h" +#include "shading.h" +#include "volumetric.h" + +#include "rayintersection.h" +#include "rayobject.h" +#include "raycounter.h" + +#define RAY_TRA 1 +#define RAY_INSIDE 2 + +#define DEPTH_SHADOW_TRA 10 + +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ +/* defined in pipeline.c, is hardcopy of active dynamic allocated Render */ +/* only to be used here in this file, it's for speed */ +extern struct Render R; +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ +static int test_break(void *data) +{ + Render *re = (Render *)data; + return re->test_break(re->tbh); +} + +static void RE_rayobject_config_control(RayObject *r, Render *re) +{ + if (RE_rayobject_isRayAPI(r)) { + r = RE_rayobject_align(r); + r->control.data = re; + r->control.test_break = test_break; + } +} + +RayObject *RE_rayobject_create(int type, int size, int octree_resolution) +{ + RayObject * res = NULL; + + if (type == R_RAYSTRUCTURE_AUTO) { + /* TODO */ + //if (detect_simd()) +#ifdef __SSE__ + type = BLI_cpu_support_sse2()? R_RAYSTRUCTURE_SIMD_SVBVH: R_RAYSTRUCTURE_VBVH; +#else + type = R_RAYSTRUCTURE_VBVH; +#endif + } + +#ifndef __SSE__ + if (type == R_RAYSTRUCTURE_SIMD_SVBVH || type == R_RAYSTRUCTURE_SIMD_QBVH) { + puts("Warning: Using VBVH (SSE was disabled at compile time)"); + type = R_RAYSTRUCTURE_VBVH; + } +#endif + + + if (type == R_RAYSTRUCTURE_OCTREE) //TODO dynamic ocres + res = RE_rayobject_octree_create(octree_resolution, size); + else if (type == R_RAYSTRUCTURE_VBVH) + res = RE_rayobject_vbvh_create(size); + else if (type == R_RAYSTRUCTURE_SIMD_SVBVH) + res = RE_rayobject_svbvh_create(size); + else if (type == R_RAYSTRUCTURE_SIMD_QBVH) + res = RE_rayobject_qbvh_create(size); + else + res = RE_rayobject_vbvh_create(size); //Fallback + + return res; +} + +static RayObject* rayobject_create(Render *re, int type, int size) +{ + RayObject * res = NULL; + + res = RE_rayobject_create(type, size, re->r.ocres); + + if (res) + RE_rayobject_config_control(res, re); + + return res; +} + +#ifdef RE_RAYCOUNTER +RayCounter re_rc_counter[BLENDER_MAX_THREADS]; +#endif + + +void freeraytree(Render *re) +{ + ObjectInstanceRen *obi; + + if (re->raytree) { + RE_rayobject_free(re->raytree); + re->raytree = NULL; + } + if (re->rayfaces) { + MEM_freeN(re->rayfaces); + re->rayfaces = NULL; + } + if (re->rayprimitives) { + MEM_freeN(re->rayprimitives); + re->rayprimitives = NULL; + } + + for (obi=re->instancetable.first; obi; obi=obi->next) { + ObjectRen *obr = obi->obr; + if (obr->raytree) { + RE_rayobject_free(obr->raytree); + obr->raytree = NULL; + } + if (obr->rayfaces) { + MEM_freeN(obr->rayfaces); + obr->rayfaces = NULL; + } + if (obi->raytree) { + RE_rayobject_free(obi->raytree); + obi->raytree = NULL; + } + } + +#ifdef RE_RAYCOUNTER + { + const int num_threads = re->r.threads; + RayCounter sum; + memset(&sum, 0, sizeof(sum)); + int i; + for (i=0; i<num_threads; i++) + RE_RC_MERGE(&sum, re_rc_counter+i); + RE_RC_INFO(&sum); + } +#endif +} + +static bool is_raytraceable_vlr(Render *re, VlakRen *vlr) +{ + /* note: volumetric must be tracable, wire must not */ + if ((re->flag & R_BAKE_TRACE) || (vlr->flag & R_TRACEBLE) || (vlr->mat->material_type == MA_TYPE_VOLUME)) + if (vlr->mat->material_type != MA_TYPE_WIRE) + return 1; + return 0; +} + +static bool is_raytraceable(Render *re, ObjectInstanceRen *obi) +{ + int v; + ObjectRen *obr = obi->obr; + + if (re->excludeob && obr->ob == re->excludeob) + return 0; + + for (v=0;v<obr->totvlak;v++) { + VlakRen *vlr = obr->vlaknodes[v>>8].vlak + (v&255); + + if (is_raytraceable_vlr(re, vlr)) + return 1; + } + + return 0; +} + + +RayObject* makeraytree_object(Render *re, ObjectInstanceRen *obi) +{ + /*TODO + * out-of-memory safeproof + * break render + * update render stats */ + ObjectRen *obr = obi->obr; + + if (obr->raytree == NULL) { + RayObject *raytree; + RayFace *face = NULL; + VlakPrimitive *vlakprimitive = NULL; + int v; + + //Count faces + int faces = 0; + for (v=0;v<obr->totvlak;v++) { + VlakRen *vlr = obr->vlaknodes[v>>8].vlak + (v&255); + if (is_raytraceable_vlr(re, vlr)) + faces++; + } + + if (faces == 0) + return NULL; + + //Create Ray cast accelaration structure + raytree = rayobject_create( re, re->r.raytrace_structure, faces ); + if ( (re->r.raytrace_options & R_RAYTRACE_USE_LOCAL_COORDS) ) + vlakprimitive = obr->rayprimitives = (VlakPrimitive *)MEM_callocN(faces * sizeof(VlakPrimitive), "ObjectRen primitives"); + else + face = obr->rayfaces = (RayFace *)MEM_callocN(faces * sizeof(RayFace), "ObjectRen faces"); + + obr->rayobi = obi; + + for (v=0;v<obr->totvlak;v++) { + VlakRen *vlr = obr->vlaknodes[v>>8].vlak + (v&255); + if (is_raytraceable_vlr(re, vlr)) { + if ((re->r.raytrace_options & R_RAYTRACE_USE_LOCAL_COORDS)) { + RE_rayobject_add(raytree, RE_vlakprimitive_from_vlak(vlakprimitive, obi, vlr)); + vlakprimitive++; + } + else { + RE_rayface_from_vlak(face, obi, vlr); + RE_rayobject_add(raytree, RE_rayobject_unalignRayFace(face)); + face++; + } + } + } + RE_rayobject_done(raytree); + + /* in case of cancel during build, raytree is not usable */ + if (test_break(re)) + RE_rayobject_free(raytree); + else + obr->raytree= raytree; + } + + if (obr->raytree) { + if ((obi->flag & R_TRANSFORMED) && obi->raytree == NULL) { + obi->transform_primitives = 0; + obi->raytree = RE_rayobject_instance_create( obr->raytree, obi->mat, obi, obi->obr->rayobi ); + } + } + + if (obi->raytree) return obi->raytree; + return obi->obr->raytree; +} + +static bool has_special_rayobject(Render *re, ObjectInstanceRen *obi) +{ + if ( (obi->flag & R_TRANSFORMED) && (re->r.raytrace_options & R_RAYTRACE_USE_INSTANCES) ) { + ObjectRen *obr = obi->obr; + int v, faces = 0; + + for (v=0;v<obr->totvlak;v++) { + VlakRen *vlr = obr->vlaknodes[v>>8].vlak + (v&255); + if (is_raytraceable_vlr(re, vlr)) { + faces++; + if (faces > 4) + return 1; + } + } + } + return 0; +} +/* + * create a single raytrace structure with all faces + */ +static void makeraytree_single(Render *re) +{ + ObjectInstanceRen *obi; + RayObject *raytree; + RayFace *face = NULL; + VlakPrimitive *vlakprimitive = NULL; + int faces = 0, special = 0; + + for (obi = re->instancetable.first; obi; obi = obi->next) { + if (is_raytraceable(re, obi)) { + ObjectRen *obr = obi->obr; + + if (has_special_rayobject(re, obi)) { + special++; + } + else { + int v; + for (v = 0;v < obr->totvlak; v++) { + VlakRen *vlr = obr->vlaknodes[v >> 8].vlak + (v&255); + if (is_raytraceable_vlr(re, vlr)) { + faces++; + } + } + } + } + } + + if (faces + special == 0) { + re->raytree = RE_rayobject_empty_create(); + return; + } + + //Create raytree + raytree = re->raytree = rayobject_create( re, re->r.raytrace_structure, faces+special ); + + if ( (re->r.raytrace_options & R_RAYTRACE_USE_LOCAL_COORDS) ) { + vlakprimitive = re->rayprimitives = (VlakPrimitive *)MEM_callocN(faces * sizeof(VlakPrimitive), "Raytrace vlak-primitives"); + } + else { + face = re->rayfaces = (RayFace *)MEM_callocN(faces * sizeof(RayFace), "Render ray faces"); + } + + for (obi=re->instancetable.first; obi; obi=obi->next) + if (is_raytraceable(re, obi)) { + if (test_break(re)) + break; + + if (has_special_rayobject(re, obi)) { + RayObject *obj = makeraytree_object(re, obi); + + if (test_break(re)) + break; + + if (obj) + RE_rayobject_add(re->raytree, obj); + } + else { + int v; + ObjectRen *obr = obi->obr; + + if (obi->flag & R_TRANSFORMED) { + obi->transform_primitives = 1; + } + + for (v=0;v<obr->totvlak;v++) { + VlakRen *vlr = obr->vlaknodes[v>>8].vlak + (v&255); + if (is_raytraceable_vlr(re, vlr)) { + if ((re->r.raytrace_options & R_RAYTRACE_USE_LOCAL_COORDS)) { + RayObject *obj = RE_vlakprimitive_from_vlak( vlakprimitive, obi, vlr ); + RE_rayobject_add(raytree, obj); + vlakprimitive++; + } + else { + RE_rayface_from_vlak(face, obi, vlr); + if ((obi->flag & R_TRANSFORMED)) { + mul_m4_v3(obi->mat, face->v1); + mul_m4_v3(obi->mat, face->v2); + mul_m4_v3(obi->mat, face->v3); + if (RE_rayface_isQuad(face)) + mul_m4_v3(obi->mat, face->v4); + } + + RE_rayobject_add(raytree, RE_rayobject_unalignRayFace(face)); + face++; + } + } + } + } + } + + if (!test_break(re)) { + re->i.infostr = IFACE_("Raytree.. building"); + re->stats_draw(re->sdh, &re->i); + + RE_rayobject_done(raytree); + } +} + +void makeraytree(Render *re) +{ + float min[3], max[3], sub[3]; + int i; + + re->i.infostr = IFACE_("Raytree.. preparing"); + re->stats_draw(re->sdh, &re->i); + + /* disable options not yet supported by octree, + * they might actually never be supported (unless people really need it) */ + if (re->r.raytrace_structure == R_RAYSTRUCTURE_OCTREE) + re->r.raytrace_options &= ~( R_RAYTRACE_USE_INSTANCES | R_RAYTRACE_USE_LOCAL_COORDS); + + makeraytree_single(re); + + if (test_break(re)) { + freeraytree(re); + + re->i.infostr = IFACE_("Raytree building canceled"); + re->stats_draw(re->sdh, &re->i); + } + else { + /* Calculate raytree max_size + * This is ONLY needed to kept a bogus behavior of SUN and HEMI lights */ + INIT_MINMAX(min, max); + RE_rayobject_merge_bb(re->raytree, min, max); + if (min[0] > max[0]) { /* empty raytree */ + zero_v3(min); + zero_v3(max); + } + for (i=0; i<3; i++) { + /* TODO: explain why add top both min and max??? */ + min[i] += 0.01f; + max[i] += 0.01f; + sub[i] = max[i]-min[i]; + } + + re->maxdist = len_v3(sub); + + re->i.infostr = IFACE_("Raytree finished"); + re->stats_draw(re->sdh, &re->i); + } + +#ifdef RE_RAYCOUNTER + memset(re_rc_counter, 0, sizeof(re_rc_counter)); +#endif +} + +/* if (shi->osatex) */ +static void shade_ray_set_derivative(ShadeInput *shi) +{ + float detsh, t00, t10, t01, t11; + int axis1, axis2; + + /* find most stable axis to project */ + axis_dominant_v3(&axis1, &axis2, shi->facenor); + + /* compute u,v and derivatives */ + if (shi->obi->flag & R_TRANSFORMED) { + float v1[3], v2[3], v3[3]; + + mul_v3_m3v3(v1, shi->obi->nmat, shi->v1->co); + mul_v3_m3v3(v2, shi->obi->nmat, shi->v2->co); + mul_v3_m3v3(v3, shi->obi->nmat, shi->v3->co); + + /* same as below */ + t00= v3[axis1]-v1[axis1]; t01= v3[axis2]-v1[axis2]; + t10= v3[axis1]-v2[axis1]; t11= v3[axis2]-v2[axis2]; + } + else { + const float *v1= shi->v1->co; + const float *v2= shi->v2->co; + const float *v3= shi->v3->co; + + /* same as above */ + t00= v3[axis1]-v1[axis1]; t01= v3[axis2]-v1[axis2]; + t10= v3[axis1]-v2[axis1]; t11= v3[axis2]-v2[axis2]; + } + + detsh= 1.0f/(t00*t11-t10*t01); + t00*= detsh; t01*=detsh; + t10*=detsh; t11*=detsh; + + shi->dx_u= shi->dxco[axis1]*t11- shi->dxco[axis2]*t10; + shi->dx_v= shi->dxco[axis2]*t00- shi->dxco[axis1]*t01; + shi->dy_u= shi->dyco[axis1]*t11- shi->dyco[axis2]*t10; + shi->dy_v= shi->dyco[axis2]*t00- shi->dyco[axis1]*t01; + +} + +/* main ray shader */ +void shade_ray(Isect *is, ShadeInput *shi, ShadeResult *shr) +{ + ObjectInstanceRen *obi = (ObjectInstanceRen *)is->hit.ob; + VlakRen *vlr = (VlakRen *)is->hit.face; + + /* set up view vector */ + copy_v3_v3(shi->view, is->dir); + + /* render co */ + shi->co[0]= is->start[0]+is->dist*(shi->view[0]); + shi->co[1]= is->start[1]+is->dist*(shi->view[1]); + shi->co[2]= is->start[2]+is->dist*(shi->view[2]); + + normalize_v3(shi->view); + + shi->obi= obi; + shi->obr= obi->obr; + shi->vlr= vlr; + shi->mat= vlr->mat; + shade_input_init_material(shi); + + if (is->isect==2) + shade_input_set_triangle_i(shi, obi, vlr, 0, 2, 3); + else + shade_input_set_triangle_i(shi, obi, vlr, 0, 1, 2); + + shi->u= is->u; + shi->v= is->v; + shi->dx_u= shi->dx_v= shi->dy_u= shi->dy_v= 0.0f; + + if (shi->osatex) + shade_ray_set_derivative(shi); + shade_input_set_normals(shi); + + shade_input_set_shade_texco(shi); + if (shi->mat->material_type == MA_TYPE_VOLUME) { + if (ELEM(is->mode, RE_RAY_SHADOW, RE_RAY_SHADOW_TRA)) { + shade_volume_shadow(shi, shr, is); + } + else { + shade_volume_outside(shi, shr); + } + } + else if (is->mode==RE_RAY_SHADOW_TRA) { + /* temp hack to prevent recursion */ + if (shi->nodes==0 && shi->mat->nodetree && shi->mat->use_nodes) { + ntreeShaderExecTree(shi->mat->nodetree, shi, shr); + shi->mat= vlr->mat; /* shi->mat is being set in nodetree */ + } + else + shade_color(shi, shr); + } + else { + if (shi->mat->nodetree && shi->mat->use_nodes) { + ntreeShaderExecTree(shi->mat->nodetree, shi, shr); + shi->mat= vlr->mat; /* shi->mat is being set in nodetree */ + } + else { + shade_material_loop(shi, shr); + } + + /* raytrace likes to separate the spec color */ + sub_v3_v3v3(shr->diff, shr->combined, shr->spec); + copy_v3_v3(shr->diffshad, shr->diff); + } + +} + +static int refraction(float refract[3], const float n[3], const float view[3], float index) +{ + float dot, fac; + + copy_v3_v3(refract, view); + + dot = dot_v3v3(view, n); + + if (dot>0.0f) { + index = 1.0f/index; + fac= 1.0f - (1.0f - dot*dot)*index*index; + if (fac <= 0.0f) return 0; + fac= -dot*index + sqrtf(fac); + } + else { + fac= 1.0f - (1.0f - dot*dot)*index*index; + if (fac <= 0.0f) return 0; + fac= -dot*index - sqrtf(fac); + } + + refract[0]= index*view[0] + fac*n[0]; + refract[1]= index*view[1] + fac*n[1]; + refract[2]= index*view[2] + fac*n[2]; + + return 1; +} + +static void reflection_simple(float ref[3], float n[3], const float view[3]) +{ + const float f1= -2.0f * dot_v3v3(n, view); + madd_v3_v3v3fl(ref, view, n, f1); +} + +/* orn = original face normal */ +static void reflection(float ref[3], float n[3], const float view[3], const float orn[3]) +{ + float f1; + + reflection_simple(ref, n, view); + + /* test phong normals, then we should prevent vector going to the back */ + f1= dot_v3v3(ref, orn); + if (f1>0.0f) { + f1+= 0.01f; + ref[0]-= f1*orn[0]; + ref[1]-= f1*orn[1]; + ref[2]-= f1*orn[2]; + } +} + +#if 0 +static void color_combine(float *result, float fac1, float fac2, float col1[3], float col2[3]) +{ + float col1t[3], col2t[3]; + + col1t[0]= sqrt(col1[0]); + col1t[1]= sqrt(col1[1]); + col1t[2]= sqrt(col1[2]); + col2t[0]= sqrt(col2[0]); + col2t[1]= sqrt(col2[1]); + col2t[2]= sqrt(col2[2]); + + result[0]= (fac1*col1t[0] + fac2*col2t[0]); + result[0]*= result[0]; + result[1]= (fac1*col1t[1] + fac2*col2t[1]); + result[1]*= result[1]; + result[2]= (fac1*col1t[2] + fac2*col2t[2]); + result[2]*= result[2]; +} +#endif + +static float shade_by_transmission(Isect *is, ShadeInput *shi, ShadeResult *shr) +{ + float d; + if (0 == (shi->mat->mode & MA_TRANSP)) + return -1; + + if (shi->mat->tx_limit <= 0.0f) { + d= 1.0f; + } + else { + float p; + + /* shi.co[] calculated by shade_ray() */ + const float dx= shi->co[0] - is->start[0]; + const float dy= shi->co[1] - is->start[1]; + const float dz= shi->co[2] - is->start[2]; + d = sqrtf(dx * dx + dy * dy + dz * dz); + if (d > shi->mat->tx_limit) + d= shi->mat->tx_limit; + + p = shi->mat->tx_falloff; + if (p < 0.0f) p= 0.0f; + else if (p > 10.0f) p= 10.0f; + + shr->alpha *= powf(d, p); + if (shr->alpha > 1.0f) + shr->alpha= 1.0f; + } + + return d; +} + +static void ray_fadeout_endcolor(float col[3], ShadeInput *origshi, ShadeInput *shi, ShadeResult *shr, Isect *isec, const float vec[3]) +{ + /* un-intersected rays get either rendered material color or sky color */ + if (origshi->mat->fadeto_mir == MA_RAYMIR_FADETOMAT) { + copy_v3_v3(col, shr->combined); + } + else if (origshi->mat->fadeto_mir == MA_RAYMIR_FADETOSKY) { + copy_v3_v3(shi->view, vec); + normalize_v3(shi->view); + + shadeSkyView(col, isec->start, shi->view, NULL, shi->thread); + shadeSunView(col, shi->view); + } +} + +static void ray_fadeout(Isect *is, ShadeInput *shi, float col[3], const float blendcol[3], float dist_mir) +{ + /* if fading out, linear blend against fade color */ + float blendfac; + + blendfac = 1.0f - len_v3v3(shi->co, is->start)/dist_mir; + + col[0] = col[0]*blendfac + (1.0f - blendfac)*blendcol[0]; + col[1] = col[1]*blendfac + (1.0f - blendfac)*blendcol[1]; + col[2] = col[2]*blendfac + (1.0f - blendfac)*blendcol[2]; +} + +/* the main recursive tracer itself + * note: 'col' must be initialized */ +static void traceray(ShadeInput *origshi, ShadeResult *origshr, short depth, const float start[3], const float dir[3], float col[4], ObjectInstanceRen *obi, VlakRen *vlr, int traflag) +{ + ShadeInput shi = {NULL}; + Isect isec; + float dist_mir = origshi->mat->dist_mir; + + /* with high depth the number of rays can explode due to the path splitting + * in two each time, giving 2^depth rays. we need to be able to cancel such + * a render to avoid hanging, a better solution would be random picking + * between directions and russian roulette termination */ + if (R.test_break(R.tbh)) { + zero_v4(col); + return; + } + + copy_v3_v3(isec.start, start); + copy_v3_v3(isec.dir, dir); + isec.dist = dist_mir > 0 ? dist_mir : RE_RAYTRACE_MAXDIST; + isec.mode= RE_RAY_MIRROR; + isec.check = RE_CHECK_VLR_RENDER; + isec.skip = RE_SKIP_VLR_NEIGHBOUR; + isec.hint = NULL; + + isec.orig.ob = obi; + isec.orig.face = vlr; + RE_RC_INIT(isec, shi); + + /* database is in original view, obi->imat transforms current position back to original */ + RE_instance_rotate_ray(origshi->obi, &isec); + + if (RE_rayobject_raycast(R.raytree, &isec)) { + ShadeResult shr= {{0}}; + float d= 1.0f; + + RE_instance_rotate_ray_restore(origshi->obi, &isec); + + /* for as long we don't have proper dx/dy transform for rays we copy over original */ + copy_v3_v3(shi.dxco, origshi->dxco); + copy_v3_v3(shi.dyco, origshi->dyco); + + shi.mask= origshi->mask; + shi.osatex= origshi->osatex; + shi.depth= origshi->depth + 1; /* only used to indicate tracing */ + shi.thread= origshi->thread; + //shi.sample= 0; // memset above, so don't need this + shi.xs= origshi->xs; + shi.ys= origshi->ys; + shi.do_manage= origshi->do_manage; + shi.lay= origshi->lay; + shi.passflag= SCE_PASS_COMBINED; /* result of tracing needs no pass info */ + shi.combinedflag= 0xFFFFFF; /* ray trace does all options */ + //shi.do_preview = false; // memset above, so don't need this + shi.light_override= origshi->light_override; + shi.mat_override= origshi->mat_override; + + shade_ray(&isec, &shi, &shr); + /* ray has traveled inside the material, so shade by transmission */ + if (traflag & RAY_INSIDE) + d= shade_by_transmission(&isec, &shi, &shr); + + if (depth>0) { + float fr, fg, fb, f1; + + if ((shi.mat->mode_l & MA_TRANSP) && shr.alpha < 1.0f && (shi.mat->mode_l & (MA_ZTRANSP | MA_RAYTRANSP))) { + float nf, f, refract[3], tracol[4]; + + tracol[0]= shi.r; + tracol[1]= shi.g; + tracol[2]= shi.b; + tracol[3]= col[3]; /* we pass on and accumulate alpha */ + + if ((shi.mat->mode & MA_TRANSP) && (shi.mat->mode & MA_RAYTRANSP)) { + /* don't overwrite traflag, it's value is used in mirror reflection */ + int new_traflag = traflag; + + if (new_traflag & RAY_INSIDE) { + /* inside the material, so use inverse normal */ + float norm[3]; + norm[0]= - shi.vn[0]; + norm[1]= - shi.vn[1]; + norm[2]= - shi.vn[2]; + + if (refraction(refract, norm, shi.view, shi.ang)) { + /* ray comes out from the material into air */ + new_traflag &= ~RAY_INSIDE; + } + else { + /* total internal reflection (ray stays inside the material) */ + reflection(refract, norm, shi.view, shi.vn); + } + } + else { + if (refraction(refract, shi.vn, shi.view, shi.ang)) { + /* ray goes in to the material from air */ + new_traflag |= RAY_INSIDE; + } + else { + /* total external reflection (ray doesn't enter the material) */ + reflection(refract, shi.vn, shi.view, shi.vn); + } + } + traceray(origshi, origshr, depth-1, shi.co, refract, tracol, shi.obi, shi.vlr, new_traflag); + } + else + traceray(origshi, origshr, depth-1, shi.co, shi.view, tracol, shi.obi, shi.vlr, 0); + + f= shr.alpha; f1= 1.0f-f; + nf= (shi.mat->mode & MA_RAYTRANSP) ? d * shi.mat->filter : 0.0f; + fr= 1.0f+ nf*(shi.r-1.0f); + fg= 1.0f+ nf*(shi.g-1.0f); + fb= 1.0f+ nf*(shi.b-1.0f); + shr.diff[0]= f*shr.diff[0] + f1*fr*tracol[0]; + shr.diff[1]= f*shr.diff[1] + f1*fg*tracol[1]; + shr.diff[2]= f*shr.diff[2] + f1*fb*tracol[2]; + + shr.spec[0] *=f; + shr.spec[1] *=f; + shr.spec[2] *=f; + + col[3]= f1*tracol[3] + f; + } + else { + col[3]= 1.0f; + } + + float f; + if (shi.mat->mode_l & MA_RAYMIRROR) { + f= shi.ray_mirror; + if (f!=0.0f) f*= fresnel_fac(shi.view, shi.vn, shi.mat->fresnel_mir_i, shi.mat->fresnel_mir); + } + else f= 0.0f; + + if (f!=0.0f) { + float mircol[4]; + float ref[3]; + + reflection_simple(ref, shi.vn, shi.view); + traceray(origshi, origshr, depth-1, shi.co, ref, mircol, shi.obi, shi.vlr, traflag); + + f1= 1.0f-f; + + /* combine */ + //color_combine(col, f*fr*(1.0f-shr.spec[0]), f1, col, shr.diff); + //col[0]+= shr.spec[0]; + //col[1]+= shr.spec[1]; + //col[2]+= shr.spec[2]; + + fr= shi.mirr; + fg= shi.mirg; + fb= shi.mirb; + + col[0]= f*fr*(1.0f-shr.spec[0])*mircol[0] + f1*shr.diff[0] + shr.spec[0]; + col[1]= f*fg*(1.0f-shr.spec[1])*mircol[1] + f1*shr.diff[1] + shr.spec[1]; + col[2]= f*fb*(1.0f-shr.spec[2])*mircol[2] + f1*shr.diff[2] + shr.spec[2]; + } + else { + col[0]= shr.diff[0] + shr.spec[0]; + col[1]= shr.diff[1] + shr.spec[1]; + col[2]= shr.diff[2] + shr.spec[2]; + } + + if (dist_mir > 0.0f) { + float blendcol[3]; + + /* max ray distance set, but found an intersection, so fade this color + * out towards the sky/material color for a smooth transition */ + ray_fadeout_endcolor(blendcol, origshi, &shi, origshr, &isec, dir); + ray_fadeout(&isec, &shi, col, blendcol, dist_mir); + } + } + else { + col[0]= shr.diff[0] + shr.spec[0]; + col[1]= shr.diff[1] + shr.spec[1]; + col[2]= shr.diff[2] + shr.spec[2]; + } + + } + else { + ray_fadeout_endcolor(col, origshi, &shi, origshr, &isec, dir); + } + RE_RC_MERGE(&origshi->raycounter, &shi.raycounter); +} + +/* **************** jitter blocks ********** */ + +/* calc distributed planar energy */ + +static void DP_energy(float *table, float vec[2], int tot, float xsize, float ysize) +{ + int x, y, a; + float *fp, force[3], result[3]; + float dx, dy, dist, min; + + min= MIN2(xsize, ysize); + min*= min; + result[0]= result[1]= 0.0f; + + for (y= -1; y<2; y++) { + dy= ysize*y; + for (x= -1; x<2; x++) { + dx= xsize*x; + fp= table; + for (a=0; a<tot; a++, fp+= 2) { + force[0]= vec[0] - fp[0]-dx; + force[1]= vec[1] - fp[1]-dy; + dist= force[0]*force[0] + force[1]*force[1]; + if (dist < min && dist>0.0f) { + result[0]+= force[0]/dist; + result[1]+= force[1]/dist; + } + } + } + } + vec[0] += 0.1f*min*result[0]/(float)tot; + vec[1] += 0.1f*min*result[1]/(float)tot; + /* cyclic clamping */ + vec[0]= vec[0] - xsize*floorf(vec[0]/xsize + 0.5f); + vec[1]= vec[1] - ysize*floorf(vec[1]/ysize + 0.5f); +} + +/* random offset of 1 in 2 */ +static void jitter_plane_offset(float *jitter1, float *jitter2, int tot, float sizex, float sizey, float ofsx, float ofsy) +{ + float dsizex= sizex*ofsx; + float dsizey= sizey*ofsy; + float hsizex= 0.5f*sizex, hsizey= 0.5f*sizey; + int x; + + for (x=tot; x>0; x--, jitter1+=2, jitter2+=2) { + jitter2[0]= jitter1[0] + dsizex; + jitter2[1]= jitter1[1] + dsizey; + if (jitter2[0] > hsizex) jitter2[0]-= sizex; + if (jitter2[1] > hsizey) jitter2[1]-= sizey; + } +} + +/* called from convertBlenderScene.c */ +/* we do this in advance to get consistent random, not alter the render seed, and be threadsafe */ +void init_jitter_plane(LampRen *lar) +{ + float *fp; + int x, tot= lar->ray_totsamp; + + /* test if already initialized */ + if (lar->jitter) return; + + /* at least 4, or max threads+1 tables */ + if (BLENDER_MAX_THREADS < 4) x= 4; + else x= BLENDER_MAX_THREADS+1; + fp= lar->jitter= MEM_callocN(x*tot*2*sizeof(float), "lamp jitter tab"); + + /* if 1 sample, we leave table to be zero's */ + if (tot>1) { + /* set per-lamp fixed seed */ + RNG *rng = BLI_rng_new_srandom(tot); + int iter=12; + + /* fill table with random locations, area_size large */ + for (x=0; x<tot; x++, fp+=2) { + fp[0]= (BLI_rng_get_float(rng)-0.5f)*lar->area_size; + fp[1]= (BLI_rng_get_float(rng)-0.5f)*lar->area_sizey; + } + + while (iter--) { + fp= lar->jitter; + for (x=tot; x>0; x--, fp+=2) { + DP_energy(lar->jitter, fp, tot, lar->area_size, lar->area_sizey); + } + } + + BLI_rng_free(rng); + } + /* create the dithered tables (could just check lamp type!) */ + jitter_plane_offset(lar->jitter, lar->jitter+2*tot, tot, lar->area_size, lar->area_sizey, 0.5f, 0.0f); + jitter_plane_offset(lar->jitter, lar->jitter+4*tot, tot, lar->area_size, lar->area_sizey, 0.5f, 0.5f); + jitter_plane_offset(lar->jitter, lar->jitter+6*tot, tot, lar->area_size, lar->area_sizey, 0.0f, 0.5f); +} + +/* table around origin, -0.5*size to 0.5*size */ +static float *give_jitter_plane(LampRen *lar, int thread, int xs, int ys) +{ + int tot; + + tot= lar->ray_totsamp; + + if (lar->ray_samp_type & LA_SAMP_JITTER) { + /* made it threadsafe */ + + if (lar->xold[thread]!=xs || lar->yold[thread]!=ys) { + jitter_plane_offset(lar->jitter, lar->jitter+2*(thread+1)*tot, tot, lar->area_size, lar->area_sizey, BLI_thread_frand(thread), BLI_thread_frand(thread)); + lar->xold[thread]= xs; + lar->yold[thread]= ys; + } + return lar->jitter+2*(thread+1)*tot; + } + if (lar->ray_samp_type & LA_SAMP_DITHER) { + return lar->jitter + 2*tot*((xs & 1)+2*(ys & 1)); + } + + return lar->jitter; +} + + +/* **************** QMC sampling *************** */ + +static void halton_sample(double *ht_invprimes, double *ht_nums, double *v) +{ + /* incremental halton sequence generator, from: + * "Instant Radiosity", Keller A. */ + unsigned int i; + + for (i = 0; i < 2; i++) { + double r = fabs((1.0 - ht_nums[i]) - 1e-10); + + if (ht_invprimes[i] >= r) { + double lasth; + double h = ht_invprimes[i]; + + do { + lasth = h; + h *= ht_invprimes[i]; + } while (h >= r); + + ht_nums[i] += ((lasth + h) - 1.0); + } + else + ht_nums[i] += ht_invprimes[i]; + + v[i] = (float)ht_nums[i]; + } +} + +/* Generate Hammersley points in [0,1)^2 + * From Lucille renderer */ +static void hammersley_create(double *out, int n) +{ + double p, t; + int k, kk; + + for (k = 0; k < n; k++) { + t = 0; + for (p = 0.5, kk = k; kk; p *= 0.5, kk >>= 1) { + if (kk & 1) { /* kk mod 2 = 1 */ + t += p; + } + } + + out[2 * k + 0] = (double)k / (double)n; + out[2 * k + 1] = t; + } +} + +static struct QMCSampler *QMC_initSampler(int type, int tot) +{ + QMCSampler *qsa = MEM_callocN(sizeof(QMCSampler), "qmc sampler"); + qsa->samp2d = MEM_callocN(2*sizeof(double)*tot, "qmc sample table"); + + qsa->tot = tot; + qsa->type = type; + + if (qsa->type==SAMP_TYPE_HAMMERSLEY) + hammersley_create(qsa->samp2d, qsa->tot); + + return qsa; +} + +static void QMC_initPixel(QMCSampler *qsa, int thread) +{ + if (qsa->type==SAMP_TYPE_HAMMERSLEY) { + /* hammersley sequence is fixed, already created in QMCSampler init. + * per pixel, gets a random offset. We create separate offsets per thread, for write-safety */ + qsa->offs[thread][0] = 0.5f * BLI_thread_frand(thread); + qsa->offs[thread][1] = 0.5f * BLI_thread_frand(thread); + } + else { /* SAMP_TYPE_HALTON */ + + /* generate a new randomized halton sequence per pixel + * to alleviate qmc artifacts and make it reproducible + * between threads/frames */ + double ht_invprimes[2], ht_nums[2]; + double r[2]; + int i; + + ht_nums[0] = BLI_thread_frand(thread); + ht_nums[1] = BLI_thread_frand(thread); + ht_invprimes[0] = 0.5; + ht_invprimes[1] = 1.0/3.0; + + for (i=0; i< qsa->tot; i++) { + halton_sample(ht_invprimes, ht_nums, r); + qsa->samp2d[2*i+0] = r[0]; + qsa->samp2d[2*i+1] = r[1]; + } + } +} + +static void QMC_freeSampler(QMCSampler *qsa) +{ + MEM_freeN(qsa->samp2d); + MEM_freeN(qsa); +} + +static void QMC_getSample(double *s, QMCSampler *qsa, int thread, int num) +{ + if (qsa->type == SAMP_TYPE_HAMMERSLEY) { + s[0] = fmod(qsa->samp2d[2*num+0] + qsa->offs[thread][0], 1.0f); + s[1] = fmod(qsa->samp2d[2*num+1] + qsa->offs[thread][1], 1.0f); + } + else { /* SAMP_TYPE_HALTON */ + s[0] = qsa->samp2d[2*num+0]; + s[1] = qsa->samp2d[2*num+1]; + } +} + +/* phong weighted disc using 'blur' for exponent, centred on 0,0 */ +static void QMC_samplePhong(float vec[3], QMCSampler *qsa, int thread, int num, float blur) +{ + double s[2]; + float phi, pz, sqr; + + QMC_getSample(s, qsa, thread, num); + + phi = s[0]*2*M_PI; + pz = pow(s[1], blur); + sqr = sqrtf(1.0f - pz * pz); + + vec[0] = (float)(cosf(phi)*sqr); + vec[1] = (float)(sinf(phi)*sqr); + vec[2] = 0.0f; +} + +/* rect of edge lengths sizex, sizey, centred on 0.0,0.0 i.e. ranging from -sizex/2 to +sizey/2 */ +static void QMC_sampleRect(float vec[3], QMCSampler *qsa, int thread, int num, float sizex, float sizey) +{ + double s[2]; + + QMC_getSample(s, qsa, thread, num); + + vec[0] = (float)(s[0] - 0.5) * sizex; + vec[1] = (float)(s[1] - 0.5) * sizey; + vec[2] = 0.0f; +} + +/* disc of radius 'radius', centred on 0,0 */ +static void QMC_sampleDisc(float vec[3], QMCSampler *qsa, int thread, int num, float radius) +{ + double s[2]; + float phi, sqr; + + QMC_getSample(s, qsa, thread, num); + + phi = s[0]*2*M_PI; + sqr = sqrt(s[1]); + + vec[0] = cosf(phi)*sqr* radius/2.0f; + vec[1] = sinf(phi)*sqr* radius/2.0f; + vec[2] = 0.0f; +} + +/* uniform hemisphere sampling */ +static void QMC_sampleHemi(float vec[3], QMCSampler *qsa, int thread, int num) +{ + double s[2]; + float phi, sqr; + + QMC_getSample(s, qsa, thread, num); + + phi = s[0]*2.0*M_PI; + sqr = sqrt(s[1]); + + vec[0] = cosf(phi)*sqr; + vec[1] = sinf(phi)*sqr; + vec[2] = (float)(1.0 - s[1]*s[1]); +} + +#if 0 /* currently not used */ +/* cosine weighted hemisphere sampling */ +static void QMC_sampleHemiCosine(float vec[3], QMCSampler *qsa, int thread, int num) +{ + double s[2]; + float phi, sqr; + + QMC_getSample(s, qsa, thread, num); + + phi = s[0]*2.f*M_PI; + sqr = s[1]*sqrt(2-s[1]*s[1]); + + vec[0] = cos(phi)*sqr; + vec[1] = sin(phi)*sqr; + vec[2] = 1.f - s[1]*s[1]; + +} +#endif + +/* called from convertBlenderScene.c */ +void init_render_qmcsampler(Render *re) +{ + const int num_threads = re->r.threads; + re->qmcsamplers= MEM_callocN(sizeof(ListBase)*num_threads, "QMCListBase"); + re->num_qmc_samplers = num_threads; +} + +static QMCSampler *get_thread_qmcsampler(Render *re, int thread, int type, int tot) +{ + QMCSampler *qsa; + + /* create qmc samplers as needed, since recursion makes it hard to + * predict how many are needed */ + + for (qsa=re->qmcsamplers[thread].first; qsa; qsa=qsa->next) { + if (qsa->type == type && qsa->tot == tot && !qsa->used) { + qsa->used = true; + return qsa; + } + } + + qsa= QMC_initSampler(type, tot); + qsa->used = true; + BLI_addtail(&re->qmcsamplers[thread], qsa); + + return qsa; +} + +static void release_thread_qmcsampler(Render *UNUSED(re), int UNUSED(thread), QMCSampler *qsa) +{ + qsa->used= 0; +} + +void free_render_qmcsampler(Render *re) +{ + if (re->qmcsamplers) { + QMCSampler *qsa, *next; + int a; + for (a = 0; a < re->num_qmc_samplers; a++) { + for (qsa=re->qmcsamplers[a].first; qsa; qsa=next) { + next= qsa->next; + QMC_freeSampler(qsa); + } + + re->qmcsamplers[a].first= re->qmcsamplers[a].last= NULL; + } + + MEM_freeN(re->qmcsamplers); + re->qmcsamplers= NULL; + } +} + +static int adaptive_sample_variance(int samples, const float col[3], const float colsq[3], float thresh) +{ + float var[3], mean[3]; + + /* scale threshold just to give a bit more precision in input rather than dealing with + * tiny tiny numbers in the UI */ + thresh /= 2; + + mean[0] = col[0] / (float)samples; + mean[1] = col[1] / (float)samples; + mean[2] = col[2] / (float)samples; + + var[0] = (colsq[0] / (float)samples) - (mean[0]*mean[0]); + var[1] = (colsq[1] / (float)samples) - (mean[1]*mean[1]); + var[2] = (colsq[2] / (float)samples) - (mean[2]*mean[2]); + + if ((var[0] * 0.4f < thresh) && (var[1] * 0.3f < thresh) && (var[2] * 0.6f < thresh)) + return 1; + else + return 0; +} + +static int adaptive_sample_contrast_val(int samples, float prev, float val, float thresh) +{ + /* if the last sample's contribution to the total value was below a small threshold + * (i.e. the samples taken are very similar), then taking more samples that are probably + * going to be the same is wasting effort */ + if (fabsf(prev / (float)(samples - 1) - val / (float)samples ) < thresh) { + return 1; + } + else + return 0; +} + +static float get_avg_speed(ShadeInput *shi) +{ + float pre_x, pre_y, post_x, post_y, speedavg; + + pre_x = (shi->winspeed[0] == PASS_VECTOR_MAX)?0.0f:shi->winspeed[0]; + pre_y = (shi->winspeed[1] == PASS_VECTOR_MAX)?0.0f:shi->winspeed[1]; + post_x = (shi->winspeed[2] == PASS_VECTOR_MAX)?0.0f:shi->winspeed[2]; + post_y = (shi->winspeed[3] == PASS_VECTOR_MAX)?0.0f:shi->winspeed[3]; + + speedavg = (sqrtf(pre_x * pre_x + pre_y * pre_y) + sqrtf(post_x * post_x + post_y * post_y)) / 2.0f; + + return speedavg; +} + +/* ***************** main calls ************** */ + + +static void trace_refract(float col[4], ShadeInput *shi, ShadeResult *shr) +{ + QMCSampler *qsa=NULL; + int samp_type; + int traflag=0; + + float samp3d[3], orthx[3], orthy[3]; + float v_refract[3], v_refract_new[3]; + float sampcol[4], colsq[4]; + + float blur = pow3f(1.0f - shi->mat->gloss_tra); + short max_samples = shi->mat->samp_gloss_tra; + float adapt_thresh = shi->mat->adapt_thresh_tra; + + int samples=0; + + colsq[0] = colsq[1] = colsq[2] = 0.0; + col[0] = col[1] = col[2] = 0.0; + col[3]= shr->alpha; + + if (blur > 0.0f) { + if (adapt_thresh != 0.0f) samp_type = SAMP_TYPE_HALTON; + else samp_type = SAMP_TYPE_HAMMERSLEY; + + /* all samples are generated per pixel */ + qsa = get_thread_qmcsampler(&R, shi->thread, samp_type, max_samples); + QMC_initPixel(qsa, shi->thread); + } + else + max_samples = 1; + + + while (samples < max_samples) { + if (refraction(v_refract, shi->vn, shi->view, shi->ang)) { + traflag |= RAY_INSIDE; + } + else { + /* total external reflection can happen for materials with IOR < 1.0 */ + if ((shi->vlr->flag & R_SMOOTH)) + reflection(v_refract, shi->vn, shi->view, shi->facenor); + else + reflection_simple(v_refract, shi->vn, shi->view); + + /* can't blur total external reflection */ + max_samples = 1; + } + + if (max_samples > 1) { + /* get a quasi-random vector from a phong-weighted disc */ + QMC_samplePhong(samp3d, qsa, shi->thread, samples, blur); + + ortho_basis_v3v3_v3(orthx, orthy, v_refract); + mul_v3_fl(orthx, samp3d[0]); + mul_v3_fl(orthy, samp3d[1]); + + /* and perturb the refraction vector in it */ + add_v3_v3v3(v_refract_new, v_refract, orthx); + add_v3_v3(v_refract_new, orthy); + + normalize_v3(v_refract_new); + } + else { + /* no blurriness, use the original normal */ + copy_v3_v3(v_refract_new, v_refract); + } + + sampcol[0]= sampcol[1]= sampcol[2]= sampcol[3]= 0.0f; + + traceray(shi, shr, shi->mat->ray_depth_tra, shi->co, v_refract_new, sampcol, shi->obi, shi->vlr, traflag); + + col[0] += sampcol[0]; + col[1] += sampcol[1]; + col[2] += sampcol[2]; + col[3] += sampcol[3]; + + /* for variance calc */ + colsq[0] += sampcol[0]*sampcol[0]; + colsq[1] += sampcol[1]*sampcol[1]; + colsq[2] += sampcol[2]*sampcol[2]; + + samples++; + + /* adaptive sampling */ + if (adapt_thresh < 1.0f && samples > max_samples/2) { + if (adaptive_sample_variance(samples, col, colsq, adapt_thresh)) + break; + + /* if the pixel so far is very dark, we can get away with less samples */ + if ( (col[0] + col[1] + col[2])/3.0f/(float)samples < 0.01f ) + max_samples--; + } + } + + col[0] /= (float)samples; + col[1] /= (float)samples; + col[2] /= (float)samples; + col[3] /= (float)samples; + + if (qsa) + release_thread_qmcsampler(&R, shi->thread, qsa); +} + +static void trace_reflect(float col[3], ShadeInput *shi, ShadeResult *shr, float fresnelfac) +{ + QMCSampler *qsa=NULL; + int samp_type; + + float samp3d[3], orthx[3], orthy[3]; + float v_nor_new[3], v_reflect[3]; + float sampcol[4], colsq[4]; + + float blur = pow3f(1.0f - shi->mat->gloss_mir); + short max_samples = shi->mat->samp_gloss_mir; + float adapt_thresh = shi->mat->adapt_thresh_mir; + float aniso = 1.0f - shi->mat->aniso_gloss_mir; + + int samples=0; + + col[0] = col[1] = col[2] = 0.0; + colsq[0] = colsq[1] = colsq[2] = 0.0; + + if (blur > 0.0f) { + if (adapt_thresh != 0.0f) samp_type = SAMP_TYPE_HALTON; + else samp_type = SAMP_TYPE_HAMMERSLEY; + + /* all samples are generated per pixel */ + qsa = get_thread_qmcsampler(&R, shi->thread, samp_type, max_samples); + QMC_initPixel(qsa, shi->thread); + } + else + max_samples = 1; + + while (samples < max_samples) { + + if (max_samples > 1) { + /* get a quasi-random vector from a phong-weighted disc */ + QMC_samplePhong(samp3d, qsa, shi->thread, samples, blur); + + /* find the normal's perpendicular plane, blurring along tangents + * if tangent shading enabled */ + if (shi->mat->mode & (MA_TANGENT_V)) { + cross_v3_v3v3(orthx, shi->vn, shi->tang); // bitangent + copy_v3_v3(orthy, shi->tang); + mul_v3_fl(orthx, samp3d[0]); + mul_v3_fl(orthy, samp3d[1]*aniso); + } + else { + ortho_basis_v3v3_v3(orthx, orthy, shi->vn); + mul_v3_fl(orthx, samp3d[0]); + mul_v3_fl(orthy, samp3d[1]); + } + + /* and perturb the normal in it */ + add_v3_v3v3(v_nor_new, shi->vn, orthx); + add_v3_v3(v_nor_new, orthy); + normalize_v3(v_nor_new); + } + else { + /* no blurriness, use the original normal */ + copy_v3_v3(v_nor_new, shi->vn); + } + + if ((shi->vlr->flag & R_SMOOTH)) + reflection(v_reflect, v_nor_new, shi->view, shi->facenor); + else + reflection_simple(v_reflect, v_nor_new, shi->view); + + sampcol[0]= sampcol[1]= sampcol[2]= sampcol[3]= 0.0f; + + traceray(shi, shr, shi->mat->ray_depth, shi->co, v_reflect, sampcol, shi->obi, shi->vlr, 0); + + + col[0] += sampcol[0]; + col[1] += sampcol[1]; + col[2] += sampcol[2]; + + /* for variance calc */ + colsq[0] += sampcol[0]*sampcol[0]; + colsq[1] += sampcol[1]*sampcol[1]; + colsq[2] += sampcol[2]*sampcol[2]; + + samples++; + + /* adaptive sampling */ + if (adapt_thresh > 0.0f && samples > max_samples/3) { + if (adaptive_sample_variance(samples, col, colsq, adapt_thresh)) + break; + + /* if the pixel so far is very dark, we can get away with less samples */ + if ( (col[0] + col[1] + col[2])/3.0f/(float)samples < 0.01f ) + max_samples--; + + /* reduce samples when reflection is dim due to low ray mirror blend value or fresnel factor + * and when reflection is blurry */ + if (fresnelfac < 0.1f * (blur+1)) { + max_samples--; + + /* even more for very dim */ + if (fresnelfac < 0.05f * (blur+1)) + max_samples--; + } + } + } + + col[0] /= (float)samples; + col[1] /= (float)samples; + col[2] /= (float)samples; + + if (qsa) + release_thread_qmcsampler(&R, shi->thread, qsa); +} + +/* extern call from render loop */ +void ray_trace(ShadeInput *shi, ShadeResult *shr) +{ + float f1, fr, fg, fb; + float mircol[4], tracol[4]; + float diff[3]; + int do_tra, do_mir; + + do_tra = ((shi->mode & MA_TRANSP) && (shi->mode & MA_RAYTRANSP) && shr->alpha != 1.0f && (shi->depth <= shi->mat->ray_depth_tra)); + do_mir = ((shi->mat->mode & MA_RAYMIRROR) && shi->ray_mirror != 0.0f && (shi->depth <= shi->mat->ray_depth)); + + /* raytrace mirror and refract like to separate the spec color */ + if (shi->combinedflag & SCE_PASS_SPEC) + sub_v3_v3v3(diff, shr->combined, shr->spec); + else + copy_v3_v3(diff, shr->combined); + + if (do_tra) { + float olddiff[3], f; + + trace_refract(tracol, shi, shr); + + f= shr->alpha; f1= 1.0f-f; + fr= 1.0f+ shi->mat->filter*(shi->r-1.0f); + fg= 1.0f+ shi->mat->filter*(shi->g-1.0f); + fb= 1.0f+ shi->mat->filter*(shi->b-1.0f); + + /* for refract pass */ + copy_v3_v3(olddiff, diff); + + diff[0]= f*diff[0] + f1*fr*tracol[0]; + diff[1]= f*diff[1] + f1*fg*tracol[1]; + diff[2]= f*diff[2] + f1*fb*tracol[2]; + + if (shi->passflag & SCE_PASS_REFRACT) + sub_v3_v3v3(shr->refr, diff, olddiff); + + if (!(shi->combinedflag & SCE_PASS_REFRACT)) + sub_v3_v3v3(diff, diff, shr->refr); + + shr->alpha = min_ff(1.0f, tracol[3]); + } + + if (do_mir) { + const float i= shi->ray_mirror*fresnel_fac(shi->view, shi->vn, shi->mat->fresnel_mir_i, shi->mat->fresnel_mir); + if (i!=0.0f) { + + trace_reflect(mircol, shi, shr, i); + + fr= i*shi->mirr; + fg= i*shi->mirg; + fb= i*shi->mirb; + + if (shi->passflag & SCE_PASS_REFLECT) { + /* mirror pass is not blocked out with spec */ + shr->refl[0]= fr*mircol[0] - fr*diff[0]; + shr->refl[1]= fg*mircol[1] - fg*diff[1]; + shr->refl[2]= fb*mircol[2] - fb*diff[2]; + } + + if (shi->combinedflag & SCE_PASS_REFLECT) { + /* values in shr->spec can be greater than 1.0. + * In this case the mircol uses a zero blending factor, so ignoring it is ok. + * Fixes bug #18837 - when the spec is higher then 1.0, + * diff can become a negative color - Campbell */ + + f1= 1.0f-i; + + diff[0] *= f1; + diff[1] *= f1; + diff[2] *= f1; + + if (shr->spec[0]<1.0f) diff[0] += mircol[0] * (fr*(1.0f-shr->spec[0])); + if (shr->spec[1]<1.0f) diff[1] += mircol[1] * (fg*(1.0f-shr->spec[1])); + if (shr->spec[2]<1.0f) diff[2] += mircol[2] * (fb*(1.0f-shr->spec[2])); + } + } + } + /* put back together */ + if (shi->combinedflag & SCE_PASS_SPEC) + add_v3_v3v3(shr->combined, diff, shr->spec); + else + copy_v3_v3(shr->combined, diff); +} + +/* color 'shadfac' passes through 'col' with alpha and filter */ +/* filter is only applied on alpha defined transparent part */ +static void addAlphaLight(float shadfac[4], const float col[3], float alpha, float filter) +{ + float fr, fg, fb; + + fr= 1.0f+ filter*(col[0]-1.0f); + fg= 1.0f+ filter*(col[1]-1.0f); + fb= 1.0f+ filter*(col[2]-1.0f); + + shadfac[0]= alpha*col[0] + fr*(1.0f-alpha)*shadfac[0]; + shadfac[1]= alpha*col[1] + fg*(1.0f-alpha)*shadfac[1]; + shadfac[2]= alpha*col[2] + fb*(1.0f-alpha)*shadfac[2]; + + shadfac[3]= (1.0f-alpha)*shadfac[3]; +} + +static void ray_trace_shadow_tra(Isect *is, ShadeInput *origshi, int depth, int traflag, float col[4]) +{ + /* ray to lamp, find first face that intersects, check alpha properties, + * if it has col[3]>0.0f continue. so exit when alpha is full */ + const float initial_dist = is->dist; + + if (RE_rayobject_raycast(R.raytree, is)) { + /* Warning regarding initializing to zero's, This is not that nice, + * and possibly a bit slow for every ray, however some variables were + * not initialized properly in, unless using + * shade_input_initialize(...), we need to zero them. */ + ShadeInput shi= {NULL}; + /* end warning! - Campbell */ + + ShadeResult shr; + + /* we got a face */ + + shi.depth= origshi->depth + 1; /* only used to indicate tracing */ + shi.mask= origshi->mask; + shi.thread= origshi->thread; + shi.passflag= SCE_PASS_COMBINED; + shi.combinedflag= 0xFFFFFF; /* ray trace does all options */ + + shi.xs= origshi->xs; + shi.ys= origshi->ys; + shi.do_manage= origshi->do_manage; + shi.lay= origshi->lay; + shi.nodes= origshi->nodes; + + RE_instance_rotate_ray_restore(origshi->obi, is); + + shade_ray(is, &shi, &shr); + if (shi.mat->material_type == MA_TYPE_SURFACE) { + const float d = (shi.mat->mode & MA_RAYTRANSP) ? + ((traflag & RAY_TRA) ? shade_by_transmission(is, &shi, &shr) : 1.0f) : + 0.0f; + /* mix colors based on shadfac (rgb + amount of light factor) */ + addAlphaLight(col, shr.diff, shr.alpha, d*shi.mat->filter); + } + else if (shi.mat->material_type == MA_TYPE_VOLUME) { + const float a = col[3]; + + col[0] = a*col[0] + shr.alpha*shr.combined[0]; + col[1] = a*col[1] + shr.alpha*shr.combined[1]; + col[2] = a*col[2] + shr.alpha*shr.combined[2]; + + col[3] = (1.0f - shr.alpha)*a; + } + + if (depth>0 && col[3]>0.0f) { + + /* adapt isect struct */ + copy_v3_v3(is->start, shi.co); + is->dist = initial_dist-is->dist; + is->orig.ob = shi.obi; + is->orig.face = shi.vlr; + + ray_trace_shadow_tra(is, origshi, depth-1, traflag | RAY_TRA, col); + } + + RE_RC_MERGE(&origshi->raycounter, &shi.raycounter); + } +} + + +/* aolight: function to create random unit sphere vectors for total random sampling */ + +/* calc distributed spherical energy */ +static void DS_energy(float *sphere, int tot, float vec[3]) +{ + float *fp, fac, force[3], res[3]; + int a; + + res[0]= res[1]= res[2]= 0.0f; + + for (a=0, fp=sphere; a<tot; a++, fp+=3) { + sub_v3_v3v3(force, vec, fp); + fac = dot_v3v3(force, force); + if (fac!=0.0f) { + fac= 1.0f/fac; + res[0]+= fac*force[0]; + res[1]+= fac*force[1]; + res[2]+= fac*force[2]; + } + } + + mul_v3_fl(res, 0.5); + add_v3_v3(vec, res); + normalize_v3(vec); + +} + +/* called from convertBlenderScene.c */ +/* creates an equally distributed spherical sample pattern */ +/* and allocates threadsafe memory */ +void init_ao_sphere(Render *re, World *wrld) +{ + /* fixed random */ + const int num_threads = re->r.threads; + RNG *rng; + float *fp; + int a, tot, iter= 16; + + /* we make twice the amount of samples, because only a hemisphere is used */ + tot= 2*wrld->aosamp*wrld->aosamp; + + wrld->aosphere= MEM_mallocN(3*tot*sizeof(float), "AO sphere"); + rng = BLI_rng_new_srandom(tot); + + /* init */ + fp= wrld->aosphere; + for (a=0; a<tot; a++, fp+= 3) { + BLI_rng_get_float_unit_v3(rng, fp); + } + + while (iter--) { + for (a=0, fp= wrld->aosphere; a<tot; a++, fp+= 3) { + DS_energy(wrld->aosphere, tot, fp); + } + } + + /* tables */ + wrld->aotables= MEM_mallocN(num_threads*3*tot*sizeof(float), "AO tables"); + + BLI_rng_free(rng); +} + +/* give per thread a table, we have to compare xs ys because of way OSA works... */ +static float *threadsafe_table_sphere(int test, int thread, int xs, int ys, int tot) +{ + static int xso[BLENDER_MAX_THREADS], yso[BLENDER_MAX_THREADS]; + static int firsttime= 1; + + if (firsttime) { + memset(xso, 255, sizeof(xso)); + memset(yso, 255, sizeof(yso)); + firsttime= 0; + } + + if (xs==xso[thread] && ys==yso[thread]) return R.wrld.aotables+ thread*tot*3; + if (test) return NULL; + xso[thread]= xs; yso[thread]= ys; + return R.wrld.aotables+ thread*tot*3; +} + +static float *sphere_sampler(int type, int resol, int thread, int xs, int ys, int reset) +{ + int tot; + float *vec; + + tot= 2*resol*resol; + + if (type & WO_AORNDSMP) { + /* total random sampling. NOT THREADSAFE! (should be removed, is not useful) */ + RNG *rng = BLI_rng_new(BLI_thread_rand(thread)); + float *sphere; + int a; + + /* always returns table */ + sphere= threadsafe_table_sphere(0, thread, xs, ys, tot); + + vec= sphere; + for (a=0; a<tot; a++, vec+=3) { + BLI_rng_get_float_unit_v3(rng, vec); + } + + BLI_rng_free(rng); + + return sphere; + } + else { + float *sphere; + float *vec1; + + /* returns table if xs and ys were equal to last call, and not resetting */ + sphere= (reset)? NULL: threadsafe_table_sphere(1, thread, xs, ys, tot); + if (sphere==NULL) { + float cosfi, sinfi, cost, sint; + float ang; + int a; + + sphere= threadsafe_table_sphere(0, thread, xs, ys, tot); + + /* random rotation */ + ang = BLI_thread_frand(thread); + sinfi = sinf(ang); cosfi = cosf(ang); + ang = BLI_thread_frand(thread); + sint = sinf(ang); cost = cosf(ang); + + vec= R.wrld.aosphere; + vec1= sphere; + for (a=0; a<tot; a++, vec+=3, vec1+=3) { + vec1[0]= cost*cosfi*vec[0] - sinfi*vec[1] + sint*cosfi*vec[2]; + vec1[1]= cost*sinfi*vec[0] + cosfi*vec[1] + sint*sinfi*vec[2]; + vec1[2]= -sint*vec[0] + cost*vec[2]; + } + } + return sphere; + } +} + +static void ray_ao_qmc(ShadeInput *shi, float ao[3], float env[3]) +{ + Isect isec; + RayHint point_hint; + QMCSampler *qsa=NULL; + float samp3d[3]; + float up[3], side[3], dir[3], nrm[3]; + + float maxdist = R.wrld.aodist; + float fac=0.0f, prev=0.0f; + float adapt_thresh = R.wrld.ao_adapt_thresh; + float adapt_speed_fac = R.wrld.ao_adapt_speed_fac; + + int samples=0; + int max_samples = R.wrld.aosamp*R.wrld.aosamp; + + float dxyview[3], skyadded=0; + int envcolor; + + RE_RC_INIT(isec, *shi); + isec.orig.ob = shi->obi; + isec.orig.face = shi->vlr; + isec.check = RE_CHECK_VLR_NON_SOLID_MATERIAL; + isec.skip = RE_SKIP_VLR_NEIGHBOUR; + isec.hint = NULL; + + isec.hit.ob = NULL; + isec.hit.face = NULL; + + isec.last_hit = NULL; + + isec.mode= (R.wrld.aomode & WO_AODIST)?RE_RAY_SHADOW_TRA:RE_RAY_SHADOW; + isec.lay= -1; + + copy_v3_v3(isec.start, shi->co); + + RE_instance_rotate_ray_start(shi->obi, &isec); + + RE_rayobject_hint_bb(R.raytree, &point_hint, isec.start, isec.start); + isec.hint = &point_hint; + + zero_v3(ao); + zero_v3(env); + + /* prevent sky colors to be added for only shadow (shadow becomes alpha) */ + envcolor= R.wrld.aocolor; + if (shi->mat->mode & MA_ONLYSHADOW) + envcolor= WO_AOPLAIN; + + if (envcolor == WO_AOSKYTEX) { + dxyview[0]= 1.0f/(float)R.wrld.aosamp; + dxyview[1]= 1.0f/(float)R.wrld.aosamp; + dxyview[2]= 0.0f; + } + + if (shi->vlr->flag & R_SMOOTH) { + copy_v3_v3(nrm, shi->vn); + } + else { + copy_v3_v3(nrm, shi->facenor); + } + + ortho_basis_v3v3_v3(up, side, nrm); + + /* sampling init */ + if (R.wrld.ao_samp_method==WO_AOSAMP_HALTON) { + float speedfac; + + speedfac = get_avg_speed(shi) * adapt_speed_fac; + CLAMP(speedfac, 1.0f, 1000.0f); + max_samples /= speedfac; + if (max_samples < 5) max_samples = 5; + + qsa = get_thread_qmcsampler(&R, shi->thread, SAMP_TYPE_HALTON, max_samples); + } + else if (R.wrld.ao_samp_method==WO_AOSAMP_HAMMERSLEY) + qsa = get_thread_qmcsampler(&R, shi->thread, SAMP_TYPE_HAMMERSLEY, max_samples); + + QMC_initPixel(qsa, shi->thread); + + while (samples < max_samples) { + + /* sampling, returns quasi-random vector in unit hemisphere */ + QMC_sampleHemi(samp3d, qsa, shi->thread, samples); + + dir[0] = (samp3d[0]*up[0] + samp3d[1]*side[0] + samp3d[2]*nrm[0]); + dir[1] = (samp3d[0]*up[1] + samp3d[1]*side[1] + samp3d[2]*nrm[1]); + dir[2] = (samp3d[0]*up[2] + samp3d[1]*side[2] + samp3d[2]*nrm[2]); + + normalize_v3(dir); + + isec.dir[0] = -dir[0]; + isec.dir[1] = -dir[1]; + isec.dir[2] = -dir[2]; + isec.dist = maxdist; + + RE_instance_rotate_ray_dir(shi->obi, &isec); + + prev = fac; + + if (RE_rayobject_raycast(R.raytree, &isec)) { + if (R.wrld.aomode & WO_AODIST) fac+= expf(-isec.dist*R.wrld.aodistfac); + else fac+= 1.0f; + } + else if (envcolor!=WO_AOPLAIN) { + float skycol[4]; + float view[3]; + + view[0]= -dir[0]; + view[1]= -dir[1]; + view[2]= -dir[2]; + normalize_v3(view); + + if (envcolor==WO_AOSKYCOL) { + const float skyfac= 0.5f * (1.0f + dot_v3v3(view, R.grvec)); + env[0]+= (1.0f-skyfac)*R.wrld.horr + skyfac*R.wrld.zenr; + env[1]+= (1.0f-skyfac)*R.wrld.horg + skyfac*R.wrld.zeng; + env[2]+= (1.0f-skyfac)*R.wrld.horb + skyfac*R.wrld.zenb; + } + else { /* WO_AOSKYTEX */ + shadeSkyView(skycol, isec.start, view, dxyview, shi->thread); + shadeSunView(skycol, shi->view); + env[0]+= skycol[0]; + env[1]+= skycol[1]; + env[2]+= skycol[2]; + } + skyadded++; + } + + samples++; + + if (qsa && qsa->type == SAMP_TYPE_HALTON) { + /* adaptive sampling - consider samples below threshold as in shadow (or vice versa) and exit early */ + if (adapt_thresh > 0.0f && (samples > max_samples/2) ) { + + if (adaptive_sample_contrast_val(samples, prev, fac, adapt_thresh)) { + break; + } + } + } + } + + /* average color times distances/hits formula */ + ao[0]= ao[1]= ao[2]= 1.0f - fac/(float)samples; + + if (envcolor!=WO_AOPLAIN && skyadded) + mul_v3_fl(env, (1.0f - fac/(float)samples)/((float)skyadded)); + else + copy_v3_v3(env, ao); + + if (qsa) + release_thread_qmcsampler(&R, shi->thread, qsa); +} + +/* extern call from shade_lamp_loop, ambient occlusion calculus */ +static void ray_ao_spheresamp(ShadeInput *shi, float ao[3], float env[3]) +{ + Isect isec; + RayHint point_hint; + float *vec, *nrm, bias, sh=0.0f; + float maxdist = R.wrld.aodist; + float dxyview[3]; + int j= -1, tot, actual=0, skyadded=0, envcolor, resol= R.wrld.aosamp; + + RE_RC_INIT(isec, *shi); + isec.orig.ob = shi->obi; + isec.orig.face = shi->vlr; + isec.check = RE_CHECK_VLR_RENDER; + isec.skip = RE_SKIP_VLR_NEIGHBOUR; + isec.hint = NULL; + + isec.hit.ob = NULL; + isec.hit.face = NULL; + + isec.last_hit = NULL; + + isec.mode= (R.wrld.aomode & WO_AODIST)?RE_RAY_SHADOW_TRA:RE_RAY_SHADOW; + isec.lay= -1; + + copy_v3_v3(isec.start, shi->co); + RE_instance_rotate_ray_start(shi->obi, &isec); + + RE_rayobject_hint_bb(R.raytree, &point_hint, isec.start, isec.start); + isec.hint = &point_hint; + + zero_v3(ao); + zero_v3(env); + + /* bias prevents smoothed faces to appear flat */ + if (shi->vlr->flag & R_SMOOTH) { + bias= R.wrld.aobias; + nrm= shi->vn; + } + else { + bias= 0.0f; + nrm= shi->facenor; + } + + /* prevent sky colors to be added for only shadow (shadow becomes alpha) */ + envcolor= R.wrld.aocolor; + if (shi->mat->mode & MA_ONLYSHADOW) + envcolor= WO_AOPLAIN; + + if (resol>32) resol= 32; + + /* get sphere samples. for faces we get the same samples for sample x/y values, + * for strand render we always require a new sampler because x/y are not set */ + vec= sphere_sampler(R.wrld.aomode, resol, shi->thread, shi->xs, shi->ys, shi->strand != NULL); + + /* warning: since we use full sphere now, and dotproduct is below, we do twice as much */ + tot= 2*resol*resol; + + if (envcolor == WO_AOSKYTEX) { + dxyview[0]= 1.0f/(float)resol; + dxyview[1]= 1.0f/(float)resol; + dxyview[2]= 0.0f; + } + + while (tot--) { + + if (dot_v3v3(vec, nrm) > bias) { + /* only ao samples for mask */ + if (R.r.mode & R_OSA) { + j++; + if (j==R.osa) j= 0; + if (!(shi->mask & (1<<j))) { + vec+=3; + continue; + } + } + + actual++; + + /* always set start/vec/dist */ + isec.dir[0] = -vec[0]; + isec.dir[1] = -vec[1]; + isec.dir[2] = -vec[2]; + isec.dist = maxdist; + + RE_instance_rotate_ray_dir(shi->obi, &isec); + + /* do the trace */ + if (RE_rayobject_raycast(R.raytree, &isec)) { + if (R.wrld.aomode & WO_AODIST) sh+= expf(-isec.dist*R.wrld.aodistfac); + else sh+= 1.0f; + } + else if (envcolor!=WO_AOPLAIN) { + float skycol[4]; + float view[3]; + + view[0]= -vec[0]; + view[1]= -vec[1]; + view[2]= -vec[2]; + normalize_v3(view); + + if (envcolor==WO_AOSKYCOL) { + const float fac = 0.5f * (1.0f + dot_v3v3(view, R.grvec)); + env[0]+= (1.0f-fac)*R.wrld.horr + fac*R.wrld.zenr; + env[1]+= (1.0f-fac)*R.wrld.horg + fac*R.wrld.zeng; + env[2]+= (1.0f-fac)*R.wrld.horb + fac*R.wrld.zenb; + } + else { /* WO_AOSKYTEX */ + shadeSkyView(skycol, isec.start, view, dxyview, shi->thread); + shadeSunView(skycol, shi->view); + env[0]+= skycol[0]; + env[1]+= skycol[1]; + env[2]+= skycol[2]; + } + skyadded++; + } + } + /* samples */ + vec+= 3; + } + + if (actual==0) sh= 1.0f; + else sh = 1.0f - sh/((float)actual); + + /* average color times distances/hits formula */ + ao[0]= ao[1]= ao[2]= sh; + + if (envcolor!=WO_AOPLAIN && skyadded) + mul_v3_fl(env, sh/((float)skyadded)); + else + copy_v3_v3(env, ao); +} + +void ray_ao(ShadeInput *shi, float ao[3], float env[3]) +{ + /* Unfortunately, the unusual way that the sphere sampler calculates roughly twice as many + * samples as are actually traced, and skips them based on bias and OSA settings makes it very difficult + * to reuse code between these two functions. This is the easiest way I can think of to do it + * --broken */ + if (ELEM(R.wrld.ao_samp_method, WO_AOSAMP_HAMMERSLEY, WO_AOSAMP_HALTON)) + ray_ao_qmc(shi, ao, env); + else if (R.wrld.ao_samp_method == WO_AOSAMP_CONSTANT) + ray_ao_spheresamp(shi, ao, env); +} + +static void ray_shadow_jittered_coords(ShadeInput *shi, int max, float jitco[RE_MAX_OSA][3], int *totjitco) +{ + /* magic numbers for reordering sample positions to give better + * results with adaptive sample, when it usually only takes 4 samples */ + int order8[8] = {0, 1, 5, 6, 2, 3, 4, 7}; + int order11[11] = {1, 3, 8, 10, 0, 2, 4, 5, 6, 7, 9}; + int order16[16] = {1, 3, 9, 12, 0, 6, 7, 8, 13, 2, 4, 5, 10, 11, 14, 15}; + int count = count_mask(shi->mask); + + /* for better antialising shadow samples are distributed over the subpixel + * sample coordinates, this only works for raytracing depth 0 though */ + if (!shi->strand && shi->depth == 0 && count > 1 && count <= max) { + float xs, ys, zs, view[3]; + int samp, ordsamp, tot= 0; + + for (samp=0; samp<R.osa; samp++) { + if (R.osa == 8) ordsamp = order8[samp]; + else if (R.osa == 11) ordsamp = order11[samp]; + else if (R.osa == 16) ordsamp = order16[samp]; + else ordsamp = samp; + + if (shi->mask & (1<<ordsamp)) { + /* zbuffer has this inverse corrected, ensures xs,ys are inside pixel */ + xs= (float)shi->scanco[0] + R.jit[ordsamp][0] + 0.5f; + ys= (float)shi->scanco[1] + R.jit[ordsamp][1] + 0.5f; + zs= shi->scanco[2]; + + shade_input_calc_viewco(shi, xs, ys, zs, view, NULL, jitco[tot], NULL, NULL); + tot++; + } + } + + *totjitco= tot; + } + else { + copy_v3_v3(jitco[0], shi->co); + *totjitco= 1; + } +} + +static void ray_shadow_qmc(ShadeInput *shi, LampRen *lar, const float lampco[3], float shadfac[4], Isect *isec) +{ + QMCSampler *qsa=NULL; + int samples=0; + float samp3d[3]; + + float fac=0.0f, vec[3], end[3]; + float colsq[4]; + float adapt_thresh = lar->adapt_thresh; + int min_adapt_samples=4, max_samples = lar->ray_totsamp; + float start[3]; + bool do_soft = true, full_osa = false; + int i; + + float min[3], max[3]; + RayHint bb_hint; + + float jitco[RE_MAX_OSA][3]; + int totjitco; + + colsq[0] = colsq[1] = colsq[2] = 0.0; + if (isec->mode==RE_RAY_SHADOW_TRA) { + shadfac[0]= shadfac[1]= shadfac[2]= shadfac[3]= 0.0f; + } + else + shadfac[3]= 1.0f; + + if (lar->ray_totsamp < 2) do_soft = false; + if ((R.r.mode & R_OSA) && (R.osa > 0) && (shi->vlr->flag & R_FULL_OSA)) full_osa = true; + + if (full_osa) { + if (do_soft) max_samples = max_samples/R.osa + 1; + else max_samples = 1; + } + else { + if (do_soft) max_samples = lar->ray_totsamp; + else if (shi->depth == 0) max_samples = (R.osa > 4)?R.osa:5; + else max_samples = 1; + } + + ray_shadow_jittered_coords(shi, max_samples, jitco, &totjitco); + + /* sampling init */ + if (lar->ray_samp_method==LA_SAMP_HALTON) + qsa = get_thread_qmcsampler(&R, shi->thread, SAMP_TYPE_HALTON, max_samples); + else if (lar->ray_samp_method==LA_SAMP_HAMMERSLEY) + qsa = get_thread_qmcsampler(&R, shi->thread, SAMP_TYPE_HAMMERSLEY, max_samples); + + QMC_initPixel(qsa, shi->thread); + + INIT_MINMAX(min, max); + for (i = 0; i < totjitco; i++) { + minmax_v3v3_v3(min, max, jitco[i]); + } + if (shi->obi->flag & R_ENV_TRANSFORMED) { + mul_m4_v3(shi->obi->imat, min); + mul_m4_v3(shi->obi->imat, max); + } + RE_rayobject_hint_bb(R.raytree, &bb_hint, min, max); + + isec->hint = &bb_hint; + isec->check = RE_CHECK_VLR_RENDER; + isec->skip = RE_SKIP_VLR_NEIGHBOUR; + copy_v3_v3(vec, lampco); + + while (samples < max_samples) { + + isec->orig.ob = shi->obi; + isec->orig.face = shi->vlr; + + /* manually jitter the start shading co-ord per sample + * based on the pre-generated OSA texture sampling offsets, + * for anti-aliasing sharp shadow edges. */ + copy_v3_v3(start, jitco[samples % totjitco]); + + if (do_soft) { + /* sphere shadow source */ + if (lar->type == LA_LOCAL) { + float ru[3], rv[3], v[3], s[3]; + + /* calc tangent plane vectors */ + sub_v3_v3v3(v, start, lampco); + normalize_v3(v); + ortho_basis_v3v3_v3(ru, rv, v); + + /* sampling, returns quasi-random vector in area_size disc */ + QMC_sampleDisc(samp3d, qsa, shi->thread, samples, lar->area_size); + + /* distribute disc samples across the tangent plane */ + s[0] = samp3d[0]*ru[0] + samp3d[1]*rv[0]; + s[1] = samp3d[0]*ru[1] + samp3d[1]*rv[1]; + s[2] = samp3d[0]*ru[2] + samp3d[1]*rv[2]; + + copy_v3_v3(samp3d, s); + } + else { + /* sampling, returns quasi-random vector in [sizex,sizey]^2 plane */ + QMC_sampleRect(samp3d, qsa, shi->thread, samples, lar->area_size, lar->area_sizey); + + /* align samples to lamp vector */ + mul_m3_v3(lar->mat, samp3d); + } + end[0] = vec[0]+samp3d[0]; + end[1] = vec[1]+samp3d[1]; + end[2] = vec[2]+samp3d[2]; + } + else { + copy_v3_v3(end, vec); + } + + if (shi->strand) { + /* bias away somewhat to avoid self intersection */ + float jitbias= 0.5f*(len_v3(shi->dxco) + len_v3(shi->dyco)); + float v[3]; + + sub_v3_v3v3(v, start, end); + normalize_v3(v); + + start[0] -= jitbias*v[0]; + start[1] -= jitbias*v[1]; + start[2] -= jitbias*v[2]; + } + + copy_v3_v3(isec->start, start); + sub_v3_v3v3(isec->dir, end, start); + isec->dist = normalize_v3(isec->dir); + + RE_instance_rotate_ray(shi->obi, isec); + + /* trace the ray */ + if (isec->mode==RE_RAY_SHADOW_TRA) { + float col[4] = {1.0f, 1.0f, 1.0f, 1.0f}; + + ray_trace_shadow_tra(isec, shi, DEPTH_SHADOW_TRA, 0, col); + shadfac[0] += col[0]; + shadfac[1] += col[1]; + shadfac[2] += col[2]; + shadfac[3] += col[3]; + + /* for variance calc */ + colsq[0] += col[0]*col[0]; + colsq[1] += col[1]*col[1]; + colsq[2] += col[2]*col[2]; + } + else { + if ( RE_rayobject_raycast(R.raytree, isec) ) fac+= 1.0f; + } + + samples++; + + if (lar->ray_samp_method == LA_SAMP_HALTON) { + + /* adaptive sampling - consider samples below threshold as in shadow (or vice versa) and exit early */ + if ((max_samples > min_adapt_samples) && (adapt_thresh > 0.0f) && (samples > max_samples / 3)) { + if (isec->mode==RE_RAY_SHADOW_TRA) { + if ((shadfac[3] / samples > (1.0f-adapt_thresh)) || (shadfac[3] / samples < adapt_thresh)) + break; + else if (adaptive_sample_variance(samples, shadfac, colsq, adapt_thresh)) + break; + } + else { + if ((fac / samples > (1.0f-adapt_thresh)) || (fac / samples < adapt_thresh)) + break; + } + } + } + } + + if (isec->mode==RE_RAY_SHADOW_TRA) { + shadfac[0] /= samples; + shadfac[1] /= samples; + shadfac[2] /= samples; + shadfac[3] /= samples; + } + else + shadfac[3]= 1.0f-fac/samples; + + if (qsa) + release_thread_qmcsampler(&R, shi->thread, qsa); +} + +static void ray_shadow_jitter(ShadeInput *shi, LampRen *lar, const float lampco[3], float shadfac[4], Isect *isec) +{ + /* area soft shadow */ + const float *jitlamp; + float fac=0.0f, div=0.0f, vec[3]; + int a, j= -1, mask; + RayHint point_hint; + + if (isec->mode==RE_RAY_SHADOW_TRA) { + shadfac[0]= shadfac[1]= shadfac[2]= shadfac[3]= 0.0f; + } + else shadfac[3]= 1.0f; + + fac= 0.0f; + jitlamp= give_jitter_plane(lar, shi->thread, shi->xs, shi->ys); + + a= lar->ray_totsamp; + + /* this correction to make sure we always take at least 1 sample */ + mask= shi->mask; + if (a==4) mask |= (mask>>4)|(mask>>8); + else if (a==9) mask |= (mask>>9); + + copy_v3_v3(isec->start, shi->co); + RE_instance_rotate_ray_start(shi->obi, isec); + + isec->orig.ob = shi->obi; + isec->orig.face = shi->vlr; + RE_rayobject_hint_bb(R.raytree, &point_hint, isec->start, isec->start); + isec->hint = &point_hint; + + while (a--) { + + if (R.r.mode & R_OSA) { + j++; + if (j>=R.osa) j= 0; + if (!(mask & (1<<j))) { + jitlamp+= 2; + continue; + } + } + + vec[0]= jitlamp[0]; + vec[1]= jitlamp[1]; + vec[2]= 0.0f; + mul_m3_v3(lar->mat, vec); + + /* set start and vec */ + isec->dir[0] = vec[0]+lampco[0]-shi->co[0]; + isec->dir[1] = vec[1]+lampco[1]-shi->co[1]; + isec->dir[2] = vec[2]+lampco[2]-shi->co[2]; + + RE_instance_rotate_ray_dir(shi->obi, isec); + + isec->dist = 1.0f; + isec->check = RE_CHECK_VLR_RENDER; + isec->skip = RE_SKIP_VLR_NEIGHBOUR; + + if (isec->mode==RE_RAY_SHADOW_TRA) { + /* isec.col is like shadfac, so defines amount of light (0.0 is full shadow) */ + float col[4] = {1.0f, 1.0f, 1.0f, 1.0f}; + + ray_trace_shadow_tra(isec, shi, DEPTH_SHADOW_TRA, 0, col); + shadfac[0] += col[0]; + shadfac[1] += col[1]; + shadfac[2] += col[2]; + shadfac[3] += col[3]; + } + else if ( RE_rayobject_raycast(R.raytree, isec) ) fac+= 1.0f; + + div+= 1.0f; + jitlamp+= 2; + } + + if (isec->mode==RE_RAY_SHADOW_TRA) { + shadfac[0] /= div; + shadfac[1] /= div; + shadfac[2] /= div; + shadfac[3] /= div; + } + else { + /* sqrt makes nice umbra effect */ + if (lar->ray_samp_type & LA_SAMP_UMBRA) + shadfac[3] = sqrtf(1.0f - fac / div); + else + shadfac[3] = 1.0f - fac / div; + } +} +/* extern call from shade_lamp_loop */ +void ray_shadow(ShadeInput *shi, LampRen *lar, float shadfac[4]) +{ + Isect isec; + float lampco[3]; + + /* setup isec */ + RE_RC_INIT(isec, *shi); + if (shi->mat->mode & MA_SHADOW_TRA) isec.mode= RE_RAY_SHADOW_TRA; + else isec.mode= RE_RAY_SHADOW; + isec.hint = NULL; + + if (lar->mode & (LA_LAYER|LA_LAYER_SHADOW)) + isec.lay= lar->lay; + else + isec.lay= -1; + + /* only when not mir tracing, first hit optimm */ + if (shi->depth==0) { + isec.last_hit = lar->last_hit[shi->thread]; + } + else { + isec.last_hit = NULL; + } + + if (lar->type==LA_SUN || lar->type==LA_HEMI) { + /* jitter and QMC sampling add a displace vector to the lamp position + * that's incorrect because a SUN lamp does not has an exact position + * and the displace should be done at the ray vector instead of the + * lamp position. + * This is easily verified by noticing that shadows of SUN lights change + * with the scene BB. + * + * This was detected during SoC 2009 - Raytrace Optimization, but to keep + * consistency with older render code it wasn't removed. + * + * If the render code goes through some recode/serious bug-fix then this + * is something to consider! + */ + lampco[0]= shi->co[0] - R.maxdist*lar->vec[0]; + lampco[1]= shi->co[1] - R.maxdist*lar->vec[1]; + lampco[2]= shi->co[2] - R.maxdist*lar->vec[2]; + } + else { + copy_v3_v3(lampco, lar->co); + } + + if (ELEM(lar->ray_samp_method, LA_SAMP_HALTON, LA_SAMP_HAMMERSLEY)) { + + ray_shadow_qmc(shi, lar, lampco, shadfac, &isec); + + } + else { + if (lar->ray_totsamp<2) { + + isec.orig.ob = shi->obi; + isec.orig.face = shi->vlr; + + shadfac[3]= 1.0f; /* 1.0=full light */ + + /* set up isec.dir */ + copy_v3_v3(isec.start, shi->co); + sub_v3_v3v3(isec.dir, lampco, isec.start); + isec.dist = normalize_v3(isec.dir); + + RE_instance_rotate_ray(shi->obi, &isec); + + if (isec.mode==RE_RAY_SHADOW_TRA) { + /* isec.col is like shadfac, so defines amount of light (0.0 is full shadow) */ + float col[4] = {1.0f, 1.0f, 1.0f, 1.0f}; + + ray_trace_shadow_tra(&isec, shi, DEPTH_SHADOW_TRA, 0, col); + copy_v4_v4(shadfac, col); + } + else if (RE_rayobject_raycast(R.raytree, &isec)) + shadfac[3]= 0.0f; + } + else { + ray_shadow_jitter(shi, lar, lampco, shadfac, &isec); + } + } + + /* for first hit optim, set last interesected shadow face */ + if (shi->depth==0) { + lar->last_hit[shi->thread] = isec.last_hit; + } + +} + diff --git a/source/blender/render/intern/source/render_result.c b/source/blender/render/intern/source/render_result.c index a6f1ecd5405..e0cacdf4b8f 100644 --- a/source/blender/render/intern/source/render_result.c +++ b/source/blender/render/intern/source/render_result.c @@ -95,7 +95,7 @@ void render_result_free(RenderResult *res) if (rl->acolrect) MEM_freeN(rl->acolrect); if (rl->scolrect) MEM_freeN(rl->scolrect); if (rl->display_buffer) MEM_freeN(rl->display_buffer); - + while (rl->passes.first) { RenderPass *rpass = rl->passes.first; if (rpass->rect) MEM_freeN(rpass->rect); @@ -128,13 +128,13 @@ void render_result_free(RenderResult *res) void render_result_free_list(ListBase *lb, RenderResult *rr) { RenderResult *rrnext; - + for (; rr; rr = rrnext) { rrnext = rr->next; - + if (lb && lb->first) BLI_remlink(lb, rr); - + render_result_free(rr); } } @@ -206,7 +206,7 @@ static RenderPass *render_layer_add_pass(RenderResult *rr, RenderLayer *rl, int const int view_id = BLI_findstringindex(&rr->views, viewname, offsetof(RenderView, name)); RenderPass *rpass = MEM_callocN(sizeof(RenderPass), name); size_t rectsize = ((size_t)rr->rectx) * rr->recty * channels; - + rpass->channels = channels; rpass->rectx = rl->rectx; rpass->recty = rl->recty; @@ -216,7 +216,7 @@ static RenderPass *render_layer_add_pass(RenderResult *rr, RenderLayer *rl, int BLI_strncpy(rpass->chan_id, chan_id, sizeof(rpass->chan_id)); BLI_strncpy(rpass->view, viewname, sizeof(rpass->view)); set_pass_full_name(rpass->fullname, rpass->name, -1, rpass->view, rpass->chan_id); - + if (rl->exrhandle) { int a; for (a = 0; a < channels; a++) { @@ -227,13 +227,13 @@ static RenderPass *render_layer_add_pass(RenderResult *rr, RenderLayer *rl, int else { float *rect; int x; - + rpass->rect = MEM_mapallocN(sizeof(float) * rectsize, name); if (rpass->rect == NULL) { MEM_freeN(rpass); return NULL; } - + if (STREQ(rpass->name, RE_PASSNAME_VECTOR)) { /* initialize to max speed */ rect = rpass->rect; @@ -267,13 +267,13 @@ RenderResult *render_result_new(Render *re, rcti *partrct, int crop, int savebuf RenderLayer *rl; RenderView *rv; int rectx, recty; - + rectx = BLI_rcti_size_x(partrct); recty = BLI_rcti_size_y(partrct); - + if (rectx <= 0 || recty <= 0) return NULL; - + rr = MEM_callocN(sizeof(RenderResult), "new render result"); rr->rectx = rectx; rr->recty = recty; @@ -286,7 +286,7 @@ RenderResult *render_result_new(Render *re, rcti *partrct, int crop, int savebuf rr->tilerect.xmax = partrct->xmax - re->disprect.xmin; rr->tilerect.ymin = partrct->ymin - re->disprect.ymin; rr->tilerect.ymax = partrct->ymax - re->disprect.ymin; - + if (savebuffers) { rr->do_exr_tile = true; } @@ -304,14 +304,14 @@ RenderResult *render_result_new(Render *re, rcti *partrct, int crop, int savebuf rl = MEM_callocN(sizeof(RenderLayer), "new render layer"); BLI_addtail(&rr->layers, rl); - + BLI_strncpy(rl->name, view_layer->name, sizeof(rl->name)); rl->layflag = view_layer->layflag; rl->passflag = view_layer->passflag; /* for debugging: view_layer->passflag | SCE_PASS_RAYHITS; */ rl->pass_xor = view_layer->pass_xor; rl->rectx = rectx; rl->recty = recty; - + if (rr->do_exr_tile) { rl->display_buffer = MEM_mapallocN((size_t)rectx * recty * sizeof(unsigned int), "Combined display space rgba"); @@ -412,7 +412,7 @@ RenderResult *render_result_new(Render *re, rcti *partrct, int crop, int savebuf if (BLI_listbase_is_empty(&rr->layers) && !(layername && layername[0])) { rl = MEM_callocN(sizeof(RenderLayer), "new render layer"); BLI_addtail(&rr->layers, rl); - + rl->rectx = rectx; rl->recty = recty; @@ -439,15 +439,15 @@ RenderResult *render_result_new(Render *re, rcti *partrct, int crop, int savebuf /* note, this has to be in sync with scene.c */ rl->layflag = 0x7FFF; /* solid ztra halo strand */ rl->passflag = SCE_PASS_COMBINED; - + re->active_view_layer = 0; } - + /* border render; calculate offset for use in compositor. compo is centralized coords */ /* XXX obsolete? I now use it for drawing border render offset (ton) */ rr->xof = re->disprect.xmin + BLI_rcti_cent_x(&re->disprect) - (re->winx / 2); rr->yof = re->disprect.ymin + BLI_rcti_cent_y(&re->disprect) - (re->winy / 2); - + return rr; } @@ -554,7 +554,7 @@ static void *ml_addlayer_cb(void *base, const char *str) { RenderResult *rr = base; RenderLayer *rl; - + rl = MEM_callocN(sizeof(RenderLayer), "new render layer"); BLI_addtail(&rr->layers, rl); @@ -676,7 +676,7 @@ RenderResult *render_result_new_from_exr(void *exrhandle, const char *colorspace rr->rectx = rectx; rr->recty = recty; - + IMB_exr_multilayer_convert(exrhandle, rr, ml_addview_cb, ml_addlayer_cb, ml_addpass_cb); for (rl = rr->layers.first; rl; rl = rl->next) { @@ -695,7 +695,7 @@ RenderResult *render_result_new_from_exr(void *exrhandle, const char *colorspace } } } - + return rr; } @@ -740,16 +740,16 @@ static void do_merge_tile(RenderResult *rr, RenderResult *rrpart, float *target, { int y, tilex, tiley; size_t ofs, copylen; - + copylen = tilex = rrpart->rectx; tiley = rrpart->recty; - + if (rrpart->crop) { /* filters add pixel extra */ tile += pixsize * (rrpart->crop + ((size_t)rrpart->crop) * tilex); - + copylen = tilex - 2 * rrpart->crop; tiley -= 2 * rrpart->crop; - + ofs = (((size_t)rrpart->tilerect.ymin) + rrpart->crop) * rr->rectx + (rrpart->tilerect.xmin + rrpart->crop); target += pixsize * ofs; } @@ -776,7 +776,7 @@ void render_result_merge(RenderResult *rr, RenderResult *rrpart) { RenderLayer *rl, *rlp; RenderPass *rpass, *rpassp; - + for (rl = rr->layers.first; rl; rl = rl->next) { rlp = RE_GetRenderLayer(rrpart, rl->name); if (rlp) { @@ -956,7 +956,7 @@ void render_result_single_layer_begin(Render *re) /* officially pushed result should be NULL... error can happen with do_seq */ RE_FreeRenderResult(re->pushedresult); - + re->pushedresult = re->result; re->result = NULL; } @@ -980,10 +980,10 @@ void render_result_single_layer_end(Render *re) if (re->pushedresult->rectx == re->result->rectx && re->pushedresult->recty == re->result->recty) { /* find which layer in re->pushedresult should be replaced */ rl = re->result->layers.first; - + /* render result should be empty after this */ BLI_remlink(&re->result->layers, rl); - + /* reconstruct render result layers */ for (nr = 0, view_layer = re->view_layers.first; view_layer; view_layer = view_layer->next, nr++) { if (nr == re->active_view_layer) { @@ -1010,9 +1010,9 @@ static void save_render_result_tile(RenderResult *rr, RenderResult *rrpart, cons RenderLayer *rlp, *rl; RenderPass *rpassp; int offs, partx, party; - + BLI_thread_lock(LOCK_IMAGE); - + for (rlp = rrpart->layers.first; rlp; rlp = rlp->next) { rl = RE_GetRenderLayer(rr, rlp->name); @@ -1042,7 +1042,7 @@ static void save_render_result_tile(RenderResult *rr, RenderResult *rrpart, cons xstride, xstride * rrpart->rectx, rpassp->rect + a + xstride * offs); } } - + } party = rrpart->tilerect.ymin + rrpart->crop; @@ -1068,7 +1068,7 @@ void render_result_save_empty_result_tiles(Render *re) RenderPart *pa; RenderResult *rr; RenderLayer *rl; - + for (rr = re->result; rr; rr = rr->next) { for (rl = rr->layers.first; rl; rl = rl->next) { for (pa = re->parts.first; pa; pa = pa->next) { @@ -1112,7 +1112,7 @@ void render_result_exr_file_end(Render *re) rr->do_exr_tile = false; } - + render_result_free_list(&re->fullresult, re->result); re->result = NULL; @@ -1130,8 +1130,8 @@ void render_result_exr_file_merge(RenderResult *rr, RenderResult *rrpart, const void render_result_exr_file_path(Scene *scene, const char *layname, int sample, char *filepath) { char name[FILE_MAXFILE + MAX_ID_NAME + MAX_ID_NAME + 100]; - const char *fi = BLI_path_basename(G.main->name); - + const char *fi = BLI_path_basename(BKE_main_blendfile_path_from_global()); + if (sample == 0) { BLI_snprintf(name, sizeof(name), "%s_%s_%s.exr", fi, scene->id.name + 2, layname); } @@ -1194,7 +1194,7 @@ int render_result_exr_file_read_path(RenderResult *rr, RenderLayer *rl_single, c for (rl = rr->layers.first; rl; rl = rl->next) { if (rl_single && rl_single != rl) continue; - + /* passes are allocated in sync */ for (rpass = rl->passes.first; rpass; rpass = rpass->next) { const int xstride = rpass->channels; @@ -1224,10 +1224,11 @@ static void render_result_exr_file_cache_path(Scene *sce, const char *root, char char path_hexdigest[33]; /* If root is relative, use either current .blend file dir, or temp one if not saved. */ - if (G.main->name[0]) { - BLI_split_dirfile(G.main->name, dirname, filename, sizeof(dirname), sizeof(filename)); + const char *blendfile_path = BKE_main_blendfile_path_from_global(); + if (blendfile_path[0] != '\0') { + BLI_split_dirfile(blendfile_path, dirname, filename, sizeof(dirname), sizeof(filename)); BLI_replace_extension(filename, sizeof(filename), ""); /* strip '.blend' */ - BLI_hash_md5_buffer(G.main->name, strlen(G.main->name), path_digest); + BLI_hash_md5_buffer(blendfile_path, strlen(blendfile_path), path_digest); } else { BLI_strncpy(dirname, BKE_tempdir_base(), sizeof(dirname)); @@ -1291,7 +1292,7 @@ ImBuf *render_result_rect_to_ibuf(RenderResult *rr, RenderData *rd, const int vi /* float factor for random dither, imbuf takes care of it */ ibuf->dither = rd->dither_intensity; - + /* prepare to gamma correct to sRGB color space * note that sequence editor can generate 8bpc render buffers */ @@ -1332,7 +1333,7 @@ void RE_render_result_rect_from_ibuf(RenderResult *rr, RenderData *UNUSED(rd), I if (!rv->rectf) rv->rectf = MEM_mallocN(4 * sizeof(float) * rr->rectx * rr->recty, "render_seq rectf"); - + memcpy(rv->rectf, ibuf->rect_float, 4 * sizeof(float) * rr->rectx * rr->recty); /* TSK! Since sequence render doesn't free the *rr render result, the old rect32 diff --git a/source/blender/render/intern/source/render_texture.c b/source/blender/render/intern/source/render_texture.c index 79d13ecab5b..99da5b3ca01 100644 --- a/source/blender/render/intern/source/render_texture.c +++ b/source/blender/render/intern/source/render_texture.c @@ -95,7 +95,7 @@ static void tex_normal_derivate(Tex *tex, TexResult *texres) float col[4]; if (BKE_colorband_evaluate(tex->coba, texres->tin, col)) { float fac0, fac1, fac2, fac3; - + fac0= (col[0]+col[1]+col[2]); BKE_colorband_evaluate(tex->coba, texres->nor[0], col); fac1= (col[0]+col[1]+col[2]); @@ -103,11 +103,11 @@ static void tex_normal_derivate(Tex *tex, TexResult *texres) fac2= (col[0]+col[1]+col[2]); BKE_colorband_evaluate(tex->coba, texres->nor[2], col); fac3= (col[0]+col[1]+col[2]); - + texres->nor[0]= (fac0 - fac1) / 3.0f; texres->nor[1]= (fac0 - fac2) / 3.0f; texres->nor[2]= (fac0 - fac3) / 3.0f; - + return; } } @@ -173,7 +173,7 @@ static int blend(Tex *tex, const float texvec[3], TexResult *texres) static int clouds(Tex *tex, const float texvec[3], TexResult *texres) { int rv = TEX_INT; - + texres->tin = BLI_gTurbulence(tex->noisesize, texvec[0], texvec[1], texvec[2], tex->noisedepth, (tex->noisetype!=TEX_NOISESOFT), tex->noisebasis); if (texres->nor!=NULL) { @@ -181,7 +181,7 @@ static int clouds(Tex *tex, const float texvec[3], TexResult *texres) texres->nor[0] = BLI_gTurbulence(tex->noisesize, texvec[0] + tex->nabla, texvec[1], texvec[2], tex->noisedepth, (tex->noisetype!=TEX_NOISESOFT), tex->noisebasis); texres->nor[1] = BLI_gTurbulence(tex->noisesize, texvec[0], texvec[1] + tex->nabla, texvec[2], tex->noisedepth, (tex->noisetype!=TEX_NOISESOFT), tex->noisebasis); texres->nor[2] = BLI_gTurbulence(tex->noisesize, texvec[0], texvec[1], texvec[2] + tex->nabla, tex->noisedepth, (tex->noisetype!=TEX_NOISESOFT), tex->noisebasis); - + tex_normal_derivate(tex, texres); rv |= TEX_NOR; } @@ -215,7 +215,7 @@ static float tex_sin(float a) static float tex_saw(float a) { const float b = 2*M_PI; - + int n = (int)(a / b); a -= n*b; if (a < 0) a += b; @@ -227,9 +227,9 @@ static float tex_tri(float a) { const float b = 2*M_PI; const float rmax = 1.0; - + a = rmax - 2.0f*fabsf(floorf((a*(1.0f/b))+0.5f) - (a*(1.0f/b))); - + return a; } @@ -244,9 +244,9 @@ static float wood_int(Tex *tex, float x, float y, float z) waveform[0] = tex_sin; /* assign address of tex_sin() function to pointer array */ waveform[1] = tex_saw; waveform[2] = tex_tri; - + if ((wf>TEX_TRI) || (wf<TEX_SIN)) wf=0; /* check to be sure noisebasis2 is initialized ahead of time */ - + if (wt==TEX_BAND) { wi = waveform[wf]((x + y + z)*10.0f); } @@ -261,7 +261,7 @@ static float wood_int(Tex *tex, float x, float y, float z) wi = tex->turbul*BLI_gNoise(tex->noisesize, x, y, z, (tex->noisetype!=TEX_NOISESOFT), tex->noisebasis); wi = waveform[wf](sqrtf(x*x + y*y + z*z)*20.0f + wi); } - + return wi; } @@ -275,7 +275,7 @@ static int wood(Tex *tex, const float texvec[3], TexResult *texres) texres->nor[0] = wood_int(tex, texvec[0] + tex->nabla, texvec[1], texvec[2]); texres->nor[1] = wood_int(tex, texvec[0], texvec[1] + tex->nabla, texvec[2]); texres->nor[2] = wood_int(tex, texvec[0], texvec[1], texvec[2] + tex->nabla); - + tex_normal_derivate(tex, texres); rv |= TEX_NOR; } @@ -291,16 +291,16 @@ static float marble_int(Tex *tex, float x, float y, float z) float n, mi; short wf = tex->noisebasis2; /* wave form: TEX_SIN=0, TEX_SAW=1, TEX_TRI=2 */ short mt = tex->stype; /* marble type: TEX_SOFT=0, TEX_SHARP=1,TEX_SHAPER=2 */ - + float (*waveform[3])(float); /* create array of pointers to waveform functions */ waveform[0] = tex_sin; /* assign address of tex_sin() function to pointer array */ waveform[1] = tex_saw; waveform[2] = tex_tri; - + if ((wf>TEX_TRI) || (wf<TEX_SIN)) wf=0; /* check to be sure noisebasis2 isn't initialized ahead of time */ - + n = 5.0f * (x + y + z); - + mi = n + tex->turbul * BLI_gTurbulence(tex->noisesize, x, y, z, tex->noisedepth, (tex->noisetype!=TEX_NOISESOFT), tex->noisebasis); if (mt>=TEX_SOFT) { /* TEX_SOFT always true */ @@ -327,9 +327,9 @@ static int marble(Tex *tex, const float texvec[3], TexResult *texres) texres->nor[0] = marble_int(tex, texvec[0] + tex->nabla, texvec[1], texvec[2]); texres->nor[1] = marble_int(tex, texvec[0], texvec[1] + tex->nabla, texvec[2]); texres->nor[2] = marble_int(tex, texvec[0], texvec[1], texvec[2] + tex->nabla); - + tex_normal_derivate(tex, texres); - + rv |= TEX_NOR; } @@ -397,8 +397,8 @@ static int magic(Tex *tex, const float texvec[3], TexResult *texres) if (turb!=0.0f) { turb*= 2.0f; - x/= turb; - y/= turb; + x/= turb; + y/= turb; z/= turb; } texres->tr = 0.5f - x; @@ -406,10 +406,10 @@ static int magic(Tex *tex, const float texvec[3], TexResult *texres) texres->tb = 0.5f - z; texres->tin= (1.0f / 3.0f) * (texres->tr + texres->tg + texres->tb); - + BRICONTRGB; texres->ta = 1.0f; - + return TEX_RGB; } @@ -420,9 +420,9 @@ static int stucci(Tex *tex, const float texvec[3], TexResult *texres) { float nor[3], b2, ofs; int retval= TEX_INT; - + b2= BLI_gNoise(tex->noisesize, texvec[0], texvec[1], texvec[2], (tex->noisetype!=TEX_NOISESOFT), tex->noisebasis); - + ofs= tex->turbul/200.0f; if (tex->stype) ofs*=(b2*b2); @@ -431,27 +431,27 @@ static int stucci(Tex *tex, const float texvec[3], TexResult *texres) nor[2] = BLI_gNoise(tex->noisesize, texvec[0], texvec[1], texvec[2]+ofs, (tex->noisetype!=TEX_NOISESOFT), tex->noisebasis); texres->tin= nor[2]; - + if (texres->nor) { - + copy_v3_v3(texres->nor, nor); tex_normal_derivate(tex, texres); - + if (tex->stype==TEX_WALLOUT) { texres->nor[0]= -texres->nor[0]; texres->nor[1]= -texres->nor[1]; texres->nor[2]= -texres->nor[2]; } - + retval |= TEX_NOR; } - + if (tex->stype==TEX_WALLOUT) texres->tin= 1.0f-texres->tin; - + if (texres->tin<0.0f) texres->tin= 0.0f; - + return retval; } @@ -477,7 +477,7 @@ static float mg_mFractalOrfBmTex(Tex *tex, const float texvec[3], TexResult *tex texres->nor[0] = tex->ns_outscale*mgravefunc(texvec[0] + offs, texvec[1], texvec[2], tex->mg_H, tex->mg_lacunarity, tex->mg_octaves, tex->noisebasis); texres->nor[1] = tex->ns_outscale*mgravefunc(texvec[0], texvec[1] + offs, texvec[2], tex->mg_H, tex->mg_lacunarity, tex->mg_octaves, tex->noisebasis); texres->nor[2] = tex->ns_outscale*mgravefunc(texvec[0], texvec[1], texvec[2] + offs, tex->mg_H, tex->mg_lacunarity, tex->mg_octaves, tex->noisebasis); - + tex_normal_derivate(tex, texres); rv |= TEX_NOR; } @@ -507,7 +507,7 @@ static float mg_ridgedOrHybridMFTex(Tex *tex, const float texvec[3], TexResult * texres->nor[0] = tex->ns_outscale*mgravefunc(texvec[0] + offs, texvec[1], texvec[2], tex->mg_H, tex->mg_lacunarity, tex->mg_octaves, tex->mg_offset, tex->mg_gain, tex->noisebasis); texres->nor[1] = tex->ns_outscale*mgravefunc(texvec[0], texvec[1] + offs, texvec[2], tex->mg_H, tex->mg_lacunarity, tex->mg_octaves, tex->mg_offset, tex->mg_gain, tex->noisebasis); texres->nor[2] = tex->ns_outscale*mgravefunc(texvec[0], texvec[1], texvec[2] + offs, tex->mg_H, tex->mg_lacunarity, tex->mg_octaves, tex->mg_offset, tex->mg_gain, tex->noisebasis); - + tex_normal_derivate(tex, texres); rv |= TEX_NOR; } @@ -532,7 +532,7 @@ static float mg_HTerrainTex(Tex *tex, const float texvec[3], TexResult *texres) texres->nor[0] = tex->ns_outscale*mg_HeteroTerrain(texvec[0] + offs, texvec[1], texvec[2], tex->mg_H, tex->mg_lacunarity, tex->mg_octaves, tex->mg_offset, tex->noisebasis); texres->nor[1] = tex->ns_outscale*mg_HeteroTerrain(texvec[0], texvec[1] + offs, texvec[2], tex->mg_H, tex->mg_lacunarity, tex->mg_octaves, tex->mg_offset, tex->noisebasis); texres->nor[2] = tex->ns_outscale*mg_HeteroTerrain(texvec[0], texvec[1], texvec[2] + offs, tex->mg_H, tex->mg_lacunarity, tex->mg_octaves, tex->mg_offset, tex->noisebasis); - + tex_normal_derivate(tex, texres); rv |= TEX_NOR; } @@ -630,7 +630,7 @@ static float voronoiTex(Tex *tex, const float texvec[3], TexResult *texres) texres->nor[1] = sc * fabsf(tex->vn_w1*da[0] + tex->vn_w2*da[1] + tex->vn_w3*da[2] + tex->vn_w4*da[3]); voronoi(texvec[0], texvec[1], texvec[2] + offs, da, pa, tex->vn_mexp, tex->vn_distm); texres->nor[2] = sc * fabsf(tex->vn_w1*da[0] + tex->vn_w2*da[1] + tex->vn_w3*da[2] + tex->vn_w4*da[3]); - + tex_normal_derivate(tex, texres); rv |= TEX_NOR; } @@ -640,7 +640,7 @@ static float voronoiTex(Tex *tex, const float texvec[3], TexResult *texres) texres->ta = 1.0; return (rv | TEX_RGB); } - + BRICONT; return rv; @@ -653,20 +653,20 @@ static int texnoise(Tex *tex, TexResult *texres, int thread) { float div=3.0; int val, ran, loop, shift = 29; - + ran= BLI_rng_thread_rand(random_tex_array, thread); - + loop= tex->noisedepth; /* start from top bits since they have more variance */ val= ((ran >> shift) & 3); - + while (loop--) { - shift -= 2; + shift -= 2; val *= ((ran >> shift) & 3); div *= 3.0f; } - + texres->tin= ((float)val)/div; BRICONT; @@ -679,7 +679,7 @@ static int cubemap_glob(const float n[3], float x, float y, float z, float *adr1 { float x1, y1, z1, nor[3]; int ret; - + if (n==NULL) { nor[0]= x; nor[1]= y; nor[2]= z; /* use local render coord */ } @@ -690,7 +690,7 @@ static int cubemap_glob(const float n[3], float x, float y, float z, float *adr1 x1 = fabsf(nor[0]); y1 = fabsf(nor[1]); z1 = fabsf(nor[2]); - + if (z1>=x1 && z1>=y1) { *adr1 = (x + 1.0f) / 2.0f; *adr2 = (y + 1.0f) / 2.0f; @@ -719,13 +719,13 @@ static void do_2d_mapping( Tex *tex; float fx, fy, fac1, area[8]; int ok, proj, areaflag= 0, wrap; - + /* mtex variables localized, only cubemap doesn't cooperate yet... */ wrap= mtex->mapping; tex= mtex->tex; if (!(dxt && dyt)) { - + if (wrap==MTEX_FLAT) { fx = (texvec[0] + 1.0f) / 2.0f; fy = (texvec[1] + 1.0f) / 2.0f; @@ -735,15 +735,15 @@ static void do_2d_mapping( else { cubemap_glob(n, texvec[0], texvec[1], texvec[2], &fx, &fy); } - + /* repeat */ if (tex->extend==TEX_REPEAT) { if (tex->xrepeat>1) { float origf= fx *= tex->xrepeat; - + if (fx>1.0f) fx -= (int)(fx); else if (fx<0.0f) fx+= 1-(int)(fx); - + if (tex->flag & TEX_REPEAT_XMIR) { int orig= (int)floor(origf); if (orig & 1) @@ -752,10 +752,10 @@ static void do_2d_mapping( } if (tex->yrepeat>1) { float origf= fy *= tex->yrepeat; - + if (fy>1.0f) fy -= (int)(fy); else if (fy<0.0f) fy+= 1-(int)(fy); - + if (tex->flag & TEX_REPEAT_YMIR) { int orig= (int)floor(origf); if (orig & 1) @@ -777,7 +777,7 @@ static void do_2d_mapping( texvec[1]= fy; } else { - + if (wrap==MTEX_FLAT) { fx= (texvec[0] + 1.0f) / 2.0f; fy= (texvec[1] + 1.0f) / 2.0f; @@ -854,55 +854,55 @@ static void do_2d_mapping( dyt[2] *= 0.5f; } - + /* if area, then reacalculate dxt[] and dyt[] */ if (areaflag) { - fx= area[0]; + fx= area[0]; fy= area[1]; dxt[0]= area[2]-fx; dxt[1]= area[3]-fy; dyt[0]= area[4]-fx; dyt[1]= area[5]-fy; } - + /* repeat */ if (tex->extend==TEX_REPEAT) { float max= 1.0f; if (tex->xrepeat>1) { float origf= fx *= tex->xrepeat; - + /* TXF: omit mirror here, see comments in do_material_tex() after do_2d_mapping() call */ if (tex->texfilter == TXF_BOX) { if (fx>1.0f) fx -= (int)(fx); else if (fx<0.0f) fx+= 1-(int)(fx); - + if (tex->flag & TEX_REPEAT_XMIR) { int orig= (int)floor(origf); if (orig & 1) fx= 1.0f-fx; } } - + max= tex->xrepeat; - + dxt[0]*= tex->xrepeat; dyt[0]*= tex->xrepeat; } if (tex->yrepeat>1) { float origf= fy *= tex->yrepeat; - + /* TXF: omit mirror here, see comments in do_material_tex() after do_2d_mapping() call */ if (tex->texfilter == TXF_BOX) { if (fy>1.0f) fy -= (int)(fy); else if (fy<0.0f) fy+= 1-(int)(fy); - + if (tex->flag & TEX_REPEAT_YMIR) { int orig= (int)floor(origf); if (orig & 1) fy= 1.0f-fy; } } - + if (max<tex->yrepeat) max= tex->yrepeat; @@ -913,7 +913,7 @@ static void do_2d_mapping( dxt[2]*= max; dyt[2]*= max; } - + } /* crop */ if (tex->cropxmin!=0.0f || tex->cropxmax!=1.0f) { @@ -928,7 +928,7 @@ static void do_2d_mapping( dxt[1]*= fac1; dyt[1]*= fac1; } - + texvec[0]= fx; texvec[1]= fy; @@ -953,7 +953,7 @@ static int multitex(Tex *tex, int retval = 0; /* return value, int:0, col:1, nor:2, everything:3 */ texres->talpha = false; /* is set when image texture returns alpha (considered premul) */ - + if (use_nodes && tex->use_nodes && tex->nodetree) { const float cfra = 1.0f; /* This was only set for Blender Internal render before. */ retval = ntreeTexExecTree(tex->nodetree, texres, texvec, dxt, dyt, osatex, thread, @@ -1072,7 +1072,7 @@ static int multitex_nodes_intern(Tex *tex, if (mtex) which_output= mtex->which_output; - + if (tex->type==TEX_IMAGE) { int rgbnor; @@ -1093,7 +1093,7 @@ static int multitex_nodes_intern(Tex *tex, if (mtex->mapto & (MAP_COL)) { ImBuf *ibuf = BKE_image_pool_acquire_ibuf(tex->ima, &tex->iuser, pool); - + /* don't linearize float buffers, assumed to be linear */ if (ibuf != NULL && ibuf->rect_float == NULL && @@ -1110,12 +1110,12 @@ static int multitex_nodes_intern(Tex *tex, /* we don't have mtex, do default flat 2d projection */ MTex localmtex; float texvec_l[3], dxt_l[3], dyt_l[3]; - + localmtex.mapping= MTEX_FLAT; localmtex.tex= tex; localmtex.object= NULL; localmtex.texco= TEXCO_ORCO; - + copy_v3_v3(texvec_l, texvec); if (dxt && dyt) { copy_v3_v3(dxt_l, dxt); @@ -1125,7 +1125,7 @@ static int multitex_nodes_intern(Tex *tex, zero_v3(dxt_l); zero_v3(dyt_l); } - + do_2d_mapping(&localmtex, texvec_l, NULL, dxt_l, dyt_l); rgbnor = multitex(tex, texvec_l, @@ -1244,7 +1244,7 @@ int multitex_ext_safe(Tex *tex, float texvec[3], TexResult *texres, struct Image void texture_rgb_blend(float in[3], const float tex[3], const float out[3], float fact, float facg, int blendtype) { float facm; - + switch (blendtype) { case MTEX_BLEND: fact*= facg; @@ -1254,7 +1254,7 @@ void texture_rgb_blend(float in[3], const float tex[3], const float out[3], floa in[1]= (fact*tex[1] + facm*out[1]); in[2]= (fact*tex[2] + facm*out[2]); break; - + case MTEX_MUL: fact*= facg; facm= 1.0f-fact; @@ -1274,7 +1274,7 @@ void texture_rgb_blend(float in[3], const float tex[3], const float out[3], floa case MTEX_OVERLAY: fact*= facg; facm= 1.0f-fact; - + if (out[0] < 0.5f) in[0] = out[0] * (facm + 2.0f*fact*tex[0]); else @@ -1288,7 +1288,7 @@ void texture_rgb_blend(float in[3], const float tex[3], const float out[3], floa else in[2] = 1.0f - (facm + 2.0f*fact*(1.0f - tex[2])) * (1.0f - out[2]); break; - + case MTEX_SUB: fact= -fact; ATTR_FALLTHROUGH; @@ -1302,7 +1302,7 @@ void texture_rgb_blend(float in[3], const float tex[3], const float out[3], floa case MTEX_DIV: fact*= facg; facm= 1.0f-fact; - + if (tex[0]!=0.0f) in[0]= facm*out[0] + fact*out[0]/tex[0]; if (tex[1]!=0.0f) @@ -1323,7 +1323,7 @@ void texture_rgb_blend(float in[3], const float tex[3], const float out[3], floa case MTEX_DARK: fact*= facg; facm= 1.0f-fact; - + in[0] = min_ff(out[0], tex[0])*fact + out[0]*facm; in[1] = min_ff(out[1], tex[1])*fact + out[1]*facm; in[2] = min_ff(out[2], tex[2])*fact + out[2]*facm; @@ -1336,7 +1336,7 @@ void texture_rgb_blend(float in[3], const float tex[3], const float out[3], floa in[1] = max_ff(fact * tex[1], out[1]); in[2] = max_ff(fact * tex[2], out[2]); break; - + case MTEX_BLEND_HUE: fact*= facg; copy_v3_v3(in, out); @@ -1357,16 +1357,16 @@ void texture_rgb_blend(float in[3], const float tex[3], const float out[3], floa copy_v3_v3(in, out); ramp_blend(MA_RAMP_COLOR, in, fact, tex); break; - case MTEX_SOFT_LIGHT: - fact*= facg; + case MTEX_SOFT_LIGHT: + fact*= facg; copy_v3_v3(in, out); ramp_blend(MA_RAMP_SOFT, in, fact, tex); - break; - case MTEX_LIN_LIGHT: - fact*= facg; + break; + case MTEX_LIN_LIGHT: + fact*= facg; copy_v3_v3(in, out); ramp_blend(MA_RAMP_LINEAR, in, fact, tex); - break; + break; } } @@ -1376,7 +1376,7 @@ float texture_value_blend(float tex, float out, float fact, float facg, int blen int flip= (facg < 0.0f); facg= fabsf(facg); - + fact*= facg; facm= 1.0f-fact; if (flip) SWAP(float, fact, facm); @@ -1429,19 +1429,19 @@ float texture_value_blend(float tex, float out, float fact, float facg, int blen if (col > out) in= col; else in= out; break; - case MTEX_SOFT_LIGHT: + case MTEX_SOFT_LIGHT: scf=1.0f - (1.0f - tex) * (1.0f - out); in= facm*out + fact * ((1.0f - out) * tex * out) + (out * scf); - break; + break; - case MTEX_LIN_LIGHT: + case MTEX_LIN_LIGHT: if (tex > 0.5f) in = out + fact*(2.0f*(tex - 0.5f)); - else + else in = out + fact*(2.0f*tex - 1.0f); break; } - + return in; } @@ -1459,26 +1459,26 @@ int externtex(const MTex *mtex, TexResult texr; float dxt[3], dyt[3], texvec[3]; int rgb; - + tex= mtex->tex; if (tex==NULL) return 0; texr.nor= NULL; - + /* placement */ if (mtex->projx) texvec[0]= mtex->size[0]*(vec[mtex->projx-1]+mtex->ofs[0]); else texvec[0]= mtex->size[0]*(mtex->ofs[0]); - + if (mtex->projy) texvec[1]= mtex->size[1]*(vec[mtex->projy-1]+mtex->ofs[1]); else texvec[1]= mtex->size[1]*(mtex->ofs[1]); - + if (mtex->projz) texvec[2]= mtex->size[2]*(vec[mtex->projz-1]+mtex->ofs[2]); else texvec[2]= mtex->size[2]*(mtex->ofs[2]); - + /* texture */ if (tex->type==TEX_IMAGE) { do_2d_mapping(mtex, texvec, NULL, dxt, dyt); } - + rgb = multitex(tex, texvec, dxt, dyt, @@ -1489,7 +1489,7 @@ int externtex(const MTex *mtex, skip_load_image, texnode_preview, true); - + if (rgb) { texr.tin = IMB_colormanagement_get_luminance(&texr.tr); } @@ -1498,7 +1498,7 @@ int externtex(const MTex *mtex, texr.tg= mtex->g; texr.tb= mtex->b; } - + *tin= texr.tin; *tr= texr.tr; *tg= texr.tg; diff --git a/source/blender/render/intern/source/rendercore.c b/source/blender/render/intern/source/rendercore.c new file mode 100644 index 00000000000..99d2436d4bc --- /dev/null +++ b/source/blender/render/intern/source/rendercore.c @@ -0,0 +1,2030 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * Contributors: Hos, Robert Wenzlaff. + * Contributors: 2004/2005/2006 Blender Foundation, full recode + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/render/intern/source/rendercore.c + * \ingroup render + */ + + +/* system includes */ +#include <stdio.h> +#include <math.h> +#include <float.h> +#include <string.h> +#include <assert.h> + +/* External modules: */ +#include "MEM_guardedalloc.h" + +#include "BLI_math.h" +#include "BLI_blenlib.h" +#include "BLI_rand.h" +#include "BLI_threads.h" +#include "BLI_utildefines.h" + +#include "DNA_image_types.h" +#include "DNA_lamp_types.h" +#include "DNA_material_types.h" +#include "DNA_group_types.h" + +/* local include */ +#include "renderpipeline.h" +#include "render_result.h" +#include "render_types.h" +#include "renderdatabase.h" +#include "occlusion.h" +#include "pixelblending.h" +#include "pixelshading.h" +#include "shadbuf.h" +#include "shading.h" +#include "sss.h" +#include "zbuf.h" + +/* own include */ +#include "rendercore.h" + + +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ +/* defined in pipeline.c, is hardcopy of active dynamic allocated Render */ +/* only to be used here in this file, it's for speed */ +extern struct Render R; +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ + +/* x and y are current pixels in rect to be rendered */ +/* do not normalize! */ +void calc_view_vector(float view[3], float x, float y) +{ + + view[2]= -ABS(R.clipsta); + + if (R.r.mode & R_ORTHO) { + view[0]= view[1]= 0.0f; + } + else { + + if (R.r.mode & R_PANORAMA) { + x-= R.panodxp; + } + + /* move x and y to real viewplane coords */ + x = (x / (float)R.winx); + view[0] = R.viewplane.xmin + x * BLI_rctf_size_x(&R.viewplane); + + y = (y / (float)R.winy); + view[1] = R.viewplane.ymin + y * BLI_rctf_size_y(&R.viewplane); + +// if (R.flag & R_SEC_FIELD) { +// if (R.r.mode & R_ODDFIELD) view[1]= (y+R.ystart)*R.ycor; +// else view[1]= (y+R.ystart+1.0)*R.ycor; +// } +// else view[1]= (y+R.ystart+R.bluroffsy+0.5)*R.ycor; + + if (R.r.mode & R_PANORAMA) { + float u= view[0] + R.panodxv; float v= view[2]; + view[0]= R.panoco*u + R.panosi*v; + view[2]= -R.panosi*u + R.panoco*v; + } + } +} + +void calc_renderco_ortho(float co[3], float x, float y, int z) +{ + /* x and y 3d coordinate can be derived from pixel coord and winmat */ + float fx= 2.0f/(R.winx*R.winmat[0][0]); + float fy= 2.0f/(R.winy*R.winmat[1][1]); + float zco; + + co[0]= (x - 0.5f*R.winx)*fx - R.winmat[3][0]/R.winmat[0][0]; + co[1]= (y - 0.5f*R.winy)*fy - R.winmat[3][1]/R.winmat[1][1]; + + zco= ((float)z)/2147483647.0f; + co[2]= R.winmat[3][2]/( R.winmat[2][3]*zco - R.winmat[2][2] ); +} + +void calc_renderco_zbuf(float co[3], const float view[3], int z) +{ + float fac, zco; + + /* inverse of zbuf calc: zbuf = MAXZ*hoco_z/hoco_w */ + zco= ((float)z)/2147483647.0f; + co[2]= R.winmat[3][2]/( R.winmat[2][3]*zco - R.winmat[2][2] ); + + fac= co[2]/view[2]; + co[0]= fac*view[0]; + co[1]= fac*view[1]; +} + +/* also used in zbuf.c and shadbuf.c */ +int count_mask(unsigned short mask) +{ + if (R.samples) + return (R.samples->cmask[mask & 255]+R.samples->cmask[mask>>8]); + return 0; +} + +static int calchalo_z(HaloRen *har, int zz) +{ + + if (har->type & HA_ONLYSKY) { + if (zz < 0x7FFFFFF0) zz= - 0x7FFFFF; /* edge render messes zvalues */ + } + else { + zz= (zz>>8); + } + return zz; +} + + + +static void halo_pixelstruct(HaloRen *har, RenderLayer **rlpp, int totsample, int od, float dist, float xn, float yn, PixStr *ps) +{ + float col[4], accol[4], fac; + int amount, amountm, zz, flarec, sample, fullsample, mask=0; + + fullsample= (totsample > 1); + amount= 0; + accol[0] = accol[1] = accol[2] = accol[3]= 0.0f; + col[0] = col[1] = col[2] = col[3]= 0.0f; + flarec= har->flarec; + + while (ps) { + amountm= count_mask(ps->mask); + amount+= amountm; + + zz= calchalo_z(har, ps->z); + if ((zz> har->zs) || (har->mat && (har->mat->mode & MA_HALO_SOFT))) { + if (shadeHaloFloat(har, col, zz, dist, xn, yn, flarec)) { + flarec= 0; + + if (fullsample) { + for (sample=0; sample<totsample; sample++) { + if (ps->mask & (1 << sample)) { + float *pass = RE_RenderLayerGetPass(rlpp[sample], RE_PASSNAME_COMBINED, R.viewname); + addalphaAddfacFloat(pass + od*4, col, har->add); + } + } + } + else { + fac= ((float)amountm)/(float)R.osa; + accol[0]+= fac*col[0]; + accol[1]+= fac*col[1]; + accol[2]+= fac*col[2]; + accol[3]+= fac*col[3]; + } + } + } + + mask |= ps->mask; + ps= ps->next; + } + + /* now do the sky sub-pixels */ + amount= R.osa-amount; + if (amount) { + if (shadeHaloFloat(har, col, 0x7FFFFF, dist, xn, yn, flarec)) { + if (!fullsample) { + fac= ((float)amount)/(float)R.osa; + accol[0]+= fac*col[0]; + accol[1]+= fac*col[1]; + accol[2]+= fac*col[2]; + accol[3]+= fac*col[3]; + } + } + } + + if (fullsample) { + for (sample=0; sample<totsample; sample++) { + if (!(mask & (1 << sample))) { + float *pass = RE_RenderLayerGetPass(rlpp[sample], RE_PASSNAME_COMBINED, R.viewname); + addalphaAddfacFloat(pass + od*4, col, har->add); + } + } + } + else { + col[0]= accol[0]; + col[1]= accol[1]; + col[2]= accol[2]; + col[3]= accol[3]; + + for (sample=0; sample<totsample; sample++) { + float *pass = RE_RenderLayerGetPass(rlpp[sample], RE_PASSNAME_COMBINED, R.viewname); + addalphaAddfacFloat(pass + od*4, col, har->add); + } + } +} + +static void halo_tile(RenderPart *pa, RenderLayer *rl) +{ + RenderLayer *rlpp[RE_MAX_OSA]; + HaloRen *har; + rcti disprect= pa->disprect, testrect= pa->disprect; + float dist, xsq, ysq, xn, yn; + float col[4]; + intptr_t *rd= NULL; + int a, *rz, zz, y, sample, totsample, od; + short minx, maxx, miny, maxy, x; + unsigned int lay= rl->lay; + + /* we don't render halos in the cropped area, gives errors in flare counter */ + if (pa->crop) { + testrect.xmin+= pa->crop; + testrect.xmax-= pa->crop; + testrect.ymin+= pa->crop; + testrect.ymax-= pa->crop; + } + + totsample= get_sample_layers(pa, rl, rlpp); + + for (a=0; a<R.tothalo; a++) { + har= R.sortedhalos[a]; + + /* layer test, clip halo with y */ + if ((har->lay & lay) == 0) { + /* pass */ + } + else if (testrect.ymin > har->maxy) { + /* pass */ + } + else if (testrect.ymax < har->miny) { + /* pass */ + } + else { + + minx= floor(har->xs-har->rad); + maxx= ceil(har->xs+har->rad); + + if (testrect.xmin > maxx) { + /* pass */ + } + else if (testrect.xmax < minx) { + /* pass */ + } + else { + + minx = max_ii(minx, testrect.xmin); + maxx = min_ii(maxx, testrect.xmax); + + miny = max_ii(har->miny, testrect.ymin); + maxy = min_ii(har->maxy, testrect.ymax); + + for (y=miny; y<maxy; y++) { + int rectofs= (y-disprect.ymin)*pa->rectx + (minx - disprect.xmin); + rz= pa->rectz + rectofs; + od= rectofs; + + if (pa->rectdaps) + rd= pa->rectdaps + rectofs; + + yn= (y-har->ys)*R.ycor; + ysq= yn*yn; + + for (x=minx; x<maxx; x++, rz++, od++) { + xn= x- har->xs; + xsq= xn*xn; + dist= xsq+ysq; + if (dist<har->radsq) { + if (rd && *rd) { + halo_pixelstruct(har, rlpp, totsample, od, dist, xn, yn, (PixStr *)*rd); + } + else { + zz= calchalo_z(har, *rz); + if ((zz> har->zs) || (har->mat && (har->mat->mode & MA_HALO_SOFT))) { + if (shadeHaloFloat(har, col, zz, dist, xn, yn, har->flarec)) { + for (sample=0; sample<totsample; sample++) { + float * rect= RE_RenderLayerGetPass(rlpp[sample], RE_PASSNAME_COMBINED, R.viewname); + addalphaAddfacFloat(rect + od*4, col, har->add); + } + } + } + } + } + if (rd) rd++; + } + } + } + } + if (R.test_break(R.tbh) ) break; + } +} + +static void lamphalo_tile(RenderPart *pa, RenderLayer *rl) +{ + RenderLayer *rlpp[RE_MAX_OSA]; + ShadeInput shi; + float *pass; + float fac, col[4]; + intptr_t *rd= pa->rectdaps; + const int *rz= pa->rectz; + int x, y, sample, totsample, fullsample, od; + + totsample= get_sample_layers(pa, rl, rlpp); + fullsample= (totsample > 1); + + shade_input_initialize(&shi, pa, rl, 0); /* this zero's ShadeInput for us */ + + for (od=0, y=pa->disprect.ymin; y<pa->disprect.ymax; y++) { + for (x=pa->disprect.xmin; x<pa->disprect.xmax; x++, rz++, od++) { + + calc_view_vector(shi.view, x, y); + + if (rd && *rd) { + PixStr *ps= (PixStr *)*rd; + int count, totsamp= 0, mask= 0; + + while (ps) { + if (R.r.mode & R_ORTHO) + calc_renderco_ortho(shi.co, (float)x, (float)y, ps->z); + else + calc_renderco_zbuf(shi.co, shi.view, ps->z); + + totsamp+= count= count_mask(ps->mask); + mask |= ps->mask; + + col[0]= col[1]= col[2]= col[3]= 0.0f; + renderspothalo(&shi, col, 1.0f); + + if (fullsample) { + for (sample=0; sample<totsample; sample++) { + if (ps->mask & (1 << sample)) { + pass = RE_RenderLayerGetPass(rlpp[sample], RE_PASSNAME_COMBINED, R.viewname); + pass += od * 4; + pass[0]+= col[0]; + pass[1]+= col[1]; + pass[2]+= col[2]; + pass[3]+= col[3]; + if (pass[3]>1.0f) pass[3]= 1.0f; + } + } + } + else { + fac= ((float)count)/(float)R.osa; + pass = RE_RenderLayerGetPass(rl, RE_PASSNAME_COMBINED, R.viewname); + pass += od * 4; + pass[0]+= fac*col[0]; + pass[1]+= fac*col[1]; + pass[2]+= fac*col[2]; + pass[3]+= fac*col[3]; + if (pass[3]>1.0f) pass[3]= 1.0f; + } + + ps= ps->next; + } + + if (totsamp<R.osa) { + shi.co[2]= 0.0f; + + col[0]= col[1]= col[2]= col[3]= 0.0f; + renderspothalo(&shi, col, 1.0f); + + if (fullsample) { + for (sample=0; sample<totsample; sample++) { + if (!(mask & (1 << sample))) { + + pass = RE_RenderLayerGetPass(rlpp[sample], RE_PASSNAME_COMBINED, R.viewname); + pass += od * 4; + pass[0]+= col[0]; + pass[1]+= col[1]; + pass[2]+= col[2]; + pass[3]+= col[3]; + if (pass[3]>1.0f) pass[3]= 1.0f; + } + } + } + else { + fac= ((float)R.osa-totsamp)/(float)R.osa; + pass = RE_RenderLayerGetPass(rl, RE_PASSNAME_COMBINED, R.viewname); + pass += od * 4; + pass[0]+= fac*col[0]; + pass[1]+= fac*col[1]; + pass[2]+= fac*col[2]; + pass[3]+= fac*col[3]; + if (pass[3]>1.0f) pass[3]= 1.0f; + } + } + } + else { + if (R.r.mode & R_ORTHO) + calc_renderco_ortho(shi.co, (float)x, (float)y, *rz); + else + calc_renderco_zbuf(shi.co, shi.view, *rz); + + col[0]= col[1]= col[2]= col[3]= 0.0f; + renderspothalo(&shi, col, 1.0f); + + for (sample=0; sample<totsample; sample++) { + pass = RE_RenderLayerGetPass(rlpp[sample], RE_PASSNAME_COMBINED, R.viewname); + pass += od * 4; + pass[0]+= col[0]; + pass[1]+= col[1]; + pass[2]+= col[2]; + pass[3]+= col[3]; + if (pass[3]>1.0f) pass[3]= 1.0f; + } + } + + if (rd) rd++; + } + if (y&1) + if (R.test_break(R.tbh)) break; + } +} + + +/* ********************* MAINLOOPS ******************** */ + +/* osa version */ +static void add_filt_passes(RenderLayer *rl, int curmask, int rectx, int offset, ShadeInput *shi, ShadeResult *shr) +{ + RenderPass *rpass; + + for (rpass= rl->passes.first; rpass; rpass= rpass->next) { + float *fp, *col= NULL; + int pixsize= 3; + + if (STREQ(rpass->name, RE_PASSNAME_COMBINED)) { + add_filt_fmask(curmask, shr->combined, rpass->rect + 4*offset, rectx); + } + else if (STREQ(rpass->name, RE_PASSNAME_Z)) { + fp = rpass->rect + offset; + *fp = shr->z; + } + else if (STREQ(rpass->name, RE_PASSNAME_RGBA)) { + col = shr->col; + pixsize = 4; + } + else if (STREQ(rpass->name, RE_PASSNAME_EMIT)) { + col = shr->emit; + } + else if (STREQ(rpass->name, RE_PASSNAME_DIFFUSE)) { + col = shr->diff; + } + else if (STREQ(rpass->name, RE_PASSNAME_SPEC)) { + col = shr->spec; + } + else if (STREQ(rpass->name, RE_PASSNAME_SHADOW)) { + col = shr->shad; + } + else if (STREQ(rpass->name, RE_PASSNAME_AO)) { + col = shr->ao; + } + else if (STREQ(rpass->name, RE_PASSNAME_ENVIRONMENT)) { + col = shr->env; + } + else if (STREQ(rpass->name, RE_PASSNAME_INDIRECT)) { + col = shr->indirect; + } + else if (STREQ(rpass->name, RE_PASSNAME_REFLECT)) { + col = shr->refl; + } + else if (STREQ(rpass->name, RE_PASSNAME_REFRACT)) { + col = shr->refr; + } + else if (STREQ(rpass->name, RE_PASSNAME_NORMAL)) { + col = shr->nor; + } + else if (STREQ(rpass->name, RE_PASSNAME_UV)) { + /* box filter only, gauss will screwup UV too much */ + if (shi->totuv) { + float mult = (float)count_mask(curmask)/(float)R.osa; + fp = rpass->rect + 3*offset; + fp[0]+= mult*(0.5f + 0.5f*shi->uv[shi->actuv].uv[0]); + fp[1]+= mult*(0.5f + 0.5f*shi->uv[shi->actuv].uv[1]); + fp[2]+= mult; + } + } + else if (STREQ(rpass->name, RE_PASSNAME_INDEXOB)) { + /* no filter */ + if (shi->vlr) { + fp = rpass->rect + offset; + if (*fp==0.0f) + *fp = (float)shi->obr->ob->index; + } + } + else if (STREQ(rpass->name, RE_PASSNAME_INDEXMA)) { + /* no filter */ + if (shi->vlr) { + fp = rpass->rect + offset; + if (*fp==0.0f) + *fp = (float)shi->mat->index; + } + } + else if (STREQ(rpass->name, RE_PASSNAME_MIST)) { + /* */ + col = &shr->mist; + pixsize = 1; + } + else if (STREQ(rpass->name, RE_PASSNAME_VECTOR)) { + /* add minimum speed in pixel, no filter */ + fp = rpass->rect + 4*offset; + if ( (ABS(shr->winspeed[0]) + ABS(shr->winspeed[1]))< (ABS(fp[0]) + ABS(fp[1])) ) { + fp[0] = shr->winspeed[0]; + fp[1] = shr->winspeed[1]; + } + if ( (ABS(shr->winspeed[2]) + ABS(shr->winspeed[3]))< (ABS(fp[2]) + ABS(fp[3])) ) { + fp[2] = shr->winspeed[2]; + fp[3] = shr->winspeed[3]; + } + } + else if (STREQ(rpass->name, RE_PASSNAME_RAYHITS)) { + /* */ + col = shr->rayhits; + pixsize= 4; + } + + if (col) { + fp= rpass->rect + pixsize*offset; + add_filt_fmask_pixsize(curmask, col, fp, rectx, pixsize); + } + } +} + +/* non-osa version */ +static void add_passes(RenderLayer *rl, int offset, ShadeInput *shi, ShadeResult *shr) +{ + RenderPass *rpass; + float *fp; + + for (rpass= rl->passes.first; rpass; rpass= rpass->next) { + float *col= NULL, uvcol[3]; + int a, pixsize= 3; + + if (STREQ(rpass->name, RE_PASSNAME_COMBINED)) { + /* copy combined to use for preview */ + copy_v4_v4(rpass->rect + 4*offset, shr->combined); + } + else if (STREQ(rpass->name, RE_PASSNAME_Z)) { + fp = rpass->rect + offset; + *fp = shr->z; + } + else if (STREQ(rpass->name, RE_PASSNAME_RGBA)) { + col = shr->col; + pixsize = 4; + } + else if (STREQ(rpass->name, RE_PASSNAME_EMIT)) { + col = shr->emit; + } + else if (STREQ(rpass->name, RE_PASSNAME_DIFFUSE)) { + col = shr->diff; + } + else if (STREQ(rpass->name, RE_PASSNAME_SPEC)) { + col = shr->spec; + } + else if (STREQ(rpass->name, RE_PASSNAME_SHADOW)) { + col = shr->shad; + } + else if (STREQ(rpass->name, RE_PASSNAME_AO)) { + col = shr->ao; + } + else if (STREQ(rpass->name, RE_PASSNAME_ENVIRONMENT)) { + col = shr->env; + } + else if (STREQ(rpass->name, RE_PASSNAME_INDIRECT)) { + col = shr->indirect; + } + else if (STREQ(rpass->name, RE_PASSNAME_REFLECT)) { + col = shr->refl; + } + else if (STREQ(rpass->name, RE_PASSNAME_REFRACT)) { + col = shr->refr; + } + else if (STREQ(rpass->name, RE_PASSNAME_NORMAL)) { + col = shr->nor; + } + else if (STREQ(rpass->name, RE_PASSNAME_UV)) { + if (shi->totuv) { + uvcol[0] = 0.5f + 0.5f*shi->uv[shi->actuv].uv[0]; + uvcol[1] = 0.5f + 0.5f*shi->uv[shi->actuv].uv[1]; + uvcol[2] = 1.0f; + col = uvcol; + } + } + else if (STREQ(rpass->name, RE_PASSNAME_VECTOR)) { + col = shr->winspeed; + pixsize = 4; + } + else if (STREQ(rpass->name, RE_PASSNAME_INDEXOB)) { + if (shi->vlr) { + fp = rpass->rect + offset; + *fp = (float)shi->obr->ob->index; + } + } + else if (STREQ(rpass->name, RE_PASSNAME_INDEXMA)) { + if (shi->vlr) { + fp = rpass->rect + offset; + *fp = (float)shi->mat->index; + } + } + else if (STREQ(rpass->name, RE_PASSNAME_MIST)) { + fp = rpass->rect + offset; + *fp = shr->mist; + } + else if (STREQ(rpass->name, RE_PASSNAME_RAYHITS)) { + col = shr->rayhits; + pixsize = 4; + } + + if (col) { + fp = rpass->rect + pixsize*offset; + for (a=0; a<pixsize; a++) + fp[a] = col[a]; + } + } +} + +int get_sample_layers(RenderPart *pa, RenderLayer *rl, RenderLayer **rlpp) +{ + + if (pa->fullresult.first) { + int sample, nr= BLI_findindex(&pa->result->layers, rl); + + for (sample=0; sample<R.osa; sample++) { + RenderResult *rr= BLI_findlink(&pa->fullresult, sample); + + rlpp[sample]= BLI_findlink(&rr->layers, nr); + } + return R.osa; + } + else { + rlpp[0]= rl; + return 1; + } +} + + +/* only do sky, is default in the solid layer (shade_tile) btw */ +static void sky_tile(RenderPart *pa, RenderLayer *rl) +{ + RenderLayer *rlpp[RE_MAX_OSA]; + int x, y, od=0, totsample; + + if (R.r.alphamode!=R_ADDSKY) + return; + + totsample= get_sample_layers(pa, rl, rlpp); + + for (y=pa->disprect.ymin; y<pa->disprect.ymax; y++) { + for (x=pa->disprect.xmin; x<pa->disprect.xmax; x++, od+=4) { + float col[4]; + int sample; + bool done = false; + + for (sample= 0; sample<totsample; sample++) { + float *pass = RE_RenderLayerGetPass(rlpp[sample], RE_PASSNAME_COMBINED, R.viewname); + pass += od; + + if (pass[3]<1.0f) { + + if (done==0) { + shadeSkyPixel(col, x, y, pa->thread); + done = true; + } + + if (pass[3]==0.0f) { + copy_v4_v4(pass, col); + pass[3] = 1.0f; + } + else { + addAlphaUnderFloat(pass, col); + pass[3] = 1.0f; + } + } + } + } + + if (y&1) + if (R.test_break(R.tbh)) break; + } +} + +static void atm_tile(RenderPart *pa, RenderLayer *rl) +{ + RenderPass *zpass; + GroupObject *go; + LampRen *lar; + RenderLayer *rlpp[RE_MAX_OSA]; + int totsample; + int x, y, od= 0; + + totsample= get_sample_layers(pa, rl, rlpp); + + /* check that z pass is enabled */ + if (pa->rectz==NULL) return; + for (zpass= rl->passes.first; zpass; zpass= zpass->next) + if (STREQ(zpass->name, RE_PASSNAME_Z)) + break; + + if (zpass==NULL) return; + + /* check for at least one sun lamp that its atmosphere flag is enabled */ + for (go=R.lights.first; go; go= go->next) { + lar= go->lampren; + if (lar->type==LA_SUN && lar->sunsky && (lar->sunsky->effect_type & LA_SUN_EFFECT_AP)) + break; + } + /* do nothign and return if there is no sun lamp */ + if (go==NULL) + return; + + /* for each x,y and each sample, and each sun lamp*/ + for (y=pa->disprect.ymin; y<pa->disprect.ymax; y++) { + for (x=pa->disprect.xmin; x<pa->disprect.xmax; x++, od++) { + int sample; + + for (sample=0; sample<totsample; sample++) { + const float *zrect = RE_RenderLayerGetPass(rlpp[sample], RE_PASSNAME_Z, R.viewname) + od; + float *rgbrect = RE_RenderLayerGetPass(rlpp[sample], RE_PASSNAME_COMBINED, R.viewname) + 4*od; + float rgb[3] = {0}; + bool done = false; + + for (go=R.lights.first; go; go= go->next) { + + + lar= go->lampren; + if (lar->type==LA_SUN && lar->sunsky) { + + /* if it's sky continue and don't apply atmosphere effect on it */ + if (*zrect >= 9.9e10f || rgbrect[3]==0.0f) { + continue; + } + + if ((lar->sunsky->effect_type & LA_SUN_EFFECT_AP)) { + float tmp_rgb[3]; + + /* skip if worldspace lamp vector is below horizon */ + if (go->ob->obmat[2][2] < 0.f) { + continue; + } + + copy_v3_v3(tmp_rgb, rgbrect); + if (rgbrect[3]!=1.0f) { /* de-premul */ + mul_v3_fl(tmp_rgb, 1.0f/rgbrect[3]); + } + shadeAtmPixel(lar->sunsky, tmp_rgb, x, y, *zrect); + if (rgbrect[3]!=1.0f) { /* premul */ + mul_v3_fl(tmp_rgb, rgbrect[3]); + } + + if (done==0) { + copy_v3_v3(rgb, tmp_rgb); + done = true; + } + else { + rgb[0] = 0.5f*rgb[0] + 0.5f*tmp_rgb[0]; + rgb[1] = 0.5f*rgb[1] + 0.5f*tmp_rgb[1]; + rgb[2] = 0.5f*rgb[2] + 0.5f*tmp_rgb[2]; + } + } + } + } + + /* if at least for one sun lamp aerial perspective was applied*/ + if (done) { + copy_v3_v3(rgbrect, rgb); + } + } + } + } +} + +static void shadeDA_tile(RenderPart *pa, RenderLayer *rl) +{ + RenderResult *rr= pa->result; + ShadeSample ssamp; + intptr_t *rd, *rectdaps= pa->rectdaps; + int samp; + int x, y, seed, crop=0, offs=0, od; + + if (R.test_break(R.tbh)) return; + + /* irregular shadowb buffer creation */ + if (R.r.mode & R_SHADOW) + ISB_create(pa, NULL); + + /* we set per pixel a fixed seed, for random AO and shadow samples */ + seed= pa->rectx*pa->disprect.ymin; + + /* general shader info, passes */ + shade_sample_initialize(&ssamp, pa, rl); + + /* occlusion caching */ + if (R.occlusiontree) + cache_occ_samples(&R, pa, &ssamp); + + /* filtered render, for now we assume only 1 filter size */ + if (pa->crop) { + crop= 1; + rectdaps+= pa->rectx + 1; + offs= pa->rectx + 1; + } + + /* scanline updates have to be 2 lines behind */ + rr->renrect.ymin = 0; + rr->renrect.ymax = -2*crop; + rr->renlay= rl; + + for (y=pa->disprect.ymin+crop; y<pa->disprect.ymax-crop; y++, rr->renrect.ymax++) { + rd= rectdaps; + od= offs; + + for (x=pa->disprect.xmin+crop; x<pa->disprect.xmax-crop; x++, rd++, od++) { + BLI_thread_srandom(pa->thread, seed++); + + if (*rd) { + if (shade_samples(&ssamp, (PixStr *)(*rd), x, y)) { + + /* multisample buffers or filtered mask filling? */ + if (pa->fullresult.first) { + int a; + for (samp=0; samp<ssamp.tot; samp++) { + int smask= ssamp.shi[samp].mask; + for (a=0; a<R.osa; a++) { + int mask= 1<<a; + if (smask & mask) + add_passes(ssamp.rlpp[a], od, &ssamp.shi[samp], &ssamp.shr[samp]); + } + } + } + else { + for (samp=0; samp<ssamp.tot; samp++) + add_filt_passes(rl, ssamp.shi[samp].mask, pa->rectx, od, &ssamp.shi[samp], &ssamp.shr[samp]); + } + } + } + } + + rectdaps+= pa->rectx; + offs+= pa->rectx; + + if (y&1) if (R.test_break(R.tbh)) break; + } + + /* disable scanline updating */ + rr->renlay= NULL; + + if (R.r.mode & R_SHADOW) + ISB_free(pa); + + if (R.occlusiontree) + free_occ_samples(&R, pa); +} + +/* ************* pixel struct ******** */ + + +static PixStrMain *addpsmain(ListBase *lb) +{ + PixStrMain *psm; + + psm= (PixStrMain *)MEM_mallocN(sizeof(PixStrMain), "pixstrMain"); + BLI_addtail(lb, psm); + + psm->ps= (PixStr *)MEM_mallocN(4096*sizeof(PixStr), "pixstr"); + psm->counter= 0; + + return psm; +} + +static void freeps(ListBase *lb) +{ + PixStrMain *psm, *psmnext; + + for (psm= lb->first; psm; psm= psmnext) { + psmnext= psm->next; + if (psm->ps) + MEM_freeN(psm->ps); + MEM_freeN(psm); + } + BLI_listbase_clear(lb); +} + +static void addps(ListBase *lb, intptr_t *rd, int obi, int facenr, int z, int maskz, unsigned short mask) +{ + PixStrMain *psm; + PixStr *ps, *last= NULL; + + if (*rd) { + ps= (PixStr *)(*rd); + + while (ps) { + if ( ps->obi == obi && ps->facenr == facenr ) { + ps->mask |= mask; + return; + } + last= ps; + ps= ps->next; + } + } + + /* make new PS (pixel struct) */ + psm= lb->last; + + if (psm->counter==4095) + psm= addpsmain(lb); + + ps= psm->ps + psm->counter++; + + if (last) last->next= ps; + else *rd= (intptr_t)ps; + + ps->next= NULL; + ps->obi= obi; + ps->facenr= facenr; + ps->z= z; + ps->maskz= maskz; + ps->mask = mask; + ps->shadfac= 0; +} + +static void edge_enhance_add(RenderPart *pa, float *rectf, float *arect) +{ + float addcol[4]; + int pix; + + if (arect==NULL) + return; + + for (pix= pa->rectx*pa->recty; pix>0; pix--, arect++, rectf+=4) { + if (*arect != 0.0f) { + addcol[0]= *arect * R.r.edgeR; + addcol[1]= *arect * R.r.edgeG; + addcol[2]= *arect * R.r.edgeB; + addcol[3]= *arect; + addAlphaOverFloat(rectf, addcol); + } + } +} + +/* clamp alpha and RGB to 0..1 and 0..inf, can go outside due to filter */ +static void clamp_alpha_rgb_range(RenderPart *pa, RenderLayer *rl) +{ + RenderLayer *rlpp[RE_MAX_OSA]; + int y, sample, totsample; + + totsample= get_sample_layers(pa, rl, rlpp); + + /* not for full sample, there we clamp after compositing */ + if (totsample > 1) + return; + + for (sample= 0; sample<totsample; sample++) { + float *rectf = RE_RenderLayerGetPass(rlpp[sample], RE_PASSNAME_COMBINED, R.viewname); + + for (y= pa->rectx*pa->recty; y>0; y--, rectf+=4) { + rectf[0] = MAX2(rectf[0], 0.0f); + rectf[1] = MAX2(rectf[1], 0.0f); + rectf[2] = MAX2(rectf[2], 0.0f); + CLAMP(rectf[3], 0.0f, 1.0f); + } + } +} + +/* adds only alpha values */ +static void edge_enhance_tile(RenderPart *pa, float *rectf, int *rectz) +{ + /* use zbuffer to define edges, add it to the image */ + int y, x, col, *rz, *rz1, *rz2, *rz3; + int zval1, zval2, zval3; + float *rf; + + /* shift values in zbuffer 4 to the right (anti overflows), for filter we need multiplying with 12 max */ + rz= rectz; + if (rz==NULL) return; + + for (y=0; y<pa->recty; y++) + for (x=0; x<pa->rectx; x++, rz++) (*rz)>>= 4; + + rz1= rectz; + rz2= rz1+pa->rectx; + rz3= rz2+pa->rectx; + + rf= rectf+pa->rectx+1; + + for (y=0; y<pa->recty-2; y++) { + for (x=0; x<pa->rectx-2; x++, rz1++, rz2++, rz3++, rf++) { + + /* prevent overflow with sky z values */ + zval1= rz1[0] + 2*rz1[1] + rz1[2]; + zval2= 2*rz2[0] + 2*rz2[2]; + zval3= rz3[0] + 2*rz3[1] + rz3[2]; + + col= ( 4*rz2[1] - (zval1 + zval2 + zval3)/3 ); + if (col<0) col= -col; + + col >>= 5; + if (col > (1<<16)) col= (1<<16); + else col= (R.r.edgeint*col)>>8; + + if (col>0) { + float fcol; + + if (col>255) fcol= 1.0f; + else fcol= (float)col/255.0f; + + if (R.osa) + *rf+= fcol/(float)R.osa; + else + *rf= fcol; + } + } + rz1+= 2; + rz2+= 2; + rz3+= 2; + rf+= 2; + } + + /* shift back zbuf values, we might need it still */ + rz= rectz; + for (y=0; y<pa->recty; y++) + for (x=0; x<pa->rectx; x++, rz++) (*rz)<<= 4; + +} + +static void reset_sky_speed(RenderPart *pa, RenderLayer *rl) +{ + /* for all pixels with max speed, set to zero */ + RenderLayer *rlpp[RE_MAX_OSA]; + float *fp; + int a, sample, totsample; + + totsample= get_sample_layers(pa, rl, rlpp); + + for (sample= 0; sample<totsample; sample++) { + fp= RE_RenderLayerGetPass(rlpp[sample], RE_PASSNAME_VECTOR, R.viewname); + if (fp==NULL) break; + + for (a= 4*pa->rectx*pa->recty - 1; a>=0; a--) + if (fp[a] == PASS_VECTOR_MAX) fp[a]= 0.0f; + } +} + +static unsigned short *make_solid_mask(RenderPart *pa) +{ + intptr_t *rd= pa->rectdaps; + unsigned short *solidmask, *sp; + int x; + + if (rd==NULL) return NULL; + + sp=solidmask= MEM_mallocN(sizeof(short)*pa->rectx*pa->recty, "solidmask"); + + for (x=pa->rectx*pa->recty; x>0; x--, rd++, sp++) { + if (*rd) { + PixStr *ps= (PixStr *)*rd; + + *sp= ps->mask; + for (ps= ps->next; ps; ps= ps->next) + *sp |= ps->mask; + } + else + *sp= 0; + } + + return solidmask; +} + +static void addAlphaOverFloatMask(float *dest, float *source, unsigned short dmask, unsigned short smask) +{ + unsigned short shared= dmask & smask; + float mul= 1.0f - source[3]; + + if (shared) { /* overlapping masks */ + + /* masks differ, we make a mixture of 'add' and 'over' */ + if (shared!=dmask) { + float shared_bits= (float)count_mask(shared); /* alpha over */ + float tot_bits= (float)count_mask(smask|dmask); /* alpha add */ + + float add= (tot_bits - shared_bits)/tot_bits; /* add level */ + mul= add + (1.0f-add)*mul; + } + } + else if (dmask && smask) { + /* works for premul only, of course */ + dest[0]+= source[0]; + dest[1]+= source[1]; + dest[2]+= source[2]; + dest[3]+= source[3]; + + return; + } + + dest[0]= (mul*dest[0]) + source[0]; + dest[1]= (mul*dest[1]) + source[1]; + dest[2]= (mul*dest[2]) + source[2]; + dest[3]= (mul*dest[3]) + source[3]; +} + +typedef struct ZbufSolidData { + RenderLayer *rl; + ListBase *psmlist; + float *edgerect; +} ZbufSolidData; + +static void make_pixelstructs(RenderPart *pa, ZSpan *zspan, int sample, void *data) +{ + ZbufSolidData *sdata = (ZbufSolidData *)data; + ListBase *lb= sdata->psmlist; + intptr_t *rd= pa->rectdaps; + const int *ro= zspan->recto; + const int *rp= zspan->rectp; + const int *rz= zspan->rectz; + const int *rm= zspan->rectmask; + int x, y; + int mask= 1<<sample; + + for (y=0; y<pa->recty; y++) { + for (x=0; x<pa->rectx; x++, rd++, rp++, ro++, rz++, rm++) { + if (*rp) { + addps(lb, rd, *ro, *rp, *rz, (zspan->rectmask)? *rm: 0, mask); + } + } + } + + if (sdata->rl->layflag & SCE_LAY_EDGE) + if (R.r.mode & R_EDGE) + edge_enhance_tile(pa, sdata->edgerect, zspan->rectz); +} + +/* main call for shading Delta Accum, for OSA */ +/* supposed to be fully threadable! */ +void zbufshadeDA_tile(RenderPart *pa) +{ + RenderResult *rr= pa->result; + RenderLayer *rl; + ListBase psmlist= {NULL, NULL}; + float *edgerect= NULL; + + /* allocate the necessary buffers */ + /* zbuffer inits these rects */ + pa->recto= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "recto"); + pa->rectp= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "rectp"); + pa->rectz= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "rectz"); + for (rl= rr->layers.first; rl; rl= rl->next) { + float *rect = RE_RenderLayerGetPass(rl, RE_PASSNAME_COMBINED, R.viewname); + + if ((rl->layflag & SCE_LAY_ZMASK) && (rl->layflag & SCE_LAY_NEG_ZMASK)) + pa->rectmask= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "rectmask"); + + /* initialize pixelstructs and edge buffer */ + addpsmain(&psmlist); + pa->rectdaps= MEM_callocN(sizeof(intptr_t)*pa->rectx*pa->recty+4, "zbufDArectd"); + + if (rl->layflag & SCE_LAY_EDGE) + if (R.r.mode & R_EDGE) + edgerect= MEM_callocN(sizeof(float)*pa->rectx*pa->recty, "rectedge"); + + /* always fill visibility */ + for (pa->sample=0; pa->sample<R.osa; pa->sample+=4) { + ZbufSolidData sdata; + + sdata.rl= rl; + sdata.psmlist= &psmlist; + sdata.edgerect= edgerect; + zbuffer_solid(pa, rl, make_pixelstructs, &sdata); + if (R.test_break(R.tbh)) break; + } + + /* shades solid */ + if (rl->layflag & SCE_LAY_SOLID) + shadeDA_tile(pa, rl); + + /* lamphalo after solid, before ztra, looks nicest because ztra does own halo */ + if (R.flag & R_LAMPHALO) + if (rl->layflag & SCE_LAY_HALO) + lamphalo_tile(pa, rl); + + /* halo before ztra, because ztra fills in zbuffer now */ + if (R.flag & R_HALO) + if (rl->layflag & SCE_LAY_HALO) + halo_tile(pa, rl); + + /* transp layer */ + if (R.flag & R_ZTRA || R.totstrand) { + if (rl->layflag & (SCE_LAY_ZTRA|SCE_LAY_STRAND)) { + if (pa->fullresult.first) { + zbuffer_transp_shade(pa, rl, rect, &psmlist); + } + else { + unsigned short *ztramask, *solidmask= NULL; /* 16 bits, MAX_OSA */ + + /* allocate, but not free here, for asynchronous display of this rect in main thread */ + rl->acolrect= MEM_callocN(4*sizeof(float)*pa->rectx*pa->recty, "alpha layer"); + + /* swap for live updates, and it is used in zbuf.c!!! */ + SWAP(float *, rl->acolrect, rect); + ztramask = zbuffer_transp_shade(pa, rl, rect, &psmlist); + SWAP(float *, rl->acolrect, rect); + + /* zbuffer transp only returns ztramask if there's solid rendered */ + if (ztramask) + solidmask= make_solid_mask(pa); + + if (ztramask && solidmask) { + unsigned short *sps= solidmask, *spz= ztramask; + unsigned short fullmask= (1<<R.osa)-1; + float *fcol= rect; + float *acol= rl->acolrect; + int x; + + for (x=pa->rectx*pa->recty; x>0; x--, acol+=4, fcol+=4, sps++, spz++) { + if (*sps == fullmask) + addAlphaOverFloat(fcol, acol); + else + addAlphaOverFloatMask(fcol, acol, *sps, *spz); + } + } + else { + float *fcol= rect; + float *acol= rl->acolrect; + int x; + for (x=pa->rectx*pa->recty; x>0; x--, acol+=4, fcol+=4) { + addAlphaOverFloat(fcol, acol); + } + } + if (solidmask) MEM_freeN(solidmask); + if (ztramask) MEM_freeN(ztramask); + } + } + } + + /* sun/sky */ + if (rl->layflag & SCE_LAY_SKY) + atm_tile(pa, rl); + + /* sky before edge */ + if (rl->layflag & SCE_LAY_SKY) + sky_tile(pa, rl); + + /* extra layers */ + if (rl->layflag & SCE_LAY_EDGE) + if (R.r.mode & R_EDGE) + edge_enhance_add(pa, rect, edgerect); + + if (rl->passflag & SCE_PASS_VECTOR) + reset_sky_speed(pa, rl); + + /* clamp alpha to 0..1 range, can go outside due to filter */ + clamp_alpha_rgb_range(pa, rl); + + /* free stuff within loop! */ + MEM_freeN(pa->rectdaps); pa->rectdaps= NULL; + freeps(&psmlist); + + if (edgerect) MEM_freeN(edgerect); + edgerect= NULL; + + if (pa->rectmask) { + MEM_freeN(pa->rectmask); + pa->rectmask= NULL; + } + } + + /* free all */ + MEM_freeN(pa->recto); pa->recto= NULL; + MEM_freeN(pa->rectp); pa->rectp= NULL; + MEM_freeN(pa->rectz); pa->rectz= NULL; + + /* display active layer */ + rr->renrect.ymin=rr->renrect.ymax = 0; + rr->renlay= render_get_active_layer(&R, rr); +} + + +/* ------------------------------------------------------------------------ */ + +/* non OSA case, full tile render */ +/* supposed to be fully threadable! */ +void zbufshade_tile(RenderPart *pa) +{ + ShadeSample ssamp; + RenderResult *rr= pa->result; + RenderLayer *rl; + PixStr ps; + float *edgerect= NULL; + + /* fake pixel struct, to comply to osa render */ + ps.next= NULL; + ps.mask= 0xFFFF; + + /* zbuffer code clears/inits rects */ + pa->recto= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "recto"); + pa->rectp= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "rectp"); + pa->rectz= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "rectz"); + + for (rl= rr->layers.first; rl; rl= rl->next) { + float *rect= RE_RenderLayerGetPass(rl, RE_PASSNAME_COMBINED, R.viewname); + if ((rl->layflag & SCE_LAY_ZMASK) && (rl->layflag & SCE_LAY_NEG_ZMASK)) + pa->rectmask= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "rectmask"); + + /* general shader info, passes */ + shade_sample_initialize(&ssamp, pa, rl); + + zbuffer_solid(pa, rl, NULL, NULL); + + if (!R.test_break(R.tbh)) { /* NOTE: this if () is not consistent */ + + /* edges only for solid part, ztransp doesn't support it yet anti-aliased */ + if (rl->layflag & SCE_LAY_EDGE) { + if (R.r.mode & R_EDGE) { + edgerect= MEM_callocN(sizeof(float)*pa->rectx*pa->recty, "rectedge"); + edge_enhance_tile(pa, edgerect, pa->rectz); + } + } + + /* initialize scanline updates for main thread */ + rr->renrect.ymin = 0; + rr->renlay= rl; + + if (rl->layflag & SCE_LAY_SOLID) { + const float *fcol = rect; + const int *ro= pa->recto, *rp= pa->rectp, *rz= pa->rectz; + int x, y, offs=0, seed; + + /* we set per pixel a fixed seed, for random AO and shadow samples */ + seed= pa->rectx*pa->disprect.ymin; + + /* irregular shadowb buffer creation */ + if (R.r.mode & R_SHADOW) + ISB_create(pa, NULL); + + if (R.occlusiontree) + cache_occ_samples(&R, pa, &ssamp); + + for (y=pa->disprect.ymin; y<pa->disprect.ymax; y++, rr->renrect.ymax++) { + for (x=pa->disprect.xmin; x<pa->disprect.xmax; x++, ro++, rz++, rp++, fcol+=4, offs++) { + /* per pixel fixed seed */ + BLI_thread_srandom(pa->thread, seed++); + + if (*rp) { + ps.obi= *ro; + ps.facenr= *rp; + ps.z= *rz; + if (shade_samples(&ssamp, &ps, x, y)) { + /* combined and passes */ + add_passes(rl, offs, ssamp.shi, ssamp.shr); + } + } + } + if (y&1) + if (R.test_break(R.tbh)) break; + } + + if (R.occlusiontree) + free_occ_samples(&R, pa); + + if (R.r.mode & R_SHADOW) + ISB_free(pa); + } + + /* disable scanline updating */ + rr->renlay= NULL; + } + + /* lamphalo after solid, before ztra, looks nicest because ztra does own halo */ + if (R.flag & R_LAMPHALO) + if (rl->layflag & SCE_LAY_HALO) + lamphalo_tile(pa, rl); + + /* halo before ztra, because ztra fills in zbuffer now */ + if (R.flag & R_HALO) + if (rl->layflag & SCE_LAY_HALO) + halo_tile(pa, rl); + + if (R.flag & R_ZTRA || R.totstrand) { + if (rl->layflag & (SCE_LAY_ZTRA|SCE_LAY_STRAND)) { + float *fcol, *acol; + int x; + + /* allocate, but not free here, for asynchronous display of this rect in main thread */ + rl->acolrect= MEM_callocN(4*sizeof(float)*pa->rectx*pa->recty, "alpha layer"); + + /* swap for live updates */ + SWAP(float *, rl->acolrect, rect); + zbuffer_transp_shade(pa, rl, rect, NULL); + SWAP(float *, rl->acolrect, rect); + + fcol= rect; acol= rl->acolrect; + for (x=pa->rectx*pa->recty; x>0; x--, acol+=4, fcol+=4) { + addAlphaOverFloat(fcol, acol); + } + } + } + + /* sun/sky */ + if (rl->layflag & SCE_LAY_SKY) + atm_tile(pa, rl); + + /* sky before edge */ + if (rl->layflag & SCE_LAY_SKY) + sky_tile(pa, rl); + + if (!R.test_break(R.tbh)) { + if (rl->layflag & SCE_LAY_EDGE) + if (R.r.mode & R_EDGE) + edge_enhance_add(pa, rect, edgerect); + } + + if (rl->passflag & SCE_PASS_VECTOR) + reset_sky_speed(pa, rl); + + if (edgerect) MEM_freeN(edgerect); + edgerect= NULL; + + if (pa->rectmask) { + MEM_freeN(pa->rectmask); + pa->rectmask= NULL; + } + } + + /* display active layer */ + rr->renrect.ymin=rr->renrect.ymax = 0; + rr->renlay= render_get_active_layer(&R, rr); + + MEM_freeN(pa->recto); pa->recto= NULL; + MEM_freeN(pa->rectp); pa->rectp= NULL; + MEM_freeN(pa->rectz); pa->rectz= NULL; +} + +/* SSS preprocess tile render, fully threadable */ +typedef struct ZBufSSSHandle { + RenderPart *pa; + ListBase psmlist; + int totps; +} ZBufSSSHandle; + +static void addps_sss(void *cb_handle, int obi, int facenr, int x, int y, int z) +{ + ZBufSSSHandle *handle = cb_handle; + RenderPart *pa= handle->pa; + + /* extra border for filter gives double samples on part edges, + * don't use those */ + if (x<pa->crop || x>=pa->rectx-pa->crop) + return; + if (y<pa->crop || y>=pa->recty-pa->crop) + return; + + if (pa->rectall) { + intptr_t *rs= pa->rectall + pa->rectx*y + x; + + addps(&handle->psmlist, rs, obi, facenr, z, 0, 0); + handle->totps++; + } + if (pa->rectz) { + int *rz= pa->rectz + pa->rectx*y + x; + int *rp= pa->rectp + pa->rectx*y + x; + int *ro= pa->recto + pa->rectx*y + x; + + if (z < *rz) { + if (*rp == 0) + handle->totps++; + *rz= z; + *rp= facenr; + *ro= obi; + } + } + if (pa->rectbackz) { + int *rz= pa->rectbackz + pa->rectx*y + x; + int *rp= pa->rectbackp + pa->rectx*y + x; + int *ro= pa->rectbacko + pa->rectx*y + x; + + if (z >= *rz) { + if (*rp == 0) + handle->totps++; + *rz= z; + *rp= facenr; + *ro= obi; + } + } +} + +static void shade_sample_sss(ShadeSample *ssamp, Material *mat, ObjectInstanceRen *obi, VlakRen *vlr, int quad, float x, float y, float z, float *co, float color[3], float *area) +{ + ShadeInput *shi= ssamp->shi; + ShadeResult shr; + float /* texfac,*/ /* UNUSED */ orthoarea, nor[3], alpha, sx, sy; + + /* cache for shadow */ + shi->samplenr= R.shadowsamplenr[shi->thread]++; + + if (quad) + shade_input_set_triangle_i(shi, obi, vlr, 0, 2, 3); + else + shade_input_set_triangle_i(shi, obi, vlr, 0, 1, 2); + + /* center pixel */ + sx = x + 0.5f; + sy = y + 0.5f; + + /* we estimate the area here using shi->dxco and shi->dyco. we need to + * enabled shi->osatex these are filled. we compute two areas, one with + * the normal pointed at the camera and one with the original normal, and + * then clamp to avoid a too large contribution from a single pixel */ + shi->osatex= 1; + + copy_v3_v3(nor, shi->facenor); + calc_view_vector(shi->facenor, sx, sy); + normalize_v3(shi->facenor); + shade_input_set_viewco(shi, x, y, sx, sy, z); + orthoarea= len_v3(shi->dxco)*len_v3(shi->dyco); + + copy_v3_v3(shi->facenor, nor); + shade_input_set_viewco(shi, x, y, sx, sy, z); + *area = min_ff(len_v3(shi->dxco) * len_v3(shi->dyco), 2.0f * orthoarea); + + shade_input_set_uv(shi); + shade_input_set_normals(shi); + + /* we don't want flipped normals, they screw up back scattering */ + if (shi->flippednor) + shade_input_flip_normals(shi); + + /* not a pretty solution, but fixes common cases */ + if (shi->obr->ob && shi->obr->ob->transflag & OB_NEG_SCALE) { + negate_v3(shi->vn); + negate_v3(shi->vno); + negate_v3(shi->nmapnorm); + } + + /* if nodetree, use the material that we are currently preprocessing + * instead of the node material */ + if (shi->mat->nodetree && shi->mat->use_nodes) + shi->mat= mat; + + /* init material vars */ + shade_input_init_material(shi); + + /* render */ + shade_input_set_shade_texco(shi); + + shade_samples_do_AO(ssamp); + shade_material_loop(shi, &shr); + + copy_v3_v3(co, shi->co); + copy_v3_v3(color, shr.combined); + + /* texture blending */ + /* texfac= shi->mat->sss_texfac; */ /* UNUSED */ + + alpha= shr.combined[3]; + *area *= alpha; +} + +static void zbufshade_sss_free(RenderPart *pa) +{ +#if 0 + MEM_freeN(pa->rectall); pa->rectall= NULL; + freeps(&handle.psmlist); +#else + MEM_freeN(pa->rectz); pa->rectz= NULL; + MEM_freeN(pa->rectp); pa->rectp= NULL; + MEM_freeN(pa->recto); pa->recto= NULL; + MEM_freeN(pa->rectbackz); pa->rectbackz= NULL; + MEM_freeN(pa->rectbackp); pa->rectbackp= NULL; + MEM_freeN(pa->rectbacko); pa->rectbacko= NULL; +#endif +} + +void zbufshade_sss_tile(RenderPart *pa) +{ + Render *re= &R; + ShadeSample ssamp; + ZBufSSSHandle handle; + RenderResult *rr= pa->result; + RenderLayer *rl; + VlakRen *vlr; + Material *mat= re->sss_mat; + float (*co)[3], (*color)[3], *area, *fcol; + int x, y, seed, quad, totpoint; + const bool display = (re->r.scemode & (R_BUTS_PREVIEW | R_VIEWPORT_PREVIEW)) == 0; + int *ro, *rz, *rp, *rbo, *rbz, *rbp, lay; +#if 0 + PixStr *ps; + intptr_t *rs; + int z; +#endif + + /* setup pixelstr list and buffer for zbuffering */ + handle.pa= pa; + handle.totps= 0; + +#if 0 + handle.psmlist.first= handle.psmlist.last= NULL; + addpsmain(&handle.psmlist); + + pa->rectall= MEM_callocN(sizeof(intptr_t)*pa->rectx*pa->recty+4, "rectall"); +#else + pa->recto= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "recto"); + pa->rectp= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "rectp"); + pa->rectz= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "rectz"); + pa->rectbacko= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "rectbacko"); + pa->rectbackp= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "rectbackp"); + pa->rectbackz= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "rectbackz"); +#endif + + /* setup shade sample with correct passes */ + memset(&ssamp, 0, sizeof(ssamp)); + shade_sample_initialize(&ssamp, pa, rr->layers.first); + ssamp.tot= 1; + + for (rl=rr->layers.first; rl; rl=rl->next) { + ssamp.shi[0].lay |= rl->lay; + ssamp.shi[0].layflag |= rl->layflag; + ssamp.shi[0].passflag |= rl->passflag; + ssamp.shi[0].combinedflag |= ~rl->pass_xor; + } + + rl= rr->layers.first; + ssamp.shi[0].passflag |= SCE_PASS_RGBA|SCE_PASS_COMBINED; + ssamp.shi[0].combinedflag &= ~(SCE_PASS_SPEC); + ssamp.shi[0].mat_override= NULL; + ssamp.shi[0].light_override= NULL; + lay= ssamp.shi[0].lay; + + /* create the pixelstrs to be used later */ + zbuffer_sss(pa, lay, &handle, addps_sss); + + if (handle.totps==0) { + zbufshade_sss_free(pa); + return; + } + + fcol= RE_RenderLayerGetPass(rl, RE_PASSNAME_COMBINED, R.viewname); + + co= MEM_mallocN(sizeof(float)*3*handle.totps, "SSSCo"); + color= MEM_mallocN(sizeof(float)*3*handle.totps, "SSSColor"); + area= MEM_mallocN(sizeof(float)*handle.totps, "SSSArea"); + +#if 0 + /* create ISB (does not work currently!) */ + if (re->r.mode & R_SHADOW) + ISB_create(pa, NULL); +#endif + + if (display) { + /* initialize scanline updates for main thread */ + rr->renrect.ymin = 0; + rr->renlay= rl; + } + + seed= pa->rectx*pa->disprect.ymin; +#if 0 + rs= pa->rectall; +#else + rz= pa->rectz; + rp= pa->rectp; + ro= pa->recto; + rbz= pa->rectbackz; + rbp= pa->rectbackp; + rbo= pa->rectbacko; +#endif + totpoint= 0; + + for (y=pa->disprect.ymin; y<pa->disprect.ymax; y++, rr->renrect.ymax++) { + for (x=pa->disprect.xmin; x<pa->disprect.xmax; x++, fcol+=4) { + /* per pixel fixed seed */ + BLI_thread_srandom(pa->thread, seed++); + +#if 0 + if (rs) { + /* for each sample in this pixel, shade it */ + for (ps = (PixStr *)(*rs); ps; ps=ps->next) { + ObjectInstanceRen *obi= &re->objectinstance[ps->obi]; + ObjectRen *obr= obi->obr; + vlr= RE_findOrAddVlak(obr, (ps->facenr-1) & RE_QUAD_MASK); + quad= (ps->facenr & RE_QUAD_OFFS); + z= ps->z; + + shade_sample_sss(&ssamp, mat, obi, vlr, quad, x, y, z, + co[totpoint], color[totpoint], &area[totpoint]); + + totpoint++; + + add_v3_v3(fcol, color); + fcol[3]= 1.0f; + } + + rs++; + } +#else + if (rp) { + if (*rp != 0) { + ObjectInstanceRen *obi= &re->objectinstance[*ro]; + ObjectRen *obr= obi->obr; + + /* shade front */ + vlr= RE_findOrAddVlak(obr, (*rp-1) & RE_QUAD_MASK); + quad= ((*rp) & RE_QUAD_OFFS); + + shade_sample_sss(&ssamp, mat, obi, vlr, quad, x, y, *rz, + co[totpoint], color[totpoint], &area[totpoint]); + + add_v3_v3(fcol, color[totpoint]); + fcol[3]= 1.0f; + totpoint++; + } + + rp++; rz++; ro++; + } + + if (rbp) { + if (*rbp != 0 && !(*rbp == *(rp-1) && *rbo == *(ro-1))) { + ObjectInstanceRen *obi= &re->objectinstance[*rbo]; + ObjectRen *obr= obi->obr; + + /* shade back */ + vlr= RE_findOrAddVlak(obr, (*rbp-1) & RE_QUAD_MASK); + quad= ((*rbp) & RE_QUAD_OFFS); + + shade_sample_sss(&ssamp, mat, obi, vlr, quad, x, y, *rbz, + co[totpoint], color[totpoint], &area[totpoint]); + + /* to indicate this is a back sample */ + area[totpoint]= -area[totpoint]; + + add_v3_v3(fcol, color[totpoint]); + fcol[3]= 1.0f; + totpoint++; + } + + rbz++; rbp++; rbo++; + } +#endif + } + + if (y&1) + if (re->test_break(re->tbh)) break; + } + + /* note: after adding we do not free these arrays, sss keeps them */ + if (totpoint > 0) { + sss_add_points(re, co, color, area, totpoint); + } + else { + MEM_freeN(co); + MEM_freeN(color); + MEM_freeN(area); + } + +#if 0 + if (re->r.mode & R_SHADOW) + ISB_free(pa); +#endif + + if (display) { + /* display active layer */ + rr->renrect.ymin=rr->renrect.ymax = 0; + rr->renlay= render_get_active_layer(&R, rr); + } + + zbufshade_sss_free(pa); +} + +/* ------------------------------------------------------------------------ */ + +static void renderhalo_post(RenderResult *rr, float *rectf, HaloRen *har) /* postprocess version */ +{ + float dist, xsq, ysq, xn, yn, colf[4], *rectft, *rtf; + float haloxs, haloys; + int minx, maxx, miny, maxy, x, y; + + /* calculate the disprect mapped coordinate for halo. note: rectx is disprect corrected */ + haloxs= har->xs - R.disprect.xmin; + haloys= har->ys - R.disprect.ymin; + + har->miny= miny= haloys - har->rad/R.ycor; + har->maxy= maxy= haloys + har->rad/R.ycor; + + if (maxy < 0) { + /* pass */ + } + else if (rr->recty < miny) { + /* pass */ + } + else { + minx = floor(haloxs - har->rad); + maxx = ceil(haloxs + har->rad); + + if (maxx < 0) { + /* pass */ + } + else if (rr->rectx < minx) { + /* pass */ + } + else { + if (minx<0) minx= 0; + if (maxx>=rr->rectx) maxx= rr->rectx-1; + if (miny<0) miny= 0; + if (maxy>rr->recty) maxy= rr->recty; + + rectft= rectf+ 4*rr->rectx*miny; + + for (y=miny; y<maxy; y++) { + + rtf= rectft+4*minx; + + yn= (y - haloys)*R.ycor; + ysq= yn*yn; + + for (x=minx; x<=maxx; x++) { + xn= x - haloxs; + xsq= xn*xn; + dist= xsq+ysq; + if (dist<har->radsq) { + + if (shadeHaloFloat(har, colf, 0x7FFFFF, dist, xn, yn, har->flarec)) + addalphaAddfacFloat(rtf, colf, har->add); + } + rtf+=4; + } + + rectft+= 4*rr->rectx; + + if (R.test_break(R.tbh)) break; + } + } + } +} +/* ------------------------------------------------------------------------ */ + +static void renderflare(RenderResult *rr, float *rectf, HaloRen *har) +{ + extern const float hashvectf[]; + HaloRen fla; + Material *ma; + const float *rc; + float rad, alfa, visifac, vec[3]; + int b, type; + + fla= *har; + fla.linec= fla.ringc= fla.flarec= 0; + + rad= har->rad; + alfa= har->alfa; + + visifac= R.ycor*(har->pixels); + /* all radials added / r^3 == 1.0f! */ + visifac /= (har->rad*har->rad*har->rad); + visifac*= visifac; + + ma= har->mat; + + /* first halo: just do */ + + har->rad= rad*ma->flaresize*visifac; + har->radsq= har->rad*har->rad; + har->zs= fla.zs= 0; + + har->alfa= alfa*visifac; + + renderhalo_post(rr, rectf, har); + + /* next halo's: the flares */ + rc= hashvectf + ma->seed2; + + for (b=1; b<har->flarec; b++) { + + fla.r = fabsf(rc[0]); + fla.g = fabsf(rc[1]); + fla.b = fabsf(rc[2]); + fla.alfa= ma->flareboost*fabsf(alfa*visifac*rc[3]); + fla.hard= 20.0f + fabsf(70.0f*rc[7]); + fla.tex= 0; + + type= (int)(fabsf(3.9f*rc[6])); + + fla.rad = ma->subsize * sqrtf(fabsf(2.0f * har->rad * rc[4])); + + if (type==3) { + fla.rad*= 3.0f; + fla.rad+= R.rectx/10; + } + + fla.radsq= fla.rad*fla.rad; + + vec[0]= 1.4f*rc[5]*(har->xs-R.winx/2); + vec[1]= 1.4f*rc[5]*(har->ys-R.winy/2); + vec[2]= 32.0f*sqrtf(vec[0]*vec[0] + vec[1]*vec[1] + 1.0f); + + fla.xs= R.winx/2 + vec[0] + (1.2f+rc[8])*R.rectx*vec[0]/vec[2]; + fla.ys= R.winy/2 + vec[1] + (1.2f+rc[8])*R.rectx*vec[1]/vec[2]; + + if (R.flag & R_SEC_FIELD) { + if (R.r.mode & R_ODDFIELD) fla.ys += 0.5f; + else fla.ys -= 0.5f; + } + if (type & 1) fla.type= HA_FLARECIRC; + else fla.type= 0; + renderhalo_post(rr, rectf, &fla); + + fla.alfa*= 0.5f; + if (type & 2) fla.type= HA_FLARECIRC; + else fla.type= 0; + renderhalo_post(rr, rectf, &fla); + + rc+= 7; + } +} + +/* needs recode... integrate this better! */ +void add_halo_flare(Render *re) +{ + RenderResult *rr= re->result; + RenderLayer *rl; + HaloRen *har; + int a, mode; + float *rect; + + /* for now, we get the first renderlayer in list with halos set */ + for (rl= rr->layers.first; rl; rl= rl->next) { + bool do_draw = false; + + if ((rl->layflag & SCE_LAY_HALO) == 0) + continue; + + rect = RE_RenderLayerGetPass(rl, RE_PASSNAME_COMBINED, re->viewname); + + if (rect==NULL) + continue; + + mode= R.r.mode; + R.r.mode &= ~R_PANORAMA; + + project_renderdata(&R, projectverto, 0, 0, 0); + + for (a=0; a<R.tothalo; a++) { + har= R.sortedhalos[a]; + + if (har->flarec && (har->lay & rl->lay)) { + do_draw = true; + renderflare(rr, rect, har); + } + } + + if (do_draw) { + /* weak... the display callback wants an active renderlayer pointer... */ + rr->renlay= rl; + re->display_update(re->duh, rr, NULL); + } + + R.r.mode= mode; + } +} + +void render_internal_update_passes(RenderEngine *engine, Scene *scene, SceneRenderLayer *srl) +{ + int type; + + RE_engine_register_pass(engine, scene, srl, RE_PASSNAME_COMBINED, 4, "RGBA", SOCK_RGBA); + +#define CHECK_PASS(name, channels, chanid) \ + if (srl->passflag & (SCE_PASS_ ## name)) { \ + if (channels == 4) type = SOCK_RGBA; \ + else if (channels == 3) type = SOCK_VECTOR; \ + else type = SOCK_FLOAT; \ + RE_engine_register_pass(engine, scene, srl, RE_PASSNAME_ ## name, channels, chanid, type); \ + } + + CHECK_PASS(Z, 1, "Z"); + CHECK_PASS(VECTOR, 4, "XYZW"); + CHECK_PASS(NORMAL, 3, "XYZ"); + CHECK_PASS(UV, 3, "UVA"); + CHECK_PASS(RGBA, 4, "RGBA"); + CHECK_PASS(EMIT, 3, "RGB"); + CHECK_PASS(DIFFUSE, 3, "RGB"); + CHECK_PASS(SPEC, 3, "RGB"); + CHECK_PASS(AO, 3, "RGB"); + CHECK_PASS(ENVIRONMENT, 3, "RGB"); + CHECK_PASS(INDIRECT, 3, "RGB"); + CHECK_PASS(SHADOW, 3, "RGB"); + CHECK_PASS(REFLECT, 3, "RGB"); + CHECK_PASS(REFRACT, 3, "RGB"); + CHECK_PASS(INDEXOB, 1, "X"); + CHECK_PASS(INDEXMA, 1, "X"); + CHECK_PASS(MIST, 1, "Z"); + +#undef CHECK_PASS +} diff --git a/source/blender/render/intern/source/renderdatabase.c b/source/blender/render/intern/source/renderdatabase.c new file mode 100644 index 00000000000..67bfd1bfdc7 --- /dev/null +++ b/source/blender/render/intern/source/renderdatabase.c @@ -0,0 +1,1603 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * Contributor(s): 2004-2006, Blender Foundation, full recode + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/** \file blender/render/intern/source/renderdatabase.c + * \ingroup render + */ + + +/* + * Storage, retrieval and query of render specific data. + * + * All data from a Blender scene is converted by the renderconverter/ + * into a special format that is used by the render module to make + * images out of. These functions interface to the render-specific + * database. + * + * The blo{ha/ve/vl} arrays store pointers to blocks of 256 data + * entries each. + * + * The index of an entry is >>8 (the highest 24 * bits), to find an + * offset in a 256-entry block. + * + * - If the 256-entry block entry has an entry in the + * vertnodes/vlaknodes/bloha array of the current block, the i-th entry in + * that block is allocated to this entry. + * + * - If the entry has no block allocated for it yet, memory is + * allocated. + * + * The pointer to the correct entry is returned. Memory is guaranteed + * to exist (as long as the malloc does not break). Since guarded + * allocation is used, memory _must_ be available. Otherwise, an + * exit(0) would occur. + * + */ + +#include <limits.h> +#include <math.h> +#include <string.h> + +#include "MEM_guardedalloc.h" + + +#include "BLI_math.h" +#include "BLI_blenlib.h" +#include "BLI_utildefines.h" +#include "BLI_hash.h" + +#include "DNA_material_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_texture_types.h" +#include "DNA_listBase.h" +#include "DNA_particle_types.h" + +#include "BKE_customdata.h" +#include "BKE_DerivedMesh.h" + +#include "RE_render_ext.h" /* externtex */ + +#include "rayintersection.h" +#include "rayobject.h" +#include "render_types.h" +#include "renderdatabase.h" +#include "zbuf.h" + +/* ------------------------------------------------------------------------- */ + +/* More dynamic allocation of options for render vertices and faces, so we don't + * have to reserve this space inside vertices. + * Important; vertices and faces, should have been created already (to get tables + * checked) that's a reason why the calls demand VertRen/VlakRen * as arg, not + * the index */ + +/* NOTE! the hardcoded table size 256 is used still in code for going quickly over vertices/faces */ +#define RE_STRESS_ELEMS 1 +#define RE_RAD_ELEMS 4 +#define RE_STRAND_ELEMS 1 +#define RE_TANGENT_ELEMS 3 +#define RE_WINSPEED_ELEMS 4 +#define RE_MTFACE_ELEMS 1 +#define RE_MCOL_ELEMS 4 +#define RE_UV_ELEMS 2 +#define RE_VLAK_ORIGINDEX_ELEMS 1 +#define RE_VERT_ORIGINDEX_ELEMS 1 +#define RE_SURFNOR_ELEMS 3 +#define RE_RADFACE_ELEMS 1 +#define RE_SIMPLIFY_ELEMS 2 +#define RE_FACE_ELEMS 1 +#define RE_NMAP_TANGENT_ELEMS 16 + +float *RE_vertren_get_stress(ObjectRen *obr, VertRen *ver, int verify) +{ + float *stress; + int nr= ver->index>>8; + + stress= obr->vertnodes[nr].stress; + if (stress==NULL) { + if (verify) + stress= obr->vertnodes[nr].stress= MEM_mallocN(256*RE_STRESS_ELEMS*sizeof(float), "stress table"); + else + return NULL; + } + return stress + (ver->index & 255)*RE_STRESS_ELEMS; +} + +/* this one callocs! */ +float *RE_vertren_get_rad(ObjectRen *obr, VertRen *ver, int verify) +{ + float *rad; + int nr= ver->index>>8; + + rad= obr->vertnodes[nr].rad; + if (rad==NULL) { + if (verify) + rad= obr->vertnodes[nr].rad= MEM_callocN(256*RE_RAD_ELEMS*sizeof(float), "rad table"); + else + return NULL; + } + return rad + (ver->index & 255)*RE_RAD_ELEMS; +} + +float *RE_vertren_get_strand(ObjectRen *obr, VertRen *ver, int verify) +{ + float *strand; + int nr= ver->index>>8; + + strand= obr->vertnodes[nr].strand; + if (strand==NULL) { + if (verify) + strand= obr->vertnodes[nr].strand= MEM_mallocN(256*RE_STRAND_ELEMS*sizeof(float), "strand table"); + else + return NULL; + } + return strand + (ver->index & 255)*RE_STRAND_ELEMS; +} + +/* needs calloc */ +float *RE_vertren_get_tangent(ObjectRen *obr, VertRen *ver, int verify) +{ + float *tangent; + int nr= ver->index>>8; + + tangent= obr->vertnodes[nr].tangent; + if (tangent==NULL) { + if (verify) + tangent= obr->vertnodes[nr].tangent= MEM_callocN(256*RE_TANGENT_ELEMS*sizeof(float), "tangent table"); + else + return NULL; + } + return tangent + (ver->index & 255)*RE_TANGENT_ELEMS; +} + +/* needs calloc! not all renderverts have them */ +/* also winspeed is exception, it is stored per instance */ +float *RE_vertren_get_winspeed(ObjectInstanceRen *obi, VertRen *ver, int verify) +{ + float *winspeed; + int totvector; + + winspeed= obi->vectors; + if (winspeed==NULL) { + if (verify) { + totvector= obi->obr->totvert + obi->obr->totstrand; + winspeed= obi->vectors= MEM_callocN(totvector*RE_WINSPEED_ELEMS*sizeof(float), "winspeed table"); + } + else + return NULL; + } + return winspeed + ver->index*RE_WINSPEED_ELEMS; +} + +int *RE_vertren_get_origindex(ObjectRen *obr, VertRen *ver, int verify) +{ + int *origindex; + int nr= ver->index>>8; + + origindex= obr->vertnodes[nr].origindex; + if (origindex==NULL) { + if (verify) + origindex= obr->vertnodes[nr].origindex= MEM_mallocN(256*RE_VERT_ORIGINDEX_ELEMS*sizeof(int), "origindex table"); + else + return NULL; + } + return origindex + (ver->index & 255)*RE_VERT_ORIGINDEX_ELEMS; +} + +VertRen *RE_vertren_copy(ObjectRen *obr, VertRen *ver) +{ + VertRen *v1= RE_findOrAddVert(obr, obr->totvert++); + float *fp1, *fp2; + int *int1, *int2; + int index= v1->index; + + *v1= *ver; + v1->index= index; + + fp1= RE_vertren_get_stress(obr, ver, 0); + if (fp1) { + fp2= RE_vertren_get_stress(obr, v1, 1); + memcpy(fp2, fp1, RE_STRESS_ELEMS*sizeof(float)); + } + fp1= RE_vertren_get_rad(obr, ver, 0); + if (fp1) { + fp2= RE_vertren_get_rad(obr, v1, 1); + memcpy(fp2, fp1, RE_RAD_ELEMS*sizeof(float)); + } + fp1= RE_vertren_get_strand(obr, ver, 0); + if (fp1) { + fp2= RE_vertren_get_strand(obr, v1, 1); + memcpy(fp2, fp1, RE_STRAND_ELEMS*sizeof(float)); + } + fp1= RE_vertren_get_tangent(obr, ver, 0); + if (fp1) { + fp2= RE_vertren_get_tangent(obr, v1, 1); + memcpy(fp2, fp1, RE_TANGENT_ELEMS*sizeof(float)); + } + int1= RE_vertren_get_origindex(obr, ver, 0); + if (int1) { + int2= RE_vertren_get_origindex(obr, v1, 1); + memcpy(int2, int1, RE_VERT_ORIGINDEX_ELEMS*sizeof(int)); + } + return v1; +} + +VertRen *RE_findOrAddVert(ObjectRen *obr, int nr) +{ + VertTableNode *temp; + VertRen *v; + int a; + + if (nr<0) { + printf("error in findOrAddVert: %d\n", nr); + return NULL; + } + a= nr>>8; + + if (a>=obr->vertnodeslen-1) { /* Need to allocate more columns..., and keep last element NULL for free loop */ + temp= obr->vertnodes; + + obr->vertnodes= MEM_mallocN(sizeof(VertTableNode)*(obr->vertnodeslen+TABLEINITSIZE), "vertnodes"); + if (temp) memcpy(obr->vertnodes, temp, obr->vertnodeslen*sizeof(VertTableNode)); + memset(obr->vertnodes+obr->vertnodeslen, 0, TABLEINITSIZE*sizeof(VertTableNode)); + + obr->vertnodeslen+=TABLEINITSIZE; + if (temp) MEM_freeN(temp); + } + + v= obr->vertnodes[a].vert; + if (v==NULL) { + int i; + + v= (VertRen *)MEM_callocN(256*sizeof(VertRen), "findOrAddVert"); + obr->vertnodes[a].vert= v; + + for (i= (nr & 0xFFFFFF00), a=0; a<256; a++, i++) { + v[a].index= i; + } + } + v+= (nr & 255); + return v; +} + +/* ------------------------------------------------------------------------ */ + +MTFace *RE_vlakren_get_tface(ObjectRen *obr, VlakRen *vlr, int n, char **name, int verify) +{ + VlakTableNode *node; + int nr= vlr->index>>8, vlakindex= (vlr->index&255); + int index= (n<<8) + vlakindex; + + node= &obr->vlaknodes[nr]; + + if (verify) { + if (n>=node->totmtface) { + MTFace *mtface= node->mtface; + int size= (n+1)*256; + + node->mtface= MEM_callocN(size*sizeof(MTFace), "Vlak mtface"); + + if (mtface) { + size= node->totmtface*256; + memcpy(node->mtface, mtface, size*sizeof(MTFace)); + MEM_freeN(mtface); + } + + node->totmtface= n+1; + } + } + else { + if (n>=node->totmtface) + return NULL; + + if (name) *name= obr->mtface[n]; + } + + return node->mtface + index; +} + +MCol *RE_vlakren_get_mcol(ObjectRen *obr, VlakRen *vlr, int n, char **name, int verify) +{ + VlakTableNode *node; + int nr= vlr->index>>8, vlakindex= (vlr->index&255); + int index= (n<<8) + vlakindex; + + node= &obr->vlaknodes[nr]; + + if (verify) { + if (n>=node->totmcol) { + MCol *mcol= node->mcol; + int size= (n+1)*256; + + node->mcol= MEM_callocN(size*sizeof(MCol)*RE_MCOL_ELEMS, "Vlak mcol"); + + if (mcol) { + size= node->totmcol*256; + memcpy(node->mcol, mcol, size*sizeof(MCol)*RE_MCOL_ELEMS); + MEM_freeN(mcol); + } + + node->totmcol= n+1; + } + } + else { + if (n>=node->totmcol) + return NULL; + + if (name) *name= obr->mcol[n]; + } + + return node->mcol + index*RE_MCOL_ELEMS; +} + +int *RE_vlakren_get_origindex(ObjectRen *obr, VlakRen *vlak, int verify) +{ + int *origindex; + int nr= vlak->index>>8; + + origindex= obr->vlaknodes[nr].origindex; + if (origindex==NULL) { + if (verify) + origindex= obr->vlaknodes[nr].origindex= MEM_callocN(256*RE_VLAK_ORIGINDEX_ELEMS*sizeof(int), "origindex table"); + else + return NULL; + } + return origindex + (vlak->index & 255)*RE_VLAK_ORIGINDEX_ELEMS; +} + +float *RE_vlakren_get_surfnor(ObjectRen *obr, VlakRen *vlak, int verify) +{ + float *surfnor; + int nr= vlak->index>>8; + + surfnor= obr->vlaknodes[nr].surfnor; + if (surfnor==NULL) { + if (verify) + surfnor= obr->vlaknodes[nr].surfnor= MEM_callocN(256*RE_SURFNOR_ELEMS*sizeof(float), "surfnor table"); + else + return NULL; + } + return surfnor + (vlak->index & 255)*RE_SURFNOR_ELEMS; +} + +float *RE_vlakren_get_nmap_tangent(ObjectRen *obr, VlakRen *vlak, int index, bool verify) +{ + float **tangents; + int nr= vlak->index>>8; + + tangents = obr->vlaknodes[nr].tangent_arrays; + + if (index + 1 > 8) { + return NULL; + } + + index = index < 0 ? 0: index; + + if (tangents[index] == NULL) { + if (verify) { + tangents[index] = MEM_callocN(256*RE_NMAP_TANGENT_ELEMS*sizeof(float), "tangent table"); + } + else + return NULL; + } + + return tangents[index] + (vlak->index & 255)*RE_NMAP_TANGENT_ELEMS; +} + +RadFace **RE_vlakren_get_radface(ObjectRen *obr, VlakRen *vlak, int verify) +{ + RadFace **radface; + int nr= vlak->index>>8; + + radface= obr->vlaknodes[nr].radface; + if (radface==NULL) { + if (verify) + radface = obr->vlaknodes[nr].radface= MEM_callocN(256 * RE_RADFACE_ELEMS * sizeof(void *), "radface table"); + else + return NULL; + } + return radface + (vlak->index & 255)*RE_RADFACE_ELEMS; +} + +VlakRen *RE_vlakren_copy(ObjectRen *obr, VlakRen *vlr) +{ + VlakRen *vlr1 = RE_findOrAddVlak(obr, obr->totvlak++); + MTFace *mtface, *mtface1; + MCol *mcol, *mcol1; + float *surfnor, *surfnor1; + float *tangent, *tangent1; + int *origindex, *origindex1; + RadFace **radface, **radface1; + int i, index = vlr1->index; + char *name; + + *vlr1= *vlr; + vlr1->index= index; + + for (i=0; (mtface=RE_vlakren_get_tface(obr, vlr, i, &name, 0)) != NULL; i++) { + mtface1= RE_vlakren_get_tface(obr, vlr1, i, &name, 1); + memcpy(mtface1, mtface, sizeof(MTFace)*RE_MTFACE_ELEMS); + } + + for (i=0; (mcol=RE_vlakren_get_mcol(obr, vlr, i, &name, 0)) != NULL; i++) { + mcol1= RE_vlakren_get_mcol(obr, vlr1, i, &name, 1); + memcpy(mcol1, mcol, sizeof(MCol)*RE_MCOL_ELEMS); + } + + origindex= RE_vlakren_get_origindex(obr, vlr, 0); + if (origindex) { + origindex1= RE_vlakren_get_origindex(obr, vlr1, 1); + /* Just an int, but memcpy for consistency. */ + memcpy(origindex1, origindex, sizeof(int)*RE_VLAK_ORIGINDEX_ELEMS); + } + + surfnor= RE_vlakren_get_surfnor(obr, vlr, 0); + if (surfnor) { + surfnor1= RE_vlakren_get_surfnor(obr, vlr1, 1); + copy_v3_v3(surfnor1, surfnor); + } + + for (i=0; i < MAX_MTFACE; i++) { + tangent = RE_vlakren_get_nmap_tangent(obr, vlr, i, false); + if (!tangent) + continue; + tangent1 = RE_vlakren_get_nmap_tangent(obr, vlr1, i, true); + memcpy(tangent1, tangent, sizeof(float)*RE_NMAP_TANGENT_ELEMS); + } + + radface= RE_vlakren_get_radface(obr, vlr, 0); + if (radface) { + radface1= RE_vlakren_get_radface(obr, vlr1, 1); + *radface1= *radface; + } + + return vlr1; +} + +void RE_vlakren_get_normal(Render *UNUSED(re), ObjectInstanceRen *obi, VlakRen *vlr, float r_nor[3]) +{ + float (*nmat)[3]= obi->nmat; + + if (obi->flag & R_TRANSFORMED) { + mul_v3_m3v3(r_nor, nmat, vlr->n); + normalize_v3(r_nor); + } + else { + copy_v3_v3(r_nor, vlr->n); + } +} + +void RE_set_customdata_names(ObjectRen *obr, CustomData *data) +{ + /* CustomData layer names are stored per object here, because the + * DerivedMesh which stores the layers is freed */ + + CustomDataLayer *layer; + int numtf = 0, numcol = 0, i, mtfn, mcn; + + if (CustomData_has_layer(data, CD_MTFACE)) { + numtf= CustomData_number_of_layers(data, CD_MTFACE); + obr->mtface= MEM_callocN(sizeof(*obr->mtface)*numtf, "mtfacenames"); + } + + if (CustomData_has_layer(data, CD_MCOL)) { + numcol= CustomData_number_of_layers(data, CD_MCOL); + obr->mcol= MEM_callocN(sizeof(*obr->mcol)*numcol, "mcolnames"); + } + + for (i=0, mtfn=0, mcn=0; i < data->totlayer; i++) { + layer= &data->layers[i]; + + if (layer->type == CD_MTFACE) { + BLI_strncpy(obr->mtface[mtfn++], layer->name, sizeof(layer->name)); + obr->actmtface= CLAMPIS(layer->active_rnd, 0, numtf); + obr->bakemtface= layer->active; + } + else if (layer->type == CD_MCOL) { + BLI_strncpy(obr->mcol[mcn++], layer->name, sizeof(layer->name)); + obr->actmcol= CLAMPIS(layer->active_rnd, 0, numcol); + } + } +} + +VlakRen *RE_findOrAddVlak(ObjectRen *obr, int nr) +{ + VlakTableNode *temp; + VlakRen *v; + int a; + + if (nr<0) { + printf("error in findOrAddVlak: %d\n", nr); + return obr->vlaknodes[0].vlak; + } + a= nr>>8; + + if (a>=obr->vlaknodeslen-1) { /* Need to allocate more columns..., and keep last element NULL for free loop */ + temp= obr->vlaknodes; + + obr->vlaknodes= MEM_mallocN(sizeof(VlakTableNode)*(obr->vlaknodeslen+TABLEINITSIZE), "vlaknodes"); + if (temp) memcpy(obr->vlaknodes, temp, obr->vlaknodeslen*sizeof(VlakTableNode)); + memset(obr->vlaknodes+obr->vlaknodeslen, 0, TABLEINITSIZE*sizeof(VlakTableNode)); + + obr->vlaknodeslen+=TABLEINITSIZE; /*Does this really need to be power of 2?*/ + if (temp) MEM_freeN(temp); + } + + v= obr->vlaknodes[a].vlak; + + if (v==NULL) { + int i; + + v= (VlakRen *)MEM_callocN(256*sizeof(VlakRen), "findOrAddVlak"); + obr->vlaknodes[a].vlak= v; + + for (i= (nr & 0xFFFFFF00), a=0; a<256; a++, i++) + v[a].index= i; + } + v+= (nr & 255); + return v; +} + +/* ------------------------------------------------------------------------ */ + +float *RE_strandren_get_surfnor(ObjectRen *obr, StrandRen *strand, int verify) +{ + float *surfnor; + int nr= strand->index>>8; + + surfnor= obr->strandnodes[nr].surfnor; + if (surfnor==NULL) { + if (verify) + surfnor= obr->strandnodes[nr].surfnor= MEM_callocN(256*RE_SURFNOR_ELEMS*sizeof(float), "surfnor strand table"); + else + return NULL; + } + return surfnor + (strand->index & 255)*RE_SURFNOR_ELEMS; +} + +float *RE_strandren_get_uv(ObjectRen *obr, StrandRen *strand, int n, char **name, int verify) +{ + StrandTableNode *node; + int nr= strand->index>>8, strandindex= (strand->index&255); + int index= (n<<8) + strandindex; + + node= &obr->strandnodes[nr]; + + if (verify) { + if (n>=node->totuv) { + float *uv= node->uv; + int size= (n+1)*256; + + node->uv= MEM_callocN(size*sizeof(float)*RE_UV_ELEMS, "strand uv table"); + + if (uv) { + size= node->totuv*256; + memcpy(node->uv, uv, size*sizeof(float)*RE_UV_ELEMS); + MEM_freeN(uv); + } + + node->totuv= n+1; + } + } + else { + if (n>=node->totuv) + return NULL; + + if (name) *name= obr->mtface[n]; + } + + return node->uv + index*RE_UV_ELEMS; +} + +MCol *RE_strandren_get_mcol(ObjectRen *obr, StrandRen *strand, int n, char **name, int verify) +{ + StrandTableNode *node; + int nr= strand->index>>8, strandindex= (strand->index&255); + int index= (n<<8) + strandindex; + + node= &obr->strandnodes[nr]; + + if (verify) { + if (n>=node->totmcol) { + MCol *mcol= node->mcol; + int size= (n+1)*256; + + node->mcol= MEM_callocN(size*sizeof(MCol)*RE_MCOL_ELEMS, "strand mcol table"); + + if (mcol) { + size= node->totmcol*256; + memcpy(node->mcol, mcol, size*sizeof(MCol)*RE_MCOL_ELEMS); + MEM_freeN(mcol); + } + + node->totmcol= n+1; + } + } + else { + if (n>=node->totmcol) + return NULL; + + if (name) *name= obr->mcol[n]; + } + + return node->mcol + index*RE_MCOL_ELEMS; +} + +float *RE_strandren_get_simplify(struct ObjectRen *obr, struct StrandRen *strand, int verify) +{ + float *simplify; + int nr= strand->index>>8; + + simplify= obr->strandnodes[nr].simplify; + if (simplify==NULL) { + if (verify) + simplify= obr->strandnodes[nr].simplify= MEM_callocN(256*RE_SIMPLIFY_ELEMS*sizeof(float), "simplify strand table"); + else + return NULL; + } + return simplify + (strand->index & 255)*RE_SIMPLIFY_ELEMS; +} + +int *RE_strandren_get_face(ObjectRen *obr, StrandRen *strand, int verify) +{ + int *face; + int nr= strand->index>>8; + + face= obr->strandnodes[nr].face; + if (face==NULL) { + if (verify) + face= obr->strandnodes[nr].face= MEM_callocN(256*RE_FACE_ELEMS*sizeof(int), "face strand table"); + else + return NULL; + } + return face + (strand->index & 255)*RE_FACE_ELEMS; +} + +/* winspeed is exception, it is stored per instance */ +float *RE_strandren_get_winspeed(ObjectInstanceRen *obi, StrandRen *strand, int verify) +{ + float *winspeed; + int totvector; + + winspeed= obi->vectors; + if (winspeed==NULL) { + if (verify) { + totvector= obi->obr->totvert + obi->obr->totstrand; + winspeed= obi->vectors= MEM_callocN(totvector*RE_WINSPEED_ELEMS*sizeof(float), "winspeed strand table"); + } + else + return NULL; + } + return winspeed + (obi->obr->totvert + strand->index)*RE_WINSPEED_ELEMS; +} + +StrandRen *RE_findOrAddStrand(ObjectRen *obr, int nr) +{ + StrandTableNode *temp; + StrandRen *v; + int a; + + if (nr<0) { + printf("error in findOrAddStrand: %d\n", nr); + return obr->strandnodes[0].strand; + } + a= nr>>8; + + if (a>=obr->strandnodeslen-1) { /* Need to allocate more columns..., and keep last element NULL for free loop */ + temp= obr->strandnodes; + + obr->strandnodes= MEM_mallocN(sizeof(StrandTableNode)*(obr->strandnodeslen+TABLEINITSIZE), "strandnodes"); + if (temp) memcpy(obr->strandnodes, temp, obr->strandnodeslen*sizeof(StrandTableNode)); + memset(obr->strandnodes+obr->strandnodeslen, 0, TABLEINITSIZE*sizeof(StrandTableNode)); + + obr->strandnodeslen+=TABLEINITSIZE; /*Does this really need to be power of 2?*/ + if (temp) MEM_freeN(temp); + } + + v= obr->strandnodes[a].strand; + + if (v==NULL) { + int i; + + v= (StrandRen *)MEM_callocN(256*sizeof(StrandRen), "findOrAddStrand"); + obr->strandnodes[a].strand= v; + + for (i= (nr & 0xFFFFFF00), a=0; a<256; a++, i++) + v[a].index= i; + } + v+= (nr & 255); + return v; +} + +StrandBuffer *RE_addStrandBuffer(ObjectRen *obr, int totvert) +{ + StrandBuffer *strandbuf; + + strandbuf= MEM_callocN(sizeof(StrandBuffer), "StrandBuffer"); + strandbuf->vert= MEM_callocN(sizeof(StrandVert)*totvert, "StrandVert"); + strandbuf->totvert= totvert; + strandbuf->obr= obr; + + obr->strandbuf= strandbuf; + + return strandbuf; +} + +/* ------------------------------------------------------------------------ */ + +ObjectRen *RE_addRenderObject(Render *re, Object *ob, Object *par, int index, int psysindex, int lay) +{ + ObjectRen *obr= MEM_callocN(sizeof(ObjectRen), "object render struct"); + + BLI_addtail(&re->objecttable, obr); + obr->ob= ob; + obr->par= par; + obr->index= index; + obr->psysindex= psysindex; + obr->lay= lay; + + return obr; +} + +void free_renderdata_vertnodes(VertTableNode *vertnodes) +{ + int a; + + if (vertnodes==NULL) return; + + for (a=0; vertnodes[a].vert; a++) { + MEM_freeN(vertnodes[a].vert); + + if (vertnodes[a].rad) + MEM_freeN(vertnodes[a].rad); + if (vertnodes[a].strand) + MEM_freeN(vertnodes[a].strand); + if (vertnodes[a].tangent) + MEM_freeN(vertnodes[a].tangent); + if (vertnodes[a].stress) + MEM_freeN(vertnodes[a].stress); + if (vertnodes[a].winspeed) + MEM_freeN(vertnodes[a].winspeed); + if (vertnodes[a].origindex) + MEM_freeN(vertnodes[a].origindex); + } + + MEM_freeN(vertnodes); +} + +void free_renderdata_vlaknodes(VlakTableNode *vlaknodes) +{ + int a; + + if (vlaknodes==NULL) return; + + for (a=0; vlaknodes[a].vlak; a++) { + MEM_freeN(vlaknodes[a].vlak); + + if (vlaknodes[a].mtface) + MEM_freeN(vlaknodes[a].mtface); + if (vlaknodes[a].mcol) + MEM_freeN(vlaknodes[a].mcol); + if (vlaknodes[a].origindex) + MEM_freeN(vlaknodes[a].origindex); + if (vlaknodes[a].surfnor) + MEM_freeN(vlaknodes[a].surfnor); + for (int b = 0; b < MAX_MTFACE; b++) { + if (vlaknodes[a].tangent_arrays[b]) + MEM_freeN(vlaknodes[a].tangent_arrays[b]); + } + if (vlaknodes[a].radface) + MEM_freeN(vlaknodes[a].radface); + } + + MEM_freeN(vlaknodes); +} + +static void free_renderdata_strandnodes(StrandTableNode *strandnodes) +{ + int a; + + if (strandnodes==NULL) return; + + for (a=0; strandnodes[a].strand; a++) { + MEM_freeN(strandnodes[a].strand); + + if (strandnodes[a].uv) + MEM_freeN(strandnodes[a].uv); + if (strandnodes[a].mcol) + MEM_freeN(strandnodes[a].mcol); + if (strandnodes[a].winspeed) + MEM_freeN(strandnodes[a].winspeed); + if (strandnodes[a].surfnor) + MEM_freeN(strandnodes[a].surfnor); + if (strandnodes[a].simplify) + MEM_freeN(strandnodes[a].simplify); + if (strandnodes[a].face) + MEM_freeN(strandnodes[a].face); + } + + MEM_freeN(strandnodes); +} + +void free_renderdata_tables(Render *re) +{ + ObjectInstanceRen *obi; + ObjectRen *obr; + StrandBuffer *strandbuf; + int a=0; + + for (obr=re->objecttable.first; obr; obr=obr->next) { + if (obr->vertnodes) { + free_renderdata_vertnodes(obr->vertnodes); + obr->vertnodes= NULL; + obr->vertnodeslen= 0; + } + + if (obr->vlaknodes) { + free_renderdata_vlaknodes(obr->vlaknodes); + obr->vlaknodes= NULL; + obr->vlaknodeslen= 0; + obr->totvlak= 0; + } + + if (obr->bloha) { + for (a=0; obr->bloha[a]; a++) + MEM_freeN(obr->bloha[a]); + + MEM_freeN(obr->bloha); + obr->bloha= NULL; + obr->blohalen= 0; + } + + if (obr->strandnodes) { + free_renderdata_strandnodes(obr->strandnodes); + obr->strandnodes= NULL; + obr->strandnodeslen= 0; + } + + strandbuf= obr->strandbuf; + if (strandbuf) { + if (strandbuf->vert) MEM_freeN(strandbuf->vert); + if (strandbuf->bound) MEM_freeN(strandbuf->bound); + MEM_freeN(strandbuf); + } + + if (obr->mtface) + MEM_freeN(obr->mtface); + + if (obr->mcol) + MEM_freeN(obr->mcol); + + if (obr->rayfaces) { + MEM_freeN(obr->rayfaces); + obr->rayfaces = NULL; + } + + if (obr->rayprimitives) { + MEM_freeN(obr->rayprimitives); + obr->rayprimitives = NULL; + } + + if (obr->raytree) { + RE_rayobject_free(obr->raytree); + obr->raytree = NULL; + } + } + + if (re->objectinstance) { + for (obi=re->instancetable.first; obi; obi=obi->next) { + if (obi->vectors) + MEM_freeN(obi->vectors); + + if (obi->raytree) + RE_rayobject_free(obi->raytree); + } + + MEM_freeN(re->objectinstance); + re->objectinstance= NULL; + re->totinstance= 0; + re->instancetable.first= re->instancetable.last= NULL; + } + + if (re->sortedhalos) { + MEM_freeN(re->sortedhalos); + re->sortedhalos= NULL; + } + + BLI_freelistN(&re->customdata_names); + BLI_freelistN(&re->objecttable); + BLI_freelistN(&re->instancetable); +} + +/* ------------------------------------------------------------------------ */ + +HaloRen *RE_findOrAddHalo(ObjectRen *obr, int nr) +{ + HaloRen *h, **temp; + int a; + + if (nr<0) { + printf("error in findOrAddHalo: %d\n", nr); + return NULL; + } + a= nr>>8; + + if (a>=obr->blohalen-1) { /* Need to allocate more columns..., and keep last element NULL for free loop */ + //printf("Allocating %i more halo groups. %i total.\n", + // TABLEINITSIZE, obr->blohalen+TABLEINITSIZE ); + temp=obr->bloha; + + obr->bloha = (HaloRen **)MEM_callocN(sizeof(void *) * (obr->blohalen + TABLEINITSIZE), "Bloha"); + if (temp) memcpy(obr->bloha, temp, obr->blohalen*sizeof(void *)); + memset(&(obr->bloha[obr->blohalen]), 0, TABLEINITSIZE * sizeof(void *)); + obr->blohalen+=TABLEINITSIZE; /*Does this really need to be power of 2?*/ + if (temp) MEM_freeN(temp); + } + + h= obr->bloha[a]; + if (h==NULL) { + h= (HaloRen *)MEM_callocN(256*sizeof(HaloRen), "findOrAdHalo"); + obr->bloha[a]= h; + } + h+= (nr & 255); + return h; +} + +/* ------------------------------------------------------------------------- */ + +HaloRen *RE_inithalo(Render *re, ObjectRen *obr, Material *ma, + const float vec[3], const float vec1[3], + const float *orco, float hasize, float vectsize, int seed) +{ + const bool skip_load_image = (re->r.scemode & R_NO_IMAGE_LOAD) != 0; + const bool texnode_preview = (re->r.scemode & R_TEXNODE_PREVIEW) != 0; + HaloRen *har; + MTex *mtex; + float tin, tr, tg, tb, ta; + float xn, yn, zn, texvec[3], hoco[4], hoco1[4]; + + if (hasize==0.0f) return NULL; + + projectverto(vec, re->winmat, hoco); + if (hoco[3]==0.0f) return NULL; + if (vec1) { + projectverto(vec1, re->winmat, hoco1); + if (hoco1[3]==0.0f) return NULL; + } + + har= RE_findOrAddHalo(obr, obr->tothalo++); + copy_v3_v3(har->co, vec); + har->hasize= hasize; + + /* actual projectvert is done in function project_renderdata() because of parts/border/pano */ + /* we do it here for sorting of halos */ + zn= hoco[3]; + har->xs= 0.5f*re->winx*(hoco[0]/zn); + har->ys= 0.5f*re->winy*(hoco[1]/zn); + har->zs= 0x7FFFFF*(hoco[2]/zn); + + har->zBufDist = 0x7FFFFFFF*(hoco[2]/zn); + + /* halovect */ + if (vec1) { + + har->type |= HA_VECT; + + xn= har->xs - 0.5f*re->winx*(hoco1[0]/hoco1[3]); + yn= har->ys - 0.5f*re->winy*(hoco1[1]/hoco1[3]); + if (yn == 0.0f && xn >= 0.0f) zn = 0.0f; + else zn = atan2f(yn, xn); + + har->sin = sinf(zn); + har->cos = cosf(zn); + zn= len_v3v3(vec1, vec); + + har->hasize= vectsize*zn + (1.0f-vectsize)*hasize; + + sub_v3_v3v3(har->no, vec, vec1); + normalize_v3(har->no); + } + + if (ma->mode & MA_HALO_XALPHA) har->type |= HA_XALPHA; + + har->alfa= ma->alpha; + har->r= ma->r; + har->g= ma->g; + har->b= ma->b; + har->add= (255.0f*ma->add); + har->mat= ma; + har->hard= ma->har; + har->seed= seed % 256; + + if (ma->mode & MA_STAR) har->starpoints= ma->starc; + if (ma->mode & MA_HALO_LINES) har->linec= ma->linec; + if (ma->mode & MA_HALO_RINGS) har->ringc= ma->ringc; + if (ma->mode & MA_HALO_FLARE) har->flarec= ma->flarec; + + + if (ma->mtex[0]) { + + if (ma->mode & MA_HALOTEX) { + har->tex = 1; + } + else if (har->mat->septex & (1 << 0)) { + /* only 1 level textures */ + } + else { + mtex= ma->mtex[0]; + copy_v3_v3(texvec, vec); + + if (mtex->texco & TEXCO_NORM) { + ; + } + else if (mtex->texco & TEXCO_OBJECT) { + /* texvec[0]+= imatbase->ivec[0]; */ + /* texvec[1]+= imatbase->ivec[1]; */ + /* texvec[2]+= imatbase->ivec[2]; */ + /* mul_m3_v3(imatbase->imat, texvec); */ + } + else { + if (orco) { + copy_v3_v3(texvec, orco); + } + } + + externtex(mtex, + texvec, + &tin, &tr, &tg, &tb, &ta, + 0, + re->pool, + skip_load_image, + texnode_preview); + + yn= tin*mtex->colfac; + //zn= tin*mtex->alphafac; + + if (mtex->mapto & MAP_COL) { + zn= 1.0f-yn; + har->r= (yn*tr+ zn*ma->r); + har->g= (yn*tg+ zn*ma->g); + har->b= (yn*tb+ zn*ma->b); + } + if (mtex->texco & TEXCO_UV) { + har->alfa= tin; + } + if (mtex->mapto & MAP_ALPHA) + har->alfa= tin; + } + } + + har->pool = re->pool; + har->skip_load_image = skip_load_image; + har->texnode_preview = texnode_preview; + + return har; +} + +HaloRen *RE_inithalo_particle(Render *re, ObjectRen *obr, DerivedMesh *dm, Material *ma, + const float vec[3], const float vec1[3], + const float *orco, const float *uvco, float hasize, float vectsize, int seed, const float pa_co[3]) +{ + const bool skip_load_image = (re->r.scemode & R_NO_IMAGE_LOAD) != 0; + const bool texnode_preview = (re->r.scemode & R_TEXNODE_PREVIEW) != 0; + HaloRen *har; + MTex *mtex; + float tin, tr, tg, tb, ta; + float xn, yn, zn, texvec[3], hoco[4], hoco1[4], in[3], tex[3], out[3]; + int i, hasrgb; + + if (hasize==0.0f) return NULL; + + projectverto(vec, re->winmat, hoco); + if (hoco[3]==0.0f) return NULL; + if (vec1) { + projectverto(vec1, re->winmat, hoco1); + if (hoco1[3]==0.0f) return NULL; + } + + har= RE_findOrAddHalo(obr, obr->tothalo++); + copy_v3_v3(har->co, vec); + har->hasize= hasize; + + /* actual projectvert is done in function project_renderdata() because of parts/border/pano */ + /* we do it here for sorting of halos */ + zn= hoco[3]; + har->xs= 0.5f*re->winx*(hoco[0]/zn); + har->ys= 0.5f*re->winy*(hoco[1]/zn); + har->zs= 0x7FFFFF*(hoco[2]/zn); + + har->zBufDist = 0x7FFFFFFF*(hoco[2]/zn); + + /* halovect */ + if (vec1) { + + har->type |= HA_VECT; + + xn= har->xs - 0.5f*re->winx*(hoco1[0]/hoco1[3]); + yn= har->ys - 0.5f*re->winy*(hoco1[1]/hoco1[3]); + if (yn == 0.0f && xn >= 0.0f) zn = 0.0f; + else zn = atan2f(yn, xn); + + har->sin = sinf(zn); + har->cos = cosf(zn); + zn= len_v3v3(vec1, vec)*0.5f; + + har->hasize= vectsize*zn + (1.0f-vectsize)*hasize; + + sub_v3_v3v3(har->no, vec, vec1); + normalize_v3(har->no); + } + + if (ma->mode & MA_HALO_XALPHA) har->type |= HA_XALPHA; + + har->alfa= ma->alpha; + har->r= ma->r; + har->g= ma->g; + har->b= ma->b; + har->add= (255.0f*ma->add); + har->mat= ma; + har->hard= ma->har; + har->seed= seed % 256; + + if (ma->mode & MA_STAR) har->starpoints= ma->starc; + if (ma->mode & MA_HALO_LINES) har->linec= ma->linec; + if (ma->mode & MA_HALO_RINGS) har->ringc= ma->ringc; + if (ma->mode & MA_HALO_FLARE) har->flarec= ma->flarec; + + if ((ma->mode & MA_HALOTEX) && ma->mtex[0]) + har->tex= 1; + + for (i=0; i<MAX_MTEX; i++) + if (ma->mtex[i] && (ma->septex & (1<<i))==0) { + mtex= ma->mtex[i]; + copy_v3_v3(texvec, vec); + + if (mtex->texco & TEXCO_NORM) { + ; + } + else if (mtex->texco & TEXCO_OBJECT) { + if (mtex->object) + mul_m4_v3(mtex->object->imat_ren, texvec); + } + else if (mtex->texco & TEXCO_GLOB) { + copy_v3_v3(texvec, vec); + } + else if (mtex->texco & TEXCO_UV && uvco) { + int uv_index=CustomData_get_named_layer_index(&dm->faceData, CD_MTFACE, mtex->uvname); + if (uv_index<0) + uv_index=CustomData_get_active_layer_index(&dm->faceData, CD_MTFACE); + + uv_index-=CustomData_get_layer_index(&dm->faceData, CD_MTFACE); + + texvec[0]=2.0f*uvco[2*uv_index]-1.0f; + texvec[1]=2.0f*uvco[2*uv_index+1]-1.0f; + texvec[2]=0.0f; + } + else if (mtex->texco & TEXCO_PARTICLE) { + /* particle coordinates in range [0, 1] */ + texvec[0] = 2.f * pa_co[0] - 1.f; + texvec[1] = 2.f * pa_co[1] - 1.f; + texvec[2] = pa_co[2]; + } + else if (orco) { + copy_v3_v3(texvec, orco); + } + + hasrgb = externtex(mtex, + texvec, + &tin, &tr, &tg, &tb, &ta, + 0, + re->pool, + skip_load_image, + texnode_preview); + + //yn= tin*mtex->colfac; + //zn= tin*mtex->alphafac; + if (mtex->mapto & MAP_COL) { + tex[0]=tr; + tex[1]=tg; + tex[2]=tb; + out[0]=har->r; + out[1]=har->g; + out[2]=har->b; + + texture_rgb_blend(in, tex, out, tin, mtex->colfac, mtex->blendtype); + // zn= 1.0-yn; + //har->r= (yn*tr+ zn*ma->r); + //har->g= (yn*tg+ zn*ma->g); + //har->b= (yn*tb+ zn*ma->b); + har->r= in[0]; + har->g= in[1]; + har->b= in[2]; + } + + /* alpha returned, so let's use it instead of intensity */ + if (hasrgb) + tin = ta; + + if (mtex->mapto & MAP_ALPHA) + har->alfa = texture_value_blend(mtex->def_var, har->alfa, tin, mtex->alphafac, mtex->blendtype); + if (mtex->mapto & MAP_HAR) + har->hard = 1.0f+126.0f*texture_value_blend(mtex->def_var, ((float)har->hard)/127.0f, tin, mtex->hardfac, mtex->blendtype); + if (mtex->mapto & MAP_RAYMIRR) + har->hasize = 100.0f*texture_value_blend(mtex->def_var, har->hasize/100.0f, tin, mtex->raymirrfac, mtex->blendtype); + if (mtex->mapto & MAP_TRANSLU) { + float add = texture_value_blend(mtex->def_var, (float)har->add/255.0f, tin, mtex->translfac, mtex->blendtype); + CLAMP(add, 0.f, 1.f); + har->add = 255.0f*add; + } + /* now what on earth is this good for?? */ + //if (mtex->texco & 16) { + // har->alfa= tin; + //} + } + + har->pool = re->pool; + har->skip_load_image = (re->r.scemode & R_NO_IMAGE_LOAD) != 0; + har->texnode_preview = (re->r.scemode & R_TEXNODE_PREVIEW) != 0; + + return har; +} + +/* -------------------------- operations on entire database ----------------------- */ + +/* ugly function for halos in panorama */ +static int panotestclip(Render *re, bool do_pano, float v[4]) +{ + /* part size (ensure we run RE_parts_clamp first) */ + BLI_assert(re->partx == min_ii(re->r.tilex, re->rectx)); + BLI_assert(re->party == min_ii(re->r.tiley, re->recty)); + + if (do_pano == false) { + return testclip(v); + } + else { + /* to be used for halos en infos */ + float abs4; + short c = 0; + + int xparts = (re->rectx + re->partx - 1) / re->partx; + + abs4= fabsf(v[3]); + + if (v[2]< -abs4) c=16; /* this used to be " if (v[2]<0) ", see clippz() */ + else if (v[2]> abs4) c+= 32; + + if ( v[1]>abs4) c+=4; + else if ( v[1]< -abs4) c+=8; + + abs4*= xparts; + if ( v[0]>abs4) c+=2; + else if ( v[0]< -abs4) c+=1; + + return c; + } +} + +/** + * This adds the hcs coordinates to vertices. It iterates over all + * vertices, halos and faces. After the conversion, we clip in hcs. + * + * Elsewhere, all primites are converted to vertices. + * Called in + * - envmapping (envmap.c) + * - shadow buffering (shadbuf.c) + */ + +void project_renderdata(Render *re, + void (*projectfunc)(const float *, float mat[4][4], float *), + bool do_pano, float xoffs, bool UNUSED(do_buckets)) +{ + ObjectRen *obr; + HaloRen *har = NULL; + float zn, vec[3], hoco[4]; + int a; + + if (do_pano) { + float panophi= xoffs; + + re->panosi = sinf(panophi); + re->panoco = cosf(panophi); + } + + for (obr=re->objecttable.first; obr; obr=obr->next) { + /* calculate view coordinates (and zbuffer value) */ + for (a=0; a<obr->tothalo; a++) { + if ((a & 255)==0) har= obr->bloha[a>>8]; + else har++; + + if (do_pano) { + vec[0]= re->panoco*har->co[0] + re->panosi*har->co[2]; + vec[1]= har->co[1]; + vec[2]= -re->panosi*har->co[0] + re->panoco*har->co[2]; + } + else { + copy_v3_v3(vec, har->co); + } + + projectfunc(vec, re->winmat, hoco); + + /* we clip halos less critical, but not for the Z */ + hoco[0]*= 0.5f; + hoco[1]*= 0.5f; + + if ( panotestclip(re, do_pano, hoco) ) { + har->miny= har->maxy= -10000; /* that way render clips it */ + } + else if (hoco[3]<0.0f) { + har->miny= har->maxy= -10000; /* render clips it */ + } + else { /* do the projection...*/ + /* bring back hocos */ + hoco[0]*= 2.0f; + hoco[1]*= 2.0f; + + zn= hoco[3]; + har->xs= 0.5f*re->winx*(1.0f+hoco[0]/zn); /* the 0.5 negates the previous 2...*/ + har->ys= 0.5f*re->winy*(1.0f+hoco[1]/zn); + + /* this should be the zbuffer coordinate */ + har->zs= 0x7FFFFF*(hoco[2]/zn); + /* taking this from the face clip functions? seems ok... */ + har->zBufDist = 0x7FFFFFFF*(hoco[2]/zn); + + vec[0]+= har->hasize; + projectfunc(vec, re->winmat, hoco); + vec[0]-= har->hasize; + zn= hoco[3]; + har->rad= fabsf(har->xs- 0.5f*re->winx*(1.0f+hoco[0]/zn)); + + /* this clip is not really OK, to prevent stars to become too large */ + if (har->type & HA_ONLYSKY) { + if (har->rad>3.0f) har->rad= 3.0f; + } + + har->radsq= har->rad*har->rad; + + har->miny= har->ys - har->rad/re->ycor; + har->maxy= har->ys + har->rad/re->ycor; + + /* the Zd value is still not really correct for pano */ + + vec[2] -= har->hasize; /* z negative, otherwise it's clipped */ + projectfunc(vec, re->winmat, hoco); + zn = hoco[3]; + zn = fabsf((float)har->zs - 0x7FFFFF * (hoco[2] / zn)); + har->zd = CLAMPIS(zn, 0, INT_MAX); + + } + + } + } +} + +/* ------------------------------------------------------------------------- */ + +void RE_updateRenderInstance(Render *re, ObjectInstanceRen *obi, int flag) +{ + /* flag specifies what things have changed. */ + if (flag & RE_OBJECT_INSTANCES_UPDATE_OBMAT) { + copy_m4_m4(obi->obmat, obi->ob->obmat); + invert_m4_m4(obi->obinvmat, obi->obmat); + } + if (flag & RE_OBJECT_INSTANCES_UPDATE_VIEW) { + mul_m4_m4m4(obi->localtoviewmat, re->viewmat, obi->obmat); + mul_m4_m4m4(obi->localtoviewinvmat, obi->obinvmat, re->viewinv); + } +} + +void RE_updateRenderInstances(Render *re, int flag) +{ + int i = 0; + for (i = 0; i < re->totinstance; i++) + RE_updateRenderInstance(re, &re->objectinstance[i], flag); +} + +ObjectInstanceRen *RE_addRenderInstance( + Render *re, ObjectRen *obr, Object *ob, Object *par, + int index, int psysindex, float mat[4][4], int lay, const DupliObject *dob) +{ + ObjectInstanceRen *obi; + float mat3[3][3]; + + obi= MEM_callocN(sizeof(ObjectInstanceRen), "ObjectInstanceRen"); + obi->obr= obr; + obi->ob= ob; + obi->par= par; + obi->index= index; + obi->psysindex= psysindex; + obi->lay= lay; + + /* Fill particle info */ + if (par && dob) { + const ParticleSystem *psys = dob->particle_system; + if (psys) { + int part_index; + if (obi->index < psys->totpart) { + part_index = obi->index; + } + else if (psys->child) { + part_index = psys->child[obi->index - psys->totpart].parent; + } + else { + part_index = -1; + } + + if (part_index >= 0) { + const ParticleData *p = &psys->particles[part_index]; + obi->part_index = part_index; + obi->part_size = p->size; + obi->part_age = RE_GetStats(re)->cfra - p->time; + obi->part_lifetime = p->lifetime; + + copy_v3_v3(obi->part_co, p->state.co); + copy_v3_v3(obi->part_vel, p->state.vel); + copy_v3_v3(obi->part_avel, p->state.ave); + } + } + } + + /* Fill object info */ + if (dob) { + obi->random_id = dob->random_id; + } + else { + obi->random_id = BLI_hash_int_2d(BLI_hash_string(obi->ob->id.name + 2), 0); + } + + RE_updateRenderInstance(re, obi, RE_OBJECT_INSTANCES_UPDATE_OBMAT | RE_OBJECT_INSTANCES_UPDATE_VIEW); + + if (mat) { + copy_m4_m4(obi->mat, mat); + copy_m3_m4(mat3, mat); + invert_m3_m3(obi->nmat, mat3); + transpose_m3(obi->nmat); + obi->flag |= R_DUPLI_TRANSFORMED; + } + + BLI_addtail(&re->instancetable, obi); + + return obi; +} + +void RE_instance_get_particle_info(struct ObjectInstanceRen *obi, float *index, float *random, float *age, float *lifetime, float co[3], float *size, float vel[3], float angvel[3]) +{ + *index = obi->part_index; + *random = BLI_hash_int_01(obi->part_index); + *age = obi->part_age; + *lifetime = obi->part_lifetime; + copy_v3_v3(co, obi->part_co); + *size = obi->part_size; + copy_v3_v3(vel, obi->part_vel); + copy_v3_v3(angvel, obi->part_avel); +} + + +void RE_makeRenderInstances(Render *re) +{ + ObjectInstanceRen *obi, *oldobi; + ListBase newlist; + int tot; + + /* convert list of object instances to an array for index based lookup */ + tot= BLI_listbase_count(&re->instancetable); + re->objectinstance= MEM_callocN(sizeof(ObjectInstanceRen)*tot, "ObjectInstance"); + re->totinstance= tot; + newlist.first= newlist.last= NULL; + + obi= re->objectinstance; + for (oldobi=re->instancetable.first; oldobi; oldobi=oldobi->next) { + *obi= *oldobi; + + if (obi->obr) { + obi->prev= obi->next= NULL; + BLI_addtail(&newlist, obi); + obi++; + } + else + re->totinstance--; + } + + BLI_freelistN(&re->instancetable); + re->instancetable= newlist; +} + +/* four functions to facilitate envmap rotation for raytrace */ +void RE_instance_rotate_ray_start(ObjectInstanceRen *obi, Isect *is) +{ + if (obi && (obi->flag & R_ENV_TRANSFORMED)) { + copy_v3_v3(is->origstart, is->start); + mul_m4_v3(obi->imat, is->start); + } +} + +void RE_instance_rotate_ray_dir(ObjectInstanceRen *obi, Isect *is) +{ + if (obi && (obi->flag & R_ENV_TRANSFORMED)) { + float end[3]; + + copy_v3_v3(is->origdir, is->dir); + add_v3_v3v3(end, is->origstart, is->dir); + + mul_m4_v3(obi->imat, end); + sub_v3_v3v3(is->dir, end, is->start); + } +} + +void RE_instance_rotate_ray(ObjectInstanceRen *obi, Isect *is) +{ + RE_instance_rotate_ray_start(obi, is); + RE_instance_rotate_ray_dir(obi, is); +} + +void RE_instance_rotate_ray_restore(ObjectInstanceRen *obi, Isect *is) +{ + if (obi && (obi->flag & R_ENV_TRANSFORMED)) { + copy_v3_v3(is->start, is->origstart); + copy_v3_v3(is->dir, is->origdir); + } +} + +int clip_render_object(float boundbox[2][3], float bounds[4], float winmat[4][4]) +{ + float mat[4][4], vec[4]; + int a, fl, flag = -1; + + copy_m4_m4(mat, winmat); + + for (a=0; a < 8; a++) { + vec[0]= (a & 1)? boundbox[0][0]: boundbox[1][0]; + vec[1]= (a & 2)? boundbox[0][1]: boundbox[1][1]; + vec[2]= (a & 4)? boundbox[0][2]: boundbox[1][2]; + vec[3]= 1.0; + mul_m4_v4(mat, vec); + + fl = 0; + if (bounds) { + if (vec[0] < bounds[0] * vec[3]) fl |= 1; + else if (vec[0] > bounds[1] * vec[3]) fl |= 2; + + if (vec[1] > bounds[3] * vec[3]) fl |= 4; + else if (vec[1] < bounds[2] * vec[3]) fl |= 8; + } + else { + if (vec[0] < -vec[3]) fl |= 1; + else if (vec[0] > vec[3]) fl |= 2; + + if (vec[1] > vec[3]) fl |= 4; + else if (vec[1] < -vec[3]) fl |= 8; + } + if (vec[2] < -vec[3]) fl |= 16; + else if (vec[2] > vec[3]) fl |= 32; + + flag &= fl; + if (flag == 0) { + return 0; + } + } + + return flag; +} + diff --git a/source/blender/render/intern/source/shadbuf.c b/source/blender/render/intern/source/shadbuf.c new file mode 100644 index 00000000000..04e9177241b --- /dev/null +++ b/source/blender/render/intern/source/shadbuf.c @@ -0,0 +1,2647 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * Contributor(s): 2004-2006, Blender Foundation + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/render/intern/source/shadbuf.c + * \ingroup render + */ + + +#include <math.h> +#include <string.h> + + +#include "MEM_guardedalloc.h" + +#include "DNA_group_types.h" +#include "DNA_lamp_types.h" +#include "DNA_material_types.h" + +#include "BLI_math.h" +#include "BLI_blenlib.h" +#include "BLI_jitter_2d.h" +#include "BLI_memarena.h" +#include "BLI_rand.h" +#include "BLI_utildefines.h" + +#include "BKE_global.h" +#include "BKE_scene.h" + +#include "PIL_time.h" + +#include "render_types.h" +#include "renderdatabase.h" +#include "rendercore.h" +#include "shadbuf.h" +#include "shading.h" +#include "zbuf.h" + +/* XXX, could be better implemented... this is for endian issues */ +#ifdef __BIG_ENDIAN__ +//# define RCOMP 3 +# define GCOMP 2 +# define BCOMP 1 +# define ACOMP 0 +#else +//# define RCOMP 0 +# define GCOMP 1 +# define BCOMP 2 +# define ACOMP 3 +#endif + +#define RCT_SIZE_X(rct) ((rct)->xmax - (rct)->xmin) +#define RCT_SIZE_Y(rct) ((rct)->ymax - (rct)->ymin) + +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ +/* defined in pipeline.c, is hardcopy of active dynamic allocated Render */ +/* only to be used here in this file, it's for speed */ +extern struct Render R; +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ + +/* ------------------------------------------------------------------------- */ + +/* initshadowbuf() in convertBlenderScene.c */ + +/* ------------------------------------------------------------------------- */ + +static void copy_to_ztile(int *rectz, int size, int x1, int y1, int tile, char *r1) +{ + int len4, *rz; + int x2, y2; + + x2= x1+tile; + y2= y1+tile; + if (x2>=size) x2= size-1; + if (y2>=size) y2= size-1; + + if (x1>=x2 || y1>=y2) return; + + len4= 4*(x2- x1); + rz= rectz + size*y1 + x1; + for (; y1<y2; y1++) { + memcpy(r1, rz, len4); + rz+= size; + r1+= len4; + } +} + +#if 0 +static int sizeoflampbuf(ShadBuf *shb) +{ + int num, count=0; + char *cp; + + cp= shb->cbuf; + num= (shb->size*shb->size)/256; + + while (num--) count+= *(cp++); + + return 256*count; +} +#endif + +/* not threadsafe... */ +static float *give_jitter_tab(int samp) +{ + /* these are all possible jitter tables, takes up some + * 12k, not really bad! + * For soft shadows, it saves memory and render time + */ + static int tab[17]={1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121, 144, 169, 196, 225, 256}; + static float jit[1496][2]; + static char ctab[17]= {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + int a, offset=0; + + if (samp<2) samp= 2; + else if (samp>16) samp= 16; + + for (a=0; a<samp-1; a++) offset+= tab[a]; + + if (ctab[samp]==0) { + ctab[samp]= 1; + BLI_jitter_init((float (*)[2])jit[offset], samp*samp); + } + + return jit[offset]; + +} + +static void make_jitter_weight_tab(Render *re, ShadBuf *shb, short filtertype) +{ + float *jit, totw= 0.0f; + int samp= get_render_shadow_samples(&re->r, shb->samp); + int a, tot=samp*samp; + + shb->weight= MEM_mallocN(sizeof(float)*tot, "weight tab lamp"); + + for (jit= shb->jit, a=0; a<tot; a++, jit+=2) { + if (filtertype==LA_SHADBUF_TENT) + shb->weight[a] = 0.71f - sqrtf(jit[0] * jit[0] + jit[1] * jit[1]); + else if (filtertype==LA_SHADBUF_GAUSS) + shb->weight[a] = RE_filter_value(R_FILTER_GAUSS, 1.8f * sqrtf(jit[0] * jit[0] + jit[1] * jit[1])); + else + shb->weight[a]= 1.0f; + + totw+= shb->weight[a]; + } + + totw= 1.0f/totw; + for (a=0; a<tot; a++) { + shb->weight[a]*= totw; + } +} + +static int verg_deepsample(const void *poin1, const void *poin2) +{ + const DeepSample *ds1= (const DeepSample*)poin1; + const DeepSample *ds2= (const DeepSample*)poin2; + + if (ds1->z < ds2->z) return -1; + else if (ds1->z == ds2->z) return 0; + else return 1; +} + +static int compress_deepsamples(DeepSample *dsample, int tot, float epsilon) +{ + /* uses doubles to avoid overflows and other numerical issues, + * could be improved */ + DeepSample *ds, *newds; + float v; + double slope, slopemin, slopemax, min, max, div, newmin, newmax; + int a, first, z, newtot= 0; + +#if 0 + if (print) { + for (a=0, ds=dsample; a<tot; a++, ds++) + printf("%lf, %f ", ds->z/(double)0x7FFFFFFF, ds->v); + printf("\n"); + } +#endif + + /* read from and write into same array */ + ds= dsample; + newds= dsample; + a= 0; + + /* as long as we are not at the end of the array */ + for (a++, ds++; a<tot; a++, ds++) { + slopemin= 0.0f; + slopemax= 0.0f; + first= 1; + + for (; a<tot; a++, ds++) { + //dz= ds->z - newds->z; + if (ds->z == newds->z) { + /* still in same z position, simply check + * visibility difference against epsilon */ + if (!(fabsf(newds->v - ds->v) <= epsilon)) { + break; + } + } + else { + /* compute slopes */ + div= (double)0x7FFFFFFF / ((double)ds->z - (double)newds->z); + min= (double)((ds->v - epsilon) - newds->v) * div; + max= (double)((ds->v + epsilon) - newds->v) * div; + + /* adapt existing slopes */ + if (first) { + newmin= min; + newmax= max; + first= 0; + } + else { + newmin= MAX2(slopemin, min); + newmax= MIN2(slopemax, max); + + /* verify if there is still space between the slopes */ + if (newmin > newmax) { + ds--; + a--; + break; + } + } + + slopemin= newmin; + slopemax= newmax; + } + } + + if (a == tot) { + ds--; + a--; + } + + /* always previous z */ + z= ds->z; + + if (first || a==tot-1) { + /* if slopes were not initialized, use last visibility */ + v= ds->v; + } + else { + /* compute visibility at center between slopes at z */ + slope = (slopemin + slopemax) * 0.5; + v = (double)newds->v + slope * ((double)(z - newds->z) / (double)0x7FFFFFFF); + } + + newds++; + newtot++; + + newds->z= z; + newds->v= v; + } + + if (newtot == 0 || (newds->v != (newds-1)->v)) + newtot++; + +#if 0 + if (print) { + for (a=0, ds=dsample; a<newtot; a++, ds++) + printf("%lf, %f ", ds->z/(double)0x7FFFFFFF, ds->v); + printf("\n"); + } +#endif + + return newtot; +} + +static float deep_alpha(Render *re, int obinr, int facenr, bool use_strand) +{ + ObjectInstanceRen *obi= &re->objectinstance[obinr]; + Material *ma; + + if (use_strand) { + StrandRen *strand= RE_findOrAddStrand(obi->obr, facenr-1); + ma= strand->buffer->ma; + } + else { + VlakRen *vlr= RE_findOrAddVlak(obi->obr, (facenr-1) & RE_QUAD_MASK); + ma= vlr->mat; + } + + return ma->shad_alpha; +} + +static void compress_deepshadowbuf(Render *re, ShadBuf *shb, APixstr *apixbuf, APixstrand *apixbufstrand) +{ + ShadSampleBuf *shsample; + DeepSample *ds[RE_MAX_OSA], *sampleds[RE_MAX_OSA], *dsb, *newbuf; + APixstr *ap, *apn; + APixstrand *aps, *apns; + float visibility; + + const int totbuf= shb->totbuf; + const float totbuf_f= (float)shb->totbuf; + const float totbuf_f_inv= 1.0f/totbuf_f; + const int size= shb->size; + + int a, b, c, tot, minz, found, prevtot, newtot; + int sampletot[RE_MAX_OSA], totsample = 0, totsamplec = 0; + + shsample= MEM_callocN(sizeof(ShadSampleBuf), "shad sample buf"); + BLI_addtail(&shb->buffers, shsample); + + shsample->totbuf = MEM_callocN(sizeof(int) * size * size, "deeptotbuf"); + shsample->deepbuf = MEM_callocN(sizeof(DeepSample *) * size * size, "deepbuf"); + + ap= apixbuf; + aps= apixbufstrand; + for (a=0; a<size*size; a++, ap++, aps++) { + /* count number of samples */ + for (c=0; c<totbuf; c++) + sampletot[c]= 0; + + tot= 0; + for (apn=ap; apn; apn=apn->next) + for (b=0; b<4; b++) + if (apn->p[b]) + for (c=0; c<totbuf; c++) + if (apn->mask[b] & (1<<c)) + sampletot[c]++; + + if (apixbufstrand) { + for (apns=aps; apns; apns=apns->next) + for (b=0; b<4; b++) + if (apns->p[b]) + for (c=0; c<totbuf; c++) + if (apns->mask[b] & (1<<c)) + sampletot[c]++; + } + + for (c=0; c<totbuf; c++) + tot += sampletot[c]; + + if (tot == 0) { + shsample->deepbuf[a]= NULL; + shsample->totbuf[a]= 0; + continue; + } + + /* fill samples */ + ds[0]= sampleds[0]= MEM_callocN(sizeof(DeepSample)*tot*2, "deepsample"); + for (c=1; c<totbuf; c++) + ds[c]= sampleds[c]= sampleds[c-1] + sampletot[c-1]*2; + + for (apn=ap; apn; apn=apn->next) { + for (b=0; b<4; b++) { + if (apn->p[b]) { + for (c=0; c<totbuf; c++) { + if (apn->mask[b] & (1<<c)) { + /* two entries to create step profile */ + ds[c]->z= apn->z[b]; + ds[c]->v= 1.0f; /* not used */ + ds[c]++; + ds[c]->z= apn->z[b]; + ds[c]->v= deep_alpha(re, apn->obi[b], apn->p[b], 0); + ds[c]++; + } + } + } + } + } + + if (apixbufstrand) { + for (apns=aps; apns; apns=apns->next) { + for (b=0; b<4; b++) { + if (apns->p[b]) { + for (c=0; c<totbuf; c++) { + if (apns->mask[b] & (1<<c)) { + /* two entries to create step profile */ + ds[c]->z= apns->z[b]; + ds[c]->v= 1.0f; /* not used */ + ds[c]++; + ds[c]->z= apns->z[b]; + ds[c]->v= deep_alpha(re, apns->obi[b], apns->p[b], 1); + ds[c]++; + } + } + } + } + } + } + + for (c=0; c<totbuf; c++) { + /* sort by increasing z */ + qsort(sampleds[c], sampletot[c], sizeof(DeepSample)*2, verg_deepsample); + + /* sum visibility, replacing alpha values */ + visibility= 1.0f; + ds[c]= sampleds[c]; + + for (b=0; b<sampletot[c]; b++) { + /* two entries creating step profile */ + ds[c]->v= visibility; + ds[c]++; + + visibility *= 1.0f-ds[c]->v; + ds[c]->v= visibility; + ds[c]++; + } + + /* halfway trick, probably won't work well for volumes? */ + ds[c]= sampleds[c]; + for (b=0; b<sampletot[c]; b++) { + if (b+1 < sampletot[c]) { + ds[c]->z= (ds[c]->z>>1) + ((ds[c]+2)->z>>1); + ds[c]++; + ds[c]->z= (ds[c]->z>>1) + ((ds[c]+2)->z>>1); + ds[c]++; + } + else { + ds[c]->z= (ds[c]->z>>1) + (0x7FFFFFFF>>1); + ds[c]++; + ds[c]->z= (ds[c]->z>>1) + (0x7FFFFFFF>>1); + ds[c]++; + } + } + + /* init for merge loop */ + ds[c]= sampleds[c]; + sampletot[c] *= 2; + } + + shsample->deepbuf[a]= MEM_callocN(sizeof(DeepSample)*tot*2, "deepsample"); + shsample->totbuf[a]= 0; + + /* merge buffers */ + dsb= shsample->deepbuf[a]; + while (1) { + minz= 0; + found= 0; + + for (c=0; c<totbuf; c++) { + if (sampletot[c] && (!found || ds[c]->z < minz)) { + minz= ds[c]->z; + found= 1; + } + } + + if (!found) + break; + + dsb->z= minz; + dsb->v= 0.0f; + + visibility= 0.0f; + for (c=0; c<totbuf; c++) { + if (sampletot[c] && ds[c]->z == minz) { + ds[c]++; + sampletot[c]--; + } + + if (sampleds[c] == ds[c]) + visibility += totbuf_f_inv; + else + visibility += (ds[c]-1)->v / totbuf_f; + } + + dsb->v= visibility; + dsb++; + shsample->totbuf[a]++; + } + + prevtot= shsample->totbuf[a]; + totsample += prevtot; + + newtot= compress_deepsamples(shsample->deepbuf[a], prevtot, shb->compressthresh); + shsample->totbuf[a]= newtot; + totsamplec += newtot; + + if (newtot < prevtot) { + newbuf= MEM_mallocN(sizeof(DeepSample)*newtot, "cdeepsample"); + memcpy(newbuf, shsample->deepbuf[a], sizeof(DeepSample)*newtot); + MEM_freeN(shsample->deepbuf[a]); + shsample->deepbuf[a]= newbuf; + } + + MEM_freeN(sampleds[0]); + } + + //printf("%d -> %d, ratio %f\n", totsample, totsamplec, (float)totsamplec/(float)totsample); +} + +/* create Z tiles (for compression): this system is 24 bits!!! */ +static void compress_shadowbuf(ShadBuf *shb, int *rectz, int square) +{ + ShadSampleBuf *shsample; + float dist; + uintptr_t *ztile; + int *rz, *rz1, verg, verg1, size= shb->size; + int a, x, y, minx, miny, byt1, byt2; + char *rc, *rcline, *ctile, *zt; + + shsample= MEM_callocN(sizeof(ShadSampleBuf), "shad sample buf"); + BLI_addtail(&shb->buffers, shsample); + + shsample->zbuf= MEM_mallocN(sizeof(uintptr_t)*(size*size)/256, "initshadbuf2"); + shsample->cbuf= MEM_callocN((size*size)/256, "initshadbuf3"); + + ztile= (uintptr_t *)shsample->zbuf; + ctile= shsample->cbuf; + + /* help buffer */ + rcline= MEM_mallocN(256*4+sizeof(int), "makeshadbuf2"); + + for (y=0; y<size; y+=16) { + if (y< size/2) miny= y+15-size/2; + else miny= y-size/2; + + for (x=0; x<size; x+=16) { + + /* is tile within spotbundle? */ + a= size/2; + if (x< a) minx= x+15-a; + else minx= x-a; + + dist = sqrtf((float)(minx * minx + miny * miny)); + + if (square==0 && dist>(float)(a+12)) { /* 12, tested with a onlyshadow lamp */ + a= 256; verg= 0; /* 0x80000000; */ /* 0x7FFFFFFF; */ + rz1= (&verg)+1; + } + else { + copy_to_ztile(rectz, size, x, y, 16, rcline); + rz1= (int *)rcline; + + verg= (*rz1 & 0xFFFFFF00); + + for (a=0;a<256;a++, rz1++) { + if ( (*rz1 & 0xFFFFFF00) !=verg) break; + } + } + if (a==256) { /* complete empty tile */ + *ctile= 0; + *ztile= *(rz1-1); + } + else { + + /* ACOMP etc. are defined to work L/B endian */ + + rc= rcline; + rz1= (int *)rcline; + verg= rc[ACOMP]; + verg1= rc[BCOMP]; + rc+= 4; + byt1= 1; byt2= 1; + for (a=1;a<256;a++, rc+=4) { + byt1 &= (verg==rc[ACOMP]); + byt2 &= (verg1==rc[BCOMP]); + + if (byt1==0) break; + } + if (byt1 && byt2) { /* only store byte */ + *ctile= 1; + *ztile= (uintptr_t)MEM_mallocN(256+4, "tile1"); + rz= (int *)*ztile; + *rz= *rz1; + + zt= (char *)(rz+1); + rc= rcline; + for (a=0; a<256; a++, zt++, rc+=4) *zt= rc[GCOMP]; + } + else if (byt1) { /* only store short */ + *ctile= 2; + *ztile= (uintptr_t)MEM_mallocN(2*256+4, "Tile2"); + rz= (int *)*ztile; + *rz= *rz1; + + zt= (char *)(rz+1); + rc= rcline; + for (a=0; a<256; a++, zt+=2, rc+=4) { + zt[0]= rc[BCOMP]; + zt[1]= rc[GCOMP]; + } + } + else { /* store triple */ + *ctile= 3; + *ztile= (uintptr_t)MEM_mallocN(3*256, "Tile3"); + + zt= (char *)*ztile; + rc= rcline; + for (a=0; a<256; a++, zt+=3, rc+=4) { + zt[0]= rc[ACOMP]; + zt[1]= rc[BCOMP]; + zt[2]= rc[GCOMP]; + } + } + } + ztile++; + ctile++; + } + } + + MEM_freeN(rcline); +} + +/* sets start/end clipping. lar->shb should be initialized */ +static void shadowbuf_autoclip(Render *re, LampRen *lar) +{ + ObjectInstanceRen *obi; + ObjectRen *obr; + VlakRen *vlr= NULL; + VertRen *ver= NULL; + Material *ma= NULL; + float minz, maxz, vec[3], viewmat[4][4], obviewmat[4][4]; + unsigned int lay = -1; + int i, a, maxtotvert, ok= 1; + char *clipflag; + + minz= 1.0e30f; maxz= -1.0e30f; + copy_m4_m4(viewmat, lar->shb->viewmat); + + if (lar->mode & (LA_LAYER|LA_LAYER_SHADOW)) lay= lar->lay; + + maxtotvert= 0; + for (obr=re->objecttable.first; obr; obr=obr->next) + maxtotvert = max_ii(obr->totvert, maxtotvert); + + clipflag= MEM_callocN(sizeof(char)*maxtotvert, "autoclipflag"); + + /* set clip in vertices when face visible */ + for (i=0, obi=re->instancetable.first; obi; i++, obi=obi->next) { + obr= obi->obr; + + if (obi->flag & R_TRANSFORMED) + mul_m4_m4m4(obviewmat, viewmat, obi->mat); + else + copy_m4_m4(obviewmat, viewmat); + + memset(clipflag, 0, sizeof(char)*obr->totvert); + + /* clear clip, is being set if face is visible (clip is calculated for real later) */ + for (a=0; a<obr->totvlak; a++) { + if ((a & 255)==0) vlr= obr->vlaknodes[a>>8].vlak; + else vlr++; + + /* note; these conditions are copied from zbuffer_shadow() */ + if (vlr->mat!= ma) { + ma= vlr->mat; + ok= 1; + if ((ma->mode2 & MA_CASTSHADOW)==0 || (ma->mode & MA_SHADBUF)==0) ok= 0; + } + + if (ok && (obi->lay & lay)) { + clipflag[vlr->v1->index]= 1; + clipflag[vlr->v2->index]= 1; + clipflag[vlr->v3->index]= 1; + if (vlr->v4) clipflag[vlr->v4->index]= 1; + } + } + + /* calculate min and max */ + for (a=0; a< obr->totvert;a++) { + if ((a & 255)==0) ver= RE_findOrAddVert(obr, a); + else ver++; + + if (clipflag[a]) { + copy_v3_v3(vec, ver->co); + mul_m4_v3(obviewmat, vec); + /* Z on visible side of lamp space */ + if (vec[2] < 0.0f) { + float inpr, z= -vec[2]; + + /* since vec is rotated in lampspace, this is how to get the cosine of angle */ + /* precision is set 20% larger */ + vec[2]*= 1.2f; + normalize_v3(vec); + inpr= - vec[2]; + + if (inpr>=lar->spotsi) { + if (z<minz) minz= z; + if (z>maxz) maxz= z; + } + } + } + } + } + + MEM_freeN(clipflag); + + /* set clipping min and max */ + if (minz < maxz) { + float delta= (maxz - minz); /* threshold to prevent precision issues */ + + //printf("minz %f maxz %f delta %f\n", minz, maxz, delta); + if (lar->bufflag & LA_SHADBUF_AUTO_START) + lar->shb->d= minz - delta*0.02f; /* 0.02 is arbitrary... needs more thinking! */ + if (lar->bufflag & LA_SHADBUF_AUTO_END) + lar->shb->clipend= maxz + delta*0.1f; + + /* bias was calculated as percentage, we scale it to prevent animation issues */ + delta= (lar->clipend-lar->clipsta)/(lar->shb->clipend-lar->shb->d); + //printf("bias delta %f\n", delta); + lar->shb->bias= (int) (delta*(float)lar->shb->bias); + } +} + +static void makeflatshadowbuf(Render *re, LampRen *lar, float *jitbuf) +{ + ShadBuf *shb= lar->shb; + int *rectz, samples; + + /* zbuffering */ + rectz= MEM_mapallocN(sizeof(int)*shb->size*shb->size, "makeshadbuf"); + + for (samples=0; samples<shb->totbuf; samples++) { + zbuffer_shadow(re, shb->persmat, lar, rectz, shb->size, jitbuf[2*samples], jitbuf[2*samples+1]); + /* create Z tiles (for compression): this system is 24 bits!!! */ + compress_shadowbuf(shb, rectz, lar->mode & LA_SQUARE); + + if (re->test_break(re->tbh)) + break; + } + + MEM_freeN(rectz); +} + +static void makedeepshadowbuf(Render *re, LampRen *lar, float *jitbuf) +{ + ShadBuf *shb= lar->shb; + APixstr *apixbuf; + APixstrand *apixbufstrand= NULL; + ListBase apsmbase= {NULL, NULL}; + + /* zbuffering */ + apixbuf= MEM_callocN(sizeof(APixstr)*shb->size*shb->size, "APixbuf"); + if (re->totstrand) + apixbufstrand= MEM_callocN(sizeof(APixstrand)*shb->size*shb->size, "APixbufstrand"); + + zbuffer_abuf_shadow(re, lar, shb->persmat, apixbuf, apixbufstrand, &apsmbase, shb->size, + shb->totbuf, (float(*)[2])jitbuf); + + /* create Z tiles (for compression): this system is 24 bits!!! */ + compress_deepshadowbuf(re, shb, apixbuf, apixbufstrand); + + MEM_freeN(apixbuf); + if (apixbufstrand) + MEM_freeN(apixbufstrand); + freepsA(&apsmbase); +} + +void makeshadowbuf(Render *re, LampRen *lar) +{ + ShadBuf *shb= lar->shb; + float wsize, *jitbuf, twozero[2]= {0.0f, 0.0f}, angle, temp; + + if (lar->bufflag & (LA_SHADBUF_AUTO_START|LA_SHADBUF_AUTO_END)) + shadowbuf_autoclip(re, lar); + + /* just to enforce identical behavior of all irregular buffers */ + if (lar->buftype==LA_SHADBUF_IRREGULAR) + shb->size= 1024; + + /* matrices and window: in winmat the transformation is being put, + * transforming from observer view to lamp view, including lamp window matrix */ + + angle= saacos(lar->spotsi); + temp = 0.5f * shb->size * cosf(angle) / sinf(angle); + shb->pixsize= (shb->d)/temp; + wsize= shb->pixsize*(shb->size/2.0f); + + perspective_m4(shb->winmat, -wsize, wsize, -wsize, wsize, shb->d, shb->clipend); + mul_m4_m4m4(shb->persmat, shb->winmat, shb->viewmat); + + if (ELEM(lar->buftype, LA_SHADBUF_REGULAR, LA_SHADBUF_HALFWAY, LA_SHADBUF_DEEP)) { + shb->totbuf= lar->buffers; + + /* jitter, weights - not threadsafe! */ + BLI_thread_lock(LOCK_CUSTOM1); + shb->jit= give_jitter_tab(get_render_shadow_samples(&re->r, shb->samp)); + make_jitter_weight_tab(re, shb, lar->filtertype); + BLI_thread_unlock(LOCK_CUSTOM1); + + if (shb->totbuf==4) jitbuf= give_jitter_tab(2); + else if (shb->totbuf==9) jitbuf= give_jitter_tab(3); + else jitbuf= twozero; + + /* zbuffering */ + if (lar->buftype == LA_SHADBUF_DEEP) { + makedeepshadowbuf(re, lar, jitbuf); + shb->totbuf= 1; + } + else + makeflatshadowbuf(re, lar, jitbuf); + + /* printf("lampbuf %d\n", sizeoflampbuf(shb)); */ + } +} + +static void *do_shadow_thread(void *re_v) +{ + Render *re = (Render *)re_v; + LampRen *lar; + + do { + BLI_thread_lock(LOCK_CUSTOM1); + for (lar=re->lampren.first; lar; lar=lar->next) { + if (lar->shb && !lar->thread_assigned) { + lar->thread_assigned= 1; + break; + } + } + BLI_thread_unlock(LOCK_CUSTOM1); + + /* if type is irregular, this only sets the perspective matrix and autoclips */ + if (lar) { + makeshadowbuf(re, lar); + BLI_thread_lock(LOCK_CUSTOM1); + lar->thread_ready= 1; + BLI_thread_unlock(LOCK_CUSTOM1); + } + } while (lar && !re->test_break(re->tbh)); + + return NULL; +} + +static volatile int g_break= 0; +static int thread_break(void *UNUSED(arg)) +{ + return g_break; +} + +void threaded_makeshadowbufs(Render *re) +{ + ListBase threads; + LampRen *lar; + int a, totthread= 0; + int (*test_break)(void *); + + /* count number of threads to use */ + if (G.is_rendering) { + for (lar=re->lampren.first; lar; lar= lar->next) + if (lar->shb) + totthread++; + + totthread = min_ii(totthread, re->r.threads); + } + else + totthread = 1; /* preview render */ + + if (totthread <= 1) { + for (lar=re->lampren.first; lar; lar= lar->next) { + if (re->test_break(re->tbh)) break; + if (lar->shb) { + /* if type is irregular, this only sets the perspective matrix and autoclips */ + makeshadowbuf(re, lar); + } + } + } + else { + /* swap test break function */ + test_break= re->test_break; + re->test_break= thread_break; + + for (lar=re->lampren.first; lar; lar= lar->next) { + lar->thread_assigned= 0; + lar->thread_ready= 0; + } + + BLI_threadpool_init(&threads, do_shadow_thread, totthread); + + for (a=0; a<totthread; a++) + BLI_threadpool_insert(&threads, re); + + /* keep rendering as long as there are shadow buffers not ready */ + do { + if ((g_break=test_break(re->tbh))) + break; + + PIL_sleep_ms(50); + + BLI_thread_lock(LOCK_CUSTOM1); + for (lar=re->lampren.first; lar; lar= lar->next) + if (lar->shb && !lar->thread_ready) + break; + BLI_thread_unlock(LOCK_CUSTOM1); + } while (lar); + + BLI_threadpool_end(&threads); + + /* unset threadsafety */ + re->test_break= test_break; + g_break= 0; + } +} + +void freeshadowbuf(LampRen *lar) +{ + if (lar->shb) { + ShadBuf *shb= lar->shb; + ShadSampleBuf *shsample; + int b, v; + + for (shsample= shb->buffers.first; shsample; shsample= shsample->next) { + if (shsample->deepbuf) { + v= shb->size*shb->size; + for (b=0; b<v; b++) + if (shsample->deepbuf[b]) + MEM_freeN(shsample->deepbuf[b]); + + MEM_freeN(shsample->deepbuf); + MEM_freeN(shsample->totbuf); + } + else { + intptr_t *ztile= shsample->zbuf; + const char *ctile= shsample->cbuf; + + v= (shb->size*shb->size)/256; + for (b=0; b<v; b++, ztile++, ctile++) + if (*ctile) MEM_freeN((void *) *ztile); + + MEM_freeN(shsample->zbuf); + MEM_freeN(shsample->cbuf); + } + } + BLI_freelistN(&shb->buffers); + + if (shb->weight) MEM_freeN(shb->weight); + MEM_freeN(lar->shb); + + lar->shb= NULL; + } +} + + +static int firstreadshadbuf(ShadBuf *shb, ShadSampleBuf *shsample, int **rz, int xs, int ys, int nr) +{ + /* return a 1 if fully compressed shadbuf-tile && z==const */ + int ofs; + const char *ct; + + if (shsample->deepbuf) + return 0; + + /* always test borders of shadowbuffer */ + if (xs<0) xs= 0; else if (xs>=shb->size) xs= shb->size-1; + if (ys<0) ys= 0; else if (ys>=shb->size) ys= shb->size-1; + + /* calc z */ + ofs= (ys>>4)*(shb->size>>4) + (xs>>4); + ct= shsample->cbuf+ofs; + if (*ct==0) { + if (nr==0) { + *rz= *( (int **)(shsample->zbuf+ofs) ); + return 1; + } + else if (*rz!= *( (int **)(shsample->zbuf+ofs) )) return 0; + + return 1; + } + + return 0; +} + +static float readdeepvisibility(DeepSample *dsample, int tot, int z, int bias, float *biast) +{ + DeepSample *ds, *prevds; + float t; + int a; + + /* tricky stuff here; we use ints which can overflow easily with bias values */ + + ds= dsample; + for (a=0; a<tot && (z-bias > ds->z); a++, ds++) {} + + if (a == tot) { + if (biast) + *biast= 0.0f; + return (ds-1)->v; /* completely behind all samples */ + } + + /* check if this read needs bias blending */ + if (biast) { + if (z > ds->z) + *biast= (float)(z - ds->z)/(float)bias; + else + *biast= 0.0f; + } + + if (a == 0) + return 1.0f; /* completely in front of all samples */ + + /* converting to float early here because ds->z - prevds->z can overflow */ + prevds= ds-1; + t= ((float)(z-bias) - (float)prevds->z)/((float)ds->z - (float)prevds->z); + return t*ds->v + (1.0f-t)*prevds->v; +} + +static float readdeepshadowbuf(ShadBuf *shb, ShadSampleBuf *shsample, int bias, int xs, int ys, int zs) +{ + float v, biasv, biast; + int ofs, tot; + + if (zs < - 0x7FFFFE00 + bias) + return 1.0; /* extreme close to clipstart */ + + /* calc z */ + ofs= ys*shb->size + xs; + tot= shsample->totbuf[ofs]; + if (tot == 0) + return 1.0f; + + v= readdeepvisibility(shsample->deepbuf[ofs], tot, zs, bias, &biast); + + if (biast != 0.0f) { + /* in soft bias area */ + biasv = readdeepvisibility(shsample->deepbuf[ofs], tot, zs, 0, NULL); + + biast= biast*biast; + return (1.0f-biast)*v + biast*biasv; + } + + return v; +} + +/* return 1.0 : fully in light */ +static float readshadowbuf(ShadBuf *shb, ShadSampleBuf *shsample, int bias, int xs, int ys, int zs) +{ + float temp; + int *rz, ofs; + int zsamp=0; + char *ct, *cz; + + /* simpleclip */ + /* if (xs<0 || ys<0) return 1.0; */ + /* if (xs>=shb->size || ys>=shb->size) return 1.0; */ + + /* always test borders of shadowbuffer */ + if (xs<0) xs= 0; else if (xs>=shb->size) xs= shb->size-1; + if (ys<0) ys= 0; else if (ys>=shb->size) ys= shb->size-1; + + if (shsample->deepbuf) + return readdeepshadowbuf(shb, shsample, bias, xs, ys, zs); + + /* calc z */ + ofs= (ys>>4)*(shb->size>>4) + (xs>>4); + ct= shsample->cbuf+ofs; + rz= *( (int **)(shsample->zbuf+ofs) ); + + if (*ct==3) { + ct= ((char *)rz)+3*16*(ys & 15)+3*(xs & 15); + cz= (char *)&zsamp; + cz[ACOMP]= ct[0]; + cz[BCOMP]= ct[1]; + cz[GCOMP]= ct[2]; + } + else if (*ct==2) { + ct= ((char *)rz); + ct+= 4+2*16*(ys & 15)+2*(xs & 15); + zsamp= *rz; + + cz= (char *)&zsamp; + cz[BCOMP]= ct[0]; + cz[GCOMP]= ct[1]; + } + else if (*ct==1) { + ct= ((char *)rz); + ct+= 4+16*(ys & 15)+(xs & 15); + zsamp= *rz; + + cz= (char *)&zsamp; + cz[GCOMP]= ct[0]; + + } + else { + /* got warning on this for 64 bits.... */ + /* but it's working code! in this case rz is not a pointer but zvalue (ton) */ + zsamp= GET_INT_FROM_POINTER(rz); + } + + /* tricky stuff here; we use ints which can overflow easily with bias values */ + + if (zsamp > zs) return 1.0; /* absolute no shadow */ + else if (zs < - 0x7FFFFE00 + bias) return 1.0; /* extreme close to clipstart */ + else if (zsamp < zs-bias) return 0.0; /* absolute in shadow */ + else { /* soft area */ + + temp= ( (float)(zs- zsamp) )/(float)bias; + return 1.0f - temp*temp; + + } +} + +static void shadowbuf_project_co(float *x, float *y, float *z, ShadBuf *shb, const float co[3]) +{ + float hco[4], size= 0.5f*(float)shb->size; + + copy_v3_v3(hco, co); + hco[3]= 1.0f; + + mul_m4_v4(shb->persmat, hco); + + *x= size*(1.0f+hco[0]/hco[3]); + *y= size*(1.0f+hco[1]/hco[3]); + if (z) *z= (hco[2]/hco[3]); +} + +/* the externally called shadow testing (reading) function */ +/* return 1.0: no shadow at all */ +float testshadowbuf(Render *re, ShadBuf *shb, const float co[3], const float dxco[3], const float dyco[3], float inp, float mat_bias) +{ + ShadSampleBuf *shsample; + float fac, dco[3], dx[3], dy[3], shadfac=0.0f; + float xs1, ys1, zs1, *jit, *weight, xres, yres, biasf; + int xs, ys, zs, bias, *rz; + short a, num; + + /* crash preventer */ + if (shb->buffers.first==NULL) + return 1.0f; + + /* when facing away, assume fully in shadow */ + if (inp <= 0.0f) + return 0.0f; + + /* project coordinate to pixel space */ + shadowbuf_project_co(&xs1, &ys1, &zs1, shb, co); + + /* clip z coordinate, z is projected so that (-1.0, 1.0) matches + * (clipstart, clipend), so we can do this simple test */ + if (zs1>=1.0f) + return 0.0f; + else if (zs1<= -1.0f) + return 1.0f; + + zs= ((float)0x7FFFFFFF)*zs1; + + /* take num*num samples, increase area with fac */ + num= get_render_shadow_samples(&re->r, shb->samp); + num= num*num; + fac= shb->soft; + + /* compute z bias */ + if (mat_bias!=0.0f) biasf= shb->bias*mat_bias; + else biasf= shb->bias; + /* with inp==1.0, bias is half the size. correction value was 1.1, giving errors + * on cube edges, with one side being almost frontal lighted (ton) */ + bias= (1.5f-inp*inp)*biasf; + + /* in case of no filtering we can do things simpler */ + if (num==1) { + for (shsample= shb->buffers.first; shsample; shsample= shsample->next) + shadfac += readshadowbuf(shb, shsample, bias, (int)xs1, (int)ys1, zs); + + return shadfac/(float)shb->totbuf; + } + + /* calculate filter size */ + add_v3_v3v3(dco, co, dxco); + shadowbuf_project_co(&dx[0], &dx[1], NULL, shb, dco); + dx[0]= xs1 - dx[0]; + dx[1]= ys1 - dx[1]; + + add_v3_v3v3(dco, co, dyco); + shadowbuf_project_co(&dy[0], &dy[1], NULL, shb, dco); + dy[0]= xs1 - dy[0]; + dy[1]= ys1 - dy[1]; + + xres = fac * (fabsf(dx[0]) + fabsf(dy[0])); + yres = fac * (fabsf(dx[1]) + fabsf(dy[1])); + if (xres<1.0f) xres= 1.0f; + if (yres<1.0f) yres= 1.0f; + + /* make xs1/xs1 corner of sample area */ + xs1 -= xres*0.5f; + ys1 -= yres*0.5f; + + /* in case we have a constant value in a tile, we can do quicker lookup */ + if (xres<16.0f && yres<16.0f) { + shsample= shb->buffers.first; + if (firstreadshadbuf(shb, shsample, &rz, (int)xs1, (int)ys1, 0)) { + if (firstreadshadbuf(shb, shsample, &rz, (int)(xs1+xres), (int)ys1, 1)) { + if (firstreadshadbuf(shb, shsample, &rz, (int)xs1, (int)(ys1+yres), 1)) { + if (firstreadshadbuf(shb, shsample, &rz, (int)(xs1+xres), (int)(ys1+yres), 1)) { + return readshadowbuf(shb, shsample, bias, (int)xs1, (int)ys1, zs); + } + } + } + } + } + + /* full jittered shadow buffer lookup */ + for (shsample= shb->buffers.first; shsample; shsample= shsample->next) { + jit= shb->jit; + weight= shb->weight; + + for (a=num; a>0; a--, jit+=2, weight++) { + /* instead of jit i tried random: ugly! */ + /* note: the plus 0.5 gives best sampling results, jit goes from -0.5 to 0.5 */ + /* xs1 and ys1 are already corrected to be corner of sample area */ + xs= xs1 + xres*(jit[0] + 0.5f); + ys= ys1 + yres*(jit[1] + 0.5f); + + shadfac+= *weight * readshadowbuf(shb, shsample, bias, xs, ys, zs); + } + } + + /* Renormalizes for the sample number: */ + return shadfac/(float)shb->totbuf; +} + +/* different function... sampling behind clipend can be LIGHT, bias is negative! */ +/* return: light */ +static float readshadowbuf_halo(ShadBuf *shb, ShadSampleBuf *shsample, int xs, int ys, int zs) +{ + float temp; + int *rz, ofs; + int bias, zbias, zsamp; + char *ct, *cz; + + /* negative! The other side is more important */ + bias= -shb->bias; + + /* simpleclip */ + if (xs<0 || ys<0) return 0.0; + if (xs>=shb->size || ys>=shb->size) return 0.0; + + /* calc z */ + ofs= (ys>>4)*(shb->size>>4) + (xs>>4); + ct= shsample->cbuf+ofs; + rz= *( (int **)(shsample->zbuf+ofs) ); + + if (*ct==3) { + ct= ((char *)rz)+3*16*(ys & 15)+3*(xs & 15); + cz= (char *)&zsamp; + zsamp= 0; + cz[ACOMP]= ct[0]; + cz[BCOMP]= ct[1]; + cz[GCOMP]= ct[2]; + } + else if (*ct==2) { + ct= ((char *)rz); + ct+= 4+2*16*(ys & 15)+2*(xs & 15); + zsamp= *rz; + + cz= (char *)&zsamp; + cz[BCOMP]= ct[0]; + cz[GCOMP]= ct[1]; + } + else if (*ct==1) { + ct= ((char *)rz); + ct+= 4+16*(ys & 15)+(xs & 15); + zsamp= *rz; + + cz= (char *)&zsamp; + cz[GCOMP]= ct[0]; + + } + else { + /* same as before */ + /* still working code! (ton) */ + zsamp= GET_INT_FROM_POINTER(rz); + } + + /* NO schadow when sampled at 'eternal' distance */ + + if (zsamp >= 0x7FFFFE00) return 1.0; + + if (zsamp > zs) return 1.0; /* absolute no shadww */ + else { + /* bias is negative, so the (zs-bias) can be beyond 0x7fffffff */ + zbias= 0x7fffffff - zs; + if (zbias > -bias) { + if ( zsamp < zs-bias) return 0.0; /* absolute in shadow */ + } + else return 0.0; /* absolute shadow */ + } + + /* soft area */ + + temp= ( (float)(zs- zsamp) )/(float)bias; + return 1.0f - temp*temp; +} + + +float shadow_halo(LampRen *lar, const float p1[3], const float p2[3]) +{ + /* p1 p2 already are rotated in spot-space */ + ShadBuf *shb= lar->shb; + ShadSampleBuf *shsample; + float co[4], siz; + float lambda, lambda_o, lambda_x, lambda_y, ldx, ldy; + float zf, xf1, yf1, zf1, xf2, yf2, zf2; + float count, lightcount; + int x, y, z, xs1, ys1; + int dx = 0, dy = 0; + + siz= 0.5f*(float)shb->size; + + co[0]= p1[0]; + co[1]= p1[1]; + co[2]= p1[2]/lar->sh_zfac; + co[3]= 1.0; + mul_m4_v4(shb->winmat, co); /* rational hom co */ + xf1= siz*(1.0f+co[0]/co[3]); + yf1= siz*(1.0f+co[1]/co[3]); + zf1= (co[2]/co[3]); + + + co[0]= p2[0]; + co[1]= p2[1]; + co[2]= p2[2]/lar->sh_zfac; + co[3]= 1.0; + mul_m4_v4(shb->winmat, co); /* rational hom co */ + xf2= siz*(1.0f+co[0]/co[3]); + yf2= siz*(1.0f+co[1]/co[3]); + zf2= (co[2]/co[3]); + + /* the 2dda (a pixel line formula) */ + + xs1= (int)xf1; + ys1= (int)yf1; + + if (xf1 != xf2) { + if (xf2-xf1 > 0.0f) { + lambda_x= (xf1-xs1-1.0f)/(xf1-xf2); + ldx= -shb->shadhalostep/(xf1-xf2); + dx= shb->shadhalostep; + } + else { + lambda_x= (xf1-xs1)/(xf1-xf2); + ldx= shb->shadhalostep/(xf1-xf2); + dx= -shb->shadhalostep; + } + } + else { + lambda_x= 1.0; + ldx= 0.0; + } + + if (yf1 != yf2) { + if (yf2-yf1 > 0.0f) { + lambda_y= (yf1-ys1-1.0f)/(yf1-yf2); + ldy= -shb->shadhalostep/(yf1-yf2); + dy= shb->shadhalostep; + } + else { + lambda_y= (yf1-ys1)/(yf1-yf2); + ldy= shb->shadhalostep/(yf1-yf2); + dy= -shb->shadhalostep; + } + } + else { + lambda_y= 1.0; + ldy= 0.0; + } + + x= xs1; + y= ys1; + lambda= count= lightcount= 0.0; + +/* printf("start %x %x \n", (int)(0x7FFFFFFF*zf1), (int)(0x7FFFFFFF*zf2)); */ + + do { + lambda_o= lambda; + + if (lambda_x==lambda_y) { + lambda_x+= ldx; + x+= dx; + lambda_y+= ldy; + y+= dy; + } + else { + if (lambda_x<lambda_y) { + lambda_x+= ldx; + x+= dx; + } + else { + lambda_y+= ldy; + y+= dy; + } + } + + lambda = min_ff(lambda_x, lambda_y); + + /* not making any progress? */ + if (lambda==lambda_o) break; + + /* clip to end of volume */ + lambda = min_ff(lambda, 1.0f); + + zf= zf1 + lambda*(zf2-zf1); + count+= (float)shb->totbuf; + + if (zf<= -1.0f) lightcount += 1.0f; /* close to the spot */ + else { + + /* make sure, behind the clipend we extend halolines. */ + if (zf>=1.0f) z= 0x7FFFF000; + else z= (int)(0x7FFFF000*zf); + + for (shsample= shb->buffers.first; shsample; shsample= shsample->next) + lightcount+= readshadowbuf_halo(shb, shsample, x, y, z); + + } + } + while (lambda < 1.0f); + + if (count!=0.0f) return (lightcount/count); + return 0.0f; + +} + + +/* ********************* Irregular Shadow Buffer (ISB) ************* */ +/* ********** storage of all view samples in a raster of lists ***** */ + +/* based on several articles describing this method, like: + * The Irregular Z-Buffer and its Application to Shadow Mapping + * Gregory S. Johnson - William R. Mark - Christopher A. Burns + * and + * Alias-Free Shadow Maps + * Timo Aila and Samuli Laine + */ + +/* bsp structure (actually kd tree) */ + +#define BSPMAX_SAMPLE 128 +#define BSPMAX_DEPTH 32 + +/* aligned with struct rctf */ +typedef struct Boxf { + float xmin, xmax; + float ymin, ymax; + float zmin, zmax; +} Boxf; + +typedef struct ISBBranch { + struct ISBBranch *left, *right; + float divider[2]; + Boxf box; + short totsamp, index, full, unused; + ISBSample **samples; +} ISBBranch; + +typedef struct BSPFace { + Boxf box; + const float *v1, *v2, *v3, *v4; + int obi; /* object for face lookup */ + int facenr; /* index to retrieve VlakRen */ + int type; /* only for strand now */ + short shad_alpha, is_full; + + /* strand caching data, optimize for point_behind_strand() */ + float radline, radline_end, len; + float vec1[3], vec2[3], rc[3]; +} BSPFace; + +/* boxes are in lamp projection */ +static void init_box(Boxf *box) +{ + box->xmin = 1000000.0f; + box->xmax = 0; + box->ymin = 1000000.0f; + box->ymax = 0; + box->zmin= 0x7FFFFFFF; + box->zmax= - 0x7FFFFFFF; +} + +/* use v1 to calculate boundbox */ +static void bound_boxf(Boxf *box, const float v1[3]) +{ + if (v1[0] < box->xmin) box->xmin = v1[0]; + if (v1[0] > box->xmax) box->xmax = v1[0]; + if (v1[1] < box->ymin) box->ymin = v1[1]; + if (v1[1] > box->ymax) box->ymax = v1[1]; + if (v1[2] < box->zmin) box->zmin= v1[2]; + if (v1[2] > box->zmax) box->zmax= v1[2]; +} + +/* use v1 to calculate boundbox */ +static void bound_rectf(rctf *box, const float v1[2]) +{ + if (v1[0] < box->xmin) box->xmin = v1[0]; + if (v1[0] > box->xmax) box->xmax = v1[0]; + if (v1[1] < box->ymin) box->ymin = v1[1]; + if (v1[1] > box->ymax) box->ymax = v1[1]; +} + + +/* halfway splitting, for initializing a more regular tree */ +static void isb_bsp_split_init(ISBBranch *root, MemArena *mem, int level) +{ + + /* if level > 0 we create new branches and go deeper */ + if (level > 0) { + ISBBranch *left, *right; + int i; + + /* splitpoint */ + root->divider[0]= 0.5f*(root->box.xmin+root->box.xmax); + root->divider[1]= 0.5f*(root->box.ymin+root->box.ymax); + + /* find best splitpoint */ + if (RCT_SIZE_X(&root->box) > RCT_SIZE_Y(&root->box)) + i = root->index = 0; + else + i = root->index = 1; + + left= root->left= BLI_memarena_alloc(mem, sizeof(ISBBranch)); + right= root->right= BLI_memarena_alloc(mem, sizeof(ISBBranch)); + + /* box info */ + left->box= root->box; + right->box= root->box; + if (i==0) { + left->box.xmax = root->divider[0]; + right->box.xmin = root->divider[0]; + } + else { + left->box.ymax = root->divider[1]; + right->box.ymin = root->divider[1]; + } + isb_bsp_split_init(left, mem, level-1); + isb_bsp_split_init(right, mem, level-1); + } + else { + /* we add sample array */ + root->samples= BLI_memarena_alloc(mem, BSPMAX_SAMPLE*sizeof(void *)); + } +} + +/* note; if all samples on same location we just spread them over 2 new branches */ +static void isb_bsp_split(ISBBranch *root, MemArena *mem) +{ + ISBBranch *left, *right; + ISBSample *samples[BSPMAX_SAMPLE]; + int a, i; + + /* splitpoint */ + root->divider[0]= root->divider[1]= 0.0f; + for (a=BSPMAX_SAMPLE-1; a>=0; a--) { + root->divider[0]+= root->samples[a]->zco[0]; + root->divider[1]+= root->samples[a]->zco[1]; + } + root->divider[0]/= BSPMAX_SAMPLE; + root->divider[1]/= BSPMAX_SAMPLE; + + /* find best splitpoint */ + if (RCT_SIZE_X(&root->box) > RCT_SIZE_Y(&root->box)) + i = root->index = 0; + else + i = root->index = 1; + + /* new branches */ + left= root->left= BLI_memarena_alloc(mem, sizeof(ISBBranch)); + right= root->right= BLI_memarena_alloc(mem, sizeof(ISBBranch)); + + /* new sample array */ + left->samples = BLI_memarena_alloc(mem, BSPMAX_SAMPLE*sizeof(void *)); + right->samples = samples; /* tmp */ + + /* split samples */ + for (a=BSPMAX_SAMPLE-1; a>=0; a--) { + int comp= 0; + /* this prevents adding samples all to 1 branch when divider is equal to samples */ + if (root->samples[a]->zco[i] == root->divider[i]) + comp= a & 1; + else if (root->samples[a]->zco[i] < root->divider[i]) + comp= 1; + + if (comp==1) { + left->samples[left->totsamp]= root->samples[a]; + left->totsamp++; + } + else { + right->samples[right->totsamp]= root->samples[a]; + right->totsamp++; + } + } + + /* copy samples from tmp */ + memcpy(root->samples, samples, right->totsamp*(sizeof(void *))); + right->samples= root->samples; + root->samples= NULL; + + /* box info */ + left->box= root->box; + right->box= root->box; + if (i==0) { + left->box.xmax = root->divider[0]; + right->box.xmin = root->divider[0]; + } + else { + left->box.ymax = root->divider[1]; + right->box.ymin = root->divider[1]; + } +} + +/* inserts sample in main tree, also splits on threshold */ +/* returns 1 if error */ +static int isb_bsp_insert(ISBBranch *root, MemArena *memarena, ISBSample *sample) +{ + ISBBranch *bspn= root; + const float *zco= sample->zco; + int i= 0; + + /* debug counter, also used to check if something was filled in ever */ + root->totsamp++; + + /* going over branches until last one found */ + while (bspn->left) { + if (zco[bspn->index] <= bspn->divider[bspn->index]) + bspn= bspn->left; + else + bspn= bspn->right; + i++; + } + /* bspn now is the last branch */ + + if (bspn->totsamp==BSPMAX_SAMPLE) { + printf("error in bsp branch\n"); /* only for debug, cannot happen */ + return 1; + } + + /* insert */ + bspn->samples[bspn->totsamp]= sample; + bspn->totsamp++; + + /* split if allowed and needed */ + if (bspn->totsamp==BSPMAX_SAMPLE) { + if (i==BSPMAX_DEPTH) { + bspn->totsamp--; /* stop filling in... will give errors */ + return 1; + } + isb_bsp_split(bspn, memarena); + } + return 0; +} + +/* initialize vars in face, for optimal point-in-face test */ +static void bspface_init_strand(BSPFace *face) +{ + + face->radline= 0.5f* len_v2v2(face->v1, face->v2); + + mid_v3_v3v3(face->vec1, face->v1, face->v2); + if (face->v4) + mid_v3_v3v3(face->vec2, face->v3, face->v4); + else + copy_v3_v3(face->vec2, face->v3); + + face->rc[0]= face->vec2[0]-face->vec1[0]; + face->rc[1]= face->vec2[1]-face->vec1[1]; + face->rc[2]= face->vec2[2]-face->vec1[2]; + + face->len= face->rc[0]*face->rc[0]+ face->rc[1]*face->rc[1]; + + if (face->len != 0.0f) { + face->radline_end = face->radline / sqrtf(face->len); + face->len = 1.0f / face->len; + } +} + +/* brought back to a simple 2d case */ +static int point_behind_strand(const float p[3], BSPFace *face) +{ + /* v1 - v2 is radius, v1 - v3 length */ + float dist, rc[2], pt[2]; + + /* using code from dist_to_line_segment_v2(), distance vec to line-piece */ + + if (face->len==0.0f) { + rc[0]= p[0]-face->vec1[0]; + rc[1]= p[1]-face->vec1[1]; + dist = len_v2(rc); + + if (dist < face->radline) + return 1; + } + else { + float lambda= ( face->rc[0]*(p[0]-face->vec1[0]) + face->rc[1]*(p[1]-face->vec1[1]) )*face->len; + + if (lambda > -face->radline_end && lambda < 1.0f+face->radline_end) { + /* hesse for dist: */ + //dist= (float)(fabs( (p[0]-vec2[0])*rc[1] + (p[1]-vec2[1])*rc[0])/len); + + pt[0]= lambda*face->rc[0]+face->vec1[0]; + pt[1]= lambda*face->rc[1]+face->vec1[1]; + + rc[0]= pt[0]-p[0]; + rc[1]= pt[1]-p[1]; + dist = len_v2(rc); + + if (dist < face->radline) { + float zval= face->vec1[2] + lambda*face->rc[2]; + if (p[2] > zval) + return 1; + } + } + } + return 0; +} + + +/* return 1 if inside. code derived from src/parametrizer.c */ +static int point_behind_tria2d(const float p[3], const float v1[3], const float v2[3], const float v3[3]) +{ + float a[2], c[2], h[2], div; + float u, v; + + a[0] = v2[0] - v1[0]; + a[1] = v2[1] - v1[1]; + c[0] = v3[0] - v1[0]; + c[1] = v3[1] - v1[1]; + + div = a[0]*c[1] - a[1]*c[0]; + if (div==0.0f) + return 0; + + h[0] = p[0] - v1[0]; + h[1] = p[1] - v1[1]; + + div = 1.0f/div; + + u = (h[0]*c[1] - h[1]*c[0])*div; + if (u >= 0.0f) { + v = (a[0]*h[1] - a[1]*h[0])*div; + if (v >= 0.0f) { + if ( u + v <= 1.0f) { + /* inside, now check if point p is behind */ + float z= (1.0f-u-v)*v1[2] + u*v2[2] + v*v3[2]; + if (z <= p[2]) + return 1; + } + } + } + + return 0; +} + +#if 0 +/* tested these calls, but it gives inaccuracy, 'side' cannot be found reliably using v3 */ + +/* check if line v1-v2 has all rect points on other side of point v3 */ +static int rect_outside_line(rctf *rect, const float v1[3], const float v2[3], const float v3[3]) +{ + float a, b, c; + int side; + + /* line formula for v1-v2 */ + a= v2[1]-v1[1]; + b= v1[0]-v2[0]; + c= -a*v1[0] - b*v1[1]; + side= a*v3[0] + b*v3[1] + c < 0.0f; + + /* the four quad points */ + if ( side==(rect->xmin*a + rect->ymin*b + c >= 0.0f) ) + if ( side==(rect->xmax*a + rect->ymin*b + c >= 0.0f) ) + if ( side==(rect->xmax*a + rect->ymax*b + c >= 0.0f) ) + if ( side==(rect->xmin*a + rect->ymax*b + c >= 0.0f) ) + return 1; + return 0; +} + +/* check if one of the triangle edges separates all rect points on 1 side */ +static int rect_isect_tria(rctf *rect, const float v1[3], const float v2[3], const float v3[3]) +{ + if (rect_outside_line(rect, v1, v2, v3)) + return 0; + if (rect_outside_line(rect, v2, v3, v1)) + return 0; + if (rect_outside_line(rect, v3, v1, v2)) + return 0; + return 1; +} +#endif + +/* if face overlaps a branch, it executes func. recursive */ +static void isb_bsp_face_inside(ISBBranch *bspn, BSPFace *face) +{ + + /* are we descending? */ + if (bspn->left) { + /* hrmf, the box struct cannot be addressed with index */ + if (bspn->index==0) { + if (face->box.xmin <= bspn->divider[0]) + isb_bsp_face_inside(bspn->left, face); + if (face->box.xmax > bspn->divider[0]) + isb_bsp_face_inside(bspn->right, face); + } + else { + if (face->box.ymin <= bspn->divider[1]) + isb_bsp_face_inside(bspn->left, face); + if (face->box.ymax > bspn->divider[1]) + isb_bsp_face_inside(bspn->right, face); + } + } + else { + /* else: end branch reached */ + int a; + + if (bspn->totsamp==0) return; + + /* check for nodes entirely in shadow, can be skipped */ + if (bspn->totsamp==bspn->full) + return; + + /* if bsp node is entirely in front of face, give up */ + if (bspn->box.zmax < face->box.zmin) + return; + + /* if face boundbox is outside of branch rect, give up */ + if (0==BLI_rctf_isect((rctf *)&face->box, (rctf *)&bspn->box, NULL)) + return; + + /* test all points inside branch */ + for (a=bspn->totsamp-1; a>=0; a--) { + ISBSample *samp= bspn->samples[a]; + + if ((samp->facenr!=face->facenr || samp->obi!=face->obi) && samp->shadfac) { + if (face->box.zmin < samp->zco[2]) { + if (BLI_rctf_isect_pt_v((rctf *)&face->box, samp->zco)) { + int inshadow= 0; + + if (face->type) { + if (point_behind_strand(samp->zco, face)) + inshadow= 1; + } + else if ( point_behind_tria2d(samp->zco, face->v1, face->v2, face->v3)) + inshadow= 1; + else if (face->v4 && point_behind_tria2d(samp->zco, face->v1, face->v3, face->v4)) + inshadow= 1; + + if (inshadow) { + *(samp->shadfac) += face->shad_alpha; + /* optimize; is_full means shad_alpha==4096 */ + if (*(samp->shadfac) >= 4096 || face->is_full) { + bspn->full++; + samp->shadfac= NULL; + } + } + } + } + } + } + } +} + +/* based on available samples, recalculate the bounding box for bsp nodes, recursive */ +static void isb_bsp_recalc_box(ISBBranch *root) +{ + if (root->left) { + isb_bsp_recalc_box(root->left); + isb_bsp_recalc_box(root->right); + } + else if (root->totsamp) { + int a; + + init_box(&root->box); + for (a=root->totsamp-1; a>=0; a--) + bound_boxf(&root->box, root->samples[a]->zco); + } +} + +/* callback function for zbuf clip */ +static void isb_bsp_test_strand(ZSpan *zspan, int obi, int zvlnr, + const float *v1, const float *v2, const float *v3, const float *v4) +{ + BSPFace face; + + face.v1= v1; + face.v2= v2; + face.v3= v3; + face.v4= v4; + face.obi= obi; + face.facenr= zvlnr & ~RE_QUAD_OFFS; + face.type= R_STRAND; + if (R.osa) + face.shad_alpha= (short)ceil(4096.0f*zspan->shad_alpha/(float)R.osa); + else + face.shad_alpha= (short)ceil(4096.0f*zspan->shad_alpha); + + face.is_full= (zspan->shad_alpha==1.0f); + + /* setup boundbox */ + init_box(&face.box); + bound_boxf(&face.box, v1); + bound_boxf(&face.box, v2); + bound_boxf(&face.box, v3); + if (v4) + bound_boxf(&face.box, v4); + + /* optimize values */ + bspface_init_strand(&face); + + isb_bsp_face_inside((ISBBranch *)zspan->rectz, &face); + +} + +/* callback function for zbuf clip */ +static void isb_bsp_test_face(ZSpan *zspan, int obi, int zvlnr, + const float *v1, const float *v2, const float *v3, const float *v4) +{ + BSPFace face; + + face.v1= v1; + face.v2= v2; + face.v3= v3; + face.v4= v4; + face.obi= obi; + face.facenr= zvlnr & ~RE_QUAD_OFFS; + face.type= 0; + if (R.osa) + face.shad_alpha= (short)ceil(4096.0f*zspan->shad_alpha/(float)R.osa); + else + face.shad_alpha= (short)ceil(4096.0f*zspan->shad_alpha); + + face.is_full= (zspan->shad_alpha==1.0f); + + /* setup boundbox */ + init_box(&face.box); + bound_boxf(&face.box, v1); + bound_boxf(&face.box, v2); + bound_boxf(&face.box, v3); + if (v4) + bound_boxf(&face.box, v4); + + isb_bsp_face_inside((ISBBranch *)zspan->rectz, &face); +} + +static int testclip_minmax(const float ho[4], const float minmax[4]) +{ + float wco= ho[3]; + int flag= 0; + + if ( ho[0] > minmax[1]*wco) flag = 1; + else if ( ho[0]< minmax[0]*wco) flag = 2; + + if ( ho[1] > minmax[3]*wco) flag |= 4; + else if ( ho[1]< minmax[2]*wco) flag |= 8; + + return flag; +} + +/* main loop going over all faces and check in bsp overlaps, fill in shadfac values */ +static void isb_bsp_fillfaces(Render *re, LampRen *lar, ISBBranch *root) +{ + ObjectInstanceRen *obi; + ObjectRen *obr; + ShadBuf *shb= lar->shb; + ZSpan zspan, zspanstrand; + VlakRen *vlr= NULL; + Material *ma= NULL; + float minmaxf[4], winmat[4][4]; + int size= shb->size; + int i, a, ok=1, lay= -1; + + /* further optimize, also sets minz maxz */ + isb_bsp_recalc_box(root); + + /* extra clipping for minmax */ + minmaxf[0]= (2.0f*root->box.xmin - size-2.0f)/size; + minmaxf[1]= (2.0f*root->box.xmax - size+2.0f)/size; + minmaxf[2]= (2.0f*root->box.ymin - size-2.0f)/size; + minmaxf[3]= (2.0f*root->box.ymax - size+2.0f)/size; + + if (lar->mode & (LA_LAYER|LA_LAYER_SHADOW)) lay= lar->lay; + + /* (ab)use zspan, since we use zbuffer clipping code */ + zbuf_alloc_span(&zspan, size, size, re->clipcrop); + + zspan.zmulx= ((float)size)/2.0f; + zspan.zmuly= ((float)size)/2.0f; + zspan.zofsx= -0.5f; + zspan.zofsy= -0.5f; + + /* pass on bsp root to zspan */ + zspan.rectz= (int *)root; + + /* filling methods */ + zspanstrand= zspan; + // zspan.zbuflinefunc= zbufline_onlyZ; + zspan.zbuffunc= isb_bsp_test_face; + zspanstrand.zbuffunc= isb_bsp_test_strand; + + for (i=0, obi=re->instancetable.first; obi; i++, obi=obi->next) { + obr= obi->obr; + + if (obi->flag & R_TRANSFORMED) + mul_m4_m4m4(winmat, shb->persmat, obi->mat); + else + copy_m4_m4(winmat, shb->persmat); + + for (a=0; a<obr->totvlak; a++) { + + if ((a & 255)==0) vlr= obr->vlaknodes[a>>8].vlak; + else vlr++; + + /* note, these conditions are copied in shadowbuf_autoclip() */ + if (vlr->mat!= ma) { + ma= vlr->mat; + ok= 1; + if ((ma->mode2 & MA_CASTSHADOW)==0 || (ma->mode & MA_SHADBUF)==0) ok= 0; + if (ma->material_type == MA_TYPE_WIRE) ok= 0; + zspanstrand.shad_alpha= zspan.shad_alpha= ma->shad_alpha; + } + + if (ok && (obi->lay & lay)) { + float hoco[4][4]; + int c1, c2, c3, c4=0; + int d1, d2, d3, d4=0; + int partclip; + + /* create hocos per face, it is while render */ + projectvert(vlr->v1->co, winmat, hoco[0]); d1= testclip_minmax(hoco[0], minmaxf); + projectvert(vlr->v2->co, winmat, hoco[1]); d2= testclip_minmax(hoco[1], minmaxf); + projectvert(vlr->v3->co, winmat, hoco[2]); d3= testclip_minmax(hoco[2], minmaxf); + if (vlr->v4) { + projectvert(vlr->v4->co, winmat, hoco[3]); d4= testclip_minmax(hoco[3], minmaxf); + } + + /* minmax clipping */ + if (vlr->v4) partclip= d1 & d2 & d3 & d4; + else partclip= d1 & d2 & d3; + + if (partclip==0) { + + /* window clipping */ + c1= testclip(hoco[0]); + c2= testclip(hoco[1]); + c3= testclip(hoco[2]); + if (vlr->v4) + c4= testclip(hoco[3]); + + /* ***** NO WIRE YET */ + if (ma->material_type == MA_TYPE_WIRE) { + if (vlr->v4) + zbufclipwire(&zspan, i, a+1, vlr->ec, hoco[0], hoco[1], hoco[2], hoco[3], c1, c2, c3, c4); + else + zbufclipwire(&zspan, i, a+1, vlr->ec, hoco[0], hoco[1], hoco[2], NULL, c1, c2, c3, 0); + } + else if (vlr->v4) { + if (vlr->flag & R_STRAND) + zbufclip4(&zspanstrand, i, a+1, hoco[0], hoco[1], hoco[2], hoco[3], c1, c2, c3, c4); + else + zbufclip4(&zspan, i, a+1, hoco[0], hoco[1], hoco[2], hoco[3], c1, c2, c3, c4); + } + else + zbufclip(&zspan, i, a+1, hoco[0], hoco[1], hoco[2], c1, c2, c3); + + } + } + } + } + + zbuf_free_span(&zspan); +} + +/* returns 1 when the viewpixel is visible in lampbuffer */ +static int viewpixel_to_lampbuf(ShadBuf *shb, ObjectInstanceRen *obi, VlakRen *vlr, float x, float y, float co_r[3]) +{ + float hoco[4], v1[3], nor[3]; + float dface, fac, siz; + + RE_vlakren_get_normal(&R, obi, vlr, nor); + copy_v3_v3(v1, vlr->v1->co); + if (obi->flag & R_TRANSFORMED) + mul_m4_v3(obi->mat, v1); + + /* from shadepixel() */ + dface = dot_v3v3(v1, nor); + hoco[3]= 1.0f; + + /* ortho viewplane cannot intersect using view vector originating in (0, 0, 0) */ + if (R.r.mode & R_ORTHO) { + /* x and y 3d coordinate can be derived from pixel coord and winmat */ + float fx= 2.0f/(R.winx*R.winmat[0][0]); + float fy= 2.0f/(R.winy*R.winmat[1][1]); + + hoco[0]= (x - 0.5f*R.winx)*fx - R.winmat[3][0]/R.winmat[0][0]; + hoco[1]= (y - 0.5f*R.winy)*fy - R.winmat[3][1]/R.winmat[1][1]; + + /* using a*x + b*y + c*z = d equation, (a b c) is normal */ + if (nor[2]!=0.0f) + hoco[2]= (dface - nor[0]*hoco[0] - nor[1]*hoco[1])/nor[2]; + else + hoco[2]= 0.0f; + } + else { + float div, view[3]; + + calc_view_vector(view, x, y); + + div = dot_v3v3(nor, view); + if (div==0.0f) + return 0; + + fac= dface/div; + + hoco[0]= fac*view[0]; + hoco[1]= fac*view[1]; + hoco[2]= fac*view[2]; + } + + /* move 3d vector to lampbuf */ + mul_m4_v4(shb->persmat, hoco); /* rational hom co */ + + /* clip We can test for -1.0/1.0 because of the properties of the + * coordinate transformations. */ + fac = fabsf(hoco[3]); + if (hoco[0]<-fac || hoco[0]>fac) + return 0; + if (hoco[1]<-fac || hoco[1]>fac) + return 0; + if (hoco[2]<-fac || hoco[2]>fac) + return 0; + + siz= 0.5f*(float)shb->size; + co_r[0]= siz*(1.0f+hoco[0]/hoco[3]) -0.5f; + co_r[1]= siz*(1.0f+hoco[1]/hoco[3]) -0.5f; + co_r[2]= ((float)0x7FFFFFFF)*(hoco[2]/hoco[3]); + + /* XXXX bias, much less than normal shadbuf, or do we need a constant? */ + co_r[2] -= 0.05f*shb->bias; + + return 1; +} + +/* storage of shadow results, solid osa and transp case */ +static void isb_add_shadfac(ISBShadfacA **isbsapp, MemArena *mem, int obi, int facenr, short shadfac, short samples) +{ + ISBShadfacA *new; + float shadfacf; + + /* in osa case, the samples were filled in with factor 1.0/R.osa. if fewer samples we have to correct */ + if (R.osa) + shadfacf= ((float)shadfac*R.osa)/(4096.0f*samples); + else + shadfacf= ((float)shadfac)/(4096.0f); + + new= BLI_memarena_alloc(mem, sizeof(ISBShadfacA)); + new->obi= obi; + new->facenr= facenr & ~RE_QUAD_OFFS; + new->shadfac= shadfacf; + if (*isbsapp) + new->next= (*isbsapp); + else + new->next= NULL; + + *isbsapp= new; +} + +/* adding samples, solid case */ +static int isb_add_samples(RenderPart *pa, ISBBranch *root, MemArena *memarena, ISBSample **samplebuf) +{ + int xi, yi, *xcos, *ycos; + int sample, bsp_err= 0; + + /* bsp split doesn't like to handle regular sequences */ + xcos= MEM_mallocN(pa->rectx*sizeof(int), "xcos"); + ycos= MEM_mallocN(pa->recty*sizeof(int), "ycos"); + for (xi=0; xi<pa->rectx; xi++) + xcos[xi]= xi; + for (yi=0; yi<pa->recty; yi++) + ycos[yi]= yi; + BLI_array_randomize(xcos, sizeof(int), pa->rectx, 12345); + BLI_array_randomize(ycos, sizeof(int), pa->recty, 54321); + + for (sample=0; sample<(R.osa?R.osa:1); sample++) { + ISBSample *samp= samplebuf[sample], *samp1; + + for (yi=0; yi<pa->recty; yi++) { + int y= ycos[yi]; + for (xi=0; xi<pa->rectx; xi++) { + int x= xcos[xi]; + samp1= samp + y*pa->rectx + x; + if (samp1->facenr) + bsp_err |= isb_bsp_insert(root, memarena, samp1); + } + if (bsp_err) break; + } + } + + MEM_freeN(xcos); + MEM_freeN(ycos); + + return bsp_err; +} + +/* solid version */ +/* lar->shb, pa->rectz and pa->rectp should exist */ +static void isb_make_buffer(RenderPart *pa, LampRen *lar) +{ + ShadBuf *shb= lar->shb; + ISBData *isbdata; + ISBSample *samp, *samplebuf[16]; /* should be RE_MAX_OSA */ + ISBBranch root; + MemArena *memarena; + intptr_t *rd; + int *recto, *rectp, x, y, sindex, sample, bsp_err=0; + + /* storage for shadow, per thread */ + isbdata= shb->isb_result[pa->thread]; + + /* to map the shi->xs and ys coordinate */ + isbdata->minx= pa->disprect.xmin; + isbdata->miny= pa->disprect.ymin; + isbdata->rectx= pa->rectx; + isbdata->recty= pa->recty; + + /* branches are added using memarena (32k branches) */ + memarena = BLI_memarena_new(0x8000 * sizeof(ISBBranch), "isb arena"); + BLI_memarena_use_calloc(memarena); + + /* samplebuf is in camera view space (pixels) */ + for (sample=0; sample<(R.osa?R.osa:1); sample++) + samplebuf[sample]= MEM_callocN(sizeof(ISBSample)*pa->rectx*pa->recty, "isb samplebuf"); + + /* for end result, ISBSamples point to this in non OSA case, otherwise to pixstruct->shadfac */ + if (R.osa==0) + isbdata->shadfacs= MEM_callocN(pa->rectx*pa->recty*sizeof(short), "isb shadfacs"); + + /* setup bsp root */ + memset(&root, 0, sizeof(ISBBranch)); + root.box.xmin = (float)shb->size; + root.box.ymin = (float)shb->size; + + /* create the sample buffers */ + for (sindex=0, y=0; y<pa->recty; y++) { + for (x=0; x<pa->rectx; x++, sindex++) { + + /* this makes it a long function, but splitting it out would mean 10+ arguments */ + /* first check OSA case */ + if (R.osa) { + rd= pa->rectdaps + sindex; + if (*rd) { + float xs= (float)(x + pa->disprect.xmin); + float ys= (float)(y + pa->disprect.ymin); + + for (sample=0; sample<R.osa; sample++) { + PixStr *ps= (PixStr *)(*rd); + int mask= (1<<sample); + + while (ps) { + if (ps->mask & mask) + break; + ps= ps->next; + } + if (ps && ps->facenr>0) { + ObjectInstanceRen *obi= &R.objectinstance[ps->obi]; + ObjectRen *obr= obi->obr; + VlakRen *vlr= RE_findOrAddVlak(obr, (ps->facenr-1) & RE_QUAD_MASK); + + samp= samplebuf[sample] + sindex; + /* convert image plane pixel location to lamp buffer space */ + if (viewpixel_to_lampbuf(shb, obi, vlr, xs + R.jit[sample][0], ys + R.jit[sample][1], samp->zco)) { + samp->obi= ps->obi; + samp->facenr= ps->facenr & ~RE_QUAD_OFFS; + ps->shadfac= 0; + samp->shadfac= &ps->shadfac; + bound_rectf((rctf *)&root.box, samp->zco); + } + } + } + } + } + else { + rectp= pa->rectp + sindex; + recto= pa->recto + sindex; + if (*rectp>0) { + ObjectInstanceRen *obi= &R.objectinstance[*recto]; + ObjectRen *obr= obi->obr; + VlakRen *vlr= RE_findOrAddVlak(obr, (*rectp-1) & RE_QUAD_MASK); + float xs= (float)(x + pa->disprect.xmin); + float ys= (float)(y + pa->disprect.ymin); + + samp= samplebuf[0] + sindex; + /* convert image plane pixel location to lamp buffer space */ + if (viewpixel_to_lampbuf(shb, obi, vlr, xs, ys, samp->zco)) { + samp->obi= *recto; + samp->facenr= *rectp & ~RE_QUAD_OFFS; + samp->shadfac= isbdata->shadfacs + sindex; + bound_rectf((rctf *)&root.box, samp->zco); + } + } + } + } + } + + /* simple method to see if we have samples */ + if (root.box.xmin != (float)shb->size) { + /* now create a regular split, root.box has the initial bounding box of all pixels */ + /* split bsp 8 levels deep, in regular grid (16 x 16) */ + isb_bsp_split_init(&root, memarena, 8); + + /* insert all samples in BSP now */ + bsp_err= isb_add_samples(pa, &root, memarena, samplebuf); + + if (bsp_err==0) { + /* go over all faces and fill in shadow values */ + + isb_bsp_fillfaces(&R, lar, &root); /* shb->persmat should have been calculated */ + + /* copy shadow samples to persistent buffer, reduce memory overhead */ + if (R.osa) { + ISBShadfacA **isbsa= isbdata->shadfaca= MEM_callocN(pa->rectx*pa->recty*sizeof(void *), "isb shadfacs"); + + isbdata->memarena = BLI_memarena_new(0x8000 * sizeof(ISBSampleA), "isb arena"); + BLI_memarena_use_calloc(isbdata->memarena); + + for (rd= pa->rectdaps, x=pa->rectx*pa->recty; x>0; x--, rd++, isbsa++) { + + if (*rd) { + PixStr *ps= (PixStr *)(*rd); + while (ps) { + if (ps->shadfac) + isb_add_shadfac(isbsa, isbdata->memarena, ps->obi, ps->facenr, ps->shadfac, count_mask(ps->mask)); + ps= ps->next; + } + } + } + } + } + } + else { + if (isbdata->shadfacs) { + MEM_freeN(isbdata->shadfacs); + isbdata->shadfacs= NULL; + } + } + + /* free BSP */ + BLI_memarena_free(memarena); + + /* free samples */ + for (x=0; x<(R.osa?R.osa:1); x++) + MEM_freeN(samplebuf[x]); + + if (bsp_err) printf("error in filling bsp\n"); +} + +/* add sample to buffer, isbsa is the root sample in a buffer */ +static ISBSampleA *isb_alloc_sample_transp(ISBSampleA **isbsa, MemArena *mem) +{ + ISBSampleA *new; + + new= BLI_memarena_alloc(mem, sizeof(ISBSampleA)); + if (*isbsa) + new->next= (*isbsa); + else + new->next= NULL; + + *isbsa= new; + return new; +} + +/* adding samples in BSP, transparent case */ +static int isb_add_samples_transp(RenderPart *pa, ISBBranch *root, MemArena *memarena, ISBSampleA ***samplebuf) +{ + int xi, yi, *xcos, *ycos; + int sample, bsp_err= 0; + + /* bsp split doesn't like to handle regular sequences */ + xcos= MEM_mallocN(pa->rectx*sizeof(int), "xcos"); + ycos= MEM_mallocN(pa->recty*sizeof(int), "ycos"); + for (xi=0; xi<pa->rectx; xi++) + xcos[xi]= xi; + for (yi=0; yi<pa->recty; yi++) + ycos[yi]= yi; + BLI_array_randomize(xcos, sizeof(int), pa->rectx, 12345); + BLI_array_randomize(ycos, sizeof(int), pa->recty, 54321); + + for (sample=0; sample<(R.osa?R.osa:1); sample++) { + ISBSampleA **samp= samplebuf[sample], *samp1; + + for (yi=0; yi<pa->recty; yi++) { + int y= ycos[yi]; + for (xi=0; xi<pa->rectx; xi++) { + int x= xcos[xi]; + + samp1= *(samp + y*pa->rectx + x); + while (samp1) { + bsp_err |= isb_bsp_insert(root, memarena, (ISBSample *)samp1); + samp1= samp1->next; + } + } + if (bsp_err) break; + } + } + + MEM_freeN(xcos); + MEM_freeN(ycos); + + return bsp_err; +} + + +/* Ztransp version */ +/* lar->shb, pa->rectz and pa->rectp should exist */ +static void isb_make_buffer_transp(RenderPart *pa, APixstr *apixbuf, LampRen *lar) +{ + ShadBuf *shb= lar->shb; + ISBData *isbdata; + ISBSampleA *samp, **samplebuf[16]; /* MAX_OSA */ + ISBBranch root; + MemArena *memarena; + APixstr *ap; + int x, y, sindex, sample, bsp_err=0; + + /* storage for shadow, per thread */ + isbdata= shb->isb_result[pa->thread]; + + /* to map the shi->xs and ys coordinate */ + isbdata->minx= pa->disprect.xmin; + isbdata->miny= pa->disprect.ymin; + isbdata->rectx= pa->rectx; + isbdata->recty= pa->recty; + + /* branches are added using memarena (32k branches) */ + memarena = BLI_memarena_new(0x8000 * sizeof(ISBBranch), "isb arena"); + BLI_memarena_use_calloc(memarena); + + /* samplebuf is in camera view space (pixels) */ + for (sample=0; sample<(R.osa?R.osa:1); sample++) + samplebuf[sample]= MEM_callocN(sizeof(void *)*pa->rectx*pa->recty, "isb alpha samplebuf"); + + /* setup bsp root */ + memset(&root, 0, sizeof(ISBBranch)); + root.box.xmin = (float)shb->size; + root.box.ymin = (float)shb->size; + + /* create the sample buffers */ + for (ap= apixbuf, sindex=0, y=0; y<pa->recty; y++) { + for (x=0; x<pa->rectx; x++, sindex++, ap++) { + + if (ap->p[0]) { + APixstr *apn; + float xs= (float)(x + pa->disprect.xmin); + float ys= (float)(y + pa->disprect.ymin); + + for (apn=ap; apn; apn= apn->next) { + int a; + for (a=0; a<4; a++) { + if (apn->p[a]) { + ObjectInstanceRen *obi= &R.objectinstance[apn->obi[a]]; + ObjectRen *obr= obi->obr; + VlakRen *vlr= RE_findOrAddVlak(obr, (apn->p[a]-1) & RE_QUAD_MASK); + float zco[3]; + + /* here we store shadfac, easier to create the end storage buffer. needs zero'ed, multiple shadowbufs use it */ + apn->shadfac[a]= 0; + + if (R.osa) { + for (sample=0; sample<R.osa; sample++) { + int mask= (1<<sample); + + if (apn->mask[a] & mask) { + + /* convert image plane pixel location to lamp buffer space */ + if (viewpixel_to_lampbuf(shb, obi, vlr, xs + R.jit[sample][0], ys + R.jit[sample][1], zco)) { + samp= isb_alloc_sample_transp(samplebuf[sample] + sindex, memarena); + samp->obi= apn->obi[a]; + samp->facenr= apn->p[a] & ~RE_QUAD_OFFS; + samp->shadfac= &apn->shadfac[a]; + + copy_v3_v3(samp->zco, zco); + bound_rectf((rctf *)&root.box, samp->zco); + } + } + } + } + else { + + /* convert image plane pixel location to lamp buffer space */ + if (viewpixel_to_lampbuf(shb, obi, vlr, xs, ys, zco)) { + + samp= isb_alloc_sample_transp(samplebuf[0] + sindex, memarena); + samp->obi= apn->obi[a]; + samp->facenr= apn->p[a] & ~RE_QUAD_OFFS; + samp->shadfac= &apn->shadfac[a]; + + copy_v3_v3(samp->zco, zco); + bound_rectf((rctf *)&root.box, samp->zco); + } + } + } + } + } + } + } + } + + /* simple method to see if we have samples */ + if (root.box.xmin != (float)shb->size) { + /* now create a regular split, root.box has the initial bounding box of all pixels */ + /* split bsp 8 levels deep, in regular grid (16 x 16) */ + isb_bsp_split_init(&root, memarena, 8); + + /* insert all samples in BSP now */ + bsp_err= isb_add_samples_transp(pa, &root, memarena, samplebuf); + + if (bsp_err==0) { + ISBShadfacA **isbsa; + + /* go over all faces and fill in shadow values */ + isb_bsp_fillfaces(&R, lar, &root); /* shb->persmat should have been calculated */ + + /* copy shadow samples to persistent buffer, reduce memory overhead */ + isbsa= isbdata->shadfaca= MEM_callocN(pa->rectx*pa->recty*sizeof(void *), "isb shadfacs"); + + isbdata->memarena = BLI_memarena_new(0x8000 * sizeof(ISBSampleA), "isb arena"); + + for (ap= apixbuf, x=pa->rectx*pa->recty; x>0; x--, ap++, isbsa++) { + + if (ap->p[0]) { + APixstr *apn; + for (apn=ap; apn; apn= apn->next) { + int a; + for (a=0; a<4; a++) { + if (apn->p[a] && apn->shadfac[a]) { + if (R.osa) + isb_add_shadfac(isbsa, isbdata->memarena, apn->obi[a], apn->p[a], apn->shadfac[a], count_mask(apn->mask[a])); + else + isb_add_shadfac(isbsa, isbdata->memarena, apn->obi[a], apn->p[a], apn->shadfac[a], 0); + } + } + } + } + } + } + } + + /* free BSP */ + BLI_memarena_free(memarena); + + /* free samples */ + for (x=0; x<(R.osa?R.osa:1); x++) + MEM_freeN(samplebuf[x]); + + if (bsp_err) printf("error in filling bsp\n"); +} + + + +/* exported */ + +/* returns amount of light (1.0 = no shadow) */ +/* note, shadepixel() rounds the coordinate, not the real sample info */ +float ISB_getshadow(ShadeInput *shi, ShadBuf *shb) +{ + /* if raytracing, we can't accept irregular shadow */ + if (shi->depth==0) { + ISBData *isbdata= shb->isb_result[shi->thread]; + + if (isbdata) { + if (isbdata->shadfacs || isbdata->shadfaca) { + int x= shi->xs - isbdata->minx; + + if (x >= 0 && x < isbdata->rectx) { + int y= shi->ys - isbdata->miny; + + if (y >= 0 && y < isbdata->recty) { + if (isbdata->shadfacs) { + const short *sp= isbdata->shadfacs + y*isbdata->rectx + x; + return *sp>=4096?0.0f:1.0f - ((float)*sp)/4096.0f; + } + else { + int sindex= y*isbdata->rectx + x; + int obi= shi->obi - R.objectinstance; + ISBShadfacA *isbsa= *(isbdata->shadfaca + sindex); + + while (isbsa) { + if (isbsa->facenr==shi->facenr+1 && isbsa->obi==obi) + return isbsa->shadfac>=1.0f?0.0f:1.0f - isbsa->shadfac; + isbsa= isbsa->next; + } + } + } + } + } + } + } + return 1.0f; +} + +/* part is supposed to be solid zbuffered (apixbuf==NULL) or transparent zbuffered */ +void ISB_create(RenderPart *pa, APixstr *apixbuf) +{ + GroupObject *go; + + /* go over all lamps, and make the irregular buffers */ + for (go=R.lights.first; go; go= go->next) { + LampRen *lar= go->lampren; + + if (lar->type==LA_SPOT && lar->shb && lar->buftype==LA_SHADBUF_IRREGULAR) { + + /* create storage for shadow, per thread */ + lar->shb->isb_result[pa->thread]= MEM_callocN(sizeof(ISBData), "isb data"); + + if (apixbuf) + isb_make_buffer_transp(pa, apixbuf, lar); + else + isb_make_buffer(pa, lar); + } + } +} + + +/* end of part rendering, free stored shadow data for this thread from all lamps */ +void ISB_free(RenderPart *pa) +{ + GroupObject *go; + + /* go over all lamps, and free the irregular buffers */ + for (go=R.lights.first; go; go= go->next) { + LampRen *lar= go->lampren; + + if (lar->type==LA_SPOT && lar->shb && lar->buftype==LA_SHADBUF_IRREGULAR) { + ISBData *isbdata= lar->shb->isb_result[pa->thread]; + + if (isbdata) { + if (isbdata->shadfacs) + MEM_freeN(isbdata->shadfacs); + if (isbdata->shadfaca) + MEM_freeN(isbdata->shadfaca); + + if (isbdata->memarena) + BLI_memarena_free(isbdata->memarena); + + MEM_freeN(isbdata); + lar->shb->isb_result[pa->thread]= NULL; + } + } + } +} diff --git a/source/blender/render/intern/source/shadeinput.c b/source/blender/render/intern/source/shadeinput.c new file mode 100644 index 00000000000..d79749871c3 --- /dev/null +++ b/source/blender/render/intern/source/shadeinput.c @@ -0,0 +1,1490 @@ +/* + * ***** 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) 2006 Blender Foundation + * All rights reserved. + * + * Contributors: Hos, Robert Wenzlaff. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/render/intern/source/shadeinput.c + * \ingroup render + */ + + +#include <stdio.h> +#include <math.h> +#include <string.h> + + +#include "BLI_math.h" +#include "BLI_utildefines.h" + +#include "DNA_lamp_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_material_types.h" +#include "DNA_particle_types.h" + +#include "BKE_scene.h" + +#include "BKE_node.h" + +/* local include */ +#include "raycounter.h" +#include "render_types.h" +#include "renderdatabase.h" +#include "rendercore.h" +#include "shading.h" +#include "strand.h" +#include "texture.h" +#include "volumetric.h" +#include "zbuf.h" + +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ +/* defined in pipeline.c, is hardcopy of active dynamic allocated Render */ +/* only to be used here in this file, it's for speed */ +extern struct Render R; +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ + +/* Shade Sample order: + * + * - shade_samples_fill_with_ps() + * - for each sample + * - shade_input_set_triangle() <- if prev sample-face is same, use shade_input_copy_triangle() + * - if vlr + * - shade_input_set_viewco() <- not for ray or bake + * - shade_input_set_uv() <- not for ray or bake + * - shade_input_set_normals() + * - shade_samples() + * - if AO + * - shade_samples_do_AO() + * - if shading happens + * - for each sample + * - shade_input_set_shade_texco() + * - shade_samples_do_shade() + * - OSA: distribute sample result with filter masking + * + */ + +/* initialize material variables in shadeinput, + * doing inverse gamma correction where applicable */ +void shade_input_init_material(ShadeInput *shi) +{ + /* note, keep this synced with render_types.h */ + memcpy(&shi->r, &shi->mat->r, 23 * sizeof(float)); + shi->har = shi->mat->har; +} + +/* also used as callback for nodes */ +/* delivers a fully filled in ShadeResult, for all passes */ +void shade_material_loop(ShadeInput *shi, ShadeResult *shr) +{ + + shade_lamp_loop(shi, shr); /* clears shr */ + + if (shi->translucency != 0.0f) { + ShadeResult shr_t; + float fac = shi->translucency; + + shade_input_init_material(shi); + negate_v3_v3(shi->vn, shi->vno); + negate_v3(shi->facenor); + shi->depth++; /* hack to get real shadow now */ + shade_lamp_loop(shi, &shr_t); + shi->depth--; + + /* a couple of passes */ + madd_v3_v3fl(shr->combined, shr_t.combined, fac); + if (shi->passflag & SCE_PASS_SPEC) + madd_v3_v3fl(shr->spec, shr_t.spec, fac); + if (shi->passflag & SCE_PASS_DIFFUSE) { + madd_v3_v3fl(shr->diff, shr_t.diff, fac); + madd_v3_v3fl(shr->diffshad, shr_t.diffshad, fac); + } + if (shi->passflag & SCE_PASS_SHADOW) + madd_v3_v3fl(shr->shad, shr_t.shad, fac); + + negate_v3(shi->vn); + negate_v3(shi->facenor); + } + + /* depth >= 1 when ray-shading */ + if (shi->depth == 0 || shi->volume_depth > 0) { + if (R.r.mode & R_RAYTRACE) { + if (shi->ray_mirror != 0.0f || ((shi->mode & MA_TRANSP) && (shi->mode & MA_RAYTRANSP) && shr->alpha != 1.0f)) { + /* ray trace works on combined, but gives pass info */ + ray_trace(shi, shr); + } + } + /* disable adding of sky for raytransp */ + if ((shi->mode & MA_TRANSP) && (shi->mode & MA_RAYTRANSP)) + if ((shi->layflag & SCE_LAY_SKY) && (R.r.alphamode == R_ADDSKY)) + shr->alpha = 1.0f; + } + + if (R.r.mode & R_RAYTRACE) { + if (R.render_volumes_inside.first) + shade_volume_inside(shi, shr); + } +} + + +/* do a shade, finish up some passes, apply mist */ +void shade_input_do_shade(ShadeInput *shi, ShadeResult *shr) +{ + bool compat = false; + float alpha; + + /* ------ main shading loop -------- */ +#ifdef RE_RAYCOUNTER + memset(&shi->raycounter, 0, sizeof(shi->raycounter)); +#endif + + if (shi->mat->nodetree && shi->mat->use_nodes) { + compat = ntreeShaderExecTree(shi->mat->nodetree, shi, shr); + } + + /* also run this when node shaders fail, due to incompatible shader nodes */ + if (compat == false) { + /* copy all relevant material vars, note, keep this synced with render_types.h */ + shade_input_init_material(shi); + + if (shi->mat->material_type == MA_TYPE_VOLUME) { + if (R.r.mode & R_RAYTRACE) { + shade_volume_outside(shi, shr); + } + } + else { /* MA_TYPE_SURFACE, MA_TYPE_WIRE */ + shade_material_loop(shi, shr); + } + } + + /* copy additional passes */ + if (shi->passflag & (SCE_PASS_VECTOR | SCE_PASS_NORMAL)) { + copy_v4_v4(shr->winspeed, shi->winspeed); + copy_v3_v3(shr->nor, shi->vn); + } + + /* MIST */ + if ((shi->passflag & SCE_PASS_MIST) || ((R.wrld.mode & WO_MIST) && (shi->mat->mode & MA_NOMIST) == 0)) { + if (R.r.mode & R_ORTHO) + shr->mist = mistfactor(-shi->co[2], shi->co); + else + shr->mist = mistfactor(len_v3(shi->co), shi->co); + } + else shr->mist = 0.0f; + + if ((R.wrld.mode & WO_MIST) && (shi->mat->mode & MA_NOMIST) == 0) { + alpha = shr->mist; + } + else alpha = 1.0f; + + /* add mist and premul color */ + if (shr->alpha != 1.0f || alpha != 1.0f) { + float fac = alpha * (shr->alpha); + shr->combined[3] = fac; + + if (shi->mat->material_type != MA_TYPE_VOLUME) + mul_v3_fl(shr->combined, fac); + } + else + shr->combined[3] = 1.0f; + + /* add z */ + shr->z = -shi->co[2]; + + /* RAYHITS */ +#if 0 + if (1 || shi->passflag & SCE_PASS_RAYHITS) { + shr->rayhits[0] = (float)shi->raycounter.faces.test; + shr->rayhits[1] = (float)shi->raycounter.bb.hit; + shr->rayhits[2] = 0.0; + shr->rayhits[3] = 1.0; + } +#endif + + RE_RC_MERGE(&re_rc_counter[shi->thread], &shi->raycounter); +} + +/* **************************************************************************** */ +/* ShadeInput */ +/* **************************************************************************** */ + + +void vlr_set_uv_indices(VlakRen *vlr, int *i1, int *i2, int *i3) +{ + /* to prevent storing new tfaces or vcols, we check a split runtime */ + /* 4---3 4---3 */ + /* |\ 1| or |1 /| */ + /* |0\ | |/ 0| */ + /* 1---2 1---2 0 = orig face, 1 = new face */ + + /* Update vert nums to point to correct verts of original face */ + if (vlr->flag & R_DIVIDE_24) { + if (vlr->flag & R_FACE_SPLIT) { + (*i1)++; (*i2)++; (*i3)++; + } + else { + (*i3)++; + } + } + else if (vlr->flag & R_FACE_SPLIT) { + (*i2)++; (*i3)++; + } +} + +/* copy data from face to ShadeInput, general case */ +/* indices 0 1 2 3 only */ +void shade_input_set_triangle_i(ShadeInput *shi, ObjectInstanceRen *obi, VlakRen *vlr, short i1, short i2, short i3) +{ + VertRen **vpp = &vlr->v1; + + shi->vlr = vlr; + shi->obi = obi; + shi->obr = obi->obr; + + shi->v1 = vpp[i1]; + shi->v2 = vpp[i2]; + shi->v3 = vpp[i3]; + + shi->i1 = i1; + shi->i2 = i2; + shi->i3 = i3; + + /* note, shi->mat is set in node shaders */ + shi->mat = shi->mat_override ? shi->mat_override : vlr->mat; + + shi->osatex = (shi->mat->texco & TEXCO_OSA); + shi->mode = shi->mat->mode_l; /* or-ed result for all nodes */ + shi->mode2 = shi->mat->mode2_l; + + /* facenormal copy, can get flipped */ + shi->flippednor = 0; + RE_vlakren_get_normal(&R, obi, vlr, shi->facenor); + + /* calculate vertexnormals */ + if (vlr->flag & R_SMOOTH) { + copy_v3_v3(shi->n1, shi->v1->n); + copy_v3_v3(shi->n2, shi->v2->n); + copy_v3_v3(shi->n3, shi->v3->n); + + if (obi->flag & R_TRANSFORMED) { + mul_m3_v3(obi->nmat, shi->n1); normalize_v3(shi->n1); + mul_m3_v3(obi->nmat, shi->n2); normalize_v3(shi->n2); + mul_m3_v3(obi->nmat, shi->n3); normalize_v3(shi->n3); + } + } +} + +/* copy data from face to ShadeInput, scanline case */ +void shade_input_set_triangle(ShadeInput *shi, int obi, int facenr, int UNUSED(normal_flip)) +{ + if (facenr > 0) { + shi->obi = &R.objectinstance[obi]; + shi->obr = shi->obi->obr; + shi->facenr = (facenr - 1) & RE_QUAD_MASK; + if (shi->facenr < shi->obr->totvlak) { + VlakRen *vlr = RE_findOrAddVlak(shi->obr, shi->facenr); + + if (facenr & RE_QUAD_OFFS) + shade_input_set_triangle_i(shi, shi->obi, vlr, 0, 2, 3); + else + shade_input_set_triangle_i(shi, shi->obi, vlr, 0, 1, 2); + } + else + shi->vlr = NULL; /* general signal we got sky */ + } + else + shi->vlr = NULL; /* general signal we got sky */ +} + +/* full osa case: copy static info */ +void shade_input_copy_triangle(ShadeInput *shi, ShadeInput *from) +{ + /* not so nice, but works... warning is in RE_shader_ext.h */ + memcpy(shi, from, sizeof(struct ShadeInputCopy)); +} + +/* copy data from strand to shadeinput */ +void shade_input_set_strand(ShadeInput *shi, StrandRen *strand, StrandPoint *spoint) +{ + /* note, shi->mat is set in node shaders */ + shi->mat = shi->mat_override ? shi->mat_override : strand->buffer->ma; + + shi->osatex = (shi->mat->texco & TEXCO_OSA); + shi->mode = shi->mat->mode_l; /* or-ed result for all nodes */ + + /* shade_input_set_viewco equivalent */ + copy_v3_v3(shi->co, spoint->co); + copy_v3_v3(shi->view, shi->co); + normalize_v3(shi->view); + + shi->xs = (int)spoint->x; + shi->ys = (int)spoint->y; + + if (shi->osatex || (R.r.mode & R_SHADOW)) { + copy_v3_v3(shi->dxco, spoint->dtco); + copy_v3_v3(shi->dyco, spoint->dsco); + } + + /* dxview, dyview, not supported */ + + /* facenormal, simply viewco flipped */ + copy_v3_v3(shi->facenor, spoint->nor); + + /* shade_input_set_normals equivalent */ + if (shi->mat->mode & MA_TANGENT_STR) { + copy_v3_v3(shi->vn, spoint->tan); + } + else { + float cross[3]; + + cross_v3_v3v3(cross, spoint->co, spoint->tan); + cross_v3_v3v3(shi->vn, cross, spoint->tan); + normalize_v3(shi->vn); + + if (dot_v3v3(shi->vn, shi->view) < 0.0f) + negate_v3(shi->vn); + } + + copy_v3_v3(shi->vno, shi->vn); +} + +void shade_input_set_strand_texco(ShadeInput *shi, StrandRen *strand, StrandVert *svert, StrandPoint *spoint) +{ + StrandBuffer *strandbuf = strand->buffer; + ObjectRen *obr = strandbuf->obr; + StrandVert *sv; + int mode = shi->mode; /* or-ed result for all nodes */ + short texco = shi->mat->texco; + + if ((shi->mat->texco & TEXCO_REFL)) { + /* shi->dxview, shi->dyview, not supported */ + } + + if (shi->osatex && (texco & (TEXCO_NORM | TEXCO_REFL))) { + /* not supported */ + } + + if (mode & (MA_TANGENT_V | MA_NORMAP_TANG)) { + copy_v3_v3(shi->tang, spoint->tan); + copy_v3_v3(shi->nmaptang, spoint->tan); + } + + if (mode & MA_STR_SURFDIFF) { + const float *surfnor = RE_strandren_get_surfnor(obr, strand, 0); + + if (surfnor) + copy_v3_v3(shi->surfnor, surfnor); + else + copy_v3_v3(shi->surfnor, shi->vn); + + if (shi->mat->strand_surfnor > 0.0f) { + shi->surfdist = 0.0f; + for (sv = strand->vert; sv != svert; sv++) + shi->surfdist += len_v3v3(sv->co, (sv + 1)->co); + shi->surfdist += spoint->t * len_v3v3(sv->co, (sv + 1)->co); + } + } + + if (R.r.mode & R_SPEED) { + const float *speed; + + speed = RE_strandren_get_winspeed(shi->obi, strand, 0); + if (speed) + copy_v4_v4(shi->winspeed, speed); + else + shi->winspeed[0] = shi->winspeed[1] = shi->winspeed[2] = shi->winspeed[3] = 0.0f; + } + + /* shade_input_set_shade_texco equivalent */ + if (texco & NEED_UV) { + if (texco & TEXCO_ORCO) { + copy_v3_v3(shi->lo, strand->orco); + /* no shi->osatex, orco derivatives are zero */ + } + + if (texco & TEXCO_GLOB) { + mul_v3_m4v3(shi->gl, R.viewinv, shi->co); + + if (shi->osatex) { + mul_v3_mat3_m4v3(shi->dxgl, R.viewinv, shi->dxco); + mul_v3_mat3_m4v3(shi->dygl, R.viewinv, shi->dyco); + } + } + + if (texco & TEXCO_STRAND) { + shi->strandco = spoint->strandco; + + if (shi->osatex) { + shi->dxstrand = spoint->dtstrandco; + shi->dystrand = 0.0f; + } + } + + if ((texco & TEXCO_UV) || (mode & (MA_VERTEXCOL | MA_VERTEXCOLP | MA_FACETEXTURE))) { + MCol *mcol; + const float *uv; + char *name; + int i; + + shi->totuv = 0; + shi->totcol = 0; + shi->actuv = obr->actmtface; + shi->actcol = obr->actmcol; + + if (mode & (MA_VERTEXCOL | MA_VERTEXCOLP)) { + for (i = 0; (mcol = RE_strandren_get_mcol(obr, strand, i, &name, 0)); i++) { + ShadeInputCol *scol = &shi->col[i]; + const char *cp = (char *)mcol; + + shi->totcol++; + scol->name = name; + + scol->col[0] = cp[3] / 255.0f; + scol->col[1] = cp[2] / 255.0f; + scol->col[2] = cp[1] / 255.0f; + scol->col[3] = cp[0] / 255.0f; + } + + if (shi->totcol) { + shi->vcol[0] = shi->col[shi->actcol].col[0]; + shi->vcol[1] = shi->col[shi->actcol].col[1]; + shi->vcol[2] = shi->col[shi->actcol].col[2]; + shi->vcol[3] = shi->col[shi->actcol].col[3]; + } + else { + shi->vcol[0] = 0.0f; + shi->vcol[1] = 0.0f; + shi->vcol[2] = 0.0f; + shi->vcol[3] = 0.0f; + } + } + + for (i = 0; (uv = RE_strandren_get_uv(obr, strand, i, &name, 0)); i++) { + ShadeInputUV *suv = &shi->uv[i]; + + shi->totuv++; + suv->name = name; + + if (strandbuf->overrideuv == i) { + suv->uv[0] = -1.0f; + suv->uv[1] = spoint->strandco; + suv->uv[2] = 0.0f; + } + else { + suv->uv[0] = -1.0f + 2.0f * uv[0]; + suv->uv[1] = -1.0f + 2.0f * uv[1]; + suv->uv[2] = 0.0f; /* texture.c assumes there are 3 coords */ + } + + if (shi->osatex) { + suv->dxuv[0] = 0.0f; + suv->dxuv[1] = 0.0f; + suv->dyuv[0] = 0.0f; + suv->dyuv[1] = 0.0f; + } + + if ((mode & MA_FACETEXTURE) && i == obr->actmtface) { + if ((mode & (MA_VERTEXCOL | MA_VERTEXCOLP)) == 0) { + shi->vcol[0] = 1.0f; + shi->vcol[1] = 1.0f; + shi->vcol[2] = 1.0f; + shi->vcol[3] = 1.0f; + } + } + } + + if (shi->totuv == 0) { + ShadeInputUV *suv = &shi->uv[0]; + + suv->uv[0] = 0.0f; + suv->uv[1] = spoint->strandco; + suv->uv[2] = 0.0f; /* texture.c assumes there are 3 coords */ + + if (mode & MA_FACETEXTURE) { + /* no tface? set at 1.0f */ + shi->vcol[0] = 1.0f; + shi->vcol[1] = 1.0f; + shi->vcol[2] = 1.0f; + shi->vcol[3] = 1.0f; + } + } + + } + + if (texco & TEXCO_NORM) { + shi->orn[0] = -shi->vn[0]; + shi->orn[1] = -shi->vn[1]; + shi->orn[2] = -shi->vn[2]; + } + + if (texco & TEXCO_STRESS) { + /* not supported */ + } + + if (texco & TEXCO_TANGENT) { + if ((mode & MA_TANGENT_V) == 0) { + /* just prevent surprises */ + shi->tang[0] = shi->tang[1] = shi->tang[2] = 0.0f; + shi->nmaptang[0] = shi->nmaptang[1] = shi->nmaptang[2] = 0.0f; + } + } + } + + /* this only avalailable for scanline renders */ + if (shi->depth == 0) { + if (texco & TEXCO_WINDOW) { + shi->winco[0] = -1.0f + 2.0f * spoint->x / (float)R.winx; + shi->winco[1] = -1.0f + 2.0f * spoint->y / (float)R.winy; + shi->winco[2] = 0.0f; + + /* not supported */ + if (shi->osatex) { + shi->dxwin[0] = 0.0f; + shi->dywin[1] = 0.0f; + shi->dxwin[0] = 0.0f; + shi->dywin[1] = 0.0f; + } + } + } + + if (shi->do_manage) { + if (mode & (MA_VERTEXCOL | MA_VERTEXCOLP | MA_FACETEXTURE)) { + srgb_to_linearrgb_v3_v3(shi->vcol, shi->vcol); + } + } + +} + +/* from scanline pixel coordinates to 3d coordinates, requires set_triangle */ +void shade_input_calc_viewco(ShadeInput *shi, float x, float y, float z, float view[3], float dxyview[2], float co[3], float dxco[3], float dyco[3]) +{ + /* returns not normalized, so is in viewplane coords */ + calc_view_vector(view, x, y); + + if (shi->mat->material_type == MA_TYPE_WIRE) { + /* wire cannot use normal for calculating shi->co, so + * we reconstruct the coordinate less accurate */ + if (R.r.mode & R_ORTHO) + calc_renderco_ortho(co, x, y, z); + else + calc_renderco_zbuf(co, view, z); + } + else { + /* for non-wire, intersect with the triangle to get the exact coord */ + float fac, dface, v1[3]; + + copy_v3_v3(v1, shi->v1->co); + if (shi->obi->flag & R_TRANSFORMED) + mul_m4_v3(shi->obi->mat, v1); + + dface = dot_v3v3(v1, shi->facenor); + + /* ortho viewplane cannot intersect using view vector originating in (0,0,0) */ + if (R.r.mode & R_ORTHO) { + /* x and y 3d coordinate can be derived from pixel coord and winmat */ + float fx = 2.0f / (R.winx * R.winmat[0][0]); + float fy = 2.0f / (R.winy * R.winmat[1][1]); + + co[0] = (x - 0.5f * R.winx) * fx - R.winmat[3][0] / R.winmat[0][0]; + co[1] = (y - 0.5f * R.winy) * fy - R.winmat[3][1] / R.winmat[1][1]; + + /* using a*x + b*y + c*z = d equation, (a b c) is normal */ + if (shi->facenor[2] != 0.0f) + co[2] = (dface - shi->facenor[0] * co[0] - shi->facenor[1] * co[1]) / shi->facenor[2]; + else + co[2] = 0.0f; + + if (dxco && dyco) { + dxco[0] = fx; + dxco[1] = 0.0f; + if (shi->facenor[2] != 0.0f) + dxco[2] = -(shi->facenor[0] * fx) / shi->facenor[2]; + else + dxco[2] = 0.0f; + + dyco[0] = 0.0f; + dyco[1] = fy; + if (shi->facenor[2] != 0.0f) + dyco[2] = -(shi->facenor[1] * fy) / shi->facenor[2]; + else + dyco[2] = 0.0f; + + if (dxyview) { + fac = (co[2] != 0.0f) ? (1.0f / co[2]) : 0.0f; + dxyview[0] = -R.viewdx * fac; + dxyview[1] = -R.viewdy * fac; + } + } + } + else { + float div; + + div = dot_v3v3(shi->facenor, view); + if (div != 0.0f) fac = dface / div; + else fac = 0.0f; + + co[0] = fac * view[0]; + co[1] = fac * view[1]; + co[2] = fac * view[2]; + + /* pixel dx/dy for render coord */ + if (dxco && dyco) { + float u = dface / (div - R.viewdx * shi->facenor[0]); + float v = dface / (div - R.viewdy * shi->facenor[1]); + + dxco[0] = co[0] - (view[0] - R.viewdx) * u; + dxco[1] = co[1] - (view[1]) * u; + dxco[2] = co[2] - (view[2]) * u; + + dyco[0] = co[0] - (view[0]) * v; + dyco[1] = co[1] - (view[1] - R.viewdy) * v; + dyco[2] = co[2] - (view[2]) * v; + + if (dxyview) { + if (fac != 0.0f) fac = 1.0f / fac; + dxyview[0] = -R.viewdx * fac; + dxyview[1] = -R.viewdy * fac; + } + } + } + } + + /* set camera coords - for scanline, it's always 0.0,0.0,0.0 (render is in camera space) + * however for raytrace it can be different - the position of the last intersection */ + shi->camera_co[0] = shi->camera_co[1] = shi->camera_co[2] = 0.0f; + + /* cannot normalize earlier, code above needs it at viewplane level */ + normalize_v3(view); +} + +/* from scanline pixel coordinates to 3d coordinates, requires set_triangle */ +void shade_input_set_viewco(ShadeInput *shi, float x, float y, float xs, float ys, float z) +{ + float *dxyview = NULL, *dxco = NULL, *dyco = NULL; + + /* currently in use for dithering (soft shadow), node preview, irregular shad */ + shi->xs = (int)xs; + shi->ys = (int)ys; + + /* original scanline coordinate without jitter */ + shi->scanco[0] = x; + shi->scanco[1] = y; + shi->scanco[2] = z; + + /* check if we need derivatives */ + if (shi->osatex || (R.r.mode & R_SHADOW)) { + dxco = shi->dxco; + dyco = shi->dyco; + + if ((shi->mat->texco & TEXCO_REFL)) + dxyview = &shi->dxview; + } + + shade_input_calc_viewco(shi, xs, ys, z, shi->view, dxyview, shi->co, dxco, dyco); +} + +void barycentric_differentials_from_position( + const float co[3], const float v1[3], const float v2[3], const float v3[3], + const float dxco[3], const float dyco[3], const float facenor[3], const bool differentials, + float *u, float *v, float *dx_u, float *dx_v, float *dy_u, float *dy_v) +{ + /* find most stable axis to project */ + int axis1, axis2; + axis_dominant_v3(&axis1, &axis2, facenor); + + /* compute u,v and derivatives */ + float t00 = v3[axis1] - v1[axis1]; + float t01 = v3[axis2] - v1[axis2]; + float t10 = v3[axis1] - v2[axis1]; + float t11 = v3[axis2] - v2[axis2]; + + float detsh = (t00 * t11 - t10 * t01); + detsh = (detsh != 0.0f) ? 1.0f / detsh : 0.0f; + t00 *= detsh; t01 *= detsh; + t10 *= detsh; t11 *= detsh; + + *u = (v3[axis1] - co[axis1]) * t11 - (v3[axis2] - co[axis2]) * t10; + *v = (v3[axis2] - co[axis2]) * t00 - (v3[axis1] - co[axis1]) * t01; + if (differentials) { + *dx_u = dxco[axis1] * t11 - dxco[axis2] * t10; + *dx_v = dxco[axis2] * t00 - dxco[axis1] * t01; + *dy_u = dyco[axis1] * t11 - dyco[axis2] * t10; + *dy_v = dyco[axis2] * t00 - dyco[axis1] * t01; + } +} +/* calculate U and V, for scanline (silly render face u and v are in range -1 to 0) */ +void shade_input_set_uv(ShadeInput *shi) +{ + VlakRen *vlr = shi->vlr; + + if ((vlr->flag & R_SMOOTH) || (shi->mat->texco & NEED_UV) || (shi->passflag & SCE_PASS_UV)) { + float v1[3], v2[3], v3[3]; + + copy_v3_v3(v1, shi->v1->co); + copy_v3_v3(v2, shi->v2->co); + copy_v3_v3(v3, shi->v3->co); + + if (shi->obi->flag & R_TRANSFORMED) { + mul_m4_v3(shi->obi->mat, v1); + mul_m4_v3(shi->obi->mat, v2); + mul_m4_v3(shi->obi->mat, v3); + } + + /* exception case for wire render of edge */ + if (vlr->v2 == vlr->v3) { + float lend, lenc; + + lend = len_v3v3(v2, v1); + lenc = len_v3v3(shi->co, v1); + + if (lend == 0.0f) { + shi->u = shi->v = 0.0f; + } + else { + shi->u = -(1.0f - lenc / lend); + shi->v = 0.0f; + } + + if (shi->osatex) { + shi->dx_u = 0.0f; + shi->dx_v = 0.0f; + shi->dy_u = 0.0f; + shi->dy_v = 0.0f; + } + } + else { + barycentric_differentials_from_position( + shi->co, v1, v2, v3, shi->dxco, shi->dyco, shi->facenor, shi->osatex, + &shi->u, &shi->v, &shi->dx_u, &shi->dx_v, &shi->dy_u, &shi->dy_v); + + shi->u = -shi->u; + shi->v = -shi->v; + + /* u and v are in range -1 to 0, we allow a little bit extra but not too much, screws up speedvectors */ + CLAMP(shi->u, -2.0f, 1.0f); + CLAMP(shi->v, -2.0f, 1.0f); + } + } +} + +void shade_input_set_normals(ShadeInput *shi) +{ + float u = shi->u, v = shi->v; + float l = 1.0f + u + v; + + shi->flippednor = 0; + + /* test flip normals to viewing direction */ + if (!(shi->vlr->flag & R_TANGENT)) { + if (dot_v3v3(shi->facenor, shi->view) < 0.0f) { + negate_v3(shi->facenor); + shi->flippednor = 1; + } + } + + /* calculate vertexnormals */ + if (shi->vlr->flag & R_SMOOTH) { + float *n1 = shi->n1, *n2 = shi->n2, *n3 = shi->n3; + + if (shi->flippednor) { + negate_v3(n1); + negate_v3(n2); + negate_v3(n3); + } + + shi->vn[0] = l * n3[0] - u * n1[0] - v * n2[0]; + shi->vn[1] = l * n3[1] - u * n1[1] - v * n2[1]; + shi->vn[2] = l * n3[2] - u * n1[2] - v * n2[2]; + + /* use unnormalized normal (closer to games) */ + copy_v3_v3(shi->nmapnorm, shi->vn); + + normalize_v3(shi->vn); + } + else { + copy_v3_v3(shi->vn, shi->facenor); + copy_v3_v3(shi->nmapnorm, shi->vn); + } + + /* used in nodes */ + copy_v3_v3(shi->vno, shi->vn); + + /* flip normals to viewing direction */ + if (!(shi->vlr->flag & R_TANGENT)) + if (dot_v3v3(shi->facenor, shi->view) < 0.0f) + shade_input_flip_normals(shi); +} + +/* XXX shi->flippednor messes up otherwise */ +void shade_input_set_vertex_normals(ShadeInput *shi) +{ + float u = shi->u, v = shi->v; + float l = 1.0f + u + v; + + /* calculate vertexnormals */ + if (shi->vlr->flag & R_SMOOTH) { + const float *n1 = shi->n1, *n2 = shi->n2, *n3 = shi->n3; + + shi->vn[0] = l * n3[0] - u * n1[0] - v * n2[0]; + shi->vn[1] = l * n3[1] - u * n1[1] - v * n2[1]; + shi->vn[2] = l * n3[2] - u * n1[2] - v * n2[2]; + + /* use unnormalized normal (closer to games) */ + copy_v3_v3(shi->nmapnorm, shi->vn); + + normalize_v3(shi->vn); + } + else { + copy_v3_v3(shi->vn, shi->facenor); + copy_v3_v3(shi->nmapnorm, shi->vn); + } + + /* used in nodes */ + copy_v3_v3(shi->vno, shi->vn); +} + + +/* use by raytrace, sss, bake to flip into the right direction */ +void shade_input_flip_normals(ShadeInput *shi) +{ + negate_v3(shi->facenor); + negate_v3(shi->vn); + negate_v3(shi->vno); + negate_v3(shi->nmapnorm); + shi->flippednor = !shi->flippednor; +} + +void shade_input_set_shade_texco(ShadeInput *shi) +{ + ObjectInstanceRen *obi = shi->obi; + ObjectRen *obr = shi->obr; + VertRen *v1 = shi->v1, *v2 = shi->v2, *v3 = shi->v3; + float u = shi->u, v = shi->v; + float l = 1.0f + u + v, dl; + int mode = shi->mode; /* or-ed result for all nodes */ + int mode2 = shi->mode2; + short texco = shi->mat->texco; + const bool need_mikk_tangent = (mode & MA_NORMAP_TANG || R.flag & R_NEED_TANGENT); + const bool need_mikk_tangent_concrete = (mode2 & MA_TANGENT_CONCRETE) != 0; + + /* calculate dxno */ + if (shi->vlr->flag & R_SMOOTH) { + + if (shi->osatex && (texco & (TEXCO_NORM | TEXCO_REFL)) ) { + const float *n1 = shi->n1, *n2 = shi->n2, *n3 = shi->n3; + + dl = shi->dx_u + shi->dx_v; + shi->dxno[0] = dl * n3[0] - shi->dx_u * n1[0] - shi->dx_v * n2[0]; + shi->dxno[1] = dl * n3[1] - shi->dx_u * n1[1] - shi->dx_v * n2[1]; + shi->dxno[2] = dl * n3[2] - shi->dx_u * n1[2] - shi->dx_v * n2[2]; + dl = shi->dy_u + shi->dy_v; + shi->dyno[0] = dl * n3[0] - shi->dy_u * n1[0] - shi->dy_v * n2[0]; + shi->dyno[1] = dl * n3[1] - shi->dy_u * n1[1] - shi->dy_v * n2[1]; + shi->dyno[2] = dl * n3[2] - shi->dy_u * n1[2] - shi->dy_v * n2[2]; + + } + } + + /* calc tangents */ + if (mode & (MA_TANGENT_V | MA_NORMAP_TANG) || mode2 & MA_TANGENT_CONCRETE || R.flag & R_NEED_TANGENT) { + const float *s1, *s2, *s3; + float tl, tu, tv; + + if (shi->vlr->flag & R_SMOOTH) { + tl = l; + tu = u; + tv = v; + } + else { + /* qdn: flat faces have tangents too, + * could pick either one, using average here */ + tl = 1.0f / 3.0f; + tu = -1.0f / 3.0f; + tv = -1.0f / 3.0f; + } + + shi->tang[0] = shi->tang[1] = shi->tang[2] = 0.0f; + shi->nmaptang[0] = shi->nmaptang[1] = shi->nmaptang[2] = 0.0f; + + if (mode & MA_TANGENT_V) { + s1 = RE_vertren_get_tangent(obr, v1, 0); + s2 = RE_vertren_get_tangent(obr, v2, 0); + s3 = RE_vertren_get_tangent(obr, v3, 0); + + if (s1 && s2 && s3) { + shi->tang[0] = (tl * s3[0] - tu * s1[0] - tv * s2[0]); + shi->tang[1] = (tl * s3[1] - tu * s1[1] - tv * s2[1]); + shi->tang[2] = (tl * s3[2] - tu * s1[2] - tv * s2[2]); + + if (obi->flag & R_TRANSFORMED) + mul_m3_v3(obi->nmat, shi->tang); + + normalize_v3(shi->tang); + copy_v3_v3(shi->nmaptang, shi->tang); + } + } + + if (need_mikk_tangent || need_mikk_tangent_concrete) { + int j1 = shi->i1, j2 = shi->i2, j3 = shi->i3; + float c0[3], c1[3], c2[3]; + int acttang = obr->actmtface; + + vlr_set_uv_indices(shi->vlr, &j1, &j2, &j3); + + /* cycle through all tangent in vlakren */ + for (int i = 0; i < MAX_MTFACE; i++) { + const float *tangent = RE_vlakren_get_nmap_tangent(obr, shi->vlr, i, false); + if (!tangent) + continue; + + copy_v3_v3(c0, &tangent[j1 * 4]); + copy_v3_v3(c1, &tangent[j2 * 4]); + copy_v3_v3(c2, &tangent[j3 * 4]); + + /* keeping tangents normalized at vertex level + * corresponds better to how it's done in game engines */ + if (obi->flag & R_TRANSFORMED) { + mul_mat3_m4_v3(obi->mat, c0); normalize_v3(c0); + mul_mat3_m4_v3(obi->mat, c1); normalize_v3(c1); + mul_mat3_m4_v3(obi->mat, c2); normalize_v3(c2); + } + + /* we don't normalize the interpolated TBN tangent + * corresponds better to how it's done in game engines */ + shi->tangents[i][0] = (tl * c2[0] - tu * c0[0] - tv * c1[0]); + shi->tangents[i][1] = (tl * c2[1] - tu * c0[1] - tv * c1[1]); + shi->tangents[i][2] = (tl * c2[2] - tu * c0[2] - tv * c1[2]); + + /* the sign is the same for all 3 vertices of any + * non degenerate triangle. */ + shi->tangents[i][3] = tangent[j1 * 4 + 3]; + + if (acttang == i && need_mikk_tangent) { + for (int m = 0; m < 4; m++) { + shi->nmaptang[m] = shi->tangents[i][m]; + } + } + } + } + } + + if (mode & MA_STR_SURFDIFF) { + const float *surfnor = RE_vlakren_get_surfnor(obr, shi->vlr, 0); + + if (surfnor) { + copy_v3_v3(shi->surfnor, surfnor); + if (obi->flag & R_TRANSFORMED) + mul_m3_v3(obi->nmat, shi->surfnor); + } + else + copy_v3_v3(shi->surfnor, shi->vn); + + shi->surfdist = 0.0f; + } + + if (R.r.mode & R_SPEED) { + const float *s1, *s2, *s3; + + s1 = RE_vertren_get_winspeed(obi, v1, 0); + s2 = RE_vertren_get_winspeed(obi, v2, 0); + s3 = RE_vertren_get_winspeed(obi, v3, 0); + if (s1 && s2 && s3) { + shi->winspeed[0] = (l * s3[0] - u * s1[0] - v * s2[0]); + shi->winspeed[1] = (l * s3[1] - u * s1[1] - v * s2[1]); + shi->winspeed[2] = (l * s3[2] - u * s1[2] - v * s2[2]); + shi->winspeed[3] = (l * s3[3] - u * s1[3] - v * s2[3]); + } + else { + shi->winspeed[0] = shi->winspeed[1] = shi->winspeed[2] = shi->winspeed[3] = 0.0f; + } + } + + /* pass option forces UV calc */ + if ((shi->passflag & SCE_PASS_UV) || (R.flag & R_NEED_VCOL)) + texco |= (NEED_UV | TEXCO_UV); + + /* texture coordinates. shi->dxuv shi->dyuv have been set */ + if (texco & NEED_UV) { + + if (texco & TEXCO_ORCO) { + if (v1->orco) { + const float *o1, *o2, *o3; + + o1 = v1->orco; + o2 = v2->orco; + o3 = v3->orco; + + shi->lo[0] = l * o3[0] - u * o1[0] - v * o2[0]; + shi->lo[1] = l * o3[1] - u * o1[1] - v * o2[1]; + shi->lo[2] = l * o3[2] - u * o1[2] - v * o2[2]; + + if (shi->osatex) { + dl = shi->dx_u + shi->dx_v; + shi->dxlo[0] = dl * o3[0] - shi->dx_u * o1[0] - shi->dx_v * o2[0]; + shi->dxlo[1] = dl * o3[1] - shi->dx_u * o1[1] - shi->dx_v * o2[1]; + shi->dxlo[2] = dl * o3[2] - shi->dx_u * o1[2] - shi->dx_v * o2[2]; + dl = shi->dy_u + shi->dy_v; + shi->dylo[0] = dl * o3[0] - shi->dy_u * o1[0] - shi->dy_v * o2[0]; + shi->dylo[1] = dl * o3[1] - shi->dy_u * o1[1] - shi->dy_v * o2[1]; + shi->dylo[2] = dl * o3[2] - shi->dy_u * o1[2] - shi->dy_v * o2[2]; + } + } + + copy_v3_v3(shi->duplilo, obi->dupliorco); + } + + if (texco & TEXCO_GLOB) { + copy_v3_v3(shi->gl, shi->co); + mul_m4_v3(R.viewinv, shi->gl); + if (shi->osatex) { + copy_v3_v3(shi->dxgl, shi->dxco); + mul_mat3_m4_v3(R.viewinv, shi->dxgl); + copy_v3_v3(shi->dygl, shi->dyco); + mul_mat3_m4_v3(R.viewinv, shi->dygl); + } + } + + if (texco & TEXCO_STRAND) { + shi->strandco = (l * v3->accum - u * v1->accum - v * v2->accum); + if (shi->osatex) { + dl = shi->dx_u + shi->dx_v; + shi->dxstrand = dl * v3->accum - shi->dx_u * v1->accum - shi->dx_v * v2->accum; + dl = shi->dy_u + shi->dy_v; + shi->dystrand = dl * v3->accum - shi->dy_u * v1->accum - shi->dy_v * v2->accum; + } + } + + if ((texco & TEXCO_UV) || (mode & (MA_VERTEXCOL | MA_VERTEXCOLP | MA_FACETEXTURE)) || (R.flag & R_NEED_VCOL)) { + VlakRen *vlr = shi->vlr; + MTFace *tface; + MCol *mcol; + char *name; + int i, j1 = shi->i1, j2 = shi->i2, j3 = shi->i3; + + /* uv and vcols are not copied on split, so set them according vlr divide flag */ + vlr_set_uv_indices(vlr, &j1, &j2, &j3); + + shi->totuv = 0; + shi->totcol = 0; + shi->actuv = obr->actmtface; + shi->actcol = obr->actmcol; + + if ((mode & (MA_VERTEXCOL | MA_VERTEXCOLP)) || (R.flag & R_NEED_VCOL)) { + for (i = 0; (mcol = RE_vlakren_get_mcol(obr, vlr, i, &name, 0)); i++) { + ShadeInputCol *scol = &shi->col[i]; + const char *cp1, *cp2, *cp3; + float a[3]; + + shi->totcol++; + scol->name = name; + + cp1 = (char *)(mcol + j1); + cp2 = (char *)(mcol + j2); + cp3 = (char *)(mcol + j3); + + /* alpha values */ + a[0] = ((float)cp1[0]) / 255.f; + a[1] = ((float)cp2[0]) / 255.f; + a[2] = ((float)cp3[0]) / 255.f; + scol->col[3] = l * a[2] - u * a[0] - v * a[1]; + + /* sample premultiplied color value */ + scol->col[0] = (l * ((float)cp3[3]) * a[2] - u * ((float)cp1[3]) * a[0] - v * ((float)cp2[3]) * a[1]) / 255.f; + scol->col[1] = (l * ((float)cp3[2]) * a[2] - u * ((float)cp1[2]) * a[0] - v * ((float)cp2[2]) * a[1]) / 255.f; + scol->col[2] = (l * ((float)cp3[1]) * a[2] - u * ((float)cp1[1]) * a[0] - v * ((float)cp2[1]) * a[1]) / 255.f; + + /* if not zero alpha, restore non-multiplied color */ + if (scol->col[3]) { + mul_v3_fl(scol->col, 1.0f / scol->col[3]); + } + } + + if (shi->totcol) { + shi->vcol[0] = shi->col[shi->actcol].col[0]; + shi->vcol[1] = shi->col[shi->actcol].col[1]; + shi->vcol[2] = shi->col[shi->actcol].col[2]; + shi->vcol[3] = shi->col[shi->actcol].col[3]; + } + else { + shi->vcol[0] = 0.0f; + shi->vcol[1] = 0.0f; + shi->vcol[2] = 0.0f; + shi->vcol[3] = 1.0f; + } + } + + for (i = 0; (tface = RE_vlakren_get_tface(obr, vlr, i, &name, 0)); i++) { + ShadeInputUV *suv = &shi->uv[i]; + const float *uv1 = tface->uv[j1]; + const float *uv2 = tface->uv[j2]; + const float *uv3 = tface->uv[j3]; + + shi->totuv++; + suv->name = name; + + if ((shi->mat->mapflag & MA_MAPFLAG_UVPROJECT) && (shi->depth == 0)) { + float x = shi->xs; + float y = shi->ys; + + float s1[2] = {-1.0f + 2.0f * uv1[0], -1.0f + 2.0f * uv1[1]}; + float s2[2] = {-1.0f + 2.0f * uv2[0], -1.0f + 2.0f * uv2[1]}; + float s3[2] = {-1.0f + 2.0f * uv3[0], -1.0f + 2.0f * uv3[1]}; + + + float obwinmat[4][4], winmat[4][4], ho1[4], ho2[4], ho3[4]; + float Zmulx, Zmuly; + float hox, hoy, l_proj, dl_proj, u_proj, v_proj; + float s00, s01, s10, s11, detsh; + + /* old globals, localized now */ + Zmulx = ((float)R.winx) / 2.0f; + Zmuly = ((float)R.winy) / 2.0f; + + zbuf_make_winmat(&R, winmat); + if (shi->obi->flag & R_TRANSFORMED) + mul_m4_m4m4(obwinmat, winmat, obi->mat); + else + copy_m4_m4(obwinmat, winmat); + + zbuf_render_project(obwinmat, v1->co, ho1); + zbuf_render_project(obwinmat, v2->co, ho2); + zbuf_render_project(obwinmat, v3->co, ho3); + + s00 = ho3[0] / ho3[3] - ho1[0] / ho1[3]; + s01 = ho3[1] / ho3[3] - ho1[1] / ho1[3]; + s10 = ho3[0] / ho3[3] - ho2[0] / ho2[3]; + s11 = ho3[1] / ho3[3] - ho2[1] / ho2[3]; + + detsh = s00 * s11 - s10 * s01; + detsh = (detsh != 0.0f) ? 1.0f / detsh : 0.0f; + s00 *= detsh; s01 *= detsh; + s10 *= detsh; s11 *= detsh; + + /* recalc u and v again */ + hox = x / Zmulx - 1.0f; + hoy = y / Zmuly - 1.0f; + u_proj = (hox - ho3[0] / ho3[3]) * s11 - (hoy - ho3[1] / ho3[3]) * s10; + v_proj = (hoy - ho3[1] / ho3[3]) * s00 - (hox - ho3[0] / ho3[3]) * s01; + l_proj = 1.0f + u_proj + v_proj; + + suv->uv[0] = l_proj * s3[0] - u_proj * s1[0] - v_proj * s2[0]; + suv->uv[1] = l_proj * s3[1] - u_proj * s1[1] - v_proj * s2[1]; + suv->uv[2] = 0.0f; + + if (shi->osatex) { + float dxuv[2], dyuv[2]; + dxuv[0] = s11 / Zmulx; + dxuv[1] = -s01 / Zmulx; + dyuv[0] = -s10 / Zmuly; + dyuv[1] = s00 / Zmuly; + + dl_proj = dxuv[0] + dxuv[1]; + suv->dxuv[0] = dl_proj * s3[0] - dxuv[0] * s1[0] - dxuv[1] * s2[0]; + suv->dxuv[1] = dl_proj * s3[1] - dxuv[0] * s1[1] - dxuv[1] * s2[1]; + dl_proj = dyuv[0] + dyuv[1]; + suv->dyuv[0] = dl_proj * s3[0] - dyuv[0] * s1[0] - dyuv[1] * s2[0]; + suv->dyuv[1] = dl_proj * s3[1] - dyuv[0] * s1[1] - dyuv[1] * s2[1]; + } + } + else { + + suv->uv[0] = -1.0f + 2.0f * (l * uv3[0] - u * uv1[0] - v * uv2[0]); + suv->uv[1] = -1.0f + 2.0f * (l * uv3[1] - u * uv1[1] - v * uv2[1]); + suv->uv[2] = 0.0f; /* texture.c assumes there are 3 coords */ + + if (shi->osatex) { + float duv[2]; + + dl = shi->dx_u + shi->dx_v; + duv[0] = shi->dx_u; + duv[1] = shi->dx_v; + + suv->dxuv[0] = 2.0f * (dl * uv3[0] - duv[0] * uv1[0] - duv[1] * uv2[0]); + suv->dxuv[1] = 2.0f * (dl * uv3[1] - duv[0] * uv1[1] - duv[1] * uv2[1]); + + dl = shi->dy_u + shi->dy_v; + duv[0] = shi->dy_u; + duv[1] = shi->dy_v; + + suv->dyuv[0] = 2.0f * (dl * uv3[0] - duv[0] * uv1[0] - duv[1] * uv2[0]); + suv->dyuv[1] = 2.0f * (dl * uv3[1] - duv[0] * uv1[1] - duv[1] * uv2[1]); + } + + if ((mode & MA_FACETEXTURE) && i == obr->actmtface) { + if (((mode & (MA_VERTEXCOL | MA_VERTEXCOLP)) == 0) && ((R.flag & R_NEED_VCOL) == 0)) { + shi->vcol[0] = 1.0f; + shi->vcol[1] = 1.0f; + shi->vcol[2] = 1.0f; + shi->vcol[3] = 1.0f; + } + if (tface->tpage) { + render_realtime_texture(shi, tface->tpage); + } + } + } + } + + shi->dupliuv[0] = -1.0f + 2.0f * obi->dupliuv[0]; + shi->dupliuv[1] = -1.0f + 2.0f * obi->dupliuv[1]; + shi->dupliuv[2] = 0.0f; + + if (shi->totuv == 0) { + ShadeInputUV *suv = &shi->uv[0]; + + suv->uv[0] = 2.0f * (u + .5f); + suv->uv[1] = 2.0f * (v + .5f); + suv->uv[2] = 0.0f; /* texture.c assumes there are 3 coords */ + + if (mode & MA_FACETEXTURE) { + /* no tface? set at 1.0f */ + shi->vcol[0] = 1.0f; + shi->vcol[1] = 1.0f; + shi->vcol[2] = 1.0f; + shi->vcol[3] = 1.0f; + } + } + } + + if (texco & TEXCO_NORM) { + shi->orn[0] = -shi->vn[0]; + shi->orn[1] = -shi->vn[1]; + shi->orn[2] = -shi->vn[2]; + } + + if (texco & TEXCO_STRESS) { + const float *s1, *s2, *s3; + + s1 = RE_vertren_get_stress(obr, v1, 0); + s2 = RE_vertren_get_stress(obr, v2, 0); + s3 = RE_vertren_get_stress(obr, v3, 0); + if (s1 && s2 && s3) { + shi->stress = l * s3[0] - u * s1[0] - v * s2[0]; + if (shi->stress < 1.0f) shi->stress -= 1.0f; + else shi->stress = (shi->stress - 1.0f) / shi->stress; + } + else shi->stress = 0.0f; + } + + if (texco & TEXCO_TANGENT) { + if ((mode & MA_TANGENT_V) == 0) { + /* just prevent surprises */ + shi->tang[0] = shi->tang[1] = shi->tang[2] = 0.0f; + shi->nmaptang[0] = shi->nmaptang[1] = shi->nmaptang[2] = 0.0f; + } + } + } + + /* this only avalailable for scanline renders */ + if (shi->depth == 0) { + float x = shi->xs; + float y = shi->ys; + + if (texco & TEXCO_WINDOW) { + shi->winco[0] = -1.0f + 2.0f * x / (float)R.winx; + shi->winco[1] = -1.0f + 2.0f * y / (float)R.winy; + shi->winco[2] = 0.0f; + if (shi->osatex) { + shi->dxwin[0] = 2.0f / (float)R.winx; + shi->dywin[1] = 2.0f / (float)R.winy; + shi->dxwin[1] = shi->dxwin[2] = 0.0f; + shi->dywin[0] = shi->dywin[2] = 0.0f; + } + } + } + /* else { + * Note! For raytracing winco is not set, + * important because thus means all shader input's need to have their variables set to zero + * else un-initialized values are used + */ + if (shi->do_manage) { + if ((mode & (MA_VERTEXCOL | MA_VERTEXCOLP | MA_FACETEXTURE)) || (R.flag & R_NEED_VCOL)) { + srgb_to_linearrgb_v3_v3(shi->vcol, shi->vcol); + } + } + +} + +/* ****************** ShadeSample ************************************** */ + +/* initialize per part, not per pixel! */ +void shade_input_initialize(ShadeInput *shi, RenderPart *pa, RenderLayer *rl, int sample) +{ + + memset(shi, 0, sizeof(ShadeInput)); + + shi->sample = sample; + shi->thread = pa->thread; + shi->do_preview = (R.r.scemode & R_MATNODE_PREVIEW) != 0; + + shi->do_manage = BKE_scene_check_color_management_enabled(R.scene); + shi->use_world_space_shading = BKE_scene_use_world_space_shading(R.scene); + + shi->lay = rl->lay; + shi->layflag = rl->layflag; + shi->passflag = rl->passflag; + shi->combinedflag = ~rl->pass_xor; + shi->mat_override = rl->mat_override; + shi->light_override = rl->light_override; +// shi->rl= rl; + /* note shi.depth==0 means first hit, not raytracing */ + +} + +/* initialize per part, not per pixel! */ +void shade_sample_initialize(ShadeSample *ssamp, RenderPart *pa, RenderLayer *rl) +{ + int a, tot; + + tot = R.osa == 0 ? 1 : R.osa; + + for (a = 0; a < tot; a++) { + shade_input_initialize(&ssamp->shi[a], pa, rl, a); + memset(&ssamp->shr[a], 0, sizeof(ShadeResult)); + } + + get_sample_layers(pa, rl, ssamp->rlpp); +} + +/* Do AO or (future) GI */ +void shade_samples_do_AO(ShadeSample *ssamp) +{ + if (!(R.r.mode & R_SHADOW)) + return; + if (!(R.r.mode & R_RAYTRACE) && !(R.wrld.ao_gather_method == WO_AOGATHER_APPROX)) + return; + + if (R.wrld.mode & (WO_AMB_OCC | WO_ENV_LIGHT | WO_INDIRECT_LIGHT)) { + ShadeInput *shi = &ssamp->shi[0]; + int sample; + + if (((shi->passflag & SCE_PASS_COMBINED) && (shi->combinedflag & (SCE_PASS_AO | SCE_PASS_ENVIRONMENT | SCE_PASS_INDIRECT))) || + (shi->passflag & (SCE_PASS_AO | SCE_PASS_ENVIRONMENT | SCE_PASS_INDIRECT))) + { + for (sample = 0; sample < ssamp->tot; shi++, sample++) + if (!(shi->mode & MA_SHLESS)) + ambient_occlusion(shi); /* stores in shi->ao[] */ + } + } +} + + +void shade_samples_fill_with_ps(ShadeSample *ssamp, PixStr *ps, int x, int y) +{ + ShadeInput *shi; + float xs, ys; + + ssamp->tot = 0; + + for (shi = ssamp->shi; ps; ps = ps->next) { + shade_input_set_triangle(shi, ps->obi, ps->facenr, 1); + + if (shi->vlr) { /* NULL happens for env material or for 'all z' */ + unsigned short curmask = ps->mask; + + /* full osa is only set for OSA renders */ + if (shi->vlr->flag & R_FULL_OSA) { + short shi_cp = 0, samp; + + for (samp = 0; samp < R.osa; samp++) { + if (curmask & (1 << samp)) { + /* zbuffer has this inverse corrected, ensures xs,ys are inside pixel */ + xs = (float)x + R.jit[samp][0] + 0.5f; + ys = (float)y + R.jit[samp][1] + 0.5f; + + if (shi_cp) + shade_input_copy_triangle(shi, shi - 1); + + shi->mask = (1 << samp); +// shi->rl= ssamp->rlpp[samp]; + shi->samplenr = R.shadowsamplenr[shi->thread]++; /* this counter is not being reset per pixel */ + shade_input_set_viewco(shi, x, y, xs, ys, (float)ps->z); + shade_input_set_uv(shi); + if (shi_cp == 0) + shade_input_set_normals(shi); + else /* XXX shi->flippednor messes up otherwise */ + shade_input_set_vertex_normals(shi); + + shi_cp = 1; + shi++; + } + } + } + else { + if (R.osa) { + short b = R.samples->centmask[curmask]; + xs = (float)x + R.samples->centLut[b & 15] + 0.5f; + ys = (float)y + R.samples->centLut[b >> 4] + 0.5f; + } + else if (R.i.curblur) { + xs= (float)x + R.mblur_jit[R.i.curblur-1][0] + 0.5f; + ys= (float)y + R.mblur_jit[R.i.curblur-1][1] + 0.5f; + } + else { + xs = (float)x + 0.5f; + ys = (float)y + 0.5f; + } + + shi->mask = curmask; + shi->samplenr = R.shadowsamplenr[shi->thread]++; + shade_input_set_viewco(shi, x, y, xs, ys, (float)ps->z); + shade_input_set_uv(shi); + shade_input_set_normals(shi); + shi++; + } + + /* total sample amount, shi->sample is static set in initialize */ + if (shi != ssamp->shi) + ssamp->tot = (shi - 1)->sample + 1; + } + } +} + +/* shades samples, returns true if anything happened */ +int shade_samples(ShadeSample *ssamp, PixStr *ps, int x, int y) +{ + shade_samples_fill_with_ps(ssamp, ps, x, y); + + if (ssamp->tot) { + ShadeInput *shi = ssamp->shi; + ShadeResult *shr = ssamp->shr; + int samp; + + /* if shadow or AO? */ + shade_samples_do_AO(ssamp); + + /* if shade (all shadepinputs have same passflag) */ + if (ssamp->shi[0].passflag & ~(SCE_PASS_Z | SCE_PASS_INDEXOB | SCE_PASS_INDEXMA)) { + + for (samp = 0; samp < ssamp->tot; samp++, shi++, shr++) { + shade_input_set_shade_texco(shi); + shade_input_do_shade(shi, shr); + } + } + else if (shi->passflag & SCE_PASS_Z) { + for (samp = 0; samp < ssamp->tot; samp++, shi++, shr++) + shr->z = -shi->co[2]; + } + + return 1; + } + return 0; +} + diff --git a/source/blender/render/intern/source/shadeoutput.c b/source/blender/render/intern/source/shadeoutput.c new file mode 100644 index 00000000000..090c249defb --- /dev/null +++ b/source/blender/render/intern/source/shadeoutput.c @@ -0,0 +1,2182 @@ +/* + * ***** 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) 2006 Blender Foundation + * All rights reserved. + * + * Contributors: Hos, Robert Wenzlaff. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/render/intern/source/shadeoutput.c + * \ingroup render + */ + +#include <stdio.h> +#include <float.h> +#include <math.h> +#include <string.h> + +#include "BLI_math.h" +#include "BLI_utildefines.h" + +#include "BKE_colorband.h" +#include "BKE_colortools.h" +#include "BKE_material.h" + +#include "DNA_group_types.h" +#include "DNA_lamp_types.h" +#include "DNA_material_types.h" + +/* local include */ +#include "occlusion.h" +#include "render_types.h" +#include "rendercore.h" +#include "shadbuf.h" +#include "sss.h" +#include "texture.h" + +#include "shading.h" /* own include */ + +#include "IMB_colormanagement.h" + +/* could enable at some point but for now there are far too many conversions */ +#ifdef __GNUC__ +# pragma GCC diagnostic ignored "-Wdouble-promotion" +#endif + +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ +/* defined in pipeline.c, is hardcopy of active dynamic allocated Render */ +/* only to be used here in this file, it's for speed */ +extern struct Render R; +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ + +ListBase *get_lights(ShadeInput *shi) +{ + + if (R.r.scemode & R_BUTS_PREVIEW) + return &R.lights; + if (shi->light_override) + return &shi->light_override->gobject; + if (shi->mat && shi->mat->group) + return &shi->mat->group->gobject; + + return &R.lights; +} + +#if 0 +static void fogcolor(const float colf[3], float *rco, float *view) +{ + float alpha, stepsize, startdist, dist, hor[4], zen[3], vec[3], dview[3]; + float div=0.0f, distfac; + + hor[0]= R.wrld.horr; hor[1]= R.wrld.horg; hor[2]= R.wrld.horb; + zen[0]= R.wrld.zenr; zen[1]= R.wrld.zeng; zen[2]= R.wrld.zenb; + + copy_v3_v3(vec, rco); + + /* we loop from cur coord to mist start in steps */ + stepsize= 1.0f; + + div= ABS(view[2]); + dview[0]= view[0]/(stepsize*div); + dview[1]= view[1]/(stepsize*div); + dview[2]= -stepsize; + + startdist= -rco[2] + BLI_frand(); + for (dist= startdist; dist>R.wrld.miststa; dist-= stepsize) { + + hor[0]= R.wrld.horr; hor[1]= R.wrld.horg; hor[2]= R.wrld.horb; + alpha= 1.0f; + do_sky_tex(vec, vec, NULL, hor, zen, &alpha); + + distfac= (dist-R.wrld.miststa)/R.wrld.mistdist; + + hor[3]= hor[0]*distfac*distfac; + + /* premul! */ + alpha= hor[3]; + hor[0]= hor[0]*alpha; + hor[1]= hor[1]*alpha; + hor[2]= hor[2]*alpha; + addAlphaOverFloat(colf, hor); + + sub_v3_v3(vec, dview); + } +} +#endif + +/* zcor is distance, co the 3d coordinate in eye space, return alpha */ +float mistfactor(float zcor, float const co[3]) +{ + float fac, hi; + + fac = zcor - R.wrld.miststa; /* zcor is calculated per pixel */ + + /* fac= -co[2]-R.wrld.miststa; */ + + if (fac > 0.0f) { + if (fac < R.wrld.mistdist) { + + fac = (fac / R.wrld.mistdist); + + if (R.wrld.mistype == 0) { + fac *= fac; + } + else if (R.wrld.mistype == 1) { + /* pass */ + } + else { + fac = sqrtf(fac); + } + } + else { + fac = 1.0f; + } + } + else { + fac = 0.0f; + } + + /* height switched off mist */ + if (R.wrld.misthi!=0.0f && fac!=0.0f) { + /* at height misthi the mist is completely gone */ + + hi = R.viewinv[0][2] * co[0] + + R.viewinv[1][2] * co[1] + + R.viewinv[2][2] * co[2] + + R.viewinv[3][2]; + + if (hi > R.wrld.misthi) { + fac = 0.0f; + } + else if (hi>0.0f) { + hi= (R.wrld.misthi-hi)/R.wrld.misthi; + fac*= hi*hi; + } + } + + return (1.0f-fac)* (1.0f-R.wrld.misi); +} + +static void spothalo(struct LampRen *lar, ShadeInput *shi, float *intens) +{ + double a, b, c, disc, nray[3], npos[3]; + double t0, t1 = 0.0f, t2= 0.0f, t3; + float p1[3], p2[3], ladist, maxz = 0.0f, maxy = 0.0f, haint; + int cuts; + bool do_clip = true, use_yco = false; + + *intens= 0.0f; + haint= lar->haint; + + if (R.r.mode & R_ORTHO) { + /* camera pos (view vector) cannot be used... */ + /* camera position (cox,coy,0) rotate around lamp */ + p1[0]= shi->co[0]-lar->co[0]; + p1[1]= shi->co[1]-lar->co[1]; + p1[2]= -lar->co[2]; + mul_m3_v3(lar->imat, p1); + copy_v3db_v3fl(npos, p1); /* npos is double! */ + + /* pre-scale */ + npos[2] *= (double)lar->sh_zfac; + } + else { + copy_v3db_v3fl(npos, lar->sh_invcampos); /* in initlamp calculated */ + } + + /* rotate view */ + copy_v3db_v3fl(nray, shi->view); + mul_m3_v3_double(lar->imat, nray); + + if (R.wrld.mode & WO_MIST) { + /* patchy... */ + haint *= mistfactor(-lar->co[2], lar->co); + if (haint==0.0f) { + return; + } + } + + + /* rotate maxz */ + if (shi->co[2]==0.0f) { + do_clip = false; /* for when halo at sky */ + } + else { + p1[0]= shi->co[0]-lar->co[0]; + p1[1]= shi->co[1]-lar->co[1]; + p1[2]= shi->co[2]-lar->co[2]; + + maxz= lar->imat[0][2]*p1[0]+lar->imat[1][2]*p1[1]+lar->imat[2][2]*p1[2]; + maxz*= lar->sh_zfac; + maxy= lar->imat[0][1]*p1[0]+lar->imat[1][1]*p1[1]+lar->imat[2][1]*p1[2]; + + if (fabs(nray[2]) < FLT_EPSILON) { + use_yco = true; + } + } + + /* scale z to make sure volume is normalized */ + nray[2] *= (double)lar->sh_zfac; + /* nray does not need normalization */ + + ladist= lar->sh_zfac*lar->dist; + + /* solve */ + a = nray[0] * nray[0] + nray[1] * nray[1] - nray[2]*nray[2]; + b = nray[0] * npos[0] + nray[1] * npos[1] - nray[2]*npos[2]; + c = npos[0] * npos[0] + npos[1] * npos[1] - npos[2]*npos[2]; + + cuts= 0; + if (fabs(a) < DBL_EPSILON) { + /* + * Only one intersection point... + */ + return; + } + else { + disc = b*b - a*c; + + if (disc==0.0) { + t1=t2= (-b)/ a; + cuts= 2; + } + else if (disc > 0.0) { + disc = sqrt(disc); + t1 = (-b + disc) / a; + t2 = (-b - disc) / a; + cuts= 2; + } + } + if (cuts==2) { + int ok1=0, ok2=0; + + /* sort */ + if (t1>t2) { + a= t1; t1= t2; t2= a; + } + + /* z of intersection points with diabolo */ + p1[2]= npos[2] + t1*nray[2]; + p2[2]= npos[2] + t2*nray[2]; + + /* evaluate both points */ + if (p1[2]<=0.0f) ok1= 1; + if (p2[2]<=0.0f && t1!=t2) ok2= 1; + + /* at least 1 point with negative z */ + if (ok1==0 && ok2==0) return; + + /* intersction point with -ladist, the bottom of the cone */ + if (use_yco == false) { + t3= ((double)(-ladist)-npos[2])/nray[2]; + + /* de we have to replace one of the intersection points? */ + if (ok1) { + if (p1[2]<-ladist) t1= t3; + } + else { + t1= t3; + } + if (ok2) { + if (p2[2]<-ladist) t2= t3; + } + else { + t2= t3; + } + } + else if (ok1==0 || ok2==0) return; + + /* at least 1 visible interesction point */ + if (t1<0.0 && t2<0.0) return; + + if (t1<0.0) t1= 0.0; + if (t2<0.0) t2= 0.0; + + if (t1==t2) return; + + /* sort again to be sure */ + if (t1>t2) { + a= t1; t1= t2; t2= a; + } + + /* calculate t0: is the maximum visible z (when halo is intersected by face) */ + if (do_clip) { + if (use_yco == false) t0 = ((double)maxz - npos[2]) / nray[2]; + else t0 = ((double)maxy - npos[1]) / nray[1]; + + if (t0 < t1) return; + if (t0 < t2) t2= t0; + } + + /* calc points */ + p1[0]= npos[0] + t1*nray[0]; + p1[1]= npos[1] + t1*nray[1]; + p1[2]= npos[2] + t1*nray[2]; + p2[0]= npos[0] + t2*nray[0]; + p2[1]= npos[1] + t2*nray[1]; + p2[2]= npos[2] + t2*nray[2]; + + + /* now we have 2 points, make three lengths with it */ + + a = len_v3(p1); + b = len_v3(p2); + c = len_v3v3(p1, p2); + + a/= ladist; + a= sqrt(a); + b/= ladist; + b= sqrt(b); + c/= ladist; + + *intens= c*( (1.0-a)+(1.0-b) ); + + /* WATCH IT: do not clip a,b en c at 1.0, this gives nasty little overflows + * at the edges (especially with narrow halos) */ + if (*intens<=0.0f) return; + + /* soft area */ + /* not needed because t0 has been used for p1/p2 as well */ + /* if (doclip && t0<t2) { */ + /* *intens *= (t0-t1)/(t2-t1); */ + /* } */ + + *intens *= haint; + + if (lar->shb && lar->shb->shadhalostep) { + *intens *= shadow_halo(lar, p1, p2); + } + + } +} + +void renderspothalo(ShadeInput *shi, float col[4], float alpha) +{ + ListBase *lights; + GroupObject *go; + LampRen *lar; + float i; + + if (alpha==0.0f) return; + + lights= get_lights(shi); + for (go=lights->first; go; go= go->next) { + lar= go->lampren; + if (lar==NULL) continue; + + if (lar->type==LA_SPOT && (lar->mode & LA_HALO) && (lar->buftype != LA_SHADBUF_DEEP) && lar->haint>0) { + + if (lar->mode & LA_LAYER) + if (shi->vlr && (lar->lay & shi->obi->lay)==0) + continue; + if ((lar->lay & shi->lay)==0) + continue; + + spothalo(lar, shi, &i); + if (i > 0.0f) { + const float i_alpha = i * alpha; + col[0] += i_alpha * lar->r; + col[1] += i_alpha * lar->g; + col[2] += i_alpha * lar->b; + col[3] += i_alpha; /* all premul */ + } + } + } + /* clip alpha, is needed for unified 'alpha threshold' (vanillaRenderPipe.c) */ + if (col[3]>1.0f) col[3]= 1.0f; +} + + + +/* ---------------- shaders ----------------------- */ + +static double Normalize_d(double *n) +{ + double d; + + d= n[0]*n[0]+n[1]*n[1]+n[2]*n[2]; + + if (d>0.00000000000000001) { + d= sqrt(d); + + n[0]/=d; + n[1]/=d; + n[2]/=d; + } + else { + n[0]=n[1]=n[2]= 0.0; + d= 0.0; + } + return d; +} + +/* mix of 'real' fresnel and allowing control. grad defines blending gradient */ +float fresnel_fac(const float view[3], const float vn[3], float grad, float fac) +{ + float t1, t2; + + if (fac==0.0f) return 1.0f; + + t1 = dot_v3v3(view, vn); + if (t1>0.0f) t2= 1.0f+t1; + else t2= 1.0f-t1; + + t2= grad + (1.0f-grad)*powf(t2, fac); + + if (t2<0.0f) return 0.0f; + else if (t2>1.0f) return 1.0f; + return t2; +} + +static double saacos_d(double fac) +{ + if (fac<= -1.0) return M_PI; + else if (fac>=1.0) return 0.0; + else return acos(fac); +} + +/* Stoke's form factor. Need doubles here for extreme small area sizes */ +static float area_lamp_energy(float (*area)[3], const float co[3], const float vn[3]) +{ + double fac; + double vec[4][3]; /* vectors of rendered co to vertices lamp */ + double cross[4][3]; /* cross products of this */ + double rad[4]; /* angles between vecs */ + + VECSUB(vec[0], co, area[0]); + VECSUB(vec[1], co, area[1]); + VECSUB(vec[2], co, area[2]); + VECSUB(vec[3], co, area[3]); + + Normalize_d(vec[0]); + Normalize_d(vec[1]); + Normalize_d(vec[2]); + Normalize_d(vec[3]); + + /* cross product */ +#define CROSS(dest, a, b) \ + { \ + dest[0]= a[1] * b[2] - a[2] * b[1]; \ + dest[1]= a[2] * b[0] - a[0] * b[2]; \ + dest[2]= a[0] * b[1] - a[1] * b[0]; \ + } (void)0 + + CROSS(cross[0], vec[0], vec[1]); + CROSS(cross[1], vec[1], vec[2]); + CROSS(cross[2], vec[2], vec[3]); + CROSS(cross[3], vec[3], vec[0]); + +#undef CROSS + + Normalize_d(cross[0]); + Normalize_d(cross[1]); + Normalize_d(cross[2]); + Normalize_d(cross[3]); + + /* angles */ + rad[0]= vec[0][0]*vec[1][0]+ vec[0][1]*vec[1][1]+ vec[0][2]*vec[1][2]; + rad[1]= vec[1][0]*vec[2][0]+ vec[1][1]*vec[2][1]+ vec[1][2]*vec[2][2]; + rad[2]= vec[2][0]*vec[3][0]+ vec[2][1]*vec[3][1]+ vec[2][2]*vec[3][2]; + rad[3]= vec[3][0]*vec[0][0]+ vec[3][1]*vec[0][1]+ vec[3][2]*vec[0][2]; + + rad[0]= saacos_d(rad[0]); + rad[1]= saacos_d(rad[1]); + rad[2]= saacos_d(rad[2]); + rad[3]= saacos_d(rad[3]); + + /* Stoke formula */ + fac= rad[0]*(vn[0]*cross[0][0]+ vn[1]*cross[0][1]+ vn[2]*cross[0][2]); + fac+= rad[1]*(vn[0]*cross[1][0]+ vn[1]*cross[1][1]+ vn[2]*cross[1][2]); + fac+= rad[2]*(vn[0]*cross[2][0]+ vn[1]*cross[2][1]+ vn[2]*cross[2][2]); + fac+= rad[3]*(vn[0]*cross[3][0]+ vn[1]*cross[3][1]+ vn[2]*cross[3][2]); + + if (fac<=0.0) return 0.0; + return fac; +} + +static float area_lamp_energy_multisample(LampRen *lar, const float co[3], float *vn) +{ + /* corner vectors are moved around according lamp jitter */ + float *jitlamp= lar->jitter, vec[3]; + float area[4][3], intens= 0.0f; + int a= lar->ray_totsamp; + + /* test if co is behind lamp */ + sub_v3_v3v3(vec, co, lar->co); + if (dot_v3v3(vec, lar->vec) < 0.0f) + return 0.0f; + + while (a--) { + vec[0]= jitlamp[0]; + vec[1]= jitlamp[1]; + vec[2]= 0.0f; + mul_m3_v3(lar->mat, vec); + + add_v3_v3v3(area[0], lar->area[0], vec); + add_v3_v3v3(area[1], lar->area[1], vec); + add_v3_v3v3(area[2], lar->area[2], vec); + add_v3_v3v3(area[3], lar->area[3], vec); + + intens+= area_lamp_energy(area, co, vn); + + jitlamp+= 2; + } + intens /= (float)lar->ray_totsamp; + + return pow(intens * lar->areasize, lar->k); /* corrected for buttons size and lar->dist^2 */ +} + +static float spec(float inp, int hard) +{ + float b1; + + if (inp>=1.0f) return 1.0f; + else if (inp<=0.0f) return 0.0f; + + b1= inp*inp; + /* avoid FPE */ + if (b1<0.01f) b1= 0.01f; + + if ((hard & 1)==0) inp= 1.0f; + if (hard & 2) inp*= b1; + b1*= b1; + if (hard & 4) inp*= b1; + b1*= b1; + if (hard & 8) inp*= b1; + b1*= b1; + if (hard & 16) inp*= b1; + b1*= b1; + + /* avoid FPE */ + if (b1<0.001f) b1= 0.0f; + + if (hard & 32) inp*= b1; + b1*= b1; + if (hard & 64) inp*=b1; + b1*= b1; + if (hard & 128) inp*=b1; + + if (b1<0.001f) b1= 0.0f; + + if (hard & 256) { + b1*= b1; + inp*=b1; + } + + return inp; +} + +static float Phong_Spec(const float n[3], const float l[3], const float v[3], int hard, int tangent ) +{ + float h[3]; + float rslt; + + h[0] = l[0] + v[0]; + h[1] = l[1] + v[1]; + h[2] = l[2] + v[2]; + normalize_v3(h); + + rslt = h[0]*n[0] + h[1]*n[1] + h[2]*n[2]; + if (tangent) rslt= sasqrt(1.0f - rslt*rslt); + + if ( rslt > 0.0f ) rslt= spec(rslt, hard); + else rslt = 0.0f; + + return rslt; +} + + +/* reduced cook torrance spec (for off-specular peak) */ +static float CookTorr_Spec(const float n[3], const float l[3], const float v[3], int hard, int tangent) +{ + float i, nh, nv, h[3]; + + h[0]= v[0]+l[0]; + h[1]= v[1]+l[1]; + h[2]= v[2]+l[2]; + normalize_v3(h); + + nh= n[0]*h[0]+n[1]*h[1]+n[2]*h[2]; + if (tangent) nh= sasqrt(1.0f - nh*nh); + else if (nh<0.0f) return 0.0f; + + nv= n[0]*v[0]+n[1]*v[1]+n[2]*v[2]; + if (tangent) nv= sasqrt(1.0f - nv*nv); + else if (nv<0.0f) nv= 0.0f; + + i= spec(nh, hard); + + i= i/(0.1f+nv); + return i; +} + +/* Blinn spec */ +static float Blinn_Spec(const float n[3], const float l[3], const float v[3], float refrac, float spec_power, int tangent) +{ + float i, nh, nv, nl, vh, h[3]; + float a, b, c, g=0.0f, p, f, ang; + + if (refrac < 1.0f) return 0.0f; + if (spec_power == 0.0f) return 0.0f; + + /* conversion from 'hardness' (1-255) to 'spec_power' (50 maps at 0.1) */ + if (spec_power<100.0f) + spec_power = sqrtf(1.0f / spec_power); + else spec_power= 10.0f/spec_power; + + h[0]= v[0]+l[0]; + h[1]= v[1]+l[1]; + h[2]= v[2]+l[2]; + normalize_v3(h); + + nh= n[0]*h[0]+n[1]*h[1]+n[2]*h[2]; /* Dot product between surface normal and half-way vector */ + if (tangent) nh= sasqrt(1.0f - nh*nh); + else if (nh<0.0f) return 0.0f; + + nv= n[0]*v[0]+n[1]*v[1]+n[2]*v[2]; /* Dot product between surface normal and view vector */ + if (tangent) nv= sasqrt(1.0f - nv*nv); + if (nv<=0.01f) nv= 0.01f; /* hrms... */ + + nl= n[0]*l[0]+n[1]*l[1]+n[2]*l[2]; /* Dot product between surface normal and light vector */ + if (tangent) nl= sasqrt(1.0f - nl*nl); + if (nl<=0.01f) { + return 0.0f; + } + + vh= v[0]*h[0]+v[1]*h[1]+v[2]*h[2]; /* Dot product between view vector and half-way vector */ + if (vh<=0.0f) vh= 0.01f; + + a = 1.0f; + b = (2.0f*nh*nv)/vh; + c = (2.0f*nh*nl)/vh; + + if ( a < b && a < c ) g = a; + else if ( b < a && b < c ) g = b; + else if ( c < a && c < b ) g = c; + + p = sqrt((double)((refrac * refrac)+(vh * vh) - 1.0f)); + f = (((p-vh)*(p-vh))/((p+vh)*(p+vh)))*(1+((((vh*(p+vh))-1.0f)*((vh*(p+vh))-1.0f))/(((vh*(p-vh))+1.0f)*((vh*(p-vh))+1.0f)))); + ang = saacos(nh); + + i= f * g * exp((double)(-(ang*ang) / (2.0f*spec_power*spec_power))); + if (i<0.0f) i= 0.0f; + + return i; +} + +/* cartoon render spec */ +static float Toon_Spec(const float n[3], const float l[3], const float v[3], float size, float smooth, int tangent) +{ + float h[3]; + float ang; + float rslt; + + h[0] = l[0] + v[0]; + h[1] = l[1] + v[1]; + h[2] = l[2] + v[2]; + normalize_v3(h); + + rslt = h[0]*n[0] + h[1]*n[1] + h[2]*n[2]; + if (tangent) rslt = sasqrt(1.0f - rslt*rslt); + + ang = saacos( rslt ); + + if ( ang < size ) rslt = 1.0f; + else if ( ang >= (size + smooth) || smooth == 0.0f ) rslt = 0.0f; + else rslt = 1.0f - ((ang - size) / smooth); + + return rslt; +} + +/* Ward isotropic gaussian spec */ +static float WardIso_Spec(const float n[3], const float l[3], const float v[3], float rms, int tangent) +{ + float i, nh, nv, nl, h[3], angle, alpha; + + + /* half-way vector */ + h[0] = l[0] + v[0]; + h[1] = l[1] + v[1]; + h[2] = l[2] + v[2]; + normalize_v3(h); + + nh = n[0]*h[0]+n[1]*h[1]+n[2]*h[2]; /* Dot product between surface normal and half-way vector */ + if (tangent) nh = sasqrt(1.0f - nh*nh); + if (nh<=0.0f) nh = 0.001f; + + nv = n[0]*v[0]+n[1]*v[1]+n[2]*v[2]; /* Dot product between surface normal and view vector */ + if (tangent) nv = sasqrt(1.0f - nv*nv); + if (nv<=0.0f) nv = 0.001f; + + nl = n[0]*l[0]+n[1]*l[1]+n[2]*l[2]; /* Dot product between surface normal and light vector */ + if (tangent) nl = sasqrt(1.0f - nl*nl); + if (nl<=0.0f) nl = 0.001f; + + angle = tanf(saacos(nh)); + alpha = MAX2(rms, 0.001f); + + i= nl * (1.0f/(4.0f*(float)M_PI*alpha*alpha)) * (expf( -(angle*angle)/(alpha*alpha))/(sqrtf(nv*nl))); + + return i; +} + +/* cartoon render diffuse */ +static float Toon_Diff(const float n[3], const float l[3], const float UNUSED(v[3]), float size, float smooth) +{ + float rslt, ang; + + rslt = n[0]*l[0] + n[1]*l[1] + n[2]*l[2]; + + ang = saacos(rslt); + + if ( ang < size ) rslt = 1.0f; + else if ( ang >= (size + smooth) || smooth == 0.0f ) rslt = 0.0f; + else rslt = 1.0f - ((ang - size) / smooth); + + return rslt; +} + +/* Oren Nayar diffuse */ + +/* 'nl' is either dot product, or return value of area light */ +/* in latter case, only last multiplication uses 'nl' */ +static float OrenNayar_Diff(float nl, const float n[3], const float l[3], const float v[3], float rough ) +{ + float i/*, nh*/, nv /*, vh */, realnl, h[3]; + float a, b, t, A, B; + float Lit_A, View_A, Lit_B[3], View_B[3]; + + h[0]= v[0]+l[0]; + h[1]= v[1]+l[1]; + h[2]= v[2]+l[2]; + normalize_v3(h); + + /* nh= n[0]*h[0]+n[1]*h[1]+n[2]*h[2]; */ /* Dot product between surface normal and half-way vector */ + /* if (nh<0.0f) nh = 0.0f; */ + + nv= n[0]*v[0]+n[1]*v[1]+n[2]*v[2]; /* Dot product between surface normal and view vector */ + if (nv<=0.0f) nv= 0.0f; + + realnl= n[0]*l[0]+n[1]*l[1]+n[2]*l[2]; /* Dot product between surface normal and light vector */ + if (realnl<=0.0f) return 0.0f; + if (nl<0.0f) return 0.0f; /* value from area light */ + + /* vh= v[0]*h[0]+v[1]*h[1]+v[2]*h[2]; */ /* Dot product between view vector and halfway vector */ + /* if (vh<=0.0f) vh= 0.0f; */ + + Lit_A = saacos(realnl); + View_A = saacos( nv ); + + Lit_B[0] = l[0] - (realnl * n[0]); + Lit_B[1] = l[1] - (realnl * n[1]); + Lit_B[2] = l[2] - (realnl * n[2]); + normalize_v3(Lit_B); + + View_B[0] = v[0] - (nv * n[0]); + View_B[1] = v[1] - (nv * n[1]); + View_B[2] = v[2] - (nv * n[2]); + normalize_v3(View_B); + + t = Lit_B[0]*View_B[0] + Lit_B[1]*View_B[1] + Lit_B[2]*View_B[2]; + if ( t < 0 ) t = 0; + + if ( Lit_A > View_A ) { + a = Lit_A; + b = View_A; + } + else { + a = View_A; + b = Lit_A; + } + + A = 1.0f - (0.5f * ((rough * rough) / ((rough * rough) + 0.33f))); + B = 0.45f * ((rough * rough) / ((rough * rough) + 0.09f)); + + b*= 0.95f; /* prevent tangens from shooting to inf, 'nl' can be not a dot product here. */ + /* overflow only happens with extreme size area light, and higher roughness */ + i = nl * ( A + ( B * t * sinf(a) * tanf(b) ) ); + + return i; +} + +/* Minnaert diffuse */ +static float Minnaert_Diff(float nl, const float n[3], const float v[3], float darkness) +{ + float i, nv; + + /* nl = dot product between surface normal and light vector */ + if (nl <= 0.0f) + return 0.0f; + + /* nv = dot product between surface normal and view vector */ + nv = dot_v3v3(n, v); + if (nv < 0.0f) + nv = 0.0f; + + if (darkness <= 1.0f) + i = nl * pow(max_ff(nv * nl, 0.1f), (darkness - 1.0f) ); /*The Real model*/ + else + i = nl * pow( (1.001f - nv), (darkness - 1.0f) ); /*Nvidia model*/ + + return i; +} + +static float Fresnel_Diff(float *vn, float *lv, float *UNUSED(view), float fac_i, float fac) +{ + return fresnel_fac(lv, vn, fac_i, fac); +} + +/* --------------------------------------------- */ +/* also called from texture.c */ +void calc_R_ref(ShadeInput *shi) +{ + float i; + + /* shi->vn dot shi->view */ + i= -2*(shi->vn[0]*shi->view[0]+shi->vn[1]*shi->view[1]+shi->vn[2]*shi->view[2]); + + shi->ref[0]= (shi->view[0]+i*shi->vn[0]); + shi->ref[1]= (shi->view[1]+i*shi->vn[1]); + shi->ref[2]= (shi->view[2]+i*shi->vn[2]); + if (shi->osatex) { + if (shi->vlr->flag & R_SMOOTH) { + i= -2*( (shi->vn[0]+shi->dxno[0])*(shi->view[0]+shi->dxview) + + (shi->vn[1]+shi->dxno[1])*shi->view[1]+ (shi->vn[2]+shi->dxno[2])*shi->view[2] ); + + shi->dxref[0]= shi->ref[0]- ( shi->view[0]+shi->dxview+i*(shi->vn[0]+shi->dxno[0])); + shi->dxref[1]= shi->ref[1]- (shi->view[1]+ i*(shi->vn[1]+shi->dxno[1])); + shi->dxref[2]= shi->ref[2]- (shi->view[2]+ i*(shi->vn[2]+shi->dxno[2])); + + i= -2*( (shi->vn[0]+shi->dyno[0])*shi->view[0]+ + (shi->vn[1]+shi->dyno[1])*(shi->view[1]+shi->dyview)+ (shi->vn[2]+shi->dyno[2])*shi->view[2] ); + + shi->dyref[0]= shi->ref[0]- (shi->view[0]+ i*(shi->vn[0]+shi->dyno[0])); + shi->dyref[1]= shi->ref[1]- (shi->view[1]+shi->dyview+i*(shi->vn[1]+shi->dyno[1])); + shi->dyref[2]= shi->ref[2]- (shi->view[2]+ i*(shi->vn[2]+shi->dyno[2])); + + } + else { + + i= -2*( shi->vn[0]*(shi->view[0]+shi->dxview) + + shi->vn[1]*shi->view[1]+ shi->vn[2]*shi->view[2] ); + + shi->dxref[0]= shi->ref[0]- (shi->view[0]+shi->dxview+i*shi->vn[0]); + shi->dxref[1]= shi->ref[1]- (shi->view[1]+ i*shi->vn[1]); + shi->dxref[2]= shi->ref[2]- (shi->view[2]+ i*shi->vn[2]); + + i= -2*( shi->vn[0]*shi->view[0]+ + shi->vn[1]*(shi->view[1]+shi->dyview)+ shi->vn[2]*shi->view[2] ); + + shi->dyref[0]= shi->ref[0]- (shi->view[0]+ i*shi->vn[0]); + shi->dyref[1]= shi->ref[1]- (shi->view[1]+shi->dyview+i*shi->vn[1]); + shi->dyref[2]= shi->ref[2]- (shi->view[2]+ i*shi->vn[2]); + } + } + +} + +/* called from rayshade.c */ +void shade_color(ShadeInput *shi, ShadeResult *shr) +{ + Material *ma= shi->mat; + + if (ma->mode & (MA_FACETEXTURE)) { + shi->r= shi->vcol[0]; + shi->g= shi->vcol[1]; + shi->b= shi->vcol[2]; + if (ma->mode & (MA_FACETEXTURE_ALPHA)) + shi->alpha= shi->vcol[3]; + } + else if (ma->mode & (MA_VERTEXCOLP)) { + float neg_alpha = 1.0f - shi->vcol[3]; + shi->r= shi->r*neg_alpha + shi->vcol[0]*shi->vcol[3]; + shi->g= shi->g*neg_alpha + shi->vcol[1]*shi->vcol[3]; + shi->b= shi->b*neg_alpha + shi->vcol[2]*shi->vcol[3]; + } + + if (ma->texco) + do_material_tex(shi, &R); + + if (ma->fresnel_tra!=0.0f) + shi->alpha*= fresnel_fac(shi->view, shi->vn, ma->fresnel_tra_i, ma->fresnel_tra); + + if (!(shi->mode & MA_TRANSP)) shi->alpha= 1.0f; + + shr->diff[0]= shi->r; + shr->diff[1]= shi->g; + shr->diff[2]= shi->b; + shr->alpha= shi->alpha; + + /* modulate by the object color */ + if ((ma->shade_flag & MA_OBCOLOR) && shi->obr->ob) { + float obcol[4]; + + copy_v4_v4(obcol, shi->obr->ob->col); + CLAMP(obcol[3], 0.0f, 1.0f); + + shr->diff[0] *= obcol[0]; + shr->diff[1] *= obcol[1]; + shr->diff[2] *= obcol[2]; + if (shi->mode & MA_TRANSP) shr->alpha *= obcol[3]; + } + + copy_v3_v3(shr->diffshad, shr->diff); +} + +/* ramp for at end of shade */ +static void ramp_diffuse_result(float *diff, ShadeInput *shi) +{ + Material *ma= shi->mat; + float col[4]; + + if (ma->ramp_col) { + if (ma->rampin_col==MA_RAMP_IN_RESULT) { + float fac = IMB_colormanagement_get_luminance(diff); + BKE_colorband_evaluate(ma->ramp_col, fac, col); + + /* blending method */ + fac= col[3]*ma->rampfac_col; + + ramp_blend(ma->rampblend_col, diff, fac, col); + } + } +} + +/* r,g,b denote energy, ramp is used with different values to make new material color */ +static void add_to_diffuse(float diff[3], const ShadeInput *shi, const float is, const float rgb[3]) +{ + Material *ma= shi->mat; + + if (ma->ramp_col && (ma->mode & MA_RAMP_COL)) { + + /* MA_RAMP_IN_RESULT is exceptional */ + if (ma->rampin_col==MA_RAMP_IN_RESULT) { + /* normal add */ + diff[0] += rgb[0] * shi->r; + diff[1] += rgb[1] * shi->g; + diff[2] += rgb[2] * shi->b; + } + else { + float colt[3], col[4]; + float fac; + + /* input */ + switch (ma->rampin_col) { + case MA_RAMP_IN_ENERGY: + fac = IMB_colormanagement_get_luminance(rgb); + break; + case MA_RAMP_IN_SHADER: + fac = is; + break; + case MA_RAMP_IN_NOR: + fac = dot_v3v3(shi->view, shi->vn); + break; + default: + fac = 0.0f; + break; + } + + BKE_colorband_evaluate(ma->ramp_col, fac, col); + + /* blending method */ + fac = col[3] * ma->rampfac_col; + copy_v3_v3(colt, &shi->r); + + ramp_blend(ma->rampblend_col, colt, fac, col); + + /* output to */ + diff[0] += rgb[0] * colt[0]; + diff[1] += rgb[1] * colt[1]; + diff[2] += rgb[2] * colt[2]; + } + } + else { + diff[0] += rgb[0] * shi->r; + diff[1] += rgb[1] * shi->g; + diff[2] += rgb[2] * shi->b; + } +} + +static void ramp_spec_result(float spec_col[3], ShadeInput *shi) +{ + Material *ma= shi->mat; + + if (ma->ramp_spec && (ma->rampin_spec==MA_RAMP_IN_RESULT)) { + float col[4]; + float fac = IMB_colormanagement_get_luminance(spec_col); + + BKE_colorband_evaluate(ma->ramp_spec, fac, col); + + /* blending method */ + fac= col[3]*ma->rampfac_spec; + + ramp_blend(ma->rampblend_spec, spec_col, fac, col); + + } +} + +/* is = dot product shade, t = spec energy */ +static void do_specular_ramp(ShadeInput *shi, float is, float t, float spec[3]) +{ + Material *ma= shi->mat; + + spec[0]= shi->specr; + spec[1]= shi->specg; + spec[2]= shi->specb; + + /* MA_RAMP_IN_RESULT is exception */ + if (ma->ramp_spec && (ma->rampin_spec!=MA_RAMP_IN_RESULT)) { + float fac; + float col[4]; + + /* input */ + switch (ma->rampin_spec) { + case MA_RAMP_IN_ENERGY: + fac= t; + break; + case MA_RAMP_IN_SHADER: + fac= is; + break; + case MA_RAMP_IN_NOR: + fac= shi->view[0]*shi->vn[0] + shi->view[1]*shi->vn[1] + shi->view[2]*shi->vn[2]; + break; + default: + fac= 0.0f; + break; + } + + BKE_colorband_evaluate(ma->ramp_spec, fac, col); + + /* blending method */ + fac= col[3]*ma->rampfac_spec; + + ramp_blend(ma->rampblend_spec, spec, fac, col); + } +} + +/* pure AO, check for raytrace and world should have been done */ +/* preprocess, textures were not done, don't use shi->amb for that reason */ +void ambient_occlusion(ShadeInput *shi) +{ + if ((R.wrld.ao_gather_method == WO_AOGATHER_APPROX) && shi->mat->amb!=0.0f) { + sample_occ(&R, shi); + } + else if ((R.r.mode & R_RAYTRACE) && shi->mat->amb!=0.0f) { + ray_ao(shi, shi->ao, shi->env); + } + else { + shi->ao[0]= shi->ao[1]= shi->ao[2]= 1.0f; + zero_v3(shi->env); + zero_v3(shi->indirect); + } +} + + +/* wrld mode was checked for */ +static void ambient_occlusion_apply(ShadeInput *shi, ShadeResult *shr) +{ + float f= R.wrld.aoenergy; + float tmp[3], tmpspec[3]; + + if (!((R.r.mode & R_RAYTRACE) || R.wrld.ao_gather_method == WO_AOGATHER_APPROX)) + return; + if (f == 0.0f) + return; + + if (R.wrld.aomix==WO_AOADD) { + shr->combined[0] += shi->ao[0]*shi->r*shi->refl*f; + shr->combined[1] += shi->ao[1]*shi->g*shi->refl*f; + shr->combined[2] += shi->ao[2]*shi->b*shi->refl*f; + } + else if (R.wrld.aomix==WO_AOMUL) { + mul_v3_v3v3(tmp, shr->combined, shi->ao); + mul_v3_v3v3(tmpspec, shr->spec, shi->ao); + + if (f == 1.0f) { + copy_v3_v3(shr->combined, tmp); + copy_v3_v3(shr->spec, tmpspec); + } + else { + interp_v3_v3v3(shr->combined, shr->combined, tmp, f); + interp_v3_v3v3(shr->spec, shr->spec, tmpspec, f); + } + } +} + +void environment_lighting_apply(ShadeInput *shi, ShadeResult *shr) +{ + float f= R.wrld.ao_env_energy*shi->amb; + + if (!((R.r.mode & R_RAYTRACE) || R.wrld.ao_gather_method == WO_AOGATHER_APPROX)) + return; + if (f == 0.0f) + return; + + shr->combined[0] += shi->env[0]*shi->r*shi->refl*f; + shr->combined[1] += shi->env[1]*shi->g*shi->refl*f; + shr->combined[2] += shi->env[2]*shi->b*shi->refl*f; +} + +static void indirect_lighting_apply(ShadeInput *shi, ShadeResult *shr) +{ + float f= R.wrld.ao_indirect_energy; + + if (!((R.r.mode & R_RAYTRACE) || R.wrld.ao_gather_method == WO_AOGATHER_APPROX)) + return; + if (f == 0.0f) + return; + + shr->combined[0] += shi->indirect[0]*shi->r*shi->refl*f; + shr->combined[1] += shi->indirect[1]*shi->g*shi->refl*f; + shr->combined[2] += shi->indirect[2]*shi->b*shi->refl*f; +} + +/* result written in shadfac */ +void lamp_get_shadow(LampRen *lar, ShadeInput *shi, float inp, float shadfac[4], int do_real) +{ + LampShadowSubSample *lss= &(lar->shadsamp[shi->thread].s[shi->sample]); + + if (do_real || lss->samplenr!=shi->samplenr) { + + shadfac[0]= shadfac[1]= shadfac[2]= shadfac[3]= 1.0f; + + if (lar->shb) { + if (lar->buftype==LA_SHADBUF_IRREGULAR) + shadfac[3]= ISB_getshadow(shi, lar->shb); + else + shadfac[3] = testshadowbuf(&R, lar->shb, shi->co, shi->dxco, shi->dyco, inp, shi->mat->lbias); + } + else if (lar->mode & LA_SHAD_RAY) { + ray_shadow(shi, lar, shadfac); + } + + if (shi->depth==0) { + copy_v4_v4(lss->shadfac, shadfac); + lss->samplenr= shi->samplenr; + } + } + else { + copy_v4_v4(shadfac, lss->shadfac); + } +} + +/* lampdistance and spot angle, writes in lv and dist */ +float lamp_get_visibility(LampRen *lar, const float co[3], float lv[3], float *dist) +{ + if (lar->type==LA_SUN || lar->type==LA_HEMI) { + *dist= 1.0f; + copy_v3_v3(lv, lar->vec); + return 1.0f; + } + else { + float visifac= 1.0f, visifac_r; + + sub_v3_v3v3(lv, co, lar->co); + mul_v3_fl(lv, 1.0f / (*dist = len_v3(lv))); + + /* area type has no quad or sphere option */ + if (lar->type==LA_AREA) { + /* area is single sided */ + //if (dot_v3v3(lv, lar->vec) > 0.0f) + // visifac= 1.0f; + //else + // visifac= 0.0f; + } + else { + switch (lar->falloff_type) { + case LA_FALLOFF_CONSTANT: + visifac = 1.0f; + break; + case LA_FALLOFF_INVLINEAR: + visifac = lar->dist/(lar->dist + dist[0]); + break; + case LA_FALLOFF_INVSQUARE: + /* NOTE: This seems to be a hack since commit r12045 says this + * option is similar to old Quad, but with slight changes. + * Correct inv square would be (which would be old Quad): + * visifac = lar->distkw / (lar->distkw + dist[0]*dist[0]); + */ + visifac = lar->dist / (lar->dist + dist[0]*dist[0]); + break; + case LA_FALLOFF_SLIDERS: + if (lar->ld1>0.0f) + visifac= lar->dist/(lar->dist+lar->ld1*dist[0]); + if (lar->ld2>0.0f) + visifac*= lar->distkw/(lar->distkw+lar->ld2*dist[0]*dist[0]); + break; + case LA_FALLOFF_INVCOEFFICIENTS: + visifac_r = lar->coeff_const + + lar->coeff_lin * dist[0] + + lar->coeff_quad * dist[0] * dist[0]; + if (visifac_r > 0.0) + visifac = 1.0 / visifac_r; + else + visifac = 0.0; + break; + case LA_FALLOFF_CURVE: + /* curvemapping_initialize is called from #add_render_lamp */ + visifac = curvemapping_evaluateF(lar->curfalloff, 0, dist[0]/lar->dist); + break; + } + + if (lar->mode & LA_SPHERE) { + float t= lar->dist - dist[0]; + if (t<=0.0f) + visifac= 0.0f; + else + visifac*= t/lar->dist; + } + + if (visifac > 0.0f) { + if (lar->type==LA_SPOT) { + float inpr, t; + + if (lar->mode & LA_SQUARE) { + if (dot_v3v3(lv, lar->vec) > 0.0f) { + float lvrot[3], x; + + /* rotate view to lampspace */ + copy_v3_v3(lvrot, lv); + mul_m3_v3(lar->imat, lvrot); + + x = max_ff(fabsf(lvrot[0]/lvrot[2]), fabsf(lvrot[1]/lvrot[2])); + /* 1.0f/(sqrt(1+x*x)) is equivalent to cos(atan(x)) */ + + inpr = 1.0f / (sqrtf(1.0f + x * x)); + } + else inpr= 0.0f; + } + else { + inpr= lv[0]*lar->vec[0]+lv[1]*lar->vec[1]+lv[2]*lar->vec[2]; + } + + t= lar->spotsi; + if (inpr<=t) + visifac= 0.0f; + else { + t= inpr-t; + if (t<lar->spotbl && lar->spotbl!=0.0f) { + /* soft area */ + float i= t/lar->spotbl; + t= i*i; + inpr*= (3.0f*t-2.0f*t*i); + } + visifac*= inpr; + } + } + } + } + if (visifac <= 0.001f) visifac = 0.0f; + return visifac; + } +} + +/* function returns raw diff, spec and full shadowed diff in the 'shad' pass */ +static void shade_one_light(LampRen *lar, ShadeInput *shi, ShadeResult *shr, int passflag) +{ + Material *ma= shi->mat; + VlakRen *vlr= shi->vlr; + float lv[3], lampdist, lacol[3], shadfac[4], lashdw[3]; + float i, is, i_noshad, inp, *vn, *view, vnor[3], phongcorr=1.0f; + float visifac; + + vn= shi->vn; + view= shi->view; + + + if (lar->energy == 0.0f) return; + /* only shadow lamps shouldn't affect shadow-less materials at all */ + if ((lar->mode & LA_ONLYSHADOW) && (!(ma->mode & MA_SHADOW) || !(R.r.mode & R_SHADOW))) + return; + /* optimization, don't render fully black lamps */ + if (!(lar->mode & LA_TEXTURE) && (lar->r + lar->g + lar->b == 0.0f)) + return; + + /* lampdist, spot angle, area side, ... */ + visifac= lamp_get_visibility(lar, shi->co, lv, &lampdist); + if (visifac==0.0f) + return; + + if (lar->type==LA_SPOT) { + if (lar->mode & LA_OSATEX) { + shi->osatex= 1; /* signal for multitex() */ + + shi->dxlv[0]= lv[0] - (shi->co[0]-lar->co[0]+shi->dxco[0])/lampdist; + shi->dxlv[1]= lv[1] - (shi->co[1]-lar->co[1]+shi->dxco[1])/lampdist; + shi->dxlv[2]= lv[2] - (shi->co[2]-lar->co[2]+shi->dxco[2])/lampdist; + + shi->dylv[0]= lv[0] - (shi->co[0]-lar->co[0]+shi->dyco[0])/lampdist; + shi->dylv[1]= lv[1] - (shi->co[1]-lar->co[1]+shi->dyco[1])/lampdist; + shi->dylv[2]= lv[2] - (shi->co[2]-lar->co[2]+shi->dyco[2])/lampdist; + } + } + + /* lamp color texture */ + lacol[0]= lar->r; + lacol[1]= lar->g; + lacol[2]= lar->b; + + lashdw[0]= lar->shdwr; + lashdw[1]= lar->shdwg; + lashdw[2]= lar->shdwb; + + if (lar->mode & LA_TEXTURE) do_lamp_tex(lar, lv, shi, lacol, LA_TEXTURE); + if (lar->mode & LA_SHAD_TEX) do_lamp_tex(lar, lv, shi, lashdw, LA_SHAD_TEX); + + /* tangent case; calculate fake face normal, aligned with lampvector */ + /* note, vnor==vn is used as tangent trigger for buffer shadow */ + if (vlr->flag & R_TANGENT) { + float cross[3], nstrand[3], blend; + + if (ma->mode & MA_STR_SURFDIFF) { + cross_v3_v3v3(cross, shi->surfnor, vn); + cross_v3_v3v3(nstrand, vn, cross); + + blend= dot_v3v3(nstrand, shi->surfnor); + blend= 1.0f - blend; + CLAMP(blend, 0.0f, 1.0f); + + interp_v3_v3v3(vnor, nstrand, shi->surfnor, blend); + normalize_v3(vnor); + } + else { + cross_v3_v3v3(cross, lv, vn); + cross_v3_v3v3(vnor, cross, vn); + normalize_v3(vnor); + } + + if (ma->strand_surfnor > 0.0f) { + if (ma->strand_surfnor > shi->surfdist) { + blend= (ma->strand_surfnor - shi->surfdist)/ma->strand_surfnor; + interp_v3_v3v3(vnor, vnor, shi->surfnor, blend); + normalize_v3(vnor); + } + } + + vnor[0]= -vnor[0];vnor[1]= -vnor[1];vnor[2]= -vnor[2]; + vn= vnor; + } + else if (ma->mode & MA_TANGENT_V) { + float cross[3]; + cross_v3_v3v3(cross, lv, shi->tang); + cross_v3_v3v3(vnor, cross, shi->tang); + normalize_v3(vnor); + vnor[0]= -vnor[0];vnor[1]= -vnor[1];vnor[2]= -vnor[2]; + vn= vnor; + } + + /* dot product and reflectivity */ + /* inp = dotproduct, is = shader result, i = lamp energy (with shadow), i_noshad = i without shadow */ + inp= dot_v3v3(vn, lv); + + /* phong threshold to prevent backfacing faces having artifacts on ray shadow (terminator problem) */ + /* this complex construction screams for a nicer implementation! (ton) */ + if (R.r.mode & R_SHADOW) { + if (ma->mode & MA_SHADOW) { + if (lar->type == LA_HEMI || lar->type == LA_AREA) { + /* pass */ + } + else if ((ma->mode & MA_RAYBIAS) && (lar->mode & LA_SHAD_RAY) && (vlr->flag & R_SMOOTH)) { + float thresh= shi->obr->ob->smoothresh; + if (inp>thresh) + phongcorr= (inp-thresh)/(inp*(1.0f-thresh)); + else + phongcorr= 0.0f; + } + else if (ma->sbias!=0.0f && ((lar->mode & LA_SHAD_RAY) || lar->shb)) { + if (inp>ma->sbias) + phongcorr= (inp-ma->sbias)/(inp*(1.0f-ma->sbias)); + else + phongcorr= 0.0f; + } + } + } + + /* diffuse shaders */ + if (lar->mode & LA_NO_DIFF) { + is = 0.0f; /* skip shaders */ + } + else if (lar->type==LA_HEMI) { + is = 0.5f * inp + 0.5f; + } + else { + + if (lar->type==LA_AREA) + inp= area_lamp_energy_multisample(lar, shi->co, vn); + + /* diffuse shaders (oren nayer gets inp from area light) */ + if (ma->diff_shader==MA_DIFF_ORENNAYAR) is= OrenNayar_Diff(inp, vn, lv, view, ma->roughness); + else if (ma->diff_shader==MA_DIFF_TOON) is= Toon_Diff(vn, lv, view, ma->param[0], ma->param[1]); + else if (ma->diff_shader==MA_DIFF_MINNAERT) is= Minnaert_Diff(inp, vn, view, ma->darkness); + else if (ma->diff_shader==MA_DIFF_FRESNEL) is= Fresnel_Diff(vn, lv, view, ma->param[0], ma->param[1]); + else is= inp; /* Lambert */ + } + + /* 'is' is diffuse */ + if ((ma->shade_flag & MA_CUBIC) && is > 0.0f && is < 1.0f) { + is= 3.0f * is * is - 2.0f * is * is * is; /* nicer termination of shades */ + } + + i= is*phongcorr; + + if (i>0.0f) { + i*= visifac*shi->refl; + } + i_noshad= i; + + vn = shi->vn; /* bring back original vector, we use special specular shaders for tangent */ + if (ma->mode & MA_TANGENT_V) + vn= shi->tang; + + /* init transp shadow */ + shadfac[0]= shadfac[1]= shadfac[2]= shadfac[3]= 1.0f; + + /* shadow and spec, (visifac==0 outside spot) */ + if (visifac> 0.0f) { + + if ((R.r.mode & R_SHADOW)) { + if (ma->mode & MA_SHADOW) { + if (lar->shb || (lar->mode & LA_SHAD_RAY)) { + + if (vn==vnor) /* tangent trigger */ + lamp_get_shadow(lar, shi, dot_v3v3(shi->vn, lv), shadfac, shi->depth); + else + lamp_get_shadow(lar, shi, inp, shadfac, shi->depth); + + /* warning, here it skips the loop */ + if ((lar->mode & LA_ONLYSHADOW) && i>0.0f) { + + shadfac[3]= i*lar->energy*(1.0f-shadfac[3]); + shr->shad[0] -= shadfac[3]*shi->r*(1.0f-lashdw[0]); + shr->shad[1] -= shadfac[3]*shi->g*(1.0f-lashdw[1]); + shr->shad[2] -= shadfac[3]*shi->b*(1.0f-lashdw[2]); + + if (!(lar->mode & LA_NO_SPEC)) { + shr->spec[0] -= shadfac[3]*shi->specr*(1.0f-lashdw[0]); + shr->spec[1] -= shadfac[3]*shi->specg*(1.0f-lashdw[1]); + shr->spec[2] -= shadfac[3]*shi->specb*(1.0f-lashdw[2]); + } + + return; + } + + i*= shadfac[3]; + shr->shad[3] = shadfac[3]; /* store this for possible check in troublesome cases */ + } + else { + shr->shad[3] = 1.0f; /* No shadow at all! */ + } + } + } + + /* in case 'no diffuse' we still do most calculus, spec can be in shadow.*/ + if (!(lar->mode & LA_NO_DIFF)) { + if (i>0.0f) { + if (ma->mode & MA_SHADOW_TRA) { + const float tcol[3] = { + i * shadfac[0] * lacol[0], + i * shadfac[1] * lacol[1], + i * shadfac[2] * lacol[2], + }; + add_to_diffuse(shr->shad, shi, is, tcol); + } + else { + const float tcol[3] = { + i * lacol[0], + i * lacol[1], + i * lacol[2], + }; + add_to_diffuse(shr->shad, shi, is, tcol); + } + } + /* add light for colored shadow */ + if (i_noshad>i && !(lashdw[0]==0 && lashdw[1]==0 && lashdw[2]==0)) { + const float tcol[3] = { + lashdw[0] * (i_noshad - i) * lacol[0], + lashdw[1] * (i_noshad - i) * lacol[1], + lashdw[2] * (i_noshad - i) * lacol[2], + }; + add_to_diffuse(shr->shad, shi, is, tcol); + } + if (i_noshad>0.0f) { + if (passflag & (SCE_PASS_DIFFUSE|SCE_PASS_SHADOW) || + ((passflag & SCE_PASS_COMBINED) && !(shi->combinedflag & SCE_PASS_SHADOW))) + { + const float tcol[3] = { + i_noshad * lacol[0], + i_noshad * lacol[1], + i_noshad * lacol[2] + }; + add_to_diffuse(shr->diff, shi, is, tcol); + } + else { + copy_v3_v3(shr->diff, shr->shad); + } + } + } + + /* specularity */ + shadfac[3]*= phongcorr; /* note, shadfac not allowed to be stored nonlocal */ + + if (shadfac[3]>0.0f && shi->spec!=0.0f && !(lar->mode & LA_NO_SPEC) && !(lar->mode & LA_ONLYSHADOW)) { + + if (!(passflag & (SCE_PASS_COMBINED | SCE_PASS_SPEC))) { + /* pass */ + } + else if (lar->type == LA_HEMI) { + float t; + /* hemi uses no spec shaders (yet) */ + + lv[0]+= view[0]; + lv[1]+= view[1]; + lv[2]+= view[2]; + + normalize_v3(lv); + + t= vn[0]*lv[0]+vn[1]*lv[1]+vn[2]*lv[2]; + + if (lar->type==LA_HEMI) { + t= 0.5f*t+0.5f; + } + + t= shadfac[3]*shi->spec*spec(t, shi->har); + + shr->spec[0]+= t*(lacol[0] * shi->specr); + shr->spec[1]+= t*(lacol[1] * shi->specg); + shr->spec[2]+= t*(lacol[2] * shi->specb); + } + else { + /* specular shaders */ + float specfac, t; + + if (ma->spec_shader==MA_SPEC_PHONG) + specfac= Phong_Spec(vn, lv, view, shi->har, (vlr->flag & R_TANGENT) || (ma->mode & MA_TANGENT_V)); + else if (ma->spec_shader==MA_SPEC_COOKTORR) + specfac= CookTorr_Spec(vn, lv, view, shi->har, (vlr->flag & R_TANGENT) || (ma->mode & MA_TANGENT_V)); + else if (ma->spec_shader==MA_SPEC_BLINN) + specfac= Blinn_Spec(vn, lv, view, ma->refrac, (float)shi->har, (vlr->flag & R_TANGENT) || (ma->mode & MA_TANGENT_V)); + else if (ma->spec_shader==MA_SPEC_WARDISO) + specfac= WardIso_Spec( vn, lv, view, ma->rms, (vlr->flag & R_TANGENT) || (ma->mode & MA_TANGENT_V)); + else + specfac= Toon_Spec(vn, lv, view, ma->param[2], ma->param[3], (vlr->flag & R_TANGENT) || (ma->mode & MA_TANGENT_V)); + + /* area lamp correction */ + if (lar->type==LA_AREA) specfac*= inp; + + t= shadfac[3]*shi->spec*visifac*specfac; + + if (ma->mode & MA_RAMP_SPEC) { + float spec[3]; + do_specular_ramp(shi, specfac, t, spec); + shr->spec[0]+= t*(lacol[0] * spec[0]); + shr->spec[1]+= t*(lacol[1] * spec[1]); + shr->spec[2]+= t*(lacol[2] * spec[2]); + } + else { + shr->spec[0]+= t*(lacol[0] * shi->specr); + shr->spec[1]+= t*(lacol[1] * shi->specg); + shr->spec[2]+= t*(lacol[2] * shi->specb); + } + } + } + } +} + +static void shade_lamp_loop_only_shadow(ShadeInput *shi, ShadeResult *shr) +{ + + if (R.r.mode & R_SHADOW) { + ListBase *lights; + LampRen *lar; + GroupObject *go; + float inpr, lv[3]; + float /* *view, */ shadfac[4]; + float ir, accum, visifac, lampdist; + float shaded = 0.0f, lightness = 0.0f; + + + /* view= shi->view; */ /* UNUSED */ + accum= ir= 0.0f; + + lights= get_lights(shi); + for (go=lights->first; go; go= go->next) { + lar= go->lampren; + if (lar==NULL) continue; + + if (lar->mode & LA_LAYER) if ((lar->lay & shi->obi->lay)==0) continue; + if ((lar->lay & shi->lay)==0) continue; + + if (lar->shb || (lar->mode & LA_SHAD_RAY)) { + visifac= lamp_get_visibility(lar, shi->co, lv, &lampdist); + ir+= 1.0f; + + if (visifac <= 0.0f) { + if (shi->mat->shadowonly_flag == MA_SO_OLD) + accum+= 1.0f; + + continue; + } + inpr= dot_v3v3(shi->vn, lv); + if (inpr <= 0.0f) { + if (shi->mat->shadowonly_flag == MA_SO_OLD) + accum+= 1.0f; + + continue; + } + + lamp_get_shadow(lar, shi, inpr, shadfac, shi->depth); + + if (shi->mat->shadowonly_flag == MA_SO_OLD) { + /* Old "Shadows Only" */ + accum+= (1.0f-visifac) + (visifac)*IMB_colormanagement_get_luminance(shadfac)*shadfac[3]; + } + else { + shaded += IMB_colormanagement_get_luminance(shadfac)*shadfac[3] * visifac * lar->energy; + + if (shi->mat->shadowonly_flag == MA_SO_SHADOW) { + lightness += visifac * lar->energy; + } + } + } + } + + /* Apply shadows as alpha */ + if (ir>0.0f) { + if (shi->mat->shadowonly_flag == MA_SO_OLD) { + accum = 1.0f - accum/ir; + } + else { + if (shi->mat->shadowonly_flag == MA_SO_SHADOW) { + if (lightness > 0.0f) { + /* Get shadow value from between 0.0f and non-shadowed lightness */ + accum = (lightness - shaded) / (lightness); + } + else { + accum = 0.0f; + } + } + else { /* shadowonly_flag == MA_SO_SHADED */ + /* Use shaded value */ + accum = 1.0f - shaded; + } + } + + shr->alpha= (shi->alpha)*(accum); + if (shr->alpha<0.0f) shr->alpha=0.0f; + } + else { + /* If "fully shaded", use full alpha even on areas that have no lights */ + if (shi->mat->shadowonly_flag == MA_SO_SHADED) shr->alpha=shi->alpha; + else shr->alpha= 0.f; + } + } + + /* quite disputable this... also note it doesn't mirror-raytrace */ + if ((R.wrld.mode & (WO_AMB_OCC|WO_ENV_LIGHT)) && shi->amb!=0.0f) { + float f; + + if (R.wrld.mode & WO_AMB_OCC) { + f= R.wrld.aoenergy*shi->amb; + + if (R.wrld.aomix==WO_AOADD) { + if (shi->mat->shadowonly_flag == MA_SO_OLD) { + f= f*(1.0f - IMB_colormanagement_get_luminance(shi->ao)); + shr->alpha= (shr->alpha + f)*f; + } + else { + shr->alpha -= f*IMB_colormanagement_get_luminance(shi->ao); + if (shr->alpha<0.0f) shr->alpha=0.0f; + } + } + else /* AO Multiply */ + shr->alpha= (1.0f - f)*shr->alpha + f*(1.0f - (1.0f - shr->alpha)*IMB_colormanagement_get_luminance(shi->ao)); + } + + if (R.wrld.mode & WO_ENV_LIGHT) { + if (shi->mat->shadowonly_flag == MA_SO_OLD) { + f= R.wrld.ao_env_energy*shi->amb*(1.0f - IMB_colormanagement_get_luminance(shi->env)); + shr->alpha= (shr->alpha + f)*f; + } + else { + f= R.wrld.ao_env_energy*shi->amb; + shr->alpha -= f*IMB_colormanagement_get_luminance(shi->env); + if (shr->alpha<0.0f) shr->alpha=0.0f; + } + } + } +} + +/* let's map negative light as if it mirrors positive light, otherwise negative values disappear */ +static void wrld_exposure_correct(float diff[3]) +{ + + diff[0]= R.wrld.linfac*(1.0f-expf( diff[0]*R.wrld.logfac) ); + diff[1]= R.wrld.linfac*(1.0f-expf( diff[1]*R.wrld.logfac) ); + diff[2]= R.wrld.linfac*(1.0f-expf( diff[2]*R.wrld.logfac) ); +} + +void shade_lamp_loop(ShadeInput *shi, ShadeResult *shr) +{ + /* Passes which might need to know material color. + * + * It seems to be faster to just calculate material color + * even if the pass doesn't really need it than trying to + * figure out whether color is really needed or not. + */ + const int color_passes = + SCE_PASS_COMBINED | SCE_PASS_RGBA | SCE_PASS_DIFFUSE | SCE_PASS_SPEC | + SCE_PASS_REFLECT | SCE_PASS_NORMAL | SCE_PASS_REFRACT | SCE_PASS_EMIT | SCE_PASS_SHADOW; + + Material *ma= shi->mat; + int passflag= shi->passflag; + + memset(shr, 0, sizeof(ShadeResult)); + + if (!(shi->mode & MA_TRANSP)) shi->alpha = 1.0f; + + /* separate loop */ + if (ma->mode & MA_ONLYSHADOW) { + shade_lamp_loop_only_shadow(shi, shr); + return; + } + + /* envmap hack, always reset */ + shi->refcol[0]= shi->refcol[1]= shi->refcol[2]= shi->refcol[3]= 0.0f; + + /* material color itself */ + if (passflag & color_passes) { + if (ma->mode & (MA_FACETEXTURE)) { + shi->r= shi->vcol[0]; + shi->g= shi->vcol[1]; + shi->b= shi->vcol[2]; + if (ma->mode & (MA_FACETEXTURE_ALPHA)) + shi->alpha= shi->vcol[3]; + } +#ifdef WITH_FREESTYLE + else if (ma->vcol_alpha) { + shi->r= shi->vcol[0]; + shi->g= shi->vcol[1]; + shi->b= shi->vcol[2]; + shi->alpha= shi->vcol[3]; + } +#endif + else if (ma->mode & (MA_VERTEXCOLP)) { + float neg_alpha = 1.0f - shi->vcol[3]; + shi->r= shi->r*neg_alpha + shi->vcol[0]*shi->vcol[3]; + shi->g= shi->g*neg_alpha + shi->vcol[1]*shi->vcol[3]; + shi->b= shi->b*neg_alpha + shi->vcol[2]*shi->vcol[3]; + } + if (ma->texco) { + do_material_tex(shi, &R); + if (!(shi->mode & MA_TRANSP)) shi->alpha = 1.0f; + } + + shr->col[0]= shi->r*shi->alpha; + shr->col[1]= shi->g*shi->alpha; + shr->col[2]= shi->b*shi->alpha; + shr->col[3]= shi->alpha; + + if ((ma->sss_flag & MA_DIFF_SSS) && !sss_pass_done(&R, ma)) { + if (ma->sss_texfac == 0.0f) { + shi->r= shi->g= shi->b= shi->alpha= 1.0f; + shr->col[0]= shr->col[1]= shr->col[2]= shr->col[3]= 1.0f; + } + else { + shi->r= pow(max_ff(shi->r, 0.0f), ma->sss_texfac); + shi->g= pow(max_ff(shi->g, 0.0f), ma->sss_texfac); + shi->b= pow(max_ff(shi->b, 0.0f), ma->sss_texfac); + shi->alpha= pow(max_ff(shi->alpha, 0.0f), ma->sss_texfac); + + shr->col[0]= pow(max_ff(shr->col[0], 0.0f), ma->sss_texfac); + shr->col[1]= pow(max_ff(shr->col[1], 0.0f), ma->sss_texfac); + shr->col[2]= pow(max_ff(shr->col[2], 0.0f), ma->sss_texfac); + shr->col[3]= pow(max_ff(shr->col[3], 0.0f), ma->sss_texfac); + } + } + } + + if (ma->mode & MA_SHLESS) { + shr->combined[0]= shi->r; + shr->combined[1]= shi->g; + shr->combined[2]= shi->b; + shr->alpha= shi->alpha; + goto finally_shadeless; + } + + if ( (ma->mode & (MA_VERTEXCOL|MA_VERTEXCOLP))== MA_VERTEXCOL ) { /* vertexcolor light */ + shr->emit[0]= shi->r*(shi->emit+shi->vcol[0]*shi->vcol[3]); + shr->emit[1]= shi->g*(shi->emit+shi->vcol[1]*shi->vcol[3]); + shr->emit[2]= shi->b*(shi->emit+shi->vcol[2]*shi->vcol[3]); + } + else { + shr->emit[0]= shi->r*shi->emit; + shr->emit[1]= shi->g*shi->emit; + shr->emit[2]= shi->b*shi->emit; + } + + /* AO pass */ + if (((passflag & SCE_PASS_COMBINED) && (shi->combinedflag & (SCE_PASS_AO|SCE_PASS_ENVIRONMENT|SCE_PASS_INDIRECT))) || + (passflag & (SCE_PASS_AO|SCE_PASS_ENVIRONMENT|SCE_PASS_INDIRECT))) { + if ((R.wrld.mode & (WO_AMB_OCC|WO_ENV_LIGHT|WO_INDIRECT_LIGHT)) && (R.r.mode & R_SHADOW)) { + /* AO was calculated for scanline already */ + if (shi->depth || shi->volume_depth) + ambient_occlusion(shi); + copy_v3_v3(shr->ao, shi->ao); + copy_v3_v3(shr->env, shi->env); /* XXX multiply */ + copy_v3_v3(shr->indirect, shi->indirect); /* XXX multiply */ + } + else { + shr->ao[0]= shr->ao[1]= shr->ao[2]= 1.0f; + zero_v3(shr->env); + zero_v3(shr->indirect); + } + } + + /* lighting pass */ + if (passflag & (SCE_PASS_COMBINED|SCE_PASS_DIFFUSE|SCE_PASS_SPEC|SCE_PASS_SHADOW)) { + GroupObject *go; + ListBase *lights; + LampRen *lar; + + lights= get_lights(shi); + for (go=lights->first; go; go= go->next) { + lar= go->lampren; + if (lar==NULL) continue; + + /* test for lamp layer */ + if (lar->mode & LA_LAYER) if ((lar->lay & shi->obi->lay)==0) continue; + if ((lar->lay & shi->lay)==0) continue; + + /* accumulates in shr->diff and shr->spec and shr->shad (diffuse with shadow!) */ + shade_one_light(lar, shi, shr, passflag); + } + + /* this check is to prevent only shadow lamps from producing negative + * colors.*/ + if (shr->spec[0] < 0) shr->spec[0] = 0; + if (shr->spec[1] < 0) shr->spec[1] = 0; + if (shr->spec[2] < 0) shr->spec[2] = 0; + + if (shr->shad[0] < 0) shr->shad[0] = 0; + if (shr->shad[1] < 0) shr->shad[1] = 0; + if (shr->shad[2] < 0) shr->shad[2] = 0; + + if (ma->sss_flag & MA_DIFF_SSS) { + float sss[3], col[3], invalpha, texfac= ma->sss_texfac; + + /* this will return false in the preprocess stage */ + if (sample_sss(&R, ma, shi->co, sss)) { + invalpha= (shr->col[3] > FLT_EPSILON)? 1.0f/shr->col[3]: 1.0f; + + if (texfac==0.0f) { + copy_v3_v3(col, shr->col); + mul_v3_fl(col, invalpha); + } + else if (texfac==1.0f) { + col[0]= col[1]= col[2]= 1.0f; + mul_v3_fl(col, invalpha); + } + else { + copy_v3_v3(col, shr->col); + mul_v3_fl(col, invalpha); + col[0]= pow(max_ff(col[0], 0.0f), 1.0f-texfac); + col[1]= pow(max_ff(col[1], 0.0f), 1.0f-texfac); + col[2]= pow(max_ff(col[2], 0.0f), 1.0f-texfac); + } + + shr->diff[0]= sss[0]*col[0]; + shr->diff[1]= sss[1]*col[1]; + shr->diff[2]= sss[2]*col[2]; + + if (shi->combinedflag & SCE_PASS_SHADOW) { + shr->shad[0]= shr->diff[0]; + shr->shad[1]= shr->diff[1]; + shr->shad[2]= shr->diff[2]; + } + } + } + + if (shi->combinedflag & SCE_PASS_SHADOW) + copy_v3_v3(shr->diffshad, shr->shad); + else + copy_v3_v3(shr->diffshad, shr->diff); + + copy_v3_v3(shr->combined, shr->diffshad); + + /* calculate shadow pass, we use a multiplication mask */ + /* Even if diff = 0,0,0, it does matter what the shadow pass is, since we may want it 'for itself'! */ + if (passflag & SCE_PASS_SHADOW) { + if (shr->diff[0]!=0.0f) shr->shad[0]= shr->shad[0]/shr->diff[0]; + /* can't determine proper shadow from shad/diff (0/0), so use shadow intensity */ + else if (shr->shad[0]==0.0f) shr->shad[0]= shr->shad[3]; + + if (shr->diff[1]!=0.0f) shr->shad[1]= shr->shad[1]/shr->diff[1]; + else if (shr->shad[1]==0.0f) shr->shad[1]= shr->shad[3]; + + if (shr->diff[2]!=0.0f) shr->shad[2]= shr->shad[2]/shr->diff[2]; + else if (shr->shad[2]==0.0f) shr->shad[2]= shr->shad[3]; + } + + /* exposure correction */ + if ((R.wrld.exp!=0.0f || R.wrld.range!=1.0f) && !R.sss_points) { + wrld_exposure_correct(shr->combined); /* has no spec! */ + wrld_exposure_correct(shr->spec); + } + } + + /* alpha in end, spec can influence it */ + if (passflag & (SCE_PASS_COMBINED)) { + if ((ma->fresnel_tra!=0.0f) && (shi->mode & MA_TRANSP)) + shi->alpha*= fresnel_fac(shi->view, shi->vn, ma->fresnel_tra_i, ma->fresnel_tra); + + /* note: shi->mode! */ + if (shi->mode & MA_TRANSP && (shi->mode & (MA_ZTRANSP|MA_RAYTRANSP))) { + if (shi->spectra!=0.0f) { + float t = max_fff(shr->spec[0], shr->spec[1], shr->spec[2]); + t *= shi->spectra; + if (t>1.0f) t= 1.0f; + shi->alpha= (1.0f-t)*shi->alpha+t; + } + } + } + shr->alpha= shi->alpha; + + /* from now stuff everything in shr->combined: ambient, AO, ramps, exposure */ + if (!(ma->sss_flag & MA_DIFF_SSS) || !sss_pass_done(&R, ma)) { + if (R.r.mode & R_SHADOW) { + /* add AO in combined? */ + if (R.wrld.mode & WO_AMB_OCC) + if (shi->combinedflag & SCE_PASS_AO) + ambient_occlusion_apply(shi, shr); + + if (R.wrld.mode & WO_ENV_LIGHT) + if (shi->combinedflag & SCE_PASS_ENVIRONMENT) + environment_lighting_apply(shi, shr); + + if (R.wrld.mode & WO_INDIRECT_LIGHT) + if (shi->combinedflag & SCE_PASS_INDIRECT) + indirect_lighting_apply(shi, shr); + } + + shr->combined[0]+= shi->ambr; + shr->combined[1]+= shi->ambg; + shr->combined[2]+= shi->ambb; + + if (ma->mode & MA_RAMP_COL) ramp_diffuse_result(shr->combined, shi); + } + + if (ma->mode & MA_RAMP_SPEC) ramp_spec_result(shr->spec, shi); + + /* refcol is for envmap only */ + if (shi->refcol[0]!=0.0f) { + float result[3]; + + result[0]= shi->mirr*shi->refcol[1] + (1.0f - shi->mirr*shi->refcol[0])*shr->combined[0]; + result[1]= shi->mirg*shi->refcol[2] + (1.0f - shi->mirg*shi->refcol[0])*shr->combined[1]; + result[2]= shi->mirb*shi->refcol[3] + (1.0f - shi->mirb*shi->refcol[0])*shr->combined[2]; + + if (passflag & SCE_PASS_REFLECT) + sub_v3_v3v3(shr->refl, result, shr->combined); + + if (shi->combinedflag & SCE_PASS_REFLECT) + copy_v3_v3(shr->combined, result); + + } + + /* and add emit and spec */ + if (shi->combinedflag & SCE_PASS_EMIT) + add_v3_v3(shr->combined, shr->emit); + if (shi->combinedflag & SCE_PASS_SPEC) + add_v3_v3(shr->combined, shr->spec); + + + /* Last section of this function applies to shadeless colors too */ +finally_shadeless: + + /* modulate by the object color */ + if ((ma->shade_flag & MA_OBCOLOR) && shi->obr->ob) { + if (!(ma->sss_flag & MA_DIFF_SSS) || !sss_pass_done(&R, ma)) { + float obcol[4]; + + copy_v4_v4(obcol, shi->obr->ob->col); + CLAMP(obcol[3], 0.0f, 1.0f); + + shr->combined[0] *= obcol[0]; + shr->combined[1] *= obcol[1]; + shr->combined[2] *= obcol[2]; + if (shi->mode & MA_TRANSP) shr->alpha *= obcol[3]; + } + } + + shr->combined[3]= shr->alpha; +} + +/* used for "Lamp Data" shader node */ +static float lamp_get_data_internal(ShadeInput *shi, GroupObject *go, float col[4], float lv[3], float *dist, float shadow[4]) +{ + LampRen *lar = go->lampren; + float visifac, inp; + + if (!lar + || ((lar->mode & LA_LAYER) && (lar->lay & shi->obi->lay) == 0) + || (lar->lay & shi->lay) == 0) + return 0.0f; + + if (lar->mode & LA_TEXTURE) + do_lamp_tex(lar, lv, shi, col, LA_TEXTURE); + + visifac = lamp_get_visibility(lar, shi->co, lv, dist); + + if (visifac == 0.0f + || lar->type == LA_HEMI + || (lar->type != LA_SPOT && !(lar->mode & LA_SHAD_RAY)) + || (R.r.scemode & R_BUTS_PREVIEW)) + return visifac; + + inp = dot_v3v3(shi->vn, lv); + + if (inp > 0.0f) { + float shadfac[4]; + + shadow[0] = lar->shdwr; + shadow[1] = lar->shdwg; + shadow[2] = lar->shdwb; + + if (lar->mode & LA_SHAD_TEX) + do_lamp_tex(lar, lv, shi, shadow, LA_SHAD_TEX); + + if (R.r.mode & R_SHADOW) { + lamp_get_shadow(lar, shi, inp, shadfac, shi->depth); + + shadow[0] = 1.0f - ((1.0f - shadfac[0] * shadfac[3]) * (1.0f - shadow[0])); + shadow[1] = 1.0f - ((1.0f - shadfac[1] * shadfac[3]) * (1.0f - shadow[1])); + shadow[2] = 1.0f - ((1.0f - shadfac[2] * shadfac[3]) * (1.0f - shadow[2])); + } + } + + return visifac; +} + +float RE_lamp_get_data(ShadeInput *shi, Object *lamp_obj, float col[4], float lv[3], float *dist, float shadow[4]) +{ + col[0] = col[1] = col[2] = 0.0f; + col[3] = 1.0f; + copy_v3_v3(lv, shi->vn); + *dist = 1.0f; + shadow[0] = shadow[1] = shadow[2] = shadow[3] = 1.0f; + + if (lamp_obj->type == OB_LAMP) { + GroupObject *go; + Lamp *lamp = (Lamp *)lamp_obj->data; + + col[0] = lamp->r * lamp->energy; + col[1] = lamp->g * lamp->energy; + col[2] = lamp->b * lamp->energy; + + if (R.r.scemode & R_BUTS_PREVIEW) { + for (go = R.lights.first; go; go = go->next) { + /* "Lamp.002" is main key light of material preview */ + if (STREQ(go->ob->id.name + 2, "Lamp.002")) + return lamp_get_data_internal(shi, go, col, lv, dist, shadow); + } + return 0.0f; + } + + if (shi->light_override) { + for (go = shi->light_override->gobject.first; go; go = go->next) { + if (go->ob == lamp_obj) + return lamp_get_data_internal(shi, go, col, lv, dist, shadow); + } + } + + if (shi->mat && shi->mat->group) { + for (go = shi->mat->group->gobject.first; go; go = go->next) { + if (go->ob == lamp_obj) + return lamp_get_data_internal(shi, go, col, lv, dist, shadow); + } + } + + for (go = R.lights.first; go; go = go->next) { + if (go->ob == lamp_obj) + return lamp_get_data_internal(shi, go, col, lv, dist, shadow); + } + } + + return 0.0f; +} + +const float (*RE_object_instance_get_matrix(struct ObjectInstanceRen *obi, int matrix_id))[4] +{ + if (obi) { + switch (matrix_id) { + case RE_OBJECT_INSTANCE_MATRIX_OB: + return (const float(*)[4])obi->obmat; + case RE_OBJECT_INSTANCE_MATRIX_OBINV: + return (const float(*)[4])obi->obinvmat; + case RE_OBJECT_INSTANCE_MATRIX_LOCALTOVIEW: + return (const float(*)[4])obi->localtoviewmat; + case RE_OBJECT_INSTANCE_MATRIX_LOCALTOVIEWINV: + return (const float(*)[4])obi->localtoviewinvmat; + } + } + return NULL; +} + +float RE_object_instance_get_object_pass_index(struct ObjectInstanceRen *obi) +{ + return obi->ob->index; +} + +float RE_object_instance_get_random_id(struct ObjectInstanceRen *obi) +{ + return obi->random_id; +} + +const float (*RE_render_current_get_matrix(int matrix_id))[4] +{ + switch (matrix_id) { + case RE_VIEW_MATRIX: + return (const float(*)[4])R.viewmat; + case RE_VIEWINV_MATRIX: + return (const float(*)[4])R.viewinv; + } + return NULL; +} + +float RE_fresnel_dielectric(float incoming[3], float normal[3], float eta) +{ + /* compute fresnel reflectance without explicitly computing + * the refracted direction */ + float c = fabs(dot_v3v3(incoming, normal)); + float g = eta * eta - 1.0 + c * c; + float result; + + if (g > 0.0) { + g = sqrtf(g); + float A = (g - c) / (g + c); + float B = (c * (g + c) - 1.0) / (c * (g - c) + 1.0); + result = 0.5 * A * A * (1.0 + B * B); + } + else { + result = 1.0; /* TIR (no refracted component) */ + } + + return result; +} diff --git a/source/blender/render/intern/source/sss.c b/source/blender/render/intern/source/sss.c new file mode 100644 index 00000000000..5919b8130d7 --- /dev/null +++ b/source/blender/render/intern/source/sss.c @@ -0,0 +1,1074 @@ +/* + * ***** 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) 2007 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/render/intern/source/sss.c + * \ingroup render + */ + +/* Possible Improvements: + * - add fresnel terms + * - adapt Rd table to scale, now with small scale there are a lot of misses? + * - possible interesting method: perform sss on all samples in the tree, + * and then use those values interpolated somehow later. can also do this + * filtering on demand for speed. since we are doing things in screen + * space now there is an exact correspondence + * - avoid duplicate shading (filtering points in advance, irradiance cache + * like lookup?) + * - lower resolution samples + */ + +#include <math.h> +#include <string.h> +#include <stdio.h> +#include <string.h> + +/* external modules: */ +#include "MEM_guardedalloc.h" + +#include "BLI_math.h" +#include "BLI_blenlib.h" +#include "BLI_utildefines.h" +#include "BLI_ghash.h" +#include "BLI_memarena.h" + +#include "BLT_translation.h" + + +#include "DNA_material_types.h" + +#include "BKE_global.h" +#include "BKE_main.h" +#include "BKE_scene.h" + + +/* this module */ +#include "render_types.h" +#include "sss.h" + +/* Generic Multiple Scattering API */ + +/* Relevant papers: + * [1] A Practical Model for Subsurface Light Transport + * [2] A Rapid Hierarchical Rendering Technique for Translucent Materials + * [3] Efficient Rendering of Local Subsurface Scattering + * [4] Implementing a skin BSSRDF (or several...) + */ + +/* Defines */ + +#define RD_TABLE_RANGE 100.0f +#define RD_TABLE_RANGE_2 10000.0f +#define RD_TABLE_SIZE 10000 + +#define MAX_OCTREE_NODE_POINTS 8 +#define MAX_OCTREE_DEPTH 15 + +/* Struct Definitions */ + +struct ScatterSettings { + float eta; /* index of refraction */ + float sigma_a; /* absorption coefficient */ + float sigma_s_; /* reduced scattering coefficient */ + float sigma_t_; /* reduced extinction coefficient */ + float sigma; /* effective extinction coefficient */ + float Fdr; /* diffuse fresnel reflectance */ + float D; /* diffusion constant */ + float A; + float alpha_; /* reduced albedo */ + float zr; /* distance of virtual lightsource above surface */ + float zv; /* distance of virtual lightsource below surface */ + float ld; /* mean free path */ + float ro; /* diffuse reflectance */ + float color; + float invsigma_t_; + float frontweight; + float backweight; + + float *tableRd; /* lookup table to avoid computing Rd */ + float *tableRd2; /* lookup table to avoid computing Rd for bigger values */ +}; + +typedef struct ScatterPoint { + float co[3]; + float rad[3]; + float area; + int back; +} ScatterPoint; + +typedef struct ScatterNode { + float co[3]; + float rad[3]; + float backrad[3]; + float area, backarea; + + int totpoint; + ScatterPoint *points; + + float split[3]; + struct ScatterNode *child[8]; +} ScatterNode; + +struct ScatterTree { + MemArena *arena; + + ScatterSettings *ss[3]; + float error, scale; + + ScatterNode *root; + ScatterPoint *points; + ScatterPoint **refpoints; + ScatterPoint **tmppoints; + int totpoint; + float min[3], max[3]; +}; + +typedef struct ScatterResult { + float rad[3]; + float backrad[3]; + float rdsum[3]; + float backrdsum[3]; +} ScatterResult; + +/* Functions for BSSRDF reparametrization in to more intuitive parameters, + * see [2] section 4 for more info. */ + +static float f_Rd(float alpha_, float A, float ro) +{ + float sq; + + sq = sqrtf(3.0f * (1.0f - alpha_)); + return (alpha_/2.0f)*(1.0f + expf((-4.0f/3.0f)*A*sq))*expf(-sq) - ro; +} + +static float compute_reduced_albedo(ScatterSettings *ss) +{ + const float tolerance= 1e-8; + const int max_iteration_count= 20; + float d, fsub, xn_1= 0.0f, xn= 1.0f, fxn, fxn_1; + int i; + + /* use secant method to compute reduced albedo using Rd function inverse + * with a given reflectance */ + fxn= f_Rd(xn, ss->A, ss->ro); + fxn_1= f_Rd(xn_1, ss->A, ss->ro); + + for (i= 0; i < max_iteration_count; i++) { + fsub= (fxn - fxn_1); + if (fabsf(fsub) < tolerance) + break; + d= ((xn - xn_1)/fsub)*fxn; + if (fabsf(d) < tolerance) + break; + + xn_1= xn; + fxn_1= fxn; + xn= xn - d; + + if (xn > 1.0f) xn= 1.0f; + if (xn_1 > 1.0f) xn_1= 1.0f; + + fxn= f_Rd(xn, ss->A, ss->ro); + } + + /* avoid division by zero later */ + if (xn <= 0.0f) + xn= 0.00001f; + + return xn; +} + +/* Exponential falloff functions */ + +static float Rd_rsquare(ScatterSettings *ss, float rr) +{ + float sr, sv, Rdr, Rdv; + + sr = sqrtf(rr + ss->zr * ss->zr); + sv = sqrtf(rr + ss->zv * ss->zv); + + Rdr= ss->zr*(1.0f + ss->sigma*sr)*expf(-ss->sigma*sr)/(sr*sr*sr); + Rdv= ss->zv*(1.0f + ss->sigma*sv)*expf(-ss->sigma*sv)/(sv*sv*sv); + + return /*ss->alpha_*/(1.0f/(4.0f*(float)M_PI))*(Rdr + Rdv); +} + +static float Rd(ScatterSettings *ss, float r) +{ + return Rd_rsquare(ss, r*r); +} + +/* table lookups for Rd. this avoids expensive exp calls. we use two + * separate tables as well for lower and higher numbers to improve + * precision, since the number are poorly distributed because we do + * a lookup with the squared distance for smaller distances, saving + * another sqrt. */ + +static void approximate_Rd_rgb(ScatterSettings **ss, float rr, float *rd) +{ + float indexf, t, idxf; + int index; + + if (rr > (RD_TABLE_RANGE_2 * RD_TABLE_RANGE_2)) { + /* pass */ + } + else if (rr > RD_TABLE_RANGE) { + rr = sqrtf(rr); + indexf= rr*(RD_TABLE_SIZE/RD_TABLE_RANGE_2); + index= (int)indexf; + idxf= (float)index; + t= indexf - idxf; + + if (index >= 0 && index < RD_TABLE_SIZE) { + rd[0]= (ss[0]->tableRd2[index]*(1-t) + ss[0]->tableRd2[index+1]*t); + rd[1]= (ss[1]->tableRd2[index]*(1-t) + ss[1]->tableRd2[index+1]*t); + rd[2]= (ss[2]->tableRd2[index]*(1-t) + ss[2]->tableRd2[index+1]*t); + return; + } + } + else { + indexf= rr*(RD_TABLE_SIZE/RD_TABLE_RANGE); + index= (int)indexf; + idxf= (float)index; + t= indexf - idxf; + + if (index >= 0 && index < RD_TABLE_SIZE) { + rd[0]= (ss[0]->tableRd[index]*(1-t) + ss[0]->tableRd[index+1]*t); + rd[1]= (ss[1]->tableRd[index]*(1-t) + ss[1]->tableRd[index+1]*t); + rd[2]= (ss[2]->tableRd[index]*(1-t) + ss[2]->tableRd[index+1]*t); + return; + } + } + + /* fallback to slow Rd computation */ + rd[0]= Rd_rsquare(ss[0], rr); + rd[1]= Rd_rsquare(ss[1], rr); + rd[2]= Rd_rsquare(ss[2], rr); +} + +static void build_Rd_table(ScatterSettings *ss) +{ + float r; + int i, size = RD_TABLE_SIZE+1; + + ss->tableRd= MEM_mallocN(sizeof(float)*size, "scatterTableRd"); + ss->tableRd2= MEM_mallocN(sizeof(float)*size, "scatterTableRd"); + + for (i= 0; i < size; i++) { + r= i*(RD_TABLE_RANGE/RD_TABLE_SIZE); +#if 0 + if (r < ss->invsigma_t_*ss->invsigma_t_) { + r= ss->invsigma_t_*ss->invsigma_t_; + } +#endif + ss->tableRd[i]= Rd(ss, sqrtf(r)); + + r= i*(RD_TABLE_RANGE_2/RD_TABLE_SIZE); +#if 0 + if (r < ss->invsigma_t_) { + r= ss->invsigma_t_; + } +#endif + ss->tableRd2[i]= Rd(ss, r); + } +} + +ScatterSettings *scatter_settings_new(float refl, float radius, float ior, float reflfac, float frontweight, float backweight) +{ + ScatterSettings *ss; + + ss= MEM_callocN(sizeof(ScatterSettings), "ScatterSettings"); + + /* see [1] and [3] for these formulas */ + ss->eta= ior; + ss->Fdr= -1.440f/ior*ior + 0.710f/ior + 0.668f + 0.0636f*ior; + ss->A= (1.0f + ss->Fdr)/(1.0f - ss->Fdr); + ss->ld= radius; + ss->ro= min_ff(refl, 0.99f); + ss->color= ss->ro*reflfac + (1.0f-reflfac); + + ss->alpha_= compute_reduced_albedo(ss); + + ss->sigma= 1.0f/ss->ld; + ss->sigma_t_= ss->sigma/sqrtf(3.0f*(1.0f - ss->alpha_)); + ss->sigma_s_= ss->alpha_*ss->sigma_t_; + ss->sigma_a= ss->sigma_t_ - ss->sigma_s_; + + ss->D= 1.0f/(3.0f*ss->sigma_t_); + + ss->zr= 1.0f/ss->sigma_t_; + ss->zv= ss->zr + 4.0f*ss->A*ss->D; + + ss->invsigma_t_= 1.0f/ss->sigma_t_; + + ss->frontweight= frontweight; + ss->backweight= backweight; + + /* precompute a table of Rd values for quick lookup */ + build_Rd_table(ss); + + return ss; +} + +void scatter_settings_free(ScatterSettings *ss) +{ + MEM_freeN(ss->tableRd); + MEM_freeN(ss->tableRd2); + MEM_freeN(ss); +} + +/* Hierarchical method as in [2]. */ + +/* traversal */ + +#define SUBNODE_INDEX(co, split) \ + ((co[0]>=split[0]) + (co[1]>=split[1])*2 + (co[2]>=split[2])*4) + +static void add_radiance(ScatterTree *tree, float *frontrad, float *backrad, float area, float backarea, float rr, ScatterResult *result) +{ + float rd[3], frontrd[3], backrd[3]; + + approximate_Rd_rgb(tree->ss, rr, rd); + + if (frontrad && area) { + frontrd[0] = rd[0]*area; + frontrd[1] = rd[1]*area; + frontrd[2] = rd[2]*area; + + result->rad[0] += frontrad[0]*frontrd[0]; + result->rad[1] += frontrad[1]*frontrd[1]; + result->rad[2] += frontrad[2]*frontrd[2]; + + result->rdsum[0] += frontrd[0]; + result->rdsum[1] += frontrd[1]; + result->rdsum[2] += frontrd[2]; + } + if (backrad && backarea) { + backrd[0] = rd[0]*backarea; + backrd[1] = rd[1]*backarea; + backrd[2] = rd[2]*backarea; + + result->backrad[0] += backrad[0]*backrd[0]; + result->backrad[1] += backrad[1]*backrd[1]; + result->backrad[2] += backrad[2]*backrd[2]; + + result->backrdsum[0] += backrd[0]; + result->backrdsum[1] += backrd[1]; + result->backrdsum[2] += backrd[2]; + } +} + +static void traverse_octree(ScatterTree *tree, ScatterNode *node, const float co[3], int self, ScatterResult *result) +{ + float sub[3], dist; + int i, index = 0; + + if (node->totpoint > 0) { + /* leaf - add radiance from all samples */ + for (i=0; i<node->totpoint; i++) { + ScatterPoint *p= &node->points[i]; + + sub_v3_v3v3(sub, co, p->co); + dist= dot_v3v3(sub, sub); + + if (p->back) + add_radiance(tree, NULL, p->rad, 0.0f, p->area, dist, result); + else + add_radiance(tree, p->rad, NULL, p->area, 0.0f, dist, result); + } + } + else { + /* branch */ + if (self) + index = SUBNODE_INDEX(co, node->split); + + for (i=0; i<8; i++) { + if (node->child[i]) { + ScatterNode *subnode= node->child[i]; + + if (self && index == i) { + /* always traverse node containing the point */ + traverse_octree(tree, subnode, co, 1, result); + } + else { + /* decide subnode traversal based on maximum solid angle */ + sub_v3_v3v3(sub, co, subnode->co); + dist= dot_v3v3(sub, sub); + + /* actually area/dist > error, but this avoids division */ + if (subnode->area+subnode->backarea>tree->error*dist) { + traverse_octree(tree, subnode, co, 0, result); + } + else { + add_radiance(tree, subnode->rad, subnode->backrad, + subnode->area, subnode->backarea, dist, result); + } + } + } + } + } +} + +static void compute_radiance(ScatterTree *tree, const float co[3], float *rad) +{ + ScatterResult result; + float rdsum[3], backrad[3], backrdsum[3]; + + memset(&result, 0, sizeof(result)); + + traverse_octree(tree, tree->root, co, 1, &result); + + /* the original paper doesn't do this, but we normalize over the + * sampled area and multiply with the reflectance. this is because + * our point samples are incomplete, there are no samples on parts + * of the mesh not visible from the camera. this can not only make + * it darker, but also lead to ugly color shifts */ + + mul_v3_fl(result.rad, tree->ss[0]->frontweight); + mul_v3_fl(result.backrad, tree->ss[0]->backweight); + + copy_v3_v3(rad, result.rad); + add_v3_v3v3(backrad, result.rad, result.backrad); + + copy_v3_v3(rdsum, result.rdsum); + add_v3_v3v3(backrdsum, result.rdsum, result.backrdsum); + + if (rdsum[0] > 1e-16f) rad[0]= tree->ss[0]->color*rad[0]/rdsum[0]; + if (rdsum[1] > 1e-16f) rad[1]= tree->ss[1]->color*rad[1]/rdsum[1]; + if (rdsum[2] > 1e-16f) rad[2]= tree->ss[2]->color*rad[2]/rdsum[2]; + + if (backrdsum[0] > 1e-16f) backrad[0]= tree->ss[0]->color*backrad[0]/backrdsum[0]; + if (backrdsum[1] > 1e-16f) backrad[1]= tree->ss[1]->color*backrad[1]/backrdsum[1]; + if (backrdsum[2] > 1e-16f) backrad[2]= tree->ss[2]->color*backrad[2]/backrdsum[2]; + + rad[0]= MAX2(rad[0], backrad[0]); + rad[1]= MAX2(rad[1], backrad[1]); + rad[2]= MAX2(rad[2], backrad[2]); +} + +/* building */ + +static void sum_leaf_radiance(ScatterTree *UNUSED(tree), ScatterNode *node) +{ + ScatterPoint *p; + float rad, totrad= 0.0f, inv; + int i; + + node->co[0]= node->co[1]= node->co[2]= 0.0; + node->rad[0]= node->rad[1]= node->rad[2]= 0.0; + node->backrad[0]= node->backrad[1]= node->backrad[2]= 0.0; + + /* compute total rad, rad weighted average position, + * and total area */ + for (i=0; i<node->totpoint; i++) { + p= &node->points[i]; + + rad= p->area*fabsf(p->rad[0] + p->rad[1] + p->rad[2]); + totrad += rad; + + node->co[0] += rad*p->co[0]; + node->co[1] += rad*p->co[1]; + node->co[2] += rad*p->co[2]; + + if (p->back) { + node->backrad[0] += p->rad[0]*p->area; + node->backrad[1] += p->rad[1]*p->area; + node->backrad[2] += p->rad[2]*p->area; + + node->backarea += p->area; + } + else { + node->rad[0] += p->rad[0]*p->area; + node->rad[1] += p->rad[1]*p->area; + node->rad[2] += p->rad[2]*p->area; + + node->area += p->area; + } + } + + if (node->area > 1e-16f) { + inv= 1.0f/node->area; + node->rad[0] *= inv; + node->rad[1] *= inv; + node->rad[2] *= inv; + } + if (node->backarea > 1e-16f) { + inv= 1.0f/node->backarea; + node->backrad[0] *= inv; + node->backrad[1] *= inv; + node->backrad[2] *= inv; + } + + if (totrad > 1e-16f) { + inv= 1.0f/totrad; + node->co[0] *= inv; + node->co[1] *= inv; + node->co[2] *= inv; + } + else { + /* make sure that if radiance is 0.0f, we still have these points in + * the tree at a good position, they count for rdsum too */ + for (i=0; i<node->totpoint; i++) { + p= &node->points[i]; + + node->co[0] += p->co[0]; + node->co[1] += p->co[1]; + node->co[2] += p->co[2]; + } + + node->co[0] /= node->totpoint; + node->co[1] /= node->totpoint; + node->co[2] /= node->totpoint; + } +} + +static void sum_branch_radiance(ScatterTree *UNUSED(tree), ScatterNode *node) +{ + ScatterNode *subnode; + float rad, totrad= 0.0f, inv; + int i, totnode; + + node->co[0]= node->co[1]= node->co[2]= 0.0; + node->rad[0]= node->rad[1]= node->rad[2]= 0.0; + node->backrad[0]= node->backrad[1]= node->backrad[2]= 0.0; + + /* compute total rad, rad weighted average position, + * and total area */ + for (i=0; i<8; i++) { + if (node->child[i] == NULL) + continue; + + subnode= node->child[i]; + + rad= subnode->area*fabsf(subnode->rad[0] + subnode->rad[1] + subnode->rad[2]); + rad += subnode->backarea*fabsf(subnode->backrad[0] + subnode->backrad[1] + subnode->backrad[2]); + totrad += rad; + + node->co[0] += rad*subnode->co[0]; + node->co[1] += rad*subnode->co[1]; + node->co[2] += rad*subnode->co[2]; + + node->rad[0] += subnode->rad[0]*subnode->area; + node->rad[1] += subnode->rad[1]*subnode->area; + node->rad[2] += subnode->rad[2]*subnode->area; + + node->backrad[0] += subnode->backrad[0]*subnode->backarea; + node->backrad[1] += subnode->backrad[1]*subnode->backarea; + node->backrad[2] += subnode->backrad[2]*subnode->backarea; + + node->area += subnode->area; + node->backarea += subnode->backarea; + } + + if (node->area > 1e-16f) { + inv= 1.0f/node->area; + node->rad[0] *= inv; + node->rad[1] *= inv; + node->rad[2] *= inv; + } + if (node->backarea > 1e-16f) { + inv= 1.0f/node->backarea; + node->backrad[0] *= inv; + node->backrad[1] *= inv; + node->backrad[2] *= inv; + } + + if (totrad > 1e-16f) { + inv= 1.0f/totrad; + node->co[0] *= inv; + node->co[1] *= inv; + node->co[2] *= inv; + } + else { + /* make sure that if radiance is 0.0f, we still have these points in + * the tree at a good position, they count for rdsum too */ + totnode= 0; + + for (i=0; i<8; i++) { + if (node->child[i]) { + subnode= node->child[i]; + + node->co[0] += subnode->co[0]; + node->co[1] += subnode->co[1]; + node->co[2] += subnode->co[2]; + + totnode++; + } + } + + node->co[0] /= totnode; + node->co[1] /= totnode; + node->co[2] /= totnode; + } +} + +static void sum_radiance(ScatterTree *tree, ScatterNode *node) +{ + if (node->totpoint > 0) { + sum_leaf_radiance(tree, node); + } + else { + int i; + + for (i=0; i<8; i++) + if (node->child[i]) + sum_radiance(tree, node->child[i]); + + sum_branch_radiance(tree, node); + } +} + +static void subnode_middle(int i, float *mid, float *subsize, float *submid) +{ + int x= i & 1, y= i & 2, z= i & 4; + + submid[0]= mid[0] + ((x)? subsize[0]: -subsize[0]); + submid[1]= mid[1] + ((y)? subsize[1]: -subsize[1]); + submid[2]= mid[2] + ((z)? subsize[2]: -subsize[2]); +} + +static void create_octree_node(ScatterTree *tree, ScatterNode *node, float *mid, float *size, ScatterPoint **refpoints, int depth) +{ + ScatterNode *subnode; + ScatterPoint **subrefpoints, **tmppoints= tree->tmppoints; + int index, nsize[8], noffset[8], i, subco, used_nodes, usedi; + float submid[3], subsize[3]; + + /* stopping condition */ + if (node->totpoint <= MAX_OCTREE_NODE_POINTS || depth == MAX_OCTREE_DEPTH) { + for (i=0; i<node->totpoint; i++) + node->points[i]= *(refpoints[i]); + + return; + } + + subsize[0]= size[0]*0.5f; + subsize[1]= size[1]*0.5f; + subsize[2]= size[2]*0.5f; + + node->split[0]= mid[0]; + node->split[1]= mid[1]; + node->split[2]= mid[2]; + + memset(nsize, 0, sizeof(nsize)); + memset(noffset, 0, sizeof(noffset)); + + /* count points in subnodes */ + for (i=0; i<node->totpoint; i++) { + index= SUBNODE_INDEX(refpoints[i]->co, node->split); + tmppoints[i]= refpoints[i]; + nsize[index]++; + } + + /* here we check if only one subnode is used. if this is the case, we don't + * create a new node, but rather call this function again, with different + * size and middle position for the same node. */ + for (usedi=0, used_nodes=0, i=0; i<8; i++) { + if (nsize[i]) { + used_nodes++; + usedi = i; + } + if (i != 0) + noffset[i]= noffset[i-1]+nsize[i-1]; + } + + if (used_nodes <= 1) { + subnode_middle(usedi, mid, subsize, submid); + create_octree_node(tree, node, submid, subsize, refpoints, depth+1); + return; + } + + /* reorder refpoints by subnode */ + for (i=0; i<node->totpoint; i++) { + index= SUBNODE_INDEX(tmppoints[i]->co, node->split); + refpoints[noffset[index]]= tmppoints[i]; + noffset[index]++; + } + + /* create subnodes */ + for (subco=0, i=0; i<8; subco+=nsize[i], i++) { + if (nsize[i] > 0) { + subnode= BLI_memarena_alloc(tree->arena, sizeof(ScatterNode)); + node->child[i]= subnode; + subnode->points= node->points + subco; + subnode->totpoint= nsize[i]; + subrefpoints= refpoints + subco; + + subnode_middle(i, mid, subsize, submid); + + create_octree_node(tree, subnode, submid, subsize, subrefpoints, + depth+1); + } + else + node->child[i]= NULL; + } + + node->points= NULL; + node->totpoint= 0; +} + +/* public functions */ + +ScatterTree *scatter_tree_new(ScatterSettings *ss[3], float scale, float error, + float (*co)[3], float (*color)[3], float *area, int totpoint) +{ + ScatterTree *tree; + ScatterPoint *points, **refpoints; + int i; + + /* allocate tree */ + tree= MEM_callocN(sizeof(ScatterTree), "ScatterTree"); + tree->scale= scale; + tree->error= error; + tree->totpoint= totpoint; + + tree->ss[0]= ss[0]; + tree->ss[1]= ss[1]; + tree->ss[2]= ss[2]; + + points = MEM_callocN(sizeof(ScatterPoint) * totpoint, "ScatterPoints"); + refpoints = MEM_callocN(sizeof(ScatterPoint *) * totpoint, "ScatterRefPoints"); + + tree->points= points; + tree->refpoints= refpoints; + + /* build points */ + INIT_MINMAX(tree->min, tree->max); + + for (i=0; i<totpoint; i++) { + copy_v3_v3(points[i].co, co[i]); + copy_v3_v3(points[i].rad, color[i]); + points[i].area= fabsf(area[i])/(tree->scale*tree->scale); + points[i].back= (area[i] < 0.0f); + + mul_v3_fl(points[i].co, 1.0f / tree->scale); + minmax_v3v3_v3(tree->min, tree->max, points[i].co); + + refpoints[i]= points + i; + } + + return tree; +} + +void scatter_tree_build(ScatterTree *tree) +{ + ScatterPoint *newpoints, **tmppoints; + float mid[3], size[3]; + int totpoint= tree->totpoint; + + newpoints = MEM_callocN(sizeof(ScatterPoint) * totpoint, "ScatterPoints"); + tmppoints = MEM_callocN(sizeof(ScatterPoint *) * totpoint, "ScatterTmpPoints"); + tree->tmppoints= tmppoints; + + tree->arena= BLI_memarena_new(0x8000 * sizeof(ScatterNode), "sss tree arena"); + BLI_memarena_use_calloc(tree->arena); + + /* build tree */ + tree->root= BLI_memarena_alloc(tree->arena, sizeof(ScatterNode)); + tree->root->points= newpoints; + tree->root->totpoint= totpoint; + + mid[0]= (tree->min[0]+tree->max[0])*0.5f; + mid[1]= (tree->min[1]+tree->max[1])*0.5f; + mid[2]= (tree->min[2]+tree->max[2])*0.5f; + + size[0]= (tree->max[0]-tree->min[0])*0.5f; + size[1]= (tree->max[1]-tree->min[1])*0.5f; + size[2]= (tree->max[2]-tree->min[2])*0.5f; + + create_octree_node(tree, tree->root, mid, size, tree->refpoints, 0); + + MEM_freeN(tree->points); + MEM_freeN(tree->refpoints); + MEM_freeN(tree->tmppoints); + tree->refpoints= NULL; + tree->tmppoints= NULL; + tree->points= newpoints; + + /* sum radiance at nodes */ + sum_radiance(tree, tree->root); +} + +void scatter_tree_sample(ScatterTree *tree, const float co[3], float color[3]) +{ + float sco[3]; + + copy_v3_v3(sco, co); + mul_v3_fl(sco, 1.0f / tree->scale); + + compute_radiance(tree, sco, color); +} + +void scatter_tree_free(ScatterTree *tree) +{ + if (tree->arena) BLI_memarena_free(tree->arena); + if (tree->points) MEM_freeN(tree->points); + if (tree->refpoints) MEM_freeN(tree->refpoints); + + MEM_freeN(tree); +} + +/* Internal Renderer API */ + +/* sss tree building */ + +typedef struct SSSData { + ScatterTree *tree; + ScatterSettings *ss[3]; +} SSSData; + +typedef struct SSSPoints { + struct SSSPoints *next, *prev; + + float (*co)[3]; + float (*color)[3]; + float *area; + int totpoint; +} SSSPoints; + +static void sss_create_tree_mat(Render *re, Material *mat) +{ + SSSPoints *p; + RenderResult *rr; + ListBase points; + float (*co)[3] = NULL, (*color)[3] = NULL, *area = NULL; + int totpoint = 0, osa, osaflag, frsflag, partsdone; + + if (re->test_break(re->tbh)) + return; + + points.first= points.last= NULL; + + /* TODO: this is getting a bit ugly, copying all those variables and + * setting them back, maybe we need to create our own Render? */ + + /* do SSS preprocessing render */ + BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE); + rr= re->result; + osa= re->osa; + osaflag= re->r.mode & R_OSA; + frsflag= re->r.mode & R_EDGE_FRS; + partsdone= re->i.partsdone; + + re->osa= 0; + re->r.mode &= ~(R_OSA | R_EDGE_FRS); + re->sss_points= &points; + re->sss_mat= mat; + re->i.partsdone = 0; + + if (!(re->r.scemode & (R_BUTS_PREVIEW|R_VIEWPORT_PREVIEW))) + re->result= NULL; + BLI_rw_mutex_unlock(&re->resultmutex); + + RE_TileProcessor(re); + + BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE); + if (!(re->r.scemode & (R_BUTS_PREVIEW|R_VIEWPORT_PREVIEW))) { + RE_FreeRenderResult(re->result); + re->result= rr; + } + BLI_rw_mutex_unlock(&re->resultmutex); + + re->i.partsdone= partsdone; + re->sss_mat= NULL; + re->sss_points= NULL; + re->osa= osa; + if (osaflag) re->r.mode |= R_OSA; + if (frsflag) re->r.mode |= R_EDGE_FRS; + + /* no points? no tree */ + if (!points.first) + return; + + /* merge points together into a single buffer */ + if (!re->test_break(re->tbh)) { + for (totpoint=0, p=points.first; p; p=p->next) + totpoint += p->totpoint; + + co= MEM_mallocN(sizeof(*co)*totpoint, "SSSCo"); + color= MEM_mallocN(sizeof(*color)*totpoint, "SSSColor"); + area= MEM_mallocN(sizeof(*area)*totpoint, "SSSArea"); + + for (totpoint=0, p=points.first; p; p=p->next) { + memcpy(co+totpoint, p->co, sizeof(*co)*p->totpoint); + memcpy(color+totpoint, p->color, sizeof(*color)*p->totpoint); + memcpy(area+totpoint, p->area, sizeof(*area)*p->totpoint); + totpoint += p->totpoint; + } + } + + /* free points */ + for (p=points.first; p; p=p->next) { + MEM_freeN(p->co); + MEM_freeN(p->color); + MEM_freeN(p->area); + } + BLI_freelistN(&points); + + /* build tree */ + if (!re->test_break(re->tbh)) { + SSSData *sss= MEM_callocN(sizeof(*sss), "SSSData"); + float ior= mat->sss_ior, cfac= mat->sss_colfac; + const float *radius = mat->sss_radius; + float fw= mat->sss_front, bw= mat->sss_back; + float error = mat->sss_error; + + error= get_render_aosss_error(&re->r, error); + if ((re->r.scemode & (R_BUTS_PREVIEW|R_VIEWPORT_PREVIEW)) && error < 0.5f) + error= 0.5f; + + sss->ss[0]= scatter_settings_new(mat->sss_col[0], radius[0], ior, cfac, fw, bw); + sss->ss[1]= scatter_settings_new(mat->sss_col[1], radius[1], ior, cfac, fw, bw); + sss->ss[2]= scatter_settings_new(mat->sss_col[2], radius[2], ior, cfac, fw, bw); + sss->tree= scatter_tree_new(sss->ss, mat->sss_scale, error, + co, color, area, totpoint); + + MEM_freeN(co); + MEM_freeN(color); + MEM_freeN(area); + + scatter_tree_build(sss->tree); + + BLI_ghash_insert(re->sss_hash, mat, sss); + } + else { + if (co) MEM_freeN(co); + if (color) MEM_freeN(color); + if (area) MEM_freeN(area); + } +} + +void sss_add_points(Render *re, float (*co)[3], float (*color)[3], float *area, int totpoint) +{ + SSSPoints *p; + + if (totpoint > 0) { + p= MEM_callocN(sizeof(SSSPoints), "SSSPoints"); + + p->co= co; + p->color= color; + p->area= area; + p->totpoint= totpoint; + + BLI_thread_lock(LOCK_CUSTOM1); + BLI_addtail(re->sss_points, p); + BLI_thread_unlock(LOCK_CUSTOM1); + } +} + +static void sss_free_tree(SSSData *sss) +{ + scatter_tree_free(sss->tree); + scatter_settings_free(sss->ss[0]); + scatter_settings_free(sss->ss[1]); + scatter_settings_free(sss->ss[2]); + MEM_freeN(sss); +} + +/* public functions */ + +void make_sss_tree(Render *re) +{ + Material *mat; + bool infostr_set = false; + const char *prevstr = NULL; + + free_sss(re); + + re->sss_hash= BLI_ghash_ptr_new("make_sss_tree gh"); + + re->stats_draw(re->sdh, &re->i); + + for (mat= re->main->mat.first; mat; mat= mat->id.next) { + if (mat->id.us && (mat->flag & MA_IS_USED) && (mat->sss_flag & MA_DIFF_SSS)) { + if (!infostr_set) { + prevstr = re->i.infostr; + re->i.infostr = IFACE_("SSS preprocessing"); + infostr_set = true; + } + + sss_create_tree_mat(re, mat); + } + } + + /* XXX preview exception */ + /* localizing preview render data is not fun for node trees :( */ + if (re->main!=G.main) { + for (mat= G.main->mat.first; mat; mat= mat->id.next) { + if (mat->id.us && (mat->flag & MA_IS_USED) && (mat->sss_flag & MA_DIFF_SSS)) { + if (!infostr_set) { + prevstr = re->i.infostr; + re->i.infostr = IFACE_("SSS preprocessing"); + infostr_set = true; + } + + sss_create_tree_mat(re, mat); + } + } + } + + if (infostr_set) + re->i.infostr = prevstr; +} + +void free_sss(Render *re) +{ + if (re->sss_hash) { + GHashIterator gh_iter; + + GHASH_ITER (gh_iter, re->sss_hash) { + sss_free_tree(BLI_ghashIterator_getValue(&gh_iter)); + } + + BLI_ghash_free(re->sss_hash, NULL, NULL); + re->sss_hash= NULL; + } +} + +int sample_sss(Render *re, Material *mat, const float co[3], float color[3]) +{ + if (re->sss_hash) { + SSSData *sss= BLI_ghash_lookup(re->sss_hash, mat); + + if (sss) { + scatter_tree_sample(sss->tree, co, color); + return 1; + } + else { + color[0]= 0.0f; + color[1]= 0.0f; + color[2]= 0.0f; + } + } + + return 0; +} + +int sss_pass_done(struct Render *re, struct Material *mat) +{ + return ((re->flag & R_BAKING) || !(re->r.mode & R_SSS) || (re->sss_hash && BLI_ghash_lookup(re->sss_hash, mat))); +} + diff --git a/source/blender/render/intern/source/strand.c b/source/blender/render/intern/source/strand.c new file mode 100644 index 00000000000..5fde688481a --- /dev/null +++ b/source/blender/render/intern/source/strand.c @@ -0,0 +1,1069 @@ +/* + * ***** 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. + * + * Contributors: Brecht Van Lommel. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/render/intern/source/strand.c + * \ingroup render + */ + + +#include <math.h> +#include <string.h> +#include <stdlib.h> + +#include "MEM_guardedalloc.h" + +#include "DNA_key_types.h" +#include "DNA_material_types.h" +#include "DNA_meshdata_types.h" + +#include "BLI_math.h" +#include "BLI_blenlib.h" +#include "BLI_utildefines.h" +#include "BLI_ghash.h" +#include "BLI_memarena.h" +#include "BLI_rand.h" + +#include "BKE_DerivedMesh.h" +#include "BKE_key.h" + + +#include "render_types.h" +#include "rendercore.h" +#include "renderdatabase.h" +#include "shading.h" +#include "strand.h" +#include "zbuf.h" + +/* *************** */ + +static float strand_eval_width(Material *ma, float strandco) +{ + float fac; + + strandco= 0.5f*(strandco + 1.0f); + + if (ma->strand_ease!=0.0f) { + if (ma->strand_ease<0.0f) + fac= pow(strandco, 1.0f+ma->strand_ease); + else + fac= pow(strandco, 1.0f/(1.0f-ma->strand_ease)); + } + else fac= strandco; + + return ((1.0f-fac)*ma->strand_sta + (fac)*ma->strand_end); +} + +void strand_eval_point(StrandSegment *sseg, StrandPoint *spoint) +{ + Material *ma; + StrandBuffer *strandbuf; + const float *simplify; + float p[4][3], data[4], cross[3], w, dx, dy, t; + int type; + + strandbuf= sseg->buffer; + ma= sseg->buffer->ma; + t= spoint->t; + type= (strandbuf->flag & R_STRAND_BSPLINE)? KEY_BSPLINE: KEY_CARDINAL; + + copy_v3_v3(p[0], sseg->v[0]->co); + copy_v3_v3(p[1], sseg->v[1]->co); + copy_v3_v3(p[2], sseg->v[2]->co); + copy_v3_v3(p[3], sseg->v[3]->co); + + if (sseg->obi->flag & R_TRANSFORMED) { + mul_m4_v3(sseg->obi->mat, p[0]); + mul_m4_v3(sseg->obi->mat, p[1]); + mul_m4_v3(sseg->obi->mat, p[2]); + mul_m4_v3(sseg->obi->mat, p[3]); + } + + if (t == 0.0f) { + copy_v3_v3(spoint->co, p[1]); + spoint->strandco= sseg->v[1]->strandco; + + spoint->dtstrandco= (sseg->v[2]->strandco - sseg->v[0]->strandco); + if (sseg->v[0] != sseg->v[1]) + spoint->dtstrandco *= 0.5f; + } + else if (t == 1.0f) { + copy_v3_v3(spoint->co, p[2]); + spoint->strandco= sseg->v[2]->strandco; + + spoint->dtstrandco= (sseg->v[3]->strandco - sseg->v[1]->strandco); + if (sseg->v[3] != sseg->v[2]) + spoint->dtstrandco *= 0.5f; + } + else { + key_curve_position_weights(t, data, type); + spoint->co[0]= data[0]*p[0][0] + data[1]*p[1][0] + data[2]*p[2][0] + data[3]*p[3][0]; + spoint->co[1]= data[0]*p[0][1] + data[1]*p[1][1] + data[2]*p[2][1] + data[3]*p[3][1]; + spoint->co[2]= data[0]*p[0][2] + data[1]*p[1][2] + data[2]*p[2][2] + data[3]*p[3][2]; + spoint->strandco= (1.0f-t)*sseg->v[1]->strandco + t*sseg->v[2]->strandco; + } + + key_curve_tangent_weights(t, data, type); + spoint->dtco[0]= data[0]*p[0][0] + data[1]*p[1][0] + data[2]*p[2][0] + data[3]*p[3][0]; + spoint->dtco[1]= data[0]*p[0][1] + data[1]*p[1][1] + data[2]*p[2][1] + data[3]*p[3][1]; + spoint->dtco[2]= data[0]*p[0][2] + data[1]*p[1][2] + data[2]*p[2][2] + data[3]*p[3][2]; + + normalize_v3_v3(spoint->tan, spoint->dtco); + normalize_v3_v3(spoint->nor, spoint->co); + negate_v3(spoint->nor); + + spoint->width= strand_eval_width(ma, spoint->strandco); + + /* simplification */ + simplify= RE_strandren_get_simplify(strandbuf->obr, sseg->strand, 0); + spoint->alpha= (simplify)? simplify[1]: 1.0f; + + /* outer points */ + cross_v3_v3v3(cross, spoint->co, spoint->tan); + + w= spoint->co[2]*strandbuf->winmat[2][3] + strandbuf->winmat[3][3]; + dx= strandbuf->winx*cross[0]*strandbuf->winmat[0][0]/w; + dy= strandbuf->winy*cross[1]*strandbuf->winmat[1][1]/w; + w = sqrtf(dx * dx + dy * dy); + + if (w > 0.0f) { + if (strandbuf->flag & R_STRAND_B_UNITS) { + const float crosslen= len_v3(cross); + w= 2.0f*crosslen*strandbuf->minwidth/w; + + if (spoint->width < w) { + spoint->alpha= spoint->width/w; + spoint->width= w; + } + + if (simplify) + /* squared because we only change width, not length */ + spoint->width *= simplify[0]*simplify[0]; + + mul_v3_fl(cross, spoint->width*0.5f/crosslen); + } + else + mul_v3_fl(cross, spoint->width/w); + } + + sub_v3_v3v3(spoint->co1, spoint->co, cross); + add_v3_v3v3(spoint->co2, spoint->co, cross); + + copy_v3_v3(spoint->dsco, cross); +} + +/* *************** */ + +static void interpolate_vec1(float *v1, float *v2, float t, float negt, float *v) +{ + v[0]= negt*v1[0] + t*v2[0]; +} + +static void interpolate_vec3(float *v1, float *v2, float t, float negt, float *v) +{ + v[0]= negt*v1[0] + t*v2[0]; + v[1]= negt*v1[1] + t*v2[1]; + v[2]= negt*v1[2] + t*v2[2]; +} + +static void interpolate_vec4(float *v1, float *v2, float t, float negt, float *v) +{ + v[0]= negt*v1[0] + t*v2[0]; + v[1]= negt*v1[1] + t*v2[1]; + v[2]= negt*v1[2] + t*v2[2]; + v[3]= negt*v1[3] + t*v2[3]; +} + +static void interpolate_shade_result(ShadeResult *shr1, ShadeResult *shr2, float t, ShadeResult *shr, int addpassflag) +{ + float negt= 1.0f - t; + + interpolate_vec4(shr1->combined, shr2->combined, t, negt, shr->combined); + + if (addpassflag & SCE_PASS_VECTOR) { + interpolate_vec4(shr1->winspeed, shr2->winspeed, t, negt, shr->winspeed); + } + /* optim... */ + if (addpassflag & ~(SCE_PASS_VECTOR)) { + if (addpassflag & SCE_PASS_Z) + interpolate_vec1(&shr1->z, &shr2->z, t, negt, &shr->z); + if (addpassflag & SCE_PASS_RGBA) + interpolate_vec4(shr1->col, shr2->col, t, negt, shr->col); + if (addpassflag & SCE_PASS_NORMAL) { + interpolate_vec3(shr1->nor, shr2->nor, t, negt, shr->nor); + normalize_v3(shr->nor); + } + if (addpassflag & SCE_PASS_EMIT) + interpolate_vec3(shr1->emit, shr2->emit, t, negt, shr->emit); + if (addpassflag & SCE_PASS_DIFFUSE) { + interpolate_vec3(shr1->diff, shr2->diff, t, negt, shr->diff); + interpolate_vec3(shr1->diffshad, shr2->diffshad, t, negt, shr->diffshad); + } + if (addpassflag & SCE_PASS_SPEC) + interpolate_vec3(shr1->spec, shr2->spec, t, negt, shr->spec); + if (addpassflag & SCE_PASS_SHADOW) + interpolate_vec3(shr1->shad, shr2->shad, t, negt, shr->shad); + if (addpassflag & SCE_PASS_AO) + interpolate_vec3(shr1->ao, shr2->ao, t, negt, shr->ao); + if (addpassflag & SCE_PASS_ENVIRONMENT) + interpolate_vec3(shr1->env, shr2->env, t, negt, shr->env); + if (addpassflag & SCE_PASS_INDIRECT) + interpolate_vec3(shr1->indirect, shr2->indirect, t, negt, shr->indirect); + if (addpassflag & SCE_PASS_REFLECT) + interpolate_vec3(shr1->refl, shr2->refl, t, negt, shr->refl); + if (addpassflag & SCE_PASS_REFRACT) + interpolate_vec3(shr1->refr, shr2->refr, t, negt, shr->refr); + if (addpassflag & SCE_PASS_MIST) + interpolate_vec1(&shr1->mist, &shr2->mist, t, negt, &shr->mist); + } +} + +static void strand_apply_shaderesult_alpha(ShadeResult *shr, float alpha) +{ + if (alpha < 1.0f) { + shr->combined[0] *= alpha; + shr->combined[1] *= alpha; + shr->combined[2] *= alpha; + shr->combined[3] *= alpha; + + shr->col[0] *= alpha; + shr->col[1] *= alpha; + shr->col[2] *= alpha; + shr->col[3] *= alpha; + + shr->alpha *= alpha; + } +} + +static void strand_shade_point(Render *re, ShadeSample *ssamp, StrandSegment *sseg, StrandVert *svert, StrandPoint *spoint) +{ + ShadeInput *shi= ssamp->shi; + ShadeResult *shr= ssamp->shr; + VlakRen vlr; + int seed; + + memset(&vlr, 0, sizeof(vlr)); + vlr.flag= R_SMOOTH; + if (sseg->buffer->ma->mode & MA_TANGENT_STR) + vlr.flag |= R_TANGENT; + + shi->vlr= &vlr; + shi->v1= NULL; + shi->v2= NULL; + shi->v3= NULL; + shi->strand= sseg->strand; + shi->obi= sseg->obi; + shi->obr= sseg->obi->obr; + + /* cache for shadow */ + shi->samplenr= re->shadowsamplenr[shi->thread]++; + + /* all samples */ + shi->mask= 0xFFFF; + + /* seed RNG for consistent results across tiles */ + seed = shi->strand->index + (svert - shi->strand->vert); + BLI_thread_srandom(shi->thread, seed); + + shade_input_set_strand(shi, sseg->strand, spoint); + shade_input_set_strand_texco(shi, sseg->strand, sseg->v[1], spoint); + + /* init material vars */ + shade_input_init_material(shi); + + /* shade */ + shade_samples_do_AO(ssamp); + shade_input_do_shade(shi, shr); + + /* apply simplification */ + strand_apply_shaderesult_alpha(shr, spoint->alpha); + + /* include lamphalos for strand, since halo layer was added already */ + if (re->flag & R_LAMPHALO) + if (shi->layflag & SCE_LAY_HALO) + renderspothalo(shi, shr->combined, shr->combined[3]); + + shi->strand= NULL; +} + +/* *************** */ + +struct StrandShadeCache { + GHash *resulthash; + GHash *refcounthash; + MemArena *memarena; +}; + +typedef struct StrandCacheEntry { + GHashPair pair; + ShadeResult shr; +} StrandCacheEntry; + +StrandShadeCache *strand_shade_cache_create(void) +{ + StrandShadeCache *cache; + + cache= MEM_callocN(sizeof(StrandShadeCache), "StrandShadeCache"); + cache->resulthash= BLI_ghash_pair_new("strand_shade_cache_create1 gh"); + cache->refcounthash= BLI_ghash_pair_new("strand_shade_cache_create2 gh"); + cache->memarena= BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "strand shade cache arena"); + + return cache; +} + +void strand_shade_cache_free(StrandShadeCache *cache) +{ + BLI_ghash_free(cache->refcounthash, NULL, NULL); + BLI_ghash_free(cache->resulthash, MEM_freeN, NULL); + BLI_memarena_free(cache->memarena); + MEM_freeN(cache); +} + +static GHashPair strand_shade_hash_pair(ObjectInstanceRen *obi, StrandVert *svert) +{ + GHashPair pair = {obi, svert}; + return pair; +} + +static void strand_shade_get(Render *re, StrandShadeCache *cache, ShadeSample *ssamp, StrandSegment *sseg, StrandVert *svert) +{ + StrandCacheEntry *entry; + StrandPoint p; + int *refcount; + GHashPair pair = strand_shade_hash_pair(sseg->obi, svert); + + entry= BLI_ghash_lookup(cache->resulthash, &pair); + refcount= BLI_ghash_lookup(cache->refcounthash, &pair); + + if (!entry) { + /* not shaded yet, shade and insert into hash */ + p.t= (sseg->v[1] == svert)? 0.0f: 1.0f; + strand_eval_point(sseg, &p); + strand_shade_point(re, ssamp, sseg, svert, &p); + + entry= MEM_callocN(sizeof(StrandCacheEntry), "StrandCacheEntry"); + entry->pair = pair; + entry->shr = ssamp->shr[0]; + BLI_ghash_insert(cache->resulthash, entry, entry); + } + else + /* already shaded, just copy previous result from hash */ + ssamp->shr[0]= entry->shr; + + /* lower reference count and remove if not needed anymore by any samples */ + (*refcount)--; + if (*refcount == 0) { + BLI_ghash_remove(cache->resulthash, &pair, MEM_freeN, NULL); + BLI_ghash_remove(cache->refcounthash, &pair, NULL, NULL); + } +} + +void strand_shade_segment(Render *re, StrandShadeCache *cache, StrandSegment *sseg, ShadeSample *ssamp, float t, float s, int addpassflag) +{ + ShadeResult shr1, shr2; + + /* get shading for two endpoints and interpolate */ + strand_shade_get(re, cache, ssamp, sseg, sseg->v[1]); + shr1= ssamp->shr[0]; + strand_shade_get(re, cache, ssamp, sseg, sseg->v[2]); + shr2= ssamp->shr[0]; + + interpolate_shade_result(&shr1, &shr2, t, ssamp->shr, addpassflag); + + /* apply alpha along width */ + if (sseg->buffer->widthfade != -1.0f) { + s = 1.0f - powf(fabsf(s), sseg->buffer->widthfade); + + strand_apply_shaderesult_alpha(ssamp->shr, s); + } +} + +void strand_shade_unref(StrandShadeCache *cache, ObjectInstanceRen *obi, StrandVert *svert) +{ + GHashPair pair = strand_shade_hash_pair(obi, svert); + int *refcount; + + /* lower reference count and remove if not needed anymore by any samples */ + refcount= BLI_ghash_lookup(cache->refcounthash, &pair); + + (*refcount)--; + if (*refcount == 0) { + BLI_ghash_remove(cache->resulthash, &pair, MEM_freeN, NULL); + BLI_ghash_remove(cache->refcounthash, &pair, NULL, NULL); + } +} + +static void strand_shade_refcount(StrandShadeCache *cache, StrandSegment *sseg, StrandVert *svert) +{ + GHashPair pair = strand_shade_hash_pair(sseg->obi, svert); + GHashPair *key; + int *refcount= BLI_ghash_lookup(cache->refcounthash, &pair); + + if (!refcount) { + key= BLI_memarena_alloc(cache->memarena, sizeof(GHashPair)); + *key = pair; + refcount= BLI_memarena_alloc(cache->memarena, sizeof(int)); + *refcount= 1; + BLI_ghash_insert(cache->refcounthash, key, refcount); + } + else + (*refcount)++; +} + +/* *************** */ + +typedef struct StrandPart { + Render *re; + ZSpan *zspan; + + APixstrand *apixbuf; + int *totapixbuf; + int *rectz; + int *rectmask; + intptr_t *rectdaps; + int rectx, recty; + int sample; + int shadow; + float (*jit)[2]; + int samples; + + StrandSegment *segment; + float t[3], s[3]; + + StrandShadeCache *cache; +} StrandPart; + +typedef struct StrandSortSegment { + struct StrandSortSegment *next; + int obi, strand, segment; + float z; +} StrandSortSegment; + +static int compare_strand_segment(const void *poin1, const void *poin2) +{ + const StrandSortSegment *seg1= (const StrandSortSegment*)poin1; + const StrandSortSegment *seg2= (const StrandSortSegment*)poin2; + + if (seg1->z < seg2->z) + return -1; + else if (seg1->z == seg2->z) + return 0; + else + return 1; +} + +static void do_strand_point_project(float winmat[4][4], ZSpan *zspan, float *co, float *hoco, float *zco) +{ + projectvert(co, winmat, hoco); + hoco_to_zco(zspan, zco, hoco); +} + +static void strand_project_point(float winmat[4][4], float winx, float winy, StrandPoint *spoint) +{ + float div; + + projectvert(spoint->co, winmat, spoint->hoco); + + div= 1.0f/spoint->hoco[3]; + spoint->x= spoint->hoco[0]*div*winx*0.5f; + spoint->y= spoint->hoco[1]*div*winy*0.5f; +} + +static APixstrand *addpsmainAstrand(ListBase *lb) +{ + APixstrMain *psm; + + psm= MEM_mallocN(sizeof(APixstrMain), "addpsmainA"); + BLI_addtail(lb, psm); + psm->ps = MEM_callocN(4096 * sizeof(APixstrand), "pixstr"); + + return psm->ps; +} + +static APixstrand *addpsAstrand(ZSpan *zspan) +{ + /* make new PS */ + if (zspan->apstrandmcounter==0) { + zspan->curpstrand= addpsmainAstrand(zspan->apsmbase); + zspan->apstrandmcounter= 4095; + } + else { + zspan->curpstrand++; + zspan->apstrandmcounter--; + } + return zspan->curpstrand; +} + +#define MAX_ZROW 2000 + +static void do_strand_fillac(void *handle, int x, int y, float u, float v, float z) +{ + StrandPart *spart= (StrandPart *)handle; + StrandShadeCache *cache= spart->cache; + StrandSegment *sseg= spart->segment; + APixstrand *apn, *apnew; + float t, s; + int offset, mask, obi, strnr, seg, zverg, bufferz, maskz=0; + + offset = y*spart->rectx + x; + obi= sseg->obi - spart->re->objectinstance; + strnr= sseg->strand->index + 1; + seg= sseg->v[1] - sseg->strand->vert; + mask= (1<<spart->sample); + + /* check against solid z-buffer */ + zverg= (int)z; + + if (spart->rectdaps) { + /* find the z of the sample */ + PixStr *ps; + intptr_t *rd= spart->rectdaps + offset; + + bufferz= 0x7FFFFFFF; + if (spart->rectmask) maskz= 0x7FFFFFFF; + + if (*rd) { + for (ps= (PixStr *)(*rd); ps; ps= ps->next) { + if (mask & ps->mask) { + bufferz= ps->z; + if (spart->rectmask) + maskz= ps->maskz; + break; + } + } + } + } + else { + bufferz= (spart->rectz)? spart->rectz[offset]: 0x7FFFFFFF; + if (spart->rectmask) + maskz= spart->rectmask[offset]; + } + +#define CHECK_ADD(n) \ + if (apn->p[n]==strnr && apn->obi[n]==obi && apn->seg[n]==seg) \ + { if (!(apn->mask[n] & mask)) { apn->mask[n] |= mask; apn->v[n] += t; apn->u[n] += s; } break; } (void)0 +#define CHECK_ASSIGN(n) \ + if (apn->p[n]==0) \ + {apn->obi[n]= obi; apn->p[n]= strnr; apn->z[n]= zverg; apn->mask[n]= mask; apn->v[n]= t; apn->u[n]= s; apn->seg[n]= seg; break; } (void)0 + + /* add to pixel list */ + if (zverg < bufferz && (spart->totapixbuf[offset] < MAX_ZROW)) { + if (!spart->rectmask || zverg > maskz) { + t = u * spart->t[0] + v * spart->t[1] + (1.0f - u - v) * spart->t[2]; + s = fabsf(u * spart->s[0] + v * spart->s[1] + (1.0f - u - v) * spart->s[2]); + + apn= spart->apixbuf + offset; + while (apn) { + CHECK_ADD(0); + CHECK_ADD(1); + CHECK_ADD(2); + CHECK_ADD(3); + CHECK_ASSIGN(0); + CHECK_ASSIGN(1); + CHECK_ASSIGN(2); + CHECK_ASSIGN(3); + + apnew= addpsAstrand(spart->zspan); + SWAP(APixstrand, *apnew, *apn); + apn->next= apnew; + CHECK_ASSIGN(0); + } + + if (cache) { + strand_shade_refcount(cache, sseg, sseg->v[1]); + strand_shade_refcount(cache, sseg, sseg->v[2]); + } + spart->totapixbuf[offset]++; + } + } +} + +/* width is calculated in hoco space, to ensure strands are visible */ +static int strand_test_clip(float winmat[4][4], ZSpan *UNUSED(zspan), float *bounds, float *co, float *zcomp, float widthx, float widthy) +{ + float hoco[4]; + int clipflag= 0; + + projectvert(co, winmat, hoco); + + /* we compare z without perspective division for segment sorting */ + *zcomp= hoco[2]; + + if (hoco[0]+widthx < bounds[0]*hoco[3]) clipflag |= 1; + else if (hoco[0]-widthx > bounds[1]*hoco[3]) clipflag |= 2; + + if (hoco[1]-widthy > bounds[3]*hoco[3]) clipflag |= 4; + else if (hoco[1]+widthy < bounds[2]*hoco[3]) clipflag |= 8; + + clipflag |= testclip(hoco); + + return clipflag; +} + +static void do_scanconvert_strand(Render *UNUSED(re), StrandPart *spart, ZSpan *zspan, float t, float dt, float *co1, float *co2, float *co3, float *co4, int sample) +{ + float jco1[3], jco2[3], jco3[3], jco4[3], jx, jy; + + copy_v3_v3(jco1, co1); + copy_v3_v3(jco2, co2); + copy_v3_v3(jco3, co3); + copy_v3_v3(jco4, co4); + + if (spart->jit) { + jx= -spart->jit[sample][0]; + jy= -spart->jit[sample][1]; + + jco1[0] += jx; jco1[1] += jy; + jco2[0] += jx; jco2[1] += jy; + jco3[0] += jx; jco3[1] += jy; + jco4[0] += jx; jco4[1] += jy; + + /* XXX mblur? */ + } + + spart->sample= sample; + + spart->t[0]= t-dt; + spart->s[0]= -1.0f; + spart->t[1]= t-dt; + spart->s[1]= 1.0f; + spart->t[2]= t; + spart->s[2]= 1.0f; + zspan_scanconvert_strand(zspan, spart, jco1, jco2, jco3, do_strand_fillac); + spart->t[0]= t-dt; + spart->s[0]= -1.0f; + spart->t[1]= t; + spart->s[1]= 1.0f; + spart->t[2]= t; + spart->s[2]= -1.0f; + zspan_scanconvert_strand(zspan, spart, jco1, jco3, jco4, do_strand_fillac); +} + +static void strand_render(Render *re, StrandSegment *sseg, float winmat[4][4], StrandPart *spart, ZSpan *zspan, int totzspan, StrandPoint *p1, StrandPoint *p2) +{ + if (spart) { + float t= p2->t; + float dt= p2->t - p1->t; + int a; + + for (a=0; a<spart->samples; a++) + do_scanconvert_strand(re, spart, zspan, t, dt, p1->zco2, p1->zco1, p2->zco1, p2->zco2, a); + } + else { + float hoco1[4], hoco2[4]; + int a, obi, index; + + obi= sseg->obi - re->objectinstance; + index= sseg->strand->index; + + projectvert(p1->co, winmat, hoco1); + projectvert(p2->co, winmat, hoco2); + + + for (a=0; a<totzspan; a++) { +#if 0 + /* render both strand and single pixel wire to counter aliasing */ + zbufclip4(re, &zspan[a], obi, index, p1->hoco2, p1->hoco1, p2->hoco1, p2->hoco2, p1->clip2, p1->clip1, p2->clip1, p2->clip2); +#endif + /* only render a line for now, which makes the shadow map more + * similar across frames, and so reduces flicker */ + zbufsinglewire(&zspan[a], obi, index, hoco1, hoco2); + } + } +} + +static int strand_segment_recursive(Render *re, float winmat[4][4], StrandPart *spart, ZSpan *zspan, int totzspan, StrandSegment *sseg, StrandPoint *p1, StrandPoint *p2, int depth) +{ + StrandPoint p; + StrandBuffer *buffer= sseg->buffer; + float dot, d1[2], d2[2], len1, len2; + + if (depth == buffer->maxdepth) + return 0; + + p.t= (p1->t + p2->t)*0.5f; + strand_eval_point(sseg, &p); + strand_project_point(buffer->winmat, buffer->winx, buffer->winy, &p); + + d1[0]= (p.x - p1->x); + d1[1]= (p.y - p1->y); + len1= d1[0]*d1[0] + d1[1]*d1[1]; + + d2[0]= (p2->x - p.x); + d2[1]= (p2->y - p.y); + len2= d2[0]*d2[0] + d2[1]*d2[1]; + + if (len1 == 0.0f || len2 == 0.0f) + return 0; + + dot= d1[0]*d2[0] + d1[1]*d2[1]; + if (dot*dot > sseg->sqadaptcos*len1*len2) + return 0; + + if (spart) { + do_strand_point_project(winmat, zspan, p.co1, p.hoco1, p.zco1); + do_strand_point_project(winmat, zspan, p.co2, p.hoco2, p.zco2); + } + else { +#if 0 + projectvert(p.co1, winmat, p.hoco1); + projectvert(p.co2, winmat, p.hoco2); + p.clip1= testclip(p.hoco1); + p.clip2= testclip(p.hoco2); +#endif + } + + if (!strand_segment_recursive(re, winmat, spart, zspan, totzspan, sseg, p1, &p, depth+1)) + strand_render(re, sseg, winmat, spart, zspan, totzspan, p1, &p); + if (!strand_segment_recursive(re, winmat, spart, zspan, totzspan, sseg, &p, p2, depth+1)) + strand_render(re, sseg, winmat, spart, zspan, totzspan, &p, p2); + + return 1; +} + +void render_strand_segment(Render *re, float winmat[4][4], StrandPart *spart, ZSpan *zspan, int totzspan, StrandSegment *sseg) +{ + StrandBuffer *buffer= sseg->buffer; + StrandPoint *p1= &sseg->point1; + StrandPoint *p2= &sseg->point2; + + p1->t= 0.0f; + p2->t= 1.0f; + + strand_eval_point(sseg, p1); + strand_project_point(buffer->winmat, buffer->winx, buffer->winy, p1); + strand_eval_point(sseg, p2); + strand_project_point(buffer->winmat, buffer->winx, buffer->winy, p2); + + if (spart) { + do_strand_point_project(winmat, zspan, p1->co1, p1->hoco1, p1->zco1); + do_strand_point_project(winmat, zspan, p1->co2, p1->hoco2, p1->zco2); + do_strand_point_project(winmat, zspan, p2->co1, p2->hoco1, p2->zco1); + do_strand_point_project(winmat, zspan, p2->co2, p2->hoco2, p2->zco2); + } + else { +#if 0 + projectvert(p1->co1, winmat, p1->hoco1); + projectvert(p1->co2, winmat, p1->hoco2); + projectvert(p2->co1, winmat, p2->hoco1); + projectvert(p2->co2, winmat, p2->hoco2); + p1->clip1= testclip(p1->hoco1); + p1->clip2= testclip(p1->hoco2); + p2->clip1= testclip(p2->hoco1); + p2->clip2= testclip(p2->hoco2); +#endif + } + + if (!strand_segment_recursive(re, winmat, spart, zspan, totzspan, sseg, p1, p2, 0)) + strand_render(re, sseg, winmat, spart, zspan, totzspan, p1, p2); +} + +/* render call to fill in strands */ +int zbuffer_strands_abuf(Render *re, RenderPart *pa, APixstrand *apixbuf, ListBase *apsmbase, unsigned int lay, int UNUSED(negzmask), float winmat[4][4], int winx, int winy, int samples, float (*jit)[2], float clipcrop, int shadow, StrandShadeCache *cache) +{ + ObjectRen *obr; + ObjectInstanceRen *obi; + ZSpan zspan; + StrandRen *strand = NULL; + StrandVert *svert; + StrandBound *sbound; + StrandPart spart; + StrandSegment sseg; + StrandSortSegment *sortsegments = NULL, *sortseg, *firstseg; + MemArena *memarena; + float z[4], bounds[4], obwinmat[4][4]; + int a, b, c, i, totsegment, clip[4]; + + if (re->test_break(re->tbh)) + return 0; + if (re->totstrand == 0) + return 0; + + /* setup StrandPart */ + memset(&spart, 0, sizeof(spart)); + + spart.re= re; + spart.rectx= pa->rectx; + spart.recty= pa->recty; + spart.apixbuf= apixbuf; + spart.zspan= &zspan; + spart.rectdaps= pa->rectdaps; + spart.rectz= pa->rectz; + spart.rectmask= pa->rectmask; + spart.cache= cache; + spart.shadow= shadow; + spart.jit= jit; + spart.samples= samples; + + zbuf_alloc_span(&zspan, pa->rectx, pa->recty, clipcrop); + + /* needed for transform from hoco to zbuffer co */ + zspan.zmulx= ((float)winx)/2.0f; + zspan.zmuly= ((float)winy)/2.0f; + + zspan.zofsx= -pa->disprect.xmin; + zspan.zofsy= -pa->disprect.ymin; + + /* to center the sample position */ + if (!shadow) { + zspan.zofsx -= 0.5f; + zspan.zofsy -= 0.5f; + } + + zspan.apsmbase= apsmbase; + + /* clipping setup */ + bounds[0]= (2*pa->disprect.xmin - winx-1)/(float)winx; + bounds[1]= (2*pa->disprect.xmax - winx+1)/(float)winx; + bounds[2]= (2*pa->disprect.ymin - winy-1)/(float)winy; + bounds[3]= (2*pa->disprect.ymax - winy+1)/(float)winy; + + memarena= BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "strand sort arena"); + firstseg= NULL; + totsegment= 0; + + /* for all object instances */ + for (obi=re->instancetable.first, i=0; obi; obi=obi->next, i++) { + Material *ma; + float widthx, widthy; + + obr= obi->obr; + + if (!obr->strandbuf || !(obr->strandbuf->lay & lay)) + continue; + + /* compute matrix and try clipping whole object */ + if (obi->flag & R_TRANSFORMED) + mul_m4_m4m4(obwinmat, winmat, obi->mat); + else + copy_m4_m4(obwinmat, winmat); + + /* test if we should skip it */ + ma = obr->strandbuf->ma; + + if (shadow && (!(ma->mode2 & MA_CASTSHADOW) || !(ma->mode & MA_SHADBUF))) + continue; + else if (!shadow && (ma->mode & MA_ONLYCAST)) + continue; + + if (clip_render_object(obi->obr->boundbox, bounds, obwinmat)) + continue; + + widthx= obr->strandbuf->maxwidth*obwinmat[0][0]; + widthy= obr->strandbuf->maxwidth*obwinmat[1][1]; + + /* for each bounding box containing a number of strands */ + sbound= obr->strandbuf->bound; + for (c=0; c<obr->strandbuf->totbound; c++, sbound++) { + if (clip_render_object(sbound->boundbox, bounds, obwinmat)) + continue; + + /* for each strand in this bounding box */ + for (a=sbound->start; a<sbound->end; a++) { + strand= RE_findOrAddStrand(obr, a); + svert= strand->vert; + + /* keep clipping and z depth for 4 control points */ + clip[1]= strand_test_clip(obwinmat, &zspan, bounds, svert->co, &z[1], widthx, widthy); + clip[2]= strand_test_clip(obwinmat, &zspan, bounds, (svert+1)->co, &z[2], widthx, widthy); + clip[0]= clip[1]; z[0]= z[1]; + + for (b=0; b<strand->totvert-1; b++, svert++) { + /* compute 4th point clipping and z depth */ + if (b < strand->totvert-2) { + clip[3]= strand_test_clip(obwinmat, &zspan, bounds, (svert+2)->co, &z[3], widthx, widthy); + } + else { + clip[3]= clip[2]; z[3]= z[2]; + } + + /* check clipping and add to sortsegments buffer */ + if (!(clip[0] & clip[1] & clip[2] & clip[3])) { + sortseg= BLI_memarena_alloc(memarena, sizeof(StrandSortSegment)); + sortseg->obi= i; + sortseg->strand= strand->index; + sortseg->segment= b; + + sortseg->z= 0.5f*(z[1] + z[2]); + + sortseg->next= firstseg; + firstseg= sortseg; + totsegment++; + } + + /* shift clipping and z depth */ + clip[0]= clip[1]; z[0]= z[1]; + clip[1]= clip[2]; z[1]= z[2]; + clip[2]= clip[3]; z[2]= z[3]; + } + } + } + } + + if (!re->test_break(re->tbh)) { + /* convert list to array and sort */ + sortsegments= MEM_mallocN(sizeof(StrandSortSegment)*totsegment, "StrandSortSegment"); + for (a=0, sortseg=firstseg; a<totsegment; a++, sortseg=sortseg->next) + sortsegments[a]= *sortseg; + qsort(sortsegments, totsegment, sizeof(StrandSortSegment), compare_strand_segment); + } + + BLI_memarena_free(memarena); + + spart.totapixbuf= MEM_callocN(sizeof(int)*pa->rectx*pa->recty, "totapixbuf"); + + if (!re->test_break(re->tbh)) { + /* render segments in sorted order */ + sortseg= sortsegments; + for (a=0; a<totsegment; a++, sortseg++) { + if (re->test_break(re->tbh)) + break; + + obi= &re->objectinstance[sortseg->obi]; + obr= obi->obr; + + sseg.obi= obi; + sseg.strand= RE_findOrAddStrand(obr, sortseg->strand); + sseg.buffer= sseg.strand->buffer; + sseg.sqadaptcos= sseg.buffer->adaptcos; + sseg.sqadaptcos *= sseg.sqadaptcos; + + svert= sseg.strand->vert + sortseg->segment; + sseg.v[0]= (sortseg->segment > 0)? (svert-1): svert; + sseg.v[1]= svert; + sseg.v[2]= svert+1; + sseg.v[3]= (sortseg->segment < sseg.strand->totvert-2)? svert+2: svert+1; + sseg.shaded= 0; + + spart.segment= &sseg; + + render_strand_segment(re, winmat, &spart, &zspan, 1, &sseg); + } + } + + if (sortsegments) + MEM_freeN(sortsegments); + MEM_freeN(spart.totapixbuf); + + zbuf_free_span(&zspan); + + return totsegment; +} + +/* *************** */ + +StrandSurface *cache_strand_surface(Render *re, ObjectRen *obr, DerivedMesh *dm, float mat[4][4], int timeoffset) +{ + StrandSurface *mesh; + MFace *mface; + MVert *mvert; + float (*co)[3]; + int a, totvert, totface; + + totvert= dm->getNumVerts(dm); + totface= dm->getNumTessFaces(dm); + + for (mesh = re->strandsurface.first; mesh; mesh = mesh->next) { + if ((mesh->obr.ob == obr->ob) && + (mesh->obr.par == obr->par) && + (mesh->obr.index == obr->index) && + (mesh->totvert == totvert) && + (mesh->totface == totface)) + { + break; + } + } + + if (!mesh) { + mesh= MEM_callocN(sizeof(StrandSurface), "StrandSurface"); + mesh->obr= *obr; + mesh->totvert= totvert; + mesh->totface= totface; + mesh->face= MEM_callocN(sizeof(int)*4*mesh->totface, "StrandSurfFaces"); + mesh->ao= MEM_callocN(sizeof(float)*3*mesh->totvert, "StrandSurfAO"); + mesh->env= MEM_callocN(sizeof(float)*3*mesh->totvert, "StrandSurfEnv"); + mesh->indirect= MEM_callocN(sizeof(float)*3*mesh->totvert, "StrandSurfIndirect"); + BLI_addtail(&re->strandsurface, mesh); + } + + if (timeoffset == -1 && !mesh->prevco) + mesh->prevco= co= MEM_callocN(sizeof(float)*3*mesh->totvert, "StrandSurfCo"); + else if (timeoffset == 0 && !mesh->co) + mesh->co= co= MEM_callocN(sizeof(float)*3*mesh->totvert, "StrandSurfCo"); + else if (timeoffset == 1 && !mesh->nextco) + mesh->nextco= co= MEM_callocN(sizeof(float)*3*mesh->totvert, "StrandSurfCo"); + else + return mesh; + + mvert= dm->getVertArray(dm); + for (a=0; a<mesh->totvert; a++, mvert++) { + copy_v3_v3(co[a], mvert->co); + mul_m4_v3(mat, co[a]); + } + + mface= dm->getTessFaceArray(dm); + for (a=0; a<mesh->totface; a++, mface++) { + mesh->face[a][0]= mface->v1; + mesh->face[a][1]= mface->v2; + mesh->face[a][2]= mface->v3; + mesh->face[a][3]= mface->v4; + } + + return mesh; +} + +void free_strand_surface(Render *re) +{ + StrandSurface *mesh; + + for (mesh=re->strandsurface.first; mesh; mesh=mesh->next) { + if (mesh->co) MEM_freeN(mesh->co); + if (mesh->prevco) MEM_freeN(mesh->prevco); + if (mesh->nextco) MEM_freeN(mesh->nextco); + if (mesh->ao) MEM_freeN(mesh->ao); + if (mesh->env) MEM_freeN(mesh->env); + if (mesh->indirect) MEM_freeN(mesh->indirect); + if (mesh->face) MEM_freeN(mesh->face); + } + + BLI_freelistN(&re->strandsurface); +} + +void strand_minmax(StrandRen *strand, float min[3], float max[3], const float width) +{ + StrandVert *svert; + const float width2 = width * 2.0f; + float vec[3]; + int a; + + for (a=0, svert=strand->vert; a<strand->totvert; a++, svert++) { + copy_v3_v3(vec, svert->co); + minmax_v3v3_v3(min, max, vec); + + if (width!=0.0f) { + add_v3_fl(vec, width); + minmax_v3v3_v3(min, max, vec); + add_v3_fl(vec, -width2); + minmax_v3v3_v3(min, max, vec); + } + } +} + diff --git a/source/blender/render/intern/source/sunsky.c b/source/blender/render/intern/source/sunsky.c new file mode 100644 index 00000000000..80dd52c220c --- /dev/null +++ b/source/blender/render/intern/source/sunsky.c @@ -0,0 +1,506 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/render/intern/source/sunsky.c + * \ingroup render + * + * This feature comes from Preetham paper on "A Practical Analytic Model for Daylight" + * and example code from Brian Smits, another author of that paper in + * http://www.cs.utah.edu/vissim/papers/sunsky/code/ + */ + +#include "sunsky.h" +#include "BLI_math.h" + +/** + * These macros are defined for vector operations + * */ + +/** + * compute v1 = v2 op v3 + * v1, v2 and v3 are vectors contains 3 float + * */ +#define VEC3OPV(v1, v2, op, v3) \ + { \ + v1[0] = (v2[0] op v3[0]); \ + v1[1] = (v2[1] op v3[1]); \ + v1[2] = (v2[2] op v3[2]); \ + } (void)0 + +/** + * compute v1 = v2 op f1 + * v1, v2 are vectors contains 3 float + * and f1 is a float + * */ +#define VEC3OPF(v1, v2, op, f1) \ + { \ + v1[0] = (v2[0] op(f1)); \ + v1[1] = (v2[1] op(f1)); \ + v1[2] = (v2[2] op(f1)); \ + } (void)0 + +/** + * compute v1 = f1 op v2 + * v1, v2 are vectors contains 3 float + * and f1 is a float + * */ +#define FOPVEC3(v1, f1, op, v2) \ + { \ + v1[0] = ((f1) op v2[0]); \ + v1[1] = ((f1) op v2[1]); \ + v1[2] = ((f1) op v2[2]); \ + } (void)0 + +/** + * ClipColor: + * clip a color to range [0, 1]; + * */ +void ClipColor(float c[3]) +{ + if (c[0] > 1.0f) c[0] = 1.0f; + if (c[0] < 0.0f) c[0] = 0.0f; + if (c[1] > 1.0f) c[1] = 1.0f; + if (c[1] < 0.0f) c[1] = 0.0f; + if (c[2] > 1.0f) c[2] = 1.0f; + if (c[2] < 0.0f) c[2] = 0.0f; +} + +/** + * AngleBetween: + * compute angle between to direction + * all angles are in radians + * */ +static float AngleBetween(float thetav, float phiv, float theta, float phi) +{ + float cospsi = sinf(thetav) * sinf(theta) * cosf(phi - phiv) + cosf(thetav) * cosf(theta); + + if (cospsi > 1.0f) + return 0; + if (cospsi < -1.0f) + return M_PI; + + return acosf(cospsi); +} + +/** + * DirectionToThetaPhi: + * this function convert a direction to it's theta and phi value + * parameters: + * toSun: contains direction information + * theta, phi, are return values from this conversion + * */ +static void DirectionToThetaPhi(float *toSun, float *theta, float *phi) +{ + *theta = acosf(toSun[2]); + if (fabsf(*theta) < 1e-5f) + *phi = 0; + else + *phi = atan2f(toSun[1], toSun[0]); +} + +/** + * PerezFunction: + * compute perez function value based on input parameters + */ +static float PerezFunction(struct SunSky *sunsky, const float *lam, float theta, float gamma, float lvz) +{ + float den, num; + + den = ((1 + lam[0] * expf(lam[1])) * + (1 + lam[2] * expf(lam[3] * sunsky->theta) + lam[4] * cosf(sunsky->theta) * cosf(sunsky->theta))); + + num = ((1 + lam[0] * expf(lam[1] / cosf(theta))) * + (1 + lam[2] * expf(lam[3] * gamma) + lam[4] * cosf(gamma) * cosf(gamma))); + + return(lvz * num / den); +} + +/** + * InitSunSky: + * this function compute some sun,sky parameters according to input parameters and also initiate some other sun, sky parameters + * parameters: + * sunSky, is a structure that contains information about sun, sky and atmosphere, in this function, most of its values initiated + * turb, is atmosphere turbidity + * toSun, contains sun direction + * horizon_brighness, controls the brightness of the horizon colors + * spread, controls colors spreed at horizon + * sun_brightness, controls sun's brightness + * sun_size, controls sun's size + * back_scatter, controls back scatter light + * */ +void InitSunSky(struct SunSky *sunsky, float turb, const float toSun[3], float horizon_brightness, + float spread, float sun_brightness, float sun_size, float back_scatter, + float skyblendfac, short skyblendtype, float sky_exposure, float sky_colorspace) +{ + float theta2; + float theta3; + float T; + float T2; + float chi; + + sunsky->turbidity = turb; + + sunsky->horizon_brightness = horizon_brightness; + sunsky->spread = spread; + sunsky->sun_brightness = sun_brightness; + sunsky->sun_size = sun_size; + sunsky->backscattered_light = back_scatter; + sunsky->skyblendfac = skyblendfac; + sunsky->skyblendtype = skyblendtype; + sunsky->sky_exposure = -sky_exposure; + sunsky->sky_colorspace = sky_colorspace; + + sunsky->toSun[0] = toSun[0]; + sunsky->toSun[1] = toSun[1]; + sunsky->toSun[2] = toSun[2]; + + DirectionToThetaPhi(sunsky->toSun, &sunsky->theta, &sunsky->phi); + + sunsky->sunSolidAngle = 0.25 * M_PI * 1.39 * 1.39 / (150 * 150); /* = 6.7443e-05 */ + + theta2 = sunsky->theta * sunsky->theta; + theta3 = theta2 * sunsky->theta; + T = turb; + T2 = turb * turb; + + chi = (4.0f / 9.0f - T / 120.0f) * ((float)M_PI - 2.0f * sunsky->theta); + sunsky->zenith_Y = (4.0453f * T - 4.9710f) * tanf(chi) - 0.2155f * T + 2.4192f; + sunsky->zenith_Y *= 1000; /* conversion from kcd/m^2 to cd/m^2 */ + + if (sunsky->zenith_Y <= 0) + sunsky->zenith_Y = 1e-6; + + sunsky->zenith_x = + (+0.00165f * theta3 - 0.00374f * theta2 + 0.00208f * sunsky->theta + 0.0f) * T2 + + (-0.02902f * theta3 + 0.06377f * theta2 - 0.03202f * sunsky->theta + 0.00394f) * T + + (+0.11693f * theta3 - 0.21196f * theta2 + 0.06052f * sunsky->theta + 0.25885f); + + sunsky->zenith_y = + (+0.00275f * theta3 - 0.00610f * theta2 + 0.00316f * sunsky->theta + 0.0f) * T2 + + (-0.04214f * theta3 + 0.08970f * theta2 - 0.04153f * sunsky->theta + 0.00515f) * T + + (+0.15346f * theta3 - 0.26756f * theta2 + 0.06669f * sunsky->theta + 0.26688f); + + + sunsky->perez_Y[0] = 0.17872f * T - 1.46303f; + sunsky->perez_Y[1] = -0.35540f * T + 0.42749f; + sunsky->perez_Y[2] = -0.02266f * T + 5.32505f; + sunsky->perez_Y[3] = 0.12064f * T - 2.57705f; + sunsky->perez_Y[4] = -0.06696f * T + 0.37027f; + + sunsky->perez_x[0] = -0.01925f * T - 0.25922f; + sunsky->perez_x[1] = -0.06651f * T + 0.00081f; + sunsky->perez_x[2] = -0.00041f * T + 0.21247f; + sunsky->perez_x[3] = -0.06409f * T - 0.89887f; + sunsky->perez_x[4] = -0.00325f * T + 0.04517f; + + sunsky->perez_y[0] = -0.01669f * T - 0.26078f; + sunsky->perez_y[1] = -0.09495f * T + 0.00921f; + sunsky->perez_y[2] = -0.00792f * T + 0.21023f; + sunsky->perez_y[3] = -0.04405f * T - 1.65369f; + sunsky->perez_y[4] = -0.01092f * T + 0.05291f; + + /* suggested by glome in patch [#8063] */ + sunsky->perez_Y[0] *= sunsky->horizon_brightness; + sunsky->perez_x[0] *= sunsky->horizon_brightness; + sunsky->perez_y[0] *= sunsky->horizon_brightness; + + sunsky->perez_Y[1] *= sunsky->spread; + sunsky->perez_x[1] *= sunsky->spread; + sunsky->perez_y[1] *= sunsky->spread; + + sunsky->perez_Y[2] *= sunsky->sun_brightness; + sunsky->perez_x[2] *= sunsky->sun_brightness; + sunsky->perez_y[2] *= sunsky->sun_brightness; + + sunsky->perez_Y[3] *= sunsky->sun_size; + sunsky->perez_x[3] *= sunsky->sun_size; + sunsky->perez_y[3] *= sunsky->sun_size; + + sunsky->perez_Y[4] *= sunsky->backscattered_light; + sunsky->perez_x[4] *= sunsky->backscattered_light; + sunsky->perez_y[4] *= sunsky->backscattered_light; +} + +/** + * GetSkyXYZRadiance: + * this function compute sky radiance according to a view parameters `theta' and `phi'and sunSky values + * parameters: + * sunSky, sontains sun and sky parameters + * theta, is sun's theta + * phi, is sun's phi + * color_out, is computed color that shows sky radiance in XYZ color format + * */ +void GetSkyXYZRadiance(struct SunSky *sunsky, float theta, float phi, float color_out[3]) +{ + float gamma; + float x, y, Y, X, Z; + float hfade = 1, nfade = 1; + + + if (theta > (float)M_PI_2) { + hfade = 1.0f - (theta * (float)M_1_PI - 0.5f) * 2.0f; + hfade = hfade * hfade * (3.0f - 2.0f * hfade); + theta = M_PI_2; + } + + if (sunsky->theta > (float)M_PI_2) { + if (theta <= (float)M_PI_2) { + nfade = 1.0f - (0.5f - theta * (float)M_1_PI) * 2.0f; + nfade *= 1.0f - (sunsky->theta * (float)M_1_PI - 0.5f) * 2.0f; + nfade = nfade * nfade * (3.0f - 2.0f * nfade); + } + } + + gamma = AngleBetween(theta, phi, sunsky->theta, sunsky->phi); + + /* Compute xyY values */ + x = PerezFunction(sunsky, sunsky->perez_x, theta, gamma, sunsky->zenith_x); + y = PerezFunction(sunsky, sunsky->perez_y, theta, gamma, sunsky->zenith_y); + Y = 6.666666667e-5f * nfade * hfade * PerezFunction(sunsky, sunsky->perez_Y, theta, gamma, sunsky->zenith_Y); + + if (sunsky->sky_exposure != 0.0f) + Y = 1.0 - exp(Y * sunsky->sky_exposure); + + X = (x / y) * Y; + Z = ((1 - x - y) / y) * Y; + + color_out[0] = X; + color_out[1] = Y; + color_out[2] = Z; +} + +/** + * GetSkyXYZRadiancef: + * this function compute sky radiance according to a view direction `varg' and sunSky values + * parameters: + * sunSky, sontains sun and sky parameters + * varg, shows direction + * color_out, is computed color that shows sky radiance in XYZ color format + * */ +void GetSkyXYZRadiancef(struct SunSky *sunsky, const float varg[3], float color_out[3]) +{ + float theta, phi; + float v[3]; + + normalize_v3_v3(v, varg); + + if (v[2] < 0.001f) { + v[2] = 0.001f; + normalize_v3(v); + } + + DirectionToThetaPhi(v, &theta, &phi); + GetSkyXYZRadiance(sunsky, theta, phi, color_out); +} + +/** + * ComputeAttenuatedSunlight: + * this function compute attenuated sun light based on sun's theta and atmosphere turbidity + * parameters: + * theta, is sun's theta + * turbidity: is atmosphere turbidity + * fTau: contains computed attenuated sun light + * */ +static void ComputeAttenuatedSunlight(float theta, int turbidity, float fTau[3]) +{ + float fBeta; + float fTauR, fTauA; + float m; + float fAlpha; + + int i; + float fLambda[3]; + fLambda[0] = 0.65f; + fLambda[1] = 0.57f; + fLambda[2] = 0.475f; + + fAlpha = 1.3f; + fBeta = 0.04608365822050f * turbidity - 0.04586025928522f; + + m = 1.0f / (cosf(theta) + 0.15f * powf(93.885f - theta / (float)M_PI * 180.0f, -1.253f)); + + for (i = 0; i < 3; i++) { + /* Rayleigh Scattering */ + fTauR = expf(-m * 0.008735f * powf(fLambda[i], (float)(-4.08f))); + + /* Aerosal (water + dust) attenuation */ + fTauA = exp(-m * fBeta * powf(fLambda[i], -fAlpha)); + + fTau[i] = fTauR * fTauA; + } +} + +/** + * InitAtmosphere: + * this function initiate sunSky structure with user input parameters. + * parameters: + * sunSky, contains information about sun, and in this function some atmosphere parameters will initiated + * sun_intens, shows sun intensity value + * mief, Mie scattering factor this factor currently call with 1.0 + * rayf, Rayleigh scattering factor, this factor currently call with 1.0 + * inscattf, inscatter light factor that range from 0.0 to 1.0, 0.0 means no inscatter light and 1.0 means full inscatter light + * extincf, extinction light factor that range from 0.0 to 1.0, 0.0 means no extinction and 1.0 means full extinction + * disf, is distance factor, multiplied to pixle's z value to compute each pixle's distance to camera, + * */ +void InitAtmosphere(struct SunSky *sunSky, float sun_intens, float mief, float rayf, + float inscattf, float extincf, float disf) +{ + const float pi = M_PI; + const float n = 1.003f; /* refractive index */ + const float N = 2.545e25; + const float pn = 0.035f; + const float T = 2.0f; + float fTemp, fTemp2, fTemp3, fBeta, fBetaDash; + float c = (6.544f * T - 6.51f) * 1e-17f; + float K[3] = {0.685f, 0.679f, 0.670f}; + float vBetaMieTemp[3]; + + float fLambda[3], fLambda2[3], fLambda4[3]; + float vLambda2[3]; + float vLambda4[3]; + + int i; + + sunSky->atm_SunIntensity = sun_intens; + sunSky->atm_BetaMieMultiplier = mief; + sunSky->atm_BetaRayMultiplier = rayf; + sunSky->atm_InscatteringMultiplier = inscattf; + sunSky->atm_ExtinctionMultiplier = extincf; + sunSky->atm_DistanceMultiplier = disf; + + sunSky->atm_HGg = 0.8; + + fLambda[0] = 1 / 650e-9f; + fLambda[1] = 1 / 570e-9f; + fLambda[2] = 1 / 475e-9f; + for (i = 0; i < 3; i++) { + fLambda2[i] = fLambda[i] * fLambda[i]; + fLambda4[i] = fLambda2[i] * fLambda2[i]; + } + + vLambda2[0] = fLambda2[0]; + vLambda2[1] = fLambda2[1]; + vLambda2[2] = fLambda2[2]; + + vLambda4[0] = fLambda4[0]; + vLambda4[1] = fLambda4[1]; + vLambda4[2] = fLambda4[2]; + + /* Rayleigh scattering constants. */ + fTemp = pi * pi * (n * n - 1) * (n * n - 1) * (6 + 3 * pn) / (6 - 7 * pn) / N; + fBeta = 8 * fTemp * pi / 3; + + VEC3OPF(sunSky->atm_BetaRay, vLambda4, *, fBeta); + fBetaDash = fTemp / 2; + VEC3OPF(sunSky->atm_BetaDashRay, vLambda4, *, fBetaDash); + + + /* Mie scattering constants. */ + fTemp2 = 0.434f * c * (2 * pi) * (2 * pi) * 0.5f; + VEC3OPF(sunSky->atm_BetaDashMie, vLambda2, *, fTemp2); + + fTemp3 = 0.434f * c * pi * (2 * pi) * (2 * pi); + + VEC3OPV(vBetaMieTemp, K, *, fLambda); + VEC3OPF(sunSky->atm_BetaMie, vBetaMieTemp, *, fTemp3); + +} + +/** + * AtmospherePixleShader: + * this function apply atmosphere effect on a pixle color `rgb' at distance `s' + * parameters: + * sunSky, contains information about sun parameters and user values + * view, is camera view vector + * s, is distance + * rgb, contains rendered color value for a pixle + * */ +void AtmospherePixleShader(struct SunSky *sunSky, float view[3], float s, float rgb[3]) +{ + float costheta; + float Phase_1; + float Phase_2; + float sunColor[3]; + + float E[3]; + float E1[3]; + + + float I[3]; + float fTemp; + float vTemp1[3], vTemp2[3]; + + float sunDirection[3]; + + s *= sunSky->atm_DistanceMultiplier; + + sunDirection[0] = sunSky->toSun[0]; + sunDirection[1] = sunSky->toSun[1]; + sunDirection[2] = sunSky->toSun[2]; + + costheta = dot_v3v3(view, sunDirection); /* cos(theta) */ + Phase_1 = 1 + (costheta * costheta); /* Phase_1 */ + + VEC3OPF(sunSky->atm_BetaRay, sunSky->atm_BetaRay, *, sunSky->atm_BetaRayMultiplier); + VEC3OPF(sunSky->atm_BetaMie, sunSky->atm_BetaMie, *, sunSky->atm_BetaMieMultiplier); + VEC3OPV(sunSky->atm_BetaRM, sunSky->atm_BetaRay, +, sunSky->atm_BetaMie); + + /* e^(-(beta_1 + beta_2) * s) = E1 */ + VEC3OPF(E1, sunSky->atm_BetaRM, *, -s / (float)M_LN2); + E1[0] = exp(E1[0]); + E1[1] = exp(E1[1]); + E1[2] = exp(E1[2]); + + copy_v3_v3(E, E1); + + /* Phase2(theta) = (1-g^2)/(1+g-2g*cos(theta))^(3/2) */ + fTemp = 1 + sunSky->atm_HGg - 2 * sunSky->atm_HGg * costheta; + fTemp = fTemp * sqrtf(fTemp); + Phase_2 = (1 - sunSky->atm_HGg * sunSky->atm_HGg) / fTemp; + + VEC3OPF(vTemp1, sunSky->atm_BetaDashRay, *, Phase_1); + VEC3OPF(vTemp2, sunSky->atm_BetaDashMie, *, Phase_2); + + VEC3OPV(vTemp1, vTemp1, +, vTemp2); + FOPVEC3(vTemp2, 1.0f, -, E1); + VEC3OPV(vTemp1, vTemp1, *, vTemp2); + + FOPVEC3(vTemp2, 1.0f, /, sunSky->atm_BetaRM); + + VEC3OPV(I, vTemp1, *, vTemp2); + + VEC3OPF(I, I, *, sunSky->atm_InscatteringMultiplier); + VEC3OPF(E, E, *, sunSky->atm_ExtinctionMultiplier); + + /* scale to color sun */ + ComputeAttenuatedSunlight(sunSky->theta, sunSky->turbidity, sunColor); + VEC3OPV(E, E, *, sunColor); + + VEC3OPF(I, I, *, sunSky->atm_SunIntensity); + + VEC3OPV(rgb, rgb, *, E); + VEC3OPV(rgb, rgb, +, I); +} + +#undef VEC3OPV +#undef VEC3OPF +#undef FOPVEC3 + +/* EOF */ diff --git a/source/blender/render/intern/source/volume_precache.c b/source/blender/render/intern/source/volume_precache.c new file mode 100644 index 00000000000..8e79f309814 --- /dev/null +++ b/source/blender/render/intern/source/volume_precache.c @@ -0,0 +1,855 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Matt Ebb, Ra˙l Fern·ndez Hern·ndez (Farsthary). + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/render/intern/source/volume_precache.c + * \ingroup render + */ + + +#include <math.h> +#include <stdlib.h> +#include <string.h> +#include <float.h> + +#include "MEM_guardedalloc.h" + +#include "BLI_blenlib.h" +#include "BLI_math.h" +#include "BLI_task.h" +#include "BLI_threads.h" +#include "BLI_voxel.h" +#include "BLI_utildefines.h" + +#include "BLT_translation.h" + +#include "PIL_time.h" + +#include "RE_shader_ext.h" + +#include "DNA_material_types.h" + +#include "rayintersection.h" +#include "rayobject.h" +#include "render_types.h" +#include "rendercore.h" +#include "renderdatabase.h" +#include "volumetric.h" +#include "volume_precache.h" + +#include "atomic_ops.h" + + +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ +/* defined in pipeline.c, is hardcopy of active dynamic allocated Render */ +/* only to be used here in this file, it's for speed */ +extern struct Render R; +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ + +/* *** utility code to set up an individual raytree for objectinstance, for checking inside/outside *** */ + +/* Recursive test for intersections, from a point inside the mesh, to outside + * Number of intersections (depth) determine if a point is inside or outside the mesh */ +static int intersect_outside_volume(RayObject *tree, Isect *isect, float *offset, int limit, int depth) +{ + if (limit == 0) return depth; + + if (RE_rayobject_raycast(tree, isect)) { + + isect->start[0] = isect->start[0] + isect->dist*isect->dir[0]; + isect->start[1] = isect->start[1] + isect->dist*isect->dir[1]; + isect->start[2] = isect->start[2] + isect->dist*isect->dir[2]; + + isect->dist = FLT_MAX; + isect->skip = RE_SKIP_VLR_NEIGHBOUR; + isect->orig.face= isect->hit.face; + isect->orig.ob= isect->hit.ob; + + return intersect_outside_volume(tree, isect, offset, limit-1, depth+1); + } + else { + return depth; + } +} + +/* Uses ray tracing to check if a point is inside or outside an ObjectInstanceRen */ +static int point_inside_obi(RayObject *tree, ObjectInstanceRen *obi, const float co[3]) +{ + Isect isect= {{0}}; + float dir[3] = {0.0f, 0.0f, 1.0f}; + int final_depth=0, depth=0, limit=20; + + /* set up the isect */ + copy_v3_v3(isect.start, co); + copy_v3_v3(isect.dir, dir); + isect.mode= RE_RAY_MIRROR; + isect.last_hit= NULL; + isect.lay= -1; + + isect.dist = FLT_MAX; + isect.orig.face= NULL; + isect.orig.ob = NULL; + + RE_instance_rotate_ray(obi, &isect); + final_depth = intersect_outside_volume(tree, &isect, dir, limit, depth); + RE_instance_rotate_ray_restore(obi, &isect); + + /* even number of intersections: point is outside + * odd number: point is inside */ + if (final_depth % 2 == 0) return 0; + else return 1; +} + +/* find the bounding box of an objectinstance in global space */ +void global_bounds_obi(Render *re, ObjectInstanceRen *obi, float bbmin[3], float bbmax[3]) +{ + ObjectRen *obr = obi->obr; + VolumePrecache *vp = obi->volume_precache; + VertRen *ver= NULL; + float co[3]; + int a; + + if (vp->bbmin != NULL && vp->bbmax != NULL) { + copy_v3_v3(bbmin, vp->bbmin); + copy_v3_v3(bbmax, vp->bbmax); + return; + } + + vp->bbmin = MEM_callocN(sizeof(float)*3, "volume precache min boundbox corner"); + vp->bbmax = MEM_callocN(sizeof(float)*3, "volume precache max boundbox corner"); + + INIT_MINMAX(bbmin, bbmax); + + for (a=0; a<obr->totvert; a++) { + if ((a & 255)==0) ver= obr->vertnodes[a>>8].vert; + else ver++; + + copy_v3_v3(co, ver->co); + + /* transformed object instance in camera space */ + if (obi->flag & R_TRANSFORMED) + mul_m4_v3(obi->mat, co); + + /* convert to global space */ + mul_m4_v3(re->viewinv, co); + + minmax_v3v3_v3(vp->bbmin, vp->bbmax, co); + } + + copy_v3_v3(bbmin, vp->bbmin); + copy_v3_v3(bbmax, vp->bbmax); + +} + +/* *** light cache filtering *** */ + +static float get_avg_surrounds(float *cache, int *res, int xx, int yy, int zz) +{ + int x, y, z, x_, y_, z_; + int added=0; + float tot=0.0f; + + for (z=-1; z <= 1; z++) { + z_ = zz+z; + if (z_ >= 0 && z_ <= res[2]-1) { + + for (y=-1; y <= 1; y++) { + y_ = yy+y; + if (y_ >= 0 && y_ <= res[1]-1) { + + for (x=-1; x <= 1; x++) { + x_ = xx+x; + if (x_ >= 0 && x_ <= res[0]-1) { + const int64_t i = BLI_VOXEL_INDEX(x_, y_, z_, res); + + if (cache[i] > 0.0f) { + tot += cache[i]; + added++; + } + + } + } + } + } + } + } + + if (added > 0) tot /= added; + + return tot; +} + +/* function to filter the edges of the light cache, where there was no volume originally. + * For each voxel which was originally external to the mesh, it finds the average values of + * the surrounding internal voxels and sets the original external voxel to that average amount. + * Works almost a bit like a 'dilate' filter */ +static void lightcache_filter(VolumePrecache *vp) +{ + int x, y, z; + + for (z=0; z < vp->res[2]; z++) { + for (y=0; y < vp->res[1]; y++) { + for (x=0; x < vp->res[0]; x++) { + /* trigger for outside mesh */ + const int64_t i = BLI_VOXEL_INDEX(x, y, z, vp->res); + + if (vp->data_r[i] < -0.f) + vp->data_r[i] = get_avg_surrounds(vp->data_r, vp->res, x, y, z); + if (vp->data_g[i] < -0.f) + vp->data_g[i] = get_avg_surrounds(vp->data_g, vp->res, x, y, z); + if (vp->data_b[i] < -0.f) + vp->data_b[i] = get_avg_surrounds(vp->data_b, vp->res, x, y, z); + } + } + } +} + +#if 0 +static void lightcache_filter2(VolumePrecache *vp) +{ + int x, y, z; + float *new_r, *new_g, *new_b; + int field_size = vp->res[0]*vp->res[1]*vp->res[2]*sizeof(float); + + new_r = MEM_mallocN(field_size, "temp buffer for light cache filter r channel"); + new_g = MEM_mallocN(field_size, "temp buffer for light cache filter g channel"); + new_b = MEM_mallocN(field_size, "temp buffer for light cache filter b channel"); + + memcpy(new_r, vp->data_r, field_size); + memcpy(new_g, vp->data_g, field_size); + memcpy(new_b, vp->data_b, field_size); + + for (z=0; z < vp->res[2]; z++) { + for (y=0; y < vp->res[1]; y++) { + for (x=0; x < vp->res[0]; x++) { + /* trigger for outside mesh */ + const int64_t i = BLI_VOXEL_INDEX(x, y, z, vp->res); + if (vp->data_r[i] < -0.f) + new_r[i] = get_avg_surrounds(vp->data_r, vp->res, x, y, z); + if (vp->data_g[i] < -0.f) + new_g[i] = get_avg_surrounds(vp->data_g, vp->res, x, y, z); + if (vp->data_b[i] < -0.f) + new_b[i] = get_avg_surrounds(vp->data_b, vp->res, x, y, z); + } + } + } + + SWAP(float *, vp->data_r, new_r); + SWAP(float *, vp->data_g, new_g); + SWAP(float *, vp->data_b, new_b); + + if (new_r) { MEM_freeN(new_r); new_r=NULL; } + if (new_g) { MEM_freeN(new_g); new_g=NULL; } + if (new_b) { MEM_freeN(new_b); new_b=NULL; } +} +#endif + +/* has a pad of 1 voxel surrounding the core for boundary simulation */ +BLI_INLINE int64_t ms_I(int x, int y, int z, const int *n) +{ + /* different ordering to light cache */ + return ((int64_t)x * (int64_t)(n[1] + 2) * (int64_t)(n[2] + 2) + + (int64_t)y * (int64_t)(n[2] + 2) + + (int64_t)z); +} + +/* has a pad of 1 voxel surrounding the core for boundary simulation */ +BLI_INLINE int64_t v_I_pad(int x, int y, int z, const int *n) +{ + /* same ordering to light cache, with padding */ + return ((int64_t)z * (int64_t)(n[1] + 2) * (int64_t)(n[0] + 2) + + (int64_t)y * (int64_t)(n[0] + 2) + + (int64_t)x); +} + +BLI_INLINE int64_t lc_to_ms_I(int x, int y, int z, const int *n) +{ + /* converting light cache index to multiple scattering index */ + return ((int64_t)(x - 1) * ((int64_t)n[1] * (int64_t)n[2]) + + (int64_t)(y - 1) * ((int64_t)n[2]) + + (int64_t)(z - 1)); +} + +/* *** multiple scattering approximation *** */ + +/* get the total amount of light energy in the light cache. used to normalize after multiple scattering */ +static float total_ss_energy(Render *re, int do_test_break, VolumePrecache *vp) +{ + int x, y, z; + const int *res = vp->res; + float energy=0.f; + + for (z=0; z < res[2]; z++) { + for (y=0; y < res[1]; y++) { + for (x=0; x < res[0]; x++) { + const int64_t i = BLI_VOXEL_INDEX(x, y, z, res); + + if (vp->data_r[i] > 0.f) energy += vp->data_r[i]; + if (vp->data_g[i] > 0.f) energy += vp->data_g[i]; + if (vp->data_b[i] > 0.f) energy += vp->data_b[i]; + } + } + + if (do_test_break && re->test_break(re->tbh)) break; + } + + return energy; +} + +static float total_ms_energy(Render *re, int do_test_break, float *sr, float *sg, float *sb, const int res[3]) +{ + int x, y, z; + float energy=0.f; + + for (z=1;z<=res[2];z++) { + for (y=1;y<=res[1];y++) { + for (x=1;x<=res[0];x++) { + const int64_t i = ms_I(x, y, z, res); + + if (sr[i] > 0.f) energy += sr[i]; + if (sg[i] > 0.f) energy += sg[i]; + if (sb[i] > 0.f) energy += sb[i]; + } + } + + if (do_test_break && re->test_break(re->tbh)) break; + } + + return energy; +} + +/** + * \param n: the unpadded resolution + */ +static void ms_diffuse(Render *re, int do_test_break, const float *x0, float *x, float diff, const int n[3]) +{ + int i, j, k, l; + const float dt = VOL_MS_TIMESTEP; + int64_t size = (int64_t)n[0] * (int64_t)n[1] * (int64_t)n[2]; + const float a = dt * diff * size; + + for (l=0; l<20; l++) { + for (k=1; k<=n[2]; k++) { + for (j=1; j<=n[1]; j++) { + for (i=1; i<=n[0]; i++) { + x[v_I_pad(i, j, k, n)] = + ((x0[v_I_pad(i, j, k, n)]) + ( + (x0[v_I_pad(i - 1, j, k, n)] + + x0[v_I_pad(i + 1, j, k, n)] + + x0[v_I_pad(i, j - 1, k, n)] + + x0[v_I_pad(i, j + 1, k, n)] + + x0[v_I_pad(i, j, k - 1, n)] + + x0[v_I_pad(i, j, k + 1, n)]) * a) / (1 + 6 * a)); + } + } + + if (do_test_break && re->test_break(re->tbh)) break; + } + + if (re->test_break(re->tbh)) break; + } +} + +static void multiple_scattering_diffusion(Render *re, VolumePrecache *vp, Material *ma) +{ + const float diff = ma->vol.ms_diff * 0.001f; /* compensate for scaling for a nicer UI range */ + const int simframes = (int)(ma->vol.ms_spread * (float)max_iii(vp->res[0], vp->res[1], vp->res[2])); + const int shade_type = ma->vol.shade_type; + float fac = ma->vol.ms_intensity; + + int x, y, z, m; + const int *n = vp->res; + const int size = (n[0]+2)*(n[1]+2)*(n[2]+2); + const int do_test_break = (size > 100000); + double time, lasttime= PIL_check_seconds_timer(); + float total; + float c=1.0f; + float origf; /* factor for blending in original light cache */ + float energy_ss, energy_ms; + + float *sr0=(float *)MEM_callocN(size*sizeof(float), "temporary multiple scattering buffer"); + float *sr=(float *)MEM_callocN(size*sizeof(float), "temporary multiple scattering buffer"); + float *sg0=(float *)MEM_callocN(size*sizeof(float), "temporary multiple scattering buffer"); + float *sg=(float *)MEM_callocN(size*sizeof(float), "temporary multiple scattering buffer"); + float *sb0=(float *)MEM_callocN(size*sizeof(float), "temporary multiple scattering buffer"); + float *sb=(float *)MEM_callocN(size*sizeof(float), "temporary multiple scattering buffer"); + + total = (float)(n[0]*n[1]*n[2]*simframes); + + energy_ss = total_ss_energy(re, do_test_break, vp); + + /* Scattering as diffusion pass */ + for (m=0; m<simframes; m++) { + /* add sources */ + for (z=1; z<=n[2]; z++) { + for (y=1; y<=n[1]; y++) { + for (x=1; x<=n[0]; x++) { + const int64_t i = lc_to_ms_I(x, y, z, n); //lc index + const int64_t j = ms_I(x, y, z, n); //ms index + + time= PIL_check_seconds_timer(); + c++; + if (vp->data_r[i] > 0.0f) + sr[j] += vp->data_r[i]; + if (vp->data_g[i] > 0.0f) + sg[j] += vp->data_g[i]; + if (vp->data_b[i] > 0.0f) + sb[j] += vp->data_b[i]; + + /* Displays progress every second */ + if (time-lasttime>1.0) { + char str[64]; + BLI_snprintf(str, sizeof(str), IFACE_("Simulating multiple scattering: %d%%"), + (int)(100.0f * (c / total))); + re->i.infostr = str; + re->stats_draw(re->sdh, &re->i); + re->i.infostr = NULL; + lasttime= time; + } + } + } + + if (do_test_break && re->test_break(re->tbh)) break; + } + + if (re->test_break(re->tbh)) break; + + SWAP(float *, sr, sr0); + SWAP(float *, sg, sg0); + SWAP(float *, sb, sb0); + + /* main diffusion simulation */ + ms_diffuse(re, do_test_break, sr0, sr, diff, n); + ms_diffuse(re, do_test_break, sg0, sg, diff, n); + ms_diffuse(re, do_test_break, sb0, sb, diff, n); + + if (re->test_break(re->tbh)) break; + } + + /* normalization factor to conserve energy */ + energy_ms = total_ms_energy(re, do_test_break, sr, sg, sb, n); + fac *= (energy_ss / energy_ms); + + /* blend multiple scattering back in the light cache */ + if (shade_type == MA_VOL_SHADE_SHADEDPLUSMULTIPLE) { + /* conserve energy - half single, half multiple */ + origf = 0.5f; + fac *= 0.5f; + } + else { + origf = 0.0f; + } + + for (z=1;z<=n[2];z++) { + for (y=1;y<=n[1];y++) { + for (x=1;x<=n[0];x++) { + const int64_t i = lc_to_ms_I(x, y, z, n); //lc index + const int64_t j = ms_I(x, y, z, n); //ms index + + vp->data_r[i] = origf * vp->data_r[i] + fac * sr[j]; + vp->data_g[i] = origf * vp->data_g[i] + fac * sg[j]; + vp->data_b[i] = origf * vp->data_b[i] + fac * sb[j]; + } + } + + if (do_test_break && re->test_break(re->tbh)) break; + } + + MEM_freeN(sr0); + MEM_freeN(sr); + MEM_freeN(sg0); + MEM_freeN(sg); + MEM_freeN(sb0); + MEM_freeN(sb); +} + + + +#if 0 /* debug stuff */ +static void *vol_precache_part_test(void *data) +{ + VolPrecachePart *pa = data; + + printf("part number: %d\n", pa->num); + printf("done: %d\n", pa->done); + printf("x min: %d x max: %d\n", pa->minx, pa->maxx); + printf("y min: %d y max: %d\n", pa->miny, pa->maxy); + printf("z min: %d z max: %d\n", pa->minz, pa->maxz); + + return NULL; +} +#endif + +/* Iterate over the 3d voxel grid, and fill the voxels with scattering information + * + * It's stored in memory as 3 big float grids next to each other, one for each RGB channel. + * I'm guessing the memory alignment may work out better this way for the purposes + * of doing linear interpolation, but I haven't actually tested this theory! :) + */ +typedef struct VolPrecacheState { + double lasttime; + unsigned int doneparts; + unsigned int totparts; +} VolPrecacheState; + +static void vol_precache_part(TaskPool * __restrict pool, void *taskdata, int UNUSED(threadid)) +{ + VolPrecacheState *state = (VolPrecacheState *)BLI_task_pool_userdata(pool); + VolPrecachePart *pa = (VolPrecachePart *)taskdata; + Render *re = pa->re; + + ObjectInstanceRen *obi = pa->obi; + RayObject *tree = pa->tree; + ShadeInput *shi = pa->shi; + float scatter_col[3] = {0.f, 0.f, 0.f}; + float co[3], cco[3], view[3]; + int x, y, z; + int res[3]; + double time; + + if (re->test_break && re->test_break(re->tbh)) + return; + + //printf("thread id %d\n", threadid); + + res[0]= pa->res[0]; + res[1]= pa->res[1]; + res[2]= pa->res[2]; + + for (z= pa->minz; z < pa->maxz; z++) { + co[2] = pa->bbmin[2] + (pa->voxel[2] * (z + 0.5f)); + + for (y= pa->miny; y < pa->maxy; y++) { + co[1] = pa->bbmin[1] + (pa->voxel[1] * (y + 0.5f)); + + for (x=pa->minx; x < pa->maxx; x++) { + int64_t i; + co[0] = pa->bbmin[0] + (pa->voxel[0] * (x + 0.5f)); + + if (re->test_break && re->test_break(re->tbh)) + break; + + /* convert from world->camera space for shading */ + mul_v3_m4v3(cco, pa->viewmat, co); + + i = BLI_VOXEL_INDEX(x, y, z, res); + + /* don't bother if the point is not inside the volume mesh */ + if (!point_inside_obi(tree, obi, cco)) { + obi->volume_precache->data_r[i] = -1.0f; + obi->volume_precache->data_g[i] = -1.0f; + obi->volume_precache->data_b[i] = -1.0f; + continue; + } + + copy_v3_v3(view, cco); + normalize_v3(view); + vol_get_scattering(shi, scatter_col, cco, view); + + obi->volume_precache->data_r[i] = scatter_col[0]; + obi->volume_precache->data_g[i] = scatter_col[1]; + obi->volume_precache->data_b[i] = scatter_col[2]; + + } + } + } + + unsigned int doneparts = atomic_add_and_fetch_u(&state->doneparts, 1); + + time = PIL_check_seconds_timer(); + if (time - state->lasttime > 1.0) { + ThreadMutex *mutex = BLI_task_pool_user_mutex(pool); + + if (BLI_mutex_trylock(mutex)) { + char str[64]; + float ratio = (float)doneparts/(float)state->totparts; + BLI_snprintf(str, sizeof(str), IFACE_("Precaching volume: %d%%"), (int)(100.0f * ratio)); + re->i.infostr = str; + re->stats_draw(re->sdh, &re->i); + re->i.infostr = NULL; + state->lasttime = time; + + BLI_mutex_unlock(mutex); + } + } +} + +static void precache_setup_shadeinput(Render *re, ObjectInstanceRen *obi, Material *ma, ShadeInput *shi) +{ + memset(shi, 0, sizeof(ShadeInput)); + shi->depth= 1; + shi->mask= 1; + shi->mat = ma; + shi->vlr = NULL; + memcpy(&shi->r, &shi->mat->r, 23*sizeof(float)); /* note, keep this synced with render_types.h */ + shi->har= shi->mat->har; + shi->obi= obi; + shi->obr= obi->obr; + shi->lay = re->lay; +} + +static void precache_launch_parts(Render *re, RayObject *tree, ShadeInput *shi, ObjectInstanceRen *obi) +{ + TaskScheduler *task_scheduler; + TaskPool *task_pool; + VolumePrecache *vp = obi->volume_precache; + VolPrecacheState state; + int i=0, x, y, z; + float voxel[3]; + int sizex, sizey, sizez; + float bbmin[3], bbmax[3]; + const int *res; + int minx, maxx; + int miny, maxy; + int minz, maxz; + int totthread = re->r.threads; + int parts[3]; + + if (!vp) return; + + /* currently we just subdivide the box, number of threads per side */ + parts[0] = parts[1] = parts[2] = totthread; + res = vp->res; + + /* setup task scheduler */ + memset(&state, 0, sizeof(state)); + state.doneparts = 0; + state.totparts = parts[0]*parts[1]*parts[2]; + state.lasttime = PIL_check_seconds_timer(); + + task_scheduler = BLI_task_scheduler_create(totthread); + task_pool = BLI_task_pool_create(task_scheduler, &state); + + /* using boundbox in worldspace */ + global_bounds_obi(re, obi, bbmin, bbmax); + sub_v3_v3v3(voxel, bbmax, bbmin); + + voxel[0] /= (float)res[0]; + voxel[1] /= (float)res[1]; + voxel[2] /= (float)res[2]; + + for (x=0; x < parts[0]; x++) { + sizex = ceil(res[0] / (float)parts[0]); + minx = x * sizex; + maxx = minx + sizex; + maxx = (maxx>res[0])?res[0]:maxx; + + for (y=0; y < parts[1]; y++) { + sizey = ceil(res[1] / (float)parts[1]); + miny = y * sizey; + maxy = miny + sizey; + maxy = (maxy>res[1])?res[1]:maxy; + + for (z=0; z < parts[2]; z++) { + VolPrecachePart *pa= MEM_callocN(sizeof(VolPrecachePart), "new precache part"); + + sizez = ceil(res[2] / (float)parts[2]); + minz = z * sizez; + maxz = minz + sizez; + maxz = (maxz>res[2])?res[2]:maxz; + + pa->re = re; + pa->num = i; + pa->tree = tree; + pa->shi = shi; + pa->obi = obi; + copy_m4_m4(pa->viewmat, re->viewmat); + + copy_v3_v3(pa->bbmin, bbmin); + copy_v3_v3(pa->voxel, voxel); + copy_v3_v3_int(pa->res, res); + + pa->minx = minx; pa->maxx = maxx; + pa->miny = miny; pa->maxy = maxy; + pa->minz = minz; pa->maxz = maxz; + + BLI_task_pool_push(task_pool, vol_precache_part, pa, true, TASK_PRIORITY_HIGH); + + i++; + } + } + } + + /* work and wait until tasks are done */ + BLI_task_pool_work_and_wait(task_pool); + + /* free */ + BLI_task_pool_free(task_pool); + BLI_task_scheduler_free(task_scheduler); +} + +/* calculate resolution from bounding box in world space */ +static int precache_resolution(Render *re, VolumePrecache *vp, ObjectInstanceRen *obi, int res) +{ + float dim[3], div; + float bbmin[3], bbmax[3]; + + /* bound box in global space */ + global_bounds_obi(re, obi, bbmin, bbmax); + sub_v3_v3v3(dim, bbmax, bbmin); + + div = max_fff(dim[0], dim[1], dim[2]); + dim[0] /= div; + dim[1] /= div; + dim[2] /= div; + + vp->res[0] = ceil(dim[0] * res); + vp->res[1] = ceil(dim[1] * res); + vp->res[2] = ceil(dim[2] * res); + + if ((vp->res[0] < 1) || (vp->res[1] < 1) || (vp->res[2] < 1)) + return 0; + + return 1; +} + +/* Precache a volume into a 3D voxel grid. + * The voxel grid is stored in the ObjectInstanceRen, + * in camera space, aligned with the ObjectRen's bounding box. + * Resolution is defined by the user. + */ +static void vol_precache_objectinstance_threads(Render *re, ObjectInstanceRen *obi, Material *ma) +{ + VolumePrecache *vp; + RayObject *tree; + ShadeInput shi; + + R = *re; + + /* create a raytree with just the faces of the instanced ObjectRen, + * used for checking if the cached point is inside or outside. */ + tree = makeraytree_object(&R, obi); + if (!tree) return; + + vp = MEM_callocN(sizeof(VolumePrecache), "volume light cache"); + obi->volume_precache = vp; + + if (!precache_resolution(re, vp, obi, ma->vol.precache_resolution)) { + MEM_freeN(vp); + vp = NULL; + return; + } + + vp->data_r = MEM_callocN(sizeof(float)*vp->res[0]*vp->res[1]*vp->res[2], "volume light cache data red channel"); + vp->data_g = MEM_callocN(sizeof(float)*vp->res[0]*vp->res[1]*vp->res[2], "volume light cache data green channel"); + vp->data_b = MEM_callocN(sizeof(float)*vp->res[0]*vp->res[1]*vp->res[2], "volume light cache data blue channel"); + if (vp->data_r==NULL || vp->data_g==NULL || vp->data_b==NULL) { + MEM_freeN(vp); + return; + } + + /* Need a shadeinput to calculate scattering */ + precache_setup_shadeinput(re, obi, ma, &shi); + + precache_launch_parts(re, tree, &shi, obi); + + if (tree) { + /* TODO: makeraytree_object creates a tree and saves it on OBI, + * if we free this tree we should also clear other pointers to it */ + //RE_rayobject_free(tree); + //tree= NULL; + } + + if (ELEM(ma->vol.shade_type, MA_VOL_SHADE_MULTIPLE, MA_VOL_SHADE_SHADEDPLUSMULTIPLE)) { + /* this should be before the filtering */ + multiple_scattering_diffusion(re, obi->volume_precache, ma); + } + + lightcache_filter(obi->volume_precache); +} + +static int using_lightcache(Material *ma) +{ + return (((ma->vol.shadeflag & MA_VOL_PRECACHESHADING) && (ma->vol.shade_type == MA_VOL_SHADE_SHADED)) || + (ELEM(ma->vol.shade_type, MA_VOL_SHADE_MULTIPLE, MA_VOL_SHADE_SHADEDPLUSMULTIPLE))); +} + +/* loop through all objects (and their associated materials) + * marked for pre-caching in convertblender.c, and pre-cache them */ +void volume_precache(Render *re) +{ + ObjectInstanceRen *obi; + VolumeOb *vo; + + re->i.infostr = IFACE_("Volume preprocessing"); + re->stats_draw(re->sdh, &re->i); + + for (vo= re->volumes.first; vo; vo= vo->next) { + if (using_lightcache(vo->ma)) { + for (obi= re->instancetable.first; obi; obi= obi->next) { + if (obi->obr == vo->obr) { + vol_precache_objectinstance_threads(re, obi, vo->ma); + + if (re->test_break && re->test_break(re->tbh)) + break; + } + } + + if (re->test_break && re->test_break(re->tbh)) + break; + } + } + + re->i.infostr = NULL; + re->stats_draw(re->sdh, &re->i); +} + +void free_volume_precache(Render *re) +{ + ObjectInstanceRen *obi; + + for (obi= re->instancetable.first; obi; obi= obi->next) { + if (obi->volume_precache != NULL) { + MEM_freeN(obi->volume_precache->data_r); + MEM_freeN(obi->volume_precache->data_g); + MEM_freeN(obi->volume_precache->data_b); + MEM_freeN(obi->volume_precache->bbmin); + MEM_freeN(obi->volume_precache->bbmax); + MEM_freeN(obi->volume_precache); + obi->volume_precache = NULL; + } + } + + BLI_freelistN(&re->volumes); +} + +int point_inside_volume_objectinstance(Render *re, ObjectInstanceRen *obi, const float co[3]) +{ + RayObject *tree; + int inside=0; + + tree = makeraytree_object(re, obi); + if (!tree) return 0; + + inside = point_inside_obi(tree, obi, co); + + //TODO: makeraytree_object creates a tree and saves it on OBI, if we free this tree we should also clear other pointers to it + //RE_rayobject_free(tree); + //tree= NULL; + + return inside; +} + diff --git a/source/blender/render/intern/source/volumetric.c b/source/blender/render/intern/source/volumetric.c new file mode 100644 index 00000000000..583353ed8cf --- /dev/null +++ b/source/blender/render/intern/source/volumetric.c @@ -0,0 +1,836 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Matt Ebb, Raul Fernandez Hernandez (Farsthary) + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/render/intern/source/volumetric.c + * \ingroup render + */ + +#include <math.h> +#include <stdlib.h> +#include <string.h> +#include <float.h> + +#include "BLI_math.h" +#include "BLI_rand.h" +#include "BLI_voxel.h" +#include "BLI_utildefines.h" + +#include "RE_shader_ext.h" + +#include "IMB_colormanagement.h" + +#include "DNA_material_types.h" +#include "DNA_group_types.h" +#include "DNA_lamp_types.h" +#include "DNA_meta_types.h" + + +#include "render_types.h" +#include "pixelshading.h" +#include "rayintersection.h" +#include "rayobject.h" +#include "renderdatabase.h" +#include "shading.h" +#include "shadbuf.h" +#include "texture.h" +#include "volumetric.h" +#include "volume_precache.h" + +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ +/* defined in pipeline.c, is hardcopy of active dynamic allocated Render */ +/* only to be used here in this file, it's for speed */ +extern struct Render R; +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ + +/* tracing */ +static float vol_get_shadow(ShadeInput *shi, LampRen *lar, const float co[3]) +{ + float visibility = 1.f; + + if (lar->shb) { + float dxco[3] = {0.f, 0.f, 0.f}, dyco[3] = {0.f, 0.f, 0.f}; + + visibility = testshadowbuf(&R, lar->shb, co, dxco, dyco, 1.0, 0.0); + } + else if (lar->mode & LA_SHAD_RAY) { + /* trace shadow manually, no good lamp api atm */ + Isect is; + + copy_v3_v3(is.start, co); + if (lar->type == LA_SUN || lar->type == LA_HEMI) { + is.dir[0] = -lar->vec[0]; + is.dir[1] = -lar->vec[1]; + is.dir[2] = -lar->vec[2]; + is.dist = R.maxdist; + } + else { + sub_v3_v3v3(is.dir, lar->co, is.start); + is.dist = normalize_v3(is.dir); + } + + is.mode = RE_RAY_MIRROR; + is.check = RE_CHECK_VLR_NON_SOLID_MATERIAL; + is.skip = 0; + + if (lar->mode & (LA_LAYER | LA_LAYER_SHADOW)) + is.lay = lar->lay; + else + is.lay = -1; + + is.orig.ob = NULL; + is.orig.face = NULL; + is.last_hit = lar->last_hit[shi->thread]; + + RE_instance_rotate_ray(shi->obi, &is); + + if (RE_rayobject_raycast(R.raytree, &is)) { + RE_instance_rotate_ray_restore(shi->obi, &is); + + visibility = 0.f; + } + + lar->last_hit[shi->thread] = is.last_hit; + } + return visibility; +} + +static int vol_get_bounds(ShadeInput *shi, const float co[3], const float vec[3], float hitco[3], Isect *isect, int intersect_type) +{ + + copy_v3_v3(isect->start, co); + copy_v3_v3(isect->dir, vec); + isect->dist = FLT_MAX; + isect->mode = RE_RAY_MIRROR; + isect->last_hit = NULL; + isect->lay = -1; + isect->check = RE_CHECK_VLR_NONE; + + if (intersect_type == VOL_BOUNDS_DEPTH) { + isect->skip = RE_SKIP_VLR_NEIGHBOUR; + isect->orig.face = (void *)shi->vlr; + isect->orig.ob = (void *)shi->obi; + } + else { // if (intersect_type == VOL_BOUNDS_SS) { + isect->skip = 0; + isect->orig.face = NULL; + isect->orig.ob = NULL; + } + + RE_instance_rotate_ray(shi->obi, isect); + + if (RE_rayobject_raycast(R.raytree, isect)) { + RE_instance_rotate_ray_restore(shi->obi, isect); + + hitco[0] = isect->start[0] + isect->dist * isect->dir[0]; + hitco[1] = isect->start[1] + isect->dist * isect->dir[1]; + hitco[2] = isect->start[2] + isect->dist * isect->dir[2]; + return 1; + } + else { + return 0; + } +} + +static void shade_intersection(ShadeInput *shi, float col_r[4], Isect *is) +{ + ShadeInput shi_new; + ShadeResult shr_new; + + memset(&shi_new, 0, sizeof(ShadeInput)); + + shi_new.mask = shi->mask; + shi_new.osatex = shi->osatex; + shi_new.thread = shi->thread; + shi_new.depth = shi->depth + 1; + shi_new.volume_depth = shi->volume_depth + 1; + shi_new.xs = shi->xs; + shi_new.ys = shi->ys; + shi_new.lay = shi->lay; + shi_new.passflag = SCE_PASS_COMBINED; /* result of tracing needs no pass info */ + shi_new.combinedflag = 0xFFFFFF; /* ray trace does all options */ + shi_new.light_override = shi->light_override; + shi_new.mat_override = shi->mat_override; + + copy_v3_v3(shi_new.camera_co, is->start); + + memset(&shr_new, 0, sizeof(ShadeResult)); + + /* hardcoded limit of 100 for now - prevents problems in weird geometry */ + if (shi->volume_depth < 100) { + shade_ray(is, &shi_new, &shr_new); + } + + copy_v3_v3(col_r, shr_new.combined); + col_r[3] = shr_new.alpha; +} + +static void vol_trace_behind(ShadeInput *shi, VlakRen *vlr, const float co[3], float col_r[4]) +{ + Isect isect; + + copy_v3_v3(isect.start, co); + copy_v3_v3(isect.dir, shi->view); + isect.dist = FLT_MAX; + + isect.mode = RE_RAY_MIRROR; + isect.check = RE_CHECK_VLR_NONE; + isect.skip = RE_SKIP_VLR_NEIGHBOUR; + isect.orig.ob = (void *) shi->obi; + isect.orig.face = (void *)vlr; + isect.last_hit = NULL; + isect.lay = -1; + + /* check to see if there's anything behind the volume, otherwise shade the sky */ + RE_instance_rotate_ray(shi->obi, &isect); + + if (RE_rayobject_raycast(R.raytree, &isect)) { + RE_instance_rotate_ray_restore(shi->obi, &isect); + + shade_intersection(shi, col_r, &isect); + } + else { + shadeSkyView(col_r, co, shi->view, NULL, shi->thread); + shadeSunView(col_r, shi->view); + } +} + + +/* trilinear interpolation */ +static void vol_get_precached_scattering(Render *re, ShadeInput *shi, float scatter_col[3], const float co[3]) +{ + VolumePrecache *vp = shi->obi->volume_precache; + float bbmin[3], bbmax[3], dim[3]; + float world_co[3], sample_co[3]; + + if (!vp) return; + + /* find sample point in global space bounding box 0.0-1.0 */ + global_bounds_obi(re, shi->obi, bbmin, bbmax); + sub_v3_v3v3(dim, bbmax, bbmin); + mul_v3_m4v3(world_co, re->viewinv, co); + + /* sample_co in 0.0-1.0 */ + sample_co[0] = (world_co[0] - bbmin[0]) / dim[0]; + sample_co[1] = (world_co[1] - bbmin[1]) / dim[1]; + sample_co[2] = (world_co[2] - bbmin[2]) / dim[2]; + + scatter_col[0] = BLI_voxel_sample_triquadratic(vp->data_r, vp->res, sample_co); + scatter_col[1] = BLI_voxel_sample_triquadratic(vp->data_g, vp->res, sample_co); + scatter_col[2] = BLI_voxel_sample_triquadratic(vp->data_b, vp->res, sample_co); +} + +/* Meta object density, brute force for now + * (might be good enough anyway, don't need huge number of metaobs to model volumetric objects */ +static float metadensity(Object *ob, const float co[3]) +{ + float mat[4][4], imat[4][4], dens = 0.f; + MetaBall *mb = (MetaBall *)ob->data; + MetaElem *ml; + + /* transform co to meta-element */ + float tco[3] = {co[0], co[1], co[2]}; + mul_m4_m4m4(mat, R.viewmat, ob->obmat); + invert_m4_m4(imat, mat); + mul_m4_v3(imat, tco); + + for (ml = mb->elems.first; ml; ml = ml->next) { + float bmat[3][3], dist2; + + /* element rotation transform */ + float tp[3] = {ml->x - tco[0], ml->y - tco[1], ml->z - tco[2]}; + quat_to_mat3(bmat, ml->quat); + transpose_m3(bmat); /* rot.only, so inverse == transpose */ + mul_m3_v3(bmat, tp); + + /* MB_BALL default */ + switch (ml->type) { + case MB_ELIPSOID: + tp[0] /= ml->expx; + tp[1] /= ml->expy; + tp[2] /= ml->expz; + break; + case MB_CUBE: + tp[2] = (tp[2] > ml->expz) ? (tp[2] - ml->expz) : ((tp[2] < -ml->expz) ? (tp[2] + ml->expz) : 0.f); + /* no break, xy as plane */ + ATTR_FALLTHROUGH; + case MB_PLANE: + tp[1] = (tp[1] > ml->expy) ? (tp[1] - ml->expy) : ((tp[1] < -ml->expy) ? (tp[1] + ml->expy) : 0.f); + /* no break, x as tube */ + ATTR_FALLTHROUGH; + case MB_TUBE: + tp[0] = (tp[0] > ml->expx) ? (tp[0] - ml->expx) : ((tp[0] < -ml->expx) ? (tp[0] + ml->expx) : 0.f); + } + + /* ml->rad2 is not set */ + dist2 = 1.0f - (dot_v3v3(tp, tp) / (ml->rad * ml->rad)); + if (dist2 > 0.f) + dens += (ml->flag & MB_NEGATIVE) ? -ml->s * dist2 * dist2 * dist2 : ml->s * dist2 * dist2 * dist2; + } + + dens -= mb->thresh; + return (dens < 0.f) ? 0.f : dens; +} + +float vol_get_density(struct ShadeInput *shi, const float co[3]) +{ + float density = shi->mat->vol.density; + float density_scale = shi->mat->vol.density_scale; + + if (shi->mat->mapto_textured & MAP_DENSITY) + do_volume_tex(shi, co, MAP_DENSITY, NULL, &density, &R); + + /* if meta-object, modulate by metadensity without increasing it */ + if (shi->obi->obr->ob->type == OB_MBALL) { + const float md = metadensity(shi->obi->obr->ob, co); + if (md < 1.f) density *= md; + } + + return density * density_scale; +} + + +/* Color of light that gets scattered out by the volume */ +/* Uses same physically based scattering parameter as in transmission calculations, + * along with artificial reflection scale/reflection color tint */ +static void vol_get_reflection_color(ShadeInput *shi, float ref_col[3], const float co[3]) +{ + float scatter = shi->mat->vol.scattering; + float reflection = shi->mat->vol.reflection; + copy_v3_v3(ref_col, shi->mat->vol.reflection_col); + + if (shi->mat->mapto_textured & (MAP_SCATTERING + MAP_REFLECTION_COL)) + do_volume_tex(shi, co, MAP_SCATTERING + MAP_REFLECTION_COL, ref_col, &scatter, &R); + + /* only one single float parameter at a time... :s */ + if (shi->mat->mapto_textured & (MAP_REFLECTION)) + do_volume_tex(shi, co, MAP_REFLECTION, NULL, &reflection, &R); + + ref_col[0] = reflection * ref_col[0] * scatter; + ref_col[1] = reflection * ref_col[1] * scatter; + ref_col[2] = reflection * ref_col[2] * scatter; +} + +/* compute emission component, amount of radiance to add per segment + * can be textured with 'emit' */ +static void vol_get_emission(ShadeInput *shi, float emission_col[3], const float co[3]) +{ + float emission = shi->mat->vol.emission; + copy_v3_v3(emission_col, shi->mat->vol.emission_col); + + if (shi->mat->mapto_textured & (MAP_EMISSION + MAP_EMISSION_COL)) + do_volume_tex(shi, co, MAP_EMISSION + MAP_EMISSION_COL, emission_col, &emission, &R); + + emission_col[0] = emission_col[0] * emission; + emission_col[1] = emission_col[1] * emission; + emission_col[2] = emission_col[2] * emission; +} + + +/* A combination of scattering and absorption -> known as sigma T. + * This can possibly use a specific scattering color, + * and absorption multiplier factor too, but these parameters are left out for simplicity. + * It's easy enough to get a good wide range of results with just these two parameters. */ +static void vol_get_sigma_t(ShadeInput *shi, float sigma_t[3], const float co[3]) +{ + /* technically absorption, but named transmission color + * since it describes the effect of the coloring *after* absorption */ + float transmission_col[3] = {shi->mat->vol.transmission_col[0], shi->mat->vol.transmission_col[1], shi->mat->vol.transmission_col[2]}; + float scattering = shi->mat->vol.scattering; + + if (shi->mat->mapto_textured & (MAP_SCATTERING + MAP_TRANSMISSION_COL)) + do_volume_tex(shi, co, MAP_SCATTERING + MAP_TRANSMISSION_COL, transmission_col, &scattering, &R); + + sigma_t[0] = (1.0f - transmission_col[0]) + scattering; + sigma_t[1] = (1.0f - transmission_col[1]) + scattering; + sigma_t[2] = (1.0f - transmission_col[2]) + scattering; +} + +/* phase function - determines in which directions the light + * is scattered in the volume relative to incoming direction + * and view direction */ +static float vol_get_phasefunc(ShadeInput *UNUSED(shi), float g, const float w[3], const float wp[3]) +{ + const float normalize = 0.25f; // = 1.f/4.f = M_PI/(4.f*M_PI) + + /* normalization constant is 1/4 rather than 1/4pi, since + * Blender's shading system doesn't normalize for + * energy conservation - eg. multiplying by pdf ( 1/pi for a lambert brdf ). + * This means that lambert surfaces in Blender are pi times brighter than they 'should be' + * and therefore, with correct energy conservation, volumes will darker than other solid objects, + * for the same lighting intensity. + * To correct this, scale up the phase function values by pi + * until Blender's shading system supports this better. --matt + */ + + if (g == 0.f) { /* isotropic */ + return normalize * 1.f; + } + else { /* schlick */ + const float k = 1.55f * g - 0.55f * g * g * g; + const float kcostheta = k * dot_v3v3(w, wp); + return normalize * (1.f - k * k) / ((1.f - kcostheta) * (1.f - kcostheta)); + } + + /* not used, but here for reference: */ +#if 0 + switch (phasefunc_type) { + case MA_VOL_PH_MIEHAZY: + return normalize * (0.5f + 4.5f * powf(0.5 * (1.f + costheta), 8.f)); + case MA_VOL_PH_MIEMURKY: + return normalize * (0.5f + 16.5f * powf(0.5 * (1.f + costheta), 32.f)); + case MA_VOL_PH_RAYLEIGH: + return normalize * 3.f / 4.f * (1 + costheta * costheta); + case MA_VOL_PH_HG: + return normalize * (1.f - g * g) / powf(1.f + g * g - 2.f * g * costheta, 1.5f); + case MA_VOL_PH_SCHLICK: + { + const float k = 1.55f * g - 0.55f * g * g * g; + const float kcostheta = k * costheta; + return normalize * (1.f - k * k) / ((1.f - kcostheta) * (1.f - kcostheta)); + } + case MA_VOL_PH_ISOTROPIC: + default: + return normalize * 1.f; + } +#endif +} + +/* Compute transmittance = e^(-attenuation) */ +static void vol_get_transmittance_seg(ShadeInput *shi, float tr[3], float stepsize, const float co[3], float density) +{ + /* input density = density at co */ + float tau[3] = {0.f, 0.f, 0.f}; + const float stepd = density * stepsize; + float sigma_t[3]; + + vol_get_sigma_t(shi, sigma_t, co); + + /* homogeneous volume within the sampled distance */ + tau[0] += stepd * sigma_t[0]; + tau[1] += stepd * sigma_t[1]; + tau[2] += stepd * sigma_t[2]; + + tr[0] *= expf(-tau[0]); + tr[1] *= expf(-tau[1]); + tr[2] *= expf(-tau[2]); +} + +/* Compute transmittance = e^(-attenuation) */ +static void vol_get_transmittance(ShadeInput *shi, float tr[3], const float co[3], const float endco[3]) +{ + float p[3] = {co[0], co[1], co[2]}; + float step_vec[3] = {endco[0] - co[0], endco[1] - co[1], endco[2] - co[2]}; + float tau[3] = {0.f, 0.f, 0.f}; + + float t0 = 0.f; + float t1 = normalize_v3(step_vec); + float pt0 = t0; + + t0 += shi->mat->vol.stepsize * ((shi->mat->vol.stepsize_type == MA_VOL_STEP_CONSTANT) ? 0.5f : BLI_thread_frand(shi->thread)); + p[0] += t0 * step_vec[0]; + p[1] += t0 * step_vec[1]; + p[2] += t0 * step_vec[2]; + mul_v3_fl(step_vec, shi->mat->vol.stepsize); + + for (; t0 < t1; pt0 = t0, t0 += shi->mat->vol.stepsize) { + const float d = vol_get_density(shi, p); + const float stepd = (t0 - pt0) * d; + float sigma_t[3]; + + vol_get_sigma_t(shi, sigma_t, p); + + tau[0] += stepd * sigma_t[0]; + tau[1] += stepd * sigma_t[1]; + tau[2] += stepd * sigma_t[2]; + + add_v3_v3(p, step_vec); + } + + /* return transmittance */ + tr[0] = expf(-tau[0]); + tr[1] = expf(-tau[1]); + tr[2] = expf(-tau[2]); +} + +static void vol_shade_one_lamp(struct ShadeInput *shi, const float co[3], const float view[3], LampRen *lar, float lacol[3]) +{ + float visifac, lv[3], lampdist; + float tr[3] = {1.0, 1.0, 1.0}; + float hitco[3], *atten_co; + float p, ref_col[3]; + + if (lar->mode & LA_LAYER) if ((lar->lay & shi->obi->lay) == 0) return; + if ((lar->lay & shi->lay) == 0) return; + if (lar->energy == 0.0f) return; + + if ((visifac = lamp_get_visibility(lar, co, lv, &lampdist)) == 0.f) return; + + copy_v3_v3(lacol, &lar->r); + + if (lar->mode & LA_TEXTURE) { + shi->osatex = 0; + do_lamp_tex(lar, lv, shi, lacol, LA_TEXTURE); + } + + mul_v3_fl(lacol, visifac); + + if (ELEM(lar->type, LA_SUN, LA_HEMI)) + copy_v3_v3(lv, lar->vec); + negate_v3(lv); + + if (shi->mat->vol.shade_type == MA_VOL_SHADE_SHADOWED) { + mul_v3_fl(lacol, vol_get_shadow(shi, lar, co)); + } + else if (ELEM(shi->mat->vol.shade_type, MA_VOL_SHADE_SHADED, MA_VOL_SHADE_MULTIPLE, MA_VOL_SHADE_SHADEDPLUSMULTIPLE)) { + Isect is; + + if (shi->mat->vol.shadeflag & MA_VOL_RECV_EXT_SHADOW) { + mul_v3_fl(lacol, vol_get_shadow(shi, lar, co)); + if (IMB_colormanagement_get_luminance(lacol) < 0.001f) return; + } + + /* find minimum of volume bounds, or lamp coord */ + if (vol_get_bounds(shi, co, lv, hitco, &is, VOL_BOUNDS_SS)) { + float dist = len_v3v3(co, hitco); + VlakRen *vlr = (VlakRen *)is.hit.face; + + /* simple internal shadowing */ + if (vlr->mat->material_type == MA_TYPE_SURFACE) { + lacol[0] = lacol[1] = lacol[2] = 0.0f; + return; + } + + if (ELEM(lar->type, LA_SUN, LA_HEMI)) + /* infinite lights, can never be inside volume */ + atten_co = hitco; + else if (lampdist < dist) { + atten_co = lar->co; + } + else + atten_co = hitco; + + vol_get_transmittance(shi, tr, co, atten_co); + + mul_v3_v3v3(lacol, lacol, tr); + } + else { + /* Point is on the outside edge of the volume, + * therefore no attenuation, full transmission. + * Radiance from lamp remains unchanged */ + } + } + + if (IMB_colormanagement_get_luminance(lacol) < 0.001f) return; + + normalize_v3(lv); + p = vol_get_phasefunc(shi, shi->mat->vol.asymmetry, view, lv); + + /* physically based scattering with non-physically based RGB gain */ + vol_get_reflection_color(shi, ref_col, co); + + lacol[0] *= p * ref_col[0]; + lacol[1] *= p * ref_col[1]; + lacol[2] *= p * ref_col[2]; +} + +/* single scattering only for now */ +void vol_get_scattering(ShadeInput *shi, float scatter_col[3], const float co[3], const float view[3]) +{ + ListBase *lights; + GroupObject *go; + LampRen *lar; + + zero_v3(scatter_col); + + lights = get_lights(shi); + for (go = lights->first; go; go = go->next) { + float lacol[3] = {0.f, 0.f, 0.f}; + lar = go->lampren; + + if (lar) { + vol_shade_one_lamp(shi, co, view, lar, lacol); + add_v3_v3(scatter_col, lacol); + } + } +} + + +/* + * The main volumetric integrator, using an emission/absorption/scattering model. + * + * Incoming radiance = + * + * outgoing radiance from behind surface * beam transmittance/attenuation + * + added radiance from all points along the ray due to participating media + * --> radiance for each segment = + * (radiance added by scattering + radiance added by emission) * beam transmittance/attenuation + */ + +/* For ease of use, I've also introduced a 'reflection' and 'reflection color' parameter, which isn't + * physically correct. This works as an RGB tint/gain on out-scattered light, but doesn't affect the light + * that is transmitted through the volume. While having wavelength dependent absorption/scattering is more correct, + * it also makes it harder to control the overall look of the volume since coloring the outscattered light results + * in the inverse color being transmitted through the rest of the volume. + */ +static void volumeintegrate(struct ShadeInput *shi, float col[4], const float co[3], const float endco[3]) +{ + float radiance[3] = {0.f, 0.f, 0.f}; + float tr[3] = {1.f, 1.f, 1.f}; + float p[3] = {co[0], co[1], co[2]}; + float step_vec[3] = {endco[0] - co[0], endco[1] - co[1], endco[2] - co[2]}; + const float stepsize = shi->mat->vol.stepsize; + + float t0 = 0.f; + float pt0 = t0; + float t1 = normalize_v3(step_vec); /* returns vector length */ + + t0 += stepsize * ((shi->mat->vol.stepsize_type == MA_VOL_STEP_CONSTANT) ? 0.5f : BLI_thread_frand(shi->thread)); + p[0] += t0 * step_vec[0]; + p[1] += t0 * step_vec[1]; + p[2] += t0 * step_vec[2]; + mul_v3_fl(step_vec, stepsize); + + for (; t0 < t1; pt0 = t0, t0 += stepsize) { + const float density = vol_get_density(shi, p); + + if (density > 0.00001f) { + float scatter_col[3] = {0.f, 0.f, 0.f}, emit_col[3]; + const float stepd = (t0 - pt0) * density; + + /* transmittance component (alpha) */ + vol_get_transmittance_seg(shi, tr, stepsize, co, density); + + if (t0 > t1 * 0.25f) { + /* only use depth cutoff after we've traced a little way into the volume */ + if (IMB_colormanagement_get_luminance(tr) < shi->mat->vol.depth_cutoff) break; + } + + vol_get_emission(shi, emit_col, p); + + if (shi->obi->volume_precache) { + float p2[3]; + + p2[0] = p[0] + (step_vec[0] * 0.5f); + p2[1] = p[1] + (step_vec[1] * 0.5f); + p2[2] = p[2] + (step_vec[2] * 0.5f); + + vol_get_precached_scattering(&R, shi, scatter_col, p2); + } + else + vol_get_scattering(shi, scatter_col, p, shi->view); + + radiance[0] += stepd * tr[0] * (emit_col[0] + scatter_col[0]); + radiance[1] += stepd * tr[1] * (emit_col[1] + scatter_col[1]); + radiance[2] += stepd * tr[2] * (emit_col[2] + scatter_col[2]); + } + add_v3_v3(p, step_vec); + } + + /* multiply original color (from behind volume) with transmittance over entire distance */ + mul_v3_v3v3(col, tr, col); + add_v3_v3(col, radiance); + + /* alpha <-- transmission luminance */ + col[3] = 1.0f - IMB_colormanagement_get_luminance(tr); +} + +/* the main entry point for volume shading */ +static void volume_trace(struct ShadeInput *shi, struct ShadeResult *shr, int inside_volume) +{ + float hitco[3], col[4] = {0.f, 0.f, 0.f, 0.f}; + const float *startco, *endco; + int trace_behind = 1; + const int ztransp = ((shi->depth == 0) && (shi->mat->mode & MA_TRANSP) && (shi->mat->mode & MA_ZTRANSP)); + Isect is; + + /* check for shading an internal face a volume object directly */ + if (inside_volume == VOL_SHADE_INSIDE) + trace_behind = 0; + else if (inside_volume == VOL_SHADE_OUTSIDE) { + if (shi->flippednor) + inside_volume = VOL_SHADE_INSIDE; + } + + if (ztransp && inside_volume == VOL_SHADE_INSIDE) { + MatInside *mi; + int render_this = 0; + + /* don't render the backfaces of ztransp volume materials. + * + * volume shading renders the internal volume from between the + * ' view intersection of the solid volume to the + * intersection on the other side, as part of the shading of + * the front face. + * + * Because ztransp renders both front and back faces independently + * this will double up, so here we prevent rendering the backface as well, + * which would otherwise render the volume in between the camera and the backface + * --matt */ + + for (mi = R.render_volumes_inside.first; mi; mi = mi->next) { + /* weak... */ + if (mi->ma == shi->mat) render_this = 1; + } + if (!render_this) return; + } + + + if (inside_volume == VOL_SHADE_INSIDE) { + startco = shi->camera_co; + endco = shi->co; + + if (trace_behind) { + if (!ztransp) + /* trace behind the volume object */ + vol_trace_behind(shi, shi->vlr, endco, col); + } + else { + /* we're tracing through the volume between the camera + * and a solid surface, so use that pre-shaded radiance */ + copy_v4_v4(col, shr->combined); + } + + /* shade volume from 'camera' to 1st hit point */ + volumeintegrate(shi, col, startco, endco); + } + /* trace to find a backface, the other side bounds of the volume */ + /* (ray intersect ignores front faces here) */ + else if (vol_get_bounds(shi, shi->co, shi->view, hitco, &is, VOL_BOUNDS_DEPTH)) { + VlakRen *vlr = (VlakRen *)is.hit.face; + + startco = shi->co; + endco = hitco; + + if (!ztransp) { + /* if it's another face in the same material */ + if (vlr->mat == shi->mat) { + /* trace behind the 2nd (raytrace) hit point */ + vol_trace_behind(shi, (VlakRen *)is.hit.face, endco, col); + } + else { + shade_intersection(shi, col, &is); + } + } + + /* shade volume from 1st hit point to 2nd hit point */ + volumeintegrate(shi, col, startco, endco); + } + + if (ztransp) + col[3] = col[3] > 1.f ? 1.f : col[3]; + else + col[3] = 1.f; + + copy_v3_v3(shr->combined, col); + shr->alpha = col[3]; + + copy_v3_v3(shr->diff, shr->combined); + copy_v3_v3(shr->diffshad, shr->diff); +} + +/* Traces a shadow through the object, + * pretty much gets the transmission over a ray path */ +void shade_volume_shadow(struct ShadeInput *shi, struct ShadeResult *shr, struct Isect *last_is) +{ + float hitco[3]; + float tr[3] = {1.0, 1.0, 1.0}; + Isect is = {{0}}; + const float *startco, *endco; + + memset(shr, 0, sizeof(ShadeResult)); + + /* if 1st hit normal is facing away from the camera, + * then we're inside the volume already. */ + if (shi->flippednor) { + startco = last_is->start; + endco = shi->co; + } + + /* trace to find a backface, the other side bounds of the volume */ + /* (ray intersect ignores front faces here) */ + else if (vol_get_bounds(shi, shi->co, shi->view, hitco, &is, VOL_BOUNDS_DEPTH)) { + startco = shi->co; + endco = hitco; + } + else { + shr->combined[0] = shr->combined[1] = shr->combined[2] = 0.f; + shr->alpha = shr->combined[3] = 1.f; + return; + } + + vol_get_transmittance(shi, tr, startco, endco); + + + /* if we hit another face in the same volume bounds */ + /* shift raytrace coordinates to the hit point, to avoid shading volume twice */ + /* due to idiosyncracy in ray_trace_shadow_tra() */ + if (is.hit.ob == shi->obi) { + copy_v3_v3(shi->co, hitco); + last_is->dist += is.dist; + shi->vlr = (VlakRen *)is.hit.face; + } + + + copy_v3_v3(shr->combined, tr); + shr->combined[3] = 1.0f - IMB_colormanagement_get_luminance(tr); + shr->alpha = shr->combined[3]; +} + + +/* delivers a fully filled in ShadeResult, for all passes */ +void shade_volume_outside(ShadeInput *shi, ShadeResult *shr) +{ + memset(shr, 0, sizeof(ShadeResult)); + volume_trace(shi, shr, VOL_SHADE_OUTSIDE); +} + + +void shade_volume_inside(ShadeInput *shi, ShadeResult *shr) +{ + MatInside *m; + Material *mat_backup; + ObjectInstanceRen *obi_backup; + float prev_alpha = shr->alpha; + + /* XXX: extend to multiple volumes perhaps later */ + mat_backup = shi->mat; + obi_backup = shi->obi; + + m = R.render_volumes_inside.first; + shi->mat = m->ma; + shi->obi = m->obi; + shi->obr = m->obi->obr; + + volume_trace(shi, shr, VOL_SHADE_INSIDE); + + shr->alpha = shr->alpha + prev_alpha; + CLAMP(shr->alpha, 0.0f, 1.0f); + + shi->mat = mat_backup; + shi->obi = obi_backup; + shi->obr = obi_backup->obr; +} diff --git a/source/blender/render/intern/source/voxeldata.c b/source/blender/render/intern/source/voxeldata.c new file mode 100644 index 00000000000..2daa4123536 --- /dev/null +++ b/source/blender/render/intern/source/voxeldata.c @@ -0,0 +1,571 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Raul Fernandez Hernandez (Farsthary), Matt Ebb. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/render/intern/source/voxeldata.c + * \ingroup render + */ + + +#include <math.h> +#include <stdlib.h> +#include <stdio.h> + +#ifdef WIN32 +#include "BLI_winstuff.h" +#endif + +#include "MEM_guardedalloc.h" + +#include "BLI_math.h" +#include "BLI_blenlib.h" +#include "BLI_threads.h" +#include "BLI_voxel.h" +#include "BLI_utildefines.h" + +#include "BLT_translation.h" + +#include "IMB_imbuf.h" +#include "IMB_imbuf_types.h" + +#include "BKE_cloth.h" +#include "BKE_global.h" +#include "BKE_image.h" +#include "BKE_main.h" +#include "BKE_modifier.h" + +#include "smoke_API.h" +#include "BPH_mass_spring.h" + +#include "DNA_texture_types.h" +#include "DNA_object_force_types.h" +#include "DNA_object_types.h" +#include "DNA_particle_types.h" +#include "DNA_modifier_types.h" +#include "DNA_smoke_types.h" + + +#include "render_types.h" +#include "texture.h" +#include "voxeldata.h" + +static bool is_vd_res_ok(VoxelData *vd) +{ + /* arbitrary large value so corrupt headers don't break */ + const int min = 1, max = 100000; + return (vd->resol[0] >= min && vd->resol[0] <= max) && + (vd->resol[1] >= min && vd->resol[1] <= max) && + (vd->resol[2] >= min && vd->resol[2] <= max); +} + +/* use size_t because the result may exceed INT_MAX */ +static size_t vd_resol_size(VoxelData *vd) +{ + return (size_t)vd->resol[0] * (size_t)vd->resol[1] * (size_t)vd->resol[2]; +} + +static int load_frame_blendervoxel(VoxelData *vd, FILE *fp, int frame) +{ + const size_t size = vd_resol_size(vd); + size_t offset = sizeof(VoxelDataHeader); + + if (is_vd_res_ok(vd) == false) + return 0; + + vd->dataset = MEM_mapallocN(sizeof(float) * size, "voxel dataset"); + if (vd->dataset == NULL) return 0; + + if (fseek(fp, frame * size * sizeof(float) + offset, 0) == -1) + return 0; + if (fread(vd->dataset, sizeof(float), size, fp) != size) + return 0; + + vd->cachedframe = frame; + vd->ok = 1; + return 1; +} + +static int load_frame_raw8(VoxelData *vd, FILE *fp, int frame) +{ + const size_t size = vd_resol_size(vd); + size_t i; + char *data_c; + + if (is_vd_res_ok(vd) == false) + return 0; + + vd->dataset = MEM_mapallocN(sizeof(float) * size, "voxel dataset"); + if (vd->dataset == NULL) return 0; + data_c = (char *)MEM_mallocN(sizeof(char) * size, "temporary voxel file reading storage"); + if (data_c == NULL) { + MEM_freeN(vd->dataset); + vd->dataset = NULL; + return 0; + } + + if (fseek(fp, (frame - 1) * size * sizeof(char), 0) == -1) { + MEM_freeN(data_c); + MEM_freeN(vd->dataset); + vd->dataset = NULL; + return 0; + } + if (fread(data_c, sizeof(char), size, fp) != size) { + MEM_freeN(data_c); + MEM_freeN(vd->dataset); + vd->dataset = NULL; + return 0; + } + + for (i = 0; i < size; i++) { + vd->dataset[i] = (float)data_c[i] / 255.f; + } + MEM_freeN(data_c); + + vd->cachedframe = frame; + vd->ok = 1; + return 1; +} + +static void load_frame_image_sequence(VoxelData *vd, Tex *tex) +{ + ImBuf *ibuf; + Image *ima = tex->ima; + ImageUser *tiuser = &tex->iuser; + ImageUser iuser = *(tiuser); + int x = 0, y = 0, z = 0; + const float *rf; + + if (!ima) return; + if (iuser.frames == 0) return; + + ima->source = IMA_SRC_SEQUENCE; + iuser.framenr = 1 + iuser.offset; + + /* find the first valid ibuf and use it to initialize the resolution of the data set */ + /* need to do this in advance so we know how much memory to allocate */ + ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL); + while (!ibuf && (iuser.framenr < iuser.frames)) { + iuser.framenr++; + ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL); + } + if (!ibuf) return; + if (!ibuf->rect_float) IMB_float_from_rect(ibuf); + + vd->flag |= TEX_VD_STILL; + vd->resol[0] = ibuf->x; + vd->resol[1] = ibuf->y; + vd->resol[2] = iuser.frames; + vd->dataset = MEM_mapallocN(sizeof(float) * vd_resol_size(vd), "voxel dataset"); + + for (z = 0; z < iuser.frames; z++) { + /* get a new ibuf for each frame */ + if (z > 0) { + iuser.framenr++; + BKE_image_release_ibuf(ima, ibuf, NULL); + ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL); + if (!ibuf) break; + if (!ibuf->rect_float) IMB_float_from_rect(ibuf); + } + rf = ibuf->rect_float; + + for (y = 0; y < ibuf->y; y++) { + for (x = 0; x < ibuf->x; x++) { + /* currently averaged to monchrome */ + vd->dataset[BLI_VOXEL_INDEX(x, y, z, vd->resol)] = (rf[0] + rf[1] + rf[2]) / 3.0f; + rf += 4; + } + } + + BKE_image_free_anim_ibufs(ima, iuser.framenr); + } + + BKE_image_release_ibuf(ima, ibuf, NULL); + + vd->ok = 1; + return; +} + +static int read_voxeldata_header(FILE *fp, struct VoxelData *vd) +{ + VoxelDataHeader *h = (VoxelDataHeader *)MEM_mallocN(sizeof(VoxelDataHeader), "voxel data header"); + + rewind(fp); + if (fread(h, sizeof(VoxelDataHeader), 1, fp) != 1) { + MEM_freeN(h); + return 0; + } + + vd->resol[0] = h->resolX; + vd->resol[1] = h->resolY; + vd->resol[2] = h->resolZ; + + MEM_freeN(h); + return 1; +} + +static void init_frame_smoke(VoxelData *vd, int cfra) +{ +#ifdef WITH_SMOKE + Object *ob; + ModifierData *md; + + vd->dataset = NULL; + if (vd->object == NULL) return; + ob = vd->object; + + /* draw code for smoke */ + if ((md = (ModifierData *)modifiers_findByType(ob, eModifierType_Smoke))) { + SmokeModifierData *smd = (SmokeModifierData *)md; + SmokeDomainSettings *sds = smd->domain; + + if (sds && sds->fluid) { + BLI_rw_mutex_lock(sds->fluid_mutex, THREAD_LOCK_READ); + + if (!sds->fluid) { + BLI_rw_mutex_unlock(sds->fluid_mutex); + return; + } + + if (cfra < sds->point_cache[0]->startframe) + ; /* don't show smoke before simulation starts, this could be made an option in the future */ + else if (vd->smoked_type == TEX_VD_SMOKEHEAT) { + size_t totRes; + size_t i; + float *heat; + + if (!smoke_has_heat(sds->fluid)) { + BLI_rw_mutex_unlock(sds->fluid_mutex); + return; + } + + copy_v3_v3_int(vd->resol, sds->res); + totRes = vd_resol_size(vd); + vd->dataset = MEM_mapallocN(sizeof(float) * (totRes), "smoke data"); + /* get heat data */ + heat = smoke_get_heat(sds->fluid); + + /* scale heat values from -2.0-2.0 to 0.0-1.0 */ + for (i = 0; i < totRes; i++) { + vd->dataset[i] = (heat[i] + 2.0f) / 4.0f; + } + } + else if (vd->smoked_type == TEX_VD_SMOKEVEL) { + size_t totRes; + size_t i; + float *xvel, *yvel, *zvel; + + copy_v3_v3_int(vd->resol, sds->res); + totRes = vd_resol_size(vd); + vd->dataset = MEM_mapallocN(sizeof(float) * (totRes), "smoke data"); + /* get velocity data */ + xvel = smoke_get_velocity_x(sds->fluid); + yvel = smoke_get_velocity_y(sds->fluid); + zvel = smoke_get_velocity_z(sds->fluid); + + /* map velocities between 0 and 0.3f */ + for (i = 0; i < totRes; i++) { + vd->dataset[i] = sqrtf(xvel[i] * xvel[i] + yvel[i] * yvel[i] + zvel[i] * zvel[i]) * 3.0f; + } + + } + else if (vd->smoked_type == TEX_VD_SMOKEFLAME) { + size_t totRes; + float *flame; + + if (sds->flags & MOD_SMOKE_HIGHRES) { + if (!smoke_turbulence_has_fuel(sds->wt)) { + BLI_rw_mutex_unlock(sds->fluid_mutex); + return; + } + smoke_turbulence_get_res(sds->wt, vd->resol); + flame = smoke_turbulence_get_flame(sds->wt); + } + else { + if (!smoke_has_fuel(sds->fluid)) { + BLI_rw_mutex_unlock(sds->fluid_mutex); + return; + } + copy_v3_v3_int(vd->resol, sds->res); + flame = smoke_get_flame(sds->fluid); + } + + /* always store copy, as smoke internal data can change */ + totRes = vd_resol_size(vd); + vd->dataset = MEM_mapallocN(sizeof(float)*(totRes), "smoke data"); + memcpy(vd->dataset, flame, sizeof(float)*totRes); + } + else { + size_t totCells; + int depth = 4; + vd->data_type = TEX_VD_RGBA_PREMUL; + + /* data resolution */ + if (sds->flags & MOD_SMOKE_HIGHRES) { + smoke_turbulence_get_res(sds->wt, vd->resol); + } + else { + copy_v3_v3_int(vd->resol, sds->res); + } + + /* TODO: is_vd_res_ok(rvd) doesnt check this resolution */ + totCells = vd_resol_size(vd) * depth; + /* always store copy, as smoke internal data can change */ + vd->dataset = MEM_mapallocN(sizeof(float) * totCells, "smoke data"); + + if (sds->flags & MOD_SMOKE_HIGHRES) { + if (smoke_turbulence_has_colors(sds->wt)) { + smoke_turbulence_get_rgba(sds->wt, vd->dataset, 1); + } + else { + smoke_turbulence_get_rgba_from_density(sds->wt, sds->active_color, vd->dataset, 1); + } + } + else { + if (smoke_has_colors(sds->fluid)) { + smoke_get_rgba(sds->fluid, vd->dataset, 1); + } + else { + smoke_get_rgba_from_density(sds->fluid, sds->active_color, vd->dataset, 1); + } + } + } /* end of fluid condition */ + + BLI_rw_mutex_unlock(sds->fluid_mutex); + } + } + + vd->ok = 1; + +#else // WITH_SMOKE + (void)vd; + (void)cfra; + + vd->dataset = NULL; +#endif +} + +static void init_frame_hair(VoxelData *vd, int UNUSED(cfra)) +{ + Object *ob; + ModifierData *md; + + vd->dataset = NULL; + if (vd->object == NULL) return; + ob = vd->object; + + if ((md = (ModifierData *)modifiers_findByType(ob, eModifierType_ParticleSystem))) { + ParticleSystemModifierData *pmd = (ParticleSystemModifierData *)md; + + if (pmd->psys && pmd->psys->clmd) { + vd->ok |= BPH_cloth_solver_get_texture_data(ob, pmd->psys->clmd, vd); + } + } +} + +void cache_voxeldata(Tex *tex, int scene_frame) +{ + VoxelData *vd = tex->vd; + FILE *fp; + int curframe; + char path[sizeof(vd->source_path)]; + + /* only re-cache if dataset needs updating */ + if ((vd->flag & TEX_VD_STILL) || (vd->cachedframe == scene_frame)) + if (vd->ok) return; + + /* clear out old cache, ready for new */ + if (vd->dataset) { + MEM_freeN(vd->dataset); + vd->dataset = NULL; + } + /* reset data_type */ + vd->data_type = TEX_VD_INTENSITY; + + if (vd->flag & TEX_VD_STILL) + curframe = vd->still_frame; + else + curframe = scene_frame; + + BLI_strncpy(path, vd->source_path, sizeof(path)); + + /* each type is responsible for setting to true */ + vd->ok = false; + + switch (vd->file_format) { + case TEX_VD_IMAGE_SEQUENCE: + load_frame_image_sequence(vd, tex); + return; + case TEX_VD_SMOKE: + init_frame_smoke(vd, scene_frame); + return; + case TEX_VD_HAIR: + init_frame_hair(vd, scene_frame); + return; + case TEX_VD_BLENDERVOXEL: + BLI_path_abs(path, BKE_main_blendfile_path_from_global()); + fp = BLI_fopen(path, "rb"); + if (!fp) return; + + if (read_voxeldata_header(fp, vd)) + load_frame_blendervoxel(vd, fp, curframe - 1); + + fclose(fp); + return; + case TEX_VD_RAW_8BIT: + BLI_path_abs(path, BKE_main_blendfile_path_from_global()); + fp = BLI_fopen(path, "rb"); + if (!fp) return; + + load_frame_raw8(vd, fp, curframe); + fclose(fp); + return; + } +} + +void make_voxeldata(struct Render *re) +{ + Tex *tex; + + re->i.infostr = IFACE_("Loading voxel datasets"); + re->stats_draw(re->sdh, &re->i); + + /* XXX: should be doing only textures used in this render */ + for (tex = re->main->tex.first; tex; tex = tex->id.next) { + if (tex->id.us && tex->type == TEX_VOXELDATA) { + cache_voxeldata(tex, re->r.cfra); + } + } + + re->i.infostr = NULL; + re->stats_draw(re->sdh, &re->i); + +} + +int voxeldatatex(struct Tex *tex, const float texvec[3], struct TexResult *texres) +{ + VoxelData *vd = tex->vd; + float co[3], offset[3] = {0.5, 0.5, 0.5}, a; + int retval = (vd->data_type == TEX_VD_RGBA_PREMUL) ? TEX_RGB : TEX_INT; + int depth = (vd->data_type == TEX_VD_RGBA_PREMUL) ? 4 : 1; + int ch; + + if (vd->dataset == NULL) { + texres->tin = 0.0f; + return 0; + } + + /* scale lookup from 0.0-1.0 (original location) to -1.0, 1.0, consistent with image texture tex coords */ + /* in implementation this works backwards, bringing sample locations from -1.0, 1.0 + * to the range 0.0, 1.0, before looking up in the voxel structure. */ + copy_v3_v3(co, texvec); + mul_v3_fl(co, 0.5f); + add_v3_v3(co, offset); + + /* co is now in the range 0.0, 1.0 */ + switch (vd->extend) { + case TEX_CLIP: + { + if ((co[0] < 0.f || co[0] > 1.f) || (co[1] < 0.f || co[1] > 1.f) || (co[2] < 0.f || co[2] > 1.f)) { + texres->tin = 0.f; + return retval; + } + break; + } + case TEX_REPEAT: + { + co[0] = co[0] - floorf(co[0]); + co[1] = co[1] - floorf(co[1]); + co[2] = co[2] - floorf(co[2]); + break; + } + case TEX_EXTEND: + { + CLAMP(co[0], 0.f, 1.f); + CLAMP(co[1], 0.f, 1.f); + CLAMP(co[2], 0.f, 1.f); + break; + } + } + + for (ch = 0; ch < depth; ch++) { + float *dataset = vd->dataset + ch*vd->resol[0]*vd->resol[1]*vd->resol[2]; + float *result = &texres->tin; + + if (vd->data_type == TEX_VD_RGBA_PREMUL) { + switch (ch) { + case 0: + result = &texres->tr; + break; + case 1: + result = &texres->tg; + break; + case 2: + result = &texres->tb; + break; + } + } + + switch (vd->interp_type) { + case TEX_VD_NEARESTNEIGHBOR: + *result = BLI_voxel_sample_nearest(dataset, vd->resol, co); + break; + case TEX_VD_LINEAR: + *result = BLI_voxel_sample_trilinear(dataset, vd->resol, co); + break; + case TEX_VD_QUADRATIC: + *result = BLI_voxel_sample_triquadratic(dataset, vd->resol, co); + break; + case TEX_VD_TRICUBIC_CATROM: + case TEX_VD_TRICUBIC_BSPLINE: + *result = BLI_voxel_sample_tricubic(dataset, vd->resol, co, (vd->interp_type == TEX_VD_TRICUBIC_BSPLINE)); + break; + } + } + + a = texres->tin; + texres->tin *= vd->int_multiplier; + BRICONT; + + if (vd->data_type == TEX_VD_RGBA_PREMUL) { + /* unmultiply */ + if (a>0.001f) { + texres->tr /= a; + texres->tg /= a; + texres->tb /= a; + } + texres->talpha = 1; + } + else { + texres->tr = texres->tin; + texres->tg = texres->tin; + texres->tb = texres->tin; + } + + texres->ta = texres->tin; + BRICONTRGB; + + return retval; +} diff --git a/source/blender/render/intern/source/zbuf.c b/source/blender/render/intern/source/zbuf.c index 3837383c4c7..436ee590f5c 100644 --- a/source/blender/render/intern/source/zbuf.c +++ b/source/blender/render/intern/source/zbuf.c @@ -54,10 +54,10 @@ void zbuf_alloc_span(ZSpan *zspan, int rectx, int recty) { memset(zspan, 0, sizeof(ZSpan)); - + zspan->rectx= rectx; zspan->recty= recty; - + zspan->span1= MEM_mallocN(recty*sizeof(float), "zspan"); zspan->span2= MEM_mallocN(recty*sizeof(float), "zspan"); } @@ -85,27 +85,27 @@ static void zbuf_add_to_span(ZSpan *zspan, const float v1[2], const float v2[2]) float *span; float xx1, dx0, xs0; int y, my0, my2; - + if (v1[1]<v2[1]) { minv= v1; maxv= v2; } else { minv= v2; maxv= v1; } - + my0= ceil(minv[1]); my2= floor(maxv[1]); - + if (my2<0 || my0>= zspan->recty) return; - + /* clip top */ if (my2>=zspan->recty) my2= zspan->recty-1; /* clip bottom */ if (my0<0) my0= 0; - + if (my0>my2) return; /* if (my0>my2) should still fill in, that way we get spans that skip nicely */ - + xx1= maxv[1]-minv[1]; if (xx1>FLT_EPSILON) { dx0= (minv[0]-maxv[0])/xx1; @@ -115,7 +115,7 @@ static void zbuf_add_to_span(ZSpan *zspan, const float v1[2], const float v2[2]) dx0 = 0.0f; xs0 = min_ff(minv[0], maxv[0]); } - + /* empty span */ if (zspan->maxp1 == NULL) { span= zspan->span1; @@ -158,9 +158,9 @@ static void zbuf_add_to_span(ZSpan *zspan, const float v1[2], const float v2[2]) } } -/*-----------------------------------------------------------*/ +/*-----------------------------------------------------------*/ /* Functions */ -/*-----------------------------------------------------------*/ +/*-----------------------------------------------------------*/ /* scanconvert for strand triangles, calls func for each x, y coordinate and gives UV barycentrics and z */ @@ -170,30 +170,30 @@ void zspan_scanconvert(ZSpan *zspan, void *handle, float *v1, float *v2, float * float u, v, uxd, uyd, vxd, vyd, uy0, vy0, xx1; const float *span1, *span2; int i, j, x, y, sn1, sn2, rectx = zspan->rectx, my0, my2; - + /* init */ zbuf_init_span(zspan); - + /* set spans */ zbuf_add_to_span(zspan, v1, v2); zbuf_add_to_span(zspan, v2, v3); zbuf_add_to_span(zspan, v3, v1); - + /* clipped */ if (zspan->minp2==NULL || zspan->maxp2==NULL) return; - + my0 = max_ii(zspan->miny1, zspan->miny2); my2 = min_ii(zspan->maxy1, zspan->maxy2); - + // printf("my %d %d\n", my0, my2); if (my2<my0) return; - + /* ZBUF DX DY, in floats still */ x1= v1[0]- v2[0]; x2= v2[0]- v3[0]; y1= v1[1]- v2[1]; y2= v2[1]- v3[1]; - + z1= 1.0f; /* (u1 - u2) */ z2= 0.0f; /* (u2 - u3) */ @@ -213,28 +213,28 @@ void zspan_scanconvert(ZSpan *zspan, void *handle, float *v1, float *v2, float * x0= y1*z2-z1*y2; y0= z1*x2-x1*z2; - + xx1= (x0*v1[0] + y0*v1[1])/z0; vxd= -(double)x0/(double)z0; vyd= -(double)y0/(double)z0; vy0= ((double)my2)*vyd + (double)xx1; - + /* correct span */ span1= zspan->span1+my2; span2= zspan->span2+my2; - + for (i = 0, y = my2; y >= my0; i++, y--, span1--, span2--) { - + sn1= floor(min_ff(*span1, *span2)); sn2= floor(max_ff(*span1, *span2)); - sn1++; - + sn1++; + if (sn2>=rectx) sn2= rectx-1; if (sn1<0) sn1= 0; - + u = (((double)sn1 * uxd) + uy0) - (i * uyd); v = (((double)sn1 * vxd) + vy0) - (i * vyd); - + for (j = 0, x = sn1; x <= sn2; j++, x++) { func(handle, x, y, u + (j * uxd), v + (j * vxd)); } diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h index 21e050e8e14..267aa448dc3 100644 --- a/source/blender/windowmanager/WM_api.h +++ b/source/blender/windowmanager/WM_api.h @@ -142,7 +142,7 @@ enum { struct wmWindow *WM_window_open(struct bContext *C, const struct rcti *rect); struct wmWindow *WM_window_open_temp(struct bContext *C, int x, int y, int sizex, int sizey, int type); void WM_window_set_dpi(wmWindow *win); - + bool WM_stereo3d_enabled(struct wmWindow *win, bool only_fullscreen_test); diff --git a/source/blender/windowmanager/WM_keymap.h b/source/blender/windowmanager/WM_keymap.h index 04ea8611dcc..9390db400d2 100644 --- a/source/blender/windowmanager/WM_keymap.h +++ b/source/blender/windowmanager/WM_keymap.h @@ -58,9 +58,9 @@ void WM_keyconfig_update_operatortype(void); void WM_keymap_init (struct bContext *C); void WM_keymap_free (struct wmKeyMap *keymap); -wmKeyMapItem *WM_keymap_verify_item(struct wmKeyMap *keymap, const char *idname, int type, +wmKeyMapItem *WM_keymap_verify_item(struct wmKeyMap *keymap, const char *idname, int type, int val, int modifier, int keymodifier); -wmKeyMapItem *WM_keymap_add_item(struct wmKeyMap *keymap, const char *idname, int type, +wmKeyMapItem *WM_keymap_add_item(struct wmKeyMap *keymap, const char *idname, int type, int val, int modifier, int keymodifier); wmKeyMapItem *WM_keymap_add_menu(struct wmKeyMap *keymap, const char *idname, int type, int val, int modifier, int keymodifier); @@ -79,7 +79,7 @@ wmKeyMap *WM_keymap_active(struct wmWindowManager *wm, struct wmKeyMap *keymap); wmKeyMap *WM_keymap_guess_opname(const struct bContext *C, const char *opname); bool WM_keymap_remove(struct wmKeyConfig *keyconfig, struct wmKeyMap *keymap); bool WM_keymap_poll(struct bContext *C, struct wmKeyMap *keymap); - + wmKeyMapItem *WM_keymap_item_find_id(struct wmKeyMap *keymap, int id); int WM_keymap_item_compare(struct wmKeyMapItem *k1, struct wmKeyMapItem *k2); diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h index 81018348ca0..929617aab04 100644 --- a/source/blender/windowmanager/WM_types.h +++ b/source/blender/windowmanager/WM_types.h @@ -200,6 +200,7 @@ typedef enum eOperatorPropTags { #define KM_RELEASE 2 #define KM_CLICK 3 #define KM_DBL_CLICK 4 +#define KM_CLICK_DRAG 5 /* ************** UI Handler ***************** */ @@ -211,14 +212,14 @@ typedef enum eOperatorPropTags { typedef struct wmNotifier { struct wmNotifier *next, *prev; - + struct wmWindowManager *wm; struct wmWindow *window; - + unsigned int category, data, subtype, action; - + void *reference; - + } wmNotifier; @@ -335,7 +336,7 @@ typedef struct wmNotifier { /* NC_TEXT Text */ #define ND_CURSOR (50<<16) #define ND_DISPLAY (51<<16) - + /* NC_ANIMATION Animato */ #define ND_KEYFRAME (70<<16) #define ND_KEYFRAME_PROP (71<<16) @@ -433,7 +434,7 @@ typedef struct wmGesture { uint is_active : 1; /* Use for gestures that support both immediate or delayed activation. */ uint wait_for_input : 1; - + void *customdata; /* customdata for border is a recti */ /* customdata for circle is recti, (xmin, ymin) is center, xmax radius */ @@ -451,7 +452,7 @@ typedef struct wmGesture { /* event comes from eventmanager and from keymap */ typedef struct wmEvent { struct wmEvent *next, *prev; - + short type; /* event code itself (short, is also in keymap) */ short val; /* press, release, scrollvalue */ int x, y; /* mouse pointer position, screen coord */ @@ -468,13 +469,14 @@ typedef struct wmEvent { int prevx, prevy; double prevclicktime; int prevclickx, prevclicky; - + /* modifier states */ short shift, ctrl, alt, oskey; /* oskey is apple or windowskey, value denotes order of pressed */ short keymodifier; /* rawkey modifier */ - + /* set in case a KM_PRESS went by unhandled */ char check_click; + char check_drag; char is_motion_absolute; /* keymap item, set by handler (weak?) */ @@ -488,7 +490,7 @@ typedef struct wmEvent { short customdatafree; int pad2; void *customdata; /* ascii, unicode, mouse coords, angles, vectors, dragdrop info */ - + } wmEvent; /* ************** custom wmEvent data ************** */ @@ -527,17 +529,17 @@ typedef enum { /* Timer flags */ typedef struct wmTimer { struct wmTimer *next, *prev; - + struct wmWindow *win; /* window this timer is attached to (optional) */ double timestep; /* set by timer user */ int event_type; /* set by timer user, goes to event system */ wmTimerFlags flags; /* Various flags controlling timer options, see below. */ void *customdata; /* set by timer user, to allow custom values */ - + double duration; /* total running time in seconds */ double delta; /* time since previous step in seconds */ - + double ltime; /* internal, last time timer was activated */ double ntime; /* internal, next time we want to activate the timer */ double stime; /* internal, when the timer started */ @@ -653,16 +655,16 @@ typedef enum wmDragFlags { typedef struct wmDrag { struct wmDrag *next, *prev; - + int icon, type; /* type, see WM_DRAG defines above */ void *poin; char path[1024]; /* FILE_MAX */ double value; - + struct ImBuf *imb; /* if no icon but imbuf should be drawn around cursor */ float scale; int sx, sy; - + char opname[200]; /* if set, draws operator name*/ unsigned int flags; } wmDrag; @@ -671,13 +673,13 @@ typedef struct wmDrag { /* allocation and free is on startup and exit */ typedef struct wmDropBox { struct wmDropBox *next, *prev; - + /* test if the dropbox is active, then can print optype name */ int (*poll)(struct bContext *, struct wmDrag *, const wmEvent *); /* before exec, this copies drag info to wmDrop properties */ void (*copy)(struct wmDrag *, struct wmDropBox *); - + /* if poll survives, operator is called */ wmOperatorType *ot; /* not saved in file, so can be pointer */ diff --git a/source/blender/windowmanager/intern/wm.c b/source/blender/windowmanager/intern/wm.c index b6a12acd57d..6a42bf26a97 100644 --- a/source/blender/windowmanager/intern/wm.c +++ b/source/blender/windowmanager/intern/wm.c @@ -106,7 +106,7 @@ void WM_operator_free(wmOperator *op) WM_operator_free(opm); } } - + MEM_freeN(op); } @@ -192,11 +192,11 @@ void wm_operator_register(bContext *C, wmOperator *op) void WM_operator_stack_clear(wmWindowManager *wm) { wmOperator *op; - + while ((op = BLI_pophead(&wm->operators))) { WM_operator_free(op); } - + WM_main_add_notifier(NC_WM | ND_HISTORY, NULL); } @@ -372,7 +372,7 @@ void WM_keymap_init(bContext *C) wm->addonconf = WM_keyconfig_new(wm, "Blender Addon"); if (!wm->userconf) wm->userconf = WM_keyconfig_new(wm, "Blender User"); - + /* initialize only after python init is done, for keymaps that * use python operators */ if (CTX_py_init_get(C) && (wm->initialized & WM_KEYMAP_IS_INITIALIZED) == 0) { @@ -394,8 +394,9 @@ void WM_keymap_init(bContext *C) void WM_check(bContext *C) { + Main *bmain = CTX_data_main(C); wmWindowManager *wm = CTX_wm_manager(C); - + /* wm context */ if (wm == NULL) { wm = CTX_data_main(C)->wm.first; @@ -424,7 +425,7 @@ void WM_check(bContext *C) /* case: fileread */ /* note: this runs in bg mode to set the screen context cb */ if ((wm->initialized & WM_WINDOW_IS_INITIALIZED) == 0) { - ED_screens_initialize(wm); + ED_screens_initialize(bmain, wm); wm->initialized |= WM_WINDOW_IS_INITIALIZED; } } @@ -433,7 +434,7 @@ void wm_clear_default_size(bContext *C) { wmWindowManager *wm = CTX_wm_manager(C); wmWindow *win; - + /* wm context */ if (wm == NULL) { wm = CTX_data_main(C)->wm.first; @@ -443,7 +444,7 @@ void wm_clear_default_size(bContext *C) if (wm == NULL || BLI_listbase_is_empty(&wm->windows)) { return; } - + for (win = wm->windows.first; win; win = win->next) { win->sizex = 0; win->sizey = 0; @@ -489,7 +490,7 @@ void wm_close_and_free(bContext *C, wmWindowManager *wm) WM_window_set_active_workspace(win, NULL); /* prevent draw clear to use screen */ wm_window_free(C, wm, win); } - + while ((op = BLI_pophead(&wm->operators))) { WM_operator_free(op); } @@ -507,7 +508,7 @@ void wm_close_and_free(bContext *C, wmWindowManager *wm) BLI_freelistN(&wm->paintcursors); WM_drag_free_list(&wm->drags); - + wm_reports_free(wm); if (wm->undo_stack) { @@ -537,16 +538,16 @@ void WM_main(bContext *C) wm_event_do_refresh_wm_and_depsgraph(C); while (1) { - + /* get events from ghost, handle window events, add to window queues */ - wm_window_process_events(C); - + wm_window_process_events(C); + /* per window, all events to the window, screen, area and region handlers */ wm_event_do_handlers(C); - + /* events have left notes about changes, we handle and cache it */ wm_event_do_notifiers(C); - + /* execute cached changes draw */ wm_draw_update(C); } diff --git a/source/blender/windowmanager/intern/wm_cursors.c b/source/blender/windowmanager/intern/wm_cursors.c index 67b04662154..f13dac9cb4c 100644 --- a/source/blender/windowmanager/intern/wm_cursors.c +++ b/source/blender/windowmanager/intern/wm_cursors.c @@ -41,7 +41,7 @@ #include "BLI_sys_types.h" #include "DNA_listBase.h" -#include "DNA_userdef_types.h" +#include "DNA_userdef_types.h" #include "DNA_workspace_types.h" #include "BKE_context.h" @@ -58,7 +58,7 @@ /* Some simple ghost <-> blender conversions */ -static GHOST_TStandardCursor convert_cursor(int curs) +static GHOST_TStandardCursor convert_cursor(int curs) { switch (curs) { default: @@ -79,23 +79,23 @@ static GHOST_TStandardCursor convert_cursor(int curs) } } -static void window_set_custom_cursor(wmWindow *win, unsigned char mask[16][2], +static void window_set_custom_cursor(wmWindow *win, unsigned char mask[16][2], unsigned char bitmap[16][2], int hotx, int hoty) { GHOST_SetCustomCursorShape(win->ghostwin, bitmap, mask, hotx, hoty); } -static void window_set_custom_cursor_ex(wmWindow *win, BCursor *cursor, int useBig) +static void window_set_custom_cursor_ex(wmWindow *win, BCursor *cursor, int useBig) { if (useBig) { - GHOST_SetCustomCursorShapeEx(win->ghostwin, + GHOST_SetCustomCursorShapeEx(win->ghostwin, (GHOST_TUns8 *)cursor->big_bm, (GHOST_TUns8 *)cursor->big_mask, cursor->big_sizex, cursor->big_sizey, cursor->big_hotx, cursor->big_hoty, cursor->fg_color, cursor->bg_color); } else { - GHOST_SetCustomCursorShapeEx(win->ghostwin, + GHOST_SetCustomCursorShapeEx(win->ghostwin, (GHOST_TUns8 *)cursor->small_bm, (GHOST_TUns8 *)cursor->small_mask, cursor->small_sizex, cursor->small_sizey, cursor->small_hotx, cursor->small_hoty, @@ -132,12 +132,12 @@ void WM_cursor_set(wmWindow *win, int curs) #endif GHOST_SetCursorVisibility(win->ghostwin, 1); - + if (curs == CURSOR_STD && win->modalcursor) curs = win->modalcursor; - + win->cursor = curs; - + /* detect if we use system cursor or Blender cursor */ if (curs >= BC_GHOST_CURSORS) { GHOST_SetCursorShape(win->ghostwin, convert_cursor(curs)); @@ -196,7 +196,7 @@ void WM_cursor_wait(bool val) if (!G.background) { wmWindowManager *wm = G.main->wm.first; wmWindow *win = wm ? wm->windows.first : NULL; - + for (; win; win = win->next) { if (val) { WM_cursor_modal_set(win, BC_WAITCURSOR); @@ -214,7 +214,7 @@ void WM_cursor_wait(bool val) void WM_cursor_grab_enable(wmWindow *win, bool wrap, bool hide, int bounds[4]) { /* Only grab cursor when not running debug. - * It helps not to get a stuck WM when hitting a breakpoint + * It helps not to get a stuck WM when hitting a breakpoint * */ GHOST_TGrabCursorMode mode = GHOST_kGrabNormal; @@ -222,7 +222,7 @@ void WM_cursor_grab_enable(wmWindow *win, bool wrap, bool hide, int bounds[4]) wm_cursor_position_to_ghost(win, &bounds[0], &bounds[1]); wm_cursor_position_to_ghost(win, &bounds[2], &bounds[3]); } - + if (hide) { mode = GHOST_kGrabHide; } @@ -311,12 +311,12 @@ void WM_cursor_time(wmWindow *win, int nr) unsigned char mask[16][2]; unsigned char bitmap[16][2] = {{0}}; int i, idx; - + if (win->lastcursor == 0) win->lastcursor = win->cursor; - + memset(&mask, 0xFF, sizeof(mask)); - + /* print number bottom right justified */ for (idx = 3; nr && idx >= 0; idx--) { const char *digit = number_bitmaps[nr % 10]; @@ -327,7 +327,7 @@ void WM_cursor_time(wmWindow *win, int nr) bitmap[i + y * 8][x] = digit[i]; nr /= 10; } - + window_set_custom_cursor(win, mask, bitmap, 7, 7); } @@ -441,7 +441,7 @@ BEGIN_CURSOR_BLOCK }; BlenderCursor[BC_NS_ARROWCURSOR] = &NSArrowCursor; - + END_CURSOR_BLOCK /********************** EW_ARROW Cursor *************************/ BEGIN_CURSOR_BLOCK @@ -462,7 +462,7 @@ BEGIN_CURSOR_BLOCK static BCursor EWArrowCursor = { /*small*/ ew_sbm, ew_smsk, - 16, 16, + 16, 16, 7, 6, /*big*/ NULL, NULL, @@ -532,7 +532,7 @@ BEGIN_CURSOR_BLOCK static BCursor WaitCursor = { /*small*/ wait_sbm, wait_smsk, - 16, 16, + 16, 16, 7, 7, /*big*/ wait_lbm, wait_lmsk, @@ -601,7 +601,7 @@ BEGIN_CURSOR_BLOCK static BCursor CrossCursor = { /*small*/ cross_sbm, cross_smsk, - 16, 16, + 16, 16, 7, 7, /*big*/ cross_lbm, cross_lmsk, @@ -633,7 +633,7 @@ BEGIN_CURSOR_BLOCK static BCursor EditCrossCursor = { /*small*/ editcross_sbm, editcross_smsk, - 16, 16, + 16, 16, 9, 8, /*big*/ NULL, NULL, @@ -666,7 +666,7 @@ BEGIN_CURSOR_BLOCK static BCursor BoxSelCursor = { /*small*/ box_sbm, box_smsk, - 16, 16, + 16, 16, 9, 8, /*big*/ NULL, NULL, @@ -738,7 +738,7 @@ BEGIN_CURSOR_BLOCK static BCursor KnifeCursor = { /*small*/ knife_sbm, knife_smsk, - 16, 16, + 16, 16, 0, 15, /*big*/ knife_lbm, knife_lmsk, @@ -751,7 +751,7 @@ BEGIN_CURSOR_BLOCK BlenderCursor[BC_KNIFECURSOR] = &KnifeCursor; END_CURSOR_BLOCK - + /********************** Loop Select Cursor ***********************/ BEGIN_CURSOR_BLOCK @@ -814,7 +814,7 @@ BEGIN_CURSOR_BLOCK static BCursor VLoopCursor = { /*small*/ vloop_sbm, vloop_smsk, - 16, 16, + 16, 16, 0, 0, /*big*/ vloop_lbm, vloop_lmsk, @@ -827,7 +827,7 @@ BEGIN_CURSOR_BLOCK BlenderCursor[BC_VLOOPCURSOR] = &VLoopCursor; END_CURSOR_BLOCK - + /********************** TextEdit Cursor ***********************/ BEGIN_CURSOR_BLOCK @@ -848,7 +848,7 @@ BEGIN_CURSOR_BLOCK static BCursor TextEditCursor = { /*small*/ textedit_sbm, textedit_smsk, - 16, 16, + 16, 16, 9, 8, /*big*/ NULL, NULL, @@ -887,7 +887,7 @@ BEGIN_CURSOR_BLOCK static BCursor PaintBrushCursor = { /*small*/ paintbrush_sbm, paintbrush_smsk, - 16, 16, + 16, 16, 0, 15, /*big*/ NULL, NULL, @@ -1060,7 +1060,7 @@ BEGIN_CURSOR_BLOCK 0x7e, 0x00, 0x3f, 0x00, 0x0c, 0x00, 0x04, 0x00, }; - + static BCursor EyedropperCursor = { /*small*/ eyedropper_sbm, eyedropper_smsk, diff --git a/source/blender/windowmanager/intern/wm_dragdrop.c b/source/blender/windowmanager/intern/wm_dragdrop.c index 319ce99f700..16ed51cbd80 100644 --- a/source/blender/windowmanager/intern/wm_dragdrop.c +++ b/source/blender/windowmanager/intern/wm_dragdrop.c @@ -69,29 +69,29 @@ static ListBase dropboxes = {NULL, NULL}; typedef struct wmDropBoxMap { struct wmDropBoxMap *next, *prev; - + ListBase dropboxes; short spaceid, regionid; char idname[KMAP_MAX_NAME]; - + } wmDropBoxMap; /* spaceid/regionid is zero for window drop maps */ ListBase *WM_dropboxmap_find(const char *idname, int spaceid, int regionid) { wmDropBoxMap *dm; - + for (dm = dropboxes.first; dm; dm = dm->next) if (dm->spaceid == spaceid && dm->regionid == regionid) if (STREQLEN(idname, dm->idname, KMAP_MAX_NAME)) return &dm->dropboxes; - + dm = MEM_callocN(sizeof(struct wmDropBoxMap), "dropmap list"); BLI_strncpy(dm->idname, idname, KMAP_MAX_NAME); dm->spaceid = spaceid; dm->regionid = regionid; BLI_addtail(&dropboxes, dm); - + return &dm->dropboxes; } @@ -101,31 +101,31 @@ wmDropBox *WM_dropbox_add(ListBase *lb, const char *idname, int (*poll)(bContext void (*copy)(wmDrag *, wmDropBox *)) { wmDropBox *drop = MEM_callocN(sizeof(wmDropBox), "wmDropBox"); - + drop->poll = poll; drop->copy = copy; drop->ot = WM_operatortype_find(idname, 0); drop->opcontext = WM_OP_INVOKE_DEFAULT; - + if (drop->ot == NULL) { MEM_freeN(drop); printf("Error: dropbox with unknown operator: %s\n", idname); return NULL; } WM_operator_properties_alloc(&(drop->ptr), &(drop->properties), idname); - + BLI_addtail(lb, drop); - + return drop; } void wm_dropbox_free(void) { wmDropBoxMap *dm; - + for (dm = dropboxes.first; dm; dm = dm->next) { wmDropBox *drop; - + for (drop = dm->dropboxes.first; drop; drop = drop->next) { if (drop->ptr) { WM_operator_properties_free(drop->ptr); @@ -134,7 +134,7 @@ void wm_dropbox_free(void) } BLI_freelistN(&dm->dropboxes); } - + BLI_freelistN(&dropboxes); } @@ -145,10 +145,10 @@ wmDrag *WM_event_start_drag(struct bContext *C, int icon, int type, void *poin, { wmWindowManager *wm = CTX_wm_manager(C); wmDrag *drag = MEM_callocN(sizeof(struct wmDrag), "new drag"); - + /* keep track of future multitouch drag too, add a mousepointer id or so */ /* if multiple drags are added, they're drawn as list */ - + BLI_addtail(&wm->drags, drag); drag->flags = flags; drag->icon = icon; @@ -158,7 +158,7 @@ wmDrag *WM_event_start_drag(struct bContext *C, int icon, int type, void *poin, else drag->poin = poin; drag->value = value; - + return drag; } @@ -211,13 +211,13 @@ static const char *wm_dropbox_active(bContext *C, wmDrag *drag, const wmEvent *e ScrArea *sa = CTX_wm_area(C); ARegion *ar = CTX_wm_region(C); const char *name; - + name = dropbox_active(C, &win->handlers, drag, event); if (name) return name; - + name = dropbox_active(C, &sa->handlers, drag, event); if (name) return name; - + name = dropbox_active(C, &ar->handlers, drag, event); if (name) return name; @@ -234,16 +234,16 @@ static void wm_drop_operator_options(bContext *C, wmDrag *drag, const wmEvent *e /* for multiwin drags, we only do this if mouse inside */ if (event->x < 0 || event->y < 0 || event->x > winsize_x || event->y > winsize_y) return; - + drag->opname[0] = 0; - + /* check buttons (XXX todo rna and value) */ if (UI_but_active_drop_name(C)) { BLI_strncpy(drag->opname, IFACE_("Paste name"), sizeof(drag->opname)); } else { const char *opname = wm_dropbox_active(C, drag, event); - + if (opname) { BLI_strncpy(drag->opname, opname, sizeof(drag->opname)); // WM_cursor_modal_set(win, CURSOR_COPY); @@ -259,7 +259,7 @@ void wm_drags_check_ops(bContext *C, const wmEvent *event) { wmWindowManager *wm = CTX_wm_manager(C); wmDrag *drag; - + for (drag = wm->drags.first; drag; drag = drag->next) { wm_drop_operator_options(C, drag, event); } @@ -312,25 +312,25 @@ void wm_drags_draw(bContext *C, wmWindow *win, rcti *rect) wmDrag *drag; const int winsize_y = WM_window_pixels_y(win); int cursorx, cursory, x, y; - + cursorx = win->eventstate->x; cursory = win->eventstate->y; if (rect) { rect->xmin = rect->xmax = cursorx; rect->ymin = rect->ymax = cursory; } - + /* XXX todo, multiline drag draws... but maybe not, more types mixed wont work well */ glEnable(GL_BLEND); for (drag = wm->drags.first; drag; drag = drag->next) { int iconsize = UI_DPI_ICON_SIZE; int padding = 4 * UI_DPI_FAC; - + /* image or icon */ if (drag->imb) { x = cursorx - drag->sx / 2; y = cursory - drag->sy / 2; - + if (rect) drag_rect_minmax(rect, x, y, x + drag->sx, y + drag->sy); else { @@ -343,13 +343,13 @@ void wm_drags_draw(bContext *C, wmWindow *win, rcti *rect) else { x = cursorx - 2 * padding; y = cursory - 2 * UI_DPI_FAC; - + if (rect) drag_rect_minmax(rect, x, y, x + iconsize, y + iconsize); else UI_icon_draw_aspect(x, y, drag->icon, 1.0f / UI_DPI_FAC, 0.8); } - + /* item name */ if (drag->imb) { x = cursorx - drag->sx / 2; @@ -359,7 +359,7 @@ void wm_drags_draw(bContext *C, wmWindow *win, rcti *rect) x = cursorx + 10 * UI_DPI_FAC; y = cursory + 1 * UI_DPI_FAC; } - + if (rect) { int w = UI_fontstyle_string_width(fstyle, wm_drag_name(drag)); drag_rect_minmax(rect, x, y, x + w, y + iconsize); @@ -368,7 +368,7 @@ void wm_drags_draw(bContext *C, wmWindow *win, rcti *rect) const unsigned char col[] = {255, 255, 255, 255}; UI_fontstyle_draw_simple(fstyle, x, y, wm_drag_name(drag), col); } - + /* operator name with roundbox */ if (drag->opname[0]) { if (drag->imb) { @@ -389,14 +389,14 @@ void wm_drags_draw(bContext *C, wmWindow *win, rcti *rect) y = (cursory - iconsize) - padding; } } - + if (rect) { int w = UI_fontstyle_string_width(fstyle, wm_drag_name(drag)); drag_rect_minmax(rect, x, y, x + w, y + iconsize); } - else + else wm_drop_operator_draw(drag->opname, x, y); - + } } glDisable(GL_BLEND); diff --git a/source/blender/windowmanager/intern/wm_draw.c b/source/blender/windowmanager/intern/wm_draw.c index 3ce64926a95..df958f35e91 100644 --- a/source/blender/windowmanager/intern/wm_draw.c +++ b/source/blender/windowmanager/intern/wm_draw.c @@ -755,7 +755,7 @@ static bool wm_draw_update_test_window(wmWindow *win) if (do_draw) return true; - + if (screen->do_refresh) return true; if (screen->do_draw) @@ -766,7 +766,7 @@ static bool wm_draw_update_test_window(wmWindow *win) return true; if (screen->do_draw_drag) return true; - + return false; } @@ -788,7 +788,7 @@ void wm_draw_update(bContext *C) #endif GPU_free_unused_buffers(); - + for (win = wm->windows.first; win; win = win->next) { #ifdef WIN32 GHOST_TWindowState state = GHOST_GetWindowState(win->ghostwin); @@ -806,7 +806,7 @@ void wm_draw_update(bContext *C) bScreen *screen = WM_window_get_active_screen(win); CTX_wm_window_set(C, win); - + /* sets context window+screen */ wm_window_make_drawable(wm, win); @@ -818,7 +818,7 @@ void wm_draw_update(bContext *C) screen->do_draw_gesture = false; screen->do_draw_paintcursor = false; screen->do_draw_drag = false; - + wm_window_swap_buffers(win); CTX_wm_window_set(C, NULL); diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index 31b51fce858..1e3a08bdcbc 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -105,7 +105,7 @@ static int wm_operator_call_internal(bContext *C, wmOperatorType *ot, PointerRNA wmEvent *wm_event_add_ex(wmWindow *win, const wmEvent *event_to_add, const wmEvent *event_to_add_after) { wmEvent *event = MEM_mallocN(sizeof(wmEvent), "wmEvent"); - + *event = *event_to_add; update_tablet_data(win, event); @@ -157,7 +157,7 @@ void wm_event_free(wmEvent *event) void wm_event_free_all(wmWindow *win) { wmEvent *event; - + while ((event = BLI_pophead(&win->queue))) { wm_event_free(event); } @@ -180,7 +180,7 @@ static bool wm_test_duplicate_notifier(wmWindowManager *wm, unsigned int type, v for (note = wm->queue.first; note; note = note->next) if ((note->category | note->data | note->subtype | note->action) == type && note->reference == reference) return 1; - + return 0; } @@ -194,17 +194,17 @@ void WM_event_add_notifier(const bContext *C, unsigned int type, void *reference return; note = MEM_callocN(sizeof(wmNotifier), "notifier"); - + note->wm = wm; BLI_addtail(¬e->wm->queue, note); - + note->window = CTX_wm_window(C); - + note->category = type & NOTE_CATEGORY; note->data = type & NOTE_DATA; note->subtype = type & NOTE_SUBTYPE; note->action = type & NOTE_ACTION; - + note->reference = reference; } @@ -218,15 +218,15 @@ void WM_main_add_notifier(unsigned int type, void *reference) return; note = MEM_callocN(sizeof(wmNotifier), "notifier"); - + note->wm = wm; BLI_addtail(¬e->wm->queue, note); - + note->category = type & NOTE_CATEGORY; note->data = type & NOTE_DATA; note->subtype = type & NOTE_SUBTYPE; note->action = type & NOTE_ACTION; - + note->reference = reference; } @@ -353,7 +353,7 @@ void wm_event_do_notifiers(bContext *C) wmWindowManager *wm = CTX_wm_manager(C); wmNotifier *note, *next; wmWindow *win; - + if (wm == NULL) return; @@ -363,9 +363,9 @@ void wm_event_do_notifiers(bContext *C) for (win = wm->windows.first; win; win = win->next) { Scene *scene = WM_window_get_active_scene(win); bool do_anim = false; - + CTX_wm_window_set(C, win); - + for (note = wm->queue.first; note; note = next) { next = note->next; @@ -443,7 +443,7 @@ void wm_event_do_notifiers(bContext *C) } } } - + /* the notifiers are sent without context, to keep it clean */ while ((note = BLI_pophead(&wm->queue))) { for (win = wm->windows.first; win; win = win->next) { @@ -484,7 +484,7 @@ void wm_event_do_notifiers(bContext *C) } } } - + MEM_freeN(note); } #endif /* if 1 (postpone disabling for in favor of message-bus), eventually. */ @@ -517,8 +517,8 @@ static int wm_handler_ui_call(bContext *C, wmEventHandler *handler, const wmEven static bool do_wheel_ui = true; const bool is_wheel = ELEM(event->type, WHEELUPMOUSE, WHEELDOWNMOUSE, MOUSEPAN); int retval; - - /* UI code doesn't handle return values - it just always returns break. + + /* UI code doesn't handle return values - it just always returns break. * to make the DBL_CLICK conversion work, we just don't send this to UI, except mouse clicks */ if (((handler->flag & WM_HANDLER_ACCEPT_DBL_CLICK) == 0) && (event->type != LEFTMOUSE) && @@ -526,7 +526,7 @@ static int wm_handler_ui_call(bContext *C, wmEventHandler *handler, const wmEven { return WM_HANDLER_CONTINUE; } - + /* UI is quite aggressive with swallowing events, like scrollwheel */ /* I realize this is not extremely nice code... when UI gets keymaps it can be maybe smarter */ if (do_wheel_ui == false) { @@ -535,7 +535,7 @@ static int wm_handler_ui_call(bContext *C, wmEventHandler *handler, const wmEven else if (wm_event_always_pass(event) == 0) do_wheel_ui = true; } - + /* we set context to where ui handler came from */ if (handler->ui_area) CTX_wm_area_set(C, handler->ui_area); if (handler->ui_region) CTX_wm_region_set(C, handler->ui_region); @@ -555,14 +555,14 @@ static int wm_handler_ui_call(bContext *C, wmEventHandler *handler, const wmEven CTX_wm_region_set(C, NULL); CTX_wm_menu_set(C, NULL); } - + if (retval == WM_UI_HANDLER_BREAK) return WM_HANDLER_BREAK; - + /* event not handled in UI, if wheel then we temporarily disable it */ if (is_wheel) do_wheel_ui = false; - + return WM_HANDLER_CONTINUE; } @@ -593,14 +593,14 @@ static void wm_handler_ui_cancel(bContext *C) int WM_operator_poll(bContext *C, wmOperatorType *ot) { wmOperatorTypeMacro *otmacro; - + for (otmacro = ot->macro.first; otmacro; otmacro = otmacro->next) { wmOperatorType *ot_macro = WM_operatortype_find(otmacro->idname, 0); - + if (0 == WM_operator_poll(C, ot_macro)) return 0; } - + /* python needs operator type, so we added exception for it */ if (ot->pyop_poll) return ot->pyop_poll(C, ot); @@ -807,7 +807,7 @@ static void wm_operator_reports(bContext *C, wmOperator *op, int retval, bool ca CTX_wm_region_set(C, ar_prev); } } - + if (retval & OPERATOR_FINISHED) { CLOG_STR_INFO_N(WM_LOG_OPERATORS, 1, WM_operator_pystring(C, op, false, true)); @@ -885,15 +885,15 @@ static int wm_operator_exec(bContext *C, wmOperator *op, const bool repeat, cons { wmWindowManager *wm = CTX_wm_manager(C); int retval = OPERATOR_CANCELLED; - + CTX_wm_operator_poll_msg_set(C, NULL); - + if (op == NULL || op->type == NULL) return retval; - + if (0 == WM_operator_poll(C, op->type)) return retval; - + if (op->type->exec) { if (op->type->flag & OPTYPE_UNDO) { wm->op_undo_depth++; @@ -912,13 +912,13 @@ static int wm_operator_exec(bContext *C, wmOperator *op, const bool repeat, cons wm->op_undo_depth--; } } - + /* XXX Disabled the repeat check to address part 2 of #31840. * Carefully checked all calls to wm_operator_exec and WM_operator_repeat, don't see any reason * why this was needed, but worth to note it in case something turns bad. (mont29) */ if (retval & (OPERATOR_FINISHED | OPERATOR_CANCELLED) /* && repeat == 0 */) wm_operator_reports(C, op, retval, false); - + if (retval & OPERATOR_FINISHED) { wm_operator_finished(C, op, repeat, store && wm->op_undo_depth == 0); } @@ -928,9 +928,9 @@ static int wm_operator_exec(bContext *C, wmOperator *op, const bool repeat, cons WM_operator_free(op); } } - + return retval | OPERATOR_HANDLED; - + } /* simply calls exec with basic checks */ @@ -1033,11 +1033,11 @@ static wmOperator *wm_operator_create(wmWindowManager *wm, wmOperatorType *ot, { /* XXX operatortype names are static still. for debug */ wmOperator *op = MEM_callocN(sizeof(wmOperator), ot->idname); - + /* XXX adding new operator could be function, only happens here now */ op->type = ot; BLI_strncpy(op->idname, ot->idname, OP_MAX_TYPENAME); - + /* initialize properties, either copy or create */ op->ptr = MEM_callocN(sizeof(PointerRNA), "wmOperatorPtrRNA"); if (properties && properties->data) { @@ -1057,20 +1057,20 @@ static wmOperator *wm_operator_create(wmWindowManager *wm, wmOperatorType *ot, op->reports = MEM_mallocN(sizeof(ReportList), "wmOperatorReportList"); BKE_reports_init(op->reports, RPT_STORE | RPT_FREE); } - + /* recursive filling of operator macro list */ if (ot->macro.first) { static wmOperator *motherop = NULL; wmOperatorTypeMacro *otmacro; int root = 0; - + /* ensure all ops are in execution order in 1 list */ if (motherop == NULL) { motherop = op; root = 1; } - + /* if properties exist, it will contain everything needed */ if (properties) { otmacro = ot->macro.first; @@ -1106,11 +1106,11 @@ static wmOperator *wm_operator_create(wmWindowManager *wm, wmOperatorType *ot, opm->opm = motherop; /* pointer to mom, for modal() */ } } - + if (root) motherop = NULL; } - + WM_operator_properties_sanitize(op->ptr, 0); return op; @@ -1250,7 +1250,7 @@ static int wm_operator_invoke( wmWindowManager *wm = CTX_wm_manager(C); wmOperator *op = wm_operator_create(wm, ot, properties, reports); /* if reports == NULL, they'll be initialized */ const bool is_nested_call = (wm->op_undo_depth != 0); - + if (event != NULL) { op->flag |= OP_IS_INVOKE; } @@ -1388,7 +1388,7 @@ static int wm_operator_call_internal( const short context, const bool poll_only) { wmEvent *event; - + int retval; CTX_wm_operator_poll_msg_set(C, NULL); @@ -1421,39 +1421,39 @@ static int wm_operator_call_internal( } switch (context) { - + case WM_OP_EXEC_REGION_WIN: - case WM_OP_INVOKE_REGION_WIN: + case WM_OP_INVOKE_REGION_WIN: case WM_OP_EXEC_REGION_CHANNELS: case WM_OP_INVOKE_REGION_CHANNELS: case WM_OP_EXEC_REGION_PREVIEW: case WM_OP_INVOKE_REGION_PREVIEW: { /* forces operator to go to the region window/channels/preview, for header menus - * but we stay in the same region if we are already in one + * but we stay in the same region if we are already in one */ ARegion *ar = CTX_wm_region(C); ScrArea *area = CTX_wm_area(C); int type = RGN_TYPE_WINDOW; - + switch (context) { case WM_OP_EXEC_REGION_CHANNELS: case WM_OP_INVOKE_REGION_CHANNELS: type = RGN_TYPE_CHANNELS; break; - + case WM_OP_EXEC_REGION_PREVIEW: case WM_OP_INVOKE_REGION_PREVIEW: type = RGN_TYPE_PREVIEW; break; - + case WM_OP_EXEC_REGION_WIN: - case WM_OP_INVOKE_REGION_WIN: + case WM_OP_INVOKE_REGION_WIN: default: type = RGN_TYPE_WINDOW; break; } - + if (!(ar && ar->regiontype == type) && area) { ARegion *ar1; if (type == RGN_TYPE_WINDOW) { @@ -1466,12 +1466,12 @@ static int wm_operator_call_internal( if (ar1) CTX_wm_region_set(C, ar1); } - + retval = wm_operator_invoke(C, ot, event, properties, reports, poll_only, true); - + /* set region back */ CTX_wm_region_set(C, ar); - + return retval; } case WM_OP_EXEC_AREA: @@ -1506,7 +1506,7 @@ static int wm_operator_call_internal( return wm_operator_invoke(C, ot, event, properties, reports, poll_only, true); } } - + return 0; } @@ -1582,7 +1582,7 @@ int WM_operator_call_py( if (!is_undo && wm) wm->op_undo_depth++; retval = wm_operator_call_internal(C, ot, properties, reports, context, false); - + if (!is_undo && wm && (wm == CTX_wm_manager(C))) wm->op_undo_depth--; return retval; @@ -1602,7 +1602,7 @@ static void wm_handler_op_context(bContext *C, wmEventHandler *handler, const wm { wmWindow *win = CTX_wm_window(C); bScreen *screen = CTX_wm_screen(C); - + if (screen && handler->op) { if (handler->op_area == NULL) CTX_wm_area_set(C, NULL); @@ -1659,7 +1659,7 @@ void WM_event_remove_handlers(bContext *C, ListBase *handlers) { wmEventHandler *handler; wmWindowManager *wm = CTX_wm_manager(C); - + /* C is zero on freeing database, modal handlers then already were freed */ while ((handler = BLI_pophead(handlers))) { if (handler->op) { @@ -1667,7 +1667,7 @@ void WM_event_remove_handlers(bContext *C, ListBase *handlers) if (handler->op->type->cancel) { ScrArea *area = CTX_wm_area(C); ARegion *region = CTX_wm_region(C); - + wm_handler_op_context(C, handler, win->eventstate); if (handler->op->type->flag & OPTYPE_UNDO) @@ -1689,7 +1689,7 @@ void WM_event_remove_handlers(bContext *C, ListBase *handlers) ScrArea *area = CTX_wm_area(C); ARegion *region = CTX_wm_region(C); ARegion *menu = CTX_wm_menu(C); - + if (handler->ui_area) CTX_wm_area_set(C, handler->ui_area); if (handler->ui_region) CTX_wm_region_set(C, handler->ui_region); if (handler->ui_menu) CTX_wm_menu_set(C, handler->ui_menu); @@ -1722,7 +1722,7 @@ int WM_userdef_event_map(int kmitype) case WHEELINMOUSE: return (U.uiflag & USER_WHEELZOOMDIR) ? WHEELDOWNMOUSE : WHEELUPMOUSE; } - + return kmitype; } @@ -1768,13 +1768,13 @@ static int wm_eventmatch(const wmEvent *winevent, wmKeyMapItem *kmi) if (winevent->val == KM_PRESS) { /* prevent double clicks */ /* NOT using ISTEXTINPUT anymore because (at least on Windows) some key codes above 255 * could have printable ascii keys - BUG [#30479] */ - if (ISKEYBOARD(winevent->type) && (winevent->ascii || winevent->utf8_buf[0])) return 1; + if (ISKEYBOARD(winevent->type) && (winevent->ascii || winevent->utf8_buf[0])) return 1; } if (kmitype != KM_ANY) { if (ELEM(kmitype, TABLET_STYLUS, TABLET_ERASER)) { const wmTabletData *wmtab = winevent->tablet_data; - + if (wmtab == NULL) return 0; else if (winevent->type != LEFTMOUSE) /* tablet events can occur on hover + keypress */ @@ -1789,10 +1789,10 @@ static int wm_eventmatch(const wmEvent *winevent, wmKeyMapItem *kmi) return 0; } } - + if (kmi->val != KM_ANY) if (winevent->val != kmi->val) return 0; - + /* modifiers also check bits, so it allows modifier order */ if (kmi->shift != KM_ANY) if (winevent->shift != kmi->shift && !(winevent->shift & kmi->shift)) return 0; @@ -1802,12 +1802,12 @@ static int wm_eventmatch(const wmEvent *winevent, wmKeyMapItem *kmi) if (winevent->alt != kmi->alt && !(winevent->alt & kmi->alt)) return 0; if (kmi->oskey != KM_ANY) if (winevent->oskey != kmi->oskey && !(winevent->oskey & kmi->oskey)) return 0; - + /* only keymap entry with keymodifier is checked, means all keys without modifier get handled too. */ /* that is currently needed to make overlapping events work (when you press A - G fast or so). */ if (kmi->keymodifier) if (winevent->keymodifier != kmi->keymodifier) return 0; - + return 1; } @@ -1825,12 +1825,12 @@ static void wm_event_modalkeymap(const bContext *C, wmOperator *op, wmEvent *eve for (kmi = keymap->items.first; kmi; kmi = kmi->next) { if (wm_eventmatch(event, kmi)) { - + event->prevtype = event->type; event->prevval = event->val; event->type = EVT_MODAL_MAP; event->val = kmi->propvalue; - + break; } } @@ -1883,7 +1883,7 @@ static int wm_handler_operator_call(bContext *C, ListBase *handlers, wmEventHand wmEvent *event, PointerRNA *properties) { int retval = OPERATOR_PASS_THROUGH; - + /* derived, modal or blocking operator */ if (handler->op) { wmOperator *op = handler->op; @@ -1911,7 +1911,7 @@ static int wm_handler_operator_call(bContext *C, ListBase *handlers, wmEventHand /* warning, after this call all context data and 'event' may be freed. see check below */ retval = ot->modal(C, op, event); OPERATOR_RETVAL_CHECK(retval); - + /* when this is _not_ the case the modal modifier may have loaded * a new blend file (demo mode does this), so we have to assume * the event, operator etc have all been freed. - campbell */ @@ -1979,7 +1979,7 @@ static int wm_handler_operator_call(bContext *C, ListBase *handlers, wmEventHand bool use_last_properties = true; PointerRNA tool_properties = {{0}}; bool use_tool_properties = (handler->keymap_tool != NULL); - + if (use_tool_properties) { WM_toolsystem_ref_properties_init_for_keymap(handler->keymap_tool, &tool_properties, properties, ot); properties = &tool_properties; @@ -2058,11 +2058,11 @@ static int wm_handler_fileselect_do(bContext *C, ListBase *handlers, wmEventHand sfile->op = handler->op; ED_fileselect_set_params(sfile); - + action = WM_HANDLER_BREAK; break; } - + case EVT_FILESELECT_EXEC: case EVT_FILESELECT_CANCEL: case EVT_FILESELECT_EXTERNAL_CANCEL: @@ -2150,11 +2150,11 @@ static int wm_handler_fileselect_do(bContext *C, ListBase *handlers, wmEventHand wm->op_undo_depth++; handler->op->type->cancel(C, handler->op); - + if (handler->op->type->flag & OPTYPE_UNDO) wm->op_undo_depth--; } - + WM_operator_free(handler->op); } @@ -2166,19 +2166,19 @@ static int wm_handler_fileselect_do(bContext *C, ListBase *handlers, wmEventHand break; } } - + return action; } static int wm_handler_fileselect_call(bContext *C, ListBase *handlers, wmEventHandler *handler, const wmEvent *event) { int action = WM_HANDLER_CONTINUE; - + if (event->type != EVT_FILESELECT) return action; if (handler->op != (wmOperator *)event->customdata) return action; - + return wm_handler_fileselect_do(C, handlers, handler, event->val); } @@ -2239,7 +2239,7 @@ static int wm_handlers_do_intern(bContext *C, wmEvent *event, ListBase *handlers for (handler = handlers->first; handler && handlers->first; handler = nexthandler) { nexthandler = handler->next; - + /* during this loop, ui handlers for nested menus can tag multiple handlers free */ if (handler->flag & WM_HANDLER_DO_FREE) { /* pass */ @@ -2247,7 +2247,7 @@ static int wm_handlers_do_intern(bContext *C, wmEvent *event, ListBase *handlers else if (handler_boundbox_test(handler, event)) { /* optional boundbox */ /* in advance to avoid access to freed event on window close */ always_pass = wm_event_always_pass(event); - + /* modal+blocking handler */ if (handler->flag & WM_HANDLER_BLOCKING) action |= WM_HANDLER_BREAK; @@ -2272,7 +2272,7 @@ static int wm_handlers_do_intern(bContext *C, wmEvent *event, ListBase *handlers event->keymap_idname = kmi->idname; action |= wm_handler_operator_call(C, handlers, handler, event, kmi->ptr); - + if (action & WM_HANDLER_BREAK) { /* not always_pass here, it denotes removed handler */ CLOG_INFO(WM_LOG_HANDLERS, 2, "handled! '%s'", kmi->idname); @@ -2315,24 +2315,24 @@ static int wm_handlers_do_intern(bContext *C, wmEvent *event, ListBase *handlers if (event->custom == EVT_DATA_DRAGDROP) { ListBase *lb = (ListBase *)event->customdata; wmDrag *drag; - + for (drag = lb->first; drag; drag = drag->next) { if (drop->poll(C, drag, event)) { drop->copy(drag, drop); - + /* free the drags before calling operator */ WM_drag_free_list(lb); event->customdata = NULL; event->custom = 0; - + WM_operator_name_call_ptr(C, drop->ot, drop->opcontext, drop->ptr); action |= WM_HANDLER_BREAK; - + /* XXX fileread case */ if (CTX_wm_window(C) == NULL) return action; - + /* escape from drag loop, got freed */ break; } @@ -2491,7 +2491,7 @@ static int wm_handlers_do_intern(bContext *C, wmEvent *event, ListBase *handlers break; } } - + /* XXX fileread case, if the wm is freed then the handler's * will have been too so the code below need not run. */ if (CTX_wm_window(C) == NULL) { @@ -2499,8 +2499,8 @@ static int wm_handlers_do_intern(bContext *C, wmEvent *event, ListBase *handlers } /* XXX code this for all modal ops, and ensure free only happens here */ - - /* modal ui handler can be tagged to be freed */ + + /* modal ui handler can be tagged to be freed */ if (BLI_findindex(handlers, handler) != -1) { /* could be freed already by regular modal ops */ if (handler->flag & WM_HANDLER_DO_FREE) { BLI_remlink(handlers, handler); @@ -2521,26 +2521,56 @@ static int wm_handlers_do_intern(bContext *C, wmEvent *event, ListBase *handlers static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers) { int action = wm_handlers_do_intern(C, event, handlers); - + /* fileread case */ if (CTX_wm_window(C) == NULL) return action; - if (!ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE, EVENT_NONE) && !ISTIMER(event->type)) { + if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) { + if (event->check_drag) { + wmWindow *win = CTX_wm_window(C); + if ((abs(event->x - win->eventstate->prevclickx)) >= U.tweak_threshold || + (abs(event->y - win->eventstate->prevclicky)) >= U.tweak_threshold) + { + short val = event->val; + short type = event->type; + event->val = KM_CLICK_DRAG; + event->type = win->eventstate->type; + + CLOG_INFO(WM_LOG_HANDLERS, 1, "handling PRESS_DRAG"); + + action |= wm_handlers_do_intern(C, event, handlers); + + event->val = val; + event->type = type; + + win->eventstate->check_click = 0; + win->eventstate->check_drag = 0; + } + } + } + else if (ISMOUSE(event->type) || ISKEYBOARD(event->type)) { + /* All events that don't set wmEvent.prevtype must be ignored. */ /* test for CLICK events */ if (wm_action_not_handled(action)) { wmWindow *win = CTX_wm_window(C); - - /* eventstate stores if previous event was a KM_PRESS, in case that + + /* eventstate stores if previous event was a KM_PRESS, in case that * wasn't handled, the KM_RELEASE will become a KM_CLICK */ - - if (win && event->val == KM_PRESS) { - win->eventstate->check_click = true; + + if (win != NULL) { + if (event->val == KM_PRESS) { + win->eventstate->check_click = true; + win->eventstate->check_drag = true; + } + else if (event->val == KM_RELEASE) { + win->eventstate->check_drag = false; + } } - + if (win && win->eventstate->prevtype == event->type) { - + if ((event->val == KM_RELEASE) && (win->eventstate->prevval == KM_PRESS) && (win->eventstate->check_click == true)) @@ -2551,19 +2581,20 @@ static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers) event->val = KM_CLICK; CLOG_INFO(WM_LOG_HANDLERS, 1, "handling CLICK"); - + action |= wm_handlers_do_intern(C, event, handlers); event->val = KM_RELEASE; } else { win->eventstate->check_click = 0; + win->eventstate->check_drag = 0; } } else if (event->val == KM_DBL_CLICK) { event->val = KM_PRESS; action |= wm_handlers_do_intern(C, event, handlers); - + /* revert value if not handled */ if (wm_action_not_handled(action)) { event->val = KM_DBL_CLICK; @@ -2578,7 +2609,7 @@ static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers) win->eventstate->check_click = 0; } } - + return action; } @@ -2595,7 +2626,7 @@ static ScrArea *area_event_inside(bContext *C, const int xy[2]) { wmWindow *win = CTX_wm_window(C); bScreen *screen = CTX_wm_screen(C); - + if (screen) { ED_screen_areas_iter(win, screen, sa) { if (BLI_rcti_isect_pt_v(&sa->totrct, xy)) @@ -2610,7 +2641,7 @@ static ARegion *region_event_inside(bContext *C, const int xy[2]) bScreen *screen = CTX_wm_screen(C); ScrArea *area = CTX_wm_area(C); ARegion *ar; - + if (screen && area) for (ar = area->regionbase.first; ar; ar = ar->next) if (BLI_rcti_isect_pt_v(&ar->winrct, xy)) @@ -2635,22 +2666,22 @@ static void wm_paintcursor_tag(bContext *C, wmPaintCursor *pc, ARegion *ar) static void wm_paintcursor_test(bContext *C, const wmEvent *event) { wmWindowManager *wm = CTX_wm_manager(C); - + if (wm->paintcursors.first) { ARegion *ar = CTX_wm_region(C); - + if (ar) wm_paintcursor_tag(C, wm->paintcursors.first, ar); - + /* if previous position was not in current region, we have to set a temp new context */ if (ar == NULL || !BLI_rcti_isect_pt_v(&ar->winrct, &event->prevx)) { ScrArea *sa = CTX_wm_area(C); - + CTX_wm_area_set(C, area_event_inside(C, &event->prevx)); CTX_wm_region_set(C, region_event_inside(C, &event->prevx)); wm_paintcursor_tag(C, wm->paintcursors.first, CTX_wm_region(C)); - + CTX_wm_area_set(C, sa); CTX_wm_region_set(C, ar); } @@ -2664,7 +2695,7 @@ static void wm_event_drag_test(wmWindowManager *wm, wmWindow *win, wmEvent *even if (BLI_listbase_is_empty(&wm->drags)) { return; } - + if (event->type == MOUSEMOVE || ISKEYMODIFIER(event->type)) { screen->do_draw_drag = true; } @@ -2675,20 +2706,20 @@ static void wm_event_drag_test(wmWindowManager *wm, wmWindow *win, wmEvent *even } else if (event->type == LEFTMOUSE && event->val == KM_RELEASE) { event->type = EVT_DROP; - + /* create customdata, first free existing */ if (event->customdata) { if (event->customdatafree) MEM_freeN(event->customdata); } - + event->custom = EVT_DATA_DRAGDROP; event->customdata = &wm->drags; event->customdatafree = 1; - + /* clear drop icon */ screen->do_draw_drag = true; - + /* restore cursor (disabled, see wm_dragdrop.c) */ // WM_cursor_modal_restore(win); } @@ -2738,12 +2769,12 @@ void wm_event_do_handlers(bContext *C) if (scene) { int is_playing_sound = BKE_sound_scene_playing(scene); - + if (is_playing_sound != -1) { bool is_playing_screen; CTX_wm_window_set(C, win); CTX_data_scene_set(C, scene); - + is_playing_screen = (ED_screen_animation_playing(wm) != NULL); if (((is_playing_sound == 1) && (is_playing_screen == 0)) || @@ -2751,7 +2782,7 @@ void wm_event_do_handlers(bContext *C) { ED_screen_animation_play(C, -1, 1); } - + if (is_playing_sound == 0) { const float time = BKE_sound_sync_scene(scene); if (isfinite(time)) { @@ -2764,14 +2795,14 @@ void wm_event_do_handlers(bContext *C) } } } - + CTX_data_scene_set(C, NULL); CTX_wm_screen_set(C, NULL); CTX_wm_window_set(C, NULL); } } } - + while ( (event = win->queue.first) ) { int action = WM_HANDLER_CONTINUE; @@ -2805,16 +2836,16 @@ void wm_event_do_handlers(bContext *C) /* we let modal handlers get active area/region, also wm_paintcursor_test needs it */ CTX_wm_area_set(C, area_event_inside(C, &event->x)); CTX_wm_region_set(C, region_event_inside(C, &event->x)); - + /* MVC demands to not draw in event handlers... but we need to leave it for ogl selecting etc */ wm_window_make_drawable(wm, win); - + wm_region_mouse_co(C, event); /* first we do priority handlers, modal + some limited keymaps */ action |= wm_handlers_do(C, event, &win->modalhandlers); - + /* fileread case */ if (CTX_wm_window(C) == NULL) return; @@ -2830,13 +2861,13 @@ void wm_event_do_handlers(bContext *C) /* check dragging, creates new event or frees, adds draw tag */ wm_event_drag_test(wm, win, event); - + /* builtin tweak, if action is break it removes tweak */ wm_tweakevent_test(C, event, action); if ((action & WM_HANDLER_BREAK) == 0) { ARegion *ar; - + /* Note: setting subwin active should be done here, after modal handlers have been done */ if (event->type == MOUSEMOVE) { /* state variables in screen, cursors. Also used in wm_draw.c, fails for modal handlers though */ @@ -2871,7 +2902,7 @@ void wm_event_do_handlers(bContext *C) for (ar = sa->regionbase.first; ar; ar = ar->next) { if (wm_event_inside_i(event, &ar->winrct)) { CTX_wm_region_set(C, ar); - + /* call even on non mouse events, since the */ wm_region_mouse_co(C, event); @@ -2945,7 +2976,7 @@ void wm_event_do_handlers(bContext *C) /* NOTE: do not escape on WM_HANDLER_BREAK, mousemove needs handled for previous area */ } } - + if ((action & WM_HANDLER_BREAK) == 0) { /* also some non-modal handlers need active area/region */ CTX_wm_area_set(C, area_event_inside(C, &event->x)); @@ -2969,9 +3000,9 @@ void wm_event_do_handlers(bContext *C) /* unlink and free here, blender-quit then frees all */ BLI_remlink(&win->queue, event); wm_event_free(event); - + } - + /* only add mousemove when queue was read entirely */ if (win->addmousemove && win->eventstate) { wmEvent tevent = *(win->eventstate); @@ -2982,7 +3013,7 @@ void wm_event_do_handlers(bContext *C) wm_event_add(win, &tevent); win->addmousemove = 0; } - + CTX_wm_window_set(C, NULL); } @@ -2997,10 +3028,10 @@ void WM_event_fileselect_event(wmWindowManager *wm, void *ophandle, int eventval { /* add to all windows! */ wmWindow *win; - + for (win = wm->windows.first; win; win = win->next) { wmEvent event = *win->eventstate; - + event.type = EVT_FILESELECT; event.val = eventval; event.customdata = ophandle; // only as void pointer type check @@ -3027,7 +3058,7 @@ void WM_event_add_fileselect(bContext *C, wmOperator *op) /* only allow 1 file selector open per window */ for (handler = win->modalhandlers.first; handler; handler = handlernext) { handlernext = handler->next; - + if (handler->type == WM_HANDLER_FILESELECT) { bScreen *screen = CTX_wm_screen(C); bool cancel_handler = true; @@ -3052,16 +3083,16 @@ void WM_event_add_fileselect(bContext *C, wmOperator *op) } } } - + handler = MEM_callocN(sizeof(wmEventHandler), "fileselect handler"); - + handler->type = WM_HANDLER_FILESELECT; handler->op = op; handler->op_area = CTX_wm_area(C); handler->op_region = CTX_wm_region(C); - + BLI_addhead(&win->modalhandlers, handler); - + /* check props once before invoking if check is available * ensures initial properties are valid */ if (op->type->check) { @@ -3083,7 +3114,7 @@ wmEventHandler *WM_event_add_modal_handler(bContext *C, wmOperator *op) { wmEventHandler *handler = MEM_callocN(sizeof(wmEventHandler), "event modal handler"); wmWindow *win = CTX_wm_window(C); - + /* operator was part of macro */ if (op->opm) { /* give the mother macro to the handler */ @@ -3093,11 +3124,11 @@ wmEventHandler *WM_event_add_modal_handler(bContext *C, wmOperator *op) } else handler->op = op; - + handler->op_area = CTX_wm_area(C); /* means frozen screen context for modal handlers! */ handler->op_region = CTX_wm_region(C); handler->op_region_type = handler->op_region ? handler->op_region->regiontype : -1; - + BLI_addhead(&win->modalhandlers, handler); return handler; @@ -3144,7 +3175,7 @@ wmEventHandler *WM_event_add_keymap_handler(ListBase *handlers, wmKeyMap *keymap for (handler = handlers->first; handler; handler = handler->next) if (handler->keymap == keymap) return handler; - + handler = MEM_callocN(sizeof(wmEventHandler), "event keymap handler"); BLI_addtail(handlers, handler); handler->keymap = keymap; @@ -3156,20 +3187,20 @@ wmEventHandler *WM_event_add_keymap_handler(ListBase *handlers, wmKeyMap *keymap wmEventHandler *WM_event_add_keymap_handler_priority(ListBase *handlers, wmKeyMap *keymap, int UNUSED(priority)) { wmEventHandler *handler; - + WM_event_remove_keymap_handler(handlers, keymap); - + handler = MEM_callocN(sizeof(wmEventHandler), "event keymap handler"); BLI_addhead(handlers, handler); handler->keymap = keymap; - + return handler; } wmEventHandler *WM_event_add_keymap_handler_bb(ListBase *handlers, wmKeyMap *keymap, const rcti *bblocal, const rcti *bbwin) { wmEventHandler *handler = WM_event_add_keymap_handler(handlers, keymap); - + if (handler) { handler->bblocal = bblocal; handler->bbwin = bbwin; @@ -3180,7 +3211,7 @@ wmEventHandler *WM_event_add_keymap_handler_bb(ListBase *handlers, wmKeyMap *key void WM_event_remove_keymap_handler(ListBase *handlers, wmKeyMap *keymap) { wmEventHandler *handler; - + for (handler = handlers->first; handler; handler = handler->next) { if (handler->keymap == keymap) { BLI_remlink(handlers, handler); @@ -3221,9 +3252,9 @@ wmEventHandler *WM_event_add_ui_handler( BLI_assert((flag & WM_HANDLER_DO_FREE) == 0); handler->flag = flag; - + BLI_addhead(handlers, handler); - + return handler; } @@ -3234,7 +3265,7 @@ void WM_event_remove_ui_handler( void *userdata, const bool postpone) { wmEventHandler *handler; - + for (handler = handlers->first; handler; handler = handler->next) { if ((handler->ui_handle == ui_handle) && (handler->ui_remove == ui_remove) && @@ -3279,13 +3310,13 @@ wmEventHandler *WM_event_add_dropbox_handler(ListBase *handlers, ListBase *dropb for (handler = handlers->first; handler; handler = handler->next) if (handler->dropboxes == dropboxes) return handler; - + handler = MEM_callocN(sizeof(wmEventHandler), "dropbox handler"); - + /* dropbox stored static, no free or copy */ handler->dropboxes = dropboxes; BLI_addhead(handlers, handler); - + return handler; } @@ -3316,7 +3347,7 @@ static void WM_event_remove_handler(ListBase *handlers, wmEventHandler *handler) void WM_event_add_mousemove(const bContext *C) { wmWindow *window = CTX_wm_window(C); - + window->addmousemove = 1; } @@ -3324,7 +3355,7 @@ void WM_event_add_mousemove(const bContext *C) /* for modal callbacks, check configuration for how to interpret exit with tweaks */ bool WM_event_is_modal_tweak_exit(const wmEvent *event, int tweak_event) { - /* if the release-confirm userpref setting is enabled, + /* if the release-confirm userpref setting is enabled, * tweak events can be canceled when mouse is released */ if (U.flag & USER_RELEASECONFIRM) { @@ -3353,13 +3384,13 @@ bool WM_event_is_modal_tweak_exit(const wmEvent *event, int tweak_event) if (event->val != KM_RELEASE) return 1; } - + return 0; } /* ********************* ghost stuff *************** */ -static int convert_key(GHOST_TKey key) +static int convert_key(GHOST_TKey key) { if (key >= GHOST_kKeyA && key <= GHOST_kKeyZ) { return (AKEY + ((int) key - GHOST_kKeyA)); @@ -3438,7 +3469,7 @@ static int convert_key(GHOST_TKey key) case GHOST_kKeyMediaStop: return MEDIASTOP; case GHOST_kKeyMediaFirst: return MEDIAFIRST; case GHOST_kKeyMediaLast: return MEDIALAST; - + default: return UNKNOWNKEY; /* GHOST_kKeyUnknown */ } @@ -3450,11 +3481,11 @@ static void wm_eventemulation(wmEvent *event) /* Store last mmb/rmb event value to make emulation work when modifier keys * are released first. This really should be in a data structure somewhere. */ static int emulating_event = EVENT_NONE; - + /* middlemouse and rightmouse emulation */ if (U.flag & USER_TWOBUTTONMOUSE) { if (event->type == LEFTMOUSE) { - + if (event->val == KM_PRESS && event->alt) { event->type = MIDDLEMOUSE; event->alt = 0; @@ -3480,9 +3511,9 @@ static void wm_eventemulation(wmEvent *event) emulating_event = EVENT_NONE; } } - + } - + /* numpad emulation */ if (U.flag & USER_NONUMPAD) { switch (event->type) { @@ -3507,16 +3538,16 @@ static void wm_eventemulation(wmEvent *event) static void update_tablet_data(wmWindow *win, wmEvent *event) { const GHOST_TabletData *td = GHOST_GetTabletData(win->ghostwin); - + /* if there's tablet data from an active tablet device then add it */ if ((td != NULL) && td->Active != GHOST_kTabletModeNone) { struct wmTabletData *wmtab = MEM_mallocN(sizeof(wmTabletData), "customdata tablet"); - + wmtab->Active = (int)td->Active; wmtab->Pressure = td->Pressure; wmtab->Xtilt = td->Xtilt; wmtab->Ytilt = td->Ytilt; - + event->tablet_data = wmtab; // printf("%s: using tablet %.5f\n", __func__, wmtab->Pressure); } @@ -3559,40 +3590,40 @@ static void attach_ndof_data(wmEvent *event, const GHOST_TEventNDOFMotionData *g static wmWindow *wm_event_cursor_other_windows(wmWindowManager *wm, wmWindow *win, wmEvent *event) { int mx = event->x, my = event->y; - + if (wm->windows.first == wm->windows.last) return NULL; - + /* in order to use window size and mouse position (pixels), we have to use a WM function */ - + /* check if outside, include top window bar... */ if (mx < 0 || my < 0 || mx > WM_window_pixels_x(win) || my > WM_window_pixels_y(win) + 30) { wmWindow *owin; wmEventHandler *handler; - + /* let's skip windows having modal handlers now */ /* potential XXX ugly... I wouldn't have added a modalhandlers list (introduced in rev 23331, ton) */ for (handler = win->modalhandlers.first; handler; handler = handler->next) if (handler->ui_handle || handler->op) return NULL; - + /* to desktop space */ mx += (int) (U.pixelsize * win->posx); my += (int) (U.pixelsize * win->posy); - + /* check other windows to see if it has mouse inside */ for (owin = wm->windows.first; owin; owin = owin->next) { - + if (owin != win) { int posx = (int) (U.pixelsize * owin->posx); int posy = (int) (U.pixelsize * owin->posy); - + if (mx - posx >= 0 && owin->posy >= 0 && mx - posx <= WM_window_pixels_x(owin) && my - posy <= WM_window_pixels_y(owin)) { event->x = mx - (int)(U.pixelsize * owin->posx); event->y = my - (int)(U.pixelsize * owin->posy); - + return owin; } } @@ -3671,7 +3702,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int U copy_v2_v2_int(&evt->x, &event_new->x); evt->is_motion_absolute = event_new->is_motion_absolute; } - + /* also add to other window if event is there, this makes overdraws disappear nicely */ /* it remaps mousecoord to other window in event */ owin = wm_event_cursor_other_windows(wm, win, &event); @@ -3688,7 +3719,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int U oevt->is_motion_absolute = event_new->is_motion_absolute; } } - + break; } case GHOST_kEventTrackpad: @@ -3712,11 +3743,11 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int U event.x = evt->x = pd->x; event.y = evt->y = pd->y; event.val = KM_NOTHING; - + /* Use prevx/prevy so we can calculate the delta later */ event.prevx = event.x - pd->deltaX; event.prevy = event.y - (-pd->deltaY); - + wm_event_add(win, &event); break; } @@ -3725,10 +3756,10 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int U case GHOST_kEventButtonUp: { GHOST_TEventButtonData *bd = customdata; - + /* get value and type from ghost */ event.val = (type == GHOST_kEventButtonDown) ? KM_PRESS : KM_RELEASE; - + if (bd->button == GHOST_kButtonMaskLeft) event.type = LEFTMOUSE; else if (bd->button == GHOST_kButtonMaskRight) @@ -3743,9 +3774,9 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int U event.type = BUTTON7MOUSE; else event.type = MIDDLEMOUSE; - + wm_eventemulation(&event); - + /* copy previous state to prev event state (two old!) */ evt->prevval = evt->val; evt->prevtype = evt->type; @@ -3756,14 +3787,14 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int U if (win->active == 0) { int cx, cy; - + /* entering window, update mouse pos. (ghost sends win-activate *after* the mouseclick in window!) */ wm_get_cursor_position(win, &cx, &cy); event.x = evt->x = cx; event.y = evt->y = cy; } - + /* double click test */ if (wm_event_is_double_click(&event, evt)) { CLOG_INFO(WM_LOG_HANDLERS, 1, "Send double click"); @@ -3774,23 +3805,23 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int U evt->prevclickx = event.x; evt->prevclicky = event.y; } - + /* add to other window if event is there (not to both!) */ owin = wm_event_cursor_other_windows(wm, win, &event); if (owin) { wmEvent oevent = *(owin->eventstate); - + oevent.x = event.x; oevent.y = event.y; oevent.type = event.type; oevent.val = event.val; - + wm_event_add(owin, &oevent); } else { wm_event_add(win, &event); } - + break; } /* keyboard */ @@ -3803,9 +3834,9 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int U event.ascii = kd->ascii; memcpy(event.utf8_buf, kd->utf8_buf, sizeof(event.utf8_buf)); /* might be not null terminated*/ event.val = (type == GHOST_kEventKeyDown) ? KM_PRESS : KM_RELEASE; - + wm_eventemulation(&event); - + /* copy previous state to prev event state (two old!) */ evt->prevval = evt->val; evt->prevtype = evt->type; @@ -3813,7 +3844,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int U /* copy to event state */ evt->val = event.val; evt->type = event.type; - + /* exclude arrow keys, esc, etc from text input */ if (type == GHOST_kEventKeyUp) { event.ascii = '\0'; @@ -3887,19 +3918,19 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int U CLOG_INFO(WM_LOG_HANDLERS, 1, "Send double click"); evt->val = event.val = KM_DBL_CLICK; } - + /* this case happens on holding a key pressed, it should not generate * press events events with the same key as modifier */ if (event.keymodifier == event.type) event.keymodifier = 0; - + /* this case happens with an external numpad, and also when using 'dead keys' (to compose complex latin * characters e.g.), it's not really clear why. * Since it's impossible to map a key modifier to an unknown key, it shouldn't harm to clear it. */ if (event.keymodifier == UNKNOWNKEY) { evt->keymodifier = event.keymodifier = 0; } - + /* if test_break set, it catches this. Do not set with modifier presses. XXX Keep global for now? */ if ((event.type == ESCKEY && event.val == KM_PRESS) && /* check other modifiers because ms-windows uses these to bring up the task manager */ @@ -3907,31 +3938,34 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int U { G.is_break = true; } - + /* double click test - only for press */ if (event.val == KM_PRESS) { - evt->prevclicktime = PIL_check_seconds_timer(); - evt->prevclickx = event.x; - evt->prevclicky = event.y; + /* Don't reset timer & location when holding the key generates repeat events. */ + if ((evt->prevtype != event.type) || (evt->prevval != KM_PRESS)) { + evt->prevclicktime = PIL_check_seconds_timer(); + evt->prevclickx = event.x; + evt->prevclicky = event.y; + } } - + wm_event_add(win, &event); - + break; } - + case GHOST_kEventWheel: { GHOST_TEventWheelData *wheelData = customdata; - + if (wheelData->z > 0) event.type = WHEELUPMOUSE; else event.type = WHEELDOWNMOUSE; - + event.val = KM_PRESS; wm_event_add(win, &event); - + break; } case GHOST_kEventTimer: diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c index 68be37ef709..3aaec875627 100644 --- a/source/blender/windowmanager/intern/wm_files.c +++ b/source/blender/windowmanager/intern/wm_files.c @@ -152,27 +152,27 @@ static void wm_window_match_init(bContext *C, ListBase *wmlist) { wmWindowManager *wm; wmWindow *win, *active_win; - + *wmlist = G.main->wm; BLI_listbase_clear(&G.main->wm); - + active_win = CTX_wm_window(C); /* first wrap up running stuff */ /* code copied from wm_init_exit.c */ for (wm = wmlist->first; wm; wm = wm->id.next) { - + WM_jobs_kill_all(wm); - + for (win = wm->windows.first; win; win = win->next) { - + CTX_wm_window_set(C, win); /* needed by operator close callbacks */ WM_event_remove_handlers(C, &win->handlers); WM_event_remove_handlers(C, &win->modalhandlers); ED_screen_exit(C, win, WM_window_get_active_screen(win)); } } - + /* reset active window */ CTX_wm_window_set(C, active_win); @@ -215,6 +215,7 @@ static void wm_window_match_keep_current_wm( const bool load_ui, ListBase *r_new_wm_list) { + Main *bmain = CTX_data_main(C); wmWindowManager *wm = current_wm_list->first; bScreen *screen = NULL; @@ -236,7 +237,7 @@ static void wm_window_match_keep_current_wm( } else { WorkSpaceLayout *layout_old = WM_window_get_active_layout(win); - WorkSpaceLayout *layout_new = ED_workspace_layout_duplicate(workspace, layout_old, win); + WorkSpaceLayout *layout_new = ED_workspace_layout_duplicate(bmain, workspace, layout_old, win); WM_window_set_active_layout(win, workspace, layout_new); } @@ -339,8 +340,8 @@ static void wm_window_match_do( static void wm_init_userdef(Main *bmain, const bool read_userdef_from_memory) { /* versioning is here */ - UI_init_userdef(); - + UI_init_userdef(bmain); + MEM_CacheLimiter_set_maximum(((size_t)U.memcachelimit) * 1024 * 1024); BKE_sound_init(bmain); @@ -569,7 +570,7 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports) /* it throws error box when file doesn't exist and returns -1 */ /* note; it should set some error message somewhere... (ton) */ retval = wm_read_exotic(filepath); - + /* we didn't succeed, now try to read Blender file */ if (retval == BKE_READ_EXOTIC_OK_BLEND) { int G_f = G.f; @@ -578,12 +579,16 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports) /* put aside screens to match with persistent windows later */ /* also exit screens and editors */ wm_window_match_init(C, &wmbase); - + /* confusing this global... */ G.relbase_valid = 1; retval = BKE_blendfile_read(C, filepath, reports, 0); + + /* BKE_file_read sets new Main into context. */ + Main *bmain = CTX_data_main(C); + /* when loading startup.blend's, we can be left with a blank path */ - if (G.main->name[0]) { + if (BKE_main_blendfile_path(bmain)) { G.save_over = 1; } else { @@ -599,14 +604,14 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports) } /* match the read WM with current WM */ - wm_window_match_do(C, &wmbase, &G.main->wm, &G.main->wm); + wm_window_match_do(C, &wmbase, &bmain->wm, &bmain->wm); WM_check(C); /* opens window(s), checks keymaps */ if (retval == BKE_BLENDFILE_READ_OK_USERPREFS) { /* in case a userdef is read from regular .blend */ - wm_init_userdef(G.main, false); + wm_init_userdef(bmain, false); } - + if (retval != BKE_BLENDFILE_READ_FAIL) { if (do_history) { wm_history_file_update(); @@ -672,6 +677,7 @@ int wm_homefile_read( bool use_factory_settings, bool use_empty_data, bool use_userdef, const char *filepath_startup_override, const char *app_template_override) { + Main *bmain = G.main; /* Context does not always have valid main pointer here... */ ListBase wmbase; bool success = false; @@ -863,16 +869,18 @@ int wm_homefile_read( * can remove this eventually, only in a 2.53 and older, now its not written */ G.fileflags &= ~G_FILE_RELATIVE_REMAP; - if (use_userdef) { + bmain = CTX_data_main(C); + + if (use_userdef) { /* check userdef before open window, keymaps etc */ - wm_init_userdef(CTX_data_main(C), read_userdef_from_memory); + wm_init_userdef(bmain, read_userdef_from_memory); } - + /* match the read WM with current WM */ - wm_window_match_do(C, &wmbase, &G.main->wm, &G.main->wm); + wm_window_match_do(C, &wmbase, &bmain->wm, &bmain->wm); WM_check(C); /* opens window(s), checks keymaps */ - G.main->name[0] = '\0'; + bmain->name[0] = '\0'; /* start with save preference untitled.blend */ G.save_over = 0; @@ -913,7 +921,7 @@ void wm_history_file_read(void) num++; } } - + BLI_file_free_lines(lines); } @@ -969,16 +977,18 @@ static void wm_history_file_write(void) static void wm_history_file_update(void) { RecentFile *recent; + const char *blendfile_name = BKE_main_blendfile_path_from_global(); /* no write history for recovered startup files */ - if (G.main->name[0] == 0) + if (blendfile_name[0] == '\0') { return; + } recent = G.recent_files.first; /* refresh recent-files.txt of recent opened files, when current file was changed */ - if (!(recent) || (BLI_path_cmp(recent->filepath, G.main->name) != 0)) { + if (!(recent) || (BLI_path_cmp(recent->filepath, blendfile_name) != 0)) { - recent = wm_file_history_find(G.main->name); + recent = wm_file_history_find(blendfile_name); if (recent) { BLI_remlink(&G.recent_files, recent); } @@ -988,7 +998,7 @@ static void wm_history_file_update(void) recent_next = recent->next; wm_history_file_free(recent); } - recent = wm_history_file_new(G.main->name); + recent = wm_history_file_new(blendfile_name); } /* add current file to the beginning of list */ @@ -998,7 +1008,7 @@ static void wm_history_file_update(void) wm_history_file_write(); /* also update most recent files on System */ - GHOST_addToSystemRecentFiles(G.main->name); + GHOST_addToSystemRecentFiles(blendfile_name); } } @@ -1066,7 +1076,7 @@ static ImBuf *blend_file_thumb(const bContext *C, Scene *scene, bScreen *screen, /* add pretty overlay */ IMB_thumb_overlay_blend(ibuf->rect, ibuf->x, ibuf->y, aspect); - + thumb = BKE_main_thumbnail_from_imbuf(NULL, ibuf); } else { @@ -1074,10 +1084,10 @@ static ImBuf *blend_file_thumb(const bContext *C, Scene *scene, bScreen *screen, fprintf(stderr, "blend_file_thumb failed to create thumbnail: %s\n", err_out); thumb = NULL; } - + /* must be freed by caller */ *thumb_pt = thumb; - + return ibuf; } @@ -1087,7 +1097,7 @@ bool write_crash_blend(void) char path[FILE_MAX]; int fileflags = G.fileflags & ~(G_FILE_HISTORY); /* don't do file history on crash file */ - BLI_strncpy(path, G.main->name, sizeof(path)); + BLI_strncpy(path, BKE_main_blendfile_path_from_global(), sizeof(path)); BLI_replace_extension(path, sizeof(path), "_crash.blend"); if (BLO_write_file(G.main, path, fileflags, NULL, NULL)) { printf("written: %s\n", path); @@ -1104,6 +1114,7 @@ bool write_crash_blend(void) */ static int wm_file_write(bContext *C, const char *filepath, int fileflags, ReportList *reports) { + Main *bmain = CTX_data_main(C); Library *li; int len; int ret = -1; @@ -1111,7 +1122,7 @@ static int wm_file_write(bContext *C, const char *filepath, int fileflags, Repor ImBuf *ibuf_thumb = NULL; len = strlen(filepath); - + if (len == 0) { BKE_report(reports, RPT_ERROR, "Path is empty, cannot save"); return ret; @@ -1121,7 +1132,7 @@ static int wm_file_write(bContext *C, const char *filepath, int fileflags, Repor BKE_report(reports, RPT_ERROR, "Path too long, cannot save"); return ret; } - + /* Check if file write permission is ok */ if (BLI_exists(filepath) && !BLI_file_is_writable(filepath)) { BKE_reportf(reports, RPT_ERROR, "Cannot save blend file, path '%s' is not writable", filepath); @@ -1131,9 +1142,9 @@ static int wm_file_write(bContext *C, const char *filepath, int fileflags, Repor /* note: used to replace the file extension (to ensure '.blend'), * no need to now because the operator ensures, * its handy for scripts to save to a predefined name without blender editing it */ - + /* send the OnSave event */ - for (li = G.main->library.first; li; li = li->id.next) { + for (li = bmain->library.first; li; li = li->id.next) { if (BLI_path_cmp(li->filepath, filepath) == 0) { BKE_reportf(reports, RPT_ERROR, "Cannot overwrite used library '%.240s'", filepath); return ret; @@ -1141,12 +1152,12 @@ static int wm_file_write(bContext *C, const char *filepath, int fileflags, Repor } /* Call pre-save callbacks befores writing preview, that way you can generate custom file thumbnail... */ - BLI_callback_exec(G.main, NULL, BLI_CB_EVT_SAVE_PRE); + BLI_callback_exec(bmain, NULL, BLI_CB_EVT_SAVE_PRE); /* blend file thumbnail */ /* save before exit_editmode, otherwise derivedmeshes for shared data corrupt #27765) */ /* Main now can store a .blend thumbnail, usefull for background mode or thumbnail customization. */ - main_thumb = thumb = CTX_data_main(C)->blen_thumb; + main_thumb = thumb = bmain->blen_thumb; if ((U.flag & USER_SAVE_PREVIEWS) && BLI_thread_is_main()) { ibuf_thumb = blend_file_thumb(C, CTX_data_scene(C), CTX_wm_screen(C), &thumb); } @@ -1154,32 +1165,32 @@ static int wm_file_write(bContext *C, const char *filepath, int fileflags, Repor /* operator now handles overwrite checks */ if (G.fileflags & G_AUTOPACK) { - packAll(G.main, reports, false); + packAll(bmain, reports, false); } /* don't forget not to return without! */ WM_cursor_wait(1); - + ED_editors_flush_edits(C, false); fileflags |= G_FILE_HISTORY; /* write file history */ /* first time saving */ /* XXX temp solution to solve bug, real fix coming (ton) */ - if ((G.main->name[0] == '\0') && !(fileflags & G_FILE_SAVE_COPY)) { - BLI_strncpy(G.main->name, filepath, sizeof(G.main->name)); + if ((BKE_main_blendfile_path(bmain)[0] == '\0') && !(fileflags & G_FILE_SAVE_COPY)) { + BLI_strncpy(bmain->name, filepath, sizeof(bmain->name)); } /* XXX temp solution to solve bug, real fix coming (ton) */ - G.main->recovered = 0; - + bmain->recovered = 0; + if (BLO_write_file(CTX_data_main(C), filepath, fileflags, reports, thumb)) { const bool do_history = (G.background == false) && (CTX_wm_manager(C)->op_undo_depth == 0); if (!(fileflags & G_FILE_SAVE_COPY)) { G.relbase_valid = 1; - BLI_strncpy(G.main->name, filepath, sizeof(G.main->name)); /* is guaranteed current file */ - + BLI_strncpy(bmain->name, filepath, sizeof(bmain->name)); /* is guaranteed current file */ + G.save_over = 1; /* disable untitled.blend convention */ } @@ -1190,7 +1201,7 @@ static int wm_file_write(bContext *C, const char *filepath, int fileflags, Repor wm_history_file_update(); } - BLI_callback_exec(G.main, NULL, BLI_CB_EVT_SAVE_POST); + BLI_callback_exec(bmain, NULL, BLI_CB_EVT_SAVE_POST); /* run this function after because the file cant be written before the blend is */ if (ibuf_thumb) { @@ -1224,7 +1235,7 @@ void wm_autosave_location(char *filepath) #endif if (G.main && G.relbase_valid) { - const char *basename = BLI_path_basename(G.main->name); + const char *basename = BLI_path_basename(BKE_main_blendfile_path_from_global()); int len = strlen(basename) - 6; BLI_snprintf(path, sizeof(path), "%.*s.blend", len, basename); } @@ -1264,7 +1275,7 @@ void wm_autosave_timer(const bContext *C, wmWindowManager *wm, wmTimer *UNUSED(w wmWindow *win; wmEventHandler *handler; char filepath[FILE_MAX]; - + WM_event_remove_timer(wm, NULL, wm->autosavetimer); /* if a modal operator is running, don't autosave, but try again in 10 seconds */ @@ -1313,7 +1324,7 @@ void wm_autosave_timer_ended(wmWindowManager *wm) void wm_autosave_delete(void) { char filename[FILE_MAX]; - + wm_autosave_location(filename); if (BLI_exists(filename)) { @@ -1754,7 +1765,8 @@ struct FileRuntime { static int wm_open_mainfile_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - const char *openname = G.main->name; + Main *bmain = CTX_data_main(C); + const char *openname = BKE_main_blendfile_path(bmain); if (CTX_wm_window(C) == NULL) { /* in rare cases this could happen, when trying to invoke in background @@ -1893,6 +1905,7 @@ void WM_OT_open_mainfile(wmOperatorType *ot) static int wm_revert_mainfile_exec(bContext *C, wmOperator *op) { + Main *bmain = CTX_data_main(C); bool success; char filepath[FILE_MAX]; @@ -1903,7 +1916,7 @@ static int wm_revert_mainfile_exec(bContext *C, wmOperator *op) else G.f &= ~G_SCRIPT_AUTOEXEC; - BLI_strncpy(filepath, G.main->name, sizeof(filepath)); + BLI_strncpy(filepath, BKE_main_blendfile_path(bmain), sizeof(filepath)); success = wm_file_read_opwrap(C, filepath, op->reports, !(G.f & G_SCRIPT_AUTOEXEC)); if (success) { @@ -1941,6 +1954,7 @@ void WM_OT_revert_mainfile(wmOperatorType *ot) void WM_recover_last_session(bContext *C, ReportList *reports) { + Main *bmain = CTX_data_main(C); char filepath[FILE_MAX]; BLI_make_file_string("/", filepath, BKE_tempdir_base(), BLENDER_QUIT_FILE); @@ -1953,8 +1967,9 @@ void WM_recover_last_session(bContext *C, ReportList *reports) G.fileflags &= ~G_FILE_RECOVER; /* XXX bad global... fixme */ - if (G.main->name[0]) + if (BKE_main_blendfile_path(bmain)[0] != '\0') { G.file_loaded = 1; /* prevents splash to show */ + } else { G.relbase_valid = 0; G.save_over = 0; /* start with save preference untitled.blend */ @@ -2053,20 +2068,21 @@ static void save_set_compress(wmOperator *op) } } -static void save_set_filepath(wmOperator *op) +static void save_set_filepath(bContext *C, wmOperator *op) { + Main *bmain = CTX_data_main(C); PropertyRNA *prop; char name[FILE_MAX]; prop = RNA_struct_find_property(op->ptr, "filepath"); if (!RNA_property_is_set(op->ptr, prop)) { /* if not saved before, get the name of the most recently used .blend file */ - if (G.main->name[0] == 0 && G.recent_files.first) { + if (BKE_main_blendfile_path(bmain)[0] == '\0' && G.recent_files.first) { struct RecentFile *recent = G.recent_files.first; BLI_strncpy(name, recent->filepath, FILE_MAX); } else { - BLI_strncpy(name, G.main->name, FILE_MAX); + BLI_strncpy(name, bmain->name, FILE_MAX); } wm_filepath_default(name); @@ -2078,7 +2094,7 @@ static int wm_save_as_mainfile_invoke(bContext *C, wmOperator *op, const wmEvent { save_set_compress(op); - save_set_filepath(op); + save_set_filepath(C, op); WM_event_add_fileselect(C, op); @@ -2088,6 +2104,7 @@ static int wm_save_as_mainfile_invoke(bContext *C, wmOperator *op, const wmEvent /* function used for WM_OT_save_mainfile too */ static int wm_save_as_mainfile_exec(bContext *C, wmOperator *op) { + Main *bmain = CTX_data_main(C); char path[FILE_MAX]; int fileflags; @@ -2097,7 +2114,7 @@ static int wm_save_as_mainfile_exec(bContext *C, wmOperator *op) RNA_string_get(op->ptr, "filepath", path); } else { - BLI_strncpy(path, G.main->name, FILE_MAX); + BLI_strncpy(path, BKE_main_blendfile_path(bmain), FILE_MAX); wm_filepath_default(path); } @@ -2193,7 +2210,7 @@ static int wm_save_mainfile_invoke(bContext *C, wmOperator *op, const wmEvent *U return OPERATOR_CANCELLED; save_set_compress(op); - save_set_filepath(op); + save_set_filepath(C, op); /* if we're saving for the first time and prefer relative paths - any existing paths will be absolute, * enable the option to remap paths to avoid confusion [#37240] */ diff --git a/source/blender/windowmanager/intern/wm_files_link.c b/source/blender/windowmanager/intern/wm_files_link.c index 0f2da2e8f36..c7d55b290f5 100644 --- a/source/blender/windowmanager/intern/wm_files_link.c +++ b/source/blender/windowmanager/intern/wm_files_link.c @@ -115,7 +115,7 @@ static int wm_link_append_invoke(bContext *C, wmOperator *op, const wmEvent *UNU } else if (G.relbase_valid) { char path[FILE_MAX]; - BLI_strncpy(path, G.main->name, sizeof(G.main->name)); + BLI_strncpy(path, BKE_main_blendfile_path_from_global(), sizeof(path)); BLI_parent_dir(path); RNA_string_set(op->ptr, "filepath", path); } @@ -333,7 +333,7 @@ static int wm_link_append_exec(bContext *C, wmOperator *op) BKE_reportf(op->reports, RPT_ERROR, "'%s': nothing indicated", path); return OPERATOR_CANCELLED; } - else if (BLI_path_cmp(bmain->name, libname) == 0) { + else if (BLI_path_cmp(BKE_main_blendfile_path(bmain), libname) == 0) { BKE_reportf(op->reports, RPT_ERROR, "'%s': cannot use current file as library", path); return OPERATOR_CANCELLED; } @@ -372,7 +372,7 @@ static int wm_link_append_exec(bContext *C, wmOperator *op) if (view_layer && RNA_boolean_get(op->ptr, "autoselect")) { BKE_view_layer_base_deselect_all(view_layer); } - + /* tag everything, all untagged data can be made local * its also generally useful to know what is new * @@ -531,18 +531,18 @@ void WM_OT_link(wmOperatorType *ot) ot->name = "Link from Library"; ot->idname = "WM_OT_link"; ot->description = "Link from a Library .blend file"; - + ot->invoke = wm_link_append_invoke; ot->exec = wm_link_append_exec; ot->poll = wm_link_append_poll; - + ot->flag |= OPTYPE_UNDO; WM_operator_properties_filesel( ot, FILE_TYPE_FOLDER | FILE_TYPE_BLENDER | FILE_TYPE_BLENDERLIB, FILE_LOADLIB, FILE_OPENFILE, WM_FILESEL_FILEPATH | WM_FILESEL_DIRECTORY | WM_FILESEL_FILENAME | WM_FILESEL_RELPATH | WM_FILESEL_FILES, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA); - + wm_link_append_properties_common(ot, true); } diff --git a/source/blender/windowmanager/intern/wm_gesture.c b/source/blender/windowmanager/intern/wm_gesture.c index 2c3583a9f02..144bb38ae76 100644 --- a/source/blender/windowmanager/intern/wm_gesture.c +++ b/source/blender/windowmanager/intern/wm_gesture.c @@ -63,20 +63,20 @@ wmGesture *WM_gesture_new(bContext *C, const wmEvent *event, int type) wmGesture *gesture = MEM_callocN(sizeof(wmGesture), "new gesture"); wmWindow *window = CTX_wm_window(C); ARegion *ar = CTX_wm_region(C); - + BLI_addtail(&window->gesture, gesture); - + gesture->type = type; gesture->event_type = event->type; gesture->winrct = ar->winrct; gesture->userdata_free = true; /* Free if userdata is set. */ gesture->modal_state = GESTURE_MODAL_NOP; - + if (ELEM(type, WM_GESTURE_RECT, WM_GESTURE_CROSS_RECT, WM_GESTURE_TWEAK, WM_GESTURE_CIRCLE, WM_GESTURE_STRAIGHTLINE)) { rcti *rect = MEM_callocN(sizeof(rcti), "gesture rect new"); - + gesture->customdata = rect; rect->xmin = event->x - gesture->winrct.xmin; rect->ymin = event->y - gesture->winrct.ymin; @@ -96,14 +96,14 @@ wmGesture *WM_gesture_new(bContext *C, const wmEvent *event, int type) lasso[1] = event->y - gesture->winrct.ymin; gesture->points = 1; } - + return gesture; } void WM_gesture_end(bContext *C, wmGesture *gesture) { wmWindow *win = CTX_wm_window(C); - + if (win->tweak == gesture) win->tweak = NULL; BLI_remlink(&win->gesture, gesture); @@ -117,7 +117,7 @@ void WM_gesture_end(bContext *C, wmGesture *gesture) void WM_gestures_remove(bContext *C) { wmWindow *win = CTX_wm_window(C); - + while (win->gesture.first) WM_gesture_end(C, win->gesture.first); } @@ -141,7 +141,7 @@ int wm_gesture_evaluate(wmGesture *gesture) else if (theta == -1) val = EVT_GESTURE_SE; else if (theta == -2) val = EVT_GESTURE_S; else if (theta == -3) val = EVT_GESTURE_SW; - + #if 0 /* debug */ if (val == 1) printf("tweak north\n"); @@ -421,7 +421,7 @@ void wm_gesture_draw(wmWindow *win) for (; gt; gt = gt->next) { /* all in subwindow space */ wmViewport(>->winrct); - + if (gt->type == WM_GESTURE_RECT) wm_gesture_draw_rect(gt); // else if (gt->type == WM_GESTURE_TWEAK) @@ -448,7 +448,7 @@ void wm_gesture_draw(wmWindow *win) void wm_gesture_tag_redraw(bContext *C) { bScreen *screen = CTX_wm_screen(C); - + if (screen) screen->do_draw_gesture = true; } diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c index 480287ce6b1..c5a57147dd6 100644 --- a/source/blender/windowmanager/intern/wm_init_exit.c +++ b/source/blender/windowmanager/intern/wm_init_exit.c @@ -186,6 +186,8 @@ void WM_init_opengl(void) GPU_set_anisotropic(U.anisotropic_filter); GPU_set_gpu_mipmapping(U.use_gpu_mipmap); + GPU_pass_cache_init(); + #ifdef WITH_OPENSUBDIV BKE_subsurf_osd_init(); #endif @@ -195,7 +197,7 @@ void WM_init_opengl(void) /* only called once, for startup */ void WM_init(bContext *C, int argc, const char **argv) { - + if (!G.background) { wm_ghost_init(C); /* note: it assigns C to ghost! */ wm_init_cursor_data(); @@ -222,12 +224,12 @@ void WM_init(bContext *C, int argc, const char **argv) BKE_spacedata_callback_id_remap_set(ED_spacedata_id_remap); /* screen.c */ DEG_editors_set_update_cb(ED_render_id_flush_update, ED_render_scene_update); - + ED_spacetypes_init(); /* editors/space_api/spacetype.c */ - + ED_file_init(); /* for fsmenu */ ED_node_init_butfuncs(); - + BLF_init(); BLT_lang_init(); @@ -293,11 +295,11 @@ void WM_init(bContext *C, int argc, const char **argv) /* allow a path of "", this is what happens when making a new file */ #if 0 - if (G.main->name[0] == 0) + if (BKE_main_blendfile_path_from_global()[0] == '\0') BLI_make_file_string("/", G.main->name, BKE_appdir_folder_default(), "untitled.blend"); #endif - BLI_strncpy(G.lib, G.main->name, FILE_MAX); + BLI_strncpy(G.lib, BKE_main_blendfile_path_from_global(), sizeof(G.lib)); #ifdef WITH_COMPOSITOR if (1) { @@ -305,7 +307,7 @@ void WM_init(bContext *C, int argc, const char **argv) COM_linker_hack = COM_execute; } #endif - + /* load last session, uses regular file reading so it has to be in end (after init py etc) */ if (U.uiflag2 & USER_KEEP_SESSION) { /* calling WM_recover_last_session(C, NULL) has been moved to creator.c */ @@ -338,7 +340,7 @@ void WM_init_splash(bContext *C) if ((U.uiflag & USER_SPLASH_DISABLE) == 0) { wmWindowManager *wm = CTX_wm_manager(C); wmWindow *prevwin = CTX_wm_window(C); - + if (wm->windows.first) { CTX_wm_window_set(C, wm->windows.first); WM_operator_name_call(C, "WM_OT_splash", WM_OP_INVOKE_DEFAULT, NULL); @@ -351,10 +353,10 @@ void WM_init_splash(bContext *C) static void free_openrecent(void) { struct RecentFile *recent; - + for (recent = G.recent_files.first; recent; recent = recent->next) MEM_freeN(recent->filepath); - + BLI_freelistN(&(G.recent_files)); } @@ -437,11 +439,11 @@ void WM_exit_ext(bContext *C, const bool do_python) } } } - + WM_jobs_kill_all(wm); for (win = wm->windows.first; win; win = win->next) { - + CTX_wm_window_set(C, win); /* needed by operator close callbacks */ WM_event_remove_handlers(C, &win->handlers); WM_event_remove_handlers(C, &win->modalhandlers); @@ -462,13 +464,13 @@ void WM_exit_ext(bContext *C, const bool do_python) ED_undosys_type_free(); free_openrecent(); - + BKE_mball_cubeTable_free(); - + /* render code might still access databases */ RE_FreeAllRender(); RE_engines_exit(); - + ED_preview_free_dbase(); /* frees a Main dbase, before BKE_blender_free! */ if (C && wm) @@ -478,7 +480,7 @@ void WM_exit_ext(bContext *C, const bool do_python) BKE_tracking_clipboard_free(); BKE_mask_clipboard_free(); BKE_vfont_clipboard_free(); - + #ifdef WITH_COMPOSITOR COM_deinitialize(); #endif @@ -492,7 +494,7 @@ void WM_exit_ext(bContext *C, const bool do_python) GPU_exit(); } - + BKE_blender_free(); /* blender.c, does entire library and spacetypes */ // free_matcopybuf(); ANIM_fcurves_copybuf_free(); @@ -521,11 +523,11 @@ void WM_exit_ext(bContext *C, const bool do_python) BLF_free_unifont_mono(); BLT_lang_free(); #endif - + ANIM_keyingset_infos_exit(); - + // free_txt_data(); - + #ifdef WITH_PYTHON /* option not to close python so we can use 'atexit' */ @@ -549,11 +551,11 @@ void WM_exit_ext(bContext *C, const bool do_python) BKE_blender_userdef_data_free(&U, false); RNA_exit(); /* should be after BPY_python_end so struct python slots are cleared */ - + wm_ghost_exit(); CTX_free(C); - + GHOST_DisposeSystemPaths(); DNA_sdna_current_free(); diff --git a/source/blender/windowmanager/intern/wm_jobs.c b/source/blender/windowmanager/intern/wm_jobs.c index 28f978909f7..3a4195ae1ae 100644 --- a/source/blender/windowmanager/intern/wm_jobs.c +++ b/source/blender/windowmanager/intern/wm_jobs.c @@ -78,10 +78,10 @@ struct wmJob { struct wmJob *next, *prev; - + /* job originating from, keep track of this when deleting windows */ wmWindow *win; - + /* should store entire own context, for start, update, free */ void *customdata; /* to prevent cpu overhead, use this one which only gets called when job really starts, not in thread */ @@ -95,14 +95,14 @@ struct wmJob { void (*free)(void *); /* gets called when job is stopped, not in thread */ void (*endjob)(void *); - + /* running jobs each have own timer */ double timestep; wmTimer *wt; /* the notifier event timers should send */ unsigned int note, endnote; - - + + /* internal */ void *owner; int flag; @@ -115,7 +115,7 @@ struct wmJob { /* once running, we store this separately */ void *run_customdata; void (*run_free)(void *); - + /* we use BLI_threads api, but per job only 1 thread runs */ ListBase threads; @@ -152,7 +152,7 @@ static void wm_job_main_thread_yield(wmJob *wm_job) static wmJob *wm_job_find(wmWindowManager *wm, void *owner, const int job_type) { wmJob *wm_job; - + if (owner && job_type) { for (wm_job = wm->jobs.first; wm_job; wm_job = wm_job->next) if (wm_job->owner == owner && wm_job->job_type == job_type) @@ -168,7 +168,7 @@ static wmJob *wm_job_find(wmWindowManager *wm, void *owner, const int job_type) if (wm_job->job_type == job_type) return wm_job; } - + return NULL; } @@ -183,7 +183,7 @@ static wmJob *wm_job_find(wmWindowManager *wm, void *owner, const int job_type) wmJob *WM_jobs_get(wmWindowManager *wm, wmWindow *win, void *owner, const char *name, int flag, int job_type) { wmJob *wm_job = wm_job_find(wm, owner, job_type); - + if (wm_job == NULL) { wm_job = MEM_callocN(sizeof(wmJob), "new job"); @@ -198,7 +198,7 @@ wmJob *WM_jobs_get(wmWindowManager *wm, wmWindow *win, void *owner, const char * WM_job_main_thread_lock_acquire(wm_job); } /* else: a running job, be careful */ - + /* prevent creating a job with an invalid type */ BLI_assert(wm_job->job_type != WM_JOB_TYPE_ANY); @@ -209,7 +209,7 @@ wmJob *WM_jobs_get(wmWindowManager *wm, wmWindow *win, void *owner, const char * bool WM_jobs_test(wmWindowManager *wm, void *owner, int job_type) { wmJob *wm_job; - + /* job can be running or about to run (suspended) */ for (wm_job = wm->jobs.first; wm_job; wm_job = wm_job->next) { if (wm_job->owner == owner) { @@ -227,10 +227,10 @@ bool WM_jobs_test(wmWindowManager *wm, void *owner, int job_type) float WM_jobs_progress(wmWindowManager *wm, void *owner) { wmJob *wm_job = wm_job_find(wm, owner, WM_JOB_TYPE_ANY); - + if (wm_job && wm_job->flag & WM_JOB_PROGRESS) return wm_job->progress; - + return 0.0; } @@ -248,30 +248,30 @@ double WM_jobs_starttime(wmWindowManager *wm, void *owner) char *WM_jobs_name(wmWindowManager *wm, void *owner) { wmJob *wm_job = wm_job_find(wm, owner, WM_JOB_TYPE_ANY); - + if (wm_job) return wm_job->name; - + return NULL; } void *WM_jobs_customdata(wmWindowManager *wm, void *owner) { wmJob *wm_job = wm_job_find(wm, owner, WM_JOB_TYPE_ANY); - + if (wm_job) return WM_jobs_customdata_get(wm_job); - + return NULL; } void *WM_jobs_customdata_from_type(wmWindowManager *wm, int job_type) { wmJob *wm_job = wm_job_find(wm, NULL, job_type); - + if (wm_job) return WM_jobs_customdata_get(wm_job); - + return NULL; } @@ -301,7 +301,7 @@ void WM_jobs_customdata_set(wmJob *wm_job, void *customdata, void (*free)(void * /* pending job? just free */ if (wm_job->customdata) wm_job->free(wm_job->customdata); - + wm_job->customdata = customdata; wm_job->free = free; @@ -333,10 +333,10 @@ void WM_jobs_callbacks(wmJob *wm_job, static void *do_job_thread(void *job_v) { wmJob *wm_job = job_v; - + wm_job->startjob(wm_job->run_customdata, &wm_job->stop, &wm_job->do_update, &wm_job->progress); wm_job->ready = true; - + return NULL; } @@ -345,7 +345,7 @@ static void wm_jobs_test_suspend_stop(wmWindowManager *wm, wmJob *test) { wmJob *wm_job; bool suspend = false; - + /* job added with suspend flag, we wait 1 timer step before activating it */ if (test->flag & WM_JOB_SUSPEND) { suspend = true; @@ -358,12 +358,12 @@ static void wm_jobs_test_suspend_stop(wmWindowManager *wm, wmJob *test) if (wm_job == test || !wm_job->running) { continue; } - + /* if new job is not render, then check for same startjob */ if (0 == (test->flag & WM_JOB_EXCL_RENDER)) if (wm_job->startjob != test->startjob) continue; - + /* if new job is render, any render job should be stopped */ if (test->flag & WM_JOB_EXCL_RENDER) if (0 == (wm_job->flag & WM_JOB_EXCL_RENDER)) @@ -378,7 +378,7 @@ static void wm_jobs_test_suspend_stop(wmWindowManager *wm, wmJob *test) } } } - + /* Possible suspend ourselves, waiting for other jobs, or de-suspend. */ test->suspended = suspend; // if (suspend) printf("job suspended: %s\n", test->name); @@ -396,11 +396,11 @@ void WM_jobs_start(wmWindowManager *wm, wmJob *wm_job) // printf("job started a running job, ending... %s\n", wm_job->name); } else { - + if (wm_job->customdata && wm_job->startjob) { - + wm_jobs_test_suspend_stop(wm, wm_job); - + if (wm_job->suspended == false) { /* copy to ensure proper free in end */ wm_job->run_customdata = wm_job->customdata; @@ -408,20 +408,20 @@ void WM_jobs_start(wmWindowManager *wm, wmJob *wm_job) wm_job->free = NULL; wm_job->customdata = NULL; wm_job->running = true; - + if (wm_job->initjob) wm_job->initjob(wm_job->run_customdata); - + wm_job->stop = false; wm_job->ready = false; wm_job->progress = 0.0; // printf("job started: %s\n", wm_job->name); - + BLI_threadpool_init(&wm_job->threads, do_job_thread, 1); BLI_threadpool_insert(&wm_job->threads, wm_job); } - + /* restarted job has timer already */ if (wm_job->wt == NULL) wm_job->wt = WM_event_add_timer(wm, wm_job->win, TIMERJOBS, wm_job->timestep); @@ -456,14 +456,14 @@ static void wm_jobs_kill_job(wmWindowManager *wm, wmJob *wm_job) if (wm_job->endjob) wm_job->endjob(wm_job->run_customdata); } - + if (wm_job->wt) WM_event_remove_timer(wm, wm_job->win, wm_job->wt); if (wm_job->customdata) wm_job->free(wm_job->customdata); if (wm_job->run_customdata) wm_job->run_free(wm_job->run_customdata); - + /* remove wm_job */ wm_job_free(wm, wm_job); } @@ -472,17 +472,17 @@ static void wm_jobs_kill_job(wmWindowManager *wm, wmJob *wm_job) void WM_jobs_kill_all(wmWindowManager *wm) { wmJob *wm_job; - + while ((wm_job = wm->jobs.first)) wm_jobs_kill_job(wm, wm_job); - + } /* wait until every job ended, except for one owner (used in undo to keep screen job alive) */ void WM_jobs_kill_all_except(wmWindowManager *wm, void *owner) { wmJob *wm_job, *next_job; - + for (wm_job = wm->jobs.first; wm_job; wm_job = next_job) { next_job = wm_job->next; @@ -495,7 +495,7 @@ void WM_jobs_kill_all_except(wmWindowManager *wm, void *owner) void WM_jobs_kill_type(struct wmWindowManager *wm, void *owner, int job_type) { wmJob *wm_job, *next_job; - + for (wm_job = wm->jobs.first; wm_job; wm_job = next_job) { next_job = wm_job->next; @@ -509,7 +509,7 @@ void WM_jobs_kill_type(struct wmWindowManager *wm, void *owner, int job_type) void WM_jobs_stop(wmWindowManager *wm, void *owner, void *startjob) { wmJob *wm_job; - + for (wm_job = wm->jobs.first; wm_job; wm_job = wm_job->next) { if (wm_job->owner == owner || wm_job->startjob == startjob) { if (wm_job->running) { @@ -523,7 +523,7 @@ void WM_jobs_stop(wmWindowManager *wm, void *owner, void *startjob) void WM_jobs_kill(wmWindowManager *wm, void *owner, void (*startjob)(void *, short int *, short int *, float *)) { wmJob *wm_job; - + wm_job = wm->jobs.first; while (wm_job) { if (wm_job->owner == owner || wm_job->startjob == startjob) { @@ -542,7 +542,7 @@ void WM_jobs_kill(wmWindowManager *wm, void *owner, void (*startjob)(void *, sho void wm_jobs_timer_ended(wmWindowManager *wm, wmTimer *wt) { wmJob *wm_job; - + for (wm_job = wm->jobs.first; wm_job; wm_job = wm_job->next) { if (wm_job->wt == wt) { wm_jobs_kill_job(wm, wm_job); @@ -557,18 +557,18 @@ void wm_jobs_timer(const bContext *C, wmWindowManager *wm, wmTimer *wt) wmJob *wm_job, *wm_jobnext; float total_progress = 0.f; float jobs_progress = 0; - + for (wm_job = wm->jobs.first; wm_job; wm_job = wm_jobnext) { wm_jobnext = wm_job->next; - + if (wm_job->wt == wt) { - + /* running threads */ if (wm_job->threads.first) { /* let threads get temporary lock over main thread if needed */ wm_job_main_thread_yield(wm_job); - + /* always call note and update when ready */ if (wm_job->do_update || wm_job->ready) { if (wm_job->update) @@ -580,7 +580,7 @@ void wm_jobs_timer(const bContext *C, wmWindowManager *wm, wmTimer *wt) WM_event_add_notifier(C, NC_WM | ND_JOB, NULL); wm_job->do_update = false; } - + if (wm_job->ready) { if (wm_job->endjob) wm_job->endjob(wm_job->run_customdata); @@ -589,7 +589,7 @@ void wm_jobs_timer(const bContext *C, wmWindowManager *wm, wmTimer *wt) wm_job->run_free(wm_job->run_customdata); wm_job->run_customdata = NULL; wm_job->run_free = NULL; - + // if (wm_job->stop) printf("job ready but stopped %s\n", wm_job->name); // else printf("job finished %s\n", wm_job->name); @@ -603,10 +603,10 @@ void wm_jobs_timer(const bContext *C, wmWindowManager *wm, wmTimer *wt) WM_job_main_thread_lock_release(wm_job); BLI_threadpool_end(&wm_job->threads); WM_job_main_thread_lock_acquire(wm_job); - + if (wm_job->endnote) WM_event_add_notifier(C, wm_job->endnote, NULL); - + WM_event_add_notifier(C, NC_WM | ND_JOB, NULL); /* new job added for wm_job? */ @@ -617,7 +617,7 @@ void wm_jobs_timer(const bContext *C, wmWindowManager *wm, wmTimer *wt) else { WM_event_remove_timer(wm, wm_job->win, wm_job->wt); wm_job->wt = NULL; - + /* remove wm_job */ wm_job_free(wm, wm_job); } @@ -640,8 +640,8 @@ void wm_jobs_timer(const bContext *C, wmWindowManager *wm, wmTimer *wt) } } } - - + + /* if there are running jobs, set the global progress indicator */ if (jobs_progress > 0) { wmWindow *win; @@ -656,7 +656,7 @@ void wm_jobs_timer(const bContext *C, wmWindowManager *wm, wmTimer *wt) for (win = wm->windows.first; win; win = win->next) WM_progress_clear(win); } - + } bool WM_jobs_has_running(wmWindowManager *wm) diff --git a/source/blender/windowmanager/intern/wm_keymap.c b/source/blender/windowmanager/intern/wm_keymap.c index 1fcfcee0a4c..67493454e8f 100644 --- a/source/blender/windowmanager/intern/wm_keymap.c +++ b/source/blender/windowmanager/intern/wm_keymap.c @@ -238,7 +238,7 @@ static wmKeyMapDiffItem *wm_keymap_diff_item_copy(wmKeyMapDiffItem *kmdi) kmdin->add_item = wm_keymap_item_copy(kmdi->add_item); if (kmdi->remove_item) kmdin->remove_item = wm_keymap_item_copy(kmdi->remove_item); - + return kmdin; } @@ -261,7 +261,7 @@ static void wm_keymap_diff_item_free(wmKeyMapDiffItem *kmdi) wmKeyConfig *WM_keyconfig_new(wmWindowManager *wm, const char *idname) { wmKeyConfig *keyconf; - + keyconf = MEM_callocN(sizeof(wmKeyConfig), "wmKeyConfig"); BLI_strncpy(keyconf->idname, idname, sizeof(keyconf->idname)); BLI_addtail(&wm->keyconfigs, keyconf); @@ -316,7 +316,7 @@ static wmKeyConfig *WM_keyconfig_active(wmWindowManager *wm) keyconf = BLI_findstring(&wm->keyconfigs, U.keyconfigstr, offsetof(wmKeyConfig, idname)); if (keyconf) return keyconf; - + /* otherwise use default */ return wm->defaultconf; } @@ -457,16 +457,16 @@ static void keymap_item_set_id(wmKeyMap *keymap, wmKeyMapItem *kmi) wmKeyMapItem *WM_keymap_verify_item(wmKeyMap *keymap, const char *idname, int type, int val, int modifier, int keymodifier) { wmKeyMapItem *kmi; - + for (kmi = keymap->items.first; kmi; kmi = kmi->next) if (STREQLEN(kmi->idname, idname, OP_MAX_TYPENAME)) break; if (kmi == NULL) { kmi = MEM_callocN(sizeof(wmKeyMapItem), "keymap entry"); - + BLI_addtail(&keymap->items, kmi); BLI_strncpy(kmi->idname, idname, OP_MAX_TYPENAME); - + keymap_item_set_id(keymap, kmi); keymap_event_set(kmi, type, val, modifier, keymodifier); @@ -479,7 +479,7 @@ wmKeyMapItem *WM_keymap_verify_item(wmKeyMap *keymap, const char *idname, int ty wmKeyMapItem *WM_keymap_add_item(wmKeyMap *keymap, const char *idname, int type, int val, int modifier, int keymodifier) { wmKeyMapItem *kmi = MEM_callocN(sizeof(wmKeyMapItem), "keymap entry"); - + BLI_addtail(&keymap->items, kmi); BLI_strncpy(kmi->idname, idname, OP_MAX_TYPENAME); @@ -557,7 +557,7 @@ static wmKeyMapItem *wm_keymap_find_item_equals(wmKeyMap *km, wmKeyMapItem *need for (kmi = km->items.first; kmi; kmi = kmi->next) if (wm_keymap_item_equals(kmi, needle)) return kmi; - + return NULL; } @@ -568,7 +568,7 @@ static wmKeyMapItem *wm_keymap_find_item_equals_result(wmKeyMap *km, wmKeyMapIte for (kmi = km->items.first; kmi; kmi = kmi->next) if (wm_keymap_item_equals_result(kmi, needle)) return kmi; - + return NULL; } @@ -731,7 +731,7 @@ static wmKeyMap *wm_keymap_patch_update(ListBase *lb, wmKeyMap *defaultmap, wmKe /* add to list */ BLI_addtail(lb, km); - + return km; } @@ -779,7 +779,7 @@ static void wm_keymap_diff_update(ListBase *lb, wmKeyMap *defaultmap, wmKeyMap * /* ****************** storage in WM ************ */ -/* name id's are for storing general or multiple keymaps, +/* name id's are for storing general or multiple keymaps, * space/region ids are same as DNA_space_types.h */ /* gets freed in wm.c */ @@ -791,21 +791,21 @@ wmKeyMap *WM_keymap_list_find(ListBase *lb, const char *idname, int spaceid, int if (km->spaceid == spaceid && km->regionid == regionid) if (STREQLEN(idname, km->idname, KMAP_MAX_NAME)) return km; - + return NULL; } wmKeyMap *WM_keymap_find(wmKeyConfig *keyconf, const char *idname, int spaceid, int regionid) { wmKeyMap *km = WM_keymap_list_find(&keyconf->keymaps, idname, spaceid, regionid); - + if (km == NULL) { km = wm_keymap_new(idname, spaceid, regionid); BLI_addtail(&keyconf->keymaps, km); WM_keyconfig_update_tag(km, NULL); } - + return km; } @@ -838,19 +838,19 @@ wmKeyMap *WM_modalkeymap_add(wmKeyConfig *keyconf, const char *idname, const Enu } } } - + return km; } wmKeyMap *WM_modalkeymap_get(wmKeyConfig *keyconf, const char *idname) { wmKeyMap *km; - + for (km = keyconf->keymaps.first; km; km = km->next) if (km->flag & KEYMAP_MODAL) if (STREQLEN(idname, km->idname, KMAP_MAX_NAME)) break; - + return km; } @@ -858,10 +858,10 @@ wmKeyMap *WM_modalkeymap_get(wmKeyConfig *keyconf, const char *idname) wmKeyMapItem *WM_modalkeymap_add_item(wmKeyMap *km, int type, int val, int modifier, int keymodifier, int value) { wmKeyMapItem *kmi = MEM_callocN(sizeof(wmKeyMapItem), "keymap entry"); - + BLI_addtail(&km->items, kmi); kmi->propvalue = value; - + keymap_event_set(kmi, type, val, modifier, keymodifier); keymap_item_set_id(km, kmi); @@ -1129,7 +1129,7 @@ static wmKeyMapItem *wm_keymap_item_find_handlers( /* skip disabled keymap items [T38447] */ if (kmi->flag & KMI_INACTIVE) continue; - + if (STREQ(kmi->idname, opname) && WM_key_event_string(kmi->type, false)[0]) { if (is_hotkey) { if (!ISHOTKEY(kmi->type)) @@ -1197,7 +1197,7 @@ static wmKeyMapItem *wm_keymap_item_find_handlers( } } } - + /* ensure un-initialized keymap is never used */ if (r_keymap) *r_keymap = NULL; return NULL; @@ -1231,7 +1231,7 @@ static wmKeyMapItem *wm_keymap_item_find_props( if (sa) { if (!(ar && ar->regiontype == RGN_TYPE_WINDOW)) ar = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW); - + if (ar) found = wm_keymap_item_find_handlers(C, &ar->handlers, opname, opcontext, properties, is_strict, is_hotkey, r_keymap); } @@ -1447,7 +1447,7 @@ static bool wm_keymap_test_and_clear_update(wmKeyMap *km) { wmKeyMapItem *kmi; int update; - + update = (km->flag & KEYMAP_UPDATE); km->flag &= ~KEYMAP_UPDATE; @@ -1455,7 +1455,7 @@ static bool wm_keymap_test_and_clear_update(wmKeyMap *km) update = update || (kmi->flag & KMI_UPDATE); kmi->flag &= ~KMI_UPDATE; } - + return (update != 0); } @@ -1513,7 +1513,7 @@ void WM_keyconfig_update(wmWindowManager *wm) if (wm_keymap_update_flag == 0) return; - + /* update operator properties for non-modal user keymaps */ for (km = U.user_keymaps.first; km; km = km->next) { if ((km->flag & KEYMAP_MODAL) == 0) { @@ -1586,7 +1586,7 @@ wmKeyMap *WM_keymap_active(wmWindowManager *wm, wmKeyMap *keymap) if (!keymap) return NULL; - + /* first user defined keymaps */ km = WM_keymap_list_find(&wm->userconf->keymaps, keymap->idname, keymap->spaceid, keymap->regionid); @@ -1678,13 +1678,13 @@ void WM_keymap_restore_to_default(wmKeyMap *keymap, bContext *C) wmKeyMapItem *WM_keymap_item_find_id(wmKeyMap *keymap, int id) { wmKeyMapItem *kmi; - + for (kmi = keymap->items.first; kmi; kmi = kmi->next) { if (kmi->id == id) { return kmi; } } - + return NULL; } @@ -1708,7 +1708,7 @@ wmKeyMap *WM_keymap_guess_opname(const bContext *C, const char *opname) wmKeyMap *km = NULL; SpaceLink *sl = CTX_wm_space_data(C); - + /* Window */ if (STRPREFIX(opname, "WM_OT")) { km = WM_keymap_find_all(C, "Window", 0, 0); @@ -1735,8 +1735,8 @@ wmKeyMap *WM_keymap_guess_opname(const bContext *C, const char *opname) { km = WM_keymap_find_all(C, "Window", 0, 0); } - - + + /* 3D View */ else if (STRPREFIX(opname, "VIEW3D_OT")) { km = WM_keymap_find_all(C, "3D View", sl->spacetype, 0); @@ -1756,11 +1756,11 @@ wmKeyMap *WM_keymap_guess_opname(const bContext *C, const char *opname) { km = WM_keymap_find_all(C, "Object Mode", 0, 0); } - + /* Editing Modes */ else if (STRPREFIX(opname, "MESH_OT")) { km = WM_keymap_find_all(C, "Mesh", 0, 0); - + /* some mesh operators are active in object mode too, like add-prim */ if (km && !WM_keymap_poll((bContext *)C, km)) { km = WM_keymap_find_all(C, "Object Mode", 0, 0); @@ -1770,7 +1770,7 @@ wmKeyMap *WM_keymap_guess_opname(const bContext *C, const char *opname) STRPREFIX(opname, "SURFACE_OT")) { km = WM_keymap_find_all(C, "Curve", 0, 0); - + /* some curve operators are active in object mode too, like add-prim */ if (km && !WM_keymap_poll((bContext *)C, km)) { km = WM_keymap_find_all(C, "Object Mode", 0, 0); @@ -1798,7 +1798,7 @@ wmKeyMap *WM_keymap_guess_opname(const bContext *C, const char *opname) } else if (STRPREFIX(opname, "MBALL_OT")) { km = WM_keymap_find_all(C, "Metaball", 0, 0); - + /* some mball operators are active in object mode too, like add-prim */ if (km && !WM_keymap_poll((bContext *)C, km)) { km = WM_keymap_find_all(C, "Object Mode", 0, 0); @@ -1939,7 +1939,7 @@ wmKeyMap *WM_keymap_guess_opname(const bContext *C, const char *opname) break; } } - + return km; } diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c index 965c3115199..926e87cc3b4 100644 --- a/source/blender/windowmanager/intern/wm_operators.c +++ b/source/blender/windowmanager/intern/wm_operators.c @@ -252,15 +252,15 @@ static int wm_macro_exec(bContext *C, wmOperator *op) { wmOperator *opm; int retval = OPERATOR_FINISHED; - + wm_macro_start(op); for (opm = op->macro.first; opm; opm = opm->next) { - + if (opm->type->exec) { retval = opm->type->exec(C, opm); OPERATOR_RETVAL_CHECK(retval); - + if (retval & OPERATOR_FINISHED) { MacroData *md = op->customdata; md->retval = OPERATOR_FINISHED; /* keep in mind that at least one operator finished */ @@ -273,7 +273,7 @@ static int wm_macro_exec(bContext *C, wmOperator *op) CLOG_WARN(WM_LOG_OPERATORS, "'%s' cant exec macro", opm->type->idname); } } - + return wm_macro_end(op, retval); } @@ -291,7 +291,7 @@ static int wm_macro_invoke_internal(bContext *C, wmOperator *op, const wmEvent * OPERATOR_RETVAL_CHECK(retval); BLI_movelisttolist(&op->reports->list, &opm->reports->list); - + if (retval & OPERATOR_FINISHED) { MacroData *md = op->customdata; md->retval = OPERATOR_FINISHED; /* keep in mind that at least one operator finished */ @@ -314,7 +314,7 @@ static int wm_macro_modal(bContext *C, wmOperator *op, const wmEvent *event) { wmOperator *opm = op->opm; int retval = OPERATOR_FINISHED; - + if (opm == NULL) { CLOG_ERROR(WM_LOG_OPERATORS, "macro error, calling NULL modal()"); } @@ -389,20 +389,20 @@ wmOperatorType *WM_operatortype_append_macro(const char *idname, const char *nam { wmOperatorType *ot; const char *i18n_context; - + if (WM_operatortype_find(idname, true)) { CLOG_ERROR(WM_LOG_OPERATORS, "operator %s exists, cannot create macro", idname); return NULL; } - + ot = MEM_callocN(sizeof(wmOperatorType), "operatortype"); ot->srna = RNA_def_struct_ptr(&BLENDER_RNA, "", &RNA_OperatorProperties); - + ot->idname = idname; ot->name = name; ot->description = description; ot->flag = OPTYPE_MACRO | flag; - + ot->exec = wm_macro_exec; ot->invoke = wm_macro_invoke; ot->modal = wm_macro_modal; @@ -411,7 +411,7 @@ wmOperatorType *WM_operatortype_append_macro(const char *idname, const char *nam if (!ot->description) /* XXX All ops should have a description but for now allow them not to. */ ot->description = UNDOCUMENTED_OPERATOR_TIP; - + RNA_def_struct_ui_text(ot->srna, ot->name, ot->description); RNA_def_struct_identifier(&BLENDER_RNA, ot->srna, ot->idname); /* Use i18n context from ext.srna if possible (py operators). */ @@ -479,7 +479,7 @@ wmOperatorTypeMacro *WM_operatortype_macro_define(wmOperatorType *ot, const char static void wm_operatortype_free_macro(wmOperatorType *ot) { wmOperatorTypeMacro *otmacro; - + for (otmacro = ot->macro.first; otmacro; otmacro = otmacro->next) { if (otmacro->ptr) { WM_operator_properties_free(otmacro->ptr); @@ -598,7 +598,7 @@ void WM_operator_py_idname(char *to, const char *from) const char *sep = strstr(from, "_OT_"); if (sep) { int ofs = (sep - from); - + /* note, we use ascii tolower instead of system tolower, because the * latter depends on the locale, and can lead to idname mismatch */ memcpy(to, from, sizeof(char) * ofs); @@ -1317,7 +1317,7 @@ int WM_operator_confirm_message_ex(bContext *C, wmOperator *op, layout = UI_popup_menu_layout(pup); uiItemFullO_ptr(layout, op->type, message, ICON_NONE, properties, WM_OP_EXEC_REGION_WIN, 0, NULL); UI_popup_menu_end(C, pup); - + return OPERATOR_INTERFACE; } @@ -1437,7 +1437,7 @@ ID *WM_operator_drop_load_path(struct bContext *C, wmOperator *op, const short i if (is_relative_path ) { if (exists == false) { if (idcode == ID_IM) { - BLI_path_rel(((Image *)id)->name, bmain->name); + BLI_path_rel(((Image *)id)->name, BKE_main_blendfile_path(bmain)); } else { BLI_assert(0); @@ -1522,7 +1522,7 @@ static uiBlock *wm_block_create_redo(bContext *C, ARegion *ar, void *arg_op) uiTemplateOperatorPropertyButs(C, layout, op, NULL, UI_BUT_LABEL_ALIGN_SPLIT_COLUMN, UI_TEMPLATE_OP_PROPS_SHOW_TITLE); } - + UI_block_bounds_set_popup(block, 4, 0, 0); return block; @@ -1588,10 +1588,10 @@ static uiBlock *wm_block_dialog_create(bContext *C, ARegion *ar, void *userData) UI_block_flag_enable(block, UI_BLOCK_KEEP_OPEN | UI_BLOCK_NUMSELECT); layout = UI_block_layout(block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 0, 0, data->width, data->height, 0, style); - + uiTemplateOperatorPropertyButs(C, layout, op, NULL, UI_BUT_LABEL_ALIGN_SPLIT_COLUMN, UI_TEMPLATE_OP_PROPS_SHOW_TITLE); - + /* clear so the OK button is left alone */ UI_block_func_set(block, NULL, NULL, NULL); @@ -1663,7 +1663,7 @@ static void wm_operator_ui_popup_ok(struct bContext *C, void *arg, int retval) if (op && retval > 0) WM_operator_call_ex(C, op, true); - + MEM_freeN(data); } @@ -1739,7 +1739,7 @@ int WM_operator_props_popup(bContext *C, wmOperator *op, const wmEvent *UNUSED(e int WM_operator_props_dialog_popup(bContext *C, wmOperator *op, int width, int height) { wmOpPopUp *data = MEM_callocN(sizeof(wmOpPopUp), "WM_operator_props_dialog_popup"); - + data->op = op; data->width = width; data->height = height; @@ -1763,7 +1763,7 @@ int WM_operator_redo_popup(bContext *C, wmOperator *op) BKE_reportf(CTX_wm_reports(C), RPT_ERROR, "Operator redo '%s': wrong context", op->type->idname); return OPERATOR_CANCELLED; } - + UI_popup_block_invoke(C, wm_block_create_redo, op); return OPERATOR_CANCELLED; @@ -1791,11 +1791,11 @@ static void WM_OT_debug_menu(wmOperatorType *ot) ot->name = "Debug Menu"; ot->idname = "WM_OT_debug_menu"; ot->description = "Open a popup to set the debug level"; - + ot->invoke = wm_debug_menu_invoke; ot->exec = wm_debug_menu_exec; ot->poll = WM_operator_winactive; - + RNA_def_int(ot->srna, "debug_value", 0, SHRT_MIN, SHRT_MAX, "Debug Value", "", -10000, 10000); } @@ -1898,7 +1898,7 @@ static uiBlock *wm_block_create_splash(bContext *C, ARegion *ar, void *UNUSED(ar /* Builds made from tag only shows tag sha */ BLI_snprintf(hash_buf, sizeof(hash_buf), "Hash: %s", build_hash); BLI_snprintf(date_buf, sizeof(date_buf), "Date: %s %s", build_commit_date, build_commit_time); - + BLF_size(style->widgetlabel.uifont_id, style->widgetlabel.points, U.pixelsize * U.dpi); hash_width = (int)BLF_width(style->widgetlabel.uifont_id, hash_buf, sizeof(hash_buf)) + U.widget_unit; date_width = (int)BLF_width(style->widgetlabel.uifont_id, date_buf, sizeof(date_buf)) + U.widget_unit; @@ -2011,9 +2011,9 @@ static uiBlock *wm_block_create_splash(bContext *C, ARegion *ar, void *UNUSED(ar UI_but_flag_enable(but, 1); } #endif /* WITH_BUILDINFO */ - + layout = UI_block_layout(block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 10, 2, U.pixelsize * 480, U.pixelsize * 110, 0, style); - + UI_block_emboss_set(block, UI_EMBOSS); /* show the splash menu (containing interaction presets), using python */ if (mt) { @@ -2022,10 +2022,10 @@ static uiBlock *wm_block_create_splash(bContext *C, ARegion *ar, void *UNUSED(ar // wmWindowManager *wm = CTX_wm_manager(C); // uiItemM(layout, C, "USERPREF_MT_keyconfigs", U.keyconfigstr, ICON_NONE); } - + UI_block_emboss_set(block, UI_EMBOSS_PULLDOWN); uiLayoutSetOperatorContext(layout, WM_OP_EXEC_REGION_WIN); - + split = uiLayoutSplit(layout, 0.0f, false); col = uiLayoutColumn(split, false); uiItemL(col, IFACE_("Links"), ICON_NONE); @@ -2071,21 +2071,21 @@ static uiBlock *wm_block_create_splash(bContext *C, ARegion *ar, void *UNUSED(ar uiItemS(col); uiItemO(col, NULL, ICON_RECOVER_LAST, "WM_OT_recover_last_session"); uiItemL(col, "", ICON_NONE); - + mt = WM_menutype_find("USERPREF_MT_splash_footer", false); if (mt) { UI_menutype_draw(C, mt, uiLayoutColumn(layout, false)); } UI_block_bounds_set_centered(block, 0); - + return block; } static int wm_splash_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNUSED(event)) { UI_popup_block_invoke(C, wm_block_create_splash, NULL); - + return OPERATOR_FINISHED; } @@ -2094,7 +2094,7 @@ static void WM_OT_splash(wmOperatorType *ot) ot->name = "Splash Screen"; ot->idname = "WM_OT_splash"; ot->description = "Open the splash screen with release info"; - + ot->invoke = wm_splash_invoke; ot->poll = WM_operator_winactive; } @@ -2114,26 +2114,26 @@ static uiBlock *wm_block_search_menu(bContext *C, ARegion *ar, void *userdata) wmWindow *win = CTX_wm_window(C); uiBlock *block; uiBut *but; - + block = UI_block_begin(C, ar, "_popup", UI_EMBOSS); UI_block_flag_enable(block, UI_BLOCK_LOOP | UI_BLOCK_MOVEMOUSE_QUIT | UI_BLOCK_SEARCH_MENU); - + but = uiDefSearchBut(block, search, 0, ICON_VIEWZOOM, sizeof(search), 10, 10, init_data->size[0], UI_UNIT_Y, 0, 0, ""); UI_but_func_operator_search(but); - + /* fake button, it holds space for search items */ uiDefBut(block, UI_BTYPE_LABEL, 0, "", 10, 10 - init_data->size[1], init_data->size[0], init_data->size[1], NULL, 0, 0, 0, 0, NULL); - + UI_block_bounds_set_popup(block, 6, 0, -UI_UNIT_Y); /* move it downwards, mouse over button */ - + wm_event_init_from_window(win, &event); event.type = EVT_BUT_OPEN; event.val = KM_PRESS; event.customdata = but; event.customdatafree = false; wm_event_add(win, &event); - + return block; } @@ -2152,7 +2152,7 @@ static int wm_search_menu_invoke(bContext *C, wmOperator *UNUSED(op), const wmEv }; UI_popup_block_invoke(C, wm_block_search_menu, &data); - + return OPERATOR_INTERFACE; } @@ -2181,7 +2181,7 @@ static void WM_OT_search_menu(wmOperatorType *ot) ot->name = "Search Menu"; ot->idname = "WM_OT_search_menu"; ot->description = "Pop-up a search menu over all available operators in current context"; - + ot->invoke = wm_search_menu_invoke; ot->exec = wm_search_menu_exec; ot->poll = wm_search_menu_poll; @@ -2246,8 +2246,9 @@ static int wm_call_panel_exec(bContext *C, wmOperator *op) RNA_string_get(op->ptr, "name", idname); const int space_type = RNA_enum_get(op->ptr, "space_type"); const int region_type = RNA_enum_get(op->ptr, "region_type"); + const bool keep_open = RNA_boolean_get(op->ptr, "keep_open"); - return UI_popover_panel_invoke(C, space_type, region_type, idname, true, op->reports); + return UI_popover_panel_invoke(C, space_type, region_type, idname, keep_open, op->reports); } static void WM_OT_call_panel(wmOperatorType *ot) @@ -2261,9 +2262,16 @@ static void WM_OT_call_panel(wmOperatorType *ot) ot->flag = OPTYPE_INTERNAL; - RNA_def_string(ot->srna, "name", NULL, BKE_ST_MAXNAME, "Name", "Name of the menu"); - RNA_def_enum(ot->srna, "space_type", rna_enum_space_type_items, SPACE_EMPTY, "Space Type", ""); - RNA_def_enum(ot->srna, "region_type", rna_enum_region_type_items, RGN_TYPE_WINDOW, "Region Type", ""); + PropertyRNA *prop; + + prop = RNA_def_string(ot->srna, "name", NULL, BKE_ST_MAXNAME, "Name", "Name of the menu"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + prop = RNA_def_enum(ot->srna, "space_type", rna_enum_space_type_items, SPACE_EMPTY, "Space Type", ""); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + prop = RNA_def_enum(ot->srna, "region_type", rna_enum_region_type_items, RGN_TYPE_WINDOW, "Region Type", ""); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + prop = RNA_def_boolean(ot->srna, "keep_open", true, "Keep Open", ""); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); } /* ************ window / screen operator definitions ************** */ @@ -2364,7 +2372,7 @@ static void WM_OT_console_toggle(wmOperatorType *ot) ot->name = CTX_N_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Toggle System Console"); ot->idname = "WM_OT_console_toggle"; ot->description = N_("Toggle System Console"); - + ot->exec = wm_console_toggle_exec; ot->poll = WM_operator_winactive; } @@ -2382,20 +2390,20 @@ void *WM_paint_cursor_activate(wmWindowManager *wm, int (*poll)(bContext *C), wmPaintCursorDraw draw, void *customdata) { wmPaintCursor *pc = MEM_callocN(sizeof(wmPaintCursor), "paint cursor"); - + BLI_addtail(&wm->paintcursors, pc); - + pc->customdata = customdata; pc->poll = poll; pc->draw = draw; - + return pc; } void WM_paint_cursor_end(wmWindowManager *wm, void *handle) { wmPaintCursor *pc; - + for (pc = wm->paintcursors.first; pc; pc = pc->next) { if (pc == (wmPaintCursor *)handle) { BLI_remlink(&wm->paintcursors, pc); @@ -2438,7 +2446,7 @@ static void radial_control_update_header(wmOperator *op, bContext *C) char msg[UI_MAX_DRAW_STR]; ScrArea *sa = CTX_wm_area(C); Scene *scene = CTX_data_scene(C); - + if (sa) { if (hasNumInput(&rc->num_input)) { char num_str[NUM_STR_REP_LEN]; @@ -2555,7 +2563,7 @@ static void radial_control_paint_tex(RadialControl *rc, float radius, float alph RNA_property_float_get_array(fill_ptr, fill_prop, col); } - + Gwn_VertFormat *format = immVertexFormat(); unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); @@ -2592,10 +2600,10 @@ static void radial_control_paint_tex(RadialControl *rc, float radius, float alph immAttrib2f(texCoord, 1, 0); immVertex2f(pos, radius, -radius); - + immAttrib2f(texCoord, 1, 1); immVertex2f(pos, radius, radius); - + immAttrib2f(texCoord, 0, 1); immVertex2f(pos, -radius, radius); @@ -2611,7 +2619,7 @@ static void radial_control_paint_tex(RadialControl *rc, float radius, float alph immUniformColor3fvAlpha(col, alpha); imm_draw_circle_fill_2d(pos, 0.0f, 0.0f, radius, 40); } - + immUnbindProgram(); } @@ -2626,7 +2634,7 @@ static void radial_control_paint_cursor(bContext *UNUSED(C), int x, int y, void short strdrawlen = 0; float strwidth, strheight; float r1 = 0.0f, r2 = 0.0f, rmin = 0.0, tex_radius, alpha; - float zoom[2], col[3] = {1, 1, 1}; + float zoom[2], col[3] = {1, 1, 1}; switch (rc->subtype) { case PROP_NONE: @@ -2800,7 +2808,7 @@ static int radial_control_get_path( return 0; } } - + /* check property's array length */ if (*r_prop && (len = RNA_property_array_length(r_ptr, *r_prop)) != req_length) { MEM_freeN(str); @@ -2849,7 +2857,7 @@ static int radial_control_get_properties(bContext *C, wmOperator *op) /* data path is required */ if (!rc->prop) return 0; - + if (!radial_control_get_path(&ctx_ptr, op, "rotation_path", &rc->rot_ptr, &rc->rot_prop, 0, RC_PROP_REQUIRE_FLOAT)) return 0; if (!radial_control_get_path(&ctx_ptr, op, "color_path", &rc->col_ptr, &rc->col_prop, 3, RC_PROP_REQUIRE_FLOAT)) @@ -2884,7 +2892,7 @@ static int radial_control_get_properties(bContext *C, wmOperator *op) { return 0; } - + if (!radial_control_get_path(&ctx_ptr, op, "image_id", &rc->image_id_ptr, NULL, 0, 0)) return 0; else if (rc->image_id_ptr.data) { @@ -3007,7 +3015,7 @@ static void radial_control_cancel(bContext *C, wmOperator *op) if (sa) { ED_area_headerprint(sa, NULL); } - + WM_paint_cursor_end(wm, rc->cursor); /* restore original paint cursors */ @@ -3048,10 +3056,10 @@ static int radial_control_modal(bContext *C, wmOperator *op, const wmEvent *even if (numValue < 0.0f) numValue += 2.0f * (float)M_PI; } - + CLAMP(numValue, rc->min_value, rc->max_value); new_value = numValue; - + radial_control_set_value(rc, new_value); rc->current_value = new_value; radial_control_update_header(op, C); @@ -3202,9 +3210,9 @@ static int radial_control_modal(bContext *C, wmOperator *op, const wmEvent *even CLAMP(numValue, rc->min_value, rc->max_value); new_value = numValue; - + radial_control_set_value(rc, new_value); - + rc->current_value = new_value; radial_control_update_header(op, C); return OPERATOR_RUNNING_MODAL; @@ -3408,7 +3416,7 @@ static int redraw_timer_exec(bContext *C, wmOperator *op) a = 0; } } - + time_delta = (PIL_check_seconds_timer() - time_start) * 1000; RNA_enum_description(redraw_timer_type_items, type, &infostr); @@ -3418,7 +3426,7 @@ static int redraw_timer_exec(bContext *C, wmOperator *op) BKE_reportf(op->reports, RPT_WARNING, "%d x %s: %.4f ms, average: %.8f ms", iter_steps, infostr, time_delta, time_delta / iter_steps); - + return OPERATOR_FINISHED; } @@ -3452,7 +3460,7 @@ static void WM_OT_memory_statistics(wmOperatorType *ot) ot->name = "Memory Statistics"; ot->idname = "WM_OT_memory_statistics"; ot->description = "Print memory statistics to the console"; - + ot->exec = memory_statistics_exec; } @@ -3817,21 +3825,21 @@ static void gesture_straightline_modal_keymap(wmKeyConfig *keyconf) {GESTURE_MODAL_BEGIN, "BEGIN", 0, "Begin", ""}, {0, NULL, 0, NULL, NULL} }; - + wmKeyMap *keymap = WM_modalkeymap_get(keyconf, "Gesture Straight Line"); - + /* this function is called for each spacetype, only needs to add map once */ if (keymap && keymap->modal_items) return; - + keymap = WM_modalkeymap_add(keyconf, "Gesture Straight Line", modal_items); - + /* items for modal map */ WM_modalkeymap_add_item(keymap, ESCKEY, KM_PRESS, KM_ANY, 0, GESTURE_MODAL_CANCEL); WM_modalkeymap_add_item(keymap, RIGHTMOUSE, KM_ANY, KM_ANY, 0, GESTURE_MODAL_CANCEL); - + WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_PRESS, 0, 0, GESTURE_MODAL_BEGIN); WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_RELEASE, KM_ANY, 0, GESTURE_MODAL_SELECT); - + /* assign map to operators */ WM_modalkeymap_assign(keymap, "IMAGE_OT_sample_line"); WM_modalkeymap_assign(keymap, "PAINT_OT_weight_gradient"); @@ -3859,7 +3867,7 @@ static void gesture_border_modal_keymap(wmKeyConfig *keyconf) /* items for modal map */ WM_modalkeymap_add_item(keymap, ESCKEY, KM_PRESS, KM_ANY, 0, GESTURE_MODAL_CANCEL); - + /* Note: cancel only on press otherwise you cannot map this to RMB-gesture */ WM_modalkeymap_add_item(keymap, RIGHTMOUSE, KM_PRESS, KM_ANY, 0, GESTURE_MODAL_CANCEL); WM_modalkeymap_add_item(keymap, RIGHTMOUSE, KM_RELEASE, KM_ANY, 0, GESTURE_MODAL_SELECT); @@ -3871,10 +3879,10 @@ static void gesture_border_modal_keymap(wmKeyConfig *keyconf) /* any unhandled leftclick release handles select */ WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_PRESS, 0, 0, GESTURE_MODAL_BEGIN); WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_RELEASE, KM_ANY, 0, GESTURE_MODAL_SELECT); - + WM_modalkeymap_add_item(keymap, MIDDLEMOUSE, KM_PRESS, 0, 0, GESTURE_MODAL_BEGIN); WM_modalkeymap_add_item(keymap, MIDDLEMOUSE, KM_RELEASE, 0, 0, GESTURE_MODAL_DESELECT); - + /* assign map to operators */ WM_modalkeymap_assign(keymap, "ACTION_OT_select_border"); WM_modalkeymap_assign(keymap, "ANIM_OT_channels_select_border"); @@ -3928,7 +3936,7 @@ static void gesture_zoom_border_modal_keymap(wmKeyConfig *keyconf) WM_modalkeymap_add_item(keymap, RIGHTMOUSE, KM_ANY, KM_ANY, 0, GESTURE_MODAL_CANCEL); WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_PRESS, 0, 0, GESTURE_MODAL_BEGIN); - WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_RELEASE, 0, 0, GESTURE_MODAL_IN); + WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_RELEASE, 0, 0, GESTURE_MODAL_IN); WM_modalkeymap_add_item(keymap, MIDDLEMOUSE, KM_PRESS, 0, 0, GESTURE_MODAL_BEGIN); WM_modalkeymap_add_item(keymap, MIDDLEMOUSE, KM_RELEASE, 0, 0, GESTURE_MODAL_OUT); @@ -3944,7 +3952,7 @@ void wm_window_keymap(wmKeyConfig *keyconf) { wmKeyMap *keymap = WM_keymap_find(keyconf, "Window", 0, 0); wmKeyMapItem *kmi; - + /* note, this doesn't replace existing keymap items */ WM_keymap_verify_item(keymap, "WM_OT_window_new", WKEY, KM_PRESS, KM_CTRL | KM_ALT, 0); #ifdef __APPLE__ @@ -3956,7 +3964,7 @@ void wm_window_keymap(wmKeyConfig *keyconf) WM_keymap_add_item(keymap, "WM_OT_quit_blender", QKEY, KM_PRESS, KM_OSKEY, 0); #endif WM_keymap_add_item(keymap, "WM_OT_read_homefile", NKEY, KM_PRESS, KM_CTRL, 0); - WM_keymap_add_item(keymap, "WM_OT_save_homefile", UKEY, KM_PRESS, KM_CTRL, 0); + WM_keymap_add_item(keymap, "WM_OT_save_homefile", UKEY, KM_PRESS, KM_CTRL, 0); WM_keymap_add_menu(keymap, "INFO_MT_file_open_recent", OKEY, KM_PRESS, KM_SHIFT | KM_CTRL, 0); WM_keymap_add_item(keymap, "WM_OT_open_mainfile", OKEY, KM_PRESS, KM_CTRL, 0); WM_keymap_add_item(keymap, "WM_OT_open_mainfile", F1KEY, KM_PRESS, 0, 0); @@ -3981,7 +3989,7 @@ void wm_window_keymap(wmKeyConfig *keyconf) /* menus that can be accessed anywhere in blender */ - WM_keymap_verify_item(keymap, "WM_OT_search_menu", TABKEY, KM_PRESS, 0, 0); + WM_keymap_verify_item(keymap, "WM_OT_search_menu", ACCENTGRAVEKEY, KM_RELEASE, 0, 0); #ifdef WITH_INPUT_NDOF WM_keymap_add_menu(keymap, "USERPREF_MT_ndof_settings", NDOF_BUTTON_MENU, KM_PRESS, 0, 0); @@ -4029,7 +4037,7 @@ void wm_window_keymap(wmKeyConfig *keyconf) kmi = WM_keymap_add_item(keymap, "WM_OT_context_set_enum", F12KEY, KM_PRESS, KM_SHIFT, 0); RNA_string_set(kmi->ptr, "data_path", "area.type"); RNA_string_set(kmi->ptr, "value", "DOPESHEET_EDITOR"); - + #ifdef WITH_INPUT_NDOF /* ndof speed */ const char *data_path = "user_preferences.inputs.ndof_sensitivity"; diff --git a/source/blender/windowmanager/intern/wm_playanim.c b/source/blender/windowmanager/intern/wm_playanim.c index d6a1eb81981..d93d51df105 100644 --- a/source/blender/windowmanager/intern/wm_playanim.c +++ b/source/blender/windowmanager/intern/wm_playanim.c @@ -101,7 +101,7 @@ typedef struct PlayState { /* window and viewport size */ int win_x, win_y; - + /* current zoom level */ float zoom; @@ -122,7 +122,7 @@ typedef struct PlayState { bool loading; /* x/y image flip */ bool draw_flip[2]; - + int fstep; /* current picture */ @@ -134,7 +134,7 @@ typedef struct PlayState { /* saves passing args */ struct ImBuf *curframe_ibuf; - + /* restarts player for file drop */ char dropped_file[FILE_MAX]; } PlayState; @@ -946,13 +946,13 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr ps_void) { GHOST_TEventButtonData *bd = GHOST_GetEventData(evt); int cx, cy, sizex, sizey, inside_window; - + GHOST_GetCursorPosition(g_WS.ghost_system, &cx, &cy); GHOST_ScreenToClient(g_WS.ghost_window, cx, cy, &cx, &cy); playanim_window_get_size(&sizex, &sizey); inside_window = (cx >= 0 && cx < sizex && cy >= 0 && cy <= sizey); - + if (bd->button == GHOST_kButtonMaskLeft) { if (type == GHOST_kEventButtonDown) { if (inside_window) { @@ -1016,23 +1016,23 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr ps_void) case GHOST_kEventWindowMove: { float zoomx, zoomy; - + playanim_window_get_size(&ps->win_x, &ps->win_y); GHOST_ActivateWindowDrawingContext(g_WS.ghost_window); zoomx = (float) ps->win_x / ps->ibufx; zoomy = (float) ps->win_y / ps->ibufy; - + /* zoom always show entire image */ ps->zoom = MIN2(zoomx, zoomy); - + /* zoom steps of 2 for speed */ ps->zoom = floor(ps->zoom + 0.5f); if (ps->zoom < 1.0f) ps->zoom = 1.0f; - + glViewport(0, 0, ps->win_x, ps->win_y); glScissor(0, 0, ps->win_x, ps->win_y); - + playanim_gl_matrix(); ptottime = 0.0; @@ -1049,11 +1049,11 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr ps_void) case GHOST_kEventDraggingDropDone: { GHOST_TEventDragnDropData *ddd = GHOST_GetEventData(evt); - + if (ddd->dataType == GHOST_kDragnDropTypeFilenames) { GHOST_TStringArray *stra = ddd->data; int a; - + for (a = 0; a < stra->count; a++) { BLI_strncpy(ps->dropped_file, (char *)stra->strings[a], sizeof(ps->dropped_file)); ps->go = false; @@ -1120,7 +1120,7 @@ static char *wm_main_playanim_intern(int argc, const char **argv) int sfra = -1; int efra = -1; int totblock; - + PlayState ps = {0}; /* ps.doubleb = true;*/ /* UNUSED */ @@ -1271,14 +1271,14 @@ static char *wm_main_playanim_intern(int argc, const char **argv) ps.ibufx = ibuf->x; ps.ibufy = ibuf->y; - + ps.win_x = ps.ibufx; ps.win_y = ps.ibufy; if (maxwinx % ibuf->x) maxwinx = ibuf->x * (1 + (maxwinx / ibuf->x)); if (maxwiny % ibuf->y) maxwiny = ibuf->y * (1 + (maxwiny / ibuf->y)); - + glClearColor(0.1, 0.1, 0.1, 0.0); glClear(GL_COLOR_BUFFER_BIT); @@ -1547,7 +1547,7 @@ static char *wm_main_playanim_intern(int argc, const char **argv) BLI_strncpy(filepath, ps.dropped_file, sizeof(filepath)); return filepath; } - + IMB_exit(); BKE_images_exit(); DEG_free_node_types(); @@ -1560,7 +1560,7 @@ static char *wm_main_playanim_intern(int argc, const char **argv) MEM_printmemlist(); #endif } - + return NULL; } diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c index ca5f95909f8..e1528551c12 100644 --- a/source/blender/windowmanager/intern/wm_window.c +++ b/source/blender/windowmanager/intern/wm_window.c @@ -35,7 +35,7 @@ #include <stdio.h> #include <string.h> -#include "DNA_listBase.h" +#include "DNA_listBase.h" #include "DNA_screen_types.h" #include "DNA_windowmanager_types.h" #include "DNA_workspace_types.h" @@ -85,6 +85,7 @@ #include "GPU_framebuffer.h" #include "GPU_init_exit.h" #include "GPU_immediate.h" +#include "GPU_material.h" #include "GPU_texture.h" #include "BLF_api.h" @@ -113,7 +114,7 @@ static struct WMInitStruct { int windowstate; WinOverrideFlag override_flag; - + bool native_pixels; } wm_init_state = {0, 0, 0, 0, GHOST_kWindowStateNormal, 0, true}; @@ -125,7 +126,7 @@ void wm_get_screensize(int *r_width, int *r_height) { unsigned int uiwidth; unsigned int uiheight; - + GHOST_GetMainDisplayDimensions(g_system, &uiwidth, &uiheight); *r_width = uiwidth; *r_height = uiheight; @@ -147,9 +148,9 @@ void wm_get_desktopsize(int *r_width, int *r_height) static void wm_window_check_position(rcti *rect) { int width, height, d; - + wm_get_screensize(&width, &height); - + if (rect->xmin < 0) { rect->xmax -= rect->xmin; rect->xmin = 0; @@ -168,7 +169,7 @@ static void wm_window_check_position(rcti *rect) rect->ymax -= d; rect->ymin -= d; } - + if (rect->xmin < 0) rect->xmin = 0; if (rect->ymin < 0) rect->ymin = 0; } @@ -194,12 +195,12 @@ static void wm_ghostwindow_destroy(wmWindowManager *wm, wmWindow *win) } } -/* including window itself, C can be NULL. +/* including window itself, C can be NULL. * ED_screen_exit should have been called */ void wm_window_free(bContext *C, wmWindowManager *wm, wmWindow *win) { wmTimer *wt, *wtnext; - + /* update context */ if (C) { WM_event_remove_handlers(C, &win->handlers); @@ -217,7 +218,7 @@ void wm_window_free(bContext *C, wmWindowManager *wm, wmWindow *win) if (wt->win == win && wt->event_type == TIMERJOBS) wm_jobs_timer_ended(wm, wt); } - + /* timer removing, need to call this api function */ for (wt = wm->timers.first; wt; wt = wtnext) { wtnext = wt->next; @@ -226,7 +227,7 @@ void wm_window_free(bContext *C, wmWindowManager *wm, wmWindow *win) } if (win->eventstate) MEM_freeN(win->eventstate); - + wm_event_free_all(win); wm_ghostwindow_destroy(wm, win); @@ -241,11 +242,11 @@ static int find_free_winid(wmWindowManager *wm) { wmWindow *win; int id = 1; - + for (win = wm->windows.first; win; win = win->next) if (id <= win->winid) id = win->winid + 1; - + return id; } @@ -288,6 +289,7 @@ static wmWindow *wm_window_new_test(bContext *C) /* part of wm_window.c api */ wmWindow *wm_window_copy(bContext *C, wmWindow *win_src, const bool duplicate_layout) { + Main *bmain = CTX_data_main(C); wmWindow *win_dst = wm_window_new(C); WorkSpace *workspace = WM_window_get_active_workspace(win_src); WorkSpaceLayout *layout_old = WM_window_get_active_layout(win_src); @@ -301,7 +303,7 @@ wmWindow *wm_window_copy(bContext *C, wmWindow *win_src, const bool duplicate_la win_dst->scene = scene; WM_window_set_active_workspace(win_dst, workspace); - layout_new = duplicate_layout ? ED_workspace_layout_duplicate(workspace, layout_old, win_dst) : layout_old; + layout_new = duplicate_layout ? ED_workspace_layout_duplicate(bmain, workspace, layout_old, win_dst) : layout_old; WM_window_set_active_layout(win_dst, workspace, layout_new); *win_dst->stereo3d_format = *win_src->stereo3d_format; @@ -374,6 +376,7 @@ static void wm_block_confirm_quit_save(bContext *C, void *arg_block, void *UNUSE /* Build the confirm dialog UI */ static uiBlock *block_create_confirm_quit(struct bContext *C, struct ARegion *ar, void *UNUSED(arg1)) { + Main *bmain = CTX_data_main(C); uiStyle *style = UI_style_get(); uiBlock *block = UI_block_begin(C, ar, "confirm_quit_popup", UI_EMBOSS); @@ -387,11 +390,11 @@ static uiBlock *block_create_confirm_quit(struct bContext *C, struct ARegion *ar /* Text and some vertical space */ { char *message; - if (G.main->name[0] == '\0') { + if (BKE_main_blendfile_path(bmain)[0] == '\0') { message = BLI_strdup(IFACE_("This file has not been saved yet. Save before closing?")); } else { - const char *basename = BLI_path_basename(G.main->name); + const char *basename = BLI_path_basename(BKE_main_blendfile_path(bmain)); message = BLI_sprintfN(IFACE_("Save changes to \"%s\" before closing?"), basename); } uiItemL(layout, message, ICON_ERROR); @@ -484,7 +487,7 @@ void wm_quit_with_optional_confirmation_prompt(bContext *C, wmWindow *win) void wm_window_close(bContext *C, wmWindowManager *wm, wmWindow *win) { wmWindow *tmpwin; - + /* first check if we have to quit (there are non-temp remaining windows) */ for (tmpwin = wm->windows.first; tmpwin; tmpwin = tmpwin->next) { if (tmpwin == win) @@ -502,7 +505,7 @@ void wm_window_close(bContext *C, wmWindowManager *wm, wmWindow *win) WorkSpaceLayout *layout = BKE_workspace_active_layout_get(win->workspace_hook); BLI_remlink(&wm->windows, win); - + CTX_wm_window_set(C, win); /* needed by handlers */ WM_event_remove_handlers(C, &win->handlers); WM_event_remove_handlers(C, &win->modalhandlers); @@ -546,9 +549,10 @@ void wm_window_title(wmWindowManager *wm, wmWindow *win) } else if (win->ghostwin) { /* this is set to 1 if you don't have startup.blend open */ - if (G.save_over && G.main->name[0]) { - char str[sizeof(G.main->name) + 24]; - BLI_snprintf(str, sizeof(str), "Blender%s [%s%s]", wm->file_saved ? "" : "*", G.main->name, + if (G.save_over && BKE_main_blendfile_path_from_global()[0]) { + char str[sizeof(((Main *)NULL)->name) + 24]; + BLI_snprintf(str, sizeof(str), "Blender%s [%s%s]", wm->file_saved ? "" : "*", + BKE_main_blendfile_path_from_global(), G.main->recovered ? " (Recovered)" : ""); GHOST_SetTitle(win->ghostwin, str); } @@ -559,7 +563,7 @@ void wm_window_title(wmWindowManager *wm, wmWindow *win) * and to give hint of unsaved changes for a user warning mechanism * in case of OS application terminate request (e.g. OS Shortcut Alt+F4, Cmd+Q, (...), or session end) */ GHOST_SetWindowModifiedState(win->ghostwin, (GHOST_TUns8) !wm->file_saved); - + } } @@ -625,7 +629,7 @@ static void wm_window_ghostwindow_add(wmWindowManager *wm, const char *title, wm GHOST_WindowHandle ghostwin; GHOST_GLSettings glSettings = {0}; int scr_w, scr_h, posy; - + /* a new window is created when pageflip mode is required for a window */ if (win->stereo3d_format->display_mode == S3D_DISPLAY_PAGEFLIP) glSettings.flags |= GHOST_glStereoVisual; @@ -636,7 +640,7 @@ static void wm_window_ghostwindow_add(wmWindowManager *wm, const char *title, wm wm_get_screensize(&scr_w, &scr_h); posy = (scr_h - win->posy - win->sizey); - + ghostwin = GHOST_CreateWindow(g_system, title, win->posx, posy, win->sizex, win->sizey, (GHOST_TWindowState)win->windowstate, @@ -652,16 +656,16 @@ static void wm_window_ghostwindow_add(wmWindowManager *wm, const char *title, wm gpu_batch_presets_reset(); win->gwnctx = GWN_context_create(); - + /* the new window has already been made drawable upon creation */ wm->windrawable = win; /* needed so we can detect the graphics card below */ GPU_init(); - + win->ghostwin = ghostwin; GHOST_SetWindowUserData(ghostwin, win); /* pointer back */ - + wm_window_ensure_eventstate(win); /* store actual window size in blender window */ @@ -673,7 +677,7 @@ static void wm_window_ghostwindow_add(wmWindowManager *wm, const char *title, wm win->sizey = GHOST_GetHeightRectangle(bounds); } GHOST_DisposeRectangle(bounds); - + #ifndef __APPLE__ /* set the state here, so minimized state comes up correct on windows */ GHOST_SetWindowState(ghostwin, (GHOST_TWindowState)win->windowstate); @@ -684,14 +688,14 @@ static void wm_window_ghostwindow_add(wmWindowManager *wm, const char *title, wm if (!GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_UNIX, GPU_DRIVER_OPENSOURCE)) { glClear(GL_COLOR_BUFFER_BIT); } - + /* needed here, because it's used before it reads userdef */ WM_window_set_dpi(win); - + wm_window_swap_buffers(win); - + //GHOST_SetWindowState(ghostwin, GHOST_kWindowStateModified); - + /* standard state vars for window */ GPU_state_init(); } @@ -714,7 +718,7 @@ void wm_window_ghostwindows_ensure(wmWindowManager *wm) { wmKeyMap *keymap; wmWindow *win; - + BLI_assert(G.background == false); /* no commandline prefsize? then we set this. @@ -723,7 +727,7 @@ void wm_window_ghostwindows_ensure(wmWindowManager *wm) */ if (wm_init_state.size_x == 0) { wm_get_screensize(&wm_init_state.size_x, &wm_init_state.size_y); - + /* note!, this isnt quite correct, active screen maybe offset 1000s if PX, * we'd need a wm_get_screensize like function that gives offset, * in practice the window manager will likely move to the correct monitor */ @@ -741,7 +745,7 @@ void wm_window_ghostwindows_ensure(wmWindowManager *wm) wm_init_state.size_y -= WM_WIN_INIT_PAD * 2; #endif } - + for (win = wm->windows.first; win; win = win->next) { if (win->ghostwin == NULL) { if ((win->sizex == 0) || (wm_init_state.override_flag & WIN_OVERRIDE_GEOM)) { @@ -772,13 +776,13 @@ void wm_window_ghostwindows_ensure(wmWindowManager *wm) /* add keymap handlers (1 handler for all keys in map!) */ keymap = WM_keymap_find(wm->defaultconf, "Window", 0, 0); WM_event_add_keymap_handler(&win->handlers, keymap); - + keymap = WM_keymap_find(wm->defaultconf, "Screen", 0, 0); WM_event_add_keymap_handler(&win->handlers, keymap); keymap = WM_keymap_find(wm->defaultconf, "Screen Editing", 0, 0); WM_event_add_keymap_handler(&win->modalhandlers, keymap); - + /* add drop boxes */ { ListBase *lb = WM_dropboxmap_find("Window", 0, 0); @@ -821,7 +825,7 @@ wmWindow *WM_window_open(bContext *C, const rcti *rect) { wmWindow *win_prev = CTX_wm_window(C); wmWindow *win = wm_window_new(C); - + win->posx = rect->xmin; win->posy = rect->ymin; win->sizex = BLI_rcti_size_x(rect); @@ -872,16 +876,16 @@ wmWindow *WM_window_open_temp(bContext *C, int x, int y, int sizex, int sizey, i /* changes rect to fit within desktop */ wm_window_check_position(&rect); - + /* test if we have a temp screen already */ for (win = CTX_wm_manager(C)->windows.first; win; win = win->next) if (WM_window_is_temp_screen(win)) break; - + /* add new window? */ if (win == NULL) { win = wm_window_new(C); - + win->posx = rect.xmin; win->posy = rect.ymin; } @@ -904,7 +908,7 @@ wmWindow *WM_window_open_temp(bContext *C, int x, int y, int sizex, int sizey, i if (screen == NULL) { /* add new screen layout */ WorkSpace *workspace = WM_window_get_active_workspace(win); - WorkSpaceLayout *layout = ED_workspace_layout_add(workspace, win, "temp"); + WorkSpaceLayout *layout = ED_workspace_layout_add(bmain, workspace, win, "temp"); screen = BKE_workspace_layout_screen_get(layout); WM_window_set_active_layout(win, workspace, layout); @@ -933,7 +937,7 @@ wmWindow *WM_window_open_temp(bContext *C, int x, int y, int sizex, int sizey, i /* ensure it shows the right spacetype editor */ sa = screen->areabase.first; CTX_wm_area_set(C, sa); - + if (type == WM_WINDOW_RENDER) { ED_area_newspace(C, sa, SPACE_IMAGE, false); } @@ -943,26 +947,26 @@ wmWindow *WM_window_open_temp(bContext *C, int x, int y, int sizex, int sizey, i else { ED_area_newspace(C, sa, SPACE_USERPREF, false); } - + ED_screen_change(C, screen); ED_screen_refresh(CTX_wm_manager(C), win); /* test scale */ - + /* do additional setup for specific editor type */ if (type == WM_WINDOW_DRIVERS) { /* Configure editor - mode, tabs, framing */ SpaceIpo *sipo = (SpaceIpo *)sa->spacedata.first; sipo->mode = SIPO_MODE_DRIVERS; - + ARegion *ar_props = BKE_area_find_region_type(sa, RGN_TYPE_UI); if (ar_props) { UI_panel_category_active_set(ar_props, "Drivers"); - + ar_props->flag &= ~RGN_FLAG_HIDDEN; /* XXX: Adjust width of this too? */ - + ED_region_visibility_change_update(C, ar_props); } - + ARegion *ar_main = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW); if (ar_main) { /* XXX: Ideally we recenter based on the range instead... */ @@ -970,11 +974,11 @@ wmWindow *WM_window_open_temp(bContext *C, int x, int y, int sizex, int sizey, i ar_main->v2d.tot.ymin = -2.0f; ar_main->v2d.tot.xmax = 2.0f; ar_main->v2d.tot.ymax = 2.0f; - + ar_main->v2d.cur = ar_main->v2d.tot; } } - + if (sa->spacetype == SPACE_IMAGE) title = IFACE_("Blender Render"); else if (ELEM(sa->spacetype, SPACE_OUTLINER, SPACE_USERPREF)) @@ -1029,6 +1033,7 @@ static WorkSpaceLayout *wm_window_new_find_layout(wmOperator *op, WorkSpace *wor /* new window operator callback */ int wm_window_new_exec(bContext *C, wmOperator *op) { + Main *bmain = CTX_data_main(C); wmWindow *win_src = CTX_wm_window(C); WorkSpace *workspace = WM_window_get_active_workspace(win_src); WorkSpaceLayout *layout_new = wm_window_new_find_layout(op, workspace); @@ -1038,7 +1043,7 @@ int wm_window_new_exec(bContext *C, wmOperator *op) if ((win_dst = wm_window_new_test(C))) { if (screen_new->winid) { /* layout/screen is already used, duplicate it */ - layout_new = ED_workspace_layout_duplicate(workspace, layout_new, win_dst); + layout_new = ED_workspace_layout_duplicate(bmain, workspace, layout_new, win_dst); screen_new = BKE_workspace_layout_screen_get(layout_new); } /* New window with a different screen but same workspace */ @@ -1129,7 +1134,7 @@ int wm_window_fullscreen_toggle_exec(bContext *C, wmOperator *UNUSED(op)) GHOST_SetWindowState(window->ghostwin, GHOST_kWindowStateNormal); return OPERATOR_FINISHED; - + } @@ -1138,10 +1143,10 @@ int wm_window_fullscreen_toggle_exec(bContext *C, wmOperator *UNUSED(op)) void wm_cursor_position_from_ghost(wmWindow *win, int *x, int *y) { float fac = GHOST_GetNativePixelSize(win->ghostwin); - + GHOST_ScreenToClient(win->ghostwin, *x, *y, x, y); *x *= fac; - + *y = (win->sizey - 1) - *y; *y *= fac; } @@ -1171,11 +1176,11 @@ typedef enum { } modifierKeyType; /* check if specified modifier key type is pressed */ -static int query_qual(modifierKeyType qual) +static int query_qual(modifierKeyType qual) { GHOST_TModifierKeyMask left, right; int val = 0; - + switch (qual) { case SHIFT: left = GHOST_kModifierKeyLeftShift; @@ -1194,15 +1199,15 @@ static int query_qual(modifierKeyType qual) right = GHOST_kModifierKeyRightAlt; break; } - + GHOST_GetModifierKeyState(g_system, left, &val); if (!val) GHOST_GetModifierKeyState(g_system, right, &val); - + return val; } -void wm_window_make_drawable(wmWindowManager *wm, wmWindow *win) +void wm_window_make_drawable(wmWindowManager *wm, wmWindow *win) { BLI_assert(GPU_framebuffer_current_get() == 0); @@ -1256,7 +1261,7 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr wmWindowManager *wm = CTX_wm_manager(C); GHOST_TEventType type = GHOST_GetEventType(evt); int time = GHOST_GetEventTime(evt); - + if (type == GHOST_kEventQuit) { WM_exit(C); } @@ -1264,7 +1269,7 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr GHOST_WindowHandle ghostwin = GHOST_GetEventWindow(evt); GHOST_TEventDataPtr data = GHOST_GetEventData(evt); wmWindow *win; - + /* Ghost now can call this function for life resizes, but it should return if WM didn't initialize yet. * Can happen on file read (especially full size window) */ if ((wm->initialized & WM_WINDOW_IS_INITIALIZED) == 0) { @@ -1285,12 +1290,12 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr else { win = GHOST_GetWindowUserData(ghostwin); } - + switch (type) { case GHOST_kEventWindowDeactivate: wm_event_add_ghostevent(wm, win, type, time, data); win->active = 0; /* XXX */ - + /* clear modifiers for inactive windows */ win->eventstate->alt = 0; win->eventstate->ctrl = 0; @@ -1299,7 +1304,7 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr win->eventstate->keymodifier = 0; break; - case GHOST_kEventWindowActivate: + case GHOST_kEventWindowActivate: { GHOST_TEventKeyData kdata; wmEvent event; @@ -1315,10 +1320,10 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr #endif wm->winactive = win; /* no context change! c->wm->windrawable is drawable, or for area queues */ - + win->active = 1; // window_handle(win, INPUTCHANGE, win->active); - + /* bad ghost support for modifier keys... so on activate we set the modifiers again */ /* TODO: This is not correct since a modifier may be held when a window is activated... @@ -1387,15 +1392,15 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr /* keymodifier zero, it hangs on hotkeys that open windows otherwise */ win->eventstate->keymodifier = 0; - + /* entering window, update mouse pos. but no event */ wm_get_cursor_position(win, &wx, &wy); win->eventstate->x = wx; win->eventstate->y = wy; - + win->addmousemove = 1; /* enables highlighted buttons */ - + wm_window_make_drawable(wm, win); /* window might be focused by mouse click in configuration of window manager @@ -1426,7 +1431,7 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr if (G.debug & G_DEBUG_EVENTS) { printf("%s: ghost redraw %d\n", __func__, win->winid); } - + wm_window_make_drawable(wm, win); WM_event_add_notifier(C, NC_WINDOW, NULL); @@ -1445,18 +1450,18 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr } WM_window_set_dpi(win); - + /* win32: gives undefined window size when minimized */ if (state != GHOST_kWindowStateMinimized) { GHOST_RectangleHandle client_rect; int l, t, r, b, scr_w, scr_h; int sizex, sizey, posx, posy; - + client_rect = GHOST_GetClientBounds(win->ghostwin); GHOST_GetRectangle(client_rect, &l, &t, &r, &b); - + GHOST_DisposeRectangle(client_rect); - + wm_get_desktopsize(&scr_w, &scr_h); sizex = r - l; sizey = b - t; @@ -1467,8 +1472,8 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr * Ghost sometimes send size or move events when the window hasn't changed. * One case of this is using compiz on linux. To alleviate the problem * we ignore all such event here. - * - * It might be good to eventually do that at Ghost level, but that is for + * + * It might be good to eventually do that at Ghost level, but that is for * another time. */ if (win->sizex != sizex || @@ -1511,12 +1516,12 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr win->posx, win->posy, win->sizex, win->sizey); } } - + wm_window_make_drawable(wm, win); BKE_icon_changed(screen->id.icon_id); WM_event_add_notifier(C, NC_SCREEN | NA_EDITED, NULL); WM_event_add_notifier(C, NC_WINDOW | NA_EDITED, NULL); - + #if defined(__APPLE__) || defined(WIN32) /* OSX and Win32 don't return to the mainloop while resize */ wm_event_do_notifiers(C); @@ -1547,19 +1552,19 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr PointerRNA props_ptr; wmWindow *oldWindow; const char *path = GHOST_GetEventData(evt); - + if (path) { wmOperatorType *ot = WM_operatortype_find("WM_OT_open_mainfile", false); /* operator needs a valid window in context, ensures * it is correctly set */ oldWindow = CTX_wm_window(C); CTX_wm_window_set(C, win); - + WM_operator_properties_create_ptr(&props_ptr, ot); RNA_string_set(&props_ptr, "filepath", path); WM_operator_name_call_ptr(C, ot, WM_OP_EXEC_DEFAULT, &props_ptr); WM_operator_properties_free(&props_ptr); - + CTX_wm_window_set(C, oldWindow); } break; @@ -1569,53 +1574,53 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr wmEvent event; GHOST_TEventDragnDropData *ddd = GHOST_GetEventData(evt); int wx, wy; - + /* entering window, update mouse pos */ wm_get_cursor_position(win, &wx, &wy); win->eventstate->x = wx; win->eventstate->y = wy; - + wm_event_init_from_window(win, &event); /* copy last state, like mouse coords */ - + /* activate region */ event.type = MOUSEMOVE; event.prevx = event.x; event.prevy = event.y; - + wm->winactive = win; /* no context change! c->wm->windrawable is drawable, or for area queues */ win->active = 1; - + wm_event_add(win, &event); - - + + /* make blender drop event with custom data pointing to wm drags */ event.type = EVT_DROP; event.val = KM_RELEASE; event.custom = EVT_DATA_DRAGDROP; event.customdata = &wm->drags; event.customdatafree = 1; - + wm_event_add(win, &event); - + /* printf("Drop detected\n"); */ - + /* add drag data to wm for paths: */ - + if (ddd->dataType == GHOST_kDragnDropTypeFilenames) { GHOST_TStringArray *stra = ddd->data; int a, icon; - + for (a = 0; a < stra->count; a++) { printf("drop file %s\n", stra->strings[a]); /* try to get icon type from extension */ icon = ED_file_extension_icon((char *)stra->strings[a]); - + WM_event_start_drag(C, icon, WM_DRAG_PATH, stra->strings[a], 0.0, WM_DRAG_NOP); /* void poin should point to string, it makes a copy */ break; /* only one drop element supported now */ } } - + break; } case GHOST_kEventNativeResolutionChange: @@ -1645,7 +1650,7 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr case GHOST_kEventTrackpad: { GHOST_TEventTrackpadData *pd = data; - + wm_cursor_position_from_ghost(win, &pd->x, &pd->y); wm_event_add_ghostevent(wm, win, type, time, data); break; @@ -1653,7 +1658,7 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr case GHOST_kEventCursorMove: { GHOST_TEventCursorData *cd = data; - + wm_cursor_position_from_ghost(win, &cd->x, &cd->y); wm_event_add_ghostevent(wm, win, type, time, data); break; @@ -1681,7 +1686,7 @@ static int wm_window_timer(const bContext *C) wmWindow *win; double time = PIL_check_seconds_timer(); int retval = 0; - + for (wt = wm->timers.first; wt; wt = wtnext) { wtnext = wt->next; /* in case timer gets removed */ win = wt->win; @@ -1702,7 +1707,7 @@ static int wm_window_timer(const bContext *C) else if (win) { wmEvent event; wm_event_init_from_window(win, &event); - + event.type = wt->event_type; event.val = KM_NOTHING; event.keymodifier = 0; @@ -1718,7 +1723,7 @@ static int wm_window_timer(const bContext *C) return retval; } -void wm_window_process_events(const bContext *C) +void wm_window_process_events(const bContext *C) { int hasevent; @@ -1728,7 +1733,7 @@ void wm_window_process_events(const bContext *C) if (hasevent) GHOST_DispatchEvents(g_system); - + hasevent |= wm_window_timer(C); /* no event, we sleep 5 milliseconds */ @@ -1736,7 +1741,7 @@ void wm_window_process_events(const bContext *C) PIL_sleep_ms(5); } -void wm_window_process_events_nosleep(void) +void wm_window_process_events_nosleep(void) { if (GHOST_ProcessEvents(g_system, 0)) GHOST_DispatchEvents(g_system); @@ -1755,10 +1760,10 @@ void wm_window_testbreak(void) */ if ((curtime - ltime) > 0.05) { int hasevent = GHOST_ProcessEvents(g_system, 0); /* 0 is no wait */ - + if (hasevent) GHOST_DispatchEvents(g_system); - + ltime = curtime; } } @@ -1775,13 +1780,13 @@ void wm_ghost_init(bContext *C) if (C != NULL) { consumer = GHOST_CreateEventConsumer(ghost_event_proc, C); } - + g_system = GHOST_CreateSystem(); if (C != NULL) { GHOST_AddEventConsumer(g_system, consumer); } - + if (wm_init_state.native_pixels) { GHOST_UseNativePixels(); } @@ -1802,7 +1807,7 @@ void wm_ghost_exit(void) void WM_event_timer_sleep(wmWindowManager *wm, wmWindow *UNUSED(win), wmTimer *timer, bool do_sleep) { wmTimer *wt; - + for (wt = wm->timers.first; wt; wt = wt->next) if (wt == timer) break; @@ -1821,9 +1826,9 @@ wmTimer *WM_event_add_timer(wmWindowManager *wm, wmWindow *win, int event_type, wt->stime = wt->ltime; wt->timestep = timestep; wt->win = win; - + BLI_addtail(&wm->timers, wt); - + return wt; } @@ -1848,23 +1853,23 @@ wmTimer *WM_event_add_timer_notifier(wmWindowManager *wm, wmWindow *win, unsigne void WM_event_remove_timer(wmWindowManager *wm, wmWindow *UNUSED(win), wmTimer *timer) { wmTimer *wt; - + /* extra security check */ for (wt = wm->timers.first; wt; wt = wt->next) if (wt == timer) break; if (wt) { wmWindow *win; - + if (wm->reports.reporttimer == wt) wm->reports.reporttimer = NULL; - + BLI_remlink(&wm->timers, wt); if (wt->customdata != NULL && (wt->flags & WM_TIMER_NO_FREE_CUSTOM_DATA) == 0) { MEM_freeN(wt->customdata); } MEM_freeN(wt); - + /* there might be events in queue with this timer as customdata */ for (win = wm->windows.first; win; win = win->next) { wmEvent *event; @@ -1901,7 +1906,7 @@ static char *wm_clipboard_text_get_ex(bool selection, int *r_len, *r_len = 0; return NULL; } - + /* always convert from \r\n to \n */ p2 = newbuf = MEM_mallocN(strlen(buf) + 1, __func__); @@ -1927,7 +1932,7 @@ static char *wm_clipboard_text_get_ex(bool selection, int *r_len, *p2 = '\0'; free(buf); /* ghost uses regular malloc */ - + *r_len = (p2 - newbuf); return newbuf; @@ -1959,16 +1964,16 @@ void WM_clipboard_text_set(const char *buf, bool selection) const char *p; char *p2, *newbuf; int newlen = 0; - + for (p = buf; *p; p++) { if (*p == '\n') newlen += 2; else newlen++; } - + newbuf = MEM_callocN(newlen + 1, "WM_clipboard_text_set"); - + for (p = buf, p2 = newbuf; *p; p++, p2++) { if (*p == '\n') { *(p2++) = '\r'; *p2 = '\n'; @@ -1978,7 +1983,7 @@ void WM_clipboard_text_set(const char *buf, bool selection) } } *p2 = '\0'; - + GHOST_putClipboard((GHOST_TInt8 *)newbuf, selection); MEM_freeN(newbuf); #else @@ -2007,24 +2012,25 @@ void wm_window_get_position(wmWindow *win, int *r_pos_x, int *r_pos_y) *r_pos_y = win->posy; } -void wm_window_set_size(wmWindow *win, int width, int height) +void wm_window_set_size(wmWindow *win, int width, int height) { GHOST_SetClientSize(win->ghostwin, width, height); } -void wm_window_lower(wmWindow *win) +void wm_window_lower(wmWindow *win) { GHOST_SetWindowOrder(win->ghostwin, GHOST_kWindowOrderBottom); } -void wm_window_raise(wmWindow *win) +void wm_window_raise(wmWindow *win) { GHOST_SetWindowOrder(win->ghostwin, GHOST_kWindowOrderTop); } void wm_window_swap_buffers(wmWindow *win) { - GPU_texture_delete_orphans(); /* XXX should be done elsewhere. */ + GPU_texture_orphans_delete(); /* XXX should be done elsewhere. */ + GPU_material_orphans_delete(); /* XXX Amen to that. */ GHOST_SwapWindowBuffers(win->ghostwin); } @@ -2119,13 +2125,13 @@ float WM_cursor_pressure(const struct wmWindow *win) int WM_window_pixels_x(const wmWindow *win) { float f = GHOST_GetNativePixelSize(win->ghostwin); - + return (int)(f * (float)win->sizex); } int WM_window_pixels_y(const wmWindow *win) { float f = GHOST_GetNativePixelSize(win->ghostwin); - + return (int)(f * (float)win->sizey); } diff --git a/source/blender/windowmanager/wm.h b/source/blender/windowmanager/wm.h index 33ca415b664..c92691eb65e 100644 --- a/source/blender/windowmanager/wm.h +++ b/source/blender/windowmanager/wm.h @@ -41,7 +41,7 @@ typedef struct wmPaintCursor { struct wmPaintCursor *next, *prev; void *customdata; - + int (*poll)(struct bContext *C); void (*draw)(bContext *C, int, int, void *customdata); } wmPaintCursor; @@ -54,7 +54,7 @@ extern void wm_close_and_free_all(bContext *C, ListBase *); extern void wm_add_default(struct Main *bmain, bContext *C); extern void wm_clear_default_size(bContext *C); - + /* register to windowmanager for redo or macro */ void wm_operator_register(bContext *C, wmOperator *op); diff --git a/source/blender/windowmanager/wm_cursors.h b/source/blender/windowmanager/wm_cursors.h index c695a12f52c..939409f9511 100644 --- a/source/blender/windowmanager/wm_cursors.h +++ b/source/blender/windowmanager/wm_cursors.h @@ -39,12 +39,12 @@ void wm_init_cursor_data(void); /* old cursors */ enum { CURSOR_FACESEL = BC_GHOST_CURSORS, - CURSOR_WAIT, - CURSOR_EDIT, - CURSOR_X_MOVE, - CURSOR_Y_MOVE, - CURSOR_HELP, - CURSOR_STD, + CURSOR_WAIT, + CURSOR_EDIT, + CURSOR_X_MOVE, + CURSOR_Y_MOVE, + CURSOR_HELP, + CURSOR_STD, CURSOR_NONE, CURSOR_PENCIL, CURSOR_COPY @@ -57,21 +57,21 @@ typedef struct BCursor { char *small_bm; char *small_mask; - char small_sizex; - char small_sizey; - char small_hotx; - char small_hoty; + char small_sizex; + char small_sizey; + char small_hotx; + char small_hoty; - char *big_bm; + char *big_bm; char *big_mask; - char big_sizex; - char big_sizey; - char big_hotx; - char big_hoty; + char big_sizex; + char big_sizey; + char big_hotx; + char big_hoty; - char fg_color; - char bg_color; + char fg_color; + char bg_color; } BCursor; @@ -101,7 +101,7 @@ enum { enum { BC_BLACK = 0, - BC_WHITE, + BC_WHITE, BC_RED, BC_BLUE, BC_GREEN, diff --git a/source/blender/windowmanager/wm_event_types.h b/source/blender/windowmanager/wm_event_types.h index 5edd4a76127..db2fd5ce7f2 100644 --- a/source/blender/windowmanager/wm_event_types.h +++ b/source/blender/windowmanager/wm_event_types.h @@ -92,7 +92,7 @@ enum { WM_IME_COMPOSITE_EVENT = 0x0015, /* IME event, GHOST_kEventImeCompositionEnd in ghost */ WM_IME_COMPOSITE_END = 0x0016, - + /* Tablet/Pen Specific Events */ TABLET_STYLUS = 0x001a, TABLET_ERASER = 0x001b, diff --git a/source/tools b/source/tools -Subproject 6bcd05cf6aaafae07b8a15313d7fdda1471ff59 +Subproject fca325137b6ee2dfd0930ca87684ccf30703554 diff --git a/tests/gtests/alembic/abc_export_test.cc b/tests/gtests/alembic/abc_export_test.cc index dab1e3ae040..c950084ef64 100644 --- a/tests/gtests/alembic/abc_export_test.cc +++ b/tests/gtests/alembic/abc_export_test.cc @@ -16,9 +16,8 @@ extern "C" { class TestableAbcExporter : public AbcExporter { public: TestableAbcExporter(Main *bmain, - Scene *scene, Depsgraph *depsgraph, const char *filename, ExportSettings &settings) - : AbcExporter(bmain, scene, depsgraph, filename, settings) + : AbcExporter(bmain, filename, settings) { } @@ -57,7 +56,10 @@ protected: /* TODO(sergey): Pass scene layer somehow? */ ViewLayer *view_layer = (ViewLayer *)scene.view_layers.first; - depsgraph = DEG_graph_new(&scene, view_layer, DAG_EVAL_VIEWPORT); + settings.depsgraph = depsgraph = DEG_graph_new(&scene, view_layer, DAG_EVAL_VIEWPORT); + + settings.scene = &scene; + settings.view_layer = view_layer; exporter = NULL; } @@ -72,7 +74,7 @@ protected: // Call after setting up the settings. void createExporter() { - exporter = new TestableAbcExporter(bmain, &scene, depsgraph, "somefile.abc", settings); + exporter = new TestableAbcExporter(bmain, "somefile.abc", settings); } }; diff --git a/tests/gtests/blenlib/BLI_heap_test.cc b/tests/gtests/blenlib/BLI_heap_test.cc index 82acdabd7eb..dd0bc3451ce 100644 --- a/tests/gtests/blenlib/BLI_heap_test.cc +++ b/tests/gtests/blenlib/BLI_heap_test.cc @@ -40,7 +40,7 @@ TEST(heap, One) const char *in = "test"; heap = BLI_heap_new(); - + BLI_heap_insert(heap, 0.0f, (void *)in); EXPECT_FALSE(BLI_heap_is_empty(heap)); EXPECT_EQ(BLI_heap_len(heap), 1); diff --git a/tests/python/bl_pyapi_mathutils.py b/tests/python/bl_pyapi_mathutils.py index 9ca0376192a..b2d3d79fd56 100644 --- a/tests/python/bl_pyapi_mathutils.py +++ b/tests/python/bl_pyapi_mathutils.py @@ -127,7 +127,7 @@ class MatrixTesting(unittest.TestCase): (0, 0, 0, 1))) vec = Vector((1, 2, 3)) - + prod_mat_vec = Vector((7, 12, 4)) prod_vec_mat = Vector((1, 12, 5)) diff --git a/tests/python/collada/animation/test_animation_simple.py b/tests/python/collada/animation/test_animation_simple.py index 6686d429261..bdfae03aafb 100644 --- a/tests/python/collada/animation/test_animation_simple.py +++ b/tests/python/collada/animation/test_animation_simple.py @@ -113,37 +113,37 @@ class MeshExportTest4(AbstractColladaTest): test = "suzannes_parent_inverse_sample_10_matrix" reference_dae = self.testdir / Path("%s.dae" % test) outfile = tempdir / Path("%s_out.dae" % test) - + bpy.ops.wm.collada_export(filepath="%s" % str(outfile), - check_existing=True, - filemode=8, - display_type='DEFAULT', - sort_method='FILE_SORT_ALPHA', - apply_modifiers=True, - export_mesh_type=0, - export_mesh_type_selection='view', - selected=True, - include_children=True, - include_armatures=True, - include_shapekeys=False, - deform_bones_only=False, - include_animations=True, - sample_animations=True, - sampling_rate=10, - active_uv_only=False, - use_texture_copies=True, - triangulate=False, - use_object_instantiation=True, - use_blender_profile=True, - sort_by_name=False, - export_transformation_type=0, - export_transformation_type_selection='matrix', - export_texture_type=0, - export_texture_type_selection='mat', - open_sim=False, - limit_precision=True, + check_existing=True, + filemode=8, + display_type='DEFAULT', + sort_method='FILE_SORT_ALPHA', + apply_modifiers=True, + export_mesh_type=0, + export_mesh_type_selection='view', + selected=True, + include_children=True, + include_armatures=True, + include_shapekeys=False, + deform_bones_only=False, + include_animations=True, + sample_animations=True, + sampling_rate=10, + active_uv_only=False, + use_texture_copies=True, + triangulate=False, + use_object_instantiation=True, + use_blender_profile=True, + sort_by_name=False, + export_transformation_type=0, + export_transformation_type_selection='matrix', + export_texture_type=0, + export_texture_type_selection='mat', + open_sim=False, + limit_precision=True, keep_bind_info=False) - + # Now check the resulting Collada file. if not self.checkdae(reference_dae, outfile): self.fail() @@ -154,37 +154,37 @@ class MeshExportTest3(AbstractColladaTest): test = "suzannes_parent_inverse_sample_10_channels" reference_dae = self.testdir / Path("%s.dae" % test) outfile = tempdir / Path("%s_out.dae" % test) - + bpy.ops.wm.collada_export(filepath="%s" % str(outfile), - check_existing=True, - filemode=8, - display_type='DEFAULT', - sort_method='FILE_SORT_ALPHA', - apply_modifiers=True, - export_mesh_type=0, - export_mesh_type_selection='view', - selected=True, - include_children=True, - include_armatures=True, - include_shapekeys=False, - deform_bones_only=False, - include_animations=True, - sample_animations=True, - sampling_rate=10, - active_uv_only=False, - use_texture_copies=True, - triangulate=False, - use_object_instantiation=True, - use_blender_profile=True, - sort_by_name=False, - export_transformation_type=0, - export_transformation_type_selection='transrotloc', - export_texture_type=0, - export_texture_type_selection='mat', - open_sim=False, - limit_precision=True, + check_existing=True, + filemode=8, + display_type='DEFAULT', + sort_method='FILE_SORT_ALPHA', + apply_modifiers=True, + export_mesh_type=0, + export_mesh_type_selection='view', + selected=True, + include_children=True, + include_armatures=True, + include_shapekeys=False, + deform_bones_only=False, + include_animations=True, + sample_animations=True, + sampling_rate=10, + active_uv_only=False, + use_texture_copies=True, + triangulate=False, + use_object_instantiation=True, + use_blender_profile=True, + sort_by_name=False, + export_transformation_type=0, + export_transformation_type_selection='transrotloc', + export_texture_type=0, + export_texture_type_selection='mat', + open_sim=False, + limit_precision=True, keep_bind_info=False) - + # Now check the resulting Collada file. if not self.checkdae(reference_dae, outfile): self.fail() @@ -195,37 +195,37 @@ class MeshExportTest2(AbstractColladaTest): test = "suzannes_parent_inverse_keyframes_matrix" reference_dae = self.testdir / Path("%s.dae" % test) outfile = tempdir / Path("%s_out.dae" % test) - + bpy.ops.wm.collada_export(filepath="%s" % str(outfile), - check_existing=True, - filemode=8, - display_type='DEFAULT', - sort_method='FILE_SORT_ALPHA', - apply_modifiers=True, - export_mesh_type=0, - export_mesh_type_selection='view', - selected=True, - include_children=True, - include_armatures=True, - include_shapekeys=False, - deform_bones_only=False, - include_animations=True, - sample_animations=False, - sampling_rate=1, - active_uv_only=False, - use_texture_copies=True, - triangulate=False, - use_object_instantiation=True, - use_blender_profile=True, - sort_by_name=False, - export_transformation_type=0, - export_transformation_type_selection='matrix', - export_texture_type=0, - export_texture_type_selection='mat', - open_sim=False, - limit_precision=True, + check_existing=True, + filemode=8, + display_type='DEFAULT', + sort_method='FILE_SORT_ALPHA', + apply_modifiers=True, + export_mesh_type=0, + export_mesh_type_selection='view', + selected=True, + include_children=True, + include_armatures=True, + include_shapekeys=False, + deform_bones_only=False, + include_animations=True, + sample_animations=False, + sampling_rate=1, + active_uv_only=False, + use_texture_copies=True, + triangulate=False, + use_object_instantiation=True, + use_blender_profile=True, + sort_by_name=False, + export_transformation_type=0, + export_transformation_type_selection='matrix', + export_texture_type=0, + export_texture_type_selection='mat', + open_sim=False, + limit_precision=True, keep_bind_info=False) - + # Now check the resulting Collada file. if not self.checkdae(reference_dae, outfile): self.fail() @@ -236,45 +236,45 @@ class MeshExportTest1(AbstractColladaTest): test = "suzannes_parent_inverse_keyframes_channels" reference_dae = self.testdir / Path("%s.dae" % test) outfile = tempdir / Path("%s_out.dae" % test) - + bpy.ops.wm.collada_export(filepath="%s" % str(outfile), - check_existing=True, - filemode=8, - display_type='DEFAULT', - sort_method='FILE_SORT_ALPHA', - apply_modifiers=True, - export_mesh_type=0, - export_mesh_type_selection='view', - selected=True, - include_children=True, - include_armatures=True, - include_shapekeys=False, - deform_bones_only=False, - include_animations=True, - sample_animations=False, - sampling_rate=1, - active_uv_only=False, - use_texture_copies=True, - triangulate=False, - use_object_instantiation=True, - use_blender_profile=True, - sort_by_name=False, - export_transformation_type=0, - export_transformation_type_selection='transrotloc', - export_texture_type=0, - export_texture_type_selection='mat', - open_sim=False, - limit_precision=True, + check_existing=True, + filemode=8, + display_type='DEFAULT', + sort_method='FILE_SORT_ALPHA', + apply_modifiers=True, + export_mesh_type=0, + export_mesh_type_selection='view', + selected=True, + include_children=True, + include_armatures=True, + include_shapekeys=False, + deform_bones_only=False, + include_animations=True, + sample_animations=False, + sampling_rate=1, + active_uv_only=False, + use_texture_copies=True, + triangulate=False, + use_object_instantiation=True, + use_blender_profile=True, + sort_by_name=False, + export_transformation_type=0, + export_transformation_type_selection='transrotloc', + export_texture_type=0, + export_texture_type_selection='mat', + open_sim=False, + limit_precision=True, keep_bind_info=False) - + # Now check the resulting Collada file. if not self.checkdae(reference_dae, outfile): self.fail() - + if __name__ == '__main__': sys.argv = [__file__] + (sys.argv[sys.argv.index("--") + 1:] if "--" in sys.argv else []) parser = argparse.ArgumentParser() parser.add_argument('--testdir', required=True) args, remaining = parser.parse_known_args() - unittest.main(argv=sys.argv[0:1]+remaining)
\ No newline at end of file + unittest.main(argv=sys.argv[0:1]+remaining) diff --git a/tests/python/collada/mesh/test_mesh_simple.py b/tests/python/collada/mesh/test_mesh_simple.py index f592160f6aa..213c6177fde 100644 --- a/tests/python/collada/mesh/test_mesh_simple.py +++ b/tests/python/collada/mesh/test_mesh_simple.py @@ -113,7 +113,7 @@ class MeshExportTest(AbstractColladaTest): test = "mesh_simple_001" reference_dae = self.testdir / Path("%s.dae" % test) outfile = tempdir / Path("%s_out.dae" % test) - + bpy.ops.wm.collada_export(filepath="%s" % str(outfile), check_existing=True, filemode=8, @@ -141,7 +141,7 @@ class MeshExportTest(AbstractColladaTest): open_sim=False, limit_precision=False, keep_bind_info=False) - + # Now check the resulting Collada file. if not self.checkdae(reference_dae, outfile): self.fail() @@ -151,4 +151,4 @@ if __name__ == '__main__': parser = argparse.ArgumentParser() parser.add_argument('--testdir', required=True) args, remaining = parser.parse_known_args() - unittest.main(argv=sys.argv[0:1]+remaining)
\ No newline at end of file + unittest.main(argv=sys.argv[0:1]+remaining) diff --git a/tests/python/ffmpeg_tests.py b/tests/python/ffmpeg_tests.py index 9493d6f7a17..70677677667 100755 --- a/tests/python/ffmpeg_tests.py +++ b/tests/python/ffmpeg_tests.py @@ -60,7 +60,7 @@ class AbstractFFmpegSequencerTest(AbstractFFmpegTest): class FPSDetectionTest(AbstractFFmpegSequencerTest): def test_T51153(self): self.assertAlmostEqual( - self.get_movie_file_fps('T51153_bad_clip_2.mts'), + self.get_movie_file_fps('T51153_bad_clip_2.mts'), 29.97, places=2) diff --git a/tests/python/modules/test_utils.py b/tests/python/modules/test_utils.py index 55ef882c49c..c4496c3e3ac 100755 --- a/tests/python/modules/test_utils.py +++ b/tests/python/modules/test_utils.py @@ -61,7 +61,7 @@ class AbstractBlenderRunnerTest(unittest.TestCase): # Set in a subclass blender: pathlib.Path = None testdir: pathlib.Path = None - + def run_blender(self, filepath: str, python_script: str, timeout: int=300) -> str: """Runs Blender by opening a blendfile and executing a script. diff --git a/tests/python/rna_array.py b/tests/python/rna_array.py index f9777a5b438..dda13d2c3ae 100644 --- a/tests/python/rna_array.py +++ b/tests/python/rna_array.py @@ -23,7 +23,7 @@ class TestArray(unittest.TestCase): test.farr= (1.0, 2.0, 3.0) test.iarr= (7, 8, 9) test.barr= (False, True, False) - + # test access # test slice access, negative indices def test_access(self): @@ -40,7 +40,7 @@ class TestArray(unittest.TestCase): def test_access_fail(self): for arr in (test.farr, test.iarr, test.barr): self.assertRaises(IndexError, lambda : arr[4]) - + # test assignment of a whole array def test_assign_array(self): # should accept int as float @@ -83,7 +83,7 @@ class TestArray(unittest.TestCase): for i in range(len(arr)): val= rand_func() arr[i] = val - + self.assertEqual(arr[i], val) # float prop should accept also int @@ -92,7 +92,7 @@ class TestArray(unittest.TestCase): test.farr[i] = val self.assertEqual(test.farr[i], float(val)) - # + # def test_assign_item_fail(self): def assign_bad_index(arr): @@ -100,12 +100,12 @@ class TestArray(unittest.TestCase): def assign_bad_type(arr): arr[1] = "123" - + for arr in [test.farr, test.iarr, test.barr]: self.assertRaises(IndexError, assign_bad_index, arr) # not testing bool because bool allows not only (True|False) - for arr in [test.farr, test.iarr]: + for arr in [test.farr, test.iarr]: self.assertRaises(TypeError, assign_bad_type, arr) def test_dynamic_assign_array(self): @@ -118,7 +118,7 @@ class TestArray(unittest.TestCase): def test_dynamic_assign_array_fail(self): # could also test too big length here - + def assign_empty_list(arr): setattr(test, arr, ()) @@ -236,7 +236,7 @@ def make_random_array(len, rand_func): arr= [] for i in range(len): arr.append(rand_func()) - + return arr def make_random_2d_array(dimsize, rand_func): diff --git a/tests/python/view_layer/CMakeLists.txt b/tests/python/view_layer/CMakeLists.txt index 69f7af20ad2..cec839a3efc 100644 --- a/tests/python/view_layer/CMakeLists.txt +++ b/tests/python/view_layer/CMakeLists.txt @@ -18,7 +18,7 @@ # # ***** END GPL LICENSE BLOCK ***** -# --env-system-scripts allows to run without the install target. +# --env-system-scripts allows to run without the install target. # Use '--write-blend=/tmp/test.blend' to view output @@ -43,7 +43,7 @@ else() set(TEST_BLENDER_EXE ${EXECUTABLE_OUTPUT_PATH}/blender) endif() -# for testing with valgrind prefix: valgrind --track-origins=yes --error-limit=no +# for testing with valgrind prefix: valgrind --track-origins=yes --error-limit=no set(TEST_BLENDER_EXE ${TEST_BLENDER_EXE} --background -noaudio --factory-startup --env-system-scripts ${CMAKE_SOURCE_DIR}/release/scripts) |