~diresu/blender/blender-command-port

« back to all changes in this revision

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

  • Committer: theeth
  • Date: 2008-10-14 16:52:04 UTC
  • Revision ID: vcs-imports@canonical.com-20081014165204-r32w2gm6s0osvdhn
copy back trunk

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * $Id: retopo.c 16914 2008-10-04 11:04:09Z ton $
 
3
 *
 
4
 * ***** BEGIN GPL 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.
 
10
 *
 
11
 * This program is distributed in the hope that it will be useful,
 
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
14
 * GNU General Public License for more details.
 
15
 *
 
16
 * You should have received a copy of the GNU General Public License
 
17
 * along with this program; if not, write to the Free Software  Foundation,
 
18
 * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
19
 *
 
20
 * The Original Code is Copyright (C) 2006 by Nicholas Bishop
 
21
 * All rights reserved.
 
22
 *
 
23
 * The Original Code is: all of this file.
 
24
 *
 
25
 * Contributor(s): none yet.
 
26
 *
 
27
 * ***** END GPL LICENSE BLOCK *****
 
28
 *
 
29
 * Implements the Retopo tools
 
30
 *
 
31
 * BIF_retopo.h
 
32
 *
 
33
 */
 
34
 
 
35
#include "MEM_guardedalloc.h"
 
36
 
 
37
#include "DNA_curve_types.h"
 
38
#include "DNA_mesh_types.h"
 
39
#include "DNA_meshdata_types.h"
 
40
#include "DNA_object_types.h"
 
41
#include "DNA_scene_types.h"
 
42
#include "DNA_screen_types.h"
 
43
#include "DNA_space_types.h"
 
44
#include "DNA_userdef_types.h"
 
45
#include "DNA_view3d_types.h"
 
46
 
 
47
#include "BDR_editobject.h"
 
48
 
 
49
#include "BIF_editmesh.h"
 
50
#include "BIF_editmode_undo.h"
 
51
#include "BIF_gl.h"
 
52
#include "BIF_glutil.h"
 
53
#include "BIF_mywindow.h"
 
54
#include "BIF_retopo.h"
 
55
#include "BIF_screen.h"
 
56
#include "BIF_space.h"
 
57
#include "BIF_toolbox.h"
 
58
 
 
59
#include "BKE_curve.h"
 
60
#include "BKE_depsgraph.h"
 
61
#include "BKE_global.h"
 
62
#include "BKE_mesh.h"
 
63
 
 
64
#include "BLI_blenlib.h"
 
65
#include "BLI_editVert.h"
 
66
 
 
67
#include "BSE_drawview.h"
 
68
#include "BSE_edit.h"
 
69
#include "BSE_view.h"
 
70
 
 
71
#include "editmesh.h"
 
72
#include "mydevice.h"
 
73
 
 
74
#ifdef WIN32
 
75
#define _USE_MATH_DEFINES
 
76
#endif
 
77
#include <math.h>
 
78
#include <stdlib.h>
 
79
#include <string.h>
 
80
 
 
81
typedef struct RetopoPaintHit {
 
82
        struct RetopoPaintHit *next, *prev;
 
83
        RetopoPaintPoint *intersection;
 
84
        short index;
 
85
        float where;
 
86
} RetopoPaintHit;
 
87
 
 
88
static void retopo_do_2d(View3D *v3d, double proj[2], float *v, char adj);
 
89
 
 
90
#if 0
 
91
static void retopo_paint_debug_print(RetopoPaintData *rpd)
 
92
{
 
93
        RetopoPaintLine *l;
 
94
        RetopoPaintPoint *p;
 
95
        
 
96
        for(l= rpd->lines.first; l; l= l->next) {
 
97
                printf("Line:\n");
 
98
                for(p= l->points.first; p; p= p->next) {
 
99
                        printf("   Point(%d: %d,%d)\n",p->index,p->loc.x,p->loc.y);
 
100
                }
 
101
        }
 
102
        
 
103
        fflush(stdout);
 
104
}
 
105
#endif
 
106
 
 
107
/* Painting */
 
108
RetopoPaintData *get_retopo_paint_data(void)
 
109
{
 
110
        if(!retopo_mesh_paint_check()) return NULL;
 
111
        if(!G.editMesh) return NULL;
 
112
        return G.editMesh->retopo_paint_data;
 
113
}
 
114
 
 
115
char retopo_mesh_paint_check(void)
 
116
{
 
117
        return retopo_mesh_check() && G.scene->toolsettings->retopo_mode & RETOPO_PAINT;
 
118
}
 
119
 
 
120
void retopo_free_paint_data(RetopoPaintData *rpd)
 
121
{
 
122
        if(rpd) {
 
123
                RetopoPaintLine *l;
 
124
                for(l= rpd->lines.first; l; l= l->next) {
 
125
                        BLI_freelistN(&l->points);
 
126
                        BLI_freelistN(&l->hitlist);
 
127
                }
 
128
                BLI_freelistN(&rpd->lines);
 
129
                
 
130
                BLI_freelistN(&rpd->intersections);
 
131
 
 
132
                MEM_freeN(rpd);
 
133
        }
 
134
}
 
135
 
 
136
void retopo_free_paint(void)
 
137
{
 
138
        retopo_free_paint_data(G.editMesh->retopo_paint_data);
 
139
        G.editMesh->retopo_paint_data= NULL;
 
140
}
 
