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