~ubuntu-branches/ubuntu/gutsy/blender/gutsy-security

« back to all changes in this revision

Viewing changes to source/blender/src/transform_constraints.c

  • Committer: Bazaar Package Importer
  • Author(s): Florian Ernst
  • Date: 2005-11-06 12:40:03 UTC
  • mfrom: (1.1.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20051106124003-3pgs7tcg5rox96xg
Tags: 2.37a-1.1
* Non-maintainer upload.
* Split out parts of 01_SConstruct_debian.dpatch again: root_build_dir
  really needs to get adjusted before the clean target runs - closes: #333958,
  see #288882 for reference

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/**
 
2
 * $Id: transform_constraints.c,v 1.54 2005/06/05 13:50:21 theeth Exp $
 
3
 *
 
4
 * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
 
5
 *
 
6
 * This program is free software; you can redistribute it and/or
 
7
 * modify it under the terms of the GNU General Public License
 
8
 * as published by the Free Software Foundation; either version 2
 
9
 * of the License, or (at your option) any later version. The Blender
 
10
 * Foundation also sells licenses for use in proprietary software under
 
11
 * the Blender License.  See http://www.blender.org/BL/ for information
 
12
 * about this.
 
13
 *
 
14
 * This program is distributed in the hope that it will be useful,
 
15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
17
 * GNU General Public License for more details.
 
18
 *
 
19
 * You should have received a copy of the GNU General Public License
 
20
 * along with this program; if not, write to the Free Software Foundation,
 
21
 * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
22
 *
 
23
 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
 
24
 * All rights reserved.
 
25
 *
 
26
 * The Original Code is: all of this file.
 
27
 *
 
28
 * Contributor(s): none yet.
 
29
 *
 
30
 * ***** END GPL/BL DUAL LICENSE BLOCK *****
 
31
 */
 
32
 
 
33
#include <stdlib.h>
 
34
#include <string.h>
 
35
#include <math.h>
 
36
 
 
37
#ifdef HAVE_CONFIG_H
 
38
#include <config.h>
 
39
#endif
 
40
 
 
41
#ifndef WIN32
 
42
#include <unistd.h>
 
43
#else
 
44
#include <io.h>
 
45
#endif
 
46
 
 
47
#include "MEM_guardedalloc.h"
 
48
 
 
49
#include "DNA_action_types.h"
 
50
#include "DNA_armature_types.h"
 
51
#include "DNA_camera_types.h"
 
52
#include "DNA_curve_types.h"
 
53
#include "DNA_effect_types.h"
 
54
#include "DNA_ika_types.h"
 
55
#include "DNA_image_types.h"
 
56
#include "DNA_ipo_types.h"
 
57
#include "DNA_key_types.h"
 
58
#include "DNA_lamp_types.h"
 
59
#include "DNA_lattice_types.h"
 
60
#include "DNA_mesh_types.h"
 
61
#include "DNA_meshdata_types.h"
 
62
#include "DNA_meta_types.h"
 
63
#include "DNA_object_types.h"
 
64
#include "DNA_scene_types.h"
 
65
#include "DNA_screen_types.h"
 
66
#include "DNA_texture_types.h"
 
67
#include "DNA_view3d_types.h"
 
68
#include "DNA_world_types.h"
 
69
#include "DNA_userdef_types.h"
 
70
#include "DNA_property_types.h"
 
71
#include "DNA_vfont_types.h"
 
72
#include "DNA_constraint_types.h"
 
73
 
 
74
#include "BIF_screen.h"
 
75
#include "BIF_space.h"
 
76
#include "BIF_editview.h"
 
77
#include "BIF_resources.h"
 
78
#include "BIF_mywindow.h"
 
79
#include "BIF_gl.h"
 
80
#include "BIF_editlattice.h"
 
81
#include "BIF_editarmature.h"
 
82
#include "BIF_editmesh.h"
 
83
 
 
84
#include "BKE_global.h"
 
85
#include "BKE_object.h"
 
86
#include "BKE_utildefines.h"
 
87
#include "BKE_lattice.h"
 
88
#include "BKE_armature.h"
 
89
#include "BKE_curve.h"
 
90
#include "BKE_displist.h"
 
91
 
 
92
#include "BSE_view.h"
 
93
#include "BSE_edit.h"
 
94
 
 
95
#include "BLI_arithb.h"
 
96
#include "BLI_editVert.h"
 
97
 
 
98
#include "BDR_drawobject.h"
 
99
 
 
100
#include "blendef.h"
 
101
 
 
102
#include "mydevice.h"
 
103
 
 
104
#include "transform.h"
 
105
 
 
106
extern ListBase editNurb;
 
107
extern ListBase editelems;
 
108
 
 
109
void recalcData();
 
110
 
 
111
/* ************************** CONSTRAINTS ************************* */
 
112
void getConstraintMatrix(TransInfo *t);
 
113
 
 
114
void constraintNumInput(TransInfo *t, float vec[3])
 
115
{
 
116
        int mode = t->con.mode;
 
117
        if (mode & CON_APPLY) {
 
118
                float nval = (t->flag & T_NULL_ONE)?1.0f:0.0f;
 
119
 
 
120
                if (getConstraintSpaceDimension(t) == 2) {
 
121
                        if (mode & (CON_AXIS0|CON_AXIS1)) {
 
122
                                vec[2] = nval;
 
123
                        }
 
124
                        else if (mode & (CON_AXIS1|CON_AXIS2)) {
 
125
                                vec[2] = vec[1];
 
126
                                vec[1] = vec[0];
 
127
                                vec[0] = nval;
 
128
                        }
 
129
                        else if (mode & (CON_AXIS0|CON_AXIS2)) {
 
130
                                vec[2] = vec[1];
 
131
                                vec[1] = nval;
 
132
                        }
 
133
                }
 
134
                else if (getConstraintSpaceDimension(t) == 1) {
 
135
                        if (mode & CON_AXIS0) {
 
136
                                vec[1] = nval;
 
137
                                vec[2] = nval;
 
138
                        }
 
139
                        else if (mode & CON_AXIS1) {
 
140
                                vec[1] = vec[0];
 
141
                                vec[0] = nval;
 
142
                                vec[2] = nval;
 
143
                        }
 
144
                        else if (mode & CON_AXIS2) {
 
145
                                vec[2] = vec[0];
 
146
                                vec[0] = nval;
 
147
                                vec[1] = nval;
 
148
                        }
 
149
                }
 
150
        }
 
151
}
 
152
 
 
153
static void postConstraintChecks(TransInfo *t, float vec[3], float pvec[3]) {
 
154
        int i = 0;
 
155
 
 
156
        Mat3MulVecfl(t->con.imtx, vec);
 
157
 
 
158
        snapGrid(t, vec);
 
159
 
 
160
        if (t->num.flag & T_NULL_ONE) {
 
161
                if (!(t->con.mode & CON_AXIS0))
 
162
                        vec[0] = 1.0f;
 
163
 
 
164
                if (!(t->con.mode & CON_AXIS1))
 
165
                        vec[1] = 1.0f;
 
166
 
 
167
                if (!(t->con.mode & CON_AXIS2))
 
168
                        vec[2] = 1.0f;
 
169
        }
 
170
 
 
171
        if (hasNumInput(&t->num)) {
 
172
                applyNumInput(&t->num, vec);
 
173
                constraintNumInput(t, vec);
 
174
        }
 
175
        
 
176
        if (t->con.mode & CON_AXIS0) {
 
177
                pvec[i++] = vec[0];
 
178
        }
 
179
        if (t->con.mode & CON_AXIS1) {
 
180
                pvec[i++] = vec[1];
 
181
        }
 
182
        if (t->con.mode & CON_AXIS2) {
 
183
                pvec[i++] = vec[2];
 
184
        }
 
185
 
 
186
        Mat3MulVecfl(t->con.mtx, vec);
 
187
}
 
188
 
 
189
 
 
190
static void axisProjection(TransInfo *t, float axis[3], float in[3], float out[3]) {
 
191
        float norm[3], n[3], vec[3], factor;
 
192
 
 
193
        VecAddf(vec, in, t->con.center);
 
194
        getViewVector(vec, norm);
 
195
 
 
196
        Normalise(axis);
 
197
 
 
198
        VECCOPY(n, axis);
 
199
        Mat4MulVecfl(t->viewmat, n);
 
200
        n[2] = t->viewmat[3][2];
 
201
        Mat4MulVecfl(t->viewinv, n);
 
202
 
 
203
        /* For when view is parallel to constraint... will cause NaNs otherwise
 
204
           So we take vertical motion in 3D space and apply it to the
 
205
           constraint axis. Nice for camera grab + MMB */
 
206
        if(n[0]*n[0] + n[1]*n[1] + n[2]*n[2] < 0.000001f) {
 
207
                Projf(vec, in, t->viewinv[1]);
 
208
                factor = Inpf(t->viewinv[1], vec) * 2.0f;
 
209
                /* since camera distance is quite relative, use quadratic relationship. holding shift can compensate */
 
210
                if(factor<0.0f) factor*= -factor;
 
211
                else factor*= factor;
 
212
                
 
213
                VECCOPY(out, axis);
 
214
                Normalise(out);
 
215
                VecMulf(out, -factor);  /* -factor makes move down going backwards */
 
216
        }
 
217
        else {
 
218
                // prevent division by zero, happens on constrainting without initial delta transform */
 
219
                if(in[0]!=0.0f || in[1]!=0.0f || in[2]!=0.0) {
 
220
                        Projf(vec, in, n);
 
221
                        factor = Normalise(vec);
 
222
                        // prevent NaN for 0.0/0.0
 
223
                        if(factor!=0.0f)
 
224
                                factor /= Inpf(axis, vec);
 
225
 
 
226
                        VecMulf(axis, factor);
 
227
                        VECCOPY(out, axis);
 
228
                }
 
229
        }
 
230
}
 
231
 
 
232
static void planeProjection(TransInfo *t, float in[3], float out[3]) {
 
233
        float vec[3], factor, angle, norm[3];
 
234
 
 
235
        VecAddf(vec, in, t->con.center);
 
236
        getViewVector(vec, norm);
 
237
 
 
238
        VecSubf(vec, out, in);
 
239
        factor = Normalise(vec);
 
240
        angle = Inpf(vec, norm);
 
241
 
 
242
        if (angle * angle >= 0.000001f) {
 
243
                factor /= angle;
 
244
 
 
245
                VECCOPY(vec, norm);
 
246
                VecMulf(vec, factor);
 
247
 
 
248
                VecAddf(out, in, vec);
 
249
        }
 
250
}
 
251
 
 
252
/*
 
253
 * Generic callback for constant spacial constraints applied to linear motion
 
254
 * 
 
255
 * The IN vector in projected into the constrained space and then further
 
256
 * projected along the view vector.
 
257
 * (in perspective mode, the view vector is relative to the position on screen)
 
258
 *
 
259
 */
 
260
 
 
261
static void applyAxisConstraintVec(TransInfo *t, TransData *td, float in[3], float out[3], float pvec[3])
 
262
{
 
263
        VECCOPY(out, in);
 
264
        if (!td && t->con.mode & CON_APPLY) {
 
265
                Mat3MulVecfl(t->con.pmtx, out);
 
266
                if (getConstraintSpaceDimension(t) == 2) {
 
267
                        if (out[0] != 0.0f || out[1] != 0.0f || out[2] != 0.0f) {
 
268
                                planeProjection(t, in, out);
 
269
                        }
 
270
                }
 
271
                else if (getConstraintSpaceDimension(t) == 1) {
 
272
                        float c[3];
 
273
 
 
274
                        if (t->con.mode & CON_AXIS0) {
 
275
                                VECCOPY(c, t->con.mtx[0]);
 
276
                        }
 
277
                        else if (t->con.mode & CON_AXIS1) {
 
278
                                VECCOPY(c, t->con.mtx[1]);
 
279
                        }
 
280
                        else if (t->con.mode & CON_AXIS2) {
 
281
                                VECCOPY(c, t->con.mtx[2]);
 
282
                        }
 
283
                        axisProjection(t, c, in, out);
 
284
                }
 
285
                postConstraintChecks(t, out, pvec);
 
286
        }
 
287
}
 
288
 
 
289
/*
 
290
 * Generic callback for object based spacial constraints applied to linear motion
 
291
 * 
 
292
 * At first, the following is applied to the first data in the array
 
293
 * The IN vector in projected into the constrained space and then further
 
294
 * projected along the view vector.
 
295
 * (in perspective mode, the view vector is relative to the position on screen)
 
296
 *
 
297
 * Further down, that vector is mapped to each data's space.
 
298
 */
 
299
 
 
300
static void applyObjectConstraintVec(TransInfo *t, TransData *td, float in[3], float out[3], float pvec[3])
 
301
{
 
302
        VECCOPY(out, in);
 
303
        if (t->con.mode & CON_APPLY) {
 
304
                if (!td) {
 
305
                        Mat3MulVecfl(t->con.pmtx, out);
 
306
                        if (getConstraintSpaceDimension(t) == 2) {
 
307
                                if (out[0] != 0.0f || out[1] != 0.0f || out[2] != 0.0f) {
 
308
                                        planeProjection(t, in, out);
 
309
                                }
 
310
                        }
 
311
                        else if (getConstraintSpaceDimension(t) == 1) {
 
312
                                float c[3];
 
313
 
 
314
                                if (t->con.mode & CON_AXIS0) {
 
315
                                        VECCOPY(c, t->con.mtx[0]);
 
316
                                }
 
317
                                else if (t->con.mode & CON_AXIS1) {
 
318
                                        VECCOPY(c, t->con.mtx[1]);
 
319
                                }
 
320
                                else if (t->con.mode & CON_AXIS2) {
 
321
                                        VECCOPY(c, t->con.mtx[2]);
 
322
                                }
 
323
                                axisProjection(t, c, in, out);
 
324
                        }
 
325
                        postConstraintChecks(t, out, pvec);
 
326
                        VECCOPY(out, pvec);
 
327
                }
 
328
                else {
 
329
                        Mat3MulVecfl(td->axismtx, out);
 
330
                }
 
331
        }
 
332
}
 
333
 
 
334
/*
 
335
 * Generic callback for constant spacial constraints applied to resize motion
 
336
 * 
 
337
 *
 
338
 */
 
339
 
 
340
static void applyAxisConstraintSize(TransInfo *t, TransData *td, float smat[3][3])
 
341
{
 
342
        if (!td && t->con.mode & CON_APPLY) {
 
343
                float tmat[3][3];
 
344
 
 
345
                if (!(t->con.mode & CON_AXIS0)) {
 
346
                        smat[0][0] = 1.0f;
 
347
                }
 
348
                if (!(t->con.mode & CON_AXIS1)) {
 
349
                        smat[1][1] = 1.0f;
 
350
                }
 
351
                if (!(t->con.mode & CON_AXIS2)) {
 
352
                        smat[2][2] = 1.0f;
 
353
                }
 
354
 
 
355
                Mat3MulMat3(tmat, smat, t->con.imtx);
 
356
                Mat3MulMat3(smat, t->con.mtx, tmat);
 
357
        }
 
358
}
 
359
 
 
360
/*
 
361
 * Callback for object based spacial constraints applied to resize motion
 
362
 * 
 
363
 *
 
364
 */
 
365
 
 
366
static void applyObjectConstraintSize(TransInfo *t, TransData *td, float smat[3][3])
 
367
{
 
368
        if (td && t->con.mode & CON_APPLY) {
 
369
                float tmat[3][3];
 
370
                float imat[3][3];
 
371
 
 
372
                Mat3Inv(imat, td->axismtx);
 
373
 
 
374
                if (!(t->con.mode & CON_AXIS0)) {
 
375
                        smat[0][0] = 1.0f;
 
376
                }
 
377
                if (!(t->con.mode & CON_AXIS1)) {
 
378
                        smat[1][1] = 1.0f;
 
379
                }
 
380
                if (!(t->con.mode & CON_AXIS2)) {
 
381
                        smat[2][2] = 1.0f;
 
382
                }
 
383
 
 
384
                Mat3MulMat3(tmat, smat, imat);
 
385
                Mat3MulMat3(smat, td->axismtx, tmat);
 
386
        }
 
387
}
 
388
 
 
389
/*
 
390
 * Generic callback for constant spacial constraints applied to rotations
 
391
 * 
 
392
 * The rotation axis is copied into VEC.
 
393
 *
 
394
 * In the case of single axis constraints, the rotation axis is directly the one constrained to.
 
395
 * For planar constraints (2 axis), the rotation axis is the normal of the plane.
 
396
 *
 
397
 * The following only applies when CON_NOFLIP is not set.
 
398
 * The vector is then modified to always point away from the screen (in global space)
 
399
 * This insures that the rotation is always logically following the mouse.
 
400
 * (ie: not doing counterclockwise rotations when the mouse moves clockwise).
 
401
 */
 
402
 
 
403
static void applyAxisConstraintRot(TransInfo *t, TransData *td, float vec[3])
 
404
{
 
405
        if (!td && t->con.mode & CON_APPLY) {
 
406
                int mode = t->con.mode & (CON_AXIS0|CON_AXIS1|CON_AXIS2);
 
407
 
 
408
                switch(mode) {
 
409
                case CON_AXIS0:
 
410
                case (CON_AXIS1|CON_AXIS2):
 
411
                        VECCOPY(vec, t->con.mtx[0]);
 
412
                        break;
 
413
                case CON_AXIS1:
 
414
                case (CON_AXIS0|CON_AXIS2):
 
415
                        VECCOPY(vec, t->con.mtx[1]);
 
416
                        break;
 
417
                case CON_AXIS2:
 
418
                case (CON_AXIS0|CON_AXIS1):
 
419
                        VECCOPY(vec, t->con.mtx[2]);
 
420
                        break;
 
421
                }
 
422
                if (!(mode & CON_NOFLIP)) {
 
423
                        if (Inpf(vec, t->viewinv[2]) > 0.0f) {
 
424
                                VecMulf(vec, -1.0f);
 
425
                        }
 
426
                }
 
427
        }
 
428
}
 
429
 
 
430
/*
 
431
 * Callback for object based spacial constraints applied to rotations
 
432
 * 
 
433
 * The rotation axis is copied into VEC.
 
434
 *
 
435
 * In the case of single axis constraints, the rotation axis is directly the one constrained to.
 
436
 * For planar constraints (2 axis), the rotation axis is the normal of the plane.
 
437
 *
 
438
 * The following only applies when CON_NOFLIP is not set.
 
439
 * The vector is then modified to always point away from the screen (in global space)
 
440
 * This insures that the rotation is always logically following the mouse.
 
441
 * (ie: not doing counterclockwise rotations when the mouse moves clockwise).
 
442
 */
 
443
 
 
444
static void applyObjectConstraintRot(TransInfo *t, TransData *td, float vec[3])
 
445
{
 
446
        if (td && t->con.mode & CON_APPLY) {
 
447
                int mode = t->con.mode & (CON_AXIS0|CON_AXIS1|CON_AXIS2);
 
448
 
 
449
                switch(mode) {
 
450
                case CON_AXIS0:
 
451
                case (CON_AXIS1|CON_AXIS2):
 
452
                        VECCOPY(vec, td->axismtx[0]);
 
453
                        break;
 
454
                case CON_AXIS1:
 
455
                case (CON_AXIS0|CON_AXIS2):
 
456
                        VECCOPY(vec, td->axismtx[1]);
 
457
                        break;
 
458
                case CON_AXIS2:
 
459
                case (CON_AXIS0|CON_AXIS1):
 
460
                        VECCOPY(vec, td->axismtx[2]);
 
461
                        break;
 
462
                }
 
463
                if (!(mode & CON_NOFLIP)) {
 
464
                        if (Inpf(vec, t->viewinv[2]) > 0.0f) {
 
465
                                VecMulf(vec, -1.0f);
 
466
                        }
 
467
                }
 
468
        }
 
469
}
 
470
 
 
471
static void drawObjectConstraint(TransInfo *t) {
 
472
        int i;
 
473
        TransData * td = t->data;
 
474
 
 
475
        /* Draw the first one lighter because that's the one who controls the others.
 
476
           Meaning the transformation is projected on that one and just copied on the others
 
477
           constraint space.
 
478
           In a nutshell, the object with light axis is controlled by the user and the others follow.
 
479
           Without drawing the first light, users have little clue what they are doing.
 
480
         */
 
481
        if (t->con.mode & CON_AXIS0) {
 
482
                drawLine(td->ob->obmat[3], td->axismtx[0], 'x', DRAWLIGHT);
 
483
        }
 
484
        if (t->con.mode & CON_AXIS1) {
 
485
                drawLine(td->ob->obmat[3], td->axismtx[1], 'y', DRAWLIGHT);
 
486
        }
 
487
        if (t->con.mode & CON_AXIS2) {
 
488
                drawLine(td->ob->obmat[3], td->axismtx[2], 'z', DRAWLIGHT);
 
489
        }
 
490
        
 
491
        td++;
 
492
 
 
493
        for(i=1;i<t->total;i++,td++) {
 
494
                if (t->con.mode & CON_AXIS0) {
 
495
                        drawLine(td->ob->obmat[3], td->axismtx[0], 'x', 0);
 
496
                }
 
497
                if (t->con.mode & CON_AXIS1) {
 
498
                        drawLine(td->ob->obmat[3], td->axismtx[1], 'y', 0);
 
499
                }
 
500
                if (t->con.mode & CON_AXIS2) {
 
501
                        drawLine(td->ob->obmat[3], td->axismtx[2], 'z', 0);
 
502
                }
 
503
        }
 
504
}
 
505
 
 
506
/*
 
507
 * Returns the dimension of the constraint space.
 
508
 * 
 
509
 * For that reason, the flags always needs to be set to properly evaluate here,
 
510
 * even if they aren't actually used in the callback function. (Which could happen
 
511
 * for weird constraints not yet designed. Along a path for example.)
 
512
 */
 
513
 
 
514
int getConstraintSpaceDimension(TransInfo *t)
 
515
{
 
516
        int n = 0;
 
517
 
 
518
        if (t->con.mode & CON_AXIS0)
 
519
                n++;
 
520
 
 
521
        if (t->con.mode & CON_AXIS1)
 
522
                n++;
 
523
 
 
524
        if (t->con.mode & CON_AXIS2)
 
525
                n++;
 
526
 
 
527
        return n;
 
528
/*
 
529
  Someone willing to do it criptically could do the following instead:
 
530
 
 
531
  return t->con & (CON_AXIS0|CON_AXIS1|CON_AXIS2);
 
532
        
 
533
  Based on the assumptions that the axis flags are one after the other and start at 1
 
534
*/
 
535
}
 
536
 
 
537
void setConstraint(TransInfo *t, float space[3][3], int mode, const char text[]) {
 
538
        strncpy(t->con.text + 1, text, 48);
 
539
        Mat3CpyMat3(t->con.mtx, space);
 
540
        t->con.mode = mode;
 
541
        getConstraintMatrix(t);
 
542
 
 
543
        startConstraint(t);
 
544
 
 
545
        t->con.drawExtra = NULL;
 
546
        t->con.applyVec = applyAxisConstraintVec;
 
547
        t->con.applySize = applyAxisConstraintSize;
 
548
        t->con.applyRot = applyAxisConstraintRot;
 
549
        t->redraw = 1;
 
550
}
 
551
 
 
552
void BIF_setLocalAxisConstraint(char axis, char *text) {
 
553
        TransInfo *t = BIF_GetTransInfo();
 
554
 
 
555
        switch (axis) {
 
556
        case 'X':
 
557
                setLocalConstraint(t, CON_AXIS0, text);
 
558
                break;
 
559
        case 'Y':
 
560
                setLocalConstraint(t, CON_AXIS1, text);
 
561
                break;
 
562
        case 'Z':
 
563
                setLocalConstraint(t, CON_AXIS2, text);
 
564
                break;
 
565
        }
 
566
}
 
567
 
 
568
void BIF_setLocalLockConstraint(char axis, char *text) {
 
569
        TransInfo *t = BIF_GetTransInfo();
 
570
 
 
571
        switch (axis) {
 
572
        case 'x':
 
573
                setLocalConstraint(t, (CON_AXIS1|CON_AXIS2), text);
 
574
                break;
 
575
        case 'y':
 
576
                setLocalConstraint(t, (CON_AXIS0|CON_AXIS2), text);
 
577
                break;
 
578
        case 'z':
 
579
                setLocalConstraint(t, (CON_AXIS0|CON_AXIS1), text);
 
580
                break;
 
581
        }
 
582
}
 
583
 
 
584
void setLocalConstraint(TransInfo *t, int mode, const char text[]) {
 
585
        if (t->flag & T_EDIT) {
 
586
                float obmat[3][3];
 
587
                Mat3CpyMat4(obmat, G.obedit->obmat);
 
588
                setConstraint(t, obmat, mode|CON_LOCAL, text);
 
589
        }
 
590
        else {
 
591
                if (t->total == 1) {
 
592
                        setConstraint(t, t->data->axismtx, mode|CON_LOCAL, text);
 
593
                }
 
594
                else {
 
595
                        strncpy(t->con.text + 1, text, 48);
 
596
                        Mat3CpyMat3(t->con.mtx, t->data->axismtx);
 
597
                        t->con.mode = mode|CON_LOCAL;
 
598
                        getConstraintMatrix(t);
 
599
 
 
600
                        startConstraint(t);
 
601
 
 
602
                        t->con.drawExtra = drawObjectConstraint;
 
603
                        t->con.applyVec = applyObjectConstraintVec;
 
604
                        t->con.applySize = applyObjectConstraintSize;
 
605
                        t->con.applyRot = applyObjectConstraintRot;
 
606
                        t->redraw = 1;
 
607
                }
 
608
        }
 
609
}
 
610
 
 
611
/* text is optional, for header print */
 
612
void BIF_setSingleAxisConstraint(float vec[3], char *text) {
 
613
        TransInfo *t = BIF_GetTransInfo();
 
614
        float space[3][3], v[3];
 
615
        
 
616
        VECCOPY(space[0], vec);
 
617
 
 
618
        v[0] = vec[2];
 
619
        v[1] = vec[0];
 
620
        v[2] = vec[1];
 
621
 
 
622
        Crossf(space[1], vec, v);
 
623
        Crossf(space[2], vec, space[1]);
 
624
        Mat3Ortho(space);
 
625
 
 
626
        Mat3CpyMat3(t->con.mtx, space);
 
627
        t->con.mode = (CON_AXIS0|CON_APPLY);
 
628
        getConstraintMatrix(t);
 
629
 
 
630
        /* start copying with an offset of 1, to reserve a spot for the SPACE char */
 
631
        if(text) strncpy(t->con.text+1, text, 48);      // 50 in struct
 
632
 
 
633
        
 
634
        t->con.drawExtra = NULL;
 
635
        t->con.applyVec = applyAxisConstraintVec;
 
636
        t->con.applySize = applyAxisConstraintSize;
 
637
        t->con.applyRot = applyAxisConstraintRot;
 
638
        t->redraw = 1;
 
639
}
 
640
 
 
641
void BIF_setDualAxisConstraint(float vec1[3], float vec2[3], char *text) {
 
642
        TransInfo *t = BIF_GetTransInfo();
 
643
        float space[3][3];
 
644
        
 
645
        VECCOPY(space[0], vec1);
 
646
        VECCOPY(space[1], vec2);
 
647
        Crossf(space[2], space[0], space[1]);
 
648
        Mat3Ortho(space);
 
649
        
 
650
        Mat3CpyMat3(t->con.mtx, space);
 
651
        t->con.mode = (CON_AXIS0|CON_AXIS1|CON_APPLY);
 
652
        getConstraintMatrix(t);
 
653
        
 
654
        /* start copying with an offset of 1, to reserve a spot for the SPACE char */
 
655
        if(text) strncpy(t->con.text+1, text, 48);      // 50 in struct
 
656
 
 
657
        t->con.drawExtra = NULL;
 
658
        t->con.applyVec = applyAxisConstraintVec;
 
659
        t->con.applySize = applyAxisConstraintSize;
 
660
        t->con.applyRot = applyAxisConstraintRot;
 
661
        t->redraw = 1;
 
662
}
 
663
 
 
664
 
 
665
void BIF_drawConstraint(void)
 
666
{
 
667
        TransInfo *t = BIF_GetTransInfo();
 
668
        TransCon *tc = &(t->con);
 
669
 
 
670
        if (!(tc->mode & CON_APPLY))
 
671
                return;
 
672
        if (t->flag & T_USES_MANIPULATOR)
 
673
                return;
 
674
        
 
675
        /* nasty exception for Z constraint in camera view */
 
676
        if( (t->flag & T_OBJECT) && G.vd->camera==OBACT && G.vd->persp>1) 
 
677
                return;
 
678
 
 
679
        if (tc->drawExtra) {
 
680
                tc->drawExtra(t);
 
681
        }
 
682
        else {
 
683
                if (tc->mode & CON_SELECT) {
 
684
                        float vec[3];
 
685
                        short mval[2];
 
686
                        char col2[3] = {255,255,255};
 
687
                        getmouseco_areawin(mval);
 
688
                        window_to_3d(vec, (short)(mval[0] - t->con.imval[0]), (short)(mval[1] - t->con.imval[1]));
 
689
                        VecAddf(vec, vec, tc->center);
 
690
 
 
691
                        drawLine(tc->center, tc->mtx[0], 'x', 0);
 
692
                        drawLine(tc->center, tc->mtx[1], 'y', 0);
 
693
                        drawLine(tc->center, tc->mtx[2], 'z', 0);
 
694
 
 
695
                        glColor3ubv(col2);
 
696
                        
 
697
                        glDisable(GL_DEPTH_TEST);
 
698
                        setlinestyle(1);
 
699
                        glBegin(GL_LINE_STRIP); 
 
700
                                glVertex3fv(tc->center); 
 
701
                                glVertex3fv(vec); 
 
702
                        glEnd();
 
703
                        setlinestyle(0);
 
704
                        if(G.zbuf) glEnable(GL_DEPTH_TEST);     // warning for global!
 
705
                }
 
706
 
 
707
                if (tc->mode & CON_AXIS0) {
 
708
                        drawLine(tc->center, tc->mtx[0], 'x', DRAWLIGHT);
 
709
                }
 
710
                if (tc->mode & CON_AXIS1) {
 
711
                        drawLine(tc->center, tc->mtx[1], 'y', DRAWLIGHT);
 
712
                }
 
713
                if (tc->mode & CON_AXIS2) {
 
714
                        drawLine(tc->center, tc->mtx[2], 'z', DRAWLIGHT);
 
715
                }
 
716
        }
 
717
}
 
718
 
 
719
/* called from drawview.c, as an extra per-window draw option */
 
720
void BIF_drawPropCircle()
 
721
{
 
722
        TransInfo *t = BIF_GetTransInfo();
 
723
 
 
724
        if (t->flag & T_PROP_EDIT) {
 
725
                float tmat[4][4], imat[4][4];
 
726
 
 
727
                BIF_ThemeColor(TH_GRID);
 
728
                
 
729
                /* if editmode we need to go into object space */
 
730
                if(G.obedit) mymultmatrix(G.obedit->obmat);
 
731
                
 
732
                mygetmatrix(tmat);
 
733
                Mat4Invert(imat, tmat);
 
734
                
 
735
                drawcircball(GL_LINE_LOOP, t->center, t->propsize, imat);
 
736
                
 
737
                /* if editmode we restore */
 
738
                if(G.obedit) myloadmatrix(G.vd->viewmat);
 
739
        }
 
740
}
 
741
 
 
742
int isLockConstraint(TransInfo *t) {
 
743
        int mode = t->con.mode;
 
744
 
 
745
        if ( (mode & (CON_AXIS0|CON_AXIS1)) == (CON_AXIS0|CON_AXIS1))
 
746
                return 1;
 
747
 
 
748
        if ( (mode & (CON_AXIS1|CON_AXIS2)) == (CON_AXIS1|CON_AXIS2))
 
749
                return 1;
 
750
 
 
751
        if ( (mode & (CON_AXIS0|CON_AXIS2)) == (CON_AXIS0|CON_AXIS2))
 
752
                return 1;
 
753
 
 
754
        return 0;
 
755
}
 
756
 
 
757
void initConstraint(TransInfo *t) {
 
758
        if (t->con.mode & CON_APPLY) {
 
759
                startConstraint(t);
 
760
        }
 
761
}
 
762
 
 
763
void startConstraint(TransInfo *t) {
 
764
        t->con.mode |= CON_APPLY;
 
765
        *t->con.text = ' ';
 
766
        t->num.idx_max = MIN2(getConstraintSpaceDimension(t) - 1, t->idx_max);
 
767
}
 
768
 
 
769
void stopConstraint(TransInfo *t) {
 
770
        t->con.mode &= ~(CON_APPLY|CON_SELECT);
 
771
        *t->con.text = '\0';
 
772
        t->num.idx_max = t->idx_max;
 
773
}
 
774
 
 
775
void getConstraintMatrix(TransInfo *t)
 
776
{
 
777
        float mat[3][3];
 
778
        Mat3Inv(t->con.imtx, t->con.mtx);
 
779
        Mat3One(t->con.pmtx);
 
780
 
 
781
        if (!(t->con.mode & CON_AXIS0)) {
 
782
                t->con.pmtx[0][0]               =
 
783
                        t->con.pmtx[0][1]       =
 
784
                        t->con.pmtx[0][2]       = 0.0f;
 
785
        }
 
786
 
 
787
        if (!(t->con.mode & CON_AXIS1)) {
 
788
                t->con.pmtx[1][0]               =
 
789
                        t->con.pmtx[1][1]       =
 
790
                        t->con.pmtx[1][2]       = 0.0f;
 
791
        }
 
792
 
 
793
        if (!(t->con.mode & CON_AXIS2)) {
 
794
                t->con.pmtx[2][0]               =
 
795
                        t->con.pmtx[2][1]       =
 
796
                        t->con.pmtx[2][2]       = 0.0f;
 
797
        }
 
798
 
 
799
        Mat3MulMat3(mat, t->con.pmtx, t->con.imtx);
 
800
        Mat3MulMat3(t->con.pmtx, t->con.mtx, mat);
 
801
}
 
802
 
 
803
void initSelectConstraint(TransInfo *t, float mtx[3][3])
 
804
{
 
805
        Mat3CpyMat3(t->con.mtx, mtx);
 
806
        t->con.mode |= CON_APPLY;
 
807
        t->con.mode |= CON_SELECT;
 
808
        t->con.mode &= ~CON_LOCAL;
 
809
 
 
810
        setNearestAxis(t);
 
811
        t->con.drawExtra = NULL;
 
812
        t->con.applyVec = applyAxisConstraintVec;
 
813
        t->con.applySize = applyAxisConstraintSize;
 
814
        t->con.applyRot = applyAxisConstraintRot;
 
815
}
 
816
 
 
817
void selectConstraint(TransInfo *t) {
 
818
        if (t->con.mode & CON_SELECT) {
 
819
                setNearestAxis(t);
 
820
                startConstraint(t);
 
821
        }
 
822
}
 
823
 
 
824
void postSelectConstraint(TransInfo *t)
 
825
{
 
826
        if (!(t->con.mode & CON_SELECT))
 
827
                return;
 
828
 
 
829
        t->con.mode &= ~CON_AXIS0;
 
830
        t->con.mode &= ~CON_AXIS1;
 
831
        t->con.mode &= ~CON_AXIS2;
 
832
        t->con.mode &= ~CON_SELECT;
 
833
 
 
834
        setNearestAxis(t);
 
835
 
 
836
        startConstraint(t);
 
837
        t->redraw = 1;
 
838
}
 
839
 
 
840
void setNearestAxis(TransInfo *t)
 
841
{
 
842
        float zfac;
 
843
        float mvec[3], axis[3], proj[3];
 
844
        float len[3];
 
845
        int i, icoord[2];
 
846
        short coord[2];
 
847
 
 
848
        t->con.mode &= ~CON_AXIS0;
 
849
        t->con.mode &= ~CON_AXIS1;
 
850
        t->con.mode &= ~CON_AXIS2;
 
851
 
 
852
        getmouseco_areawin(coord);
 
853
        mvec[0] = (float)(coord[0] - t->con.imval[0]);
 
854
        mvec[1] = (float)(coord[1] - t->con.imval[1]);
 
855
        mvec[2] = 0.0f;
 
856
 
 
857
                
 
858
        /* we need to correct axis length for the current zoomlevel of view,
 
859
           this to prevent projected values to be clipped behind the camera
 
860
           and to overflow the short integers.
 
861
           The formula used is a bit stupid, just a simplification of the substraction
 
862
           of two 2D points 30 pixels apart (that's the last factor in the formula) after
 
863
           projecting them with window_to_3d and then get the length of that vector.
 
864
        */
 
865
        zfac= G.vd->persmat[0][3]*t->center[0]+ G.vd->persmat[1][3]*t->center[1]+ G.vd->persmat[2][3]*t->center[2]+ G.vd->persmat[3][3];
 
866
        zfac = VecLength(G.vd->persinv[0]) * 2.0f/curarea->winx * zfac * 30.0f;
 
867
 
 
868
        for (i = 0; i<3; i++) {
 
869
                VECCOPY(axis, t->con.mtx[i]);
 
870
                
 
871
                VecMulf(axis, zfac);
 
872
                /* now we can project to get window coordinate */
 
873
                VecAddf(axis, axis, t->con.center);
 
874
                project_int(axis, icoord);
 
875
                
 
876
                axis[0] = (float)(icoord[0] - t->center2d[0]);
 
877
                axis[1] = (float)(icoord[1] - t->center2d[1]);
 
878
                axis[2] = 0.0f;
 
879
 
 
880
                if (Normalise(axis) != 0.0f) {
 
881
                        Projf(proj, mvec, axis);
 
882
                        VecSubf(axis, mvec, proj);
 
883
                        len[i] = Normalise(axis);
 
884
                }
 
885
                else {
 
886
                        len[i] = 10000000000.0f;
 
887
                }
 
888
        }
 
889
 
 
890
        if (len[0] <= len[1] && len[0] <= len[2]) {
 
891
                if (G.qual & LR_SHIFTKEY) {
 
892
                        t->con.mode |= (CON_AXIS1|CON_AXIS2);
 
893
                        strcpy(t->con.text, " locking global X");
 
894
                }
 
895
                else {
 
896
                        t->con.mode |= CON_AXIS0;
 
897
                        strcpy(t->con.text, " along global X");
 
898
                }
 
899
        }
 
900
        else if (len[1] <= len[0] && len[1] <= len[2]) {
 
901
                if (G.qual & LR_SHIFTKEY) {
 
902
                        t->con.mode |= (CON_AXIS0|CON_AXIS2);
 
903
                        strcpy(t->con.text, " locking global Y");
 
904
                }
 
905
                else {
 
906
                        t->con.mode |= CON_AXIS1;
 
907
                        strcpy(t->con.text, " along global Y");
 
908
                }
 
909
        }
 
910
        else if (len[2] <= len[1] && len[2] <= len[0]) {
 
911
                if (G.qual & LR_SHIFTKEY) {
 
912
                        t->con.mode |= (CON_AXIS0|CON_AXIS1);
 
913
                        strcpy(t->con.text, " locking global Z");
 
914
                }
 
915
                else {
 
916
                        t->con.mode |= CON_AXIS2;
 
917
                        strcpy(t->con.text, " along global Z");
 
918
                }
 
919
        }
 
920
        getConstraintMatrix(t);
 
921
}
 
922
 
 
923
char constraintModeToChar(TransInfo *t) {
 
924
        if ((t->con.mode & CON_APPLY)==0) {
 
925
                return '\0';
 
926
        }
 
927
        switch (t->con.mode & (CON_AXIS0|CON_AXIS1|CON_AXIS2)) {
 
928
        case (CON_AXIS0):
 
929
        case (CON_AXIS1|CON_AXIS2):
 
930
                return 'X';
 
931
        case (CON_AXIS1):
 
932
        case (CON_AXIS0|CON_AXIS2):
 
933
                return 'Y';
 
934
        case (CON_AXIS2):
 
935
        case (CON_AXIS0|CON_AXIS1):
 
936
                return 'Z';
 
937
        default:
 
938
                return '\0';
 
939
        }
 
940
}