141
 
 
142
char line_intersection_2d(const vec2s *a, const vec2s *b, const vec2s *c, const vec2s *d, vec2s *out,
 
143
                          float *r, float *s)
 
144
{
 
145
        float den;
 
146
        *r= (a->y - c->y) * (d->x - c->x) - (a->x - c->x) * (d->y - c->y);
 
147
        *s= (a->y - c->y) * (b->x - a->x) - (a->x - c->x) * (b->y - a->y);
 
148
        den= (b->x - a->x) * (d->y - c->y) - (b->y - a->y) * (d->x - c->x);
 
149
 
 
150
        if((a->x==b->x && a->y==b->y) || (c->x==d->x && c->y==d->y)) return 0;
 
151
 
 
152
        if(!den) return 0;
 
153
 
 
154
        *r/= den;
 
155
        *s/= den;
 
156
 
 
157
        if(*s<0 || *s>=1 || *r<0 || *r>=1) return 0;
 
158
 
 
159
        out->x= a->x + *r*(b->x - a->x);
 
160
        out->y= a->y + *r*(b->y - a->y);
 
161
        return 1;
 
162
}
 
163
 
 
164
void retopo_paint_add_line_hit(RetopoPaintLine *l, RetopoPaintPoint *p, RetopoPaintPoint *intersection, float w)
 
165
{
 
166
        RetopoPaintHit *prev, *hit= MEM_callocN(sizeof(RetopoPaintHit),"RetopoPaintHit");
 
167
        
 
168
        hit->intersection= intersection;
 
169
        hit->index= p->index;
 
170
        hit->where= w;
 
171
 
 
172
        prev= l->hitlist.first;
 
173
        if(!prev) {
 
174
                BLI_addtail(&l->hitlist,hit);
 
175
        }
 
176
        else if(prev->index>hit->index) {
 
177
                BLI_addhead(&l->hitlist,hit);
 
178
        }
 
179
        else {
 
180
                /* Move forward until we hit the next highest index */
 
181
                while(prev->next) {
 
182
                        if(prev->next->index > hit->index) break;
 
183
                        prev= prev->next;
 
184
                }
 
185
                /* Move backward until we hit the next lowest where */
 
186
                while(prev->prev && prev->prev->index==prev->index &&
 
187
                      prev->where > hit->where)
 
188
                        prev=prev->prev;
 
189
                BLI_insertlink(&l->hitlist,prev,hit);
 
190
        }
 
191
        
 
192
        /* Removed duplicate intersections */
 
193
        if(hit->prev && hit->prev->intersection==hit->intersection) {
 
194
                BLI_freelinkN(&l->hitlist,hit);
 
195
        }
 
196
}
 
197
 
 
198
char retopo_paint_add_intersection(RetopoPaintData *rpd, RetopoPaintLine *l1, RetopoPaintPoint *p1,
 
199
                                   RetopoPaintLine *l2, RetopoPaintPoint *p2, vec2s *out, float r, float s)
 
200
{
 
201
        RetopoPaintPoint *p, *hit;
 
202
        char found= 0;
 
203
 
 
204
        for(p=rpd->intersections.first; p; p= p->next) {
 
205
                if(sqrt(pow(p->loc.x-out->x,2)+pow(p->loc.y-out->y,2))<7) {
 
206
                        found= 1;
 
207
                        break;
 
208
                }
 
209
        }
 
210
 
 
211
        if(!found) {
 
212
                hit= MEM_callocN(sizeof(RetopoPaintPoint),"Retopo paint intersection");
 
213
                hit->loc.x= out->x;
 
214
                hit->loc.y= out->y;
 
215
                BLI_addtail(&rpd->intersections,hit);
 
216
        } else {
 
217
                hit= p;
 
218
        }
 
219
 
 
220
        retopo_paint_add_line_hit(l1,p1,hit,r);
 
221
        retopo_paint_add_line_hit(l2,p2,hit,s);
 
222
 
 
223
        return !found;
 
224
}
 
225
 
 
226
 
 
227
/* Returns 1 if a new intersection was added */
 
228
char do_line_intersection(RetopoPaintData *rpd, RetopoPaintLine *l1, RetopoPaintPoint *p1,
 
229
                          RetopoPaintLine *l2, RetopoPaintPoint *p2)
 
230
{
 
231
        vec2s out;
 
232
        float r,s;
 
233
        if(line_intersection_2d(&p1->loc, &p1->next->loc,
 
234
                                &p2->loc, &p2->next->loc,
 
235
                                &out,&r,&s)) {
 
236
                if(retopo_paint_add_intersection(rpd,l1,p1,l2,p2,&out,r,s))
 
237
                        return 1;
 
238
        }
 
239
        return 0;
 
240
}
 
241
 
 
242
typedef struct FaceNode {
 
243
        struct FaceNode *next, *prev;
 
244
        MFace f;
 
245
} FaceNode;
 
246
 
 
247
char faces_equal(EditFace *f1, EditFace *f2)
 
248
{
 
249
        return editface_containsVert(f2,f1->v1) &&
 
250
               editface_containsVert(f2,f1->v2) &&
 
251
               editface_containsVert(f2,f1->v3) &&
 
252
               (f1->v4 ? editface_containsVert(f2,f1->v4) : 1);
 
253
}
 
