diff options
author | Campbell Barton <ideasman42@gmail.com> | 2011-11-15 06:58:06 +0400 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2011-11-15 06:58:06 +0400 |
commit | e6e265b2b59e02cc7816a2ed43471eca8bca0a62 (patch) | |
tree | e312d2c2f6cb1aaf79148648e5725902ab23d34e /source/blender/blenkernel/intern | |
parent | e59ab6486f9e7285815671044b785c28365d5165 (diff) | |
parent | 3442c16c09b31a23f45b23be72e6eb5ba02c7bbf (diff) |
svn merge -r41779:41847 ^/trunk/blender
Diffstat (limited to 'source/blender/blenkernel/intern')
-rw-r--r-- | source/blender/blenkernel/intern/camera.c | 140 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/cdderivedmesh.c | 2 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/constraint.c | 3 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/dynamicpaint.c | 16 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/implicit.c | 2 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/mesh_validate.c | 2 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/object.c | 63 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/ocean.c | 1421 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/text.c | 47 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/texture.c | 52 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/tracking.c | 140 |
11 files changed, 1846 insertions, 42 deletions
diff --git a/source/blender/blenkernel/intern/camera.c b/source/blender/blenkernel/intern/camera.c index 145eb9363e9..6ba7a76dd5c 100644 --- a/source/blender/blenkernel/intern/camera.c +++ b/source/blender/blenkernel/intern/camera.c @@ -41,6 +41,7 @@ #include "BKE_animsys.h" #include "BKE_camera.h" +#include "BKE_object.h" #include "BKE_global.h" #include "BKE_library.h" #include "BKE_main.h" @@ -394,3 +395,142 @@ void camera_view_frame(Scene *scene, Camera *camera, float r_vec[4][3]) dummy_asp, dummy_shift, &dummy_drawsize, r_vec); } + +typedef struct CameraViewFrameData { + float frame_tx[4][3]; + float normal_tx[4][3]; + float dist_vals[4]; + unsigned int tot; +} CameraViewFrameData; + +static void camera_to_frame_view_cb(const float co[3], void *user_data) +{ + CameraViewFrameData *data= (CameraViewFrameData *)user_data; + unsigned int i; + + for (i= 0; i < 4; i++) { + float nd= -dist_to_plane_v3(co, data->frame_tx[i], data->normal_tx[i]); + if (nd < data->dist_vals[i]) { + data->dist_vals[i]= nd; + } + } + + data->tot++; +} + +/* dont move the camera, just yield the fit location */ +int camera_view_frame_fit_to_scene(Scene *scene, struct View3D *v3d, Object *camera_ob, float r_co[3]) +{ + float shift[2]; + float plane_tx[4][3]; + float rot_obmat[3][3]; + const float zero[3]= {0,0,0}; + CameraViewFrameData data_cb; + + unsigned int i; + + camera_view_frame(scene, camera_ob->data, data_cb.frame_tx); + + copy_m3_m4(rot_obmat, camera_ob->obmat); + normalize_m3(rot_obmat); + + for (i= 0; i < 4; i++) { + /* normalize so Z is always 1.0f*/ + mul_v3_fl(data_cb.frame_tx[i], 1.0f/data_cb.frame_tx[i][2]); + } + + /* get the shift back out of the frame */ + shift[0]= (data_cb.frame_tx[0][0] + + data_cb.frame_tx[1][0] + + data_cb.frame_tx[2][0] + + data_cb.frame_tx[3][0]) / 4.0f; + shift[1]= (data_cb.frame_tx[0][1] + + data_cb.frame_tx[1][1] + + data_cb.frame_tx[2][1] + + data_cb.frame_tx[3][1]) / 4.0f; + + for (i= 0; i < 4; i++) { + mul_m3_v3(rot_obmat, data_cb.frame_tx[i]); + } + + for (i= 0; i < 4; i++) { + normal_tri_v3(data_cb.normal_tx[i], + zero, data_cb.frame_tx[i], data_cb.frame_tx[(i + 1) % 4]); + } + + /* initialize callback data */ + data_cb.dist_vals[0]= + data_cb.dist_vals[1]= + data_cb.dist_vals[2]= + data_cb.dist_vals[3]= FLT_MAX; + data_cb.tot= 0; + /* run callback on all visible points */ + BKE_scene_foreach_display_point(scene, v3d, BA_SELECT, + camera_to_frame_view_cb, &data_cb); + + if (data_cb.tot <= 1) { + return FALSE; + } + else { + float plane_isect_1[3], plane_isect_1_no[3], plane_isect_1_other[3]; + float plane_isect_2[3], plane_isect_2_no[3], plane_isect_2_other[3]; + + float plane_isect_pt_1[3], plane_isect_pt_2[3]; + + /* apply the dist-from-plane's to the transformed plane points */ + for (i= 0; i < 4; i++) { + mul_v3_v3fl(plane_tx[i], data_cb.normal_tx[i], data_cb.dist_vals[i]); + } + + if ( (isect_plane_plane_v3(plane_isect_1, plane_isect_1_no, + plane_tx[0], data_cb.normal_tx[0], + plane_tx[2], data_cb.normal_tx[2]) == 0) || + (isect_plane_plane_v3(plane_isect_2, plane_isect_2_no, + plane_tx[1], data_cb.normal_tx[1], + plane_tx[3], data_cb.normal_tx[3]) == 0)) + { + /* this is very unlikely */ + return FALSE; + } + else { + + add_v3_v3v3(plane_isect_1_other, plane_isect_1, plane_isect_1_no); + add_v3_v3v3(plane_isect_2_other, plane_isect_2, plane_isect_2_no); + + if (isect_line_line_v3(plane_isect_1, plane_isect_1_other, + plane_isect_2, plane_isect_2_other, + plane_isect_pt_1, plane_isect_pt_2) == 0) + { + return FALSE; + } + else { + float cam_plane_no[3]= {0.0f, 0.0f, -1.0f}; + float plane_isect_delta[3]; + float plane_isect_delta_len; + + mul_m3_v3(rot_obmat, cam_plane_no); + + sub_v3_v3v3(plane_isect_delta, plane_isect_pt_2, plane_isect_pt_1); + plane_isect_delta_len= len_v3(plane_isect_delta); + + if (dot_v3v3(plane_isect_delta, cam_plane_no) > 0.0f) { + copy_v3_v3(r_co, plane_isect_pt_1); + + /* offset shift */ + normalize_v3(plane_isect_1_no); + madd_v3_v3fl(r_co, plane_isect_1_no, shift[1] * -plane_isect_delta_len); + } + else { + copy_v3_v3(r_co, plane_isect_pt_2); + + /* offset shift */ + normalize_v3(plane_isect_2_no); + madd_v3_v3fl(r_co, plane_isect_2_no, shift[0] * -plane_isect_delta_len); + } + + + return TRUE; + } + } + } +} diff --git a/source/blender/blenkernel/intern/cdderivedmesh.c b/source/blender/blenkernel/intern/cdderivedmesh.c index 62a23da2230..3a132aa326d 100644 --- a/source/blender/blenkernel/intern/cdderivedmesh.c +++ b/source/blender/blenkernel/intern/cdderivedmesh.c @@ -980,7 +980,7 @@ static void cdDM_drawMappedFaces(DerivedMesh *dm, int (*setDrawOptions)(void *us } if(setDrawOptions == NULL) { /* just draw the entire face array */ - glDrawArrays(GL_TRIANGLES, 0, (tottri-1) * 3); + glDrawArrays(GL_TRIANGLES, 0, (tottri) * 3); } else { /* we need to check if the next material changes */ diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c index 3e14dbe39da..92304278b3f 100644 --- a/source/blender/blenkernel/intern/constraint.c +++ b/source/blender/blenkernel/intern/constraint.c @@ -3941,7 +3941,6 @@ static void followtrack_new_data (void *cdata) data->clip= NULL; data->flag|= FOLLOWTRACK_ACTIVECLIP; - data->reference= FOLLOWTRACK_TRACK; } static void followtrack_id_looper (bConstraint *con, ConstraintIDFunc func, void *userdata) @@ -3969,7 +3968,7 @@ static void followtrack_evaluate (bConstraint *con, bConstraintOb *cob, ListBase if(!track) return; - if(data->reference==FOLLOWTRACK_BUNDLE) { + if(data->flag&FOLLOWTRACK_USE_3D_POSITION) { if(track->flag&TRACK_HAS_BUNDLE) { float pos[3], mat[4][4], obmat[4][4]; diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c index c71a8f2bfc7..16102f466da 100644 --- a/source/blender/blenkernel/intern/dynamicpaint.c +++ b/source/blender/blenkernel/intern/dynamicpaint.c @@ -207,7 +207,7 @@ typedef struct PaintAdjData { static int setError(DynamicPaintCanvasSettings *canvas, const char *string) { /* Add error to canvas ui info label */ - BLI_snprintf(canvas->error, sizeof(canvas->error), string); + BLI_strncpy(canvas->error, string, sizeof(canvas->error)); return 0; } @@ -279,13 +279,13 @@ static void dynamicPaint_setPreview(DynamicPaintSurface *t_surface) } } -int dynamicPaint_outputLayerExists(struct DynamicPaintSurface *surface, Object *ob, int index) +int dynamicPaint_outputLayerExists(struct DynamicPaintSurface *surface, Object *ob, int output) { char *name; - if (index == 0) + if (output == 0) name = surface->output_name; - else if (index == 1) + else if (output == 1) name = surface->output_name2; else return 0; @@ -317,7 +317,7 @@ static int surface_duplicateOutputExists(void *arg, const char *name) return 0; } -void surface_setUniqueOutputName(DynamicPaintSurface *surface, char *basename, int output) +static void surface_setUniqueOutputName(DynamicPaintSurface *surface, char *basename, int output) { char name[64]; BLI_strncpy(name, basename, sizeof(name)); /* in case basename is surface->name use a copy */ @@ -1919,7 +1919,7 @@ static int dynamicPaint_findNeighbourPixel(PaintUVPoint *tempPoints, DerivedMesh /* Get closest edge to that subpixel on UV map */ { float pixel[2], dist, t_dist; - int i, uindex[2], edge1_index, edge2_index, + int i, uindex[3], edge1_index, edge2_index, e1_index, e2_index, target_face; float closest_point[2], lambda, dir_vec[2]; int target_uv1, target_uv2, final_pixel[2], final_index; @@ -4139,13 +4139,13 @@ static void dynamicPaint_doEffectStep(DynamicPaintSurface *surface, float *force totalAlpha += ePoint->e_alpha; /* do color mixing */ - if (color_mix) mixColors(pPoint->e_color, pPoint->e_alpha, ePoint->e_color, color_mix); + if (color_mix > MIN_WETNESS) mixColors(pPoint->e_color, pPoint->e_alpha, ePoint->e_color, color_mix); /* Check if neighbouring point has higher wetness, * if so, add it's wetness to this point as well*/ if (ePoint->wetness <= pPoint->wetness) continue; w_factor = ePoint->wetness/numOfNeighs * (ePoint->wetness - pPoint->wetness) * speed_scale; - if (w_factor <= 0.0f) continue; + if (w_factor <= MIN_WETNESS) continue; if (ePoint->e_alpha > pPoint->e_alpha) { alphaAdd = ePoint->e_alpha/numOfNeighs * (ePoint->wetness*ePoint->e_alpha - pPoint->wetness*pPoint->e_alpha) * speed_scale; diff --git a/source/blender/blenkernel/intern/implicit.c b/source/blender/blenkernel/intern/implicit.c index df3694e0bf1..00a2de369a3 100644 --- a/source/blender/blenkernel/intern/implicit.c +++ b/source/blender/blenkernel/intern/implicit.c @@ -1814,7 +1814,7 @@ int cloth_calc_helper_forces(Object *UNUSED(ob), ClothModifierData * clmd, float /*compute forces*/ sub_v3_v3v3(vec, cos[i], cv->tx); - mul_v3_fl(vec, cv->mass*dt*20.0); + mul_v3_fl(vec, cv->mass*dt*20.0f); add_v3_v3(cv->tv, vec); //copy_v3_v3(cv->tx, cos[i]); } diff --git a/source/blender/blenkernel/intern/mesh_validate.c b/source/blender/blenkernel/intern/mesh_validate.c index 4fc843a3944..d8e91a140f7 100644 --- a/source/blender/blenkernel/intern/mesh_validate.c +++ b/source/blender/blenkernel/intern/mesh_validate.c @@ -331,7 +331,7 @@ static int mesh_validate_customdata(CustomData *data, short do_verbose, const sh #undef PRINT -int BKE_mesh_validate_all_customdata(CustomData *vdata, CustomData *edata, CustomData *fdata, short do_verbose, const short do_fixes) +static int BKE_mesh_validate_all_customdata(CustomData *vdata, CustomData *edata, CustomData *fdata, short do_verbose, const short do_fixes) { int vfixed= 0, efixed= 0, ffixed= 0; diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index 5cbce85844e..5ad7432fa39 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -2346,6 +2346,69 @@ int minmax_object_duplis(Scene *scene, Object *ob, float *min, float *max) return ok; } +void BKE_object_foreach_display_point( + Object *ob, float obmat[4][4], + void (*func_cb)(const float[3], void *), void *user_data) +{ + float co[3]; + + if (ob->derivedFinal) { + DerivedMesh *dm= ob->derivedFinal; + MVert *mv= dm->getVertArray(dm); + int totvert= dm->getNumVerts(dm); + int i; + + for (i= 0; i < totvert; i++, mv++) { + mul_v3_m4v3(co, obmat, mv->co); + func_cb(co, user_data); + } + } + else if (ob->disp.first) { + DispList *dl; + + for (dl=ob->disp.first; dl; dl=dl->next) { + float *v3= dl->verts; + int totvert= dl->nr; + int i; + + for (i= 0; i < totvert; i++, v3+=3) { + mul_v3_m4v3(co, obmat, v3); + func_cb(co, user_data); + } + } + } +} + +void BKE_scene_foreach_display_point( + Scene *scene, View3D *v3d, const short flag, + void (*func_cb)(const float[3], void *), void *user_data) +{ + Base *base; + Object *ob; + + for(base= FIRSTBASE; base; base = base->next) { + if(BASE_VISIBLE(v3d, base) && (base->flag & flag) == flag) { + ob= base->object; + + if ((ob->transflag & OB_DUPLI)==0) { + BKE_object_foreach_display_point(ob, ob->obmat, func_cb, user_data); + } + else { + ListBase *lb; + DupliObject *dob; + + lb= object_duplilist(scene, ob); + for(dob= lb->first; dob; dob= dob->next) { + if(dob->no_draw == 0) { + BKE_object_foreach_display_point(dob->ob, dob->mat, func_cb, user_data); + } + } + free_object_duplilist(lb); /* does restore */ + } + } + } +} + /* copied from DNA_object_types.h */ typedef struct ObTfmBack { float loc[3], dloc[3], orig[3]; diff --git a/source/blender/blenkernel/intern/ocean.c b/source/blender/blenkernel/intern/ocean.c new file mode 100644 index 00000000000..df4cd94cf38 --- /dev/null +++ b/source/blender/blenkernel/intern/ocean.c @@ -0,0 +1,1421 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * Contributors: Matt Ebb, Hamed Zaghaghi + * Based on original code by Drew Whitehouse / Houdini Ocean Toolkit + * OpenMP hints by Christian Schnellhammer + * + * ***** END GPL LICENSE BLOCK ***** + */ + + +#include <math.h> +#include <stdlib.h> + +#include <string.h> + +#include "MEM_guardedalloc.h" + +#include "DNA_scene_types.h" + +#include "BKE_image.h" +#include "BKE_ocean.h" +#include "BKE_utildefines.h" + +#include "BKE_global.h" // XXX TESTING + +#include "BLI_math_base.h" +#include "BLI_math_inline.h" +#include "BLI_rand.h" +#include "BLI_string.h" +#include "BLI_threads.h" +#include "BLI_path_util.h" +#include "BLI_utildefines.h" + +#include "IMB_imbuf.h" +#include "IMB_imbuf_types.h" + +#include "RE_render_ext.h" + +#ifdef WITH_OCEANSIM + +// Ocean code +#include "fftw3.h" + +#define GRAVITY 9.81f + +typedef struct Ocean { + /* ********* input parameters to the sim ********* */ + float _V; + float _l; + float _w; + float _A; + float _damp_reflections; + float _wind_alignment; + float _depth; + + float _wx; + float _wz; + + float _L; + + /* dimensions of computational grid */ + int _M; + int _N; + + /* spatial size of computational grid */ + float _Lx; + float _Lz; + + float normalize_factor; // init w + float time; + + short _do_disp_y; + short _do_normals; + short _do_chop; + short _do_jacobian; + + /* mutex for threaded texture access */ + ThreadRWMutex oceanmutex; + + /* ********* sim data arrays ********* */ + + /* two dimensional arrays of complex */ + fftw_complex *_fft_in; // init w sim w + fftw_complex *_fft_in_x; // init w sim w + fftw_complex *_fft_in_z; // init w sim w + fftw_complex *_fft_in_jxx; // init w sim w + fftw_complex *_fft_in_jzz; // init w sim w + fftw_complex *_fft_in_jxz; // init w sim w + fftw_complex *_fft_in_nx; // init w sim w + fftw_complex *_fft_in_nz; // init w sim w + fftw_complex *_htilda; // init w sim w (only once) + + /* fftw "plans" */ + fftw_plan _disp_y_plan; // init w sim r + fftw_plan _disp_x_plan; // init w sim r + fftw_plan _disp_z_plan; // init w sim r + fftw_plan _N_x_plan; // init w sim r + fftw_plan _N_z_plan; // init w sim r + fftw_plan _Jxx_plan; // init w sim r + fftw_plan _Jxz_plan; // init w sim r + fftw_plan _Jzz_plan; // init w sim r + + /* two dimensional arrays of float */ + double * _disp_y; // init w sim w via plan? + double * _N_x; // init w sim w via plan? + /*float * _N_y; all member of this array has same values, so convert this array to a float to reduce memory usage (MEM01)*/ + double _N_y; // sim w ********* can be rearranged? + double * _N_z; // init w sim w via plan? + double * _disp_x; // init w sim w via plan? + double * _disp_z; // init w sim w via plan? + + /* two dimensional arrays of float */ + /* Jacobian and minimum eigenvalue */ + double * _Jxx; // init w sim w + double * _Jzz; // init w sim w + double * _Jxz; // init w sim w + + /* one dimensional float array */ + float * _kx; // init w sim r + float * _kz; // init w sim r + + /* two dimensional complex array */ + fftw_complex * _h0; // init w sim r + fftw_complex * _h0_minus; // init w sim r + + /* two dimensional float array */ + float * _k; // init w sim r +} Ocean; + + + +static float nextfr(float min, float max) +{ + return BLI_frand()*(min-max)+max; +} + +static float gaussRand (void) +{ + float x; // Note: to avoid numerical problems with very small + float y; // numbers, we make these variables singe-precision + float length2; // floats, but later we call the double-precision log() + // and sqrt() functions instead of logf() and sqrtf(). + do + { + x = (float) (nextfr (-1, 1)); + y = (float)(nextfr (-1, 1)); + length2 = x * x + y * y; + } + while (length2 >= 1 || length2 == 0); + + return x * sqrtf(-2.0f * logf(length2) / length2); +} + +/** + * Som usefull functions + * */ +MINLINE float lerp(float a,float b,float f) +{ + return a + (b-a)*f; +} + +MINLINE float catrom(float p0,float p1,float p2,float p3,float f) +{ + return 0.5f *((2.0f * p1) + + (-p0 + p2) * f + + (2.0f*p0 - 5.0f*p1 + 4.0f*p2 - p3) * f*f + + (-p0 + 3.0f*p1- 3.0f*p2 + p3) * f*f*f); +} + +MINLINE float omega(float k, float depth) +{ + return sqrt(GRAVITY*k * tanh(k*depth)); +} + +// modified Phillips spectrum +static float Ph(struct Ocean* o, float kx,float kz ) +{ + float tmp; + float k2 = kx*kx + kz*kz; + + if (k2 == 0.0f) + { + return 0.0f; // no DC component + } + + // damp out the waves going in the direction opposite the wind + tmp = (o->_wx * kx + o->_wz * kz)/sqrtf(k2); + if (tmp < 0) + { + tmp *= o->_damp_reflections; + } + + return o->_A * expf( -1.0f / (k2*(o->_L*o->_L))) * expf(-k2 * (o->_l*o->_l)) * powf(fabsf(tmp),o->_wind_alignment) / (k2*k2); +} + +static void compute_eigenstuff(struct OceanResult *ocr, float jxx,float jzz,float jxz) +{ + float a,b,qplus,qminus; + a = jxx + jzz; + b = sqrt((jxx - jzz)*(jxx - jzz) + 4 * jxz * jxz); + + ocr->Jminus = 0.5f*(a-b); + ocr->Jplus = 0.5f*(a+b); + + qplus = (ocr->Jplus - jxx)/jxz; + qminus = (ocr->Jminus - jxx)/jxz; + + a = sqrt(1 + qplus*qplus); + b = sqrt(1 + qminus*qminus); + + ocr->Eplus[0] = 1.0f/ a; + ocr->Eplus[1] = 0.0f; + ocr->Eplus[2] = qplus/a; + + ocr->Eminus[0] = 1.0f/b; + ocr->Eminus[1] = 0.0f; + ocr->Eminus[2] = qminus/b; +} + +/* + * instead of Complex.h + * in fftw.h "fftw_complex" typedefed as double[2] + * below you can see functions are needed to work with such complex numbers. + * */ +static void init_complex(fftw_complex cmpl, float real, float image) +{ + cmpl[0] = real; + cmpl[1] = image; +} + +#if 0 // unused +static void add_complex_f(fftw_complex res, fftw_complex cmpl, float f) +{ + res[0] = cmpl[0] + f; + res[1] = cmpl[1]; +} +#endif + +static void add_comlex_c(fftw_complex res, fftw_complex cmpl1, fftw_complex cmpl2) +{ + res[0] = cmpl1[0] + cmpl2[0]; + res[1] = cmpl1[1] + cmpl2[1]; +} + +static void mul_complex_f(fftw_complex res, fftw_complex cmpl, float f) +{ + res[0] = cmpl[0]*f; + res[1] = cmpl[1]*f; +} + +static void mul_complex_c(fftw_complex res, fftw_complex cmpl1, fftw_complex cmpl2) +{ + fftwf_complex temp; + temp[0] = cmpl1[0]*cmpl2[0]-cmpl1[1]*cmpl2[1]; + temp[1] = cmpl1[0]*cmpl2[1]+cmpl1[1]*cmpl2[0]; + res[0] = temp[0]; + res[1] = temp[1]; +} + +static float real_c(fftw_complex cmpl) +{ + return cmpl[0]; +} + +static float image_c(fftw_complex cmpl) +{ + return cmpl[1]; +} + +static void conj_complex(fftw_complex res, fftw_complex cmpl1) +{ + res[0] = cmpl1[0]; + res[1] = -cmpl1[1]; +} + +static void exp_complex(fftw_complex res, fftw_complex cmpl) +{ + float r = expf(cmpl[0]); + + res[0] = cos(cmpl[1])*r; + res[1] = sin(cmpl[1])*r; +} + +float BKE_ocean_jminus_to_foam(float jminus, float coverage) +{ + float foam = jminus * -0.005f + coverage; + CLAMP(foam, 0.0f, 1.0f); + return foam*foam; +} + +void BKE_ocean_eval_uv(struct Ocean *oc, struct OceanResult *ocr, float u,float v) +{ + int i0,i1,j0,j1; + float frac_x,frac_z; + float uu,vv; + + // first wrap the texture so 0 <= (u,v) < 1 + u = fmod(u,1.0f); + v = fmod(v,1.0f); + + if (u < 0) u += 1.0f; + if (v < 0) v += 1.0f; + + BLI_rw_mutex_lock(&oc->oceanmutex, THREAD_LOCK_READ); + + uu = u * oc->_M; + vv = v * oc->_N; + + i0 = (int)floor(uu); + j0 = (int)floor(vv); + + i1 = (i0 + 1); + j1 = (j0 + 1); + + frac_x = uu - i0; + frac_z = vv - j0; + + i0 = i0 % oc->_M; + j0 = j0 % oc->_N; + + i1 = i1 % oc->_M; + j1 = j1 % oc->_N; + + +#define BILERP(m) (lerp(lerp(m[i0*oc->_N+j0],m[i1*oc->_N+j0],frac_x),lerp(m[i0*oc->_N+j1],m[i1*oc->_N+j1],frac_x),frac_z)) + { + if (oc->_do_disp_y) { + ocr->disp[1] = BILERP(oc->_disp_y); + } + + if (oc->_do_normals) { + ocr->normal[0] = BILERP(oc->_N_x); + ocr->normal[1] = oc->_N_y/*BILERP(oc->_N_y) (MEM01)*/; + ocr->normal[2] = BILERP(oc->_N_z); + } + + if (oc->_do_chop) { + ocr->disp[0] = BILERP(oc->_disp_x); + ocr->disp[2] = BILERP(oc->_disp_z); + } else { + ocr->disp[0] = 0.0; + ocr->disp[2] = 0.0; + } + + if (oc->_do_jacobian) { + compute_eigenstuff(ocr, BILERP(oc->_Jxx),BILERP(oc->_Jzz),BILERP(oc->_Jxz)); + } + } +#undef BILERP + + BLI_rw_mutex_unlock(&oc->oceanmutex); +} + +// use catmullrom interpolation rather than linear +void BKE_ocean_eval_uv_catrom(struct Ocean *oc, struct OceanResult *ocr, float u,float v) +{ + int i0,i1,i2,i3,j0,j1,j2,j3; + float frac_x,frac_z; + float uu,vv; + + // first wrap the texture so 0 <= (u,v) < 1 + u = fmod(u,1.0f); + v = fmod(v,1.0f); + + if (u < 0) u += 1.0f; + if (v < 0) v += 1.0f; + + BLI_rw_mutex_lock(&oc->oceanmutex, THREAD_LOCK_READ); + + uu = u * oc->_M; + vv = v * oc->_N; + + i1 = (int)floor(uu); + j1 = (int)floor(vv); + + i2 = (i1 + 1); + j2 = (j1 + 1); + + frac_x = uu - i1; + frac_z = vv - j1; + + i1 = i1 % oc->_M; + j1 = j1 % oc->_N; + + i2 = i2 % oc->_M; + j2 = j2 % oc->_N; + + i0 = (i1-1); + i3 = (i2+1); + i0 = i0 < 0 ? i0 + oc->_M : i0; + i3 = i3 >= oc->_M ? i3 - oc->_M : i3; + + j0 = (j1-1); + j3 = (j2+1); + j0 = j0 < 0 ? j0 + oc->_N : j0; + j3 = j3 >= oc->_N ? j3 - oc->_N : j3; + +#define INTERP(m) catrom(catrom(m[i0*oc->_N+j0],m[i1*oc->_N+j0],m[i2*oc->_N+j0],m[i3*oc->_N+j0],frac_x),\ + catrom(m[i0*oc->_N+j1],m[i1*oc->_N+j1],m[i2*oc->_N+j1],m[i3*oc->_N+j1],frac_x),\ + catrom(m[i0*oc->_N+j2],m[i1*oc->_N+j2],m[i2*oc->_N+j2],m[i3*oc->_N+j2],frac_x),\ + catrom(m[i0*oc->_N+j3],m[i1*oc->_N+j3],m[i2*oc->_N+j3],m[i3*oc->_N+j3],frac_x),\ + frac_z) + + { + if (oc->_do_disp_y) + { + ocr->disp[1] = INTERP(oc->_disp_y) ; + } + if (oc->_do_normals) + { + ocr->normal[0] = INTERP(oc->_N_x); + ocr->normal[1] = oc->_N_y/*INTERP(oc->_N_y) (MEM01)*/; + ocr->normal[2] = INTERP(oc->_N_z); + } + if (oc->_do_chop) + { + ocr->disp[0] = INTERP(oc->_disp_x); + ocr->disp[2] = INTERP(oc->_disp_z); + } + else + { + ocr->disp[0] = 0.0; + ocr->disp[2] = 0.0; + } + + if (oc->_do_jacobian) + { + compute_eigenstuff(ocr, INTERP(oc->_Jxx),INTERP(oc->_Jzz),INTERP(oc->_Jxz)); + } + } +#undef INTERP + + BLI_rw_mutex_unlock(&oc->oceanmutex); + +} + +void BKE_ocean_eval_xz(struct Ocean *oc, struct OceanResult *ocr, float x,float z) +{ + BKE_ocean_eval_uv(oc, ocr, x/oc->_Lx,z/oc->_Lz); +} + +void BKE_ocean_eval_xz_catrom(struct Ocean *oc, struct OceanResult *ocr, float x,float z) +{ + BKE_ocean_eval_uv_catrom(oc, ocr, x/oc->_Lx,z/oc->_Lz); +} + +// note that this doesn't wrap properly for i,j < 0, but its +// not really meant for that being just a way to get the raw data out +// to save in some image format. +void BKE_ocean_eval_ij(struct Ocean *oc, struct OceanResult *ocr, int i,int j) +{ + BLI_rw_mutex_lock(&oc->oceanmutex, THREAD_LOCK_READ); + + i = abs(i) % oc->_M; + j = abs(j) % oc->_N; + + ocr->disp[1] = oc->_do_disp_y ? oc->_disp_y[i*oc->_N+j] : 0.0f; + + if (oc->_do_chop) + { + ocr->disp[0] = oc->_disp_x[i*oc->_N+j]; + ocr->disp[2] = oc->_disp_z[i*oc->_N+j]; + } + else + { + ocr->disp[0] = 0.0f; + ocr->disp[2] = 0.0f; + } + + if (oc->_do_normals) + { + ocr->normal[0] = oc->_N_x[i*oc->_N+j]; + ocr->normal[1] = oc->_N_y/*oc->_N_y[i*oc->_N+j] (MEM01)*/; + ocr->normal[2] = oc->_N_z[i*oc->_N+j]; + + normalize_v3(ocr->normal); + } + + if (oc->_do_jacobian) + { + compute_eigenstuff(ocr, oc->_Jxx[i*oc->_N+j],oc->_Jzz[i*oc->_N+j],oc->_Jxz[i*oc->_N+j]); + } + + BLI_rw_mutex_unlock(&oc->oceanmutex); +} + +void BKE_simulate_ocean(struct Ocean *o, float t, float scale, float chop_amount) +{ + int i, j; + + scale *= o->normalize_factor; + + BLI_rw_mutex_lock(&o->oceanmutex, THREAD_LOCK_WRITE); + + // compute a new htilda +#pragma omp parallel for private(i, j) + for (i = 0 ; i < o->_M ; ++i) + { + // note the <= _N/2 here, see the fftw doco about + // the mechanics of the complex->real fft storage + for ( j = 0 ; j <= o->_N / 2 ; ++j) + { + fftw_complex exp_param1; + fftw_complex exp_param2; + fftw_complex conj_param; + + + init_complex(exp_param1, 0.0, omega(o->_k[i*(1+o->_N/2)+j],o->_depth)*t); + init_complex(exp_param2, 0.0, -omega(o->_k[i*(1+o->_N/2)+j],o->_depth)*t); + exp_complex(exp_param1, exp_param1); + exp_complex(exp_param2, exp_param2); + conj_complex(conj_param, o->_h0_minus[i*o->_N+j]); + + mul_complex_c(exp_param1, o->_h0[i*o->_N+j], exp_param1); + mul_complex_c(exp_param2, conj_param, exp_param2); + + add_comlex_c(o->_htilda[i*(1+o->_N/2)+j], exp_param1, exp_param2); + mul_complex_f(o->_fft_in[i*(1+o->_N/2)+j], o->_htilda[i*(1+o->_N/2)+j], scale); + } + } + +#pragma omp parallel sections private(i, j) + { + +#pragma omp section + { + if (o->_do_disp_y) + { + // y displacement + fftw_execute(o->_disp_y_plan); + } + } // section 1 + +#pragma omp section + { + if (o->_do_chop) + { + // x displacement + for ( i = 0 ; i < o->_M ; ++i) + { + for ( j = 0 ; j <= o->_N / 2 ; ++j) + { + fftw_complex mul_param; + fftw_complex minus_i; + + init_complex(minus_i, 0.0, -1.0); + init_complex(mul_param, -scale, 0); + mul_complex_f(mul_param, mul_param, chop_amount); + mul_complex_c(mul_param, mul_param, minus_i); + mul_complex_c(mul_param, mul_param, o->_htilda[i*(1+o->_N/2)+j]); + mul_complex_f(mul_param, mul_param, (o->_k[i*(1+o->_N/2)+j] == 0.0 ? 0.0 : o->_kx[i] / o->_k[i*(1+o->_N/2)+j])); + init_complex(o->_fft_in_x[i*(1+o->_N/2)+j], real_c(mul_param), image_c(mul_param)); + } + } + fftw_execute(o->_disp_x_plan); + } + } //section 2 + +#pragma omp section + { + if (o->_do_chop) + { + // z displacement + for ( i = 0 ; i < o->_M ; ++i) + { + for ( j = 0 ; j <= o->_N / 2 ; ++j) + { + fftw_complex mul_param; + fftw_complex minus_i; + + init_complex(minus_i, 0.0, -1.0); + init_complex(mul_param, -scale, 0); + mul_complex_f(mul_param, mul_param, chop_amount); + mul_complex_c(mul_param, mul_param, minus_i); + mul_complex_c(mul_param, mul_param, o->_htilda[i*(1+o->_N/2)+j]); + mul_complex_f(mul_param, mul_param, (o->_k[i*(1+o->_N/2)+j] == 0.0 ? 0.0 : o->_kz[j] / o->_k[i*(1+o->_N/2)+j])); + init_complex(o->_fft_in_z[i*(1+o->_N/2)+j], real_c(mul_param), image_c(mul_param)); + } + } + fftw_execute(o->_disp_z_plan); + } + } // section 3 + +#pragma omp section + { + if (o->_do_jacobian) + { + // Jxx + for ( i = 0 ; i < o->_M ; ++i) + { + for ( j = 0 ; j <= o->_N / 2 ; ++j) + { + fftw_complex mul_param; + + //init_complex(mul_param, -scale, 0); + init_complex(mul_param, -1, 0); + + mul_complex_f(mul_param, mul_param, chop_amount); + mul_complex_c(mul_param, mul_param, o->_htilda[i*(1+o->_N/2)+j]); + mul_complex_f(mul_param, mul_param, (o->_k[i*(1+o->_N/2)+j] == 0.0 ? 0.0 : o->_kx[i]*o->_kx[i] / o->_k[i*(1+o->_N/2)+j])); + init_complex(o->_fft_in_jxx[i*(1+o->_N/2)+j], real_c(mul_param), image_c(mul_param)); + } + } + fftw_execute(o->_Jxx_plan); + + for ( i = 0 ; i < o->_M ; ++i) + { + for ( j = 0 ; j < o->_N ; ++j) + { + o->_Jxx[i*o->_N+j] += 1.0; + } + } + } + } // section 4 + +#pragma omp section + { + if (o->_do_jacobian) + { + // Jzz + for ( i = 0 ; i < o->_M ; ++i) + { + for ( j = 0 ; j <= o->_N / 2 ; ++j) + { + fftw_complex mul_param; + + //init_complex(mul_param, -scale, 0); + init_complex(mul_param, -1, 0); + + mul_complex_f(mul_param, mul_param, chop_amount); + mul_complex_c(mul_param, mul_param, o->_htilda[i*(1+o->_N/2)+j]); + mul_complex_f(mul_param, mul_param, (o->_k[i*(1+o->_N/2)+j] == 0.0 ? 0.0 : o->_kz[j]*o->_kz[j] / o->_k[i*(1+o->_N/2)+j])); + init_complex(o->_fft_in_jzz[i*(1+o->_N/2)+j], real_c(mul_param), image_c(mul_param)); + } + } + fftw_execute(o->_Jzz_plan); + for ( i = 0 ; i < o->_M ; ++i) + { + for ( j = 0 ; j < o->_N ; ++j) + { + o->_Jzz[i*o->_N+j] += 1.0; + } + } + } + } // section 5 + +#pragma omp section + { + if (o->_do_jacobian) + { + // Jxz + for ( i = 0 ; i < o->_M ; ++i) + { + for ( j = 0 ; j <= o->_N / 2 ; ++j) + { + fftw_complex mul_param; + + //init_complex(mul_param, -scale, 0); + init_complex(mul_param, -1, 0); + + mul_complex_f(mul_param, mul_param, chop_amount); + mul_complex_c(mul_param, mul_param, o->_htilda[i*(1+o->_N/2)+j]); + mul_complex_f(mul_param, mul_param, (o->_k[i*(1+o->_N/2)+j] == 0.0f ? 0.0f : o->_kx[i]*o->_kz[j] / o->_k[i*(1+o->_N/2)+j])); + init_complex(o->_fft_in_jxz[i*(1+o->_N/2)+j], real_c(mul_param), image_c(mul_param)); + } + } + fftw_execute(o->_Jxz_plan); + } + } // section 6 + +#pragma omp section + { + // fft normals + if (o->_do_normals) + { + for ( i = 0 ; i < o->_M ; ++i) + { + for ( j = 0 ; j <= o->_N / 2 ; ++j) + { + fftw_complex mul_param; + + init_complex(mul_param, 0.0, -1.0); + mul_complex_c(mul_param, mul_param, o->_htilda[i*(1+o->_N/2)+j]); + mul_complex_f(mul_param, mul_param, o->_kx[i]); + init_complex(o->_fft_in_nx[i*(1+o->_N/2)+j], real_c(mul_param), image_c(mul_param)); + } + } + fftw_execute(o->_N_x_plan); + + } + } // section 7 + +#pragma omp section + { + if (o->_do_normals) + { + for ( i = 0 ; i < o->_M ; ++i) + { + for ( j = 0 ; j <= o->_N / 2 ; ++j) + { + fftw_complex mul_param; + + init_complex(mul_param, 0.0, -1.0); + mul_complex_c(mul_param, mul_param, o->_htilda[i*(1+o->_N/2)+j]); + mul_complex_f(mul_param, mul_param, o->_kz[i]); + init_complex(o->_fft_in_nz[i*(1+o->_N/2)+j], real_c(mul_param), image_c(mul_param)); + } + } + fftw_execute(o->_N_z_plan); + + /*for ( i = 0 ; i < o->_M ; ++i) + { + for ( j = 0 ; j < o->_N ; ++j) + { + o->_N_y[i*o->_N+j] = 1.0f/scale; + } + } + (MEM01)*/ + o->_N_y = 1.0f/scale; + } + } // section 8 + + } // omp sections + + BLI_rw_mutex_unlock(&o->oceanmutex); +} + +static void set_height_normalize_factor(struct Ocean *oc) +{ + float res = 1.0; + float max_h = 0.0; + + int i,j; + + if (!oc->_do_disp_y) return; + + oc->normalize_factor = 1.0; + + BKE_simulate_ocean(oc, 0.0, 1.0, 0); + + BLI_rw_mutex_lock(&oc->oceanmutex, THREAD_LOCK_READ); + + for (i = 0; i < oc->_M; ++i) + { + for (j = 0; j < oc->_N; ++j) + { + if( max_h < fabsf(oc->_disp_y[i*oc->_N+j])) + { + max_h = fabsf(oc->_disp_y[i*oc->_N+j]); + } + } + } + + BLI_rw_mutex_unlock(&oc->oceanmutex); + + if (max_h == 0.0f) max_h = 0.00001f; // just in case ... + + res = 1.0f / (max_h); + + oc->normalize_factor = res; +} + +struct Ocean *BKE_add_ocean(void) +{ + Ocean *oc = MEM_callocN(sizeof(Ocean), "ocean sim data"); + + BLI_rw_mutex_init(&oc->oceanmutex); + + return oc; +} + +void BKE_init_ocean(struct Ocean* o, int M,int N, float Lx, float Lz, float V, float l, float A, float w, float damp, + float alignment, float depth, float time, short do_height_field, short do_chop, short do_normals, short do_jacobian, int seed) +{ + int i,j,ii; + + BLI_rw_mutex_lock(&o->oceanmutex, THREAD_LOCK_WRITE); + + o->_M = M; + o->_N = N; + o->_V = V; + o->_l = l; + o->_A = A; + o->_w = w; + o->_damp_reflections = 1.0f - damp; + o->_wind_alignment = alignment; + o->_depth = depth; + o->_Lx = Lx; + o->_Lz = Lz; + o->_wx = cos(w); + o->_wz = -sin(w); // wave direction + o->_L = V*V / GRAVITY; // largest wave for a given velocity V + o->time = time; + + o->_do_disp_y = do_height_field; + o->_do_normals = do_normals; + o->_do_chop = do_chop; + o->_do_jacobian = do_jacobian; + + o->_k = (float*) MEM_mallocN(M * (1+N/2) * sizeof(float), "ocean_k"); + o->_h0 = (fftw_complex*) MEM_mallocN(M * N * sizeof(fftw_complex), "ocean_h0"); + o->_h0_minus = (fftw_complex*) MEM_mallocN(M * N * sizeof(fftw_complex), "ocean_h0_minus"); + o->_kx = (float*) MEM_mallocN(o->_M * sizeof(float), "ocean_kx"); + o->_kz = (float*) MEM_mallocN(o->_N * sizeof(float), "ocean_kz"); + + // make this robust in the face of erroneous usage + if (o->_Lx == 0.0f) + o->_Lx = 0.001f; + + if (o->_Lz == 0.0f) + o->_Lz = 0.001f; + + // the +ve components and DC + for (i = 0 ; i <= o->_M/2 ; ++i) + o->_kx[i] = 2.0f * (float)M_PI * i / o->_Lx; + + // the -ve components + for (i = o->_M-1,ii=0 ; i > o->_M/2 ; --i,++ii) + o->_kx[i] = -2.0f * (float)M_PI * ii / o->_Lx; + + // the +ve components and DC + for (i = 0 ; i <= o->_N/2 ; ++i) + o->_kz[i] = 2.0f * (float)M_PI * i / o->_Lz; + + // the -ve components + for (i = o->_N-1,ii=0 ; i > o->_N/2 ; --i,++ii) + o->_kz[i] = -2.0f * (float)M_PI * ii / o->_Lz; + + // pre-calculate the k matrix + for (i = 0 ; i < o->_M ; ++i) + for (j = 0 ; j <= o->_N / 2 ; ++j) + o->_k[i*(1+o->_N/2)+j] = sqrt(o->_kx[i]*o->_kx[i] + o->_kz[j]*o->_kz[j] ); + + /*srand(seed);*/ + BLI_srand(seed); + + for (i = 0 ; i < o->_M ; ++i) + { + for (j = 0 ; j < o->_N ; ++j) + { + float r1 = gaussRand(); + float r2 = gaussRand(); + + fftw_complex r1r2; + init_complex(r1r2, r1, r2); + mul_complex_f(o->_h0[i*o->_N+j], r1r2, (float)(sqrt(Ph(o, o->_kx[i], o->_kz[j]) / 2.0f))); + mul_complex_f(o->_h0_minus[i*o->_N+j], r1r2, (float)(sqrt(Ph(o, -o->_kx[i],-o->_kz[j]) / 2.0f))); + } + } + + o->_fft_in = (fftw_complex*) MEM_mallocN(o->_M * (1+o->_N/2) * sizeof(fftw_complex), "ocean_fft_in"); + o->_htilda = (fftw_complex*) MEM_mallocN(o->_M * (1+o->_N/2) * sizeof(fftw_complex), "ocean_htilda"); + + if (o->_do_disp_y){ + o->_disp_y = (double*) MEM_mallocN(o->_M * o->_N * sizeof(double), "ocean_disp_y"); + o->_disp_y_plan = fftw_plan_dft_c2r_2d(o->_M,o->_N, o->_fft_in, o->_disp_y, FFTW_ESTIMATE); + } + + if (o->_do_normals){ + o->_fft_in_nx = (fftw_complex*) MEM_mallocN(o->_M * (1+o->_N/2) * sizeof(fftw_complex), "ocean_fft_in_nx"); + o->_fft_in_nz = (fftw_complex*) MEM_mallocN(o->_M * (1+o->_N/2) * sizeof(fftw_complex), "ocean_fft_in_nz"); + + o->_N_x = (double*) MEM_mallocN(o->_M * o->_N * sizeof(double), "ocean_N_x"); + /*o->_N_y = (float*) fftwf_malloc(o->_M * o->_N * sizeof(float)); (MEM01)*/ + o->_N_z = (double*) MEM_mallocN(o->_M * o->_N * sizeof(double), "ocean_N_z"); + + o->_N_x_plan = fftw_plan_dft_c2r_2d(o->_M,o->_N, o->_fft_in_nx, o->_N_x, FFTW_ESTIMATE); + o->_N_z_plan = fftw_plan_dft_c2r_2d(o->_M,o->_N, o->_fft_in_nz, o->_N_z, FFTW_ESTIMATE); + } + + if (o->_do_chop){ + o->_fft_in_x = (fftw_complex*) MEM_mallocN(o->_M * (1+o->_N/2) * sizeof(fftw_complex), "ocean_fft_in_x"); + o->_fft_in_z = (fftw_complex*) MEM_mallocN(o->_M * (1+o->_N/2) * sizeof(fftw_complex), "ocean_fft_in_z"); + + o->_disp_x = (double*) MEM_mallocN(o->_M * o->_N * sizeof(double), "ocean_disp_x"); + o->_disp_z = (double*) MEM_mallocN(o->_M * o->_N * sizeof(double), "ocean_disp_z"); + + o->_disp_x_plan = fftw_plan_dft_c2r_2d(o->_M,o->_N, o->_fft_in_x, o->_disp_x, FFTW_ESTIMATE); + o->_disp_z_plan = fftw_plan_dft_c2r_2d(o->_M,o->_N, o->_fft_in_z, o->_disp_z, FFTW_ESTIMATE); + } + if (o->_do_jacobian){ + o->_fft_in_jxx = (fftw_complex*) MEM_mallocN(o->_M * (1+o->_N/2) * sizeof(fftw_complex), "ocean_fft_in_jxx"); + o->_fft_in_jzz = (fftw_complex*) MEM_mallocN(o->_M * (1+o->_N/2) * sizeof(fftw_complex), "ocean_fft_in_jzz"); + o->_fft_in_jxz = (fftw_complex*) MEM_mallocN(o->_M * (1+o->_N/2) * sizeof(fftw_complex), "ocean_fft_in_jxz"); + + o->_Jxx = (double*) MEM_mallocN(o->_M * o->_N * sizeof(double), "ocean_Jxx"); + o->_Jzz = (double*) MEM_mallocN(o->_M * o->_N * sizeof(double), "ocean_Jzz"); + o->_Jxz = (double*) MEM_mallocN(o->_M * o->_N * sizeof(double), "ocean_Jxz"); + + o->_Jxx_plan = fftw_plan_dft_c2r_2d(o->_M,o->_N, o->_fft_in_jxx, o->_Jxx, FFTW_ESTIMATE); + o->_Jzz_plan = fftw_plan_dft_c2r_2d(o->_M,o->_N, o->_fft_in_jzz, o->_Jzz, FFTW_ESTIMATE); + o->_Jxz_plan = fftw_plan_dft_c2r_2d(o->_M,o->_N, o->_fft_in_jxz, o->_Jxz, FFTW_ESTIMATE); + } + + BLI_rw_mutex_unlock(&o->oceanmutex); + + set_height_normalize_factor(o); + +} + +void BKE_free_ocean_data(struct Ocean *oc) +{ + if(!oc) return; + + BLI_rw_mutex_lock(&oc->oceanmutex, THREAD_LOCK_WRITE); + + if (oc->_do_disp_y) + { + fftw_destroy_plan(oc->_disp_y_plan); + MEM_freeN(oc->_disp_y); + } + + if (oc->_do_normals) + { + MEM_freeN(oc->_fft_in_nx); + MEM_freeN(oc->_fft_in_nz); + fftw_destroy_plan(oc->_N_x_plan); + fftw_destroy_plan(oc->_N_z_plan); + MEM_freeN(oc->_N_x); + /*fftwf_free(oc->_N_y); (MEM01)*/ + MEM_freeN(oc->_N_z); + } + + if (oc->_do_chop) + { + MEM_freeN(oc->_fft_in_x); + MEM_freeN(oc->_fft_in_z); + fftw_destroy_plan(oc->_disp_x_plan); + fftw_destroy_plan(oc->_disp_z_plan); + MEM_freeN(oc->_disp_x); + MEM_freeN(oc->_disp_z); + } + + if (oc->_do_jacobian) + { + MEM_freeN(oc->_fft_in_jxx); + MEM_freeN(oc->_fft_in_jzz); + MEM_freeN(oc->_fft_in_jxz); + fftw_destroy_plan(oc->_Jxx_plan); + fftw_destroy_plan(oc->_Jzz_plan); + fftw_destroy_plan(oc->_Jxz_plan); + MEM_freeN(oc->_Jxx); + MEM_freeN(oc->_Jzz); + MEM_freeN(oc->_Jxz); + } + + if (oc->_fft_in) + MEM_freeN(oc->_fft_in); + + /* check that ocean data has been initialised */ + if (oc->_htilda) { + MEM_freeN(oc->_htilda); + MEM_freeN(oc->_k); + MEM_freeN(oc->_h0); + MEM_freeN(oc->_h0_minus); + MEM_freeN(oc->_kx); + MEM_freeN(oc->_kz); + } + + BLI_rw_mutex_unlock(&oc->oceanmutex); +} + +void BKE_free_ocean(struct Ocean *oc) +{ + if(!oc) return; + + BKE_free_ocean_data(oc); + BLI_rw_mutex_end(&oc->oceanmutex); + + MEM_freeN(oc); +} + +#undef GRAVITY + + +/* ********* Baking/Caching ********* */ + + +#define CACHE_TYPE_DISPLACE 1 +#define CACHE_TYPE_FOAM 2 +#define CACHE_TYPE_NORMAL 3 + +static void cache_filename(char *string, const char *path, int frame, int type) +{ + char cachepath[FILE_MAX]; + const char *fname; + + switch(type) { + case CACHE_TYPE_FOAM: + fname= "foam_"; + break; + case CACHE_TYPE_NORMAL: + fname= "normal_"; + break; + case CACHE_TYPE_DISPLACE: + default: + fname= "disp_"; + break; + } + + BLI_join_dirfile(cachepath, sizeof(cachepath), path, fname); + + BKE_makepicstring(string, cachepath, frame, R_OPENEXR, 1, TRUE); +} + +void BKE_free_ocean_cache(struct OceanCache *och) +{ + int i, f=0; + + if (!och) return; + + if (och->ibufs_disp) { + for (i=och->start, f=0; i<=och->end; i++, f++) + { + if (och->ibufs_disp[f]) { + IMB_freeImBuf(och->ibufs_disp[f]); + } + } + MEM_freeN(och->ibufs_disp); + } + + if (och->ibufs_foam) { + for (i=och->start, f=0; i<=och->end; i++, f++) + { + if (och->ibufs_foam[f]) { + IMB_freeImBuf(och->ibufs_foam[f]); + } + } + MEM_freeN(och->ibufs_foam); + } + + if (och->ibufs_norm) { + for (i=och->start, f=0; i<=och->end; i++, f++) + { + if (och->ibufs_norm[f]) { + IMB_freeImBuf(och->ibufs_norm[f]); + } + } + MEM_freeN(och->ibufs_norm); + } + + if (och->time) + MEM_freeN(och->time); + MEM_freeN(och); +} + +void BKE_ocean_cache_eval_uv(struct OceanCache *och, struct OceanResult *ocr, int f, float u, float v) +{ + int res_x = och->resolution_x; + int res_y = och->resolution_y; + float result[4]; + + u = fmod(u, 1.0); + v = fmod(v, 1.0); + + if (u < 0) u += 1.0f; + if (v < 0) v += 1.0f; + + if (och->ibufs_disp[f]) { + ibuf_sample(och->ibufs_disp[f], u, v, (1.0f/(float)res_x), (1.0f/(float)res_y), result); + ocr->disp[0] = result[0]; + ocr->disp[1] = result[1]; + ocr->disp[2] = result[2]; + } + + if (och->ibufs_foam[f]) { + ibuf_sample(och->ibufs_foam[f], u, v, (1.0f/(float)res_x), (1.0f/(float)res_y), result); + ocr->foam = result[0]; + } + + if (och->ibufs_norm[f]) { + ibuf_sample(och->ibufs_norm[f], u, v, (1.0f/(float)res_x), (1.0f/(float)res_y), result); + ocr->normal[0] = result[0]; + ocr->normal[1] = result[1]; + ocr->normal[2] = result[2]; + } +} + +void BKE_ocean_cache_eval_ij(struct OceanCache *och, struct OceanResult *ocr, int f, int i, int j) +{ + int res_x = och->resolution_x; + int res_y = och->resolution_y; + + i = abs(i) % res_x; + j = abs(j) % res_y; + + if (och->ibufs_disp[f]) { + ocr->disp[0] = och->ibufs_disp[f]->rect_float[4*(res_x*j + i) + 0]; + ocr->disp[1] = och->ibufs_disp[f]->rect_float[4*(res_x*j + i) + 1]; + ocr->disp[2] = och->ibufs_disp[f]->rect_float[4*(res_x*j + i) + 2]; + } + + if (och->ibufs_foam[f]) { + ocr->foam = och->ibufs_foam[f]->rect_float[4*(res_x*j + i) + 0]; + } + + if (och->ibufs_norm[f]) { + ocr->normal[0] = och->ibufs_norm[f]->rect_float[4*(res_x*j + i) + 0]; + ocr->normal[1] = och->ibufs_norm[f]->rect_float[4*(res_x*j + i) + 1]; + ocr->normal[2] = och->ibufs_norm[f]->rect_float[4*(res_x*j + i) + 2]; + } +} + +struct OceanCache *BKE_init_ocean_cache(char *bakepath, int start, int end, float wave_scale, + float chop_amount, float foam_coverage, float foam_fade, int resolution) +{ + OceanCache *och = MEM_callocN(sizeof(OceanCache), "ocean cache data"); + + och->bakepath = bakepath; + och->start = start; + och->end = end; + och->duration = (end - start) + 1; + och->wave_scale = wave_scale; + och->chop_amount = chop_amount; + och->foam_coverage = foam_coverage; + och->foam_fade = foam_fade; + och->resolution_x = resolution*resolution; + och->resolution_y = resolution*resolution; + + och->ibufs_disp = MEM_callocN(sizeof(ImBuf *)*och->duration, "displacement imbuf pointer array"); + och->ibufs_foam = MEM_callocN(sizeof(ImBuf *)*och->duration, "foam imbuf pointer array"); + och->ibufs_norm = MEM_callocN(sizeof(ImBuf *)*och->duration, "normal imbuf pointer array"); + + och->time = NULL; + + return och; +} + +void BKE_simulate_ocean_cache(struct OceanCache *och, int frame) +{ + char string[FILE_MAX]; + int f = frame; + + /* ibufs array is zero based, but filenames are based on frame numbers */ + /* still need to clamp frame numbers to valid range of images on disk though */ + CLAMP(frame, och->start, och->end); + f = frame - och->start; // shift to 0 based + + /* if image is already loaded in mem, return */ + if (och->ibufs_disp[f] != NULL ) return; + + + cache_filename(string, och->bakepath, frame, CACHE_TYPE_DISPLACE); + och->ibufs_disp[f] = IMB_loadiffname(string, 0); + //if (och->ibufs_disp[f] == NULL) printf("error loading %s \n", string); + //else printf("loaded cache %s \n", string); + + cache_filename(string, och->bakepath, frame, CACHE_TYPE_FOAM); + och->ibufs_foam[f] = IMB_loadiffname(string, 0); + //if (och->ibufs_foam[f] == NULL) printf("error loading %s \n", string); + //else printf("loaded cache %s \n", string); + + cache_filename(string, och->bakepath, frame, CACHE_TYPE_NORMAL); + och->ibufs_norm[f] = IMB_loadiffname(string, 0); + //if (och->ibufs_norm[f] == NULL) printf("error loading %s \n", string); + //else printf("loaded cache %s \n", string); +} + + +void BKE_bake_ocean(struct Ocean *o, struct OceanCache *och, void (*update_cb)(void *, float progress, int *cancel), void *update_cb_data) +{ + /* note: some of these values remain uninitialized unless certain options + * are enabled, take care that BKE_ocean_eval_ij() initializes a member + * before use - campbell */ + OceanResult ocr; + + int f, i=0, x, y, cancel=0; + float progress; + + ImBuf *ibuf_foam, *ibuf_disp, *ibuf_normal; + float *prev_foam; + int res_x = och->resolution_x; + int res_y = och->resolution_y; + char string[FILE_MAX]; + + if (!o) return; + + if (o->_do_jacobian) prev_foam = MEM_callocN(res_x*res_y*sizeof(float), "previous frame foam bake data"); + else prev_foam = NULL; + + BLI_srand(0); + + for (f=och->start, i=0; f<=och->end; f++, i++) { + + /* create a new imbuf to store image for this frame */ + ibuf_foam = IMB_allocImBuf(res_x, res_y, 32, IB_rectfloat); + ibuf_disp = IMB_allocImBuf(res_x, res_y, 32, IB_rectfloat); + ibuf_normal = IMB_allocImBuf(res_x, res_y, 32, IB_rectfloat); + + ibuf_disp->profile = ibuf_foam->profile = ibuf_normal->profile = IB_PROFILE_LINEAR_RGB; + + BKE_simulate_ocean(o, och->time[i], och->wave_scale, och->chop_amount); + + /* add new foam */ + for (y=0; y < res_y; y++) { + for (x=0; x < res_x; x++) { + + BKE_ocean_eval_ij(o, &ocr, x, y); + + /* add to the image */ + ibuf_disp->rect_float[4*(res_x*y + x) + 0] = ocr.disp[0]; + ibuf_disp->rect_float[4*(res_x*y + x) + 1] = ocr.disp[1]; + ibuf_disp->rect_float[4*(res_x*y + x) + 2] = ocr.disp[2]; + ibuf_disp->rect_float[4*(res_x*y + x) + 3] = 1.0f; + + if (o->_do_jacobian) { + /* TODO, cleanup unused code - campbell */ + + float /*r,*/ /* UNUSED */ pr=0.0f, foam_result; + float neg_disp, neg_eplus; + + ocr.foam = BKE_ocean_jminus_to_foam(ocr.Jminus, och->foam_coverage); + + /* accumulate previous value for this cell */ + if (i > 0) { + pr = prev_foam[res_x*y + x]; + } + + /* r = BLI_frand(); */ /* UNUSED */ // randomly reduce foam + + //pr = pr * och->foam_fade; // overall fade + + // remember ocean coord sys is Y up! + // break up the foam where height (Y) is low (wave valley), + // and X and Z displacement is greatest + + /* + vec[0] = ocr.disp[0]; + vec[1] = ocr.disp[2]; + hor_stretch = len_v2(vec); + CLAMP(hor_stretch, 0.0, 1.0); + */ + + neg_disp = ocr.disp[1] < 0.0f ? 1.0f+ocr.disp[1] : 1.0f; + neg_disp = neg_disp < 0.0f ? 0.0f : neg_disp; + + /* foam, 'ocr.Eplus' only initialized with do_jacobian */ + neg_eplus = ocr.Eplus[2] < 0.0f ? 1.0f + ocr.Eplus[2]:1.0f; + neg_eplus = neg_eplus<0.0f ? 0.0f : neg_eplus; + + //if (ocr.disp[1] < 0.0 || r > och->foam_fade) + // pr *= och->foam_fade; + + + //pr = pr * (1.0 - hor_stretch) * ocr.disp[1]; + //pr = pr * neg_disp * neg_eplus; + + if (pr < 1.0f) pr *=pr; + + pr *= och->foam_fade * (0.75f + neg_eplus * 0.25f); + + + foam_result = pr + ocr.foam; + + prev_foam[res_x*y + x] = foam_result; + + ibuf_foam->rect_float[4*(res_x*y + x) + 0] = foam_result; + ibuf_foam->rect_float[4*(res_x*y + x) + 1] = foam_result; + ibuf_foam->rect_float[4*(res_x*y + x) + 2] = foam_result; + ibuf_foam->rect_float[4*(res_x*y + x) + 3] = 1.0; + } + + if (o->_do_normals) { + ibuf_normal->rect_float[4*(res_x*y + x) + 0] = ocr.normal[0]; + ibuf_normal->rect_float[4*(res_x*y + x) + 1] = ocr.normal[1]; + ibuf_normal->rect_float[4*(res_x*y + x) + 2] = ocr.normal[2]; + ibuf_normal->rect_float[4*(res_x*y + x) + 3] = 1.0; + } + } + } + + /* write the images */ + cache_filename(string, och->bakepath, f, CACHE_TYPE_DISPLACE); + if(0 == BKE_write_ibuf(ibuf_disp, string, R_OPENEXR, R_OPENEXR_HALF, 2)) // 2 == ZIP exr codec + printf("Cannot save Displacement File Output to %s\n", string); + + if (o->_do_jacobian) { + cache_filename(string, och->bakepath, f, CACHE_TYPE_FOAM); + if(0 == BKE_write_ibuf(ibuf_foam, string, R_OPENEXR, R_OPENEXR_HALF, 2)) // 2 == ZIP exr codec + printf("Cannot save Foam File Output to %s\n", string); + } + + if (o->_do_normals) { + cache_filename(string, och->bakepath, f, CACHE_TYPE_NORMAL); + if(0 == BKE_write_ibuf(ibuf_normal, string, R_OPENEXR, R_OPENEXR_HALF, 2)) // 2 == ZIP exr codec + printf("Cannot save Normal File Output to %s\n", string); + } + + IMB_freeImBuf(ibuf_disp); + IMB_freeImBuf(ibuf_foam); + IMB_freeImBuf(ibuf_normal); + + progress = (f - och->start) / (float)och->duration; + + update_cb(update_cb_data, progress, &cancel); + + if (cancel) { + if (prev_foam) MEM_freeN(prev_foam); + return; + } + } + + if (prev_foam) MEM_freeN(prev_foam); + och->baked = 1; +} + +#else // WITH_OCEANSIM + +/* stub */ +typedef struct Ocean { + /* need some data here, C does not allow empty struct */ + int stub; +} Ocean; + + +float BKE_ocean_jminus_to_foam(float UNUSED(jminus), float UNUSED(coverage)) { + return 0.0f; +} + +void BKE_ocean_eval_uv(struct Ocean *UNUSED(oc), struct OceanResult *UNUSED(ocr), float UNUSED(u),float UNUSED(v)) +{ +} + +// use catmullrom interpolation rather than linear +void BKE_ocean_eval_uv_catrom(struct Ocean *UNUSED(oc), struct OceanResult *UNUSED(ocr), float UNUSED(u),float UNUSED(v)) +{ +} + +void BKE_ocean_eval_xz(struct Ocean *UNUSED(oc), struct OceanResult *UNUSED(ocr), float UNUSED(x),float UNUSED(z)) +{ +} + +void BKE_ocean_eval_xz_catrom(struct Ocean *UNUSED(oc), struct OceanResult *UNUSED(ocr), float UNUSED(x),float UNUSED(z)) +{ +} + +void BKE_ocean_eval_ij(struct Ocean *UNUSED(oc), struct OceanResult *UNUSED(ocr), int UNUSED(i),int UNUSED(j)) +{ +} + +void BKE_simulate_ocean(struct Ocean *UNUSED(o), float UNUSED(t), float UNUSED(scale), float UNUSED(chop_amount)) +{ +} + +struct Ocean *BKE_add_ocean(void) +{ + Ocean *oc = MEM_callocN(sizeof(Ocean), "ocean sim data"); + + return oc; +} + +void BKE_init_ocean(struct Ocean* UNUSED(o), int UNUSED(M),int UNUSED(N), float UNUSED(Lx), float UNUSED(Lz), float UNUSED(V), float UNUSED(l), float UNUSED(A), float UNUSED(w), float UNUSED(damp), + float UNUSED(alignment), float UNUSED(depth), float UNUSED(time), short UNUSED(do_height_field), short UNUSED(do_chop), short UNUSED(do_normals), short UNUSED(do_jacobian), int UNUSED(seed)) +{ +} + +void BKE_free_ocean_data(struct Ocean *UNUSED(oc)) +{ +} + +void BKE_free_ocean(struct Ocean *oc) +{ + if(!oc) return; + MEM_freeN(oc); +} + + +/* ********* Baking/Caching ********* */ + + +void BKE_free_ocean_cache(struct OceanCache *och) +{ + if (!och) return; + + MEM_freeN(och); +} + +void BKE_ocean_cache_eval_uv(struct OceanCache *UNUSED(och), struct OceanResult *UNUSED(ocr), int UNUSED(f), float UNUSED(u), float UNUSED(v)) +{ +} + +void BKE_ocean_cache_eval_ij(struct OceanCache *UNUSED(och), struct OceanResult *UNUSED(ocr), int UNUSED(f), int UNUSED(i), int UNUSED(j)) +{ +} + +struct OceanCache *BKE_init_ocean_cache(char *UNUSED(bakepath), int UNUSED(start), int UNUSED(end), float UNUSED(wave_scale), + float UNUSED(chop_amount), float UNUSED(foam_coverage), float UNUSED(foam_fade), int UNUSED(resolution)) +{ + OceanCache *och = MEM_callocN(sizeof(OceanCache), "ocean cache data"); + + return och; +} + +void BKE_simulate_ocean_cache(struct OceanCache *UNUSED(och), int UNUSED(frame)) +{ +} + +void BKE_bake_ocean(struct Ocean *UNUSED(o), struct OceanCache *UNUSED(och), void (*update_cb)(void *, float progress, int *cancel), void *UNUSED(update_cb_data)) +{ + /* unused */ + (void)update_cb; +} +#endif // WITH_OCEANSIM diff --git a/source/blender/blenkernel/intern/text.c b/source/blender/blenkernel/intern/text.c index e8be0bb2608..5735a95764b 100644 --- a/source/blender/blenkernel/intern/text.c +++ b/source/blender/blenkernel/intern/text.c @@ -796,6 +796,7 @@ void txt_move_left(Text *text, short sel) { TextLine **linep; int *charp, oundoing= undoing; + int tabsize = 1, i=0; if (!text) return; if(sel) txt_curs_sel(text, &linep, &charp); @@ -803,14 +804,34 @@ void txt_move_left(Text *text, short sel) if (!*linep) return; undoing= 1; + + // do nice left only if there are only spaces + // TXT_TABSIZE hardcoded in DNA_text_types.h + if (text->flags & TXT_TABSTOSPACES) { + tabsize = TXT_TABSIZE; + + if (*charp < tabsize) + tabsize = *charp; + else { + for (i=0;i<(*charp);i++) + if ((*linep)->line[i] != ' ') { + tabsize = 1; + break; + } + // if in the middle of the space-tab + if ((*charp) % tabsize != 0) + tabsize = ((*charp) % tabsize); + } + } + if (*charp== 0) { if ((*linep)->prev) { txt_move_up(text, sel); *charp= (*linep)->len; } - } else { - (*charp)--; } + else (*charp)-= tabsize; + undoing= oundoing; if(!undoing) txt_undo_add_op(text, sel?UNDO_SLEFT:UNDO_CLEFT); @@ -821,6 +842,7 @@ void txt_move_right(Text *text, short sel) { TextLine **linep; int *charp, oundoing= undoing; + int tabsize=1, i=0; if (!text) return; if(sel) txt_curs_sel(text, &linep, &charp); @@ -828,13 +850,32 @@ void txt_move_right(Text *text, short sel) if (!*linep) return; undoing= 1; + + // do nice right only if there are only spaces + // spaces hardcoded in DNA_text_types.h + if (text->flags & TXT_TABSTOSPACES) { + tabsize = TXT_TABSIZE; + + if ((*charp) + tabsize > (*linep)->len) + tabsize = 1; + else { + for (i=0;i<(*charp) + tabsize - ((*charp) % tabsize);i++) + if ((*linep)->line[i] != ' ') { + tabsize = 1; + break; + } + // if in the middle of the space-tab + tabsize -= (*charp) % tabsize; + } + } + if (*charp== (*linep)->len) { if ((*linep)->next) { txt_move_down(text, sel); *charp= 0; } } else { - (*charp)++; + (*charp)+=tabsize; } undoing= oundoing; if(!undoing) txt_undo_add_op(text, sel?UNDO_SRIGHT:UNDO_CRIGHT); diff --git a/source/blender/blenkernel/intern/texture.c b/source/blender/blenkernel/intern/texture.c index c80b2880d12..db4d09e38b3 100644 --- a/source/blender/blenkernel/intern/texture.c +++ b/source/blender/blenkernel/intern/texture.c @@ -60,6 +60,7 @@ #include "BKE_utildefines.h" #include "BKE_global.h" #include "BKE_main.h" +#include "BKE_ocean.h" #include "BKE_library.h" #include "BKE_image.h" @@ -71,6 +72,7 @@ #include "BKE_animsys.h" #include "BKE_colortools.h" + /* ------------------------------------------------------------------------- */ /* All support for plugin textures: */ @@ -227,7 +229,7 @@ void default_tex_mapping(TexMapping *texmap) void init_tex_mapping(TexMapping *texmap) { - float eul[3], smat[3][3], rmat[3][3], mat[3][3], proj[3][3]; + float smat[3][3], rmat[3][3], mat[3][3], proj[3][3]; if(texmap->projx == PROJ_X && texmap->projy == PROJ_Y && texmap->projz == PROJ_Z && is_zero_v3(texmap->loc) && is_zero_v3(texmap->rot) && is_one_v3(texmap->size)) { @@ -250,10 +252,8 @@ void init_tex_mapping(TexMapping *texmap) size_to_mat3(smat, texmap->size); /* rotation */ - eul[0]= DEG2RADF(texmap->rot[0]); - eul[1]= DEG2RADF(texmap->rot[1]); - eul[2]= DEG2RADF(texmap->rot[2]); - eul_to_mat3( rmat,eul); + /* XXX TexMapping rotation are now in radians. */ + eul_to_mat3(rmat, texmap->rot); /* compose it all */ mul_m3_m3m3(mat, rmat, smat); @@ -546,6 +546,7 @@ void free_texture(Tex *tex) if(tex->env) BKE_free_envmap(tex->env); if(tex->pd) BKE_free_pointdensity(tex->pd); if(tex->vd) BKE_free_voxeldata(tex->vd); + if(tex->ot) BKE_free_oceantex(tex->ot); BKE_free_animdata((struct ID *)tex); BKE_previewimg_free(&tex->preview); @@ -628,6 +629,11 @@ void default_tex(Tex *tex) tex->vd->interp_type=TEX_VD_LINEAR; tex->vd->file_format=TEX_VD_SMOKE; } + + if (tex->ot) { + tex->ot->output = TEX_OCN_DISPLACEMENT; + tex->ot->object = NULL; + } pit = tex->plugin; if (pit) { varstr= pit->varstr; @@ -662,6 +668,10 @@ void tex_set_type(Tex *tex, int type) if (tex->env == NULL) tex->env = BKE_add_envmap(); break; + case TEX_OCEAN: + if (tex->ot == NULL) + tex->ot = BKE_add_oceantex(); + break; } tex->type = type; @@ -826,6 +836,7 @@ Tex *copy_texture(Tex *tex) if(texn->env) texn->env= BKE_copy_envmap(texn->env); if(texn->pd) texn->pd= BKE_copy_pointdensity(texn->pd); if(texn->vd) texn->vd= MEM_dupallocN(texn->vd); + if(texn->ot) texn->ot= BKE_copy_oceantex(texn->ot); if(tex->preview) texn->preview = BKE_previewimg_copy(tex->preview); if(tex->nodetree) { @@ -864,6 +875,9 @@ Tex *localize_texture(Tex *tex) if(texn->vd->dataset) texn->vd->dataset= MEM_dupallocN(texn->vd->dataset); } + if(texn->ot) { + texn->ot= BKE_copy_oceantex(tex->ot); + } texn->preview = NULL; @@ -1039,7 +1053,7 @@ void autotexname(Tex *tex) Main *bmain= G.main; char texstr[20][15]= {"None" , "Clouds" , "Wood", "Marble", "Magic" , "Blend", "Stucci", "Noise" , "Image", "Plugin", "EnvMap" , "Musgrave", - "Voronoi", "DistNoise", "Point Density", "Voxel Data", "", "", "", ""}; + "Voronoi", "DistNoise", "Point Density", "Voxel Data", "Ocean", "", "", ""}; Image *ima; char di[FILE_MAXDIR], fi[FILE_MAXFILE]; @@ -1469,6 +1483,7 @@ void BKE_free_pointdensity(PointDensity *pd) MEM_freeN(pd); } +/* ------------------------------------------------------------------------- */ void BKE_free_voxeldatadata(struct VoxelData *vd) { @@ -1513,6 +1528,31 @@ struct VoxelData *BKE_copy_voxeldata(struct VoxelData *vd) return vdn; } +/* ------------------------------------------------------------------------- */ + +struct OceanTex *BKE_add_oceantex(void) +{ + OceanTex *ot; + + ot= MEM_callocN(sizeof(struct OceanTex), "ocean texture"); + ot->output = TEX_OCN_DISPLACEMENT; + ot->object = NULL; + + return ot; +} + +struct OceanTex *BKE_copy_oceantex(struct OceanTex *ot) +{ + OceanTex *otn= MEM_dupallocN(ot); + + return otn; +} + +void BKE_free_oceantex(struct OceanTex *ot) +{ + MEM_freeN(ot); +} + /* ------------------------------------------------------------------------- */ int BKE_texture_dependsOnTime(const struct Tex *texture) diff --git a/source/blender/blenkernel/intern/tracking.c b/source/blender/blenkernel/intern/tracking.c index 65b27f725bc..d582ad7c4d8 100644 --- a/source/blender/blenkernel/intern/tracking.c +++ b/source/blender/blenkernel/intern/tracking.c @@ -47,6 +47,7 @@ #include "BLI_listbase.h" #include "BLI_ghash.h" #include "BLI_path_util.h" +#include "BLI_string.h" #include "BKE_global.h" #include "BKE_tracking.h" @@ -119,10 +120,6 @@ void BKE_tracking_clamp_track(MovieTrackingTrack *track, int event) } } else if(event==CLAMP_SEARCH_DIM) { - float max_pyramid_level_factor = 1.0; - if (track->tracker == TRACKER_KLT) { - max_pyramid_level_factor = 1 << (track->pyramid_levels - 1); - } for(a= 0; a<2; a++) { /* search shouldn't be resized smaller than pattern */ track->search_min[a]= MIN2(pat_min[a], track->search_min[a]); @@ -145,7 +142,6 @@ void BKE_tracking_clamp_track(MovieTrackingTrack *track, int event) } } } - else if(event==CLAMP_PYRAMID_LEVELS || (event==CLAMP_SEARCH_DIM && track->tracker == TRACKER_KLT)) { float dim[2]; sub_v2_v2v2(dim, track->pat_max, track->pat_min); @@ -618,18 +614,23 @@ MovieTrackingContext *BKE_tracking_context_new(MovieClip *clip, MovieClipUser *u float search_size_y= (track->search_max[1]-track->search_min[1])*height; float pattern_size_x= (track->pat_max[0]-track->pat_min[0])*width; float pattern_size_y= (track->pat_max[1]-track->pat_min[1])*height; + int wndx, wndy; /* compute the maximum pyramid size */ - double search_to_pattern_ratio= MIN2(search_size_x, search_size_y) + float search_to_pattern_ratio= MIN2(search_size_x, search_size_y) / MAX2(pattern_size_x, pattern_size_y); - double log2_search_to_pattern_ratio = log(floor(search_to_pattern_ratio)) / M_LN2; + float log2_search_to_pattern_ratio = log(floor(search_to_pattern_ratio)) / M_LN2; int max_pyramid_levels= floor(log2_search_to_pattern_ratio + 1); /* try to accomodate the user's choice of pyramid level in a way * that doesn't cause the coarsest pyramid pattern to be larger * than the search size */ int level= MIN2(track_context->track->pyramid_levels, max_pyramid_levels); - track_context->region_tracker= libmv_regionTrackerNew(100, level); + + wndx= (int)((track->pat_max[0]-track->pat_min[0])*width)/2; + wndy= (int)((track->pat_max[1]-track->pat_min[1])*height)/2; + + track_context->region_tracker= libmv_regionTrackerNew(100, level, MAX2(wndx, wndy)); } else if(track_context->track->tracker==TRACKER_SAD) { /* nothing to initialize */ @@ -879,7 +880,7 @@ static ImBuf *get_keyframed_ibuf(MovieTrackingContext *context, MovieTrackingTra while(a>=0 && a<track->markersnr) { int next= (context->backwards) ? a+1 : a-1; int is_keyframed= 0; - MovieTrackingMarker *marker= &track->markers[a]; + MovieTrackingMarker *cur_marker= &track->markers[a]; MovieTrackingMarker *next_marker= NULL; if(next>=0 && next<track->markersnr) @@ -889,11 +890,11 @@ static ImBuf *get_keyframed_ibuf(MovieTrackingContext *context, MovieTrackingTra if(next_marker && next_marker->flag&MARKER_DISABLED) is_keyframed= 1; - is_keyframed|= (marker->flag&MARKER_TRACKED)==0; + is_keyframed|= (cur_marker->flag&MARKER_TRACKED)==0; if(is_keyframed) { - framenr= marker->framenr; - *marker_keyed= marker; + framenr= cur_marker->framenr; + *marker_keyed= cur_marker; break; } @@ -1079,7 +1080,6 @@ int BKE_tracking_next(MovieTrackingContext *context) onbound= 1; } else if(track_context->track->tracker==TRACKER_KLT) { - int wndx, wndy; float *patch_new; if(need_readjust) { @@ -1102,11 +1102,8 @@ int BKE_tracking_next(MovieTrackingContext *context) x2= pos[0]; y2= pos[1]; - wndx= (int)((track->pat_max[0]-track->pat_min[0])*ibuf_new->x)/2; - wndy= (int)((track->pat_max[1]-track->pat_min[1])*ibuf_new->y)/2; - tracked= libmv_regionTrackerTrack(track_context->region_tracker, track_context->patch, patch_new, - width, height, MAX2(wndx, wndy), x1, y1, &x2, &y2); + width, height, x1, y1, &x2, &y2); MEM_freeN(patch_new); } @@ -1260,7 +1257,28 @@ static struct libmv_Tracks *create_libmv_tracks(MovieTracking *tracking, int wid return tracks; } -static int retrieve_libmv_reconstruct(MovieTracking *tracking, struct libmv_Reconstruction *libmv_reconstruction) +static void retrieve_libmv_reconstruct_intrinscis(MovieTracking *tracking, struct libmv_Reconstruction *libmv_reconstruction) +{ + struct libmv_CameraIntrinsics *libmv_intrinsics = libmv_ReconstructionExtractIntrinsics(libmv_reconstruction); + + float aspy= 1.0f/tracking->camera.pixel_aspect; + + double focal_length, principal_x, principal_y, k1, k2, k3; + int width, height; + + libmv_CameraIntrinsicsExtract(libmv_intrinsics, &focal_length, &principal_x, &principal_y, + &k1, &k2, &k3, &width, &height); + + tracking->camera.focal= focal_length; + tracking->camera.principal[0]= principal_x; + + /* todo: verify divide by aspy is correct */ + tracking->camera.principal[1]= principal_y / aspy; + tracking->camera.k1= k1; + tracking->camera.k2= k2; +} + +static int retrieve_libmv_reconstruct_tracks(MovieTracking *tracking, struct libmv_Reconstruction *libmv_reconstruction) { int tracknr= 0; int sfra= INT_MAX, efra= INT_MIN, a, origin_set= 0; @@ -1289,8 +1307,27 @@ static int retrieve_libmv_reconstruct(MovieTracking *tracking, struct libmv_Reco } if(track->markersnr) { - if(track->markers[0].framenr<sfra) sfra= track->markers[0].framenr; - if(track->markers[track->markersnr-1].framenr>efra) efra= track->markers[track->markersnr-1].framenr; + int first= 0, last= track->markersnr; + MovieTrackingMarker *first_marker= &track->markers[0]; + MovieTrackingMarker *last_marker= &track->markers[track->markersnr-1]; + + /* find first not-disabled marker */ + while(first<track->markersnr-1 && first_marker->flag&MARKER_DISABLED) { + first++; + first_marker++; + } + + /* find last not-disabled marker */ + while(last>=0 && last_marker->flag&MARKER_DISABLED) { + last--; + last_marker--; + } + + if(first<track->markersnr-1) + sfra= MIN2(sfra, first_marker->framenr); + + if(last>=0) + efra= MAX2(efra, last_marker->framenr); } track= track->next; @@ -1354,8 +1391,70 @@ static int retrieve_libmv_reconstruct(MovieTracking *tracking, struct libmv_Reco return ok; } +static int retrieve_libmv_reconstruct(MovieTracking *tracking, struct libmv_Reconstruction *libmv_reconstruction) +{ + /* take the intrinscis back from libmv */ + retrieve_libmv_reconstruct_intrinscis(tracking, libmv_reconstruction); + + return retrieve_libmv_reconstruct_tracks(tracking, libmv_reconstruction); +} + +static int get_refine_intrinsics_flags(MovieTracking *tracking) +{ + int refine= tracking->settings.refine_camera_intrinsics; + int flags= 0; + + if(refine&REFINE_FOCAL_LENGTH) + flags|= LIBMV_REFINE_FOCAL_LENGTH; + + if(refine&REFINE_PRINCIPAL_POINT) + flags|= LIBMV_REFINE_PRINCIPAL_POINT; + + if(refine&REFINE_RADIAL_DISTORTION_K1) + flags|= REFINE_RADIAL_DISTORTION_K1; + + if(refine&REFINE_RADIAL_DISTORTION_K2) + flags|= REFINE_RADIAL_DISTORTION_K2; + + return flags; +} + +static int count_tracks_on_both_keyframes(MovieTracking *tracking) +{ + int tot= 0; + int frame1= tracking->settings.keyframe1, frame2= tracking->settings.keyframe2; + MovieTrackingTrack *track; + + track= tracking->tracks.first; + while(track) { + if(BKE_tracking_has_marker(track, frame1)) + if(BKE_tracking_has_marker(track, frame2)) + tot++; + + track= track->next; + } + + return tot; +} #endif +int BKE_tracking_can_solve(MovieTracking *tracking, char *error_msg, int error_size) +{ +#if WITH_LIBMV + if(count_tracks_on_both_keyframes(tracking)<8) { + BLI_strncpy(error_msg, "At least 8 tracks on both of keyframes are needed for reconstruction", error_size); + return 0; + } + + return 1; +#else + BLI_strncpy(error_msg, "Blender is compiled without motion tracking library", error_size); + (void)tracking; + + return 0; +#endif +} + float BKE_tracking_solve_reconstruction(MovieTracking *tracking, int width, int height) { #if WITH_LIBMV @@ -1365,6 +1464,7 @@ float BKE_tracking_solve_reconstruction(MovieTracking *tracking, int width, int struct libmv_Tracks *tracks= create_libmv_tracks(tracking, width, height*aspy); struct libmv_Reconstruction *reconstruction = libmv_solveReconstruction(tracks, tracking->settings.keyframe1, tracking->settings.keyframe2, + get_refine_intrinsics_flags(tracking), camera->focal, camera->principal[0], camera->principal[1]*aspy, camera->k1, camera->k2, camera->k3); |