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