254
 
 
255
EditFace *addfaceif(EditMesh *em, EditVert *v1, EditVert *v2, EditVert *v3, EditVert *v4)
 
256
{
 
257
        EditFace *efa;
 
258
        
 
259
        for(efa= em->faces.first; efa; efa= efa->next) {
 
260
                if(editface_containsVert(efa,v1) &&
 
261
                   editface_containsVert(efa,v2) &&
 
262
                   editface_containsVert(efa,v3) &&
 
263
                   (v4 ? editface_containsVert(efa,v4) : 1))
 
264
                        return NULL;
 
265
        }
 
266
 
 
267
        return addfacelist(v1,v2,v3,v4,NULL,NULL);
 
268
}
 
269
 
 
270
void retopo_paint_apply(void)
 
271
{
 
272
        RetopoPaintData *rpd= G.editMesh->retopo_paint_data;
 
273
        EditVert *eve;
 
274
 
 
275
        if(rpd) {
 
276
                RetopoPaintLine *l1, *l2;
 
277
                RetopoPaintPoint *p1, *p2;
 
278
                unsigned hitcount= 0;
 
279
                unsigned i;
 
280
                RetopoPaintHit *h;
 
281
                float hitco[3];
 
282
                
 
283
                /* Find intersections */
 
284
                BLI_freelistN(&rpd->intersections);
 
285
                for(l1= rpd->lines.first; l1; l1= l1->next) {
 
286
                        for(l2= rpd->lines.first; l2; l2= l2->next) {
 
287
                                if(l1!=l2) {
 
288
                                        for(p1= l1->points.first; p1 && p1!=l1->points.last; p1= p1->next) {
 
289
                                                for(p2= l2->points.first; p2 && p2!=l2->points.last; p2= p2->next) {
 
290
                                                        if(p1!=p2) {
 
291
                                                                if(do_line_intersection(rpd,l1,p1,l2,p2))
 
292
                                                                        ++hitcount;
 
293
                                                        }
 
294
                                                }
 
295
                                        }
 
296
                                }
 
297
                        }
 
298
                }
 
299
 
 
300
                /*topoPaintHit *hit;
 
301
                l1= rpd->lines.first;
 
302
                for(hit= l1->hitlist.first; hit; hit= hit->next) {
 
303
                        printf("\nhit(%p,%d) ",hit->intersection,hit->index);
 
304
                }
 
305
                fflush(stdout);*/
 
306
 
 
307
                /* Deselect */
 
308
                for(eve= G.editMesh->verts.first; eve; eve= eve->next)
 
309
                        eve->f &= ~SELECT;
 
310
                EM_deselect_flush();
 
311
 
 
312
                for(i=0; i<hitcount; ++i) {
 
313
                        RetopoPaintPoint *intersection= BLI_findlink(&rpd->intersections,i);
 
314
                        double proj[2] = {intersection->loc.x, intersection->loc.y};
 
315
                        retopo_do_2d(rpd->paint_v3d, proj, hitco, 1);
 
316
                        intersection->eve= addvertlist(hitco, NULL);
 
317
                        intersection->eve->f= SELECT;
 
318
                }
 
319
                
 
320
                for(l1= rpd->lines.first; l1; l1= l1->next) {
 
321
                        unsigned etcount= BLI_countlist(&l1->hitlist);
 
322
                        if(etcount>=2) {
 
323
                                for(h= l1->hitlist.first; (h && h->next); h= h->next)
 
324
                                        addedgelist(h->intersection->eve,h->next->intersection->eve,NULL);
 
325
                                if(etcount>=3 && l1->cyclic)
 
326
                                        addedgelist(((RetopoPaintHit*)l1->hitlist.first)->intersection->eve,
 
327
                                                    ((RetopoPaintHit*)l1->hitlist.last)->intersection->eve, NULL);
 
328
                        }
 
329
                }
 
330
                
 
331
                addfaces_from_edgenet();
 
332
        }
 
333
 
 
334
        retopo_free_paint();
 
335
}
 
336
 
 
337
void add_rppoint(RetopoPaintLine *l, short x, short y)
 
338
{
 
339
        RetopoPaintPoint *p= MEM_callocN(sizeof(RetopoPaintPoint),"RetopoPaintPoint");
 
340
        double proj[2];
 
341
        p->loc.x= x;
 
342
        p->loc.y= y;
 
343
        BLI_addtail(&l->points,p);
 
344
        p->index= p->prev?p->prev->index+1:0;
 
345
 
 
346
        proj[0] = p->loc.x;
 
347
        proj[1] = p->loc.y;
 
348
 
 
349
        retopo_do_2d(G.editMesh->retopo_paint_data->paint_v3d, proj, p->co, 1);
 
350
}
 
351
RetopoPaintLine *add_rpline(RetopoPaintData *rpd)
 
352
{
 
353
        RetopoPaintLine *l= MEM_callocN(sizeof(RetopoPaintLine),"RetopoPaintLine");
 
354
        BLI_addtail(&rpd->lines,l);
 
355
        return l;
 
356
}
 
357
 
 
358
void retopo_paint_toggle_cyclic(RetopoPaintLine *l)
 
