Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCampbell Barton <ideasman42@gmail.com>2011-11-15 06:58:06 +0400
committerCampbell Barton <ideasman42@gmail.com>2011-11-15 06:58:06 +0400
commite6e265b2b59e02cc7816a2ed43471eca8bca0a62 (patch)
treee312d2c2f6cb1aaf79148648e5725902ab23d34e /source/blender/blenkernel/intern
parente59ab6486f9e7285815671044b785c28365d5165 (diff)
parent3442c16c09b31a23f45b23be72e6eb5ba02c7bbf (diff)
svn merge -r41779:41847 ^/trunk/blender
Diffstat (limited to 'source/blender/blenkernel/intern')
-rw-r--r--source/blender/blenkernel/intern/camera.c140
-rw-r--r--source/blender/blenkernel/intern/cdderivedmesh.c2
-rw-r--r--source/blender/blenkernel/intern/constraint.c3
-rw-r--r--source/blender/blenkernel/intern/dynamicpaint.c16
-rw-r--r--source/blender/blenkernel/intern/implicit.c2
-rw-r--r--source/blender/blenkernel/intern/mesh_validate.c2
-rw-r--r--source/blender/blenkernel/intern/object.c63
-rw-r--r--source/blender/blenkernel/intern/ocean.c1421
-rw-r--r--source/blender/blenkernel/intern/text.c47
-rw-r--r--source/blender/blenkernel/intern/texture.c52
-rw-r--r--source/blender/blenkernel/intern/tracking.c140
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);