diff options
author | Thomas Dinges <blender@dingto.org> | 2013-08-16 16:50:13 +0400 |
---|---|---|
committer | Thomas Dinges <blender@dingto.org> | 2013-08-16 16:50:13 +0400 |
commit | 0786eebd1194b108d71299137c715b10e100d8f5 (patch) | |
tree | 4b89a5aed5b44881a9e52c3cd982f457532d76fa | |
parent | 9591957c8aa92740985f323673ccf0b6be318d62 (diff) | |
parent | d75e14b31e5e65d1e38b1ca4688a42a346ac9495 (diff) |
Merged revision(s) 59108-59184 from trunk/blender into soc-2013-dingto.
112 files changed, 3977 insertions, 546 deletions
diff --git a/build_files/scons/tools/Blender.py b/build_files/scons/tools/Blender.py index 24bdd32ed26..ee2399500d0 100644 --- a/build_files/scons/tools/Blender.py +++ b/build_files/scons/tools/Blender.py @@ -151,12 +151,6 @@ def setup_staticlibs(lenv): libincs += Split(lenv['BF_JACK_LIBPATH']) if lenv['WITH_BF_SNDFILE']: libincs += Split(lenv['BF_SNDFILE_LIBPATH']) - if lenv['WITH_BF_OPENEXR']: - libincs += Split(lenv['BF_OPENEXR_LIBPATH']) - if lenv['WITH_BF_STATICOPENEXR']: - statlibs += Split(lenv['BF_OPENEXR_LIB_STATIC']) - if lenv['WITH_BF_ZLIB'] and lenv['WITH_BF_STATICZLIB']: - statlibs += Split(lenv['BF_ZLIB_LIB_STATIC']) if lenv['WITH_BF_TIFF']: libincs += Split(lenv['BF_TIFF_LIBPATH']) if lenv['WITH_BF_STATICTIFF']: @@ -212,6 +206,12 @@ def setup_staticlibs(lenv): libincs += Split(lenv['BF_OIIO_LIBPATH']) if lenv['WITH_BF_STATICOIIO']: statlibs += Split(lenv['BF_OIIO_LIB_STATIC']) + if lenv['WITH_BF_OPENEXR']: + libincs += Split(lenv['BF_OPENEXR_LIBPATH']) + if lenv['WITH_BF_STATICOPENEXR']: + statlibs += Split(lenv['BF_OPENEXR_LIB_STATIC']) + if lenv['WITH_BF_ZLIB'] and lenv['WITH_BF_STATICZLIB']: + statlibs += Split(lenv['BF_ZLIB_LIB_STATIC']) if lenv['WITH_BF_OCIO']: libincs += Split(lenv['BF_OCIO_LIBPATH']) diff --git a/doc/python_api/rst/bge.logic.rst b/doc/python_api/rst/bge.logic.rst index c7915ee5279..3a79d32d917 100644 --- a/doc/python_api/rst/bge.logic.rst +++ b/doc/python_api/rst/bge.logic.rst @@ -1114,6 +1114,19 @@ See :class:`bge.types.KX_GameObject.playAction` :value: 2 +.. _gameobject-playaction-blend: + +.. data:: KX_ACTION_BLEND_BLEND + + Blend layers using linear interpolation + + :value: 0 + +.. data:: KX_ACTION_BLEND_ADD + + Adds the layers together + + :value: 1 ------------- Mouse Buttons diff --git a/doc/python_api/rst/bge_types/bge.types.KX_GameObject.rst b/doc/python_api/rst/bge_types/bge.types.KX_GameObject.rst index a9c91735f91..3be148556ef 100644 --- a/doc/python_api/rst/bge_types/bge.types.KX_GameObject.rst +++ b/doc/python_api/rst/bge_types/bge.types.KX_GameObject.rst @@ -776,7 +776,7 @@ base class --- :class:`SCA_IObject` Return the value matching key, or the default value if its not found. :return: The key value or a default. - .. method:: playAction(name, start_frame, end_frame, layer=0, priority=0, blendin=0, play_mode=ACT_MODE_PLAY, layer_weight=0.0, ipo_flags=0, speed=1.0) + .. method:: playAction(name, start_frame, end_frame, layer=0, priority=0, blendin=0, play_mode=KX_ACTION_MODE_PLAY, layer_weight=0.0, ipo_flags=0, speed=1.0, blend_mode=KX_ACTION_BLEND_BLEND) Plays an action. @@ -794,12 +794,14 @@ base class --- :class:`SCA_IObject` :type blendin: float :arg play_mode: the play mode :type play_mode: one of :ref:`these constants <gameobject-playaction-mode>` - :arg layer_weight: how much of the previous layer to use for blending (0 = add) + :arg layer_weight: how much of the previous layer to use for blending :type layer_weight: float :arg ipo_flags: flags for the old IPO behaviors (force, etc) :type ipo_flags: int bitfield :arg speed: the playback speed of the action as a factor (1.0 = normal speed, 2.0 = 2x speed, etc) :type speed: float + :arg blend_mode: how to blend this layer with previous layers + :type blend_mode: one of :ref:`these constants <gameobject-playaction-blend>` .. method:: stopAction(layer=0) diff --git a/extern/libmv/libmv-capi.cc b/extern/libmv/libmv-capi.cc index 063c63f9266..e1fd509d581 100644 --- a/extern/libmv/libmv-capi.cc +++ b/extern/libmv/libmv-capi.cc @@ -58,6 +58,8 @@ #include "libmv/simple_pipeline/reconstruction_scale.h" #include "libmv/simple_pipeline/keyframe_selection.h" +#include "libmv/multiview/homography.h" + #ifdef _MSC_VER # define snprintf _snprintf #endif @@ -1080,4 +1082,28 @@ void libmv_cameraIntrinsicsInvert(const libmv_CameraIntrinsicsOptions *libmv_cam } } +void libmv_homography2DFromCorrespondencesLinear(double (*x1)[2], double (*x2)[2], int num_points, + double H[3][3], double expected_precision) +{ + libmv::Mat x1_mat, x2_mat; + libmv::Mat3 H_mat; + + x1_mat.resize(2, num_points); + x2_mat.resize(2, num_points); + + for (int i = 0; i < num_points; i++) { + x1_mat.col(i) = libmv::Vec2(x1[i][0], x1[i][1]); + x2_mat.col(i) = libmv::Vec2(x2[i][0], x2[i][1]); + } + + LG << "x1: " << x1_mat; + LG << "x2: " << x2_mat; + + libmv::Homography2DFromCorrespondencesLinear(x1_mat, x2_mat, &H_mat, expected_precision); + + LG << "H: " << H_mat; + + memcpy(H, H_mat.data(), 9 * sizeof(double)); +} + #endif diff --git a/extern/libmv/libmv-capi.h b/extern/libmv/libmv-capi.h index 7c91881fe71..37aab2465ed 100644 --- a/extern/libmv/libmv-capi.h +++ b/extern/libmv/libmv-capi.h @@ -159,6 +159,9 @@ void libmv_cameraIntrinsicsApply(const libmv_CameraIntrinsicsOptions *libmv_came void libmv_cameraIntrinsicsInvert(const libmv_CameraIntrinsicsOptions *libmv_camera_intrinsics_options, double x, double y, double *x1, double *y1); +void libmv_homography2DFromCorrespondencesLinear(double (*x1)[2], double (*x2)[2], int num_points, + double H[3][3], double expected_precision); + #ifdef __cplusplus } #endif diff --git a/extern/libmv/libmv-capi_stub.cc b/extern/libmv/libmv-capi_stub.cc index 36977eb58ba..59a3fe89398 100644 --- a/extern/libmv/libmv-capi_stub.cc +++ b/extern/libmv/libmv-capi_stub.cc @@ -277,4 +277,13 @@ void libmv_cameraIntrinsicsInvert(const libmv_CameraIntrinsicsOptions *libmv_cam *y1 = (y - principal_y) / focal_length; } +void libmv_homography2DFromCorrespondencesLinear(double (* /* x1 */)[2], double (* /* x2 */)[2], int /* num_points */, + double H[3][3], double /* expected_precision */) +{ + memset(H, 0, sizeof(H)); + H[0][0] = 1.0f; + H[1][1] = 1.0f; + H[2][2] = 1.0f; +} + #endif // ifndef WITH_LIBMV diff --git a/extern/libmv/libmv/multiview/euclidean_resection.cc b/extern/libmv/libmv/multiview/euclidean_resection.cc index 10c7330770f..d5421b9691e 100644 --- a/extern/libmv/libmv/multiview/euclidean_resection.cc +++ b/extern/libmv/libmv/multiview/euclidean_resection.cc @@ -34,6 +34,11 @@ namespace libmv { namespace euclidean_resection { typedef unsigned int uint; + +bool EuclideanResectionPPnP(const Mat2X &x_camera, + const Mat3X &X_world, + Mat3 *R, Vec3 *t, + double tolerance); bool EuclideanResection(const Mat2X &x_camera, const Mat3X &X_world, @@ -47,6 +52,9 @@ bool EuclideanResection(const Mat2X &x_camera, case RESECTION_EPNP: return EuclideanResectionEPnP(x_camera, X_world, R, t, success_threshold); break; + case RESECTION_PPNP: + return EuclideanResectionPPnP(x_camera, X_world, R, t, success_threshold); + break; default: LOG(FATAL) << "Unknown resection method."; } @@ -674,6 +682,107 @@ bool EuclideanResectionEPnP(const Mat2X &x_camera, // TODO(julien): Improve the solutions with non-linear refinement. return true; } + +/* + + Straight from the paper: + http://www.diegm.uniud.it/fusiello/papers/3dimpvt12-b.pdf + + function [R T] = ppnp(P,S,tol) + % input + % P : matrix (nx3) image coordinates in camera reference [u v 1] + % S : matrix (nx3) coordinates in world reference [X Y Z] + % tol: exit threshold + % + % output + % R : matrix (3x3) rotation (world-to-camera) + % T : vector (3x1) translation (world-to-camera) + % + n = size(P,1); + Z = zeros(n); + e = ones(n,1); + A = eye(n)-((e*e’)./n); + II = e./n; + err = +Inf; + E_old = 1000*ones(n,3); + while err>tol + [U,˜,V] = svd(P’*Z*A*S); + VT = V’; + R=U*[1 0 0; 0 1 0; 0 0 det(U*VT)]*VT; + PR = P*R; + c = (S-Z*PR)’*II; + Y = S-e*c’; + Zmindiag = diag(PR*Y’)./(sum(P.*P,2)); + Zmindiag(Zmindiag<0)=0; + Z = diag(Zmindiag); + E = Y-Z*PR; + err = norm(E-E_old,’fro’); + E_old = E; + end + T = -R*c; + end + + */ +// TODO(keir): Re-do all the variable names and add comments matching the paper. +// This implementation has too much of the terseness of the original. On the +// other hand, it did work on the first try. +bool EuclideanResectionPPnP(const Mat2X &x_camera, + const Mat3X &X_world, + Mat3 *R, Vec3 *t, + double tolerance) { + int n = x_camera.cols(); + Mat Z = Mat::Zero(n, n); + Vec e = Vec::Ones(n); + Mat A = Mat::Identity(n, n) - (e * e.transpose() / n); + Vec II = e / n; + + Mat P(n, 3); + P.col(0) = x_camera.row(0); + P.col(1) = x_camera.row(1); + P.col(2).setConstant(1.0); + + Mat S = X_world.transpose(); + + double error = std::numeric_limits<double>::infinity(); + Mat E_old = 1000 * Mat::Ones(n, 3); + + Vec3 c; + Mat E(n, 3); + + int iteration = 0; + tolerance = 1e-5; + // TODO(keir): The limit of 100 can probably be reduced, but this will require + // some investigation. + while (error > tolerance && iteration < 100) { + Mat3 tmp = P.transpose() * Z * A * S; + Eigen::JacobiSVD<Mat3> svd(tmp, Eigen::ComputeFullU | Eigen::ComputeFullV); + Mat3 U = svd.matrixU(); + Mat3 VT = svd.matrixV().transpose(); + Vec3 s; + s << 1, 1, (U * VT).determinant(); + *R = U * s.asDiagonal() * VT; + Mat PR = P * *R; // n x 3 + c = (S - Z*PR).transpose() * II; + Mat Y = S - e*c.transpose(); // n x 3 + Vec Zmindiag = (PR * Y.transpose()).diagonal() + .cwiseQuotient(P.rowwise().squaredNorm()); + for (int i = 0; i < n; ++i) { + Zmindiag[i] = std::max(Zmindiag[i], 0.0); + } + Z = Zmindiag.asDiagonal(); + E = Y - Z*PR; + error = (E - E_old).norm(); + LOG(INFO) << "PPnP error(" << (iteration++) << "): " << error; + E_old = E; + } + *t = -*R*c; + + // TODO(keir): Figure out what the failure cases are. Is it too many + // iterations? Spend some time going through the math figuring out if there + // is some way to detect that the algorithm is going crazy, and return false. + return true; +} + } // namespace resection } // namespace libmv diff --git a/extern/libmv/libmv/multiview/euclidean_resection.h b/extern/libmv/libmv/multiview/euclidean_resection.h index 1a329702c2a..ff9bccdd5c9 100644 --- a/extern/libmv/libmv/multiview/euclidean_resection.h +++ b/extern/libmv/libmv/multiview/euclidean_resection.h @@ -33,6 +33,10 @@ enum ResectionMethod { // The "EPnP" algorithm by Lepetit et al. // http://cvlab.epfl.ch/~lepetit/papers/lepetit_ijcv08.pdf RESECTION_EPNP, + + // The Procrustes PNP algorithm ("PPnP") + // http://www.diegm.uniud.it/fusiello/papers/3dimpvt12-b.pdf + RESECTION_PPNP }; /** diff --git a/extern/libmv/libmv/tracking/track_region.cc b/extern/libmv/libmv/tracking/track_region.cc index 6e9fb95654d..349d84b3817 100644 --- a/extern/libmv/libmv/tracking/track_region.cc +++ b/extern/libmv/libmv/tracking/track_region.cc @@ -796,7 +796,7 @@ struct TranslationRotationWarp { parameters[1] = t[1]; // Obtain the rotation via orthorgonal procrustes. - Mat2 correlation_matrix; + Mat2 correlation_matrix = Mat2::Zero(); for (int i = 0; i < 4; ++i) { correlation_matrix += q1.CornerRelativeToCentroid(i) * q2.CornerRelativeToCentroid(i).transpose(); @@ -864,7 +864,7 @@ struct TranslationRotationScaleWarp { parameters[2] = 1.0 - q2.Scale() / q1.Scale(); // Obtain the rotation via orthorgonal procrustes. - Mat2 correlation_matrix; + Mat2 correlation_matrix = Mat2::Zero(); for (int i = 0; i < 4; ++i) { correlation_matrix += q1.CornerRelativeToCentroid(i) * q2.CornerRelativeToCentroid(i).transpose(); diff --git a/intern/audaspace/OpenAL/AUD_OpenALDevice.cpp b/intern/audaspace/OpenAL/AUD_OpenALDevice.cpp index 371e0007bd3..676a86e88fe 100644 --- a/intern/audaspace/OpenAL/AUD_OpenALDevice.cpp +++ b/intern/audaspace/OpenAL/AUD_OpenALDevice.cpp @@ -67,6 +67,35 @@ static const char* queue_error = "AUD_OpenALDevice: Buffer couldn't be " static const char* bufferdata_error = "AUD_OpenALDevice: Buffer couldn't be " "filled with data."; +bool AUD_OpenALDevice::AUD_OpenALHandle::pause(bool keep) +{ + if(m_status) + { + AUD_MutexLock lock(*m_device); + + if(m_status == AUD_STATUS_PLAYING) + { + for(AUD_HandleIterator it = m_device->m_playingSounds.begin(); it != m_device->m_playingSounds.end(); it++) + { + if(it->get() == this) + { + boost::shared_ptr<AUD_OpenALHandle> This = *it; + + m_device->m_playingSounds.erase(it); + m_device->m_pausedSounds.push_back(This); + + alSourcePause(m_source); + + m_status = keep ? AUD_STATUS_STOPPED : AUD_STATUS_PAUSED; + + return true; + } + } + } + } + + return false;} + AUD_OpenALDevice::AUD_OpenALHandle::AUD_OpenALHandle(AUD_OpenALDevice* device, ALenum format, boost::shared_ptr<AUD_IReader> reader, bool keep) : m_isBuffered(false), m_reader(reader), m_keep(keep), m_format(format), m_current(0), m_eos(false), m_loopcount(0), m_stop(NULL), m_stop_data(NULL), m_status(AUD_STATUS_PLAYING), @@ -124,32 +153,7 @@ AUD_OpenALDevice::AUD_OpenALHandle::AUD_OpenALHandle(AUD_OpenALDevice* device, A bool AUD_OpenALDevice::AUD_OpenALHandle::pause() { - if(m_status) - { - AUD_MutexLock lock(*m_device); - - if(m_status == AUD_STATUS_PLAYING) - { - for(AUD_HandleIterator it = m_device->m_playingSounds.begin(); it != m_device->m_playingSounds.end(); it++) - { - if(it->get() == this) - { - boost::shared_ptr<AUD_OpenALHandle> This = *it; - - m_device->m_playingSounds.erase(it); - m_device->m_pausedSounds.push_back(This); - - alSourcePause(m_source); - - m_status = AUD_STATUS_PAUSED; - - return true; - } - } - } - } - - return false; + return pause(false); } bool AUD_OpenALDevice::AUD_OpenALHandle::resume() @@ -302,6 +306,9 @@ bool AUD_OpenALDevice::AUD_OpenALHandle::seek(float position) } } + if(m_status == AUD_STATUS_STOPPED) + m_status = AUD_STATUS_PAUSED; + return true; } @@ -409,7 +416,12 @@ bool AUD_OpenALDevice::AUD_OpenALHandle::setLoopCount(int count) { if(!m_status) return false; + + if(m_status == AUD_STATUS_STOPPED && (count > m_loopcount || count < 0)) + m_status = AUD_STATUS_PAUSED; + m_loopcount = count; + return true; } @@ -987,7 +999,7 @@ void AUD_OpenALDevice::updateStreams() } for(it = pauseSounds.begin(); it != pauseSounds.end(); it++) - (*it)->pause(); + (*it)->pause(true); for(it = stopSounds.begin(); it != stopSounds.end(); it++) (*it)->stop(); diff --git a/intern/audaspace/OpenAL/AUD_OpenALDevice.h b/intern/audaspace/OpenAL/AUD_OpenALDevice.h index d2a4be227ba..f0e47824967 100644 --- a/intern/audaspace/OpenAL/AUD_OpenALDevice.h +++ b/intern/audaspace/OpenAL/AUD_OpenALDevice.h @@ -96,6 +96,8 @@ private: /// Own device. AUD_OpenALDevice* m_device; + bool pause(bool keep); + public: /** diff --git a/intern/audaspace/Python/AUD_PyAPI.cpp b/intern/audaspace/Python/AUD_PyAPI.cpp index 9beba2eb0a0..b00289b3fae 100644 --- a/intern/audaspace/Python/AUD_PyAPI.cpp +++ b/intern/audaspace/Python/AUD_PyAPI.cpp @@ -2908,6 +2908,7 @@ PyInit_aud(void) PY_MODULE_ADD_CONSTANT(m, AUD_STATUS_INVALID); PY_MODULE_ADD_CONSTANT(m, AUD_STATUS_PAUSED); PY_MODULE_ADD_CONSTANT(m, AUD_STATUS_PLAYING); + PY_MODULE_ADD_CONSTANT(m, AUD_STATUS_STOPPED); // distance model constants PY_MODULE_ADD_CONSTANT(m, AUD_DISTANCE_MODEL_EXPONENT); PY_MODULE_ADD_CONSTANT(m, AUD_DISTANCE_MODEL_EXPONENT_CLAMPED); diff --git a/intern/audaspace/intern/AUD_IHandle.h b/intern/audaspace/intern/AUD_IHandle.h index 9dcb743693e..c80fb4027b8 100644 --- a/intern/audaspace/intern/AUD_IHandle.h +++ b/intern/audaspace/intern/AUD_IHandle.h @@ -113,6 +113,8 @@ public: *. invalid * - AUD_STATUS_PLAYING if the sound is currently played back. * - AUD_STATUS_PAUSED if the sound is currently paused. + * - AUD_STATUS_STOPPED if the sound finished playing and is still + * kept in the device. * \see AUD_Status */ virtual AUD_Status getStatus()=0; diff --git a/intern/audaspace/intern/AUD_SoftwareDevice.cpp b/intern/audaspace/intern/AUD_SoftwareDevice.cpp index a7e5b25664b..7bf59cd6f31 100644 --- a/intern/audaspace/intern/AUD_SoftwareDevice.cpp +++ b/intern/audaspace/intern/AUD_SoftwareDevice.cpp @@ -57,6 +57,37 @@ typedef enum /********************** AUD_SoftwareHandle Handle Code ************************/ /******************************************************************************/ +bool AUD_SoftwareDevice::AUD_SoftwareHandle::pause(bool keep) +{ + if(m_status) + { + AUD_MutexLock lock(*m_device); + + if(m_status == AUD_STATUS_PLAYING) + { + for(AUD_HandleIterator it = m_device->m_playingSounds.begin(); it != m_device->m_playingSounds.end(); it++) + { + if(it->get() == this) + { + boost::shared_ptr<AUD_SoftwareHandle> This = *it; + + m_device->m_playingSounds.erase(it); + m_device->m_pausedSounds.push_back(This); + + if(m_device->m_playingSounds.empty()) + m_device->playing(m_device->m_playback = false); + + m_status = keep ? AUD_STATUS_STOPPED : AUD_STATUS_PAUSED; + + return true; + } + } + } + } + + return false; +} + AUD_SoftwareDevice::AUD_SoftwareHandle::AUD_SoftwareHandle(AUD_SoftwareDevice* device, boost::shared_ptr<AUD_IReader> reader, boost::shared_ptr<AUD_PitchReader> pitch, boost::shared_ptr<AUD_ResampleReader> resampler, boost::shared_ptr<AUD_ChannelMapperReader> mapper, bool keep) : m_reader(reader), m_pitch(pitch), m_resampler(resampler), m_mapper(mapper), m_keep(keep), m_user_pitch(1.0f), m_user_volume(1.0f), m_user_pan(0.0f), m_volume(1.0f), m_loopcount(0), m_relative(true), m_volume_max(1.0f), m_volume_min(0), m_distance_max(std::numeric_limits<float>::max()), @@ -225,33 +256,7 @@ void AUD_SoftwareDevice::AUD_SoftwareHandle::setSpecs(AUD_Specs specs) bool AUD_SoftwareDevice::AUD_SoftwareHandle::pause() { - if(m_status) - { - AUD_MutexLock lock(*m_device); - - if(m_status == AUD_STATUS_PLAYING) - { - for(AUD_HandleIterator it = m_device->m_playingSounds.begin(); it != m_device->m_playingSounds.end(); it++) - { - if(it->get() == this) - { - boost::shared_ptr<AUD_SoftwareHandle> This = *it; - - m_device->m_playingSounds.erase(it); - m_device->m_pausedSounds.push_back(This); - - if(m_device->m_playingSounds.empty()) - m_device->playing(m_device->m_playback = false); - - m_status = AUD_STATUS_PAUSED; - - return true; - } - } - } - } - - return false; + return pause(false); } bool AUD_SoftwareDevice::AUD_SoftwareHandle::resume() @@ -360,6 +365,9 @@ bool AUD_SoftwareDevice::AUD_SoftwareHandle::seek(float position) m_reader->seek((int)(position * m_reader->getSpecs().rate)); + if(m_status == AUD_STATUS_STOPPED) + m_status = AUD_STATUS_PAUSED; + return true; } @@ -429,7 +437,12 @@ bool AUD_SoftwareDevice::AUD_SoftwareHandle::setLoopCount(int count) { if(!m_status) return false; + + if(m_status == AUD_STATUS_STOPPED && (count > m_loopcount || count < 0)) + m_status = AUD_STATUS_PAUSED; + m_loopcount = count; + return true; } @@ -793,19 +806,14 @@ void AUD_SoftwareDevice::mix(data_t* buffer, int length) m_mixer->read(buffer, m_volume); // cleanup - while(!stopSounds.empty()) - { - sound = stopSounds.front(); - stopSounds.pop_front(); - sound->stop(); - } + for(it = pauseSounds.begin(); it != pauseSounds.end(); it++) + (*it)->pause(true); - while(!pauseSounds.empty()) - { - sound = pauseSounds.front(); - pauseSounds.pop_front(); - sound->pause(); - } + for(it = stopSounds.begin(); it != stopSounds.end(); it++) + (*it)->stop(); + + pauseSounds.clear(); + stopSounds.clear(); } } diff --git a/intern/audaspace/intern/AUD_SoftwareDevice.h b/intern/audaspace/intern/AUD_SoftwareDevice.h index 8675a5ce2b8..3c8c1e438a3 100644 --- a/intern/audaspace/intern/AUD_SoftwareDevice.h +++ b/intern/audaspace/intern/AUD_SoftwareDevice.h @@ -139,6 +139,8 @@ protected: /// Own device. AUD_SoftwareDevice* m_device; + bool pause(bool keep); + public: /** diff --git a/intern/audaspace/intern/AUD_Space.h b/intern/audaspace/intern/AUD_Space.h index f42cb1ab018..ec2c06900ac 100644 --- a/intern/audaspace/intern/AUD_Space.h +++ b/intern/audaspace/intern/AUD_Space.h @@ -125,7 +125,8 @@ typedef enum { AUD_STATUS_INVALID = 0, /// Invalid handle. Maybe due to stopping. AUD_STATUS_PLAYING, /// Sound is playing. - AUD_STATUS_PAUSED /// Sound is being paused. + AUD_STATUS_PAUSED, /// Sound is being paused. + AUD_STATUS_STOPPED /// Sound is stopped but kept in the device. } AUD_Status; /// Error codes for exceptions (C++ library) or for return values (C API). diff --git a/intern/cycles/kernel/kernel_shader.h b/intern/cycles/kernel/kernel_shader.h index d8ff662c505..5dd12f98b9c 100644 --- a/intern/cycles/kernel/kernel_shader.h +++ b/intern/cycles/kernel/kernel_shader.h @@ -498,7 +498,7 @@ __device void shader_bsdf_eval(KernelGlobals *kg, const ShaderData *sd, #ifdef __MULTI_CLOSURE__ bsdf_eval_init(eval, NBUILTIN_CLOSURES, make_float3(0.0f, 0.0f, 0.0f), kernel_data.film.use_light_pass); - return _shader_bsdf_multi_eval(kg, sd, omega_in, pdf, -1, eval, 0.0f, 0.0f); + _shader_bsdf_multi_eval(kg, sd, omega_in, pdf, -1, eval, 0.0f, 0.0f); #else const ShaderClosure *sc = &sd->closure; @@ -720,7 +720,7 @@ __device float3 shader_bsdf_ao(KernelGlobals *kg, ShaderData *sd, float ao_facto eval += sc->weight*ao_factor; *N += sc->N*average(sc->weight); } - if(CLOSURE_IS_AMBIENT_OCCLUSION(sc->type)) { + else if(CLOSURE_IS_AMBIENT_OCCLUSION(sc->type)) { eval += sc->weight; *N += sd->N*average(sc->weight); } diff --git a/intern/cycles/kernel/osl/osl_closures.h b/intern/cycles/kernel/osl/osl_closures.h index 17d7260c191..ca5f441aa2d 100644 --- a/intern/cycles/kernel/osl/osl_closures.h +++ b/intern/cycles/kernel/osl/osl_closures.h @@ -33,14 +33,13 @@ #ifndef __OSL_CLOSURES_H__ #define __OSL_CLOSURES_H__ +#include "util_types.h" +#include "kernel_types.h" + #include <OSL/oslclosure.h> #include <OSL/oslexec.h> #include <OSL/genclosure.h> -#include "kernel_types.h" - -#include "util_types.h" - CCL_NAMESPACE_BEGIN OSL::ClosureParam *closure_emission_params(); diff --git a/intern/guardedalloc/intern/mallocn.c b/intern/guardedalloc/intern/mallocn.c index 08ac2ce6eff..06ae2ee864d 100644 --- a/intern/guardedalloc/intern/mallocn.c +++ b/intern/guardedalloc/intern/mallocn.c @@ -1142,12 +1142,12 @@ void *MEM_dupallocN(const void *vmemh) return newp; } -void *MEM_reallocN(void *vmemh, size_t len) +void *MEM_reallocN_id(void *vmemh, size_t len, const char *UNUSED(str)) { return realloc(vmemh, len); } -void *MEM_recallocN(void *vmemh, size_t len) +void *MEM_recallocN_id(void *vmemh, size_t len, const char *UNUSED(str)) { void *newp = NULL; diff --git a/release/scripts/modules/bpy_extras/image_utils.py b/release/scripts/modules/bpy_extras/image_utils.py index 551689c5a75..ff6d23badb6 100644 --- a/release/scripts/modules/bpy_extras/image_utils.py +++ b/release/scripts/modules/bpy_extras/image_utils.py @@ -105,7 +105,15 @@ def load_image(imagepath, if relpath is not None: # make relative from bpy.path import relpath as relpath_fn - image.filepath_raw = relpath_fn(path, start=relpath) + # can't always find the relative path + # (between drive letters on windows) + try: + filepath_rel = relpath_fn(path, start=relpath) + except ValueError: + filepath_rel = None + + if filepath_rel is not None: + image.filepath_raw = filepath_rel return image diff --git a/release/scripts/startup/bl_operators/add_mesh_torus.py b/release/scripts/startup/bl_operators/add_mesh_torus.py index 08dfc2bf8b5..692787ce281 100644 --- a/release/scripts/startup/bl_operators/add_mesh_torus.py +++ b/release/scripts/startup/bl_operators/add_mesh_torus.py @@ -105,11 +105,11 @@ class AddTorus(Operator, object_utils.AddObjectHelper): default=12, ) mode = bpy.props.EnumProperty( - name="Torus Dimentions", + name="Torus Dimensions", items=(("MAJOR_MINOR", "Major/Minor", - "Use the major/minor radiuses for torus dimensions"), + "Use the major/minor radii for torus dimensions"), ("EXT_INT", "Exterior/Interior", - "Use the exterior/interior radiuses for torus dimensions")), + "Use the exterior/interior radii for torus dimensions")), update=mode_update_callback, ) major_radius = FloatProperty( diff --git a/release/scripts/startup/bl_ui/properties_mask_common.py b/release/scripts/startup/bl_ui/properties_mask_common.py index d38f5f934b4..9f72d7a6d88 100644 --- a/release/scripts/startup/bl_ui/properties_mask_common.py +++ b/release/scripts/startup/bl_ui/properties_mask_common.py @@ -190,16 +190,21 @@ class MASK_PT_point(): clip = parent.id tracking = clip.tracking + row = col.row() + row.prop(parent, "type", expand=True) + col.prop_search(parent, "parent", tracking, "objects", icon='OBJECT_DATA', text="Object:") + tracks_list = "tracks" if parent.type == 'POINT_TRACK' else 'plane_tracks' + if parent.parent in tracking.objects: object = tracking.objects[parent.parent] col.prop_search(parent, "sub_parent", object, - "tracks", icon='ANIM_DATA', text="Track:") + tracks_list, icon='ANIM_DATA', text="Track:") else: col.prop_search(parent, "sub_parent", tracking, - "tracks", icon='ANIM_DATA', text="Track:") + tracks_list, icon='ANIM_DATA', text="Track:") class MASK_PT_display(): diff --git a/release/scripts/startup/bl_ui/space_clip.py b/release/scripts/startup/bl_ui/space_clip.py index 5048a93d565..04584855ed3 100644 --- a/release/scripts/startup/bl_ui/space_clip.py +++ b/release/scripts/startup/bl_ui/space_clip.py @@ -311,6 +311,16 @@ class CLIP_PT_tools_tracking(CLIP_PT_tracking_panel, Panel): layout.operator("clip.join_tracks", text="Join") +class CLIP_PT_tools_plane_tracking(CLIP_PT_tracking_panel, Panel): + bl_space_type = 'CLIP_EDITOR' + bl_region_type = 'TOOLS' + bl_label = "Plane Track" + + def draw(self, context): + layout = self.layout + layout.operator("clip.create_plane_track") + + class CLIP_PT_tools_solve(CLIP_PT_tracking_panel, Panel): bl_space_type = 'CLIP_EDITOR' bl_region_type = 'TOOLS' @@ -579,6 +589,26 @@ class CLIP_PT_track(CLIP_PT_tracking_panel, Panel): layout.label(text=label_text) +class CLIP_PT_plane_track(CLIP_PT_tracking_panel, Panel): + bl_space_type = 'CLIP_EDITOR' + bl_region_type = 'UI' + bl_label = "Plane Track" + + def draw(self, context): + layout = self.layout + + sc = context.space_data + clip = context.space_data.clip + active_track = clip.tracking.plane_tracks.active + + if not active_track: + layout.active = False + layout.label(text="No active plane track") + return + + layout.prop(active_track, "name") + + class CLIP_PT_track_settings(CLIP_PT_tracking_panel, Panel): bl_space_type = 'CLIP_EDITOR' bl_region_type = 'UI' diff --git a/release/scripts/startup/nodeitems_builtins.py b/release/scripts/startup/nodeitems_builtins.py index 91090dc2c75..6a5dccaed88 100644 --- a/release/scripts/startup/nodeitems_builtins.py +++ b/release/scripts/startup/nodeitems_builtins.py @@ -342,6 +342,7 @@ compositor_node_categories = [ NodeItem("CompositorNodeMapUV"), NodeItem("CompositorNodeTransform"), NodeItem("CompositorNodeStabilize"), + NodeItem("CompositorNodePlaneTrackDeform"), ]), CompositorNodeCategory("CMP_GROUP", "Group", items=node_group_items), CompositorNodeCategory("CMP_LAYOUT", "Layout", items=[ diff --git a/source/blender/blenkernel/BKE_curve.h b/source/blender/blenkernel/BKE_curve.h index 93f9ec276aa..baa90e7a856 100644 --- a/source/blender/blenkernel/BKE_curve.h +++ b/source/blender/blenkernel/BKE_curve.h @@ -69,7 +69,8 @@ bool BKE_curve_minmax(struct Curve *cu, float min[3], float max[3]); bool BKE_curve_center_median(struct Curve *cu, float cent[3]); bool BKE_curve_center_bounds(struct Curve *cu, float cent[3]); void BKE_curve_translate(struct Curve *cu, float offset[3], int do_keys); -void BKE_curve_delete_material_index(struct Curve *cu, int index); +void BKE_curve_material_index_remove(struct Curve *cu, int index); +void BKE_curve_material_index_clear(struct Curve *cu); ListBase *BKE_curve_nurbs_get(struct Curve *cu); diff --git a/source/blender/blenkernel/BKE_mask.h b/source/blender/blenkernel/BKE_mask.h index 92332116ba6..14ceba42aff 100644 --- a/source/blender/blenkernel/BKE_mask.h +++ b/source/blender/blenkernel/BKE_mask.h @@ -53,9 +53,11 @@ void BKE_mask_layer_active_set(struct Mask *mask, struct MaskLayer *masklay); void BKE_mask_layer_remove(struct Mask *mask, struct MaskLayer *masklay); void BKE_mask_layer_free_shapes(struct MaskLayer *masklay); +void BKE_mask_layer_free_deform(struct MaskLayer *mask_layer); void BKE_mask_layer_free(struct MaskLayer *masklay); void BKE_mask_layer_free_list(struct ListBase *masklayers); void BKE_mask_spline_free(struct MaskSpline *spline); +void BKE_mask_spline_free_list(struct ListBase *splines); struct MaskSpline *BKE_mask_spline_copy(struct MaskSpline *spline); void BKE_mask_point_free(struct MaskSplinePoint *point); diff --git a/source/blender/blenkernel/BKE_material.h b/source/blender/blenkernel/BKE_material.h index 7c47380f838..91c1715cca6 100644 --- a/source/blender/blenkernel/BKE_material.h +++ b/source/blender/blenkernel/BKE_material.h @@ -50,7 +50,7 @@ void init_def_material(void); void BKE_material_free(struct Material *sc); void BKE_material_free_ex(struct Material *ma, int do_id_user); void test_object_materials(struct Main *bmain, struct ID *id); -void resize_object_material(struct Object *ob, const short totcol); +void BKE_material_resize_object(struct Object *ob, const short totcol, bool do_id_user); void init_material(struct Material *ma); struct Material *BKE_material_add(struct Main *bmain, const char *name); struct Material *BKE_material_copy(struct Material *ma); @@ -87,9 +87,10 @@ int object_add_material_slot(struct Object *ob); int object_remove_material_slot(struct Object *ob); /* rna api */ -void material_append_id(struct ID *id, struct Material *ma); -struct Material *material_pop_id(struct ID *id, int index, int remove_material_slot); /* index is an int because of RNA */ - +void BKE_material_resize_id(struct ID *id, short totcol, bool do_id_user); +void BKE_material_append_id(struct ID *id, struct Material *ma); +struct Material *BKE_material_pop_id(struct ID *id, int index, bool update_data); /* index is an int because of RNA */ +void BKE_material_clear_id(struct ID *id, bool update_data); /* rendering */ void init_render_material(struct Material *, int, float *); diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h index 1c88a5c45dd..e582af77d61 100644 --- a/source/blender/blenkernel/BKE_mesh.h +++ b/source/blender/blenkernel/BKE_mesh.h @@ -188,7 +188,8 @@ void BKE_mesh_from_nurbs_displist(struct Object *ob, struct ListBase *dispbase, void BKE_mesh_from_nurbs(struct Object *ob); void BKE_mesh_to_curve_nurblist(struct DerivedMesh *dm, struct ListBase *nurblist, const int edge_users_test); void BKE_mesh_to_curve(struct Scene *scene, struct Object *ob); -void BKE_mesh_delete_material_index(struct Mesh *me, short index); +void BKE_mesh_material_index_remove(struct Mesh *me, short index); +void BKE_mesh_material_index_clear(struct Mesh *me); void BKE_mesh_smooth_flag_set(struct Object *meshOb, int enableSmooth); void BKE_mesh_convert_mfaces_to_mpolys(struct Mesh *mesh); void BKE_mesh_do_versions_convert_mfaces_to_mpolys(struct Mesh *mesh); diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index 4e9e18d43e3..27192437c89 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -898,6 +898,7 @@ void ntreeGPUMaterialNodes(struct bNodeTree *ntree, struct GPUMateria #define CMP_NODE_PIXELATE 318 #define CMP_NODE_MAP_RANGE 319 +#define CMP_NODE_PLANETRACKDEFORM 320 /* channel toggles */ #define CMP_CHAN_RGB 1 diff --git a/source/blender/blenkernel/BKE_tracking.h b/source/blender/blenkernel/BKE_tracking.h index 84bca0bd3ba..0d148e55753 100644 --- a/source/blender/blenkernel/BKE_tracking.h +++ b/source/blender/blenkernel/BKE_tracking.h @@ -38,6 +38,8 @@ struct ListBase; struct MovieReconstructContext; struct MovieTrackingTrack; struct MovieTrackingMarker; +struct MovieTrackingPlaneTrack; +struct MovieTrackingPlaneMarker; struct MovieTracking; struct MovieTrackingContext; struct MovieTrackingObject; @@ -55,6 +57,7 @@ void BKE_tracking_free(struct MovieTracking *tracking); void BKE_tracking_settings_init(struct MovieTracking *tracking); struct ListBase *BKE_tracking_get_active_tracks(struct MovieTracking *tracking); +struct ListBase *BKE_tracking_get_active_plane_tracks(struct MovieTracking *tracking); struct MovieTrackingReconstruction *BKE_tracking_get_active_reconstruction(struct MovieTracking *tracking); /* matrices for constraints and drawing */ @@ -97,6 +100,7 @@ float *BKE_tracking_track_get_mask(int frame_width, int frame_height, struct Mov /* selection */ void BKE_tracking_track_select(struct ListBase *tracksbase, struct MovieTrackingTrack *track, int area, int extend); void BKE_tracking_track_deselect(struct MovieTrackingTrack *track, int area); +void BKE_tracking_tracks_deselect_all(struct ListBase *tracksbase); /* **** Marker **** */ struct MovieTrackingMarker *BKE_tracking_marker_insert(struct MovieTrackingTrack *track, @@ -113,6 +117,32 @@ void BKE_tracking_marker_pattern_minmax(const struct MovieTrackingMarker *marker void BKE_tracking_marker_get_subframe_position(struct MovieTrackingTrack *track, float framenr, float pos[2]); +/* **** Plane Track **** */ +struct MovieTrackingPlaneTrack *BKE_tracking_plane_track_add(struct MovieTracking *tracking, struct ListBase *plane_tracks_base, + struct ListBase *tracks, int framenr); +void BKE_tracking_plane_track_unique_name(struct ListBase *plane_tracks_base, struct MovieTrackingPlaneTrack *plane_track); +void BKE_tracking_plane_track_free(struct MovieTrackingPlaneTrack *plane_track); + +bool BKE_tracking_plane_track_has_marker_at_frame(struct MovieTrackingPlaneTrack *plane_track, int framenr); +bool BKE_tracking_plane_track_has_enabled_marker_at_frame(struct MovieTrackingPlaneTrack *plane_track, int framenr); + +struct MovieTrackingPlaneTrack *BKE_tracking_plane_track_get_named(struct MovieTracking *tracking, + struct MovieTrackingObject *object, + const char *name); + +struct MovieTrackingPlaneTrack *BKE_tracking_plane_track_get_active(struct MovieTracking *tracking); + +void BKE_tracking_plane_tracks_deselect_all(struct ListBase *plane_tracks_base); + +/* **** Plane Marker **** */ +struct MovieTrackingPlaneMarker *BKE_tracking_plane_marker_insert(struct MovieTrackingPlaneTrack *plane_track, + struct MovieTrackingPlaneMarker *plane_marker); +void BKE_tracking_plane_marker_delete(struct MovieTrackingPlaneTrack *plane_track, int framenr); + +struct MovieTrackingPlaneMarker *BKE_tracking_plane_marker_get(struct MovieTrackingPlaneTrack *plane_track, int framenr); +struct MovieTrackingPlaneMarker *BKE_tracking_plane_marker_get_exact(struct MovieTrackingPlaneTrack *plane_track, int framenr); +struct MovieTrackingPlaneMarker *BKE_tracking_plane_marker_ensure(struct MovieTrackingPlaneTrack *plane_track, int framenr); + /* **** Object **** */ struct MovieTrackingObject *BKE_tracking_object_add(struct MovieTracking *tracking, const char *name); int BKE_tracking_object_delete(struct MovieTracking *tracking, struct MovieTrackingObject *object); @@ -125,6 +155,7 @@ struct MovieTrackingObject *BKE_tracking_object_get_active(struct MovieTracking struct MovieTrackingObject *BKE_tracking_object_get_camera(struct MovieTracking *tracking); struct ListBase *BKE_tracking_object_get_tracks(struct MovieTracking *tracking, struct MovieTrackingObject *object); +struct ListBase *BKE_tracking_object_get_plane_tracks(struct MovieTracking *tracking, struct MovieTrackingObject *object); struct MovieTrackingReconstruction *BKE_tracking_object_get_reconstruction(struct MovieTracking *tracking, struct MovieTrackingObject *object); @@ -182,6 +213,11 @@ void BKE_tracking_context_sync_user(const struct MovieTrackingContext *context, int BKE_tracking_context_step(struct MovieTrackingContext *context); void BKE_tracking_refine_marker(struct MovieClip *clip, struct MovieTrackingTrack *track, struct MovieTrackingMarker *marker, int backwards); +/* **** Plane tracking **** */ + +void BKE_tracking_track_plane_from_existing_motion(struct MovieTrackingPlaneTrack *plane_track, int start_frame); +void BKE_tracking_homography_between_two_quads(/*const*/ float reference_corners[4][2], /*const*/ float corners[4][2], float H[3][3]); + /* **** Camera solving **** */ int BKE_tracking_reconstruction_check(struct MovieTracking *tracking, struct MovieTrackingObject *object, char *error_msg, int error_size); diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c index eca607c08df..f006710dc21 100644 --- a/source/blender/blenkernel/intern/armature.c +++ b/source/blender/blenkernel/intern/armature.c @@ -1605,7 +1605,10 @@ static void pose_proxy_synchronize(Object *ob, Object *from, int layer_protected pchanw.next = pchan->next; pchanw.parent = pchan->parent; pchanw.child = pchan->child; - + + pchanw.mpath = pchan->mpath; + pchan->mpath = NULL; + /* this is freed so copy a copy, else undo crashes */ if (pchanw.prop) { pchanw.prop = IDP_CopyProperty(pchanw.prop); diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c index 26ae1b94aee..801ed4f00a5 100644 --- a/source/blender/blenkernel/intern/curve.c +++ b/source/blender/blenkernel/intern/curve.c @@ -2242,15 +2242,18 @@ static void make_bevel_list_3D_minimum_twist(BevList *bl) } } else { - /* Need to correct quat for the last point, + /* Need to correct quat for the first/last point, * this is so because previously it was only calculated * using it's own direction, which might not correspond - * the twist of previous point. + * the twist of neighbor point. */ + bevp1 = (BevPoint *)(bl + 1); + bevp0 = bevp1 + 1; + minimum_twist_between_two_points(bevp1, bevp0); + bevp2 = (BevPoint *)(bl + 1); bevp1 = bevp2 + (bl->nr - 1); bevp0 = bevp1 - 1; - minimum_twist_between_two_points(bevp1, bevp0); } } @@ -2369,12 +2372,23 @@ static void make_bevel_list_2D(BevList *bl) /* note: bevp->dir and bevp->quat are not needed for beveling but are * used when making a path from a 2D curve, therefor they need to be set - Campbell */ - BevPoint *bevp2 = (BevPoint *)(bl + 1); - BevPoint *bevp1 = bevp2 + (bl->nr - 1); - BevPoint *bevp0 = bevp1 - 1; + BevPoint *bevp0, *bevp1, *bevp2; int nr; - nr = bl->nr; + if (bl->poly != -1) { + bevp2 = (BevPoint *)(bl + 1); + bevp1 = bevp2 + (bl->nr - 1); + bevp0 = bevp1 - 1; + nr = bl->nr; + } + else { + bevp0 = (BevPoint *)(bl + 1); + bevp1 = bevp0 + 1; + bevp2 = bevp1 + 1; + + nr = bl->nr - 2; + } + while (nr--) { const float x1 = bevp1->vec[0] - bevp0->vec[0]; const float x2 = bevp1->vec[0] - bevp2->vec[0]; @@ -2396,15 +2410,23 @@ static void make_bevel_list_2D(BevList *bl) /* correct non-cyclic cases */ if (bl->poly == -1) { - BevPoint *bevp = (BevPoint *)(bl + 1); - bevp1 = bevp + 1; - bevp->sina = bevp1->sina; - bevp->cosa = bevp1->cosa; + BevPoint *bevp; + float angle; + + /* first */ + bevp = (BevPoint *)(bl + 1); + angle = atan2(bevp->dir[0], bevp->dir[1]) - M_PI / 2.0; + bevp->sina = sinf(angle); + bevp->cosa = cosf(angle); + vec_to_quat(bevp->quat, bevp->dir, 5, 1); + + /* last */ bevp = (BevPoint *)(bl + 1); bevp += (bl->nr - 1); - bevp1 = bevp - 1; - bevp->sina = bevp1->sina; - bevp->cosa = bevp1->cosa; + angle = atan2(bevp->dir[0], bevp->dir[1]) - M_PI / 2.0; + bevp->sina = sinf(angle); + bevp->cosa = cosf(angle); + vec_to_quat(bevp->quat, bevp->dir, 5, 1); } } @@ -3816,7 +3838,7 @@ void BKE_curve_translate(Curve *cu, float offset[3], int do_keys) } } -void BKE_curve_delete_material_index(Curve *cu, int index) +void BKE_curve_material_index_remove(Curve *cu, int index) { const int curvetype = BKE_curve_type_get(cu); @@ -3835,8 +3857,32 @@ void BKE_curve_delete_material_index(Curve *cu, int index) for (nu = cu->nurb.first; nu; nu = nu->next) { if (nu->mat_nr && nu->mat_nr >= index) { nu->mat_nr--; - if (curvetype == OB_CURVE) + if (curvetype == OB_CURVE) { nu->charidx--; + } + } + } + } +} + +void BKE_curve_material_index_clear(Curve *cu) +{ + const int curvetype = BKE_curve_type_get(cu); + + if (curvetype == OB_FONT) { + struct CharInfo *info = cu->strinfo; + int i; + for (i = cu->len - 1; i >= 0; i--, info++) { + info->mat_nr = 0; + } + } + else { + Nurb *nu; + + for (nu = cu->nurb.first; nu; nu = nu->next) { + nu->mat_nr = 0; + if (curvetype == OB_CURVE) { + nu->charidx = 0; } } } diff --git a/source/blender/blenkernel/intern/mask.c b/source/blender/blenkernel/intern/mask.c index e3f30bad5cf..a7bfb15c99d 100644 --- a/source/blender/blenkernel/intern/mask.c +++ b/source/blender/blenkernel/intern/mask.c @@ -817,6 +817,19 @@ void BKE_mask_spline_free(MaskSpline *spline) MEM_freeN(spline); } +void BKE_mask_spline_free_list(ListBase *splines) +{ + MaskSpline *spline = splines->first; + while (spline) { + MaskSpline *next_spline = spline->next; + + BLI_remlink(splines, spline); + BKE_mask_spline_free(spline); + + spline = next_spline; + } +} + static MaskSplinePoint *mask_spline_points_copy(MaskSplinePoint *points, int tot_point) { MaskSplinePoint *npoints; @@ -891,20 +904,30 @@ void BKE_mask_layer_free_shapes(MaskLayer *masklay) } } -void BKE_mask_layer_free(MaskLayer *masklay) +void BKE_mask_layer_free_deform(MaskLayer *mask_layer) { - MaskSpline *spline; - - /* free splines */ - spline = masklay->splines.first; - while (spline) { - MaskSpline *next_spline = spline->next; + MaskSpline *mask_spline; - BLI_remlink(&masklay->splines, spline); - BKE_mask_spline_free(spline); - - spline = next_spline; + for (mask_spline = mask_layer->splines.first; + mask_spline; + mask_spline = mask_spline->next) + { + if (mask_spline->points_deform) { + int i; + MaskSplinePoint *points_deform = mask_spline->points_deform; + for (i = 0; i < mask_spline->tot_point; i++) { + BKE_mask_point_free(&points_deform[i]); + } + MEM_freeN(points_deform); + mask_spline->points_deform = NULL; + } } +} + +void BKE_mask_layer_free(MaskLayer *masklay) +{ + /* free splines */ + BKE_mask_spline_free_list(&masklay->splines); /* free animation data */ BKE_mask_layer_free_shapes(masklay); @@ -1072,7 +1095,7 @@ void BKE_mask_coord_to_image(Image *image, ImageUser *iuser, float r_co[2], cons BKE_mask_coord_to_frame(r_co, co, frame_size); } -static int BKE_mask_evaluate_parent(MaskParent *parent, float ctime, float r_co[2]) +static int mask_evaluate_parent(MaskParent *parent, float ctime, float orig_co[2], float r_co[2]) { if (!parent) return FALSE; @@ -1084,18 +1107,38 @@ static int BKE_mask_evaluate_parent(MaskParent *parent, float ctime, float r_co[ MovieTrackingObject *ob = BKE_tracking_object_get_named(tracking, parent->parent); if (ob) { - MovieTrackingTrack *track = BKE_tracking_track_get_named(tracking, ob, parent->sub_parent); + MovieClipUser user = {0}; float clip_framenr = BKE_movieclip_remap_scene_to_clip_frame(clip, ctime); + BKE_movieclip_user_set_frame(&user, ctime); - MovieClipUser user = {0}; - user.framenr = ctime; + if (parent->type == MASK_PARENT_POINT_TRACK) { + MovieTrackingTrack *track = BKE_tracking_track_get_named(tracking, ob, parent->sub_parent); - if (track) { - float marker_pos_ofs[2]; - BKE_tracking_marker_get_subframe_position(track, clip_framenr, marker_pos_ofs); - BKE_mask_coord_from_movieclip(clip, &user, r_co, marker_pos_ofs); + if (track) { + float marker_pos_ofs[2]; + BKE_tracking_marker_get_subframe_position(track, clip_framenr, marker_pos_ofs); + BKE_mask_coord_from_movieclip(clip, &user, r_co, marker_pos_ofs); - return TRUE; + return TRUE; + } + } + else /* if (parent->type == MASK_PARENT_PLANE_TRACK) */ { + MovieTrackingPlaneTrack *plane_track = BKE_tracking_plane_track_get_named(tracking, ob, parent->sub_parent); + + if (plane_track) { + MovieTrackingPlaneMarker *plane_marker = BKE_tracking_plane_marker_get(plane_track, clip_framenr); + float H[3][3], vec[3], warped[3]; + + BKE_tracking_homography_between_two_quads(parent->parent_corners_orig, plane_marker->corners, H); + + BKE_mask_coord_to_movieclip(clip, &user, vec, orig_co); + vec[2] = 1.0f; + mul_v3_m3v3(warped, H, vec); + warped[0] /= warped[2]; + warped[1] /= warped[2]; + + BKE_mask_coord_from_movieclip(clip, &user, r_co, warped); + } } } } @@ -1104,17 +1147,26 @@ static int BKE_mask_evaluate_parent(MaskParent *parent, float ctime, float r_co[ return FALSE; } -/* could make external but for now its only used internally */ -static int mask_evaluate_parent_delta(MaskParent *parent, float ctime, float r_delta[2]) +static void mask_evaluate_apply_point_parent(MaskSplinePoint *point, float ctime) { - float parent_co[2]; + MaskParent *parent = &point->parent; + + if (parent->type == MASK_PARENT_POINT_TRACK) { + float parent_co[2]; - if (BKE_mask_evaluate_parent(parent, ctime, parent_co)) { - sub_v2_v2v2(r_delta, parent_co, parent->parent_orig); - return TRUE; + if (mask_evaluate_parent(parent, ctime, NULL, parent_co)) { + float delta[2]; + sub_v2_v2v2(delta, parent_co, parent->parent_orig); + + add_v2_v2(point->bezt.vec[0], delta); + add_v2_v2(point->bezt.vec[1], delta); + add_v2_v2(point->bezt.vec[2], delta); + } } - else { - return FALSE; + else /* if (parent->type == MASK_PARENT_PLANE_TRACK) */ { + mask_evaluate_parent(parent, ctime, point->bezt.vec[0], point->bezt.vec[0]); + mask_evaluate_parent(parent, ctime, point->bezt.vec[1], point->bezt.vec[1]); + mask_evaluate_parent(parent, ctime, point->bezt.vec[2], point->bezt.vec[2]); } } @@ -1438,18 +1490,13 @@ void BKE_mask_layer_evaluate(MaskLayer *masklay, const float ctime, const int do for (i = 0; i < spline->tot_point; i++) { MaskSplinePoint *point = &spline->points[i]; MaskSplinePoint *point_deform = &spline->points_deform[i]; - float delta[2]; BKE_mask_point_free(point_deform); *point_deform = *point; point_deform->uw = point->uw ? MEM_dupallocN(point->uw) : NULL; - if (mask_evaluate_parent_delta(&point->parent, ctime, delta)) { - add_v2_v2(point_deform->bezt.vec[0], delta); - add_v2_v2(point_deform->bezt.vec[1], delta); - add_v2_v2(point_deform->bezt.vec[2], delta); - } + mask_evaluate_apply_point_parent(point_deform, ctime); if (ELEM(point->bezt.h1, HD_AUTO, HD_VECT)) { need_handle_recalc = TRUE; diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c index 6dc3c6d7bc6..c23b4ac4408 100644 --- a/source/blender/blenkernel/intern/material.c +++ b/source/blender/blenkernel/intern/material.c @@ -537,17 +537,17 @@ short *give_totcolp_id(ID *id) return NULL; } -static void data_delete_material_index_id(ID *id, short index) +static void material_data_index_remove_id(ID *id, short index) { /* ensure we don't try get materials from non-obdata */ BLI_assert(OB_DATA_SUPPORT_ID(GS(id->name))); switch (GS(id->name)) { case ID_ME: - BKE_mesh_delete_material_index((Mesh *)id, index); + BKE_mesh_material_index_remove((Mesh *)id, index); break; case ID_CU: - BKE_curve_delete_material_index((Curve *)id, index); + BKE_curve_material_index_remove((Curve *)id, index); break; case ID_MB: /* meta-elems don't have materials atm */ @@ -555,7 +555,53 @@ static void data_delete_material_index_id(ID *id, short index) } } -void material_append_id(ID *id, Material *ma) +static void material_data_index_clear_id(ID *id) +{ + /* ensure we don't try get materials from non-obdata */ + BLI_assert(OB_DATA_SUPPORT_ID(GS(id->name))); + + switch (GS(id->name)) { + case ID_ME: + BKE_mesh_material_index_clear((Mesh *)id); + break; + case ID_CU: + BKE_curve_material_index_clear((Curve *)id); + break; + case ID_MB: + /* meta-elems don't have materials atm */ + break; + } +} + +void BKE_material_resize_id(struct ID *id, short totcol, bool do_id_user) +{ + Material ***matar = give_matarar_id(id); + short *totcolp = give_totcolp_id(id); + + if (matar == NULL) { + return; + } + + if (do_id_user && totcol < (*totcolp)) { + short i; + for (i = totcol; i < (*totcolp); i++) { + id_us_min((ID *)(*matar)[i]); + } + } + + if (totcol == 0) { + if (*totcolp) { + MEM_freeN(*matar); + *matar = NULL; + } + } + else { + *matar = MEM_recallocN(*matar, sizeof(void *) * totcol); + } + *totcolp = totcol; +} + +void BKE_material_append_id(ID *id, Material *ma) { Material ***matar; if ((matar = give_matarar_id(id))) { @@ -572,7 +618,7 @@ void material_append_id(ID *id, Material *ma) } } -Material *material_pop_id(ID *id, int index_i, int remove_material_slot) +Material *BKE_material_pop_id(ID *id, int index_i, bool update_data) { short index = (short)index_i; Material *ret = NULL; @@ -583,40 +629,48 @@ Material *material_pop_id(ID *id, int index_i, int remove_material_slot) ret = (*matar)[index]; id_us_min((ID *)ret); - if (remove_material_slot) { - if (*totcol <= 1) { - *totcol = 0; - MEM_freeN(*matar); - *matar = NULL; - } - else { - Material **mat; - if (index + 1 != (*totcol)) - memmove((*matar) + index, (*matar) + (index + 1), sizeof(void *) * ((*totcol) - (index + 1))); - - (*totcol)--; - - mat = MEM_callocN(sizeof(void *) * (*totcol), "newmatar"); - memcpy(mat, *matar, sizeof(void *) * (*totcol)); - MEM_freeN(*matar); - - *matar = mat; - test_object_materials(G.main, id); - } + if (*totcol <= 1) { + *totcol = 0; + MEM_freeN(*matar); + *matar = NULL; + } + else { + if (index + 1 != (*totcol)) + memmove((*matar) + index, (*matar) + (index + 1), sizeof(void *) * ((*totcol) - (index + 1))); - /* decrease mat_nr index */ - data_delete_material_index_id(id, index); + (*totcol)--; + *matar = MEM_reallocN(*matar, sizeof(void *) * (*totcol)); + test_object_materials(G.main, id); } - /* don't remove material slot, only clear it*/ - else - (*matar)[index] = NULL; + if (update_data) { + /* decrease mat_nr index */ + material_data_index_remove_id(id, index); + } } } return ret; } +void BKE_material_clear_id(struct ID *id, bool update_data) +{ + Material ***matar; + if ((matar = give_matarar_id(id))) { + short *totcol = give_totcolp_id(id); + *totcol = 0; + if (*matar) { + MEM_freeN(*matar); + *matar = NULL; + } + + if (update_data) { + /* decrease mat_nr index */ + material_data_index_clear_id(id); + } + } +} + Material *give_current_material(Object *ob, short act) { Material ***matarar, *ma; @@ -682,11 +736,18 @@ Material *give_node_material(Material *ma) return NULL; } -void resize_object_material(Object *ob, const short totcol) +void BKE_material_resize_object(Object *ob, const short totcol, bool do_id_user) { Material **newmatar; char *newmatbits; + if (do_id_user && totcol < ob->totcol) { + short i; + for (i = totcol; i < ob->totcol; i++) { + id_us_min((ID *)ob->mat[i]); + } + } + if (totcol == 0) { if (ob->totcol) { MEM_freeN(ob->mat); @@ -707,6 +768,8 @@ void resize_object_material(Object *ob, const short totcol) ob->mat = newmatar; ob->matbits = newmatbits; } + /* XXX, why not realloc on shrink? - campbell */ + ob->totcol = totcol; if (ob->totcol && ob->actcol == 0) ob->actcol = 1; if (ob->actcol > ob->totcol) ob->actcol = ob->totcol; @@ -724,7 +787,7 @@ void test_object_materials(Main *bmain, ID *id) for (ob = bmain->object.first; ob; ob = ob->id.next) { if (ob->data == id) { - resize_object_material(ob, *totcol); + BKE_material_resize_object(ob, *totcol, false); } } } @@ -1227,7 +1290,7 @@ int object_remove_material_slot(Object *ob) /* check indices from mesh */ if (ELEM4(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT)) { - data_delete_material_index_id((ID *)ob->data, actcol - 1); + material_data_index_remove_id((ID *)ob->data, actcol - 1); BKE_displist_free(&ob->disp); } @@ -1703,7 +1766,7 @@ static short mesh_getmaterialnumber(Mesh *me, Material *ma) /* append material */ static short mesh_addmaterial(Mesh *me, Material *ma) { - material_append_id(&me->id, NULL); + BKE_material_append_id(&me->id, NULL); me->mat[me->totcol - 1] = ma; id_us_plus(&ma->id); @@ -1840,8 +1903,14 @@ static void convert_tfacematerial(Main *main, Material *ma) mf->mat_nr = mat_nr; } /* remove material from mesh */ - for (a = 0; a < me->totcol; ) - if (me->mat[a] == ma) material_pop_id(&me->id, a, 1); else a++; + for (a = 0; a < me->totcol; ) { + if (me->mat[a] == ma) { + BKE_material_pop_id(&me->id, a, true); + } + else { + a++; + } + } } } diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c index 095957b40d5..0db1f92f70f 100644 --- a/source/blender/blenkernel/intern/mesh.c +++ b/source/blender/blenkernel/intern/mesh.c @@ -1852,20 +1852,37 @@ void BKE_mesh_to_curve(Scene *scene, Object *ob) } } -void BKE_mesh_delete_material_index(Mesh *me, short index) +void BKE_mesh_material_index_remove(Mesh *me, short index) { + MPoly *mp; + MFace *mf; int i; - for (i = 0; i < me->totpoly; i++) { - MPoly *mp = &((MPoly *) me->mpoly)[i]; - if (mp->mat_nr && mp->mat_nr >= index) + for (mp = me->mpoly, i = 0; i < me->totpoly; i++, mp++) { + if (mp->mat_nr && mp->mat_nr >= index) { mp->mat_nr--; + } } - - for (i = 0; i < me->totface; i++) { - MFace *mf = &((MFace *) me->mface)[i]; - if (mf->mat_nr && mf->mat_nr >= index) + + for (mf = me->mface, i = 0; i < me->totface; i++, mf++) { + if (mf->mat_nr && mf->mat_nr >= index) { mf->mat_nr--; + } + } +} + +void BKE_mesh_material_index_clear(Mesh *me) +{ + MPoly *mp; + MFace *mf; + int i; + + for (mp = me->mpoly, i = 0; i < me->totpoly; i++, mp++) { + mp->mat_nr = 0; + } + + for (mf = me->mface, i = 0; i < me->totface; i++, mf++) { + mf->mat_nr = 0; } } diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c index 5001aa01653..1349c4dc8d4 100644 --- a/source/blender/blenkernel/intern/node.c +++ b/source/blender/blenkernel/intern/node.c @@ -3391,6 +3391,7 @@ static void registerCompositNodes(void) register_node_type_cmp_mask(); register_node_type_cmp_trackpos(); + register_node_type_cmp_planetrackdeform(); } static void registerShaderNodes(void) diff --git a/source/blender/blenkernel/intern/sound.c b/source/blender/blenkernel/intern/sound.c index feff8f95fd7..2f8eb7d9931 100644 --- a/source/blender/blenkernel/intern/sound.c +++ b/source/blender/blenkernel/intern/sound.c @@ -60,10 +60,6 @@ #include "BKE_sequencer.h" #include "BKE_scene.h" -// evil quiet NaN definition -static const int NAN_INT = 0x7FC00000; -#define NAN_FLT *((float *)(&NAN_INT)) - #ifdef WITH_AUDASPACE // evil global ;-) static int sound_cfra; diff --git a/source/blender/blenkernel/intern/tracking.c b/source/blender/blenkernel/intern/tracking.c index 4c363292898..54ba9ea56d7 100644 --- a/source/blender/blenkernel/intern/tracking.c +++ b/source/blender/blenkernel/intern/tracking.c @@ -103,6 +103,18 @@ static void tracking_tracks_free(ListBase *tracks) BLI_freelistN(tracks); } +/* Free the whole list of plane tracks, list's head and tail are set to NULL. */ +static void tracking_plane_tracks_free(ListBase *plane_tracks) +{ + MovieTrackingPlaneTrack *plane_track; + + for (plane_track = plane_tracks->first; plane_track; plane_track = plane_track->next) { + BKE_tracking_plane_track_free(plane_track); + } + + BLI_freelistN(plane_tracks); +} + /* Free reconstruction structures, only frees contents of a structure, * (if structure is allocated in heap, it shall be handled outside). * @@ -122,6 +134,7 @@ static void tracking_reconstruction_free(MovieTrackingReconstruction *reconstruc static void tracking_object_free(MovieTrackingObject *object) { tracking_tracks_free(&object->tracks); + tracking_plane_tracks_free(&object->plane_tracks); tracking_reconstruction_free(&object->reconstruction); } @@ -173,6 +186,7 @@ static void tracking_dopesheet_free(MovieTrackingDopesheet *dopesheet) void BKE_tracking_free(MovieTracking *tracking) { tracking_tracks_free(&tracking->tracks); + tracking_plane_tracks_free(&tracking->plane_tracks); tracking_reconstruction_free(&tracking->reconstruction); tracking_objects_free(&tracking->objects); @@ -221,6 +235,18 @@ ListBase *BKE_tracking_get_active_tracks(MovieTracking *tracking) return &tracking->tracks; } +/* Get list base of active object's plane tracks. */ +ListBase *BKE_tracking_get_active_plane_tracks(MovieTracking *tracking) +{ + MovieTrackingObject *object = BKE_tracking_object_get_active(tracking); + + if (object && (object->flag & TRACKING_OBJECT_CAMERA) == 0) { + return &object->plane_tracks; + } + + return &tracking->plane_tracks; +} + /* Get reconstruction data of active object. */ MovieTrackingReconstruction *BKE_tracking_get_active_reconstruction(MovieTracking *tracking) { @@ -1025,6 +1051,17 @@ void BKE_tracking_track_deselect(MovieTrackingTrack *track, int area) BKE_tracking_track_flag_clear(track, area, SELECT); } +void BKE_tracking_tracks_deselect_all(ListBase *tracksbase) +{ + MovieTrackingTrack *track; + + for (track = tracksbase->first; track; track = track->next) { + if ((track->flag & TRACK_HIDDEN) == 0) { + BKE_tracking_track_flag_clear(track, TRACK_AREA_ALL, SELECT); + } + } +} + /*********************** Marker *************************/ MovieTrackingMarker *BKE_tracking_marker_insert(MovieTrackingTrack *track, MovieTrackingMarker *marker) @@ -1264,6 +1301,296 @@ void BKE_tracking_marker_get_subframe_position(MovieTrackingTrack *track, float add_v2_v2(pos, track->offset); } +/*********************** Plane Track *************************/ + +/* Creates new plane track out of selected point tracks */ +MovieTrackingPlaneTrack *BKE_tracking_plane_track_add(MovieTracking *tracking, ListBase *plane_tracks_base, + ListBase *tracks, int framenr) +{ + MovieTrackingPlaneTrack *plane_track; + MovieTrackingPlaneMarker plane_marker; + MovieTrackingTrack *track; + float tracks_min[2], tracks_max[2]; + int track_index, num_selected_tracks = 0; + + (void) tracking; /* Ignored. */ + + /* Use bounding box of selected markers as an initial size of plane. */ + INIT_MINMAX2(tracks_min, tracks_max); + for (track = tracks->first; track; track = track->next) { + if (TRACK_SELECTED(track)) { + MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr); + float pattern_min[2], pattern_max[2]; + BKE_tracking_marker_pattern_minmax(marker, pattern_min, pattern_max); + add_v2_v2(pattern_min, marker->pos); + add_v2_v2(pattern_max, marker->pos); + minmax_v2v2_v2(tracks_min, tracks_max, pattern_min); + minmax_v2v2_v2(tracks_min, tracks_max, pattern_max); + num_selected_tracks++; + } + } + + if (num_selected_tracks < 4) { + return NULL; + } + + /* Allocate new plane track. */ + plane_track = MEM_callocN(sizeof(MovieTrackingPlaneTrack), "new plane track"); + + /* Use some default name. */ + strcpy(plane_track->name, "Plane Track"); + + /* Use selected tracks from given list as a plane. */ + plane_track->point_tracks = MEM_mallocN(sizeof(MovieTrackingTrack *) * num_selected_tracks, "new plane tracks array"); + for (track = tracks->first, track_index = 0; track; track = track->next) { + if (TRACK_SELECTED(track)) { + plane_track->point_tracks[track_index] = track; + track_index++; + } + } + plane_track->point_tracksnr = num_selected_tracks; + + /* Setup new plane marker and add it to the track. */ + plane_marker.framenr = framenr; + plane_marker.flag = 0; + + copy_v2_v2(plane_marker.corners[0], tracks_min); + copy_v2_v2(plane_marker.corners[2], tracks_max); + + plane_marker.corners[1][0] = tracks_max[0]; + plane_marker.corners[1][1] = tracks_min[1]; + plane_marker.corners[3][0] = tracks_min[0]; + plane_marker.corners[3][1] = tracks_max[1]; + + BKE_tracking_plane_marker_insert(plane_track, &plane_marker); + + /* Put new plane track to the list, ensure it's name is unique. */ + BLI_addtail(plane_tracks_base, plane_track); + BKE_tracking_plane_track_unique_name(plane_tracks_base, plane_track); + + return plane_track; +} + +void BKE_tracking_plane_track_unique_name(ListBase *plane_tracks_base, MovieTrackingPlaneTrack *plane_track) +{ + BLI_uniquename(plane_tracks_base, plane_track, CTX_DATA_(BLF_I18NCONTEXT_ID_MOVIECLIP, "Plane Track"), '.', + offsetof(MovieTrackingPlaneTrack, name), sizeof(plane_track->name)); +} + +/* Free specified plane track, only frees contents of a structure + * (if track is allocated in heap, it shall be handled outside). + * + * All the pointers inside track becomes invalid after this call. + */ +void BKE_tracking_plane_track_free(MovieTrackingPlaneTrack *plane_track) +{ + if (plane_track->markers) { + MEM_freeN(plane_track->markers); + } + + MEM_freeN(plane_track->point_tracks); +} + +MovieTrackingPlaneTrack *BKE_tracking_plane_track_get_named(MovieTracking *tracking, + MovieTrackingObject *object, + const char *name) +{ + ListBase *plane_tracks_base = BKE_tracking_object_get_plane_tracks(tracking, object); + MovieTrackingPlaneTrack *plane_track; + + for (plane_track = plane_tracks_base->first; + plane_track; + plane_track = plane_track->next) + { + if (!strcmp(plane_track->name, name)) { + return plane_track; + } + } + + return NULL; +} + +MovieTrackingPlaneTrack *BKE_tracking_plane_track_get_active(struct MovieTracking *tracking) +{ + ListBase *plane_tracks_base; + + if (tracking->act_plane_track == NULL) { + return NULL; + } + + plane_tracks_base = BKE_tracking_get_active_plane_tracks(tracking); + + /* Check that active track is in current plane tracks list */ + if (BLI_findindex(plane_tracks_base, tracking->act_plane_track) >= 0) { + return tracking->act_plane_track; + } + + return NULL; +} + +void BKE_tracking_plane_tracks_deselect_all(ListBase *plane_tracks_base) +{ + MovieTrackingPlaneTrack *plane_track; + + for (plane_track = plane_tracks_base->first; plane_track; plane_track = plane_track->next) { + plane_track->flag &= ~SELECT; + } +} + +/*********************** Plane Marker *************************/ + +MovieTrackingPlaneMarker *BKE_tracking_plane_marker_insert(MovieTrackingPlaneTrack *plane_track, + MovieTrackingPlaneMarker *plane_marker) +{ + MovieTrackingPlaneMarker *old_plane_marker = NULL; + + if (plane_track->markersnr) + old_plane_marker = BKE_tracking_plane_marker_get_exact(plane_track, plane_marker->framenr); + + if (old_plane_marker) { + /* Simply replace settings in existing marker. */ + *old_plane_marker = *plane_marker; + + return old_plane_marker; + } + else { + int a = plane_track->markersnr; + + /* Find position in array where to add new marker. */ + /* TODO(sergey): we coud use bisect to speed things up. */ + while (a--) { + if (plane_track->markers[a].framenr < plane_marker->framenr) { + break; + } + } + + plane_track->markersnr++; + plane_track->markers = MEM_reallocN(plane_track->markers, + sizeof(MovieTrackingPlaneMarker) * plane_track->markersnr); + + /* Shift array to "free" space for new marker. */ + memmove(plane_track->markers + a + 2, plane_track->markers + a + 1, + (plane_track->markersnr - a - 2) * sizeof(MovieTrackingPlaneMarker)); + + /* Put new marker to an array. */ + plane_track->markers[a + 1] = *plane_marker; + plane_track->last_marker = a + 1; + + return &plane_track->markers[a + 1]; + } +} + +void BKE_tracking_plane_marker_delete(MovieTrackingPlaneTrack *plane_track, int framenr) +{ + int a = 0; + + while (a < plane_track->markersnr) { + if (plane_track->markers[a].framenr == framenr) { + if (plane_track->markersnr > 1) { + memmove(plane_track->markers + a, plane_track->markers + a + 1, + (plane_track->markersnr - a - 1) * sizeof(MovieTrackingPlaneMarker)); + plane_track->markersnr--; + plane_track->markers = MEM_reallocN(plane_track->markers, + sizeof(MovieTrackingMarker) * plane_track->markersnr); + } + else { + MEM_freeN(plane_track->markers); + plane_track->markers = NULL; + plane_track->markersnr = 0; + } + + break; + } + + a++; + } +} + +/* TODO(sergey): The next couple of functions are really quite the same as point marker version, + * would be nice to de-duplicate them somehow.. + */ + +/* Get a plane marker at given frame, + * If there's no such marker, closest one from the left side will be returned. + */ +MovieTrackingPlaneMarker *BKE_tracking_plane_marker_get(MovieTrackingPlaneTrack *plane_track, int framenr) +{ + int a = plane_track->markersnr - 1; + + if (!plane_track->markersnr) + return NULL; + + /* Approximate pre-first framenr marker with first marker. */ + if (framenr < plane_track->markers[0].framenr) { + return &plane_track->markers[0]; + } + + if (plane_track->last_marker < plane_track->markersnr) { + a = plane_track->last_marker; + } + + if (plane_track->markers[a].framenr <= framenr) { + while (a < plane_track->markersnr && plane_track->markers[a].framenr <= framenr) { + if (plane_track->markers[a].framenr == framenr) { + plane_track->last_marker = a; + + return &plane_track->markers[a]; + } + a++; + } + + /* If there's no marker for exact position, use nearest marker from left side. */ + return &plane_track->markers[a - 1]; + } + else { + while (a >= 0 && plane_track->markers[a].framenr >= framenr) { + if (plane_track->markers[a].framenr == framenr) { + plane_track->last_marker = a; + + return &plane_track->markers[a]; + } + + a--; + } + + /* If there's no marker for exact position, use nearest marker from left side. */ + return &plane_track->markers[a]; + } + + return NULL; +} + +/* Get a plane marker at exact given frame, if there's no marker at the frame, + * NULL will be returned. + */ +MovieTrackingPlaneMarker *BKE_tracking_plane_marker_get_exact(MovieTrackingPlaneTrack *plane_track, int framenr) +{ + MovieTrackingPlaneMarker *plane_marker = BKE_tracking_plane_marker_get(plane_track, framenr); + + if (plane_marker->framenr != framenr) { + return NULL; + } + + return plane_marker; +} + +/* Ensure there's a marker for the given frame. */ +MovieTrackingPlaneMarker *BKE_tracking_plane_marker_ensure(MovieTrackingPlaneTrack *plane_track, int framenr) +{ + MovieTrackingPlaneMarker *plane_marker = BKE_tracking_plane_marker_get(plane_track, framenr); + + if (plane_marker->framenr != framenr) { + MovieTrackingPlaneMarker plane_marker_new; + + plane_marker_new = *plane_marker; + plane_marker_new.framenr = framenr; + + plane_marker = BKE_tracking_plane_marker_insert(plane_track, &plane_marker_new); + } + + return plane_marker; +} + /*********************** Object *************************/ MovieTrackingObject *BKE_tracking_object_add(MovieTracking *tracking, const char *name) @@ -1379,6 +1706,15 @@ ListBase *BKE_tracking_object_get_tracks(MovieTracking *tracking, MovieTrackingO return &object->tracks; } +ListBase *BKE_tracking_object_get_plane_tracks(MovieTracking *tracking, MovieTrackingObject *object) +{ + if (object->flag & TRACKING_OBJECT_CAMERA) { + return &tracking->plane_tracks; + } + + return &object->plane_tracks; +} + MovieTrackingReconstruction *BKE_tracking_object_get_reconstruction(MovieTracking *tracking, MovieTrackingObject *object) { @@ -2528,7 +2864,7 @@ static bool track_context_update_reference(MovieTrackingContext *context, TrackC } /* Fill in libmv tracker options structure with settings need to be used to perform track. */ -static void tracking_configure_tracker(MovieTrackingTrack *track, float *mask, +static void tracking_configure_tracker(const MovieTrackingTrack *track, float *mask, libmv_TrackRegionOptions *options) { options->motion_model = track->motion_model; @@ -2863,6 +3199,147 @@ void BKE_tracking_refine_marker(MovieClip *clip, MovieTrackingTrack *track, Movi IMB_freeImBuf(destination_ibuf); } +/*********************** Plane tracking *************************/ + +typedef double Vec2[2]; + +static int point_markers_correspondences_on_both_image(MovieTrackingPlaneTrack *plane_track, int frame1, int frame2, + Vec2 **x1_r, Vec2 **x2_r) +{ + int i, correspondence_index; + Vec2 *x1, *x2; + + *x1_r = x1 = MEM_mallocN(sizeof(*x1) * plane_track->point_tracksnr, "point correspondences x1"); + *x2_r = x2 = MEM_mallocN(sizeof(*x1) * plane_track->point_tracksnr, "point correspondences x2"); + + for (i = 0, correspondence_index = 0; i < plane_track->point_tracksnr; i++) { + MovieTrackingTrack *point_track = plane_track->point_tracks[i]; + MovieTrackingMarker *point_marker1, *point_marker2; + + point_marker1 = BKE_tracking_marker_get_exact(point_track, frame1); + point_marker2 = BKE_tracking_marker_get_exact(point_track, frame2); + + if (point_marker1 != NULL && point_marker2 != NULL) { + /* Here conversion from float to double happens. */ + x1[correspondence_index][0] = point_marker1->pos[0]; + x1[correspondence_index][1] = point_marker1->pos[1]; + + x2[correspondence_index][0] = point_marker2->pos[0]; + x2[correspondence_index][1] = point_marker2->pos[1]; + + correspondence_index++; + } + } + + return correspondence_index; +} + +/* TODO(sergey): Make it generic function available for everyone. */ +BLI_INLINE void mat3f_from_mat3d(float mat_float[3][3], double mat_double[3][3]) +{ + /* Keep it stupid simple for better data flow in CPU. */ + mat_float[0][0] = mat_double[0][0]; + mat_float[0][1] = mat_double[0][1]; + mat_float[0][2] = mat_double[0][2]; + + mat_float[1][0] = mat_double[1][0]; + mat_float[1][1] = mat_double[1][1]; + mat_float[1][2] = mat_double[1][2]; + + mat_float[2][0] = mat_double[2][0]; + mat_float[2][1] = mat_double[2][1]; + mat_float[2][2] = mat_double[2][2]; +} + +/* NOTE: frame number should be in clip space, not scene space */ +static void track_plane_from_existing_motion(MovieTrackingPlaneTrack *plane_track, int start_frame, int direction) +{ + MovieTrackingPlaneMarker *start_plane_marker = BKE_tracking_plane_marker_get(plane_track, start_frame); + MovieTrackingPlaneMarker new_plane_marker; + int current_frame, frame_delta = direction > 0 ? 1 : -1; + + new_plane_marker = *start_plane_marker; + new_plane_marker.flag |= PLANE_MARKER_TRACKED; + + for (current_frame = start_frame; ; current_frame += frame_delta) { + MovieTrackingPlaneMarker *next_plane_marker = + BKE_tracking_plane_marker_get_exact(plane_track, current_frame + frame_delta); + Vec2 *x1, *x2; + int i, num_correspondences; + double H_double[3][3]; + float H[3][3]; + + /* As soon as we meet keyframed plane, we stop updating the sequence. */ + if (next_plane_marker && (next_plane_marker->flag & PLANE_MARKER_TRACKED) == 0) { + break; + } + + num_correspondences = + point_markers_correspondences_on_both_image(plane_track, current_frame, current_frame + frame_delta, + &x1, &x2); + + if (num_correspondences < 4) { + MEM_freeN(x1); + MEM_freeN(x2); + + break; + } + + libmv_homography2DFromCorrespondencesLinear(x1, x2, num_correspondences, H_double, 1e-8); + + mat3f_from_mat3d(H, H_double); + + for (i = 0; i < 4; i++) { + float vec[3] = {0.0f, 0.0f, 1.0f}, vec2[3]; + copy_v2_v2(vec, new_plane_marker.corners[i]); + + /* Apply homography */ + mul_v3_m3v3(vec2, H, vec); + + /* Normalize. */ + vec2[0] /= vec2[2]; + vec2[1] /= vec2[2]; + + copy_v2_v2(new_plane_marker.corners[i], vec2); + } + + new_plane_marker.framenr = current_frame + frame_delta; + + BKE_tracking_plane_marker_insert(plane_track, &new_plane_marker); + + MEM_freeN(x1); + MEM_freeN(x2); + } +} + +/* NOTE: frame number should be in clip space, not scene space */ +void BKE_tracking_track_plane_from_existing_motion(MovieTrackingPlaneTrack *plane_track, int start_frame) +{ + track_plane_from_existing_motion(plane_track, start_frame, 1); + track_plane_from_existing_motion(plane_track, start_frame, -1); +} + +BLI_INLINE void float_corners_to_double(/*const*/ float corners[4][2], double double_corners[4][2]) +{ + copy_v2db_v2fl(double_corners[0], corners[0]); + copy_v2db_v2fl(double_corners[1], corners[1]); + copy_v2db_v2fl(double_corners[2], corners[2]); + copy_v2db_v2fl(double_corners[3], corners[3]); +} + +void BKE_tracking_homography_between_two_quads(/*const*/ float reference_corners[4][2], /*const*/ float corners[4][2], float H[3][3]) +{ + Vec2 x1[4], x2[4]; + double H_double[3][3]; + + float_corners_to_double(reference_corners, x1); + float_corners_to_double(corners, x2); + + libmv_homography2DFromCorrespondencesLinear(x1, x2, 4, H_double, 1e-8); + + mat3f_from_mat3d(H, H_double); +} + /*********************** Camera solving *************************/ typedef struct MovieReconstructContext { @@ -3264,7 +3741,6 @@ static void reconstruct_update_solve_cb(void *customdata, double progress, const BLI_snprintf(progressdata->stats_message, progressdata->message_size, "Solving camera | %s", message); } - /* FIll in camera intrinsics structure from reconstruction context. */ static void camraIntrincicsOptionsFromContext(libmv_CameraIntrinsicsOptions *camera_intrinsics_options, MovieReconstructContext *context) diff --git a/source/blender/blenlib/BLI_array.h b/source/blender/blenlib/BLI_array.h index ef5cb8bde04..566fc95eb4f 100644 --- a/source/blender/blenlib/BLI_array.h +++ b/source/blender/blenlib/BLI_array.h @@ -173,4 +173,14 @@ void _bli_array_grow_func(void **arr_p, const void *arr_static, MEM_freeN(arr); \ } (void)0 + +void _bli_array_reverse(void *arr, unsigned int arr_len, size_t arr_stride); +#define BLI_array_reverse(arr, arr_len) \ + _bli_array_reverse(arr, arr_len, sizeof(*(arr))) + +void _bli_array_wrap(void *arr, unsigned int arr_len, size_t arr_stride, int dir); +#define BLI_array_wrap(arr, arr_len, dir) \ + _bli_array_wrap(arr, arr_len, sizeof(*(arr)), dir) + + #endif /* __BLI_ARRAY_H__ */ diff --git a/source/blender/blenlib/BLI_linklist.h b/source/blender/blenlib/BLI_linklist.h index 3e7fdc8bf75..9c1e1f88bab 100644 --- a/source/blender/blenlib/BLI_linklist.h +++ b/source/blender/blenlib/BLI_linklist.h @@ -36,6 +36,7 @@ */ struct MemArena; +struct BLI_mempool; typedef void (*LinkNodeFreeFP)(void *link); typedef void (*LinkNodeApplyFP)(void *link, void *userdata); @@ -56,10 +57,14 @@ void BLI_linklist_reverse(struct LinkNode **listp); void BLI_linklist_prepend(struct LinkNode **listp, void *ptr); void BLI_linklist_append(struct LinkNode **listp, void *ptr); void BLI_linklist_prepend_arena(struct LinkNode **listp, void *ptr, struct MemArena *ma); +void BLI_linklist_prepend_pool(struct LinkNode **listp, void *ptr, struct BLI_mempool *mempool); +void *BLI_linklist_pop(struct LinkNode **listp); +void *BLI_linklist_pop_pool(struct LinkNode **listp, struct BLI_mempool *mempool); void BLI_linklist_insert_after(struct LinkNode **listp, void *ptr); void BLI_linklist_free(struct LinkNode *list, LinkNodeFreeFP freefunc); void BLI_linklist_freeN(struct LinkNode *list); +void BLI_linklist_free_pool(LinkNode *list, LinkNodeFreeFP freefunc, struct BLI_mempool *mempool); void BLI_linklist_apply(struct LinkNode *list, LinkNodeApplyFP applyfunc, void *userdata); #endif diff --git a/source/blender/blenlib/BLI_math_base.h b/source/blender/blenlib/BLI_math_base.h index 4b71babdba1..69dbd3253f0 100644 --- a/source/blender/blenlib/BLI_math_base.h +++ b/source/blender/blenlib/BLI_math_base.h @@ -80,6 +80,14 @@ #define MAXFLOAT ((float)3.40282347e+38) #endif +#if defined(__GNUC__) +# define NAN_FLT __builtin_nanf("") +#else +/* evil quiet NaN definition */ +static const int NAN_INT = 0x7FC00000; +# define NAN_FLT (*((float *)(&NAN_INT))) +#endif + /* do not redefine functions from C99 or POSIX.1-2001 */ #if !(defined(_ISOC99_SOURCE) || (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112L)) diff --git a/source/blender/blenlib/intern/BLI_array.c b/source/blender/blenlib/intern/BLI_array.c index 5823b7db3f1..510bf072513 100644 --- a/source/blender/blenlib/intern/BLI_array.c +++ b/source/blender/blenlib/intern/BLI_array.c @@ -59,9 +59,14 @@ */ #include <string.h> +#include <stdlib.h> #include "BLI_array.h" +#include "BLI_sys_types.h" +#include "BLI_utildefines.h" +#include "BLI_alloca.h" + #include "MEM_guardedalloc.h" /** @@ -95,3 +100,40 @@ void _bli_array_grow_func(void **arr_p, const void *arr_static, arr_count += num; #endif } + +void _bli_array_reverse(void *arr_v, unsigned int arr_len, size_t arr_stride) +{ + const unsigned int arr_half_stride = (arr_len / 2) * arr_stride; + unsigned int i, i_end; + char *arr = arr_v; + char *buf = BLI_array_alloca(buf, arr_stride); + + for (i = 0, i_end = (arr_len - 1) * arr_stride; + i < arr_half_stride; + i += arr_stride, i_end -= arr_stride) + { + memcpy(buf, &arr[i], arr_stride); + memcpy(&arr[i], &arr[i_end], arr_stride); + memcpy(&arr[i_end], buf, arr_stride); + } +} + +void _bli_array_wrap(void *arr_v, unsigned int arr_len, size_t arr_stride, int dir) +{ + char *arr = arr_v; + char *buf = BLI_array_alloca(buf, arr_stride); + + if (dir == -1) { + memcpy(buf, arr, arr_stride); + memmove(arr, arr + arr_stride, arr_stride * (arr_len - 1)); + memcpy(arr + (arr_stride * (arr_len - 1)), buf, arr_stride); + } + else if (dir == 1) { + memcpy(buf, arr + (arr_stride * (arr_len - 1)), arr_stride); + memmove(arr + arr_stride, arr, arr_stride * (arr_len - 1)); + memcpy(arr, buf, arr_stride); + } + else { + BLI_assert(0); + } +} diff --git a/source/blender/blenlib/intern/BLI_linklist.c b/source/blender/blenlib/intern/BLI_linklist.c index b08fbe17a43..99fc5f27726 100644 --- a/source/blender/blenlib/intern/BLI_linklist.c +++ b/source/blender/blenlib/intern/BLI_linklist.c @@ -34,6 +34,7 @@ #include "MEM_guardedalloc.h" #include "BLI_linklist.h" #include "BLI_memarena.h" +#include "BLI_mempool.h" int BLI_linklist_length(LinkNode *list) { @@ -125,6 +126,39 @@ void BLI_linklist_prepend_arena(LinkNode **listp, void *ptr, MemArena *ma) *listp = nlink; } +void BLI_linklist_prepend_pool(LinkNode **listp, void *ptr, BLI_mempool *mempool) +{ + LinkNode *nlink = BLI_mempool_alloc(mempool); + nlink->link = ptr; + + nlink->next = *listp; + *listp = nlink; +} + +void *BLI_linklist_pop(struct LinkNode **listp) +{ + /* intentionally no NULL check */ + void *link = (*listp)->link; + void *next = (*listp)->next; + + MEM_freeN((*listp)); + + *listp = next; + return link; +} + +void *BLI_linklist_pop_pool(struct LinkNode **listp, struct BLI_mempool *mempool) +{ + /* intentionally no NULL check */ + void *link = (*listp)->link; + void *next = (*listp)->next; + + BLI_mempool_free(mempool, (*listp)); + + *listp = next; + return link; +} + void BLI_linklist_insert_after(LinkNode **listp, void *ptr) { LinkNode *nlink = MEM_mallocN(sizeof(*nlink), "nlink"); @@ -155,6 +189,19 @@ void BLI_linklist_free(LinkNode *list, LinkNodeFreeFP freefunc) } } +void BLI_linklist_free_pool(LinkNode *list, LinkNodeFreeFP freefunc, struct BLI_mempool *mempool) +{ + while (list) { + LinkNode *next = list->next; + + if (freefunc) + freefunc(list->link); + BLI_mempool_free(mempool, list); + + list = next; + } +} + void BLI_linklist_freeN(LinkNode *list) { while (list) { diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 1f8bbfbec88..37cebc3063d 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -4345,7 +4345,7 @@ static void lib_link_object(FileData *fd, Main *main) /* Only expand so as not to loose any object materials that might be set. */ if (totcol_data && (*totcol_data > ob->totcol)) { /* printf("'%s' %d -> %d\n", ob->id.name, ob->totcol, *totcol_data); */ - resize_object_material(ob, *totcol_data); + BKE_material_resize_object(ob, *totcol_data, false); } } @@ -6687,6 +6687,28 @@ static void direct_link_movieTracks(FileData *fd, ListBase *tracksbase) } } +static void direct_link_moviePlaneTracks(FileData *fd, ListBase *plane_tracks_base) +{ + MovieTrackingPlaneTrack *plane_track; + + link_list(fd, plane_tracks_base); + + for (plane_track = plane_tracks_base->first; + plane_track; + plane_track = plane_track->next) + { + int i; + + plane_track->point_tracks = newdataadr(fd, plane_track->point_tracks); + + for (i = 0; i < plane_track->point_tracksnr; i++) { + plane_track->point_tracks[i] = newdataadr(fd, plane_track->point_tracks[i]); + } + + plane_track->markers = newdataadr(fd, plane_track->markers); + } +} + static void direct_link_movieclip(FileData *fd, MovieClip *clip) { MovieTracking *tracking = &clip->tracking; @@ -6701,9 +6723,11 @@ static void direct_link_movieclip(FileData *fd, MovieClip *clip) else clip->tracking.camera.intrinsics = NULL; direct_link_movieTracks(fd, &tracking->tracks); + direct_link_moviePlaneTracks(fd, &tracking->plane_tracks); direct_link_movieReconstruction(fd, &tracking->reconstruction); clip->tracking.act_track = newdataadr(fd, clip->tracking.act_track); + clip->tracking.act_plane_track = newdataadr(fd, clip->tracking.act_plane_track); clip->anim = NULL; clip->tracking_context = NULL; @@ -6720,6 +6744,7 @@ static void direct_link_movieclip(FileData *fd, MovieClip *clip) for (object = tracking->objects.first; object; object = object->next) { direct_link_movieTracks(fd, &object->tracks); + direct_link_moviePlaneTracks(fd, &object->plane_tracks); direct_link_movieReconstruction(fd, &object->reconstruction); } } diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index 4f0ccd3c626..f3d58c42bc8 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -2920,6 +2920,21 @@ static void write_movieTracks(WriteData *wd, ListBase *tracks) } } +static void write_moviePlaneTracks(WriteData *wd, ListBase *plane_tracks_base) +{ + MovieTrackingPlaneTrack *plane_track; + + for (plane_track = plane_tracks_base->first; + plane_track; + plane_track = plane_track->next) + { + writestruct(wd, DATA, "MovieTrackingPlaneTrack", 1, plane_track); + + writedata(wd, DATA, sizeof(MovieTrackingTrack *) * plane_track->point_tracksnr, plane_track->point_tracks); + writestruct(wd, DATA, "MovieTrackingPlaneMarker", plane_track->markersnr, plane_track->markers); + } +} + static void write_movieReconstruction(WriteData *wd, MovieTrackingReconstruction *reconstruction) { if (reconstruction->camnr) @@ -2944,6 +2959,7 @@ static void write_movieclips(WriteData *wd, ListBase *idbase) write_animdata(wd, clip->adt); write_movieTracks(wd, &tracking->tracks); + write_moviePlaneTracks(wd, &tracking->plane_tracks); write_movieReconstruction(wd, &tracking->reconstruction); object= tracking->objects.first; @@ -2951,6 +2967,7 @@ static void write_movieclips(WriteData *wd, ListBase *idbase) writestruct(wd, DATA, "MovieTrackingObject", 1, object); write_movieTracks(wd, &object->tracks); + write_moviePlaneTracks(wd, &object->plane_tracks); write_movieReconstruction(wd, &object->reconstruction); object= object->next; diff --git a/source/blender/bmesh/intern/bmesh_marking.c b/source/blender/bmesh/intern/bmesh_marking.c index bec301acaa9..0a6c0f4b293 100644 --- a/source/blender/bmesh/intern/bmesh_marking.c +++ b/source/blender/bmesh/intern/bmesh_marking.c @@ -816,6 +816,13 @@ void BM_editselection_plane(BMEditSelection *ese, float r_plane[3]) } } +static BMEditSelection *bm_select_history_create(BMHeader *ele) +{ + BMEditSelection *ese = (BMEditSelection *) MEM_callocN(sizeof(BMEditSelection), "BMEdit Selection"); + ese->htype = ele->htype; + ese->ele = (BMElem *)ele; + return ese; +} /* --- macro wrapped funcs --- */ bool _bm_select_history_check(BMesh *bm, const BMHeader *ele) @@ -837,9 +844,7 @@ bool _bm_select_history_remove(BMesh *bm, BMHeader *ele) void _bm_select_history_store_notest(BMesh *bm, BMHeader *ele) { - BMEditSelection *ese = (BMEditSelection *) MEM_callocN(sizeof(BMEditSelection), "BMEdit Selection"); - ese->htype = ele->htype; - ese->ele = (BMElem *)ele; + BMEditSelection *ese = bm_select_history_create(ele); BLI_addtail(&(bm->selected), ese); } @@ -849,6 +854,20 @@ void _bm_select_history_store(BMesh *bm, BMHeader *ele) BM_select_history_store_notest(bm, (BMElem *)ele); } } + + +void _bm_select_history_store_after_notest(BMesh *bm, BMEditSelection *ese_ref, BMHeader *ele) +{ + BMEditSelection *ese = bm_select_history_create(ele); + BLI_insertlinkafter(&(bm->selected), ese_ref, ese); +} + +void _bm_select_history_store_after(BMesh *bm, BMEditSelection *ese_ref, BMHeader *ele) +{ + if (!BM_select_history_check(bm, (BMElem *)ele)) { + BM_select_history_store_after_notest(bm, ese_ref, (BMElem *)ele); + } +} /* --- end macro wrapped funcs --- */ @@ -861,16 +880,13 @@ void BM_select_history_clear(BMesh *bm) void BM_select_history_validate(BMesh *bm) { - BMEditSelection *ese, *nextese; - - ese = bm->selected.first; + BMEditSelection *ese, *ese_next; - while (ese) { - nextese = ese->next; + for (ese = bm->selected.first; ese; ese = ese_next) { + ese_next = ese->next; if (!BM_elem_flag_test(ese->ele, BM_ELEM_SELECT)) { BLI_freelinkN(&(bm->selected), ese); } - ese = nextese; } } diff --git a/source/blender/bmesh/intern/bmesh_marking.h b/source/blender/bmesh/intern/bmesh_marking.h index 062de4f69e1..f23eac61278 100644 --- a/source/blender/bmesh/intern/bmesh_marking.h +++ b/source/blender/bmesh/intern/bmesh_marking.h @@ -87,11 +87,15 @@ void BM_editselection_plane(BMEditSelection *ese, float r_plane[3]); #define BM_select_history_remove(bm, ele) _bm_select_history_remove(bm, &(ele)->head) #define BM_select_history_store_notest(bm, ele) _bm_select_history_store_notest(bm, &(ele)->head) #define BM_select_history_store(bm, ele) _bm_select_history_store(bm, &(ele)->head) +#define BM_select_history_store_after_notest(bm, ese_ref, ele) _bm_select_history_store_after_notest(bm, ese_ref, &(ele)->head) +#define BM_select_history_store_after(bm, ese, ese_ref) _bm_select_history_store_after(bm, ese_ref, &(ele)->head) bool _bm_select_history_check(BMesh *bm, const BMHeader *ele); bool _bm_select_history_remove(BMesh *bm, BMHeader *ele); void _bm_select_history_store_notest(BMesh *bm, BMHeader *ele); void _bm_select_history_store(BMesh *bm, BMHeader *ele); +void _bm_select_history_store_after(BMesh *bm, BMEditSelection *ese_ref, BMHeader *ele); +void _bm_select_history_store_after_notest(BMesh *bm, BMEditSelection *ese_ref, BMHeader *ele); void BM_select_history_validate(BMesh *bm); void BM_select_history_clear(BMesh *em); diff --git a/source/blender/bmesh/intern/bmesh_queries.c b/source/blender/bmesh/intern/bmesh_queries.c index 0eb3b0a6443..6eab3c625fa 100644 --- a/source/blender/bmesh/intern/bmesh_queries.c +++ b/source/blender/bmesh/intern/bmesh_queries.c @@ -1986,7 +1986,7 @@ int BM_mesh_calc_edge_groups(BMesh *bm, int *r_groups_array, int (**r_group_inde BM_elem_index_set(e, i); /* set_inline */ } - bm->elem_index_dirty &= ~BM_FACE; + bm->elem_index_dirty &= ~BM_EDGE; /* detect groups */ stack = MEM_mallocN(sizeof(*stack) * tot_edges, __func__); diff --git a/source/blender/bmesh/operators/bmo_edgenet.c b/source/blender/bmesh/operators/bmo_edgenet.c index 4e78d1dc494..923b877b822 100644 --- a/source/blender/bmesh/operators/bmo_edgenet.c +++ b/source/blender/bmesh/operators/bmo_edgenet.c @@ -31,6 +31,7 @@ #include "BLI_listbase.h" #include "BLI_math.h" #include "BLI_array.h" +#include "BLI_alloca.h" #include "BLI_smallhash.h" #include "BLI_rand.h" #include "BLI_heap.h" @@ -885,27 +886,82 @@ BLI_INLINE void vote_on_winding(BMEdge *edge, EPathNode *node, unsigned int wind winding[(test_v1 == node->v)]++; } +static BMFace *bm_face_from_path(BMesh *bm, EPath *path, + EdgeData *edata, + const bool use_fill_check) +{ + /* accumulte winding directions for each edge which has a face */ + const unsigned int path_len = BLI_countlist(&path->nodes); + unsigned int winding[2] = {0, 0}; + unsigned int i; + + EPathNode *node; + + BMVert **verts = BLI_array_alloca(verts, path_len); + BMEdge **edges = BLI_array_alloca(edges, path_len); + BMEdge *e; + BMVert *v; + + for (node = path->nodes.first, i = 0; node; node = node->next, i++) { + + v = node->v; + e = BM_edge_exists(v, node->next ? + node->next->v : + ((EPathNode *)path->nodes.first)->v); + + /* check on the winding */ + if (e->l) { + if (UNLIKELY(count_edge_faces(bm, e) >= 2)) { + return NULL; + } + + vote_on_winding(e, node, winding); + } + + verts[i] = v; + edges[i] = e; + } + + /* do after incase we bail early, above */ + for (i = 0; i < path_len; i++) { + edata[BM_elem_index_get(edges[i])].ftag++; + } + + + /* if these are even it doesn't really matter what to do, + * with consistent geometry one will be zero, the choice is clear */ + if (winding[0] > winding[1]) { + BLI_array_wrap(verts, path_len, -1); + BLI_array_reverse(verts, path_len); + BLI_array_reverse(edges, path_len); + } + + if ((use_fill_check == false) || + /* fairly expensive check - see if there are already faces filling this area */ + (BM_face_exists_multi(verts, edges, path_len) == false)) + { + return BM_face_create(bm, verts, edges, path_len, BM_CREATE_NO_DOUBLE); + } + else { + return NULL; + } +} + void bmo_edgenet_fill_exec(BMesh *bm, BMOperator *op) { BMIter iter; BMOIter siter; BMFace *f; BMEdge *e; - BMVert **verts = NULL; - BLI_array_declare(verts); EPath *path; - EPathNode *node; EdgeData *edata; VertData *vdata; - BMEdge **edges = NULL; PathBase *pathbase; - BLI_array_declare(edges); const bool use_restrict = BMO_slot_bool_get(op->slots_in, "use_restrict"); const bool use_fill_check = BMO_slot_bool_get(op->slots_in, "use_fill_check"); const short mat_nr = BMO_slot_int_get(op->slots_in, "mat_nr"); const bool use_smooth = BMO_slot_bool_get(op->slots_in, "use_smooth"); - int i, j; - unsigned int winding[2]; /* accumulte winding directions for each edge which has a face */ + int i; BMOpSlot *slot_restrict = BMO_slot_get(op->slots_in, "restrict"); BMOpSlot *slot_face_groupmap_out = BMO_slot_get(op->slots_out, "face_groupmap.out"); @@ -978,99 +1034,28 @@ void bmo_edgenet_fill_exec(BMesh *bm, BMOperator *op) edata[BM_elem_index_get(edge)].tag += 1; path = edge_find_shortest_path(bm, op, edge, edata, vdata, pathbase, group); - if (!path) - continue; - - winding[0] = winding[1] = 0; - - BLI_array_empty(edges); - BLI_array_empty(verts); - i = 0; - for (node = path->nodes.first; node; node = node->next) { - if (!node->next) - continue; - - e = BM_edge_exists(node->v, node->next->v); - - /* this should never happe */ - if (!e) - break; - - /* check on the winding */ - if (e->l) { - vote_on_winding(e, node, winding); - } - - edata[BM_elem_index_get(e)].ftag++; - BLI_array_grow_one(edges); - edges[i++] = e; - - BLI_array_append(verts, node->v); - } - - if (edge->l) { - vote_on_winding(edge, path->nodes.last, winding); - } - - BLI_array_grow_one(edges); - edges[i++] = edge; - edata[BM_elem_index_get(edge)].ftag++; - - for (j = 0; j < i; j++) { - if (count_edge_faces(bm, edges[j]) >= 2) { - edge_free_path(pathbase, path); - break; + if (path && path->nodes.first) { + BMFace *f = bm_face_from_path(bm, path, edata, + use_fill_check); + + if (f && !BMO_elem_flag_test(bm, f, ELE_ORIG)) { + BMO_elem_flag_enable(bm, f, FACE_NEW); + f->mat_nr = mat_nr; + if (use_smooth) { + BM_elem_flag_enable(f, BM_ELEM_SMOOTH); + } } - } - if (j != i) { - continue; - } - - if (i) { - BMVert *v1, *v2; - - /* to define the winding order must select first edge, - * otherwise we could leave this as-is */ - edge = edges[0]; - - /* if these are even it doesn't really matter what to do, - * with consistent geometry one will be zero, the choice is clear */ - if (winding[0] < winding[1]) { - v1 = verts[0]; - v2 = verts[1]; - } - else { - v1 = verts[1]; - v2 = verts[0]; + if (use_restrict) { + BMO_slot_map_int_insert(op, slot_face_groupmap_out, f, path->group); } - if ((use_fill_check == false) || - /* fairly expensive check - see if there are already faces filling this area */ - (BM_face_exists_multi_edge(edges, i) == false)) - { - f = BM_face_create_ngon(bm, v1, v2, edges, i, BM_CREATE_NO_DOUBLE); - if (f && !BMO_elem_flag_test(bm, f, ELE_ORIG)) { - BMO_elem_flag_enable(bm, f, FACE_NEW); - f->mat_nr = mat_nr; - if (use_smooth) { - BM_elem_flag_enable(f, BM_ELEM_SMOOTH); - } - } - - if (use_restrict) { - BMO_slot_map_int_insert(op, slot_face_groupmap_out, f, path->group); - } - } + edge_free_path(pathbase, path); } - - edge_free_path(pathbase, path); } BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "faces.out", BM_FACE, FACE_NEW); - BLI_array_free(edges); - BLI_array_free(verts); edge_pathbase_free(pathbase); MEM_freeN(edata); MEM_freeN(vdata); diff --git a/source/blender/bmesh/tools/bmesh_edgesplit.c b/source/blender/bmesh/tools/bmesh_edgesplit.c index adcf325b51c..aad600d13fa 100644 --- a/source/blender/bmesh/tools/bmesh_edgesplit.c +++ b/source/blender/bmesh/tools/bmesh_edgesplit.c @@ -103,6 +103,21 @@ void BM_mesh_edgesplit(BMesh *bm, const bool use_verts, const bool tag_only, con BMIter iter; BMEdge *e; + bool use_ese = false; + GHash *ese_gh = NULL; + + if (copy_select && bm->selected.first) { + BMEditSelection *ese; + + ese_gh = BLI_ghash_ptr_new(__func__); + for (ese = bm->selected.first; ese; ese = ese->next) { + if (ese->htype != BM_FACE) { + BLI_ghash_insert(ese_gh, ese->ele, ese); + } + } + + use_ese = true; + } if (tag_only == false) { BM_mesh_elem_hflag_enable_all(bm, BM_EDGE | (use_verts ? BM_VERT : 0), BM_ELEM_TAG, false); @@ -135,9 +150,18 @@ void BM_mesh_edgesplit(BMesh *bm, const bool use_verts, const bool tag_only, con BM_elem_flag_enable(e, BM_ELEM_INTERNAL_TAG); /* keep splitting until each loop has its own edge */ - do { - bmesh_edge_separate(bm, e, e->l, copy_select); - } while (!BM_edge_is_boundary(e)); + while (!BM_edge_is_boundary(e)) { + BMLoop *l_sep = e->l; + bmesh_edge_separate(bm, e, l_sep, copy_select); + BLI_assert(l_sep->e != e); + + if (use_ese) { + BMEditSelection *ese = BLI_ghash_lookup(ese_gh, e); + if (UNLIKELY(ese)) { + BM_select_history_store_after_notest(bm, ese, l_sep->e); + } + } + } BM_elem_flag_enable(e->v1, BM_ELEM_TAG); BM_elem_flag_enable(e->v2, BM_ELEM_TAG); @@ -157,14 +181,39 @@ void BM_mesh_edgesplit(BMesh *bm, const bool use_verts, const bool tag_only, con BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { if (BM_elem_flag_test(e, BM_ELEM_TAG)) { - if (BM_elem_flag_test(e->v1, BM_ELEM_TAG)) { - BM_elem_flag_disable(e->v1, BM_ELEM_TAG); - bmesh_vert_separate(bm, e->v1, NULL, NULL, copy_select); - } - if (BM_elem_flag_test(e->v2, BM_ELEM_TAG)) { - BM_elem_flag_disable(e->v2, BM_ELEM_TAG); - bmesh_vert_separate(bm, e->v2, NULL, NULL, copy_select); + unsigned int i; + for (i = 0; i < 2; i++) { + BMVert *v = ((&e->v1)[i]); + if (BM_elem_flag_test(v, BM_ELEM_TAG)) { + BM_elem_flag_disable(v, BM_ELEM_TAG); + + if (use_ese) { + BMVert **vtar; + int vtar_len; + + bmesh_vert_separate(bm, v, &vtar, &vtar_len, copy_select); + + if (vtar_len) { + BMEditSelection *ese = BLI_ghash_lookup(ese_gh, v); + if (UNLIKELY(ese)) { + int j; + for (j = 0; j < vtar_len; j++) { + BLI_assert(v != vtar[j]); + BM_select_history_store_after_notest(bm, ese, vtar[j]); + } + } + } + MEM_freeN(vtar); + } + else { + bmesh_vert_separate(bm, v, NULL, NULL, copy_select); + } + } } } } + + if (use_ese) { + BLI_ghash_free(ese_gh, NULL, NULL); + } } diff --git a/source/blender/compositor/CMakeLists.txt b/source/blender/compositor/CMakeLists.txt index c1b99274bed..a119a89c842 100644 --- a/source/blender/compositor/CMakeLists.txt +++ b/source/blender/compositor/CMakeLists.txt @@ -184,6 +184,9 @@ set(SRC nodes/COM_GlareNode.cpp nodes/COM_GlareNode.h + nodes/COM_PlaneTrackDeformNode.cpp + nodes/COM_PlaneTrackDeformNode.h + nodes/COM_CropNode.cpp nodes/COM_CropNode.h operations/COM_CropOperation.cpp @@ -595,6 +598,12 @@ set(SRC operations/COM_ProjectorLensDistortionOperation.h operations/COM_ScreenLensDistortionOperation.cpp operations/COM_ScreenLensDistortionOperation.h + operations/COM_PlaneTrackCommonOperation.cpp + operations/COM_PlaneTrackCommonOperation.h + operations/COM_PlaneTrackMaskOperation.cpp + operations/COM_PlaneTrackMaskOperation.h + operations/COM_PlaneTrackWarpImageOperation.cpp + operations/COM_PlaneTrackWarpImageOperation.h #Filter operations operations/COM_ConvolutionFilterOperation.h diff --git a/source/blender/compositor/intern/COM_Converter.cpp b/source/blender/compositor/intern/COM_Converter.cpp index 80ae952b87f..db0cdd1692e 100644 --- a/source/blender/compositor/intern/COM_Converter.cpp +++ b/source/blender/compositor/intern/COM_Converter.cpp @@ -121,6 +121,7 @@ #include "COM_ViewerNode.h" #include "COM_ZCombineNode.h" #include "COM_PixelateNode.h" +#include "COM_PlaneTrackDeformNode.h" Node *Converter::convert(bNode *b_node, bool fast) { @@ -402,6 +403,9 @@ Node *Converter::convert(bNode *b_node, bool fast) case CMP_NODE_PIXELATE: node = new PixelateNode(b_node); break; + case CMP_NODE_PLANETRACKDEFORM: + node = new PlaneTrackDeformNode(b_node); + break; default: node = new MuteNode(b_node); break; diff --git a/source/blender/compositor/nodes/COM_PlaneTrackDeformNode.cpp b/source/blender/compositor/nodes/COM_PlaneTrackDeformNode.cpp new file mode 100644 index 00000000000..d6434c26c7d --- /dev/null +++ b/source/blender/compositor/nodes/COM_PlaneTrackDeformNode.cpp @@ -0,0 +1,81 @@ +/* + * Copyright 2013, Blender Foundation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor: + * Jeroen Bakker + * Monique Dewanchand + * Sergey Sharybin + */ + +#include "COM_PlaneTrackDeformNode.h" +#include "COM_ExecutionSystem.h" + +#include "COM_PlaneTrackMaskOperation.h" +#include "COM_PlaneTrackWarpImageOperation.h" + +extern "C" { + #include "BKE_node.h" + #include "BKE_movieclip.h" + #include "BKE_tracking.h" +} + +PlaneTrackDeformNode::PlaneTrackDeformNode(bNode *editorNode) : Node(editorNode) +{ + /* pass */ +} + +void PlaneTrackDeformNode::convertToOperations(ExecutionSystem *graph, CompositorContext *context) +{ + InputSocket *input_image = this->getInputSocket(0); + + OutputSocket *output_warped_image = this->getOutputSocket(0); + OutputSocket *output_plane = this->getOutputSocket(1); + + bNode *editorNode = this->getbNode(); + MovieClip *clip = (MovieClip *) editorNode->id; + + NodePlaneTrackDeformData *data = (NodePlaneTrackDeformData *) editorNode->storage; + + int frame_number = context->getFramenumber(); + + if (output_warped_image->isConnected()) { + PlaneTrackWarpImageOperation *warp_image_operation = new PlaneTrackWarpImageOperation(); + + warp_image_operation->setMovieClip(clip); + warp_image_operation->setTrackingObject(data->tracking_object); + warp_image_operation->setPlaneTrackName(data->plane_track_name); + warp_image_operation->setFramenumber(frame_number); + + input_image->relinkConnections(warp_image_operation->getInputSocket(0), 0, graph); + output_warped_image->relinkConnections(warp_image_operation->getOutputSocket()); + + graph->addOperation(warp_image_operation); + } + + if (output_plane->isConnected()) { + PlaneTrackMaskOperation *plane_mask_operation = new PlaneTrackMaskOperation(); + + plane_mask_operation->setMovieClip(clip); + plane_mask_operation->setTrackingObject(data->tracking_object); + plane_mask_operation->setPlaneTrackName(data->plane_track_name); + plane_mask_operation->setFramenumber(frame_number); + + output_plane->relinkConnections(plane_mask_operation->getOutputSocket()); + + graph->addOperation(plane_mask_operation); + } +} diff --git a/source/blender/compositor/nodes/COM_PlaneTrackDeformNode.h b/source/blender/compositor/nodes/COM_PlaneTrackDeformNode.h new file mode 100644 index 00000000000..cf173cd19f9 --- /dev/null +++ b/source/blender/compositor/nodes/COM_PlaneTrackDeformNode.h @@ -0,0 +1,38 @@ +/* + * Copyright 2013, Blender Foundation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor: + * Sergey Sharybin + */ + +#include "COM_Node.h" +#include "DNA_node_types.h" + +extern "C" { + #include "DNA_movieclip_types.h" + #include "DNA_node_types.h" +} + +/** + * @brief PlaneTrackDeformNode + * @ingroup Node + */ +class PlaneTrackDeformNode : public Node { +public: + PlaneTrackDeformNode(bNode *editorNode); + void convertToOperations(ExecutionSystem *graph, CompositorContext *context); +}; diff --git a/source/blender/compositor/operations/COM_ImageOperation.cpp b/source/blender/compositor/operations/COM_ImageOperation.cpp index c8e3dbf993d..89a56af6b15 100644 --- a/source/blender/compositor/operations/COM_ImageOperation.cpp +++ b/source/blender/compositor/operations/COM_ImageOperation.cpp @@ -40,7 +40,8 @@ BaseImageOperation::BaseImageOperation() : NodeOperation() { this->m_image = NULL; this->m_buffer = NULL; - this->m_imageBuffer = NULL; + this->m_imageFloatBuffer = NULL; + this->m_imageByteBuffer = NULL; this->m_imageUser = NULL; this->m_imagewidth = 0; this->m_imageheight = 0; @@ -70,10 +71,6 @@ ImBuf *BaseImageOperation::getImBuf() BKE_image_release_ibuf(this->m_image, ibuf, NULL); return NULL; } - - if (ibuf->rect_float == NULL) { - IMB_float_from_rect(ibuf); - } return ibuf; } @@ -83,7 +80,8 @@ void BaseImageOperation::initExecution() ImBuf *stackbuf = getImBuf(); this->m_buffer = stackbuf; if (stackbuf) { - this->m_imageBuffer = stackbuf->rect_float; + this->m_imageFloatBuffer = stackbuf->rect_float; + this->m_imageByteBuffer = stackbuf->rect; this->m_depthBuffer = stackbuf->zbuf_float; this->m_imagewidth = stackbuf->x; this->m_imageheight = stackbuf->y; @@ -93,7 +91,8 @@ void BaseImageOperation::initExecution() void BaseImageOperation::deinitExecution() { - this->m_imageBuffer = NULL; + this->m_imageFloatBuffer = NULL; + this->m_imageByteBuffer = NULL; BKE_image_release_ibuf(this->m_image, this->m_buffer, NULL); } @@ -112,23 +111,48 @@ void BaseImageOperation::determineResolution(unsigned int resolution[2], unsigne BKE_image_release_ibuf(this->m_image, stackbuf, NULL); } -void ImageOperation::executePixel(float output[4], float x, float y, PixelSampler sampler) +static void sampleImageAtLocation(ImBuf *ibuf, float x, float y, PixelSampler sampler, bool make_linear_rgb, float color[4]) { - if (this->m_imageBuffer == NULL || x < 0 || y < 0 || x >= this->getWidth() || y >= this->getHeight() ) { - zero_v4(output); + if (ibuf->rect_float) { + switch (sampler) { + case COM_PS_NEAREST: + nearest_interpolation_color(ibuf, NULL, color, x, y); + break; + case COM_PS_BILINEAR: + bilinear_interpolation_color(ibuf, NULL, color, x, y); + break; + case COM_PS_BICUBIC: + bicubic_interpolation_color(ibuf, NULL, color, x, y); + break; + } } else { + unsigned char byte_color[4]; switch (sampler) { case COM_PS_NEAREST: - nearest_interpolation_color(this->m_buffer, NULL, output, x, y); + nearest_interpolation_color(ibuf, byte_color, NULL, x, y); break; case COM_PS_BILINEAR: - bilinear_interpolation_color(this->m_buffer, NULL, output, x, y); + bilinear_interpolation_color(ibuf, byte_color, NULL, x, y); break; case COM_PS_BICUBIC: - bicubic_interpolation_color(this->m_buffer, NULL, output, x, y); + bicubic_interpolation_color(ibuf, byte_color, NULL, x, y); break; } + rgba_uchar_to_float(color, byte_color); + if (make_linear_rgb) { + IMB_colormanagement_colorspace_to_scene_linear_v4(color, FALSE, ibuf->rect_colorspace); + } + } +} + +void ImageOperation::executePixel(float output[4], float x, float y, PixelSampler sampler) +{ + if ((this->m_imageFloatBuffer == NULL && this->m_imageByteBuffer == NULL) || x < 0 || y < 0 || x >= this->getWidth() || y >= this->getHeight() ) { + zero_v4(output); + } + else { + sampleImageAtLocation(this->m_buffer, x, y, sampler, true, output); } } @@ -136,22 +160,12 @@ void ImageAlphaOperation::executePixel(float output[4], float x, float y, PixelS { float tempcolor[4]; - if (this->m_imageBuffer == NULL || x < 0 || y < 0 || x >= this->getWidth() || y >= this->getHeight() ) { + if ((this->m_imageFloatBuffer == NULL && this->m_imageByteBuffer == NULL) || x < 0 || y < 0 || x >= this->getWidth() || y >= this->getHeight() ) { output[0] = 0.0f; } else { tempcolor[3] = 1.0f; - switch (sampler) { - case COM_PS_NEAREST: - nearest_interpolation_color(this->m_buffer, NULL, tempcolor, x, y); - break; - case COM_PS_BILINEAR: - bilinear_interpolation_color(this->m_buffer, NULL, tempcolor, x, y); - break; - case COM_PS_BICUBIC: - bicubic_interpolation_color(this->m_buffer, NULL, tempcolor, x, y); - break; - } + sampleImageAtLocation(this->m_buffer, x, y, sampler, false, tempcolor); output[0] = tempcolor[3]; } } diff --git a/source/blender/compositor/operations/COM_ImageOperation.h b/source/blender/compositor/operations/COM_ImageOperation.h index e75e7daa186..b51f11edd04 100644 --- a/source/blender/compositor/operations/COM_ImageOperation.h +++ b/source/blender/compositor/operations/COM_ImageOperation.h @@ -42,7 +42,8 @@ protected: ImBuf *m_buffer; Image *m_image; ImageUser *m_imageUser; - float *m_imageBuffer; + float *m_imageFloatBuffer; + unsigned int *m_imageByteBuffer; float *m_depthBuffer; int m_imageheight; int m_imagewidth; diff --git a/source/blender/compositor/operations/COM_MultilayerImageOperation.cpp b/source/blender/compositor/operations/COM_MultilayerImageOperation.cpp index 1c9dd0f170e..1a2a1e77833 100644 --- a/source/blender/compositor/operations/COM_MultilayerImageOperation.cpp +++ b/source/blender/compositor/operations/COM_MultilayerImageOperation.cpp @@ -47,7 +47,7 @@ void MultilayerColorOperation::executePixel(float output[4], float x, float y, P { int yi = y; int xi = x; - if (this->m_imageBuffer == NULL || xi < 0 || yi < 0 || (unsigned int)xi >= this->getWidth() || (unsigned int)yi >= this->getHeight() ) { + if (this->m_imageFloatBuffer == NULL || xi < 0 || yi < 0 || (unsigned int)xi >= this->getWidth() || (unsigned int)yi >= this->getHeight() ) { zero_v4(output); } else { @@ -66,7 +66,7 @@ void MultilayerColorOperation::executePixel(float output[4], float x, float y, P } else { int offset = (yi * this->getWidth() + xi) * 3; - copy_v3_v3(output, &this->m_imageBuffer[offset]); + copy_v3_v3(output, &this->m_imageFloatBuffer[offset]); } } } @@ -75,11 +75,11 @@ void MultilayerValueOperation::executePixel(float output[4], float x, float y, P { int yi = y; int xi = x; - if (this->m_imageBuffer == NULL || xi < 0 || yi < 0 || (unsigned int)xi >= this->getWidth() || (unsigned int)yi >= this->getHeight() ) { + if (this->m_imageFloatBuffer == NULL || xi < 0 || yi < 0 || (unsigned int)xi >= this->getWidth() || (unsigned int)yi >= this->getHeight() ) { output[0] = 0.0f; } else { - float result = this->m_imageBuffer[yi * this->getWidth() + xi]; + float result = this->m_imageFloatBuffer[yi * this->getWidth() + xi]; output[0] = result; } } @@ -88,11 +88,11 @@ void MultilayerVectorOperation::executePixel(float output[4], float x, float y, { int yi = y; int xi = x; - if (this->m_imageBuffer == NULL || xi < 0 || yi < 0 || (unsigned int)xi >= this->getWidth() || (unsigned int)yi >= this->getHeight() ) { + if (this->m_imageFloatBuffer == NULL || xi < 0 || yi < 0 || (unsigned int)xi >= this->getWidth() || (unsigned int)yi >= this->getHeight() ) { output[0] = 0.0f; } else { int offset = (yi * this->getWidth() + xi) * 3; - copy_v3_v3(output, &this->m_imageBuffer[offset]); + copy_v3_v3(output, &this->m_imageFloatBuffer[offset]); } } diff --git a/source/blender/compositor/operations/COM_PlaneTrackCommonOperation.cpp b/source/blender/compositor/operations/COM_PlaneTrackCommonOperation.cpp new file mode 100644 index 00000000000..51e803f696b --- /dev/null +++ b/source/blender/compositor/operations/COM_PlaneTrackCommonOperation.cpp @@ -0,0 +1,95 @@ +/* + * Copyright 2013, Blender Foundation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor: + * Sergey Sharybin + */ + +#include "COM_PlaneTrackMaskOperation.h" + +#include "MEM_guardedalloc.h" + +#include "BLI_listbase.h" +#include "BLI_math.h" +#include "BLI_math_color.h" + +extern "C" { + #include "BKE_movieclip.h" + #include "BKE_node.h" + #include "BKE_tracking.h" +} + +PlaneTrackCommonOperation::PlaneTrackCommonOperation() : NodeOperation() +{ + this->m_movieClip = NULL; + this->m_framenumber = 0; + this->m_trackingObjectName[0] = '\0'; + this->m_planeTrackName[0] = '\0'; +} + +void PlaneTrackCommonOperation::initExecution() +{ + MovieTracking *tracking; + MovieTrackingObject *object; + + memset(this->m_corners, 0, sizeof(this->m_corners)); + memset(this->m_frameSpaceCorners, 0, sizeof(this->m_frameSpaceCorners)); + + if (!this->m_movieClip) + return; + + tracking = &this->m_movieClip->tracking; + + object = BKE_tracking_object_get_named(tracking, this->m_trackingObjectName); + if (object) { + MovieTrackingPlaneTrack *plane_track; + + plane_track = BKE_tracking_plane_track_get_named(tracking, object, this->m_planeTrackName); + + if (plane_track) { + MovieTrackingPlaneMarker *plane_marker; + int clip_framenr = BKE_movieclip_remap_scene_to_clip_frame(this->m_movieClip, this->m_framenumber); + + plane_marker = BKE_tracking_plane_marker_get(plane_track, clip_framenr); + memcpy(this->m_corners, plane_marker->corners, sizeof(this->m_corners)); + } + } + + for (int i = 0; i < 4; i++) { + this->m_frameSpaceCorners[i][0] = this->m_corners[i][0] * this->getWidth(); + this->m_frameSpaceCorners[i][1] = this->m_corners[i][1] * this->getHeight(); + } +} + +void PlaneTrackCommonOperation::determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2]) +{ + NodeOperation::determineResolution(resolution, preferredResolution); + + resolution[0] = 0; + resolution[1] = 0; + + if (this->m_movieClip) { + int width, height; + MovieClipUser user = {0}; + + BKE_movieclip_user_set_frame(&user, this->m_framenumber); + BKE_movieclip_get_size(this->m_movieClip, &user, &width, &height); + + resolution[0] = width; + resolution[1] = height; + } +} diff --git a/source/blender/compositor/operations/COM_PlaneTrackCommonOperation.h b/source/blender/compositor/operations/COM_PlaneTrackCommonOperation.h new file mode 100644 index 00000000000..705bdf4bd81 --- /dev/null +++ b/source/blender/compositor/operations/COM_PlaneTrackCommonOperation.h @@ -0,0 +1,62 @@ + +/* + * Copyright 2013, Blender Foundation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor: + * Sergey Sharybin + */ + +#ifndef _COM_PlaneTrackCommonOperation_h +#define _COM_PlaneTrackCommonOperation_h + +#include <string.h> + +#include "COM_NodeOperation.h" + +#include "DNA_movieclip_types.h" +#include "DNA_tracking_types.h" + +#include "BLI_listbase.h" +#include "BLI_string.h" + +class PlaneTrackCommonOperation : public NodeOperation { +protected: + MovieClip *m_movieClip; + int m_framenumber; + char m_trackingObjectName[64]; + char m_planeTrackName[64]; + + float m_corners[4][2]; /* Corners coordinates in normalized space. */ + float m_frameSpaceCorners[4][2]; /* Corners coordinates in pixel space. */ + + /** + * Determine the output resolution. The resolution is retrieved from the Renderer + */ + void determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2]); + +public: + PlaneTrackCommonOperation(); + + void setMovieClip(MovieClip *clip) {this->m_movieClip = clip;} + void setTrackingObject(char *object) { BLI_strncpy(this->m_trackingObjectName, object, sizeof(this->m_trackingObjectName)); } + void setPlaneTrackName(char *plane_track) { BLI_strncpy(this->m_planeTrackName, plane_track, sizeof(this->m_planeTrackName)); } + void setFramenumber(int framenumber) {this->m_framenumber = framenumber;} + + void initExecution(); +}; + +#endif diff --git a/source/blender/compositor/operations/COM_PlaneTrackMaskOperation.cpp b/source/blender/compositor/operations/COM_PlaneTrackMaskOperation.cpp new file mode 100644 index 00000000000..fe794cb769f --- /dev/null +++ b/source/blender/compositor/operations/COM_PlaneTrackMaskOperation.cpp @@ -0,0 +1,69 @@ +/* + * Copyright 2013, Blender Foundation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor: + * Sergey Sharybin + */ + +#include "COM_PlaneTrackMaskOperation.h" + +#include "MEM_guardedalloc.h" + +#include "BLI_listbase.h" +#include "BLI_math.h" +#include "BLI_math_color.h" + +extern "C" { + #include "BLI_jitter.h" + + #include "BKE_movieclip.h" + #include "BKE_node.h" + #include "BKE_tracking.h" +} + +PlaneTrackMaskOperation::PlaneTrackMaskOperation() : PlaneTrackCommonOperation() +{ + this->addOutputSocket(COM_DT_VALUE); +} + +void PlaneTrackMaskOperation::initExecution() +{ + PlaneTrackCommonOperation::initExecution(); + + const int osa = 8; + this->m_osa = osa; + BLI_jitter_init(this->m_jitter[0], osa); +} + +void PlaneTrackMaskOperation::executePixel(float output[4], float x, float y, PixelSampler sampler) +{ + float point[2]; + + int inside_counter = 0; + for (int sample = 0; sample < this->m_osa; sample++) { + point[0] = x + this->m_jitter[sample][0]; + point[1] = y + this->m_jitter[sample][1]; + + if (isect_point_tri_v2(point, this->m_frameSpaceCorners[0], this->m_frameSpaceCorners[1], this->m_frameSpaceCorners[2]) || + isect_point_tri_v2(point, this->m_frameSpaceCorners[0], this->m_frameSpaceCorners[2], this->m_frameSpaceCorners[3])) + { + inside_counter++; + } + } + + output[0] = (float) inside_counter / this->m_osa; +} diff --git a/source/blender/compositor/operations/COM_PlaneTrackMaskOperation.h b/source/blender/compositor/operations/COM_PlaneTrackMaskOperation.h new file mode 100644 index 00000000000..db32f9830e0 --- /dev/null +++ b/source/blender/compositor/operations/COM_PlaneTrackMaskOperation.h @@ -0,0 +1,49 @@ + +/* + * Copyright 2013, Blender Foundation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor: + * Sergey Sharybin + */ + +#ifndef _COM_PlaneTrackMaskOperation_h +#define _COM_PlaneTrackMaskOperation_h + +#include <string.h> + +#include "COM_PlaneTrackCommonOperation.h" + +#include "DNA_movieclip_types.h" +#include "DNA_tracking_types.h" + +#include "BLI_listbase.h" +#include "BLI_string.h" + +class PlaneTrackMaskOperation : public PlaneTrackCommonOperation { +protected: + int m_osa; + float m_jitter[32][2]; + +public: + PlaneTrackMaskOperation(); + + void initExecution(); + + void executePixel(float output[4], float x, float y, PixelSampler sampler); +}; + +#endif diff --git a/source/blender/compositor/operations/COM_PlaneTrackWarpImageOperation.cpp b/source/blender/compositor/operations/COM_PlaneTrackWarpImageOperation.cpp new file mode 100644 index 00000000000..9bbf45682f2 --- /dev/null +++ b/source/blender/compositor/operations/COM_PlaneTrackWarpImageOperation.cpp @@ -0,0 +1,207 @@ +/* + * Copyright 2013, Blender Foundation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor: + * Sergey Sharybin + */ + +#include "COM_PlaneTrackWarpImageOperation.h" +#include "COM_ReadBufferOperation.h" + +#include "MEM_guardedalloc.h" + +#include "BLI_listbase.h" +#include "BLI_math.h" +#include "BLI_math_color.h" + +extern "C" { + #include "BLI_jitter.h" + + #include "BKE_movieclip.h" + #include "BKE_node.h" + #include "BKE_tracking.h" +} + +BLI_INLINE bool isPointInsideQuad(const float x, const float y, const float corners[4][2]) +{ + float point[2]; + + point[0] = x; + point[1] = y; + + return isect_point_tri_v2(point, corners[0], corners[1], corners[2]) || + isect_point_tri_v2(point, corners[0], corners[2], corners[3]); +} + +BLI_INLINE bool resolveUV(const float x, const float y, const float corners[4][2], float uv[2]) +{ + float point[2]; + bool inside; + + inside = isPointInsideQuad(x, y, corners); + + point[0] = x; + point[1] = y; + + /* Use reverse bilinear to get UV coordinates within original frame */ + resolve_quad_uv(uv, point, corners[0], corners[1], corners[2], corners[3]); + + return inside; +} + +BLI_INLINE void resolveUVAndDxDy(const float x, const float y, const float corners[4][2], + float *u_r, float *v_r, float *dx_r, float *dy_r) +{ + float inputUV[2]; + float uv_a[2], uv_b[2]; + + float dx, dy; + float uv_l, uv_r; + float uv_u, uv_d; + + bool ok1, ok2; + + resolveUV(x, y, corners, inputUV); + + /* adaptive sampling, red (U) channel */ + ok1 = resolveUV(x - 1, y, corners, uv_a); + ok2 = resolveUV(x + 1, y, corners, uv_b); + uv_l = ok1 ? fabsf(inputUV[0] - uv_a[0]) : 0.0f; + uv_r = ok2 ? fabsf(inputUV[0] - uv_b[0]) : 0.0f; + + dx = 0.5f * (uv_l + uv_r); + + /* adaptive sampling, green (V) channel */ + ok1 = resolveUV(x, y - 1, corners, uv_a); + ok2 = resolveUV(x, y + 1, corners, uv_b); + uv_u = ok1 ? fabsf(inputUV[1] - uv_a[1]) : 0.f; + uv_d = ok2 ? fabsf(inputUV[1] - uv_b[1]) : 0.f; + + dy = 0.5f * (uv_u + uv_d); + + /* more adaptive sampling, red and green (UV) channels */ + ok1 = resolveUV(x - 1, y - 1, corners, uv_a); + ok2 = resolveUV(x - 1, y + 1, corners, uv_b); + uv_l = ok1 ? fabsf(inputUV[0] - uv_a[0]) : 0.f; + uv_r = ok2 ? fabsf(inputUV[0] - uv_b[0]) : 0.f; + uv_u = ok1 ? fabsf(inputUV[1] - uv_a[1]) : 0.f; + uv_d = ok2 ? fabsf(inputUV[1] - uv_b[1]) : 0.f; + + dx += 0.25f * (uv_l + uv_r); + dy += 0.25f * (uv_u + uv_d); + + ok1 = resolveUV(x + 1, y - 1, corners, uv_a); + ok2 = resolveUV(x + 1, y + 1, corners, uv_b); + uv_l = ok1 ? fabsf(inputUV[0] - uv_a[0]) : 0.f; + uv_r = ok2 ? fabsf(inputUV[0] - uv_b[0]) : 0.f; + uv_u = ok1 ? fabsf(inputUV[1] - uv_a[1]) : 0.f; + uv_d = ok2 ? fabsf(inputUV[1] - uv_b[1]) : 0.f; + + dx += 0.25f * (uv_l + uv_r); + dy += 0.25f * (uv_u + uv_d); + + /* should use mipmap */ + *dx_r = min(dx, 0.2f); + *dy_r = min(dy, 0.2f); + + *u_r = inputUV[0]; + *v_r = inputUV[1]; +} + +PlaneTrackWarpImageOperation::PlaneTrackWarpImageOperation() : PlaneTrackCommonOperation() +{ + this->addInputSocket(COM_DT_COLOR, COM_SC_NO_RESIZE); + this->addOutputSocket(COM_DT_COLOR); + this->m_pixelReader = NULL; + this->setComplex(true); +} + +void PlaneTrackWarpImageOperation::initExecution() +{ + PlaneTrackCommonOperation::initExecution(); + + this->m_pixelReader = this->getInputSocketReader(0); + + const int osa = 8; + this->m_osa = osa; + BLI_jitter_init(this->m_jitter[0], osa); +} + +void PlaneTrackWarpImageOperation::deinitExecution() +{ + this->m_pixelReader = NULL; +} + +void PlaneTrackWarpImageOperation::executePixel(float output[4], float x, float y, PixelSampler sampler) +{ + float color_accum[4]; + + zero_v4(color_accum); + for (int sample = 0; sample < this->m_osa; sample++) { + float current_x = x + this->m_jitter[sample][0], + current_y = y + this->m_jitter[sample][1]; + if (isPointInsideQuad(current_x, current_y, this->m_frameSpaceCorners)) { + float current_color[4]; + float u, v, dx, dy; + + resolveUVAndDxDy(current_x, current_y, this->m_frameSpaceCorners, &u, &v, &dx, &dy); + + u *= this->m_pixelReader->getWidth(); + v *= this->m_pixelReader->getHeight(); + + this->m_pixelReader->read(current_color, u, v, dx, dy, COM_PS_BICUBIC); + premul_to_straight_v4(current_color); + add_v4_v4(color_accum, current_color); + } + } + + mul_v4_v4fl(output, color_accum, 1.0f / this->m_osa); + straight_to_premul_v4(output); +} + +bool PlaneTrackWarpImageOperation::determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output) +{ + float frame_space_corners[4][2]; + + for (int i = 0; i < 4; i++) { + frame_space_corners[i][0] = this->m_corners[i][0] * this->getWidth(); + frame_space_corners[i][1] = this->m_corners[i][1] * this->getHeight(); + } + + float UVs[4][2]; + + /* TODO(sergey): figure out proper way to do this. */ + resolveUV(input->xmin - 2, input->ymin - 2, frame_space_corners, UVs[0]); + resolveUV(input->xmax + 2, input->ymin - 2, frame_space_corners, UVs[1]); + resolveUV(input->xmax + 2, input->ymax + 2, frame_space_corners, UVs[2]); + resolveUV(input->xmin - 2, input->ymax + 2, frame_space_corners, UVs[3]); + + float min[2], max[2]; + INIT_MINMAX2(min, max); + for (int i = 0; i < 4; i++) { + minmax_v2v2_v2(min, max, UVs[i]); + } + + rcti newInput; + + newInput.xmin = min[0] * readOperation->getWidth() - 1; + newInput.ymin = min[1] * readOperation->getHeight() - 1; + newInput.xmax = max[0] * readOperation->getWidth() + 1; + newInput.ymax = max[1] * readOperation->getHeight() + 1; + + return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); +} diff --git a/source/blender/compositor/operations/COM_PlaneTrackWarpImageOperation.h b/source/blender/compositor/operations/COM_PlaneTrackWarpImageOperation.h new file mode 100644 index 00000000000..a92ff3f9ddf --- /dev/null +++ b/source/blender/compositor/operations/COM_PlaneTrackWarpImageOperation.h @@ -0,0 +1,53 @@ + +/* + * Copyright 2013, Blender Foundation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor: + * Sergey Sharybin + */ + +#ifndef _COM_PlaneTrackWarpImageOperation_h +#define _COM_PlaneTrackWarpImageOperation_h + +#include <string.h> + +#include "COM_PlaneTrackCommonOperation.h" + +#include "DNA_movieclip_types.h" +#include "DNA_tracking_types.h" + +#include "BLI_listbase.h" +#include "BLI_string.h" + +class PlaneTrackWarpImageOperation : public PlaneTrackCommonOperation { +protected: + SocketReader *m_pixelReader; + int m_osa; + float m_jitter[32][2]; + +public: + PlaneTrackWarpImageOperation(); + + void initExecution(); + void deinitExecution(); + + void executePixel(float output[4], float x, float y, PixelSampler sampler); + + bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output); +}; + +#endif diff --git a/source/blender/editors/include/ED_transform.h b/source/blender/editors/include/ED_transform.h index 423613fb780..81308dd84f2 100644 --- a/source/blender/editors/include/ED_transform.h +++ b/source/blender/editors/include/ED_transform.h @@ -90,16 +90,14 @@ enum TfmMode { /* TRANSFORM CONTEXTS */ #define CTX_NONE 0 -#define CTX_TEXTURE 1 -#define CTX_EDGE 2 -#define CTX_NO_PET 4 -#define CTX_TWEAK 8 -#define CTX_NO_MIRROR 16 -#define CTX_AUTOCONFIRM 32 -#define CTX_BMESH 64 -#define CTX_NDOF 128 -#define CTX_MOVIECLIP 256 -#define CTX_MASK 512 +#define CTX_TEXTURE (1 << 0) +#define CTX_EDGE (1 << 1) +#define CTX_NO_PET (1 << 2) +#define CTX_NO_MIRROR (1 << 3) +#define CTX_AUTOCONFIRM (1 << 4) +#define CTX_NDOF (1 << 5) +#define CTX_MOVIECLIP (1 << 6) +#define CTX_MASK (1 << 7) /* Standalone call to get the transformation center corresponding to the current situation * returns 1 if successful, 0 otherwise (usually means there's no selection) diff --git a/source/blender/editors/mask/mask_relationships.c b/source/blender/editors/mask/mask_relationships.c index 2a1bdee32f7..6ced2423074 100644 --- a/source/blender/editors/mask/mask_relationships.c +++ b/source/blender/editors/mask/mask_relationships.c @@ -102,32 +102,53 @@ static int mask_parent_set_exec(bContext *C, wmOperator *UNUSED(op)) MaskLayer *masklay; /* parent info */ - SpaceClip *sc; - MovieClip *clip; + SpaceClip *sc = CTX_wm_space_clip(C); + MovieClip *clip = ED_space_clip_get_clip(sc); + MovieTracking *tracking; MovieTrackingTrack *track; - MovieTrackingMarker *marker; + MovieTrackingPlaneTrack *plane_track; MovieTrackingObject *tracking_object; /* done */ - int framenr; + int framenr, parent_type; + float parmask_pos[2], orig_corners[4][2]; + char *sub_parent_name; - float marker_pos_ofs[2]; - float parmask_pos[2]; - - if ((NULL == (sc = CTX_wm_space_clip(C))) || - (NULL == (clip = sc->clip)) || - (NULL == (track = clip->tracking.act_track)) || - (NULL == (tracking_object = BKE_tracking_object_get_active(&clip->tracking)))) - { + if (ELEM(NULL, sc, clip)) { return OPERATOR_CANCELLED; } framenr = ED_space_clip_get_clip_frame_number(sc); - marker = BKE_tracking_marker_get(track, framenr); - add_v2_v2v2(marker_pos_ofs, marker->pos, track->offset); + tracking = &clip->tracking; + tracking_object = BKE_tracking_object_get_active(&clip->tracking); + + if (tracking_object == NULL) { + return OPERATOR_CANCELLED; + } + + if ((track = BKE_tracking_track_get_active(tracking)) != NULL) { + MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr); + float marker_pos_ofs[2]; + + add_v2_v2v2(marker_pos_ofs, marker->pos, track->offset); - BKE_mask_coord_from_movieclip(clip, &sc->user, parmask_pos, marker_pos_ofs); + BKE_mask_coord_from_movieclip(clip, &sc->user, parmask_pos, marker_pos_ofs); + + sub_parent_name = track->name; + parent_type = MASK_PARENT_POINT_TRACK; + } + else if ((plane_track = BKE_tracking_plane_track_get_active(tracking)) != NULL) { + MovieTrackingPlaneMarker *plane_marker = BKE_tracking_plane_marker_get(plane_track, framenr); + + zero_v2(parmask_pos); + sub_parent_name = plane_track->name; + parent_type = MASK_PARENT_PLANE_TRACK; + memcpy(orig_corners, plane_marker->corners, sizeof(orig_corners)); + } + else { + return OPERATOR_CANCELLED; + } for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) { MaskSpline *spline; @@ -144,10 +165,12 @@ static int mask_parent_set_exec(bContext *C, wmOperator *UNUSED(op)) if (MASKPOINT_ISSEL_ANY(point)) { point->parent.id_type = ID_MC; point->parent.id = &clip->id; + point->parent.type = parent_type; BLI_strncpy(point->parent.parent, tracking_object->name, sizeof(point->parent.parent)); - BLI_strncpy(point->parent.sub_parent, track->name, sizeof(point->parent.sub_parent)); + BLI_strncpy(point->parent.sub_parent, sub_parent_name, sizeof(point->parent.sub_parent)); copy_v2_v2(point->parent.parent_orig, parmask_pos); + memcpy(point->parent.parent_corners_orig, orig_corners, sizeof(point->parent.parent_corners_orig)); } } } diff --git a/source/blender/editors/mask/mask_shapekey.c b/source/blender/editors/mask/mask_shapekey.c index 93bdca93096..d5fbdca5b0a 100644 --- a/source/blender/editors/mask/mask_shapekey.c +++ b/source/blender/editors/mask/mask_shapekey.c @@ -38,6 +38,7 @@ #include "BKE_context.h" #include "BKE_depsgraph.h" #include "BKE_mask.h" +#include "BKE_report.h" #include "DNA_object_types.h" #include "DNA_mask_types.h" diff --git a/source/blender/editors/mesh/editmesh_rip.c b/source/blender/editors/mesh/editmesh_rip.c index 59fe2a67057..1360a180b2d 100644 --- a/source/blender/editors/mesh/editmesh_rip.c +++ b/source/blender/editors/mesh/editmesh_rip.c @@ -952,6 +952,8 @@ static int edbm_rip_invoke__edge(bContext *C, wmOperator *op, const wmEvent *eve return OPERATOR_CANCELLED; } + BM_select_history_validate(bm); + return OPERATOR_FINISHED; } diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c index 4610bb89ae4..38ce56b4bc7 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -2399,7 +2399,7 @@ void MESH_OT_knife_cut(wmOperatorType *ot) RNA_def_int(ot->srna, "cursor", BC_KNIFECURSOR, 0, INT_MAX, "Cursor", "", 0, INT_MAX); } -static int mesh_separate_tagged(Main *bmain, Scene *scene, Base *base_old, BMesh *bm_old) +static Base *mesh_separate_tagged(Main *bmain, Scene *scene, Base *base_old, BMesh *bm_old) { Base *base_new; Object *obedit = base_old->object; @@ -2441,7 +2441,7 @@ static int mesh_separate_tagged(Main *bmain, Scene *scene, Base *base_old, BMesh BM_mesh_free(bm_new); ((Mesh *)base_new->object->data)->edit_btmesh = NULL; - return true; + return base_new; } static bool mesh_separate_selected(Main *bmain, Scene *scene, Base *base_old, BMesh *bm_old) @@ -2452,7 +2452,7 @@ static bool mesh_separate_selected(Main *bmain, Scene *scene, Base *base_old, BM /* sel -> tag */ BM_mesh_elem_hflag_enable_test(bm_old, BM_FACE | BM_EDGE | BM_VERT, BM_ELEM_TAG, true, BM_ELEM_SELECT); - return mesh_separate_tagged(bmain, scene, base_old, bm_old); + return (mesh_separate_tagged(bmain, scene, base_old, bm_old) != NULL); } /* flush a hflag to from verts to edges/faces */ @@ -2492,6 +2492,63 @@ static void bm_mesh_hflag_flush_vert(BMesh *bm, const char hflag) } } +/** + * Sets an object to a single material. from one of its slots. + * + * \note This could be used for split-by-material for non mesh types. + * \note This could take material data from another object or args. + */ +static void mesh_separate_material_assign_mat_nr(Object *ob, const short mat_nr) +{ + ID *obdata = ob->data; + + Material ***matarar; + short *totcolp; + + totcolp = give_totcolp_id(obdata); + matarar = give_matarar_id(obdata); + + if ((totcolp && matarar) == 0) { + BLI_assert(0); + return; + } + + if (*totcolp) { + Material *ma_ob; + Material *ma_obdata; + char matbit; + + if (mat_nr < ob->totcol) { + ma_ob = ob->mat[mat_nr]; + matbit = ob->matbits[mat_nr]; + } + else { + ma_ob = NULL; + matbit = 0; + } + + if (mat_nr < *totcolp) { + ma_obdata = (*matarar)[mat_nr]; + } + else { + ma_obdata = NULL; + } + + BKE_material_clear_id(obdata, true); + BKE_material_resize_object(ob, 1, true); + BKE_material_resize_id(obdata, 1, true); + + ob->mat[0] = ma_ob; + ob->matbits[0] = matbit; + (*matarar)[0] = ma_obdata; + } + else { + BKE_material_clear_id(obdata, true); + BKE_material_resize_object(ob, 0, true); + BKE_material_resize_id(obdata, 0, true); + } +} + static bool mesh_separate_material(Main *bmain, Scene *scene, Base *base_old, BMesh *bm_old) { BMFace *f_cmp, *f; @@ -2499,6 +2556,7 @@ static bool mesh_separate_material(Main *bmain, Scene *scene, Base *base_old, BM bool result = false; while ((f_cmp = BM_iter_at_index(bm_old, BM_FACES_OF_MESH, NULL, 0))) { + Base *base_new; const short mat_nr = f_cmp->mat_nr; int tot = 0; @@ -2522,11 +2580,22 @@ static bool mesh_separate_material(Main *bmain, Scene *scene, Base *base_old, BM /* leave the current object with some materials */ if (tot == bm_old->totface) { + mesh_separate_material_assign_mat_nr(base_old->object, mat_nr); + + /* since we're in editmode, must set faces here */ + BM_ITER_MESH (f, &iter, bm_old, BM_FACES_OF_MESH) { + f->mat_nr = 0; + } break; } /* Move selection into a separate object */ - result |= mesh_separate_tagged(bmain, scene, base_old, bm_old); + base_new = mesh_separate_tagged(bmain, scene, base_old, bm_old); + if (base_new) { + mesh_separate_material_assign_mat_nr(base_new->object, mat_nr); + } + + result |= (base_new != NULL); } return result; @@ -2585,7 +2654,7 @@ static bool mesh_separate_loose(Main *bmain, Scene *scene, Base *base_old, BMesh bm_mesh_hflag_flush_vert(bm_old, BM_ELEM_TAG); /* Move selection into a separate object */ - result |= mesh_separate_tagged(bmain, scene, base_old, bm_old); + result |= (mesh_separate_tagged(bmain, scene, base_old, bm_old) != NULL); } return result; diff --git a/source/blender/editors/space_clip/clip_draw.c b/source/blender/editors/space_clip/clip_draw.c index d1fd5093974..eb58bdc7696 100644 --- a/source/blender/editors/space_clip/clip_draw.c +++ b/source/blender/editors/space_clip/clip_draw.c @@ -111,6 +111,57 @@ static void draw_keyframe(int frame, int cfra, int sfra, float framelen, int wid } } +static int generic_track_get_markersnr(MovieTrackingTrack *track, MovieTrackingPlaneTrack *plane_track) +{ + if (track) { + return track->markersnr; + } + else if (plane_track) { + return plane_track->markersnr; + } + + return 0; +} + +static int generic_track_get_marker_framenr(MovieTrackingTrack *track, MovieTrackingPlaneTrack *plane_track, + int marker_index) +{ + if (track) { + return track->markers[marker_index].framenr; + } + else if (plane_track) { + return plane_track->markers[marker_index].framenr; + } + + return 0; +} + +static bool generic_track_is_marker_enabled(MovieTrackingTrack *track, MovieTrackingPlaneTrack *plane_track, + int marker_index) +{ + if (track) { + return (track->markers[marker_index].flag & MARKER_DISABLED) == 0; + } + else if (plane_track) { + return true; + } + + return false; +} + +static bool generic_track_is_marker_keyframed(MovieTrackingTrack *track, MovieTrackingPlaneTrack *plane_track, + int marker_index) +{ + if (track) { + return (track->markers[marker_index].flag & MARKER_TRACKED) == 0; + } + else if (plane_track) { + return (plane_track->markers[marker_index].flag & PLANE_MARKER_TRACKED) == 0; + } + + return false; +} + static void draw_movieclip_cache(SpaceClip *sc, ARegion *ar, MovieClip *clip, Scene *scene) { float x; @@ -119,6 +170,7 @@ static void draw_movieclip_cache(SpaceClip *sc, ARegion *ar, MovieClip *clip, Sc MovieTracking *tracking = &clip->tracking; MovieTrackingObject *act_object = BKE_tracking_object_get_active(tracking); MovieTrackingTrack *act_track = BKE_tracking_track_get_active(&clip->tracking); + MovieTrackingPlaneTrack *act_plane_track = BKE_tracking_plane_track_get_active(&clip->tracking); MovieTrackingReconstruction *reconstruction = BKE_tracking_get_active_reconstruction(tracking); glEnable(GL_BLEND); @@ -143,34 +195,29 @@ static void draw_movieclip_cache(SpaceClip *sc, ARegion *ar, MovieClip *clip, Sc } /* track */ - if (act_track) { - MovieTrackingTrack *track = act_track; - + if (act_track || act_plane_track) { for (i = sfra - clip->start_frame + 1, a = 0; i <= efra - clip->start_frame + 1; i++) { int framenr; - MovieTrackingMarker *marker; + int markersnr = generic_track_get_markersnr(act_track, act_plane_track); - while (a < track->markersnr) { - if (track->markers[a].framenr >= i) + while (a < markersnr) { + int marker_framenr = generic_track_get_marker_framenr(act_track, act_plane_track, a); + + if (marker_framenr >= i) break; - if (a < track->markersnr - 1 && track->markers[a + 1].framenr > i) + if (a < markersnr - 1 && generic_track_get_marker_framenr(act_track, act_plane_track, a + 1) > i) break; a++; } - if (a < track->markersnr) - marker = &track->markers[a]; - else - marker = &track->markers[track->markersnr - 1]; - - if ((marker->flag & MARKER_DISABLED) == 0) { - framenr = marker->framenr; + if (generic_track_is_marker_enabled(act_track, act_plane_track, a)) { + framenr = generic_track_get_marker_framenr(act_track, act_plane_track, a); if (framenr != i) glColor4ub(128, 128, 0, 96); - else if ((marker->flag & MARKER_TRACKED) == 0) + else if (generic_track_is_marker_keyframed(act_track, act_plane_track, a)) glColor4ub(255, 255, 0, 196); else glColor4ub(255, 255, 0, 96); @@ -961,13 +1008,159 @@ static void view2d_to_region_float(View2D *v2d, float x, float y, float *regionx *regiony = v2d->mask.ymin + y * BLI_rcti_size_y(&v2d->mask); } +static void plane_track_colors(bool is_active, float color[3], float selected_color[3]) +{ + UI_GetThemeColor3fv(TH_MARKER, color); + + if (is_active) + UI_GetThemeColor3fv(TH_ACT_MARKER, selected_color); + else + UI_GetThemeColor3fv(TH_SEL_MARKER, selected_color); +} + +static void getArrowEndPoint(const int width, const int height, const float zoom, + const float start_corner[2], const float end_corner[2], + float end_point[2]) +{ + float direction[2]; + float max_length; + + sub_v2_v2v2(direction, end_corner, start_corner); + + direction[0] *= width; + direction[1] *= height; + max_length = len_v2(direction); + normalize_v2(direction); + mul_v2_fl(direction, min_ff(32.0f / zoom, max_length)); + direction[0] /= width; + direction[1] /= height; + + add_v2_v2v2(end_point, start_corner, direction); +} + +static void draw_plane_marker_ex(SpaceClip *sc, MovieTrackingPlaneTrack *plane_track, + MovieTrackingPlaneMarker *plane_marker, bool is_active_track, + bool draw_outline, int width, int height) +{ + bool tiny = (sc->flag & SC_SHOW_TINY_MARKER) != 0; + bool is_selected_track = plane_track->flag & SELECT; + float px[2]; + + if (draw_outline) { + UI_ThemeColor(TH_MARKER_OUTLINE); + } + else { + float color[3], selected_color[3]; + plane_track_colors(is_active_track, color, selected_color); + if (is_selected_track) { + glColor3fv(selected_color); + } + else { + glColor3fv(color); + } + } + + px[0] = 1.0f / width / sc->zoom; + px[1] = 1.0f / height / sc->zoom; + + if (draw_outline) { + if (!tiny) { + glLineWidth(3.0f); + } + } + else if (tiny) { + glLineStipple(3, 0xaaaa); + glEnable(GL_LINE_STIPPLE); + glEnable(GL_COLOR_LOGIC_OP); + glLogicOp(GL_NOR); + } + + /* Draw rectangle itself. */ + glBegin(GL_LINE_LOOP); + glVertex2fv(plane_marker->corners[0]); + glVertex2fv(plane_marker->corners[1]); + glVertex2fv(plane_marker->corners[2]); + glVertex2fv(plane_marker->corners[3]); + glEnd(); + + /* Draw axis. */ + if (!draw_outline) { + float end_point[2]; + glPushAttrib(GL_COLOR_BUFFER_BIT | GL_CURRENT_BIT); + + getArrowEndPoint(width, height, sc->zoom, plane_marker->corners[0], plane_marker->corners[1], end_point); + glColor3f(1.0, 0.0, 0.0f); + glBegin(GL_LINES); + glVertex2fv(plane_marker->corners[0]); + glVertex2fv(end_point); + glEnd(); + + getArrowEndPoint(width, height, sc->zoom, plane_marker->corners[0], plane_marker->corners[3], end_point); + glColor3f(0.0, 1.0, 0.0f); + glBegin(GL_LINES); + glVertex2fv(plane_marker->corners[0]); + glVertex2fv(end_point); + glEnd(); + + glPopAttrib(); + } + + /* Draw sliders. */ + if (is_selected_track) { + int i; + for (i = 0; i < 4; i++) { + draw_marker_slide_square(plane_marker->corners[i][0], plane_marker->corners[i][1], + 3.0f * px[0], 3.0f * px[1], draw_outline, px); + } + } + + if (draw_outline) { + if (!tiny) { + glLineWidth(1.0f); + } + } + else if (tiny) { + glDisable(GL_COLOR_LOGIC_OP); + glDisable(GL_LINE_STIPPLE); + glLineStipple(3, 0xaaaa); + glEnable(GL_LINE_STIPPLE); + } +} + +static void draw_plane_marker_outline(SpaceClip *sc, MovieTrackingPlaneTrack *plane_track, + MovieTrackingPlaneMarker *plane_marker, int width, int height) +{ + draw_plane_marker_ex(sc, plane_track, plane_marker, false, true, width, height); +} + +static void draw_plane_marker(SpaceClip *sc, MovieTrackingPlaneTrack *plane_track, + MovieTrackingPlaneMarker *plane_marker, bool is_active_track, + int width, int height) +{ + draw_plane_marker_ex(sc, plane_track, plane_marker, is_active_track, false, width, height); +} + +static void draw_plane_track(SpaceClip *sc, MovieTrackingPlaneTrack *plane_track, + int framenr, bool is_active_track, int width, int height) +{ + MovieTrackingPlaneMarker *plane_marker; + + plane_marker = BKE_tracking_plane_marker_get(plane_track, framenr); + + draw_plane_marker_outline(sc, plane_track, plane_marker, width, height); + draw_plane_marker(sc, plane_track, plane_marker, is_active_track, width, height); +} + +/* Draw all kind of tracks. */ static void draw_tracking_tracks(SpaceClip *sc, ARegion *ar, MovieClip *clip, int width, int height, float zoomx, float zoomy) { float x, y; MovieTracking *tracking = &clip->tracking; ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking); + ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(tracking); MovieTrackingTrack *track, *act_track; + MovieTrackingPlaneTrack *plane_track, *active_plane_track; MovieTrackingMarker *marker; int framenr = ED_space_clip_get_clip_frame_number(sc); int undistort = sc->user.render_flag & MCLIP_PROXY_RENDER_UNDISTORT; @@ -1160,6 +1353,15 @@ static void draw_tracking_tracks(SpaceClip *sc, ARegion *ar, MovieClip *clip, glDisable(GL_POINT_SMOOTH); } + /* Draw plane tracks */ + active_plane_track = BKE_tracking_plane_track_get_active(tracking); + for (plane_track = plane_tracks_base->first; + plane_track; + plane_track = plane_track->next) + { + draw_plane_track(sc, plane_track, framenr, plane_track == active_plane_track, width, height); + } + glPopMatrix(); if (sc->flag & SC_SHOW_NAMES) { diff --git a/source/blender/editors/space_clip/clip_graph_ops.c b/source/blender/editors/space_clip/clip_graph_ops.c index edc6ac1ecf7..cdb0fdadebd 100644 --- a/source/blender/editors/space_clip/clip_graph_ops.c +++ b/source/blender/editors/space_clip/clip_graph_ops.c @@ -466,11 +466,10 @@ static int delete_curve_exec(bContext *C, wmOperator *UNUSED(op)) SpaceClip *sc = CTX_wm_space_clip(C); MovieClip *clip = ED_space_clip_get_clip(sc); MovieTracking *tracking = &clip->tracking; - ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking); MovieTrackingTrack *act_track = BKE_tracking_track_get_active(tracking); if (act_track) - clip_delete_track(C, clip, tracksbase, act_track); + clip_delete_track(C, clip, act_track); return OPERATOR_FINISHED; } @@ -498,7 +497,6 @@ static int delete_knot_exec(bContext *C, wmOperator *UNUSED(op)) SpaceClip *sc = CTX_wm_space_clip(C); MovieClip *clip = ED_space_clip_get_clip(sc); MovieTracking *tracking = &clip->tracking; - ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking); MovieTrackingTrack *act_track = BKE_tracking_track_get_active(tracking); if (act_track) { @@ -508,7 +506,7 @@ static int delete_knot_exec(bContext *C, wmOperator *UNUSED(op)) MovieTrackingMarker *marker = &act_track->markers[a]; if (marker->flag & MARKER_GRAPH_SEL) - clip_delete_marker(C, clip, tracksbase, act_track, marker); + clip_delete_marker(C, clip, act_track, marker); else a++; } diff --git a/source/blender/editors/space_clip/clip_intern.h b/source/blender/editors/space_clip/clip_intern.h index 51cb83eecad..8d112b7413c 100644 --- a/source/blender/editors/space_clip/clip_intern.h +++ b/source/blender/editors/space_clip/clip_intern.h @@ -132,8 +132,8 @@ void clip_graph_tracking_values_iterate(struct SpaceClip *sc, int selected_only, void clip_graph_tracking_iterate(struct SpaceClip *sc, int selected_only, int include_hidden, void *userdata, void (*func)(void *userdata, struct MovieTrackingMarker *marker)); -void clip_delete_track(struct bContext *C, struct MovieClip *clip, struct ListBase *tracksbase, struct MovieTrackingTrack *track); -void clip_delete_marker(struct bContext *C, struct MovieClip *clip, struct ListBase *tracksbase, struct MovieTrackingTrack *track, struct MovieTrackingMarker *marker); +void clip_delete_track(struct bContext *C, struct MovieClip *clip, struct MovieTrackingTrack *track); +void clip_delete_marker(struct bContext *C, struct MovieClip *clip, struct MovieTrackingTrack *track, struct MovieTrackingMarker *marker); void clip_view_center_to_point(SpaceClip *sc, float x, float y); @@ -193,6 +193,9 @@ void CLIP_OT_tracking_object_remove(struct wmOperatorType *ot); void CLIP_OT_copy_tracks(struct wmOperatorType *ot); void CLIP_OT_paste_tracks(struct wmOperatorType *ot); +void CLIP_OT_create_plane_track(struct wmOperatorType *ot); +void CLIP_OT_slide_plane_marker(struct wmOperatorType *ot); + /* tracking_select.c */ void CLIP_OT_select(struct wmOperatorType *ot); void CLIP_OT_select_all(struct wmOperatorType *ot); diff --git a/source/blender/editors/space_clip/clip_utils.c b/source/blender/editors/space_clip/clip_utils.c index d7a9b1c0cb6..72a3cb98a6a 100644 --- a/source/blender/editors/space_clip/clip_utils.c +++ b/source/blender/editors/space_clip/clip_utils.c @@ -175,11 +175,14 @@ void clip_graph_tracking_iterate(SpaceClip *sc, int selected_only, int include_h } } -void clip_delete_track(bContext *C, MovieClip *clip, ListBase *tracksbase, MovieTrackingTrack *track) +void clip_delete_track(bContext *C, MovieClip *clip, MovieTrackingTrack *track) { MovieTracking *tracking = &clip->tracking; MovieTrackingStabilization *stab = &tracking->stabilization; MovieTrackingTrack *act_track = BKE_tracking_track_get_active(tracking); + MovieTrackingPlaneTrack *plane_track, *next_plane_track; + ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking); + ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(tracking); int has_bundle = FALSE, update_stab = FALSE; @@ -196,6 +199,51 @@ void clip_delete_track(bContext *C, MovieClip *clip, ListBase *tracksbase, Movie if (track->flag & TRACK_HAS_BUNDLE) has_bundle = TRUE; + /* Make sure no plane will use freed track */ + for (plane_track = plane_tracks_base->first; + plane_track; + plane_track = next_plane_track) + { + bool found = false; + int i; + + next_plane_track = plane_track->next; + + for (i = 0; i < plane_track->point_tracksnr; i++) { + if (plane_track->point_tracks[i] == track) { + found = true; + break; + } + } + + if (!found) { + continue; + } + + if (plane_track->point_tracksnr > 4) { + int track_index; + MovieTrackingTrack **new_point_tracks; + + new_point_tracks = MEM_mallocN(sizeof(*new_point_tracks) * plane_track->point_tracksnr, + "new point tracks array"); + + for (i = 0, track_index = 0; i < plane_track->point_tracksnr; i++) { + if (plane_track->point_tracks[i] != track) { + new_point_tracks[track_index++] = plane_track->point_tracks[i]; + } + } + + MEM_freeN(plane_track->point_tracks); + plane_track->point_tracks = new_point_tracks; + plane_track->point_tracksnr--; + } + else { + /* Delete planes with less than 3 point tracks in it. */ + BKE_tracking_plane_track_free(plane_track); + BLI_freelinkN(plane_tracks_base, plane_track); + } + } + BKE_tracking_track_free(track); BLI_freelinkN(tracksbase, track); @@ -212,11 +260,11 @@ void clip_delete_track(bContext *C, MovieClip *clip, ListBase *tracksbase, Movie WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, NULL); } -void clip_delete_marker(bContext *C, MovieClip *clip, ListBase *tracksbase, - MovieTrackingTrack *track, MovieTrackingMarker *marker) +void clip_delete_marker(bContext *C, MovieClip *clip, MovieTrackingTrack *track, + MovieTrackingMarker *marker) { if (track->markersnr == 1) { - clip_delete_track(C, clip, tracksbase, track); + clip_delete_track(C, clip, track); } else { BKE_tracking_marker_delete(track, marker->framenr); diff --git a/source/blender/editors/space_clip/space_clip.c b/source/blender/editors/space_clip/space_clip.c index 562a8584560..8213853c937 100644 --- a/source/blender/editors/space_clip/space_clip.c +++ b/source/blender/editors/space_clip/space_clip.c @@ -517,6 +517,10 @@ static void clip_operatortypes(void) WM_operatortype_append(CLIP_OT_copy_tracks); WM_operatortype_append(CLIP_OT_paste_tracks); + /* Plane tracker */ + WM_operatortype_append(CLIP_OT_create_plane_track); + WM_operatortype_append(CLIP_OT_slide_plane_marker); + /* ** clip_graph_ops.c ** */ /* graph editing */ @@ -685,6 +689,9 @@ static void clip_keymap(struct wmKeyConfig *keyconf) WM_keymap_add_item(keymap, "CLIP_OT_hide_tracks_clear", HKEY, KM_PRESS, KM_ALT, 0); + /* plane tracks */ + WM_keymap_add_item(keymap, "CLIP_OT_slide_plane_marker", LEFTMOUSE, KM_PRESS, 0, 0); + /* clean-up */ WM_keymap_add_item(keymap, "CLIP_OT_join_tracks", JKEY, KM_PRESS, KM_CTRL, 0); diff --git a/source/blender/editors/space_clip/tracking_ops.c b/source/blender/editors/space_clip/tracking_ops.c index f3d070452a5..e14fc8ad399 100644 --- a/source/blender/editors/space_clip/tracking_ops.c +++ b/source/blender/editors/space_clip/tracking_ops.c @@ -34,6 +34,7 @@ #include "DNA_camera_types.h" #include "DNA_constraint_types.h" #include "DNA_gpencil_types.h" +#include "DNA_mask_types.h" #include "DNA_movieclip_types.h" #include "DNA_object_types.h" /* SELECT */ #include "DNA_scene_types.h" @@ -55,6 +56,8 @@ #include "BKE_report.h" #include "BKE_scene.h" #include "BKE_library.h" +#include "BKE_mask.h" +#include "BKE_node.h" #include "BKE_sound.h" #include "WM_api.h" @@ -88,6 +91,7 @@ static bool add_marker(const bContext *C, float x, float y) MovieClip *clip = ED_space_clip_get_clip(sc); MovieTracking *tracking = &clip->tracking; ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking); + ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(tracking); MovieTrackingTrack *track; int width, height; int framenr = ED_space_clip_get_clip_frame_number(sc); @@ -101,8 +105,10 @@ static bool add_marker(const bContext *C, float x, float y) track = BKE_tracking_track_add(tracking, tracksbase, x, y, framenr, width, height); BKE_tracking_track_select(tracksbase, track, TRACK_AREA_ALL, 0); + BKE_tracking_plane_tracks_deselect_all(plane_tracks_base); clip->tracking.act_track = track; + clip->tracking.act_plane_track = NULL; return true; } @@ -234,13 +240,31 @@ static int delete_track_exec(bContext *C, wmOperator *UNUSED(op)) MovieClip *clip = ED_space_clip_get_clip(sc); MovieTracking *tracking = &clip->tracking; ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking); + ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(tracking); MovieTrackingTrack *track = tracksbase->first, *next; + MovieTrackingPlaneTrack *plane_track, *next_plane_track; + bool modified = false; + + /* Delete selected plane tracks. */ + for (plane_track = plane_tracks_base->first; + plane_track; + plane_track = next_plane_track) + { + next_plane_track = plane_track->next; + + if (plane_track->flag & SELECT) { + BKE_tracking_plane_track_free(plane_track); + BLI_freelinkN(plane_tracks_base, plane_track); + modified = true; + } + } + /* Remove selected point tracks (they'll also be removed from planes which uses them). */ while (track) { next = track->next; if (TRACK_VIEW_SELECTED(sc, track)) - clip_delete_track(C, clip, tracksbase, track); + clip_delete_track(C, clip, track); track = next; } @@ -248,6 +272,10 @@ static int delete_track_exec(bContext *C, wmOperator *UNUSED(op)) /* nothing selected now, unlock view so it can be scrolled nice again */ sc->flag &= ~SC_LOCK_SELECTION; + if (modified) { + WM_event_add_notifier(C, NC_MOVIECLIP | NA_EDITED, clip); + } + return OPERATOR_FINISHED; } @@ -274,7 +302,9 @@ static int delete_marker_exec(bContext *C, wmOperator *UNUSED(op)) SpaceClip *sc = CTX_wm_space_clip(C); MovieClip *clip = ED_space_clip_get_clip(sc); ListBase *tracksbase = BKE_tracking_get_active_tracks(&clip->tracking); + ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(&clip->tracking); MovieTrackingTrack *track = tracksbase->first, *next; + MovieTrackingPlaneTrack *plane_track, *plane_track_next; int framenr = ED_space_clip_get_clip_frame_number(sc); int has_selection = 0; @@ -287,13 +317,34 @@ static int delete_marker_exec(bContext *C, wmOperator *UNUSED(op)) if (marker) { has_selection |= track->markersnr > 1; - clip_delete_marker(C, clip, tracksbase, track, marker); + clip_delete_marker(C, clip, track, marker); } } track = next; } + for (plane_track = plane_tracks_base->first; + plane_track; + plane_track = plane_track_next) + { + plane_track_next = plane_track->next; + + if (plane_track->flag & SELECT) { + MovieTrackingPlaneMarker *plane_marker = BKE_tracking_plane_marker_get_exact(plane_track, framenr); + + if (plane_marker) { + if (plane_track->markersnr == 1) { + BKE_tracking_plane_track_free(plane_track); + BLI_freelinkN(plane_tracks_base, plane_track); + } + else { + BKE_tracking_plane_marker_delete(plane_track, framenr); + } + } + } + } + if (!has_selection) { /* nothing selected now, unlock view so it can be scrolled nice again */ sc->flag &= ~SC_LOCK_SELECTION; @@ -727,6 +778,7 @@ static int slide_marker_invoke(bContext *C, wmOperator *op, const wmEvent *event MovieTracking *tracking = &clip->tracking; tracking->act_track = slidedata->track; + tracking->act_plane_track = NULL; op->customdata = slidedata; @@ -3670,3 +3722,350 @@ void CLIP_OT_paste_tracks(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } + +/********************** Create plane track operator *********************/ + +static int create_plane_track_tracks_exec(bContext *C, wmOperator *op) +{ + SpaceClip *sc = CTX_wm_space_clip(C); + MovieClip *clip = ED_space_clip_get_clip(sc); + MovieTracking *tracking = &clip->tracking; + MovieTrackingPlaneTrack *plane_track; + ListBase *tracks_base = BKE_tracking_get_active_tracks(tracking); + ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(tracking); + int framenr = ED_space_clip_get_clip_frame_number(sc); + + plane_track = BKE_tracking_plane_track_add(tracking, plane_tracks_base, tracks_base, framenr); + + if (plane_track == NULL) { + BKE_report(op->reports, RPT_ERROR, "Need at least 4 selected point tracks to create a plane"); + return OPERATOR_CANCELLED; + } + else { + BKE_tracking_tracks_deselect_all(tracks_base); + + plane_track->flag |= SELECT; + clip->tracking.act_track = NULL; + clip->tracking.act_plane_track = plane_track; + + /* Copute homoraphies and apply them on marker's corner, so we've got + * quite nice motion from the very beginning. + */ + BKE_tracking_track_plane_from_existing_motion(plane_track, framenr); + } + + WM_event_add_notifier(C, NC_MOVIECLIP | NA_EDITED, clip); + + return OPERATOR_FINISHED; +} + +void CLIP_OT_create_plane_track(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Create Plane Track"; + ot->description = "Create new plane track out of selected point tracks"; + ot->idname = "CLIP_OT_create_plane_track"; + + /* api callbacks */ + ot->exec = create_plane_track_tracks_exec; + ot->poll = ED_space_clip_tracking_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +/********************** Slide plane marker corner operator *********************/ + +typedef struct SlidePlaneMarkerData { + MovieTrackingPlaneTrack *plane_track; + MovieTrackingPlaneMarker *plane_marker; + int width, height; + int corner_index; + float *corner; + int previous_mval[2]; + float previous_corner[2]; + float old_corner[2]; + bool accurate; +} SlidePlaneMarkerData; + +static bool mouse_on_plane_slide_zone(SpaceClip *sc, float co[2], float slide_zone[2], int width, int height) +{ + const float size = 12.0f; + float dx, dy; + + dx = size / width / sc->zoom; + dy = size / height / sc->zoom; + + return IN_RANGE_INCL(co[0], slide_zone[0] - dx, slide_zone[0] + dx) && + IN_RANGE_INCL(co[1], slide_zone[1] - dy, slide_zone[1] + dy); +} + +static MovieTrackingPlaneTrack *tracking_plane_marker_check_slide(bContext *C, const wmEvent *event, int *corner_r) +{ + SpaceClip *sc = CTX_wm_space_clip(C); + ARegion *ar = CTX_wm_region(C); + MovieClip *clip = ED_space_clip_get_clip(sc); + MovieTrackingPlaneTrack *plane_track; + int width, height; + float co[2]; + ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(&clip->tracking); + int framenr = ED_space_clip_get_clip_frame_number(sc); + + ED_space_clip_get_size(sc, &width, &height); + + if (width == 0 || height == 0) { + return NULL; + } + + ED_clip_mouse_pos(sc, ar, event->mval, co); + + for (plane_track = plane_tracks_base->first; + plane_track; + plane_track = plane_track->next) + { + if (plane_track->flag & SELECT) { + MovieTrackingPlaneMarker *plane_marker = BKE_tracking_plane_marker_get(plane_track, framenr); + bool ok = false; + int i; + + for (i = 0; i < 4; i++) { + if (mouse_on_plane_slide_zone(sc, co, plane_marker->corners[i], width, height)) { + if (corner_r) { + *corner_r = i; + } + ok = true; + break; + } + } + + if (ok) { + return plane_track; + } + } + } + + return NULL; +} + +static void *slide_plane_marker_customdata(bContext *C, const wmEvent *event) +{ + SpaceClip *sc = CTX_wm_space_clip(C); + ARegion *ar = CTX_wm_region(C); + MovieTrackingPlaneTrack *plane_track; + int width, height; + float co[2]; + SlidePlaneMarkerData *customdata = NULL; + int framenr = ED_space_clip_get_clip_frame_number(sc); + int corner; + + ED_space_clip_get_size(sc, &width, &height); + + if (width == 0 || height == 0) { + return NULL; + } + + ED_clip_mouse_pos(sc, ar, event->mval, co); + + plane_track = tracking_plane_marker_check_slide(C, event, &corner); + if (plane_track) { + MovieTrackingPlaneMarker *plane_marker; + + customdata = MEM_callocN(sizeof(SlidePlaneMarkerData), "slide plane marker data"); + + plane_marker = BKE_tracking_plane_marker_ensure(plane_track, framenr); + + customdata->plane_track = plane_track; + customdata->plane_marker = plane_marker; + customdata->width = width; + customdata->height = height; + + customdata->previous_mval[0] = event->mval[0]; + customdata->previous_mval[1] = event->mval[1]; + + customdata->corner_index = corner; + customdata->corner = plane_marker->corners[corner]; + + copy_v2_v2(customdata->previous_corner, customdata->corner); + copy_v2_v2(customdata->old_corner, customdata->corner); + } + + return customdata; +} + +static int slide_plane_marker_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + SlidePlaneMarkerData *slidedata = slide_plane_marker_customdata(C, event); + + if (slidedata) { + SpaceClip *sc = CTX_wm_space_clip(C); + MovieClip *clip = ED_space_clip_get_clip(sc); + MovieTracking *tracking = &clip->tracking; + + tracking->act_plane_track = slidedata->plane_track; + tracking->act_track = NULL; + + op->customdata = slidedata; + + hide_cursor(C); + WM_event_add_modal_handler(C, op); + + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, NULL); + + return OPERATOR_RUNNING_MODAL; + } + + return OPERATOR_PASS_THROUGH; +} + +static void cancel_mouse_slide_plane_marker(SlidePlaneMarkerData *data) +{ + copy_v2_v2(data->corner, data->old_corner); +} + +static void free_slide_plane_marker_data(SlidePlaneMarkerData *data) +{ + MEM_freeN(data); +} + +static void slide_plane_marker_update_homographies(SpaceClip *sc, SlidePlaneMarkerData *data) +{ + int framenr = ED_space_clip_get_clip_frame_number(sc); + + BKE_tracking_track_plane_from_existing_motion(data->plane_track, framenr); +} + +static int slide_plane_marker_modal(bContext *C, wmOperator *op, const wmEvent *event) +{ + SpaceClip *sc = CTX_wm_space_clip(C); + MovieClip *clip = ED_space_clip_get_clip(sc); + SlidePlaneMarkerData *data = (SlidePlaneMarkerData *) op->customdata; + float dx, dy, mdelta[2]; + int next_corner_index, prev_corner_index, diag_corner_index; + float *next_corner, *prev_corner, *diag_corner; + float next_edge[2], prev_edge[2], next_diag_edge[2], prev_diag_edge[2]; + + switch (event->type) { + case LEFTCTRLKEY: + case RIGHTCTRLKEY: + case LEFTSHIFTKEY: + case RIGHTSHIFTKEY: + if (ELEM(event->type, LEFTSHIFTKEY, RIGHTSHIFTKEY)) + data->accurate = event->val == KM_PRESS; + + /* fall-through */ + case MOUSEMOVE: + mdelta[0] = event->mval[0] - data->previous_mval[0]; + mdelta[1] = event->mval[1] - data->previous_mval[1]; + + dx = mdelta[0] / data->width / sc->zoom; + dy = mdelta[1] / data->height / sc->zoom; + + if (data->accurate) { + dx /= 5.0f; + dy /= 5.0f; + } + + data->corner[0] = data->previous_corner[0] + dx; + data->corner[1] = data->previous_corner[1] + dy; + + + /* + prev_edge + (Corner 3, current) <----------------------- (Corner 2, previous) + | ^ + | | + | | + | | + next_edge | | next_diag_edge + | | + | | + | | + v | + (Corner 0, next) -----------------------> (Corner 1, diagonal) + prev_diag_edge + */ + + next_corner_index = (data->corner_index + 1) % 4; + prev_corner_index = (data->corner_index + 3) % 4; + diag_corner_index = (data->corner_index + 2) % 4; + + next_corner = data->plane_marker->corners[next_corner_index]; + prev_corner = data->plane_marker->corners[prev_corner_index]; + diag_corner = data->plane_marker->corners[diag_corner_index]; + + sub_v2_v2v2(next_edge, next_corner, data->corner); + sub_v2_v2v2(prev_edge, data->corner, prev_corner); + sub_v2_v2v2(next_diag_edge, prev_corner, diag_corner); + sub_v2_v2v2(prev_diag_edge, diag_corner, next_corner); + + if (cross_v2v2(prev_edge, next_edge) < 0.0f) { + closest_to_line_v2(data->corner, data->corner, prev_corner, next_corner); + } + + if (cross_v2v2(next_diag_edge, prev_edge) < 0.0f) { + closest_to_line_v2(data->corner, data->corner, prev_corner, diag_corner); + } + + if (cross_v2v2(next_edge, prev_diag_edge) < 0.0f) { + closest_to_line_v2(data->corner, data->corner, next_corner, diag_corner); + } + + data->previous_mval[0] = event->mval[0]; + data->previous_mval[1] = event->mval[1]; + copy_v2_v2(data->previous_corner, data->corner); + + DAG_id_tag_update(&sc->clip->id, 0); + + WM_event_add_notifier(C, NC_MOVIECLIP | NA_EDITED, NULL); + + break; + + case LEFTMOUSE: + if (event->val == KM_RELEASE) { + /* Marker is now keyframed. */ + data->plane_marker->flag &= ~PLANE_MARKER_TRACKED; + + slide_plane_marker_update_homographies(sc, data); + + free_slide_plane_marker_data(op->customdata); + + show_cursor(C); + + DAG_id_tag_update(&sc->clip->id, 0); + WM_event_add_notifier(C, NC_MOVIECLIP | NA_EDITED, clip); + + return OPERATOR_FINISHED; + } + + break; + + case ESCKEY: + cancel_mouse_slide_plane_marker(op->customdata); + + free_slide_plane_marker_data(op->customdata); + + show_cursor(C); + + WM_event_add_notifier(C, NC_MOVIECLIP | NA_EDITED, clip); + + return OPERATOR_CANCELLED; + } + + return OPERATOR_RUNNING_MODAL; +} + +void CLIP_OT_slide_plane_marker(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Slide Plane Marker"; + ot->description = "Slide plane marker areas"; + ot->idname = "CLIP_OT_slide_plane_marker"; + + /* api callbacks */ + ot->poll = ED_space_clip_tracking_poll; + ot->invoke = slide_plane_marker_invoke; + ot->modal = slide_plane_marker_modal; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_GRAB_POINTER | OPTYPE_BLOCKING; +} diff --git a/source/blender/editors/space_clip/tracking_select.c b/source/blender/editors/space_clip/tracking_select.c index b03209173d8..6e4d10173fb 100644 --- a/source/blender/editors/space_clip/tracking_select.c +++ b/source/blender/editors/space_clip/tracking_select.c @@ -169,6 +169,7 @@ static float dist_to_rect(float co[2], float pos[2], float min[2], float max[2]) return sqrtf(min_ffff(d1, d2, d3, d4)); } +/* Distance to quad defined by it's corners, corners are relative to pos */ static float dist_to_crns(float co[2], float pos[2], float crns[4][2]) { float d1, d2, d3, d4; @@ -184,7 +185,22 @@ static float dist_to_crns(float co[2], float pos[2], float crns[4][2]) return sqrtf(min_ffff(d1, d2, d3, d4)); } -static MovieTrackingTrack *find_nearest_track(SpaceClip *sc, ListBase *tracksbase, float co[2]) +/* Same as above, but all the coordinates are absolute */ +static float dist_to_crns_abs(float co[2], float corners[4][2]) +{ + float d1, d2, d3, d4; + float *v1 = corners[0], *v2 = corners[1]; + float *v3 = corners[2], *v4 = corners[3]; + + d1 = dist_squared_to_line_segment_v2(co, v1, v2); + d2 = dist_squared_to_line_segment_v2(co, v2, v3); + d3 = dist_squared_to_line_segment_v2(co, v3, v4); + d4 = dist_squared_to_line_segment_v2(co, v4, v1); + + return sqrtf(min_ffff(d1, d2, d3, d4)); +} + +static MovieTrackingTrack *find_nearest_track(SpaceClip *sc, ListBase *tracksbase, float co[2], float *distance_r) { MovieTrackingTrack *track = NULL, *cur; float mindist = 0.0f; @@ -221,19 +237,88 @@ static MovieTrackingTrack *find_nearest_track(SpaceClip *sc, ListBase *tracksbas cur = cur->next; } + *distance_r = mindist; + return track; } +static MovieTrackingPlaneTrack *find_nearest_plane_track(SpaceClip *sc, ListBase *plane_tracks_base, + float co[2], float *distance_r) +{ + MovieTrackingPlaneTrack *plane_track = NULL, *current_plane_track; + float min_distance = 0.0f; + int framenr = ED_space_clip_get_clip_frame_number(sc); + + for (current_plane_track = plane_tracks_base->first; + current_plane_track; + current_plane_track = current_plane_track->next) + { + MovieTrackingPlaneMarker *plane_marker = BKE_tracking_plane_marker_get(current_plane_track, framenr); + + if ((current_plane_track->flag & TRACK_HIDDEN) == 0) { + float distance = dist_to_crns_abs(co, plane_marker->corners); + if (plane_track == NULL || distance < min_distance) { + plane_track = current_plane_track; + min_distance = distance; + } + } + } + + *distance_r = min_distance; + + return plane_track; +} + +static void delect_all_tracks(ListBase *tracks_base) +{ + MovieTrackingTrack *track; + for (track = tracks_base->first; + track; + track = track->next) + { + BKE_tracking_track_flag_clear(track, TRACK_AREA_ALL, SELECT); + } +} + +static void delect_all_plane_tracks(ListBase *plane_tracks_base) +{ + MovieTrackingPlaneTrack *plane_track; + for (plane_track = plane_tracks_base->first; + plane_track; + plane_track = plane_track->next) + { + plane_track->flag &= ~SELECT; + } +} + static int mouse_select(bContext *C, float co[2], int extend) { SpaceClip *sc = CTX_wm_space_clip(C); MovieClip *clip = ED_space_clip_get_clip(sc); MovieTracking *tracking = &clip->tracking; ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking); + ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(tracking); MovieTrackingTrack *act_track = BKE_tracking_track_get_active(tracking); - MovieTrackingTrack *track = NULL; /* selected marker */ + MovieTrackingTrack *track; + MovieTrackingPlaneTrack *plane_track; + float distance_to_track, distance_to_plane_track; + + track = find_nearest_track(sc, tracksbase, co, &distance_to_track); + plane_track = find_nearest_plane_track(sc, plane_tracks_base, co, &distance_to_plane_track); + + /* Between track and plane we choose closest to the mouse for selection here. */ + if (track && plane_track) { + if (distance_to_track < distance_to_plane_track) { + plane_track = NULL; + } + else { + track = NULL; + } + } - track = find_nearest_track(sc, tracksbase, co); + if (!extend) { + delect_all_plane_tracks(plane_tracks_base); + } if (track) { int area = track_mouse_area(C, co, track); @@ -242,10 +327,13 @@ static int mouse_select(bContext *C, float co[2], int extend) area = TRACK_AREA_ALL; if (extend && TRACK_AREA_SELECTED(track, area)) { - if (track == act_track) + if (track == act_track) { BKE_tracking_track_deselect(track, area); - else + } + else { clip->tracking.act_track = track; + clip->tracking.act_plane_track = NULL; + } } else { if (area == TRACK_AREA_POINT) @@ -253,7 +341,25 @@ static int mouse_select(bContext *C, float co[2], int extend) BKE_tracking_track_select(tracksbase, track, area, extend); clip->tracking.act_track = track; + clip->tracking.act_plane_track = NULL; + } + } + else if (plane_track) { + if (!extend) { + delect_all_tracks(tracksbase); + } + + if (plane_track->flag & SELECT) { + if (extend) { + plane_track->flag &= ~SELECT; + } + } + else { + plane_track->flag |= SELECT; } + + clip->tracking.act_track = NULL; + clip->tracking.act_plane_track = plane_track; } if (!extend) { @@ -350,7 +456,9 @@ static int border_select_exec(bContext *C, wmOperator *op) MovieClip *clip = ED_space_clip_get_clip(sc); MovieTracking *tracking = &clip->tracking; MovieTrackingTrack *track; + MovieTrackingPlaneTrack *plane_track; ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking); + ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(tracking); rcti rect; rctf rectf; int change = FALSE, mode, extend; @@ -389,6 +497,33 @@ static int border_select_exec(bContext *C, wmOperator *op) track = track->next; } + for (plane_track = plane_tracks_base->first; + plane_track; + plane_track = plane_track->next) + { + if ((plane_track->flag & PLANE_TRACK_HIDDEN) == 0) { + MovieTrackingPlaneMarker *plane_marker = + BKE_tracking_plane_marker_get(plane_track, framenr); + int i; + + for (i = 0; i < 4; i++) { + if (BLI_rctf_isect_pt_v(&rectf, plane_marker->corners[i])) { + if (mode == GESTURE_MODAL_SELECT) { + plane_track->flag |= SELECT; + } + else { + plane_track->flag &= ~SELECT; + } + } + else if (!extend) { + plane_track->flag &= ~SELECT; + } + } + + change = TRUE; + } + } + if (change) { BKE_tracking_dopesheet_tag_update(tracking); @@ -430,7 +565,9 @@ static int do_lasso_select_marker(bContext *C, const int mcords[][2], const shor MovieClip *clip = ED_space_clip_get_clip(sc); MovieTracking *tracking = &clip->tracking; MovieTrackingTrack *track; + MovieTrackingPlaneTrack *plane_track; ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking); + ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(tracking); rcti rect; int change = FALSE; int framenr = ED_space_clip_get_clip_frame_number(sc); @@ -466,6 +603,37 @@ static int do_lasso_select_marker(bContext *C, const int mcords[][2], const shor track = track->next; } + for (plane_track = plane_tracks_base->first; + plane_track; + plane_track = plane_track->next) + { + if ((plane_track->flag & PLANE_TRACK_HIDDEN) == 0) { + MovieTrackingPlaneMarker *plane_marker = + BKE_tracking_plane_marker_get(plane_track, framenr); + int i; + + for (i = 0; i < 4; i++) { + float screen_co[2]; + + /* marker in screen coords */ + ED_clip_point_stable_pos__reverse(sc, ar, plane_marker->corners[i], screen_co); + + if (BLI_rcti_isect_pt(&rect, screen_co[0], screen_co[1]) && + BLI_lasso_is_point_inside(mcords, moves, screen_co[0], screen_co[1], V2D_IS_CLIPPED)) + { + if (select) { + plane_track->flag |= SELECT; + } + else { + plane_track->flag &= ~SELECT; + } + } + } + + change = TRUE; + } + } + if (change) { BKE_tracking_dopesheet_tag_update(tracking); @@ -518,17 +686,22 @@ void CLIP_OT_select_lasso(wmOperatorType *ot) /********************** circle select operator *********************/ -static int marker_inside_ellipse(MovieTrackingMarker *marker, float offset[2], float ellipse[2]) +static int point_inside_ellipse(float point[2], float offset[2], float ellipse[2]) { /* normalized ellipse: ell[0] = scaleX, ell[1] = scaleY */ float x, y; - x = (marker->pos[0] - offset[0]) * ellipse[0]; - y = (marker->pos[1] - offset[1]) * ellipse[1]; + x = (point[0] - offset[0]) * ellipse[0]; + y = (point[1] - offset[1]) * ellipse[1]; return x * x + y * y < 1.0f; } +static int marker_inside_ellipse(MovieTrackingMarker *marker, float offset[2], float ellipse[2]) +{ + return point_inside_ellipse(marker->pos, offset, ellipse); +} + static int circle_select_exec(bContext *C, wmOperator *op) { SpaceClip *sc = CTX_wm_space_clip(C); @@ -537,7 +710,9 @@ static int circle_select_exec(bContext *C, wmOperator *op) MovieClip *clip = ED_space_clip_get_clip(sc); MovieTracking *tracking = &clip->tracking; MovieTrackingTrack *track; + MovieTrackingPlaneTrack *plane_track; ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking); + ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(tracking); int x, y, radius, width, height, mode, change = FALSE; float zoomx, zoomy, offset[2], ellipse[2]; int framenr = ED_space_clip_get_clip_frame_number(sc); @@ -577,6 +752,30 @@ static int circle_select_exec(bContext *C, wmOperator *op) track = track->next; } + for (plane_track = plane_tracks_base->first; + plane_track; + plane_track = plane_track->next) + { + if ((plane_track->flag & PLANE_TRACK_HIDDEN) == 0) { + MovieTrackingPlaneMarker *plane_marker = + BKE_tracking_plane_marker_get(plane_track, framenr); + int i; + + for (i = 0; i < 4; i++) { + if (point_inside_ellipse(plane_marker->corners[i], offset, ellipse)) { + if (mode == GESTURE_MODAL_SELECT) { + plane_track->flag |= SELECT; + } + else { + plane_track->flag &= ~SELECT; + } + } + } + + change = TRUE; + } + } + if (change) { BKE_tracking_dopesheet_tag_update(tracking); @@ -619,16 +818,18 @@ static int select_all_exec(bContext *C, wmOperator *op) MovieClip *clip = ED_space_clip_get_clip(sc); MovieTracking *tracking = &clip->tracking; MovieTrackingTrack *track = NULL; /* selected track */ + MovieTrackingPlaneTrack *plane_track = NULL; /* selected plane track */ MovieTrackingMarker *marker; ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking); + ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(tracking); int action = RNA_enum_get(op->ptr, "action"); int framenr = ED_space_clip_get_clip_frame_number(sc); int has_selection = FALSE; if (action == SEL_TOGGLE) { action = SEL_SELECT; - track = tracksbase->first; - while (track) { + + for (track = tracksbase->first; track; track = track->next) { if (TRACK_VIEW_SELECTED(sc, track)) { marker = BKE_tracking_marker_get(track, framenr); @@ -637,13 +838,20 @@ static int select_all_exec(bContext *C, wmOperator *op) break; } } + } - track = track->next; + for (plane_track = plane_tracks_base->first; + plane_track; + plane_track = plane_track->next) + { + if (plane_track->flag & SELECT) { + action = SEL_DESELECT; + break; + } } } - track = tracksbase->first; - while (track) { + for (track = tracksbase->first; track; track = track->next) { if ((track->flag & TRACK_HIDDEN) == 0) { marker = BKE_tracking_marker_get(track, framenr); @@ -670,8 +878,29 @@ static int select_all_exec(bContext *C, wmOperator *op) if (TRACK_VIEW_SELECTED(sc, track)) has_selection = TRUE; + } - track = track->next; + for (plane_track = plane_tracks_base->first; + plane_track; + plane_track = plane_track->next) + { + if ((plane_track->flag & PLANE_TRACK_HIDDEN) == 0) { + switch (action) { + case SEL_SELECT: + plane_track->flag |= SELECT; + break; + case SEL_DESELECT: + plane_track->flag &= ~SELECT; + break; + case SEL_INVERT: + plane_track->flag ^= SELECT; + break; + } + } + + if (plane_track->flag & SELECT) { + has_selection = TRUE; + } } if (!has_selection) diff --git a/source/blender/editors/space_file/file_panels.c b/source/blender/editors/space_file/file_panels.c index d6f644ab330..0efc7b927a9 100644 --- a/source/blender/editors/space_file/file_panels.c +++ b/source/blender/editors/space_file/file_panels.c @@ -115,6 +115,7 @@ static void file_panel_category(const bContext *C, Panel *pa, FSMenuCategory cat /* create list item */ but = uiDefIconTextButS(block, LISTROW, 0, icon, dir, 0, 0, UI_UNIT_X * 10, UI_UNIT_Y, nr, 0, i, 0, 0, entry); uiButSetFunc(but, file_panel_cb, entry, NULL); + uiButClearFlag(but, UI_BUT_UNDO); /* skip undo on screen buttons */ uiButSetFlag(but, UI_ICON_LEFT | UI_TEXT_LEFT); /* create delete button */ diff --git a/source/blender/editors/space_logic/logic_window.c b/source/blender/editors/space_logic/logic_window.c index 2957edd941b..aed5699a9d7 100644 --- a/source/blender/editors/space_logic/logic_window.c +++ b/source/blender/editors/space_logic/logic_window.c @@ -1465,6 +1465,7 @@ static void draw_actuator_action(uiLayout *layout, PointerRNA *ptr) row = uiLayoutRow(layout, FALSE); uiItemR(row, ptr, "layer", 0, NULL, ICON_NONE); uiItemR(row, ptr, "layer_weight", 0, NULL, ICON_NONE); + uiItemR(row, ptr, "blend_mode", 0, "", ICON_NONE); uiItemPointerR(layout, ptr, "frame_property", &settings_ptr, "properties", NULL, ICON_NONE); diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c index cf3c0454e6b..5cc22b25f72 100644 --- a/source/blender/editors/space_node/drawnode.c +++ b/source/blender/editors/space_node/drawnode.c @@ -2225,6 +2225,39 @@ static void node_composit_buts_trackpos(uiLayout *layout, bContext *C, PointerRN } } +static void node_composit_buts_planetrackdeform(uiLayout *layout, bContext *C, PointerRNA *ptr) +{ + bNode *node = ptr->data; + + uiTemplateID(layout, C, ptr, "clip", NULL, "CLIP_OT_open", NULL); + + if (node->id) { + MovieClip *clip = (MovieClip *) node->id; + MovieTracking *tracking = &clip->tracking; + MovieTrackingObject *object; + uiLayout *col; + PointerRNA tracking_ptr; + NodeTrackPosData *data = node->storage; + + RNA_pointer_create(&clip->id, &RNA_MovieTracking, tracking, &tracking_ptr); + + col = uiLayoutColumn(layout, FALSE); + uiItemPointerR(col, ptr, "tracking_object", &tracking_ptr, "objects", "", ICON_OBJECT_DATA); + + object = BKE_tracking_object_get_named(tracking, data->tracking_object); + if (object) { + PointerRNA object_ptr; + + RNA_pointer_create(&clip->id, &RNA_MovieTrackingObject, object, &object_ptr); + + uiItemPointerR(col, ptr, "plane_track_name", &object_ptr, "plane_tracks", "", ICON_ANIM_DATA); + } + else { + uiItemR(layout, ptr, "plane_track_name", 0, "", ICON_ANIM_DATA); + } + } +} + /* only once called */ static void node_composit_set_butfunc(bNodeType *ntype) { @@ -2444,6 +2477,9 @@ static void node_composit_set_butfunc(bNodeType *ntype) case CMP_NODE_TRACKPOS: ntype->uifunc = node_composit_buts_trackpos; break; + case CMP_NODE_PLANETRACKDEFORM: + ntype->uifunc = node_composit_buts_planetrackdeform; + break; } } diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c index a014724af4a..1e9b681197c 100644 --- a/source/blender/editors/space_outliner/outliner_edit.c +++ b/source/blender/editors/space_outliner/outliner_edit.c @@ -1648,26 +1648,29 @@ void OUTLINER_OT_parent_drop(wmOperatorType *ot) RNA_def_enum(ot->srna, "type", prop_make_parent_types, 0, "Type", ""); } +static int outliner_parenting_poll(bContext *C) +{ + SpaceOops *soops = CTX_wm_space_outliner(C); + + if (soops) { + return ELEM4(soops->outlinevis, SO_ALL_SCENES, SO_CUR_SCENE, SO_VISIBLE, SO_GROUPS); + } + + return FALSE; +} + static int parent_clear_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { Main *bmain = CTX_data_main(C); - Scene *scene = NULL; Object *ob = NULL; SpaceOops *soops = CTX_wm_space_outliner(C); - TreeElement *te; char obname[MAX_ID_NAME]; RNA_string_get(op->ptr, "dragged_obj", obname); ob = (Object *)BKE_libblock_find_name(ID_OB, obname); /* search forwards to find the object */ - te = outliner_find_id(soops, &soops->tree, (ID *)ob); - /* then search backwards to get the scene */ - scene = (Scene *)outliner_search_back(soops, te, ID_SCE); - - if (scene == NULL) { - return OPERATOR_CANCELLED; - } + outliner_find_id(soops, &soops->tree, (ID *)ob); ED_object_parent_clear(ob, RNA_enum_get(op->ptr, "type")); @@ -1687,7 +1690,7 @@ void OUTLINER_OT_parent_clear(wmOperatorType *ot) /* api callbacks */ ot->invoke = parent_clear_invoke; - ot->poll = ED_operator_outliner_active; + ot->poll = outliner_parenting_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; diff --git a/source/blender/editors/space_outliner/space_outliner.c b/source/blender/editors/space_outliner/space_outliner.c index 00476cd467d..874852ee320 100644 --- a/source/blender/editors/space_outliner/space_outliner.c +++ b/source/blender/editors/space_outliner/space_outliner.c @@ -144,6 +144,10 @@ static int outliner_parent_clear_poll(bContext *C, wmDrag *drag, const wmEvent * UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]); + if (!ELEM4(soops->outlinevis, SO_ALL_SCENES, SO_CUR_SCENE, SO_VISIBLE, SO_GROUPS)) { + return FALSE; + } + if (drag->type == WM_DRAG_ID) { ID *id = (ID *)drag->poin; if (GS(id->name) == ID_OB) { diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index ed466186d63..6d801b86685 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -1324,12 +1324,6 @@ int transformEvent(TransInfo *t, const wmEvent *event) t->redraw |= TREDRAW_HARD; } break; -// case LEFTMOUSE: -// case RIGHTMOUSE: -// if (WM_modal_tweak_exit(event, t->event_type)) -//// if (t->options & CTX_TWEAK) -// t->state = TRANS_CONFIRM; -// break; case LEFTALTKEY: case RIGHTALTKEY: if (ELEM(t->spacetype, SPACE_SEQ, SPACE_VIEW3D)) { @@ -1374,7 +1368,7 @@ int calculateTransformCenter(bContext *C, int centerMode, float cent3d[3], int c t->state = TRANS_RUNNING; /* avoid calculating PET */ - t->options = CTX_NONE | CTX_NO_PET; + t->options = CTX_NO_PET; t->mode = TFM_DUMMY; @@ -3011,7 +3005,12 @@ static void ElementResize(TransInfo *t, TransData *td, float mat[3][3]) copy_v3_v3(center, td->center); } else if (t->options & CTX_MOVIECLIP) { - copy_v3_v3(center, td->center); + if (td->flag & TD_INDIVIDUAL_SCALE) { + copy_v3_v3(center, td->center); + } + else { + copy_v3_v3(center, t->center); + } } else { copy_v3_v3(center, t->center); diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h index 4a1c4203a43..4954f861934 100644 --- a/source/blender/editors/transform/transform.h +++ b/source/blender/editors/transform/transform.h @@ -455,7 +455,7 @@ typedef struct TransInfo { #define TD_USEQUAT (1 << 3) #define TD_NOTCONNECTED (1 << 4) #define TD_SINGLESIZE (1 << 5) /* used for scaling of MetaElem->rad */ -/*#define TD_TIMEONLY (1 << 8) */ /*UNUSED*/ +#define TD_INDIVIDUAL_SCALE (1 << 8) /* Scale relative to individual element center */ #define TD_NOCENTER (1 << 9) #define TD_NO_EXT (1 << 10) /* ext abused for particle key timing */ #define TD_SKIP (1 << 11) /* don't transform this data */ diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c index cb2cb801b50..01605003d7b 100644 --- a/source/blender/editors/transform/transform_conversions.c +++ b/source/blender/editors/transform/transform_conversions.c @@ -5959,7 +5959,8 @@ static void createTransNodeData(bContext *UNUSED(C), TransInfo *t) enum transDataTracking_Mode { transDataTracking_ModeTracks = 0, - transDataTracking_ModeCurves = 1 + transDataTracking_ModeCurves = 1, + transDataTracking_ModePlaneTracks = 2, }; typedef struct TransDataTracking { @@ -5978,6 +5979,9 @@ typedef struct TransDataTracking { /* marker transformation from curves editor */ float *prev_pos, scale; short coord; + + MovieTrackingTrack *track; + MovieTrackingPlaneTrack *plane_track; } TransDataTracking; static void markerToTransDataInit(TransData *td, TransData2D *td2d, TransDataTracking *tdt, @@ -6008,6 +6012,7 @@ static void markerToTransDataInit(TransData *td, TransData2D *td2d, TransDataTra tdt->markersnr = track->markersnr; tdt->markers = track->markers; + tdt->track = track; if (rel) { if (!anchor) { @@ -6026,6 +6031,7 @@ static void markerToTransDataInit(TransData *td, TransData2D *td2d, TransDataTra copy_v3_v3(td->iloc, td->loc); //copy_v3_v3(td->center, td->loc); + td->flag |= TD_INDIVIDUAL_SCALE; td->center[0] = marker->pos[0] * aspx; td->center[1] = marker->pos[1] * aspy; @@ -6076,6 +6082,52 @@ static void trackToTransData(const int framenr, TransData *td, TransData2D *td2d } } +static void planeMarkerToTransDataInit(TransData *td, TransData2D *td2d, TransDataTracking *tdt, + MovieTrackingPlaneTrack *plane_track, float corner[2], + float aspx, float aspy) +{ + tdt->mode = transDataTracking_ModePlaneTracks; + tdt->plane_track = plane_track; + + td2d->loc[0] = corner[0] * aspx; /* hold original location */ + td2d->loc[1] = corner[1] * aspy; + + td2d->loc2d = corner; /* current location */ + td2d->loc[2] = 0.0f; + + td->flag = 0; + td->loc = td2d->loc; + copy_v3_v3(td->iloc, td->loc); + copy_v3_v3(td->center, td->loc); + + memset(td->axismtx, 0, sizeof(td->axismtx)); + td->axismtx[2][2] = 1.0f; + + td->ext = NULL; + td->val = NULL; + + td->flag |= TD_SELECTED; + td->dist = 0.0; + + unit_m3(td->mtx); + unit_m3(td->smtx); +} + +static void planeTrackToTransData(const int framenr, TransData *td, TransData2D *td2d, + TransDataTracking *tdt, MovieTrackingPlaneTrack *plane_track, + float aspx, float aspy) +{ + MovieTrackingPlaneMarker *plane_marker = BKE_tracking_plane_marker_ensure(plane_track, framenr); + int i; + + tdt->flag = plane_marker->flag; + plane_marker->flag &= ~PLANE_MARKER_TRACKED; + + for (i = 0; i < 4; i++) { + planeMarkerToTransDataInit(td++, td2d++, tdt++, plane_track, plane_marker->corners[i], aspx, aspy); + } +} + static void transDataTrackingFree(TransInfo *t) { TransDataTracking *tdt = t->customData; @@ -6096,7 +6148,9 @@ static void createTransTrackingTracksData(bContext *C, TransInfo *t) SpaceClip *sc = CTX_wm_space_clip(C); MovieClip *clip = ED_space_clip_get_clip(sc); ListBase *tracksbase = BKE_tracking_get_active_tracks(&clip->tracking); + ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(&clip->tracking); MovieTrackingTrack *track; + MovieTrackingPlaneTrack *plane_track; TransDataTracking *tdt; int framenr = ED_space_clip_get_clip_frame_number(sc); float aspx, aspy; @@ -6122,6 +6176,15 @@ static void createTransTrackingTracksData(bContext *C, TransInfo *t) track = track->next; } + for (plane_track = plane_tracks_base->first; + plane_track; + plane_track = plane_track->next) + { + if (plane_track->flag & SELECT) { + t->total += 4; + } + } + if (t->total == 0) return; @@ -6165,11 +6228,23 @@ static void createTransTrackingTracksData(bContext *C, TransInfo *t) track = track->next; } + + for (plane_track = plane_tracks_base->first; + plane_track; + plane_track = plane_track->next) + { + if (plane_track->flag & SELECT) { + planeTrackToTransData(framenr, td, td2d, tdt, plane_track, aspx, aspy); + td += 4; + td2d += 4; + tdt += 4; + } + } } static void markerToTransCurveDataInit(TransData *td, TransData2D *td2d, TransDataTracking *tdt, - MovieTrackingMarker *marker, MovieTrackingMarker *prev_marker, - short coord, float size) + MovieTrackingTrack *track, MovieTrackingMarker *marker, + MovieTrackingMarker *prev_marker, short coord, float size) { float frames_delta = (marker->framenr - prev_marker->framenr); @@ -6180,6 +6255,7 @@ static void markerToTransCurveDataInit(TransData *td, TransData2D *td2d, TransDa tdt->coord = coord; tdt->scale = 1.0f / size * frames_delta; tdt->prev_pos = prev_marker->pos; + tdt->track = track; /* calculate values depending on marker's speed */ td2d->loc[0] = marker->framenr; @@ -6265,14 +6341,14 @@ static void createTransTrackingCurvesData(bContext *C, TransInfo *t) continue; if (marker->flag & MARKER_GRAPH_SEL_X) { - markerToTransCurveDataInit(td, td2d, tdt, marker, &track->markers[i - 1], 0, width); + markerToTransCurveDataInit(td, td2d, tdt, track, marker, &track->markers[i - 1], 0, width); td += 1; td2d += 1; tdt += 1; } if (marker->flag & MARKER_GRAPH_SEL_Y) { - markerToTransCurveDataInit(td, td2d, tdt, marker, &track->markers[i - 1], 1, height); + markerToTransCurveDataInit(td, td2d, tdt, track, marker, &track->markers[i - 1], 1, height); td += 1; td2d += 1; @@ -6313,57 +6389,54 @@ static void createTransTrackingData(bContext *C, TransInfo *t) static void cancelTransTracking(TransInfo *t) { - TransDataTracking *tdt = t->customData; SpaceClip *sc = t->sa->spacedata.first; - MovieClip *clip = ED_space_clip_get_clip(sc); - ListBase *tracksbase = BKE_tracking_get_active_tracks(&clip->tracking); - MovieTrackingTrack *track; - MovieTrackingMarker *marker; - int a, framenr = ED_space_clip_get_clip_frame_number(sc); + int i, framenr = ED_space_clip_get_clip_frame_number(sc); - if (tdt->mode == transDataTracking_ModeTracks) { - track = tracksbase->first; - while (track) { - if (TRACK_VIEW_SELECTED(sc, track) && (track->flag & TRACK_LOCKED) == 0) { - marker = BKE_tracking_marker_get(track, framenr); - marker->flag = tdt->flag; + i = 0; + while (i < t->total) { + TransDataTracking *tdt = (TransDataTracking *) t->customData + i; - tdt++; + if (tdt->mode == transDataTracking_ModeTracks) { + MovieTrackingTrack *track = tdt->track; + MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr); - if (track->flag & SELECT) - tdt++; + marker->flag = tdt->flag; - if (track->pat_flag & SELECT) - tdt += 2; + if (track->flag & SELECT) + i++; - if (track->search_flag & SELECT) - tdt += 2; - } + if (track->pat_flag & SELECT) + i += 4; - track = track->next; + if (track->search_flag & SELECT) + i += 2; } - } - else if (tdt->mode == transDataTracking_ModeCurves) { - MovieTrackingMarker *prev_marker; + else if (tdt->mode == transDataTracking_ModeCurves) { + MovieTrackingTrack *track = tdt->track; + MovieTrackingMarker *marker, *prev_marker; + int a; - track = tracksbase->first; - while (track) { - if (TRACK_VIEW_SELECTED(sc, track) && (track->flag & TRACK_LOCKED) == 0) { - for (a = 1; a < track->markersnr; a++) { - marker = &track->markers[a]; - prev_marker = &track->markers[a - 1]; + for (a = 1; a < track->markersnr; a++) { + marker = &track->markers[a]; + prev_marker = &track->markers[a - 1]; - if ((marker->flag & MARKER_DISABLED) || (prev_marker->flag & MARKER_DISABLED)) - continue; + if ((marker->flag & MARKER_DISABLED) || (prev_marker->flag & MARKER_DISABLED)) + continue; - if (marker->flag & (MARKER_GRAPH_SEL_X | MARKER_GRAPH_SEL_Y)) { - marker->flag = tdt->flag; - } + if (marker->flag & (MARKER_GRAPH_SEL_X | MARKER_GRAPH_SEL_Y)) { + marker->flag = tdt->flag; } } + } + else if (tdt->mode == transDataTracking_ModePlaneTracks) { + MovieTrackingPlaneTrack *plane_track = tdt->plane_track; + MovieTrackingPlaneMarker *plane_marker = BKE_tracking_plane_marker_get(plane_track, framenr); - track = track->next; + plane_marker->flag = tdt->flag; + i += 3; } + + i++; } } @@ -6432,6 +6505,10 @@ void flushTransTracking(TransInfo *t) else if (tdt->mode == transDataTracking_ModeCurves) { td2d->loc2d[tdt->coord] = tdt->prev_pos[tdt->coord] + td2d->loc[1] * tdt->scale; } + else if (tdt->mode == transDataTracking_ModePlaneTracks) { + td2d->loc2d[0] = td2d->loc[0] / aspx; + td2d->loc2d[1] = td2d->loc[1] / aspy; + } } } @@ -6668,10 +6745,6 @@ void createTransData(bContext *C, TransInfo *t) sort_trans_data_dist(t); } } - else if (t->options == CTX_BMESH) { - // TRANSFORM_FIX_ME - //createTransBMeshVerts(t, G.editBMesh->bm, G.editBMesh->td); - } else if (t->spacetype == SPACE_IMAGE) { t->flag |= T_POINTS | T_2D_EDIT; if (t->options & CTX_MASK) { diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c index cb0a0530036..4c7ac4193b3 100644 --- a/source/blender/editors/transform/transform_generics.c +++ b/source/blender/editors/transform/transform_generics.c @@ -659,7 +659,9 @@ static void recalcData_spaceclip(TransInfo *t) if (ED_space_clip_check_show_trackedit(sc)) { MovieClip *clip = ED_space_clip_get_clip(sc); ListBase *tracksbase = BKE_tracking_get_active_tracks(&clip->tracking); + ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(&clip->tracking); MovieTrackingTrack *track; + MovieTrackingPlaneTrack *plane_track; int framenr = ED_space_clip_get_clip_frame_number(sc); flushTransTracking(t); @@ -690,6 +692,15 @@ static void recalcData_spaceclip(TransInfo *t) track = track->next; } + for (plane_track = plane_tracks_base->first; + plane_track; + plane_track = plane_track->next) + { + if (plane_track->flag & SELECT) { + BKE_tracking_track_plane_from_existing_motion(plane_track, framenr); + } + } + DAG_id_tag_update(&clip->id, 0); } else if (t->options & CTX_MASK) { diff --git a/source/blender/makesdna/DNA_actuator_types.h b/source/blender/makesdna/DNA_actuator_types.h index 1495ba1b1a5..f4e2ff43fc5 100644 --- a/source/blender/makesdna/DNA_actuator_types.h +++ b/source/blender/makesdna/DNA_actuator_types.h @@ -59,7 +59,7 @@ typedef struct bActionActuator { short layer; /* Animation layer */ short end_reset; /* Ending the actuator (negative pulse) wont reset the the action to its starting frame */ short strideaxis; /* Displacement axis */ - short pad; + short blend_mode; /* Layer blending mode */ float stridelength; /* Displacement incurred by cycle */ // not in use float layer_weight; /* How much of the previous layer to use for blending. (<0 = disable, 0 = add mode) */ } bActionActuator; @@ -341,6 +341,10 @@ typedef struct bActuator { #define ACT_ACTION_FROM_PROP 6 #define ACT_ACTION_MOTION 7 +/* actionactuator->blend_mode */ +#define ACT_ACTION_BLEND 0 +#define ACT_ACTION_ADD 1 + /* ipoactuator->type */ #define ACT_IPO_PLAY 0 #define ACT_IPO_PINGPONG 1 diff --git a/source/blender/makesdna/DNA_mask_types.h b/source/blender/makesdna/DNA_mask_types.h index 1b6b802f2de..1b1c912d179 100644 --- a/source/blender/makesdna/DNA_mask_types.h +++ b/source/blender/makesdna/DNA_mask_types.h @@ -58,15 +58,18 @@ typedef struct Mask { typedef struct MaskParent { // int flag; /* parenting flags */ /* not used */ - int pad; int id_type; /* type of parenting */ + int type; /* type of parenting */ ID *id; /* ID block of entity to which mask/spline is parented to * in case of parenting to movie tracking data set to MovieClip datablock */ char parent[64]; /* entity of parent to which parenting happened * in case of parenting to movie tracking data contains name of layer */ char sub_parent[64]; /* sub-entity of parent to which parenting happened * in case of parenting to movie tracking data contains name of track */ - float parent_orig[2]; /* track location at the moment of parenting */ + float parent_orig[2]; /* track location at the moment of parenting, + stored in mask space*/ + + float parent_corners_orig[4][2]; /* Original corners of plane track at the moment of parenting */ } MaskParent; typedef struct MaskSplinePointUW { @@ -141,6 +144,12 @@ typedef struct MaskLayer { /* MaskParent->flag */ /* #define MASK_PARENT_ACTIVE (1 << 0) */ /* UNUSED */ +/* MaskParent->type */ +enum { + MASK_PARENT_POINT_TRACK = 0, /* parenting happens to point track */ + MASK_PARENT_PLANE_TRACK = 1, /* parenting happens to plane track */ +}; + /* MaskSpline->flag */ /* reserve (1 << 0) for SELECT */ enum { diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index 9ff4392242e..109cdf5f1a1 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -827,6 +827,10 @@ typedef struct NodeTranslateData { char pad[6]; } NodeTranslateData; +typedef struct NodePlaneTrackDeformData { + char tracking_object[64]; + char plane_track_name[64]; +} NodePlaneTrackDeformData; typedef struct NodeShaderScript { int mode; diff --git a/source/blender/makesdna/DNA_tracking_types.h b/source/blender/makesdna/DNA_tracking_types.h index 04cd69bc5ae..f81ac4dab06 100644 --- a/source/blender/makesdna/DNA_tracking_types.h +++ b/source/blender/makesdna/DNA_tracking_types.h @@ -144,6 +144,44 @@ typedef struct MovieTrackingTrack { struct bGPdata *gpd; /* grease-pencil data */ } MovieTrackingTrack; +typedef struct MovieTrackingPlaneMarker { + /* Corners of the plane in the following order: + * + * Y + * ^ + * | (3) --- (2) + * | | | + * | | | + * | | | + * | (0) --- (1) + * +-------------> X + * + * The coordinates are stored in frame normalized coordinates. + */ + float corners[4][2]; + + int framenr; /* Number of frame plane marker is associated with */ + int flag; /* Marker's flag (alive, ...) */ +} MovieTrackingPlaneMarker; + +typedef struct MovieTrackingPlaneTrack { + struct MovieTrackingPlaneTrack *next, *prev; + + char name[64]; /* MAX_NAME */ + + MovieTrackingTrack **point_tracks; /* Array of point tracks used to define this plane. + Each element is a pointer to MovieTrackingTrack. */ + int point_tracksnr, pad; /* Number of tracks in point_tracks array. */ + + MovieTrackingPlaneMarker *markers; /* Markers in the plane track */ + int markersnr; /* Count of markers in track (size of markers array) */ + + int flag; /* flags (selection, ...) */ + + /* Runtime data */ + int last_marker, pad2; /* Most recently used marker */ +} MovieTrackingPlaneTrack; + typedef struct MovieTrackingSettings { int flag; @@ -225,6 +263,7 @@ typedef struct MovieTrackingObject { float scale; /* scale of object solution in amera space */ ListBase tracks; /* list of tracks use to tracking this object */ + ListBase plane_tracks; /* list of plane tracks used by this object */ MovieTrackingReconstruction reconstruction; /* reconstruction data for this object */ /* reconstruction options */ @@ -280,9 +319,11 @@ typedef struct MovieTracking { MovieTrackingSettings settings; /* different tracking-related settings */ MovieTrackingCamera camera; /* camera intrinsics */ ListBase tracks; /* list of tracks used for camera object */ + ListBase plane_tracks; /* list of plane tracks used by camera object */ MovieTrackingReconstruction reconstruction; /* reconstruction data for camera object */ MovieTrackingStabilization stabilization; /* stabilization data */ - MovieTrackingTrack *act_track; /* active track */ + MovieTrackingTrack *act_track; /* active track */ + MovieTrackingPlaneTrack *act_plane_track; /* active plane track */ ListBase objects; int objectnr, tot_object; /* index of active object and total number of objects */ @@ -432,4 +473,16 @@ enum { TRACKING_COVERAGE_OK = 2 }; +/* MovieTrackingPlaneMarker->flag */ +enum { + PLANE_MARKER_DISABLED = (1 << 0), + PLANE_MARKER_TRACKED = (1 << 1), +}; + +/* MovieTrackingPlaneTrack->flag */ +enum { + PLANE_TRACK_HIDDEN = (1 << 1), + PLANE_TRACK_LOCKED = (1 << 2), +}; + #endif /* __DNA_TRACKING_TYPES_H__ */ diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c index 0489f85a37f..26febf217a6 100644 --- a/source/blender/makesrna/intern/rna_ID.c +++ b/source/blender/makesrna/intern/rna_ID.c @@ -347,15 +347,32 @@ int rna_IDMaterials_assign_int(PointerRNA *ptr, int key, const PointerRNA *assig static void rna_IDMaterials_append_id(ID *id, Material *ma) { - material_append_id(id, ma); + BKE_material_append_id(id, ma); WM_main_add_notifier(NC_OBJECT | ND_DRAW, id); WM_main_add_notifier(NC_OBJECT | ND_OB_SHADING, id); } -static Material *rna_IDMaterials_pop_id(ID *id, int index_i, int remove_material_slot) +static Material *rna_IDMaterials_pop_id(ID *id, ReportList *reports, int index_i, int remove_material_slot) { - Material *ma = material_pop_id(id, index_i, remove_material_slot); + Material *ma; + short *totcol = give_totcolp_id(id); + const short totcol_orig = *totcol; + if (index_i < 0) { + index_i += (*totcol); + } + + if ((index_i < 0) || (index_i >= (*totcol))) { + BKE_report(reports, RPT_ERROR, "Index out of range"); + return NULL; + } + + ma = BKE_material_pop_id(id, index_i, remove_material_slot); + + if (*totcol == totcol_orig) { + BKE_report(reports, RPT_ERROR, "No material to removed"); + return NULL; + } DAG_id_tag_update(id, OB_RECALC_DATA); WM_main_add_notifier(NC_OBJECT | ND_DRAW, id); @@ -364,6 +381,15 @@ static Material *rna_IDMaterials_pop_id(ID *id, int index_i, int remove_material return ma; } +static void rna_IDMaterials_clear_id(ID *id, int remove_material_slot) +{ + BKE_material_clear_id(id, remove_material_slot); + + DAG_id_tag_update(id, OB_RECALC_DATA); + WM_main_add_notifier(NC_OBJECT | ND_DRAW, id); + WM_main_add_notifier(NC_OBJECT | ND_OB_SHADING, id); +} + static void rna_Library_filepath_set(PointerRNA *ptr, const char *value) { Library *lib = (Library *)ptr->data; @@ -476,12 +502,16 @@ static void rna_def_ID_materials(BlenderRNA *brna) RNA_def_property_flag(parm, PROP_REQUIRED); func = RNA_def_function(srna, "pop", "rna_IDMaterials_pop_id"); + RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a material from the data block"); - parm = RNA_def_int(func, "index", 0, 0, MAXMAT, "", "Index of material to remove", 0, MAXMAT); - RNA_def_property_flag(parm, PROP_REQUIRED); + parm = RNA_def_int(func, "index", -1, -MAXMAT, MAXMAT, "", "Index of material to remove", 0, MAXMAT); RNA_def_boolean(func, "update_data", 0, "", "Update data by re-adjusting the material slots assigned"); parm = RNA_def_pointer(func, "material", "Material", "", "Material to remove"); RNA_def_function_return(func, parm); + + func = RNA_def_function(srna, "clear", "rna_IDMaterials_clear_id"); + RNA_def_function_ui_description(func, "Remove all materials from the data block"); + RNA_def_boolean(func, "update_data", 0, "", "Update data by re-adjusting the material slots assigned"); } static void rna_def_ID(BlenderRNA *brna) diff --git a/source/blender/makesrna/intern/rna_actuator.c b/source/blender/makesrna/intern/rna_actuator.c index 134c5bcbee4..99053714246 100644 --- a/source/blender/makesrna/intern/rna_actuator.c +++ b/source/blender/makesrna/intern/rna_actuator.c @@ -593,6 +593,12 @@ static void rna_def_action_actuator(BlenderRNA *brna) {0, NULL, 0, NULL, NULL} }; + static EnumPropertyItem prop_blend_items[] = { + {ACT_ACTION_BLEND, "BLEND", 0, "Blend", ""}, + {ACT_ACTION_ADD, "ADD", 0, "Add", ""}, + {0, NULL, 0, NULL, NULL} + }; + srna = RNA_def_struct(brna, "ActionActuator", "Actuator"); RNA_def_struct_ui_text(srna, "Action Actuator", "Actuator to control the object movement"); RNA_def_struct_sdna_from(srna, "bActionActuator", "data"); @@ -656,7 +662,7 @@ static void rna_def_action_actuator(BlenderRNA *brna) prop = RNA_def_property(srna, "layer_weight", PROP_FLOAT, PROP_NONE); RNA_def_property_range(prop, 0.0, 1.0); RNA_def_property_ui_text(prop, "Layer Weight", - "How much of the previous layer to blend into this one (0 = add mode)"); + "How much of the previous layer to blend into this one"); RNA_def_property_update(prop, NC_LOGIC, NULL); prop = RNA_def_property(srna, "frame_property", PROP_STRING, PROP_NONE); @@ -691,6 +697,12 @@ static void rna_def_action_actuator(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Child", "Update Action on all children Objects as well"); RNA_def_property_update(prop, NC_LOGIC, NULL); + prop = RNA_def_property(srna, "blend_mode", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "blend_mode"); + RNA_def_property_enum_items(prop, prop_blend_items); + RNA_def_property_ui_text(prop, "Blend Mode", "Determines how this layer is blended with previous layers"); + RNA_def_property_update(prop, NC_LOGIC, NULL); + #ifdef __NLA_ACTION_BY_MOTION_ACTUATOR prop = RNA_def_property(srna, "stride_length", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "stridelength"); diff --git a/source/blender/makesrna/intern/rna_curve.c b/source/blender/makesrna/intern/rna_curve.c index 21bf2ec6719..9773e7a340b 100644 --- a/source/blender/makesrna/intern/rna_curve.c +++ b/source/blender/makesrna/intern/rna_curve.c @@ -568,6 +568,10 @@ static Nurb *rna_Curve_spline_new(Curve *cu, int type) nu->resolu = nu->resolv = 12; nu->flag = CU_SMOOTH; + if ((cu->flag & CU_3D) == 0) { + nu->flag |= CU_2D; + } + BLI_addtail(BKE_curve_nurbs_get(cu), nu); return nu; diff --git a/source/blender/makesrna/intern/rna_mask.c b/source/blender/makesrna/intern/rna_mask.c index 65e6b15d676..6a5fc393269 100644 --- a/source/blender/makesrna/intern/rna_mask.c +++ b/source/blender/makesrna/intern/rna_mask.c @@ -84,21 +84,33 @@ static void rna_Mask_update_parent(Main *bmain, Scene *scene, PointerRNA *ptr) MovieTrackingObject *object = BKE_tracking_object_get_named(tracking, parent->parent); if (object) { - MovieTrackingTrack *track = BKE_tracking_track_get_named(tracking, object, parent->sub_parent); + int clip_framenr = BKE_movieclip_remap_scene_to_clip_frame(clip, scene->r.cfra); - if (track) { - int clip_framenr = BKE_movieclip_remap_scene_to_clip_frame(clip, scene->r.cfra); - MovieTrackingMarker *marker = BKE_tracking_marker_get(track, clip_framenr); - float marker_pos_ofs[2], parmask_pos[2]; - MovieClipUser user = {0}; + if (parent->type == MASK_PARENT_POINT_TRACK) { + MovieTrackingTrack *track = BKE_tracking_track_get_named(tracking, object, parent->sub_parent); - BKE_movieclip_user_set_frame(&user, scene->r.cfra); + if (track) { + MovieTrackingMarker *marker = BKE_tracking_marker_get(track, clip_framenr); + float marker_pos_ofs[2], parmask_pos[2]; + MovieClipUser user = {0}; - add_v2_v2v2(marker_pos_ofs, marker->pos, track->offset); + BKE_movieclip_user_set_frame(&user, scene->r.cfra); - BKE_mask_coord_from_movieclip(clip, &user, parmask_pos, marker_pos_ofs); + add_v2_v2v2(marker_pos_ofs, marker->pos, track->offset); - copy_v2_v2(parent->parent_orig, parmask_pos); + BKE_mask_coord_from_movieclip(clip, &user, parmask_pos, marker_pos_ofs); + + copy_v2_v2(parent->parent_orig, parmask_pos); + } + } + else /* if (parent->type == MASK_PARENT_PLANE_TRACK) */ { + MovieTrackingPlaneTrack *plane_track = BKE_tracking_plane_track_get_named(tracking, object, parent->sub_parent); + if (plane_track) { + MovieTrackingPlaneMarker *plane_marker = BKE_tracking_plane_marker_get(plane_track, clip_framenr); + + memcpy(parent->parent_corners_orig, plane_marker->corners, sizeof(parent->parent_corners_orig)); + zero_v2(parent->parent_orig); + } } } } @@ -513,6 +525,11 @@ static void rna_MaskSpline_point_remove(ID *id, MaskSpline *spline, ReportList * {ID_MC, "MOVIECLIP", ICON_SEQUENCE, "Movie Clip", ""}, {0, NULL, 0, NULL, NULL}}; + static EnumPropertyItem parent_type_items[] = { + {MASK_PARENT_POINT_TRACK, "POINT_TRACK", 0, "Point Track", ""}, + {MASK_PARENT_PLANE_TRACK, "PLANE_TRACK", 0, "Plane Track", ""}, + {0, NULL, 0, NULL, NULL}}; + srna = RNA_def_struct(brna, "MaskParent", NULL); RNA_def_struct_ui_text(srna, "Mask Parent", "Parenting settings for masking element"); @@ -535,6 +552,12 @@ static void rna_MaskSpline_point_remove(ID *id, MaskSpline *spline, ReportList * RNA_def_property_ui_text(prop, "ID Type", "Type of ID-block that can be used"); RNA_def_property_update(prop, 0, "rna_Mask_update_parent"); + /* type */ + prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, parent_type_items); + RNA_def_property_ui_text(prop, "Parent Type", "Parent Type"); + RNA_def_property_update(prop, 0, "rna_Mask_update_parent"); + /* parent */ prop = RNA_def_property(srna, "parent", PROP_STRING, PROP_NONE); RNA_def_property_ui_text(prop, "Parent", "Name of parent object in specified data block to which parenting happens"); diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index 535c279c02f..3b594ab0961 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -5919,6 +5919,29 @@ static void def_cmp_translate(StructRNA *srna) RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } +static void def_cmp_planetrackdeform(StructRNA *srna) +{ + PropertyRNA *prop; + + prop = RNA_def_property(srna, "clip", PROP_POINTER, PROP_NONE); + RNA_def_property_pointer_sdna(prop, NULL, "id"); + RNA_def_property_struct_type(prop, "MovieClip"); + RNA_def_property_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, "Movie Clip", ""); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); + + RNA_def_struct_sdna_from(srna, "NodePlaneTrackDeformData", "storage"); + + prop = RNA_def_property(srna, "tracking_object", PROP_STRING, PROP_NONE); + RNA_def_property_string_sdna(prop, NULL, "tracking_object"); + RNA_def_property_ui_text(prop, "Tracking Object", ""); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); + + prop = RNA_def_property(srna, "plane_track_name", PROP_STRING, PROP_NONE); + RNA_def_property_string_sdna(prop, NULL, "plane_track_name"); + RNA_def_property_ui_text(prop, "Plane Track", ""); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); +} /* -- Texture Nodes --------------------------------------------------------- */ diff --git a/source/blender/makesrna/intern/rna_tracking.c b/source/blender/makesrna/intern/rna_tracking.c index 4c47bbf93a6..1026a2c7772 100644 --- a/source/blender/makesrna/intern/rna_tracking.c +++ b/source/blender/makesrna/intern/rna_tracking.c @@ -95,6 +95,13 @@ static void rna_trackingTracks_begin(CollectionPropertyIterator *iter, PointerRN rna_iterator_listbase_begin(iter, &clip->tracking.tracks, NULL); } +static void rna_trackingPlaneTracks_begin(CollectionPropertyIterator *iter, PointerRNA *ptr) +{ + MovieClip *clip = (MovieClip *)ptr->id.data; + + rna_iterator_listbase_begin(iter, &clip->tracking.plane_tracks, NULL); +} + static void rna_trackingObjects_begin(CollectionPropertyIterator *iter, PointerRNA *ptr) { MovieClip *clip = (MovieClip *)ptr->id.data; @@ -146,6 +153,27 @@ static void rna_tracking_active_track_set(PointerRNA *ptr, PointerRNA value) clip->tracking.act_track = NULL; } +static PointerRNA rna_tracking_active_plane_track_get(PointerRNA *ptr) +{ + MovieClip *clip = (MovieClip *)ptr->id.data; + MovieTrackingPlaneTrack *act_plane_track = BKE_tracking_plane_track_get_active(&clip->tracking); + + return rna_pointer_inherit_refine(ptr, &RNA_MovieTrackingPlaneTrack, act_plane_track); +} + +static void rna_tracking_active_plane_track_set(PointerRNA *ptr, PointerRNA value) +{ + MovieClip *clip = (MovieClip *)ptr->id.data; + MovieTrackingPlaneTrack *plane_track = (MovieTrackingPlaneTrack *) value.data; + ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(&clip->tracking); + int index = BLI_findindex(plane_tracks_base, plane_track); + + if (index >= 0) + clip->tracking.act_plane_track = plane_track; + else + clip->tracking.act_plane_track = NULL; +} + static void rna_trackingTrack_name_set(PointerRNA *ptr, const char *value) { MovieClip *clip = (MovieClip *)ptr->id.data; @@ -197,6 +225,71 @@ static void rna_trackingTrack_select_set(PointerRNA *ptr, int value) } } +static void rna_trackingPlaneMarker_frame_set(PointerRNA *ptr, int value) +{ + MovieClip *clip = (MovieClip *) ptr->id.data; + MovieTracking *tracking = &clip->tracking; + MovieTrackingPlaneTrack *plane_track; + MovieTrackingPlaneMarker *plane_marker = (MovieTrackingPlaneMarker *) ptr->data; + + /* TODO(sergey): Need to support editing markers from object's tracks */ + + plane_track = tracking->plane_tracks.first; + while (plane_track) { + if (plane_marker >= plane_track->markers && + plane_marker < plane_track->markers + plane_track->markersnr) + { + break; + } + + plane_track = plane_track->next; + } + + if (plane_track) { + MovieTrackingPlaneMarker new_plane_marker = *plane_marker; + new_plane_marker.framenr = value; + + BKE_tracking_plane_marker_delete(plane_track, plane_marker->framenr); + BKE_tracking_plane_marker_insert(plane_track, &new_plane_marker); + } +} + +static char *rna_trackingPlaneTrack_path(PointerRNA *ptr) +{ + MovieTrackingPlaneTrack *plane_track = (MovieTrackingPlaneTrack *)ptr->data; + char name_esc[sizeof(plane_track->name) * 2]; + BLI_strescape(name_esc, plane_track->name, sizeof(name_esc)); + return BLI_sprintfN("tracking.plane_tracks[\"%s\"]", name_esc); +} + +static void rna_trackingPlaneTrack_name_set(PointerRNA *ptr, const char *value) +{ + MovieClip *clip = (MovieClip *)ptr->id.data; + MovieTracking *tracking = &clip->tracking; + MovieTrackingPlaneTrack *plane_track = (MovieTrackingPlaneTrack *)ptr->data; + ListBase *plane_tracks_base = &tracking->plane_tracks; + + BLI_strncpy(plane_track->name, value, sizeof(plane_track->name)); + + /* TODO: it's a bit difficult to find list track came from knowing just + * movie clip ID and MovieTracking structure, so keep this naive + * search for a while */ + if (BLI_findindex(plane_tracks_base, plane_track) < 0) { + MovieTrackingObject *object = tracking->objects.first; + + while (object) { + if (BLI_findindex(&object->plane_tracks, plane_track)) { + plane_tracks_base = &object->plane_tracks; + break; + } + + object = object->next; + } + } + + BKE_tracking_plane_track_unique_name(plane_tracks_base, plane_track); +} + static char *rna_trackingCamera_path(PointerRNA *UNUSED(ptr)) { return BLI_sprintfN("tracking.camera"); @@ -294,6 +387,20 @@ static void rna_trackingObject_tracks_begin(CollectionPropertyIterator *iter, Po } } +static void rna_trackingObject_plane_tracks_begin(CollectionPropertyIterator *iter, PointerRNA *ptr) +{ + MovieTrackingObject *object = (MovieTrackingObject *)ptr->data; + + if (object->flag & TRACKING_OBJECT_CAMERA) { + MovieClip *clip = (MovieClip *)ptr->id.data; + + rna_iterator_listbase_begin(iter, &clip->tracking.plane_tracks, NULL); + } + else { + rna_iterator_listbase_begin(iter, &object->plane_tracks, NULL); + } +} + static PointerRNA rna_trackingObject_reconstruction_get(PointerRNA *ptr) { MovieTrackingObject *object = (MovieTrackingObject *)ptr->data; @@ -1188,6 +1295,83 @@ static void rna_def_trackingTrack(BlenderRNA *brna) RNA_def_property_update(prop, NC_MOVIECLIP | ND_DISPLAY, NULL); } +static void rna_def_trackingPlaneMarker(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + srna = RNA_def_struct(brna, "MovieTrackingPlaneMarker", NULL); + RNA_def_struct_ui_text(srna, "Movie Tracking Plane Marker Data", "Match-moving plane marker data for tracking"); + + /* frame */ + prop = RNA_def_property(srna, "frame", PROP_INT, PROP_NONE); + RNA_def_property_int_sdna(prop, NULL, "framenr"); + RNA_def_property_ui_text(prop, "Frame", "Frame number marker is keyframed on"); + RNA_def_property_int_funcs(prop, NULL, "rna_trackingPlaneMarker_frame_set", NULL); + RNA_def_property_update(prop, NC_MOVIECLIP | NA_EDITED, 0); + + /* Corners */ + prop = RNA_def_property(srna, "corners", PROP_FLOAT, PROP_MATRIX); + RNA_def_property_float_sdna(prop, NULL, "corners"); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + RNA_def_property_multi_array(prop, 2, rna_matrix_dimsize_4x2); + RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, RNA_TRANSLATION_PREC_DEFAULT); + RNA_def_property_ui_text(prop, "Corners", + "Array of coordinates which represents UI rectange corners in " + "frame normalized coordinates"); + RNA_def_property_update(prop, NC_MOVIECLIP | NA_EDITED, NULL); + + /* enable */ + prop = RNA_def_property(srna, "mute", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", PLANE_MARKER_DISABLED); + RNA_def_property_ui_text(prop, "Mode", "Is marker muted for current frame"); + RNA_def_property_update(prop, NC_MOVIECLIP | NA_EDITED, NULL); +} + +static void rna_def_trackingPlaneMarkers(BlenderRNA *brna, PropertyRNA *cprop) +{ + StructRNA *srna; + + RNA_def_property_srna(cprop, "MovieTrackingPlaneMarkers"); + srna = RNA_def_struct(brna, "MovieTrackingPlaneMarkers", NULL); + RNA_def_struct_sdna(srna, "MovieTrackingPlaneTrack"); + RNA_def_struct_ui_text(srna, "Movie Tracking Plane Markers", "Collection of markers for movie tracking plane track"); +} + +static void rna_def_trackingPlaneTrack(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + rna_def_trackingPlaneMarker(brna); + + srna = RNA_def_struct(brna, "MovieTrackingPlaneTrack", NULL); + RNA_def_struct_path_func(srna, "rna_trackingPlaneTrack_path"); + RNA_def_struct_ui_text(srna, "Movie tracking plane track data", "Match-moving plane track data for tracking"); + RNA_def_struct_ui_icon(srna, ICON_ANIM_DATA); + + /* name */ + prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE); + RNA_def_property_ui_text(prop, "Name", "Unique name of track"); + RNA_def_property_string_funcs(prop, NULL, NULL, "rna_trackingPlaneTrack_name_set"); + RNA_def_property_string_maxlength(prop, MAX_ID_NAME - 2); + RNA_def_property_update(prop, NC_MOVIECLIP | NA_EDITED, NULL); + RNA_def_struct_name_property(srna, prop); + + /* markers */ + prop = RNA_def_property(srna, "markers", PROP_COLLECTION, PROP_NONE); + RNA_def_property_struct_type(prop, "MovieTrackingPlaneMarker"); + RNA_def_property_collection_sdna(prop, NULL, "markers", "markersnr"); + RNA_def_property_ui_text(prop, "Markers", "Collection of markers in track"); + rna_def_trackingPlaneMarkers(brna, prop); + + /* select */ + prop = RNA_def_property(srna, "select", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", SELECT); + RNA_def_property_ui_text(prop, "Select", "Plane track is selected"); + RNA_def_property_update(prop, NC_MOVIECLIP | ND_DISPLAY, NULL); +} + static void rna_def_trackingStabilization(BlenderRNA *brna) { StructRNA *srna; @@ -1373,6 +1557,23 @@ static void rna_def_trackingTracks(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Active Track", "Active track in this tracking data object"); } +static void rna_def_trackingPlaneTracks(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + srna = RNA_def_struct(brna, "MovieTrackingPlaneTracks", NULL); + RNA_def_struct_sdna(srna, "MovieTracking"); + RNA_def_struct_ui_text(srna, "Movie Plane Tracks", "Collection of movie tracking plane tracks"); + + /* active plane track */ + prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE); + RNA_def_property_struct_type(prop, "MovieTrackingPlaneTrack"); + RNA_def_property_pointer_funcs(prop, "rna_tracking_active_plane_track_get", "rna_tracking_active_plane_track_set", NULL, NULL); + RNA_def_property_flag(prop, PROP_EDITABLE | PROP_NEVER_UNLINK); + RNA_def_property_ui_text(prop, "Active Plane Track", "Active plane track in this tracking data object"); +} + static void rna_def_trackingObjectTracks(BlenderRNA *brna) { StructRNA *srna; @@ -1400,6 +1601,23 @@ static void rna_def_trackingObjectTracks(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Active Track", "Active track in this tracking data object"); } +static void rna_def_trackingObjectPlaneTracks(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + srna = RNA_def_struct(brna, "MovieTrackingObjectPlaneTracks", NULL); + RNA_def_struct_sdna(srna, "MovieTrackingObject"); + RNA_def_struct_ui_text(srna, "Plane Tracks", "Collection of tracking plane tracks"); + + /* active track */ + prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE); + RNA_def_property_struct_type(prop, "MovieTrackingTrack"); + RNA_def_property_pointer_funcs(prop, "rna_tracking_active_plane_track_get", "rna_tracking_active_plane_track_set", NULL, NULL); + RNA_def_property_flag(prop, PROP_EDITABLE | PROP_NEVER_UNLINK); + RNA_def_property_ui_text(prop, "Active Track", "Active track in this tracking data object"); +} + static void rna_def_trackingObject(BlenderRNA *brna) { StructRNA *srna; @@ -1432,6 +1650,15 @@ static void rna_def_trackingObject(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Tracks", "Collection of tracks in this tracking data object"); RNA_def_property_srna(prop, "MovieTrackingObjectTracks"); + /* plane tracks */ + prop = RNA_def_property(srna, "plane_tracks", PROP_COLLECTION, PROP_NONE); + RNA_def_property_collection_funcs(prop, "rna_trackingObject_plane_tracks_begin", "rna_iterator_listbase_next", + "rna_iterator_listbase_end", "rna_iterator_listbase_get", + NULL, NULL, NULL, NULL); + RNA_def_property_struct_type(prop, "MovieTrackingPlaneTrack"); + RNA_def_property_ui_text(prop, "Plane Tracks", "Collection of plane tracks in this tracking data object"); + RNA_def_property_srna(prop, "MovieTrackingObjectPlaneTracks"); + /* reconstruction */ prop = RNA_def_property(srna, "reconstruction", PROP_POINTER, PROP_NONE); RNA_def_property_struct_type(prop, "MovieTrackingReconstruction"); @@ -1549,8 +1776,11 @@ static void rna_def_tracking(BlenderRNA *brna) rna_def_trackingSettings(brna); rna_def_trackingCamera(brna); rna_def_trackingTrack(brna); + rna_def_trackingPlaneTrack(brna); rna_def_trackingTracks(brna); + rna_def_trackingPlaneTracks(brna); rna_def_trackingObjectTracks(brna); + rna_def_trackingObjectPlaneTracks(brna); rna_def_trackingStabilization(brna); rna_def_trackingReconstruction(brna); rna_def_trackingObject(brna); @@ -1577,6 +1807,15 @@ static void rna_def_tracking(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Tracks", "Collection of tracks in this tracking data object"); RNA_def_property_srna(prop, "MovieTrackingTracks"); + /* tracks */ + prop = RNA_def_property(srna, "plane_tracks", PROP_COLLECTION, PROP_NONE); + RNA_def_property_collection_funcs(prop, "rna_trackingPlaneTracks_begin", "rna_iterator_listbase_next", + "rna_iterator_listbase_end", "rna_iterator_listbase_get", + NULL, NULL, NULL, NULL); + RNA_def_property_struct_type(prop, "MovieTrackingPlaneTrack"); + RNA_def_property_ui_text(prop, "Plane Tracks", "Collection of plane tracks in this tracking data object"); + RNA_def_property_srna(prop, "MovieTrackingPlaneTracks"); + /* stabilization */ prop = RNA_def_property(srna, "stabilization", PROP_POINTER, PROP_NONE); RNA_def_property_struct_type(prop, "MovieTrackingStabilization"); diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt index 64261246e3d..4ac75c15efe 100644 --- a/source/blender/nodes/CMakeLists.txt +++ b/source/blender/nodes/CMakeLists.txt @@ -92,6 +92,7 @@ set(SRC composite/nodes/node_composite_normal.c composite/nodes/node_composite_normalize.c composite/nodes/node_composite_outputFile.c + composite/nodes/node_composite_planetrackdeform.c composite/nodes/node_composite_premulkey.c composite/nodes/node_composite_rgb.c composite/nodes/node_composite_rotate.c diff --git a/source/blender/nodes/NOD_composite.h b/source/blender/nodes/NOD_composite.h index 626e7955b08..4320e0436ce 100644 --- a/source/blender/nodes/NOD_composite.h +++ b/source/blender/nodes/NOD_composite.h @@ -137,6 +137,7 @@ void register_node_type_cmp_bokehblur(void); void register_node_type_cmp_switch(void); void register_node_type_cmp_pixelate(void); void register_node_type_cmp_trackpos(void); +void register_node_type_cmp_planetrackdeform(void); void node_cmp_rlayers_force_hidden_passes(struct bNode *node); diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h index 0b526fcde0e..eeec40c911f 100644 --- a/source/blender/nodes/NOD_static_types.h +++ b/source/blender/nodes/NOD_static_types.h @@ -1,3 +1,4 @@ + /* * ***** BEGIN GPL LICENSE BLOCK ***** * @@ -200,6 +201,7 @@ DefNode( CompositorNode, CMP_NODE_KEYINGSCREEN, def_cmp_keyingscreen, "KEYIN DefNode( CompositorNode, CMP_NODE_KEYING, def_cmp_keying, "KEYING", Keying, "Keying", "" ) DefNode( CompositorNode, CMP_NODE_TRACKPOS, def_cmp_trackpos, "TRACKPOS", TrackPos, "Track Position", "" ) DefNode( CompositorNode, CMP_NODE_PIXELATE, 0, "PIXELATE", Pixelate, "Pixelate", "" ) +DefNode( CompositorNode, CMP_NODE_PLANETRACKDEFORM,def_cmp_planetrackdeform,"PLANETRACKDEFORM",PlaneTrackDeform,"Plane Track Deform","" ) DefNode( TextureNode, TEX_NODE_OUTPUT, def_tex_output, "OUTPUT", Output, "Output", "" ) DefNode( TextureNode, TEX_NODE_CHECKER, 0, "CHECKER", Checker, "Checker", "" ) diff --git a/source/blender/nodes/composite/nodes/node_composite_planetrackdeform.c b/source/blender/nodes/composite/nodes/node_composite_planetrackdeform.c new file mode 100644 index 00000000000..7a15d6364dc --- /dev/null +++ b/source/blender/nodes/composite/nodes/node_composite_planetrackdeform.c @@ -0,0 +1,64 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2013 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Blender Foundation, + * Sergey Sharybin + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/nodes/composite/nodes/node_composite_planetrackdeform.c + * \ingroup cmpnodes + */ + + +#include "node_composite_util.h" + +static bNodeSocketTemplate cmp_node_planetrackdeform_in[] = { + { SOCK_RGBA, 1, N_("Image"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE}, + { -1, 0, "" } +}; + +static bNodeSocketTemplate cmp_node_planetrackdeform_out[] = { + { SOCK_RGBA, 0, N_("Image")}, + { SOCK_FLOAT, 0, N_("Plane")}, + { -1, 0, "" } +}; + +static void init(bNodeTree *UNUSED(ntree), bNode *node) +{ + NodePlaneTrackDeformData *data = MEM_callocN(sizeof(NodePlaneTrackDeformData), "node plane track deform data"); + + node->storage = data; +} + +void register_node_type_cmp_planetrackdeform(void) +{ + static bNodeType ntype; + + cmp_node_type_base(&ntype, CMP_NODE_PLANETRACKDEFORM, "Plane Track Deform", NODE_CLASS_DISTORT, 0); + node_type_socket_templates(&ntype, cmp_node_planetrackdeform_in, cmp_node_planetrackdeform_out); + node_type_init(&ntype, init); + node_type_storage(&ntype, "NodePlaneTrackDeformData", node_free_standard_storage, node_copy_standard_storage); + + nodeRegisterType(&ntype); +} diff --git a/source/gameengine/Converter/BL_ActionActuator.cpp b/source/gameengine/Converter/BL_ActionActuator.cpp index 90383021c90..a28906254a1 100644 --- a/source/gameengine/Converter/BL_ActionActuator.cpp +++ b/source/gameengine/Converter/BL_ActionActuator.cpp @@ -66,6 +66,7 @@ BL_ActionActuator::BL_ActionActuator(SCA_IObject *gameobj, float endtime, struct bAction *action, short playtype, + short blend_mode, short blendin, short priority, short layer, @@ -88,6 +89,7 @@ BL_ActionActuator::BL_ActionActuator(SCA_IObject *gameobj, m_stridelength(stride), m_layer_weight(layer_weight), m_playtype(playtype), + m_blendmode(blend_mode), m_priority(priority), m_layer(layer), m_ipo_flags(ipo_flags), @@ -187,6 +189,7 @@ bool BL_ActionActuator::Update(double curtime, bool frame) bool bUseContinue = false; KX_GameObject *obj = (KX_GameObject*)GetParent(); short playtype = BL_Action::ACT_MODE_PLAY; + short blendmode = (m_blendmode == ACT_ACTION_ADD) ? BL_Action::ACT_BLEND_ADD : BL_Action::ACT_BLEND_BLEND; float start = m_startframe; float end = m_endframe; @@ -283,7 +286,7 @@ bool BL_ActionActuator::Update(double curtime, bool frame) ResetStartTime(curtime); } - if (obj->PlayAction(m_action->id.name+2, start, end, m_layer, m_priority, m_blendin, playtype, m_layer_weight, m_ipo_flags)) + if (obj->PlayAction(m_action->id.name+2, start, end, m_layer, m_priority, m_blendin, playtype, m_layer_weight, m_ipo_flags, 1.f, blendmode)) { m_flag |= ACT_FLAG_ACTIVE; if (bUseContinue) @@ -328,7 +331,7 @@ bool BL_ActionActuator::Update(double curtime, bool frame) // Convert into a play action and play back to the beginning end = start; start = obj->GetActionFrame(m_layer); - obj->PlayAction(m_action->id.name+2, start, end, m_layer, m_priority, 0, BL_Action::ACT_MODE_PLAY, m_layer_weight, m_ipo_flags); + obj->PlayAction(m_action->id.name+2, start, end, m_layer, m_priority, 0, BL_Action::ACT_MODE_PLAY, m_layer_weight, m_ipo_flags, 1.f, blendmode); m_flag |= ACT_FLAG_PLAY_END; break; diff --git a/source/gameengine/Converter/BL_ActionActuator.h b/source/gameengine/Converter/BL_ActionActuator.h index ce805c774ef..4579a21f554 100644 --- a/source/gameengine/Converter/BL_ActionActuator.h +++ b/source/gameengine/Converter/BL_ActionActuator.h @@ -48,6 +48,7 @@ public: float endtime, struct bAction *action, short playtype, + short blend_mode, short blendin, short priority, short layer, @@ -129,6 +130,7 @@ protected: float m_stridelength; float m_layer_weight; short m_playtype; + short m_blendmode; short m_priority; short m_layer; short m_ipo_flags; diff --git a/source/gameengine/Converter/BL_ArmatureObject.cpp b/source/gameengine/Converter/BL_ArmatureObject.cpp index 55d9decb333..d8ddb33ddc4 100644 --- a/source/gameengine/Converter/BL_ArmatureObject.cpp +++ b/source/gameengine/Converter/BL_ArmatureObject.cpp @@ -32,6 +32,7 @@ #include "BL_ArmatureObject.h" #include "BL_ActionActuator.h" +#include "BL_Action.h" #include "KX_BlenderSceneConverter.h" #include "MEM_guardedalloc.h" #include "BLI_blenlib.h" @@ -50,7 +51,6 @@ #include "DNA_armature_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" -#include "DNA_nla_types.h" #include "DNA_constraint_types.h" #include "KX_PythonSeq.h" #include "KX_PythonInit.h" @@ -137,25 +137,22 @@ void game_copy_pose(bPose **dst, bPose *src, int copy_constraint) /* Only allowed for Poses with identical channels */ -void game_blend_poses(bPose *dst, bPose *src, float srcweight/*, short mode*/) +void game_blend_poses(bPose *dst, bPose *src, float srcweight, short mode) { - short mode= ACTSTRIPMODE_BLEND; - bPoseChannel *dchan; const bPoseChannel *schan; bConstraint *dcon, *scon; float dstweight; int i; - switch (mode) { - case ACTSTRIPMODE_BLEND: - dstweight = 1.0F - srcweight; - break; - case ACTSTRIPMODE_ADD: - dstweight = 1.0F; - break; - default : - dstweight = 1.0F; + if (mode == BL_Action::ACT_BLEND_BLEND) + { + dstweight = 1.0f - srcweight; + } else if (mode == BL_Action::ACT_BLEND_ADD) + { + dstweight = 1.0f; + } else { + dstweight = 1.0f; } schan= (bPoseChannel *)src->chanbase.first; @@ -167,7 +164,7 @@ void game_blend_poses(bPose *dst, bPose *src, float srcweight/*, short mode*/) copy_qt_qt(dquat, dchan->quat); copy_qt_qt(squat, schan->quat); - if (mode==ACTSTRIPMODE_BLEND) + if (mode==BL_Action::ACT_BLEND_BLEND) interp_qt_qtqt(dchan->quat, dquat, squat, srcweight); else { mul_fac_qt_fl(squat, srcweight); diff --git a/source/gameengine/Converter/BL_ArmatureObject.h b/source/gameengine/Converter/BL_ArmatureObject.h index 445b9af1b10..81388355fc4 100644 --- a/source/gameengine/Converter/BL_ArmatureObject.h +++ b/source/gameengine/Converter/BL_ArmatureObject.h @@ -147,7 +147,7 @@ protected: }; /* Pose function specific to the game engine */ -void game_blend_poses(struct bPose *dst, struct bPose *src, float srcweight/*, short mode*/); /* was blend_poses */ +void game_blend_poses(struct bPose *dst, struct bPose *src, float srcweight, short mode); /* was blend_poses */ //void extract_pose_from_pose(struct bPose *pose, const struct bPose *src); void game_copy_pose(struct bPose **dst, struct bPose *src, int copy_con); void game_free_pose(struct bPose *pose); diff --git a/source/gameengine/Converter/KX_ConvertActuators.cpp b/source/gameengine/Converter/KX_ConvertActuators.cpp index 5b528972e00..27989983326 100644 --- a/source/gameengine/Converter/KX_ConvertActuators.cpp +++ b/source/gameengine/Converter/KX_ConvertActuators.cpp @@ -225,6 +225,7 @@ void BL_ConvertActuators(const char* maggiename, actact->end, actact->act, actact->type, // + 1, because Blender starts to count at zero, + actact->blend_mode, actact->blendin, actact->priority, actact->layer, diff --git a/source/gameengine/Ketsji/BL_Action.cpp b/source/gameengine/Ketsji/BL_Action.cpp index 9d189a6170e..6d9b22eed91 100644 --- a/source/gameengine/Ketsji/BL_Action.cpp +++ b/source/gameengine/Ketsji/BL_Action.cpp @@ -65,7 +65,8 @@ BL_Action::BL_Action(class KX_GameObject* gameobj) m_blendstart(0.f), m_speed(0.f), m_priority(0), - m_playmode(0), + m_playmode(ACT_MODE_PLAY), + m_blendmode(ACT_BLEND_BLEND), m_ipo_flags(0), m_done(true), m_calc_localtime(true) @@ -104,7 +105,8 @@ bool BL_Action::Play(const char* name, short play_mode, float layer_weight, short ipo_flags, - float playback_speed) + float playback_speed, + short blend_mode) { // Only start playing a new action if we're done, or if @@ -229,6 +231,7 @@ bool BL_Action::Play(const char* name, m_endframe = end; m_blendin = blendin; m_playmode = play_mode; + m_blendmode = blend_mode; m_endtime = 0.f; m_blendframe = 0.f; m_blendstart = 0.f; @@ -423,7 +426,7 @@ void BL_Action::Update(float curtime) float weight = 1.f - (m_blendframe/m_blendin); // Blend the poses - game_blend_poses(m_pose, m_blendinpose, weight); + game_blend_poses(m_pose, m_blendinpose, weight, ACT_BLEND_BLEND); } @@ -431,7 +434,7 @@ void BL_Action::Update(float curtime) if (m_layer_weight >= 0) { obj->GetMRDPose(&m_blendpose); - game_blend_poses(m_pose, m_blendpose, m_layer_weight); + game_blend_poses(m_pose, m_blendpose, m_layer_weight, m_blendmode); } obj->SetPose(m_pose); diff --git a/source/gameengine/Ketsji/BL_Action.h b/source/gameengine/Ketsji/BL_Action.h index e4088633e61..e9d09916517 100644 --- a/source/gameengine/Ketsji/BL_Action.h +++ b/source/gameengine/Ketsji/BL_Action.h @@ -34,7 +34,6 @@ #include "MEM_guardedalloc.h" #endif - class BL_Action { private: @@ -64,6 +63,7 @@ private: short m_priority; short m_playmode; + short m_blendmode; short m_ipo_flags; @@ -91,7 +91,8 @@ public: short play_mode, float layer_weight, short ipo_flags, - float playback_speed); + float playback_speed, + short blend_mode); /** * Stop playing the action */ @@ -114,7 +115,7 @@ public: void SetPlayMode(short play_mode); void SetTimes(float start, float end); - enum + enum { ACT_MODE_PLAY = 0, ACT_MODE_LOOP, @@ -124,6 +125,13 @@ public: enum { + ACT_BLEND_BLEND=0, + ACT_BLEND_ADD=1, + ACT_BLEND_MAX, + }; + + enum + { ACT_IPOFLAG_FORCE = 1, ACT_IPOFLAG_LOCAL = 2, ACT_IPOFLAG_ADD = 4, diff --git a/source/gameengine/Ketsji/BL_ActionManager.cpp b/source/gameengine/Ketsji/BL_ActionManager.cpp index e3402972ca6..2e882ceba74 100644 --- a/source/gameengine/Ketsji/BL_ActionManager.cpp +++ b/source/gameengine/Ketsji/BL_ActionManager.cpp @@ -25,6 +25,7 @@ */ #include "BL_ActionManager.h" +#include "BL_Action.h" BL_ActionManager::BL_ActionManager(class KX_GameObject *obj) { @@ -72,12 +73,13 @@ bool BL_ActionManager::PlayAction(const char* name, short play_mode, float layer_weight, short ipo_flags, - float playback_speed) + float playback_speed, + short blend_mode) { // Disable layer blending on the first layer if (layer == 0) layer_weight = -1.f; - return m_layers[layer]->Play(name, start, end, priority, blendin, play_mode, layer_weight, ipo_flags, playback_speed); + return m_layers[layer]->Play(name, start, end, priority, blendin, play_mode, layer_weight, ipo_flags, playback_speed, blend_mode); } void BL_ActionManager::StopAction(short layer) diff --git a/source/gameengine/Ketsji/BL_ActionManager.h b/source/gameengine/Ketsji/BL_ActionManager.h index 600e7b6621e..88aa241b6ce 100644 --- a/source/gameengine/Ketsji/BL_ActionManager.h +++ b/source/gameengine/Ketsji/BL_ActionManager.h @@ -27,10 +27,10 @@ #ifndef __BL_ACTIONMANAGER_H__ #define __BL_ACTIONMANAGER_H__ -#include "BL_Action.h" - #define MAX_ACTION_LAYERS 8 +class BL_Action; + /** * BL_ActionManager is responsible for handling a KX_GameObject's actions. */ @@ -52,7 +52,8 @@ public: short play_mode=0, float layer_weight=0.f, short ipo_flags=0, - float playback_speed=1.f); + float playback_speed=1.f, + short blend_mode=0); /** * Gets the current frame of an action */ diff --git a/source/gameengine/Ketsji/KX_Dome.cpp b/source/gameengine/Ketsji/KX_Dome.cpp index aa082c7ef19..85fa0b2b3ce 100644 --- a/source/gameengine/Ketsji/KX_Dome.cpp +++ b/source/gameengine/Ketsji/KX_Dome.cpp @@ -401,21 +401,21 @@ void KX_Dome::GLDrawWarpQuads(void) if (warp.nodes[i][j].i < 0 || warp.nodes[i+1][j].i < 0 || warp.nodes[i+1][j+1].i < 0 || warp.nodes[i][j+1].i < 0) continue; - glColor3f(warp.nodes[i][j].i, warp.nodes[i][j].i, warp.nodes[i][j].i); - glTexCoord2f((warp.nodes[i][j].u * uv_width), (warp.nodes[i][j].v * uv_height)); - glVertex3f(warp.nodes[i][j].x, warp.nodes[i][j].y,0.0); - - glColor3f(warp.nodes[i+1][j].i, warp.nodes[i+1][j].i, warp.nodes[i+1][j].i); - glTexCoord2f((warp.nodes[i+1][j].u * uv_width), (warp.nodes[i+1][j].v * uv_height)); - glVertex3f(warp.nodes[i+1][j].x, warp.nodes[i+1][j].y,0.0); + glColor3f(warp.nodes[i][j+1].i, warp.nodes[i][j+1].i, warp.nodes[i][j+1].i); + glTexCoord2f((warp.nodes[i][j+1].u * uv_width), (warp.nodes[i][j+1].v * uv_height)); + glVertex3f(warp.nodes[i][j+1].x, warp.nodes[i][j+1].y,0.0); glColor3f(warp.nodes[i+1][j+1].i, warp.nodes[i+1][j+1].i, warp.nodes[i+1][j+1].i); glTexCoord2f((warp.nodes[i+1][j+1].u * uv_width), (warp.nodes[i+1][j+1].v * uv_height)); glVertex3f(warp.nodes[i+1][j+1].x, warp.nodes[i+1][j+1].y,0.0); - glColor3f(warp.nodes[i][j+1].i, warp.nodes[i][j+1].i, warp.nodes[i][j+1].i); - glTexCoord2f((warp.nodes[i][j+1].u * uv_width), (warp.nodes[i][j+1].v * uv_height)); - glVertex3f(warp.nodes[i][j+1].x, warp.nodes[i][j+1].y,0.0); + glColor3f(warp.nodes[i+1][j].i, warp.nodes[i+1][j].i, warp.nodes[i+1][j].i); + glTexCoord2f((warp.nodes[i+1][j].u * uv_width), (warp.nodes[i+1][j].v * uv_height)); + glVertex3f(warp.nodes[i+1][j].x, warp.nodes[i+1][j].y,0.0); + + glColor3f(warp.nodes[i][j].i, warp.nodes[i][j].i, warp.nodes[i][j].i); + glTexCoord2f((warp.nodes[i][j].u * uv_width), (warp.nodes[i][j].v * uv_height)); + glVertex3f(warp.nodes[i][j].x, warp.nodes[i][j].y,0.0); } } glEnd(); diff --git a/source/gameengine/Ketsji/KX_GameObject.cpp b/source/gameengine/Ketsji/KX_GameObject.cpp index ec62ae63f0c..e0ec4983739 100644 --- a/source/gameengine/Ketsji/KX_GameObject.cpp +++ b/source/gameengine/Ketsji/KX_GameObject.cpp @@ -73,6 +73,7 @@ typedef unsigned long uint_ptr; #include "KX_ObstacleSimulation.h" #include "BL_ActionManager.h" +#include "BL_Action.h" #include "PyObjectPlus.h" /* python stuff */ @@ -429,9 +430,10 @@ bool KX_GameObject::PlayAction(const char* name, short play_mode, float layer_weight, short ipo_flags, - float playback_speed) + float playback_speed, + short blend_mode) { - return GetActionManager()->PlayAction(name, start, end, layer, priority, blendin, play_mode, layer_weight, ipo_flags, playback_speed); + return GetActionManager()->PlayAction(name, start, end, layer, priority, blendin, play_mode, layer_weight, ipo_flags, playback_speed, blend_mode); } void KX_GameObject::StopAction(short layer) @@ -3311,11 +3313,12 @@ KX_PYMETHODDEF_DOC(KX_GameObject, playAction, short layer=0, priority=0; short ipo_flags=0; short play_mode=0; + short blend_mode=0; - static const char *kwlist[] = {"name", "start_frame", "end_frame", "layer", "priority", "blendin", "play_mode", "layer_weight", "ipo_flags", "speed", NULL}; + static const char *kwlist[] = {"name", "start_frame", "end_frame", "layer", "priority", "blendin", "play_mode", "layer_weight", "ipo_flags", "speed", "blend_mode", NULL}; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "sff|hhfhfhf:playAction", const_cast<char**>(kwlist), - &name, &start, &end, &layer, &priority, &blendin, &play_mode, &layer_weight, &ipo_flags, &speed)) + if (!PyArg_ParseTupleAndKeywords(args, kwds, "sff|hhfhfhfh:playAction", const_cast<char**>(kwlist), + &name, &start, &end, &layer, &priority, &blendin, &play_mode, &layer_weight, &ipo_flags, &speed, &blend_mode)) return NULL; layer_check(layer, "playAction"); @@ -3323,7 +3326,13 @@ KX_PYMETHODDEF_DOC(KX_GameObject, playAction, if (play_mode < 0 || play_mode > BL_Action::ACT_MODE_MAX) { printf("KX_GameObject.playAction(): given play_mode (%d) is out of range (0 - %d), setting to ACT_MODE_PLAY", play_mode, BL_Action::ACT_MODE_MAX-1); - play_mode = BL_Action::ACT_MODE_MAX; + play_mode = BL_Action::ACT_MODE_PLAY; + } + + if (blend_mode < 0 || blend_mode > BL_Action::ACT_BLEND_MAX) + { + printf("KX_GameObject.playAction(): given blend_mode (%d) is out of range (0 - %d), setting to ACT_BLEND_BLEND", blend_mode, BL_Action::ACT_BLEND_MAX-1); + blend_mode = BL_Action::ACT_BLEND_BLEND; } if (layer_weight < 0.f || layer_weight > 1.f) @@ -3332,7 +3341,7 @@ KX_PYMETHODDEF_DOC(KX_GameObject, playAction, layer_weight = 0.f; } - PlayAction(name, start, end, layer, priority, blendin, play_mode, layer_weight, ipo_flags, speed); + PlayAction(name, start, end, layer, priority, blendin, play_mode, layer_weight, ipo_flags, speed, blend_mode); Py_RETURN_NONE; } diff --git a/source/gameengine/Ketsji/KX_GameObject.h b/source/gameengine/Ketsji/KX_GameObject.h index 13a79cebefb..5a3b9df74ee 100644 --- a/source/gameengine/Ketsji/KX_GameObject.h +++ b/source/gameengine/Ketsji/KX_GameObject.h @@ -255,7 +255,8 @@ public: short play_mode=0, float layer_weight=0.f, short ipo_flags=0, - float playback_speed=1.f); + float playback_speed=1.f, + short blend_mode=0); /** * Gets the current frame of an action diff --git a/source/gameengine/Ketsji/KX_PythonInit.cpp b/source/gameengine/Ketsji/KX_PythonInit.cpp index d8b4bf9e8bd..ae9cbbb2656 100644 --- a/source/gameengine/Ketsji/KX_PythonInit.cpp +++ b/source/gameengine/Ketsji/KX_PythonInit.cpp @@ -1820,6 +1820,10 @@ PyObject *initGameLogic(KX_KetsjiEngine *engine, KX_Scene* scene) // quick hack KX_MACRO_addTypesToDict(d, KX_ACTION_MODE_LOOP, BL_Action::ACT_MODE_LOOP); KX_MACRO_addTypesToDict(d, KX_ACTION_MODE_PING_PONG, BL_Action::ACT_MODE_PING_PONG); + /* BL_Action blend modes */ + KX_MACRO_addTypesToDict(d, KX_ACTION_BLEND_BLEND, BL_Action::ACT_BLEND_BLEND); + KX_MACRO_addTypesToDict(d, KX_ACTION_BLEND_ADD, BL_Action::ACT_BLEND_ADD); + // Check for errors if (PyErr_Occurred()) { diff --git a/source/gameengine/Ketsji/KX_SoundActuator.cpp b/source/gameengine/Ketsji/KX_SoundActuator.cpp index 5438ae5a97c..3a4b1d82946 100644 --- a/source/gameengine/Ketsji/KX_SoundActuator.cpp +++ b/source/gameengine/Ketsji/KX_SoundActuator.cpp @@ -109,7 +109,7 @@ void KX_SoundActuator::play() try { - m_handle = AUD_getDevice()->play(sound, 0); + m_handle = AUD_getDevice()->play(sound); } catch(AUD_Exception&) { |