359
{
 
360
        if(l==NULL)
 
361
                return;
 
362
        if(!l->cyclic) {
 
363
                RetopoPaintPoint *pf= l->points.first;
 
364
 
 
365
                if(pf) {
 
366
                        add_rppoint(l, pf->loc.x, pf->loc.y);
 
367
                        l->cyclic= l->points.last;
 
368
                }
 
369
        } else {
 
370
                BLI_freelinkN(&l->points,l->cyclic);
 
371
                l->cyclic= NULL;
 
372
        }
 
373
}
 
374
 
 
375
void retopo_paint_add_line(RetopoPaintData *rpd, short mouse[2])
 
376
{
 
377
        RetopoPaintLine *l= add_rpline(rpd);
 
378
        float range[2]= {mouse[0]-rpd->sloc[0],mouse[1]-rpd->sloc[1]};
 
379
        int i;
 
380
 
 
381
        /* Add initial point */
 
382
        add_rppoint(l,rpd->sloc[0],rpd->sloc[1]);
 
383
        for(i=0; i<G.scene->toolsettings->line_div; ++i) {
 
384
                const float mul= (i+1.0f) / G.scene->toolsettings->line_div;
 
385
                add_rppoint(l,rpd->sloc[0] + range[0]*mul,rpd->sloc[1] + range[1]*mul);
 
386
        }
 
387
 
 
388
        allqueue(REDRAWVIEW3D,0);
 
389
}
 
390
 
 
391
void retopo_paint_add_ellipse(RetopoPaintData *rpd, short mouse[2])
 
392
{
 
393
        int i;
 
394
 
 
395
        add_rpline(rpd);
 
396
        for (i=0; i<G.scene->toolsettings->ellipse_div; i++) {
 
397
                float t= (float) i / G.scene->toolsettings->ellipse_div;
 
398
                float cur= t*(M_PI*2);
 
399
                
 
400
                float w= abs(mouse[0]-rpd->sloc[0]);
 
401
                float h= abs(mouse[1]-rpd->sloc[1]);
 
402
 
 
403
                add_rppoint(rpd->lines.last,cos(cur)*w+rpd->sloc[0],sin(cur)*h+rpd->sloc[1]);
 
404
        }
 
405
 
 
406
        retopo_paint_toggle_cyclic(rpd->lines.last);
 
407
 
 
408
        allqueue(REDRAWVIEW3D,0);
 
409
}
 
410
 
 
411
void retopo_end_okee(void)
 
412
{
 
413
        if(okee("Apply retopo paint?"))
 
414
                retopo_paint_apply();
 
415
        else
 
416
                retopo_free_paint();
 
417
        G.scene->toolsettings->retopo_mode &= ~RETOPO_PAINT;
 
418
}
 
419
 
 
420
void retopo_paint_toggle(void *a, void *b)
 
421
{
 
422
        /* Note that these operations are reversed because mode bit has already been set! */
 
423
        if(retopo_mesh_paint_check()) { /* Activate retopo paint */
 
424
                RetopoPaintData *rpd= MEM_callocN(sizeof(RetopoPaintData),"RetopoPaintData");
 
425
                
 
426
                G.editMesh->retopo_paint_data= rpd;
 
427
                G.scene->toolsettings->retopo_paint_tool= RETOPO_PEN;
 
428
                rpd->seldist= 15;
 
429
                rpd->nearest.line= NULL;
 
430
                G.scene->toolsettings->line_div= 25;
 
431
                G.scene->toolsettings->ellipse_div= 25;
 
432
                G.scene->toolsettings->retopo_hotspot= 1;
 
433
        } else retopo_end_okee();
 
434
 
 
435
        BIF_undo_push("Retopo toggle");
 
436
 
 
437
        allqueue(REDRAWVIEW3D, 1);
 
438
}
 
439
 
 
440
void retopo_paint_view_update(struct View3D *v3d)
 
441
{
 
442
        RetopoPaintData *rpd= get_retopo_paint_data();
 
443
 
 
444
        if(rpd && rpd->paint_v3d==v3d) {
 
445
                RetopoPaintLine *l;
 
446
                RetopoPaintPoint *p;
 
447
                double ux, uy, uz;
 
448
                
 
449
                for(l= rpd->lines.first; l; l= l->next) {
 
450
                        for(p= l->points.first; p; p= p->next) {
 
451
                                gluProject(p->co[0],p->co[1],p->co[2], v3d->retopo_view_data->mats.modelview,
 
452
                                           v3d->retopo_view_data->mats.projection,
 
453
                                           (GLint *)v3d->retopo_view_data->mats.viewport, &ux, &uy, &uz);
 
454
                                p->loc.x= ux;
 
455
                                p->loc.y= uy;
 
456
                        }
 
457
                }
 
458
        }
 
459
}
 
460
 
 
461
void retopo_force_update(void)
 
462
{
 
463
        RetopoPaintData *rpd= get_retopo_paint_data();
 
464
        
 
465
        if(rpd) {
 
466
                View3D *vd= rpd->paint_v3d;
 
467
                
 
468
                if(vd) {
 
469
                        if(vd->depths) vd->depths->damaged= 1;
 
470
                        retopo_queue_updates(vd);
 
471
                        if(retopo_mesh_paint_check() && vd->retopo_view_data)
 
472
                                allqueue(REDRAWVIEW3D, 0);
 
473
                }
 
474
        }
 
475
}
 
476
 
 
477
/* Returns 1 if event should be processed by caller, 0 otherwise */
 
478
char retopo_paint(const unsigned short event)
 
479
{
 
480
        RetopoPaintData *rpd= get_retopo_paint_data();
 
481
 
 
482
        if(!event) return 1;
 
483
        if(rpd) {
 
484
                RetopoPaintLine *l;
 
485
                short mouse[2];
 
486
                char lbut= get_mbut() & (U.flag & USER_LMOUSESELECT ? R_MOUSE : L_MOUSE);
 
487
                
 
488
                if(rpd->paint_v3d && rpd->paint_v3d!=G.vd) return 1;
 
489
        
 
490
                getmouseco_areawin(mouse);
 
491
 
 
492
                if(rpd->in_drag && !lbut) { /* End drag */
 
493
                        rpd->in_drag= 0;
 
494
 
 
495
                        switch(G.scene->toolsettings->retopo_paint_tool) {
 
496
                        case RETOPO_PEN:
 
497
                                break;
 
498
                        case RETOPO_LINE:
 
499
                                retopo_paint_add_line(rpd, mouse);
 
500
                                break;
 
501
                        case RETOPO_ELLIPSE:
 
502
                                retopo_paint_add_ellipse(rpd, mouse);
 
503
                                break;
 
504
                        }
 
505
                        BIF_undo_push("Retopo paint");
 
506
                }
 
507
 
 
508
                switch(event) {
 
509
                case MOUSEX:
 
510
                case MOUSEY:
 
511
                        switch(G.scene->toolsettings->retopo_paint_tool) {
 
512
                        case RETOPO_PEN:
 
513
                                if(rpd->in_drag && rpd->lines.last) {
 
514
                                        l= rpd->lines.last;
 
515
 
 
516
                                        if(((RetopoPaintPoint*)l->points.last)->loc.x != mouse[0] ||
 
517
                                           ((RetopoPaintPoint*)l->points.last)->loc.y != mouse[1]) {
 
518
                                                add_rppoint(l,mouse[0],mouse[1]);
 
519
                                        }
 
520
                                        rpd->nearest.line= NULL;
 
521
                                        
 
522
                                        break;
 
523
                                } else if(G.scene->toolsettings->retopo_hotspot) { /* Find nearest endpoint */
 
524
                                        float sdist;
 
525
                                        RetopoPaintLine *l= rpd->lines.first;
 
526
                                        RetopoPaintSel n= {NULL,NULL,l,1};
 
527
                                        sdist= rpd->seldist + 10;
 
528
                                        for(l= rpd->lines.first; l; l= l->next) {
 
529
                                                float tdist;
 
530
                                                RetopoPaintPoint *p1= l->points.first, *p2= l->points.last;
 
531
                                                
 
532
                                                tdist= sqrt(pow(mouse[0] - p1->loc.x,2)+pow(mouse[1] - p1->loc.y,2));
 
533
                                                if(tdist < sdist && tdist < rpd->seldist) {
 
534
                                                        sdist= tdist;
 
535
                                                        n.line= l;
 
536
                                                        n.first= 1;
 
537
                                                } else {
 
538
                                                        tdist= sqrt(pow(mouse[0] - p2->loc.x,2)+pow(mouse[1] - p2->loc.y,2));
 
539
                                                        if(tdist < sdist && tdist < rpd->seldist) {
 
540
                                                                sdist= tdist;
 
541
                                                                n.line= l;
 
542
                                                                n.first= 0;
 
543
                                                        }
 
544
                                                }
 
545
                                        }
 
546
                                        
 
547
                                        if(sdist < rpd->seldist)
 
548
                                                rpd->nearest= n;
 
549
                                        else rpd->nearest.line= NULL;
 
550
                                }
 
551
                                break;
 
552
                        case RETOPO_LINE:
 
553
                                break;
 
554
                        case RETOPO_ELLIPSE:
 
555
                                break;
 
556
                        }
 
557
                        allqueue(REDRAWVIEW3D,0);
 
558
                        break;
 
559
                case RETKEY:
 
560
                case PADENTER:
 
561
                        retopo_paint_apply();
 
562
                case ESCKEY:
 
563
                        G.scene->toolsettings->retopo_mode&= ~RETOPO_PAINT;
 
564
                        retopo_free_paint();
 
565
 
 
566
                        BIF_undo_push("Retopo toggle");
 
567
                
 
568
                        allqueue(REDRAWVIEW3D, 1);
 
569
                        allqueue(REDRAWBUTSEDIT, 0);
 
570
                        break;
 
571
                case CKEY:
 
572
                        retopo_paint_toggle_cyclic(rpd->lines.last);
 
573
                        BIF_undo_push("Retopo toggle cyclic");
 
574
                        allqueue(REDRAWVIEW3D, 0);
 
575
                        break;
 
576
                case EKEY:
 
577
                        G.scene->toolsettings->retopo_paint_tool= RETOPO_ELLIPSE;
 
578
                        allqueue(REDRAWVIEW3D, 1);
 
579
                        break;
 
580
                case HKEY:
 
581
                        G.scene->toolsettings->retopo_hotspot= !G.scene->toolsettings->retopo_hotspot;
 
582
                        allqueue(REDRAWVIEW3D, 1);
 
583
                        break;
 
584
                case LKEY:
 
585
                        G.scene->toolsettings->retopo_paint_tool= RETOPO_LINE;
 
586
                        allqueue(REDRAWVIEW3D, 1);
 
587
                        break;
 
588
                case PKEY:
 
589
                        G.scene->toolsettings->retopo_paint_tool= RETOPO_PEN;
 
590
                        allqueue(REDRAWVIEW3D, 1);
 
591
                        break;
 
592
                case XKEY:
 
593
                case DELKEY:
 
594
                        l= rpd->lines.last;
 
595
                        if(l) {
 
596
                                BLI_freelistN(&l->points);
 
597
                                BLI_freelistN(&l->hitlist);
 
598
                                BLI_freelinkN(&rpd->lines, l);
 
599
                                if(rpd->nearest.line == l)
 
600
                                        rpd->nearest.line= NULL;
 
601
                                BIF_undo_push("Erase line");
 
602
                                allqueue(REDRAWVIEW3D, 0);
 
603
                        }
 
604
                        break;
 
605
                case LEFTMOUSE:
 
606
                        if(!rpd->in_drag) { /* Start new drag */
 
607
                                rpd->in_drag= 1;
 
608
                                
 
609
                                if(!rpd->paint_v3d)
 
610
                                        rpd->paint_v3d= G.vd;
 
611
                                
 
612
                                /* Location of mouse down */
 
613
                                rpd->sloc[0]= mouse[0];
 
614
                                rpd->sloc[1]= mouse[1];
 
615
                                
 
616
                                switch(G.scene->toolsettings->retopo_paint_tool) {
 
617
                                case RETOPO_PEN:
 
618
                                        if(rpd->nearest.line) {
 
619
                                                RetopoPaintPoint *p, *pt;
 
620
                                                int i;
 
621
                                                
 
622
                                                BLI_remlink(&rpd->lines,rpd->nearest.line);
 
623
                                                BLI_addtail(&rpd->lines,rpd->nearest.line);
 
624
                                                
 
625
                                                /* Check if we need to reverse the line */
 
626
                                                if(rpd->nearest.first) {
 
627
                                                        for(p= rpd->nearest.line->points.first; p; p= p->prev) {
 
628
                                                                pt= p->prev;
 
629
                                                                p->prev= p->next;
 
630
                                                                p->next= pt;
 
631
                                                        }
 
632
                                                        pt= rpd->nearest.line->points.first;
 
633
                                                        rpd->nearest.line->points.first= rpd->nearest.line->points.last;
 
634
                                                        rpd->nearest.line->points.last= pt;
 
635
                                                        
 
636
                                                        /* Reverse indices */
 
637
                                                        i= 0;
 
638
                                                        for(p= rpd->nearest.line->points.first; p; p= p->next)
 
639
                                                                p->index= i++;
 
640
                                                }
 
641
                                        } else {
 
642
                                                add_rpline(rpd);
 
643
                                                add_rppoint(rpd->lines.last,mouse[0],mouse[1]);
 
644
                                        }
 
645
                                        break;
 
646
                                case RETOPO_LINE:
 
647
                                        break;
 
648
                                case RETOPO_ELLIPSE:
 
649
                                        break;
 
650
                                }
 
651
                                allqueue(REDRAWVIEW3D, 0);
 
652
                        }
 
653
                        break;
 
654
                case MIDDLEMOUSE:
 
655
                case WHEELUPMOUSE:
 
656
                case WHEELDOWNMOUSE:
 
657
                case PAD0: case PAD1: case PAD2: case PAD3: case PAD4:
 
658
                case PAD5: case PAD6: case PAD7: case PAD8: case PAD9:
 
659
                case PADMINUS: case PADPLUSKEY:
 
660
                        return 1;
 
661
                }
 
662
                return 0;
 
663
        } else return 1;
 
664
}
 
665
void retopo_draw_paint_lines()
 
666
{
 
667
        RetopoPaintData *rpd= get_retopo_paint_data();
 
668
 
 
669
        if(rpd && rpd->paint_v3d==G.vd) {
 
670
                RetopoPaintLine *l;
 
671
                RetopoPaintPoint *p;
 
672
 
 
673
                glColor3f(0,0,0);
 
674
                glLineWidth(2);
 
675
 
 
676
                /* Draw existing lines */
 
677
                for(l= rpd->lines.first; l; l= l->next) {
 
678
                        if(l==rpd->lines.last)
 
679
                                glColor3f(0.3,0,0);
 
680
                        glBegin(l->cyclic?GL_LINE_LOOP:GL_LINE_STRIP);
 
681
                        for(p= l->points.first; p; p= p->next) {
 
682
                                glVertex2s(p->loc.x,p->loc.y);
 
683
                        }
 
684
                        glEnd();
 
685
                }
 
686
 
 
687
                /* Draw ellipse */
 
688
                if(G.scene->toolsettings->retopo_paint_tool==RETOPO_ELLIPSE && rpd->in_drag) {
 
689
                        short mouse[2];
 
690
                        getmouseco_areawin(mouse);
 
691
                
 
692
                        setlinestyle(3);
 
693
                        fdrawXORellipse(rpd->sloc[0],rpd->sloc[1],abs(mouse[0]-rpd->sloc[0]),abs(mouse[1]-rpd->sloc[1]));
 
694
                        setlinestyle(0);
 
695
                }
 
696
                else if(G.scene->toolsettings->retopo_paint_tool==RETOPO_LINE && rpd->in_drag) {
 
697
                        short mouse[2];
 
698
                        getmouseco_areawin(mouse);
 
699
 
 
700
                        setlinestyle(3);
 
701
                        sdrawXORline(rpd->sloc[0],rpd->sloc[1],mouse[0],mouse[1]);
 
702
                        setlinestyle(0);
 
703
                }
 
704
                else if(rpd->nearest.line) { /* Draw selection */
 
705
                        RetopoPaintPoint *p= rpd->nearest.first ? rpd->nearest.line->points.first :
 
706
                                rpd->nearest.line->points.last;
 
707
                        if(p)
 
708
                                fdrawXORcirc(p->loc.x, p->loc.y, rpd->seldist);
 
709
                }
 
710
 
 
711
                glLineWidth(1);
 
712
        }
 
713
}
 
714
 
 
715
RetopoPaintData *retopo_paint_data_copy(RetopoPaintData *rpd)
 
716
{
 
717
        RetopoPaintData *copy;
 
718
        RetopoPaintLine *l, *lcp;
 
719
        RetopoPaintPoint *p, *pcp;
 
720
 
 
721
        if(!rpd) return NULL;
 
722
 
 
723
        copy= MEM_mallocN(sizeof(RetopoPaintData),"RetopoPaintDataCopy");
 
724
 
 
725
        memcpy(copy,rpd,sizeof(RetopoPaintData));
 
726
        copy->lines.first= copy->lines.last= NULL;
 
727
        copy->nearest.next= copy->nearest.prev= NULL;
 
728
        copy->nearest.line= NULL;
 
729
        copy->nearest.first= 0;
 
730
        
 
731
        for(l= rpd->lines.first; l; l= l->next) {
 
732
                lcp= MEM_dupallocN(l);
 
733
                BLI_addtail(&copy->lines, lcp);
 
734
                
 
735
                lcp->hitlist.first= lcp->hitlist.last= NULL;
 
736
                lcp->points.first= lcp->points.last= NULL;
 
737
                lcp->cyclic= NULL;
 
738
                
 
739
                for(p= l->points.first; p; p= p->next) {
 
740
                        pcp= MEM_dupallocN(p);
 
741
                        BLI_addtail(&lcp->points, pcp);
 
742
                        pcp->eve= NULL;
 
743
                }
 
744
        }
 
745
 
 
746
        copy->intersections.first= copy->intersections.last= NULL;
 
747
 
 
748
        return copy;
 
749
}
 
750
 
 
751
char retopo_mesh_check(void)
 
752
{
 
753
        return G.obedit && G.obedit->type==OB_MESH && (G.scene->toolsettings->retopo_mode & RETOPO);
 
754
}
 
755
char retopo_curve_check(void)
 
756
{
 
757
        return G.obedit && (G.obedit->type==OB_CURVE ||
 
758
                            G.obedit->type==OB_SURF) && (((Curve*)G.obedit->data)->flag & CU_RETOPO);
 
759
}
 
760
 
 
761
void retopo_toggle(void *j1,void *j2)
 
762
{
 
763
        if(retopo_mesh_check() || retopo_curve_check()) {
 
764
                if(G.vd->depths) G.vd->depths->damaged= 1;
 
765
                retopo_queue_updates(G.vd);
 
766
        } else {
 
767
                if(G.editMesh && G.scene->toolsettings->retopo_mode & RETOPO_PAINT)
 
768
                        retopo_end_okee();
 
769
        }
 
770
 
 
771
        allqueue(REDRAWBUTSEDIT, 0);
 
772
        allqueue(REDRAWVIEW3D, 0);
 
773
}
 
774
 
 
775
static void retopo_do_2d(View3D *v3d, double proj[2], float *v, char adj)
 
776
{
 
777
        /* Check to make sure vert is visible in window */
 
778
        if(proj[0]>0 && proj[1]>0 && proj[0] < v3d->depths->w && proj[1] < v3d->depths->h) {
 
779
                float depth= v3d->depths->depths[((int)proj[1])*v3d->depths->w+((int)proj[0])];
 
780
                double px, py, pz;
 
781
        
 
782
                /* Don't modify the point if it'll be mapped to the background */
 
783
                if(depth==v3d->depths->depth_range[1]) {
 
784
                        if(adj) {
 
785
                                /* Find the depth of (0,0,0); */
 
786
                                gluProject(0,0,0,v3d->retopo_view_data->mats.modelview,
 
787
                                           v3d->retopo_view_data->mats.projection,
 
788
                                           (GLint *)v3d->retopo_view_data->mats.viewport,&px,&py,&pz);
 
789
                                depth= pz;
 
790
                        }
 
791
                        else return;
 
792
                }
 
793
                
 
794
                /* Find 3D location with new depth (unproject) */
 
795
                gluUnProject(proj[0],proj[1],depth,v3d->retopo_view_data->mats.modelview,
 
796
                             v3d->retopo_view_data->mats.projection,
 
797
                             (GLint *)v3d->retopo_view_data->mats.viewport,&px,&py,&pz);
 
798
                
 
799
                v[0]= px;
 
800
                v[1]= py;
 
801
                v[2]= pz;
 
802
        }
 
803
}
 
804
 
 
805
void retopo_do_vert(View3D *v3d, float *v)
 
806
{
 
807
        double proj[3];
 
808
 
 
809
        /* Find 2D location (project) */
 
810
        gluProject(v[0],v[1],v[2],v3d->retopo_view_data->mats.modelview,v3d->retopo_view_data->mats.projection,
 
811
                   (GLint *)v3d->retopo_view_data->mats.viewport,&proj[0],&proj[1],&proj[2]);
 
812
        
 
813
        retopo_do_2d(v3d,proj,v,0);
 
814
}
 
815
 
 
816
void retopo_do_all(void)
 
817
{
 
818
        RetopoViewData *rvd= G.vd->retopo_view_data;
 
819
        if(retopo_mesh_check()) {
 
820
                if(rvd) {
 
821
                        EditMesh *em= G.editMesh;
 
822
                        EditVert *eve;
 
823
                        
 
824
                        /* Apply retopo to all selected vertices */
 
825
                        eve= em->verts.first;
 
826
                        while(eve) {
 
827
                                if(eve->f & SELECT)
 
828
                                        retopo_do_vert(G.vd,eve->co);
 
829
                                eve= eve->next;
 
830
                        }
 
831
                        
 
832
                        DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
 
833
                        allqueue(REDRAWVIEW3D, 0);
 
834
                }
 
835
        }
 
836
        else if(retopo_curve_check()) {
 
837
                if(rvd) {
 
838
                        extern ListBase editNurb;
 
839
                        Nurb *nu;
 
840
                        BPoint *bp;
 
841
                        int i, j;
 
842
 
 
843
                        for(nu= editNurb.first; nu; nu= nu->next)
 
844
                        {
 
845
                                if(nu->type & CU_2D) {
 
846
                                        /* Can't wrap a 2D curve onto a 3D surface */
 
847
                                }
 
848
                                else if(nu->type & CU_BEZIER) {
 
849
                                        for(i=0; i<nu->pntsu; ++i) {
 
850
                                                if(nu->bezt[i].f1 & SELECT)
 
851
                                                        retopo_do_vert(G.vd, nu->bezt[i].vec[0]);
 
852
                                                if(nu->bezt[i].f2 & SELECT)
 
853
                                                        retopo_do_vert(G.vd, nu->bezt[i].vec[1]);
 
854
                                                if(nu->bezt[i].f3 & SELECT)
 
855
                                                        retopo_do_vert(G.vd, nu->bezt[i].vec[2]);
 
856
                                        }
 
857
                                }
 
858
                                else {
 
859
                                        bp= nu->bp;
 
860
                                        for(i=0; i<nu->pntsv; ++i) {
 
861
                                                for(j=0; j<nu->pntsu; ++j, ++bp) {
 
862
                                                        if(bp->f1 & SELECT)
 
863
                                                                retopo_do_vert(G.vd,bp->vec);
 
864
                                                }
 
865
                                        }
 
866
                                }
 
867
                                
 
868
                                testhandlesNurb(nu);
 
869
                        }
 
870
                        
 
871
                        DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
 
872
                        allqueue(REDRAWVIEW3D, 0);                      
 
873
                }
 
874
        }
 
875
}
 
876
 
 
877
void retopo_do_all_cb(void *j1, void *j2)
 
878
{
 
879
        /* This is called from editbuttons, so user needs to specify view */
 
880
        if(!select_area(SPACE_VIEW3D)) return;
 
881
 
 
882
        if(G.vd->drawtype == OB_WIRE) {
 
883
                error("Cannot apply retopo in wireframe mode");
 
884
                return;
 
885
        }
 
886
 
 
887
        retopo_do_all();
 
888
        BIF_undo_push("Retopo all");
 
889
}
 
890
 
 
891
void retopo_queue_updates(View3D *v3d)
 
892
{
 
893
        if(retopo_mesh_check() || retopo_curve_check()) {
 
894
                if(!v3d->retopo_view_data)
 
895
                        v3d->retopo_view_data= MEM_callocN(sizeof(RetopoViewData),"RetopoViewData");
 
896
                
 
897
                v3d->retopo_view_data->queue_matrix_update= 1;
 
898
                
 
899
                allqueue(REDRAWVIEW3D, 0);
 
900
        }
 
901
}
 
902
 
 
903
void retopo_matrix_update(View3D *v3d)
 
904
{
 
905
        RetopoPaintData *rpd= get_retopo_paint_data();
 
906
        if((retopo_mesh_check() || retopo_curve_check()) && (!rpd || rpd->paint_v3d==v3d)) {
 
907
                RetopoViewData *rvd= v3d->retopo_view_data;
 
908
                if(!rvd) {
 
909
                        rvd= MEM_callocN(sizeof(RetopoViewData),"RetopoViewData");
 
910
                        v3d->retopo_view_data= rvd;
 
911
                        rvd->queue_matrix_update= 1;
 
912
                }
 
913
                if(rvd && rvd->queue_matrix_update) {
 
914
                        bgl_get_mats(&rvd->mats);
 
915
 
 
916
                        rvd->queue_matrix_update= 0;
 
917
                }
 
918
        }
 
919
}
 
920
 
 
921
void retopo_free_view_data(View3D *v3d)
 
922
{
 
923
        if(v3d->retopo_view_data) {
 
924
                MEM_freeN(v3d->retopo_view_data);
 
925
                v3d->retopo_view_data= NULL;
 
926
        }
 
927
}