5f9df666c6741bdd00ff68467ad79959b6984cf3
[blender.git] / source / blender / src / drawgpencil.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) 2008, Blender Foundation
21  * This is a new part of Blender
22  *
23  * Contributor(s): Joshua Leung
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27  
28 #include <stdio.h>
29 #include <string.h>
30 #include <stdlib.h>
31 #include <stddef.h>
32 #include <math.h>
33
34 #ifdef HAVE_CONFIG_H
35 #include <config.h>
36 #endif
37
38 #include "MEM_guardedalloc.h"
39
40 #include "IMB_imbuf.h"
41 #include "IMB_imbuf_types.h"
42
43 #include "BMF_Api.h"
44
45 #include "BLI_arithb.h"
46 #include "BLI_blenlib.h"
47
48 #include "DNA_listBase.h"
49 #include "DNA_gpencil_types.h"
50 #include "DNA_scene_types.h"
51 #include "DNA_screen_types.h"
52 #include "DNA_space_types.h"
53 #include "DNA_userdef_types.h"
54 #include "DNA_view3d_types.h"
55
56 #include "BKE_global.h"
57 #include "BKE_utildefines.h"
58 #include "BKE_blender.h"
59
60 #include "BIF_gl.h"
61 #include "BIF_glutil.h"
62 #include "BIF_butspace.h"
63 #include "BIF_drawseq.h"
64 #include "BIF_graphics.h"
65 #include "BIF_interface.h"
66 #include "BIF_mywindow.h"
67 #include "BIF_resources.h"
68 #include "BIF_space.h"
69 #include "BIF_screen.h"
70 #include "BIF_toolbox.h"
71 #include "BIF_toets.h"
72
73 #include "BDR_gpencil.h"
74 #include "BIF_drawgpencil.h"
75
76 #include "BSE_drawipo.h"
77 #include "BSE_headerbuttons.h"
78 #include "BSE_view.h"
79
80 #include "blendef.h"
81 #include "butspace.h"
82
83 #include "PIL_time.h"
84 #include "mydevice.h"
85
86 /* ************************************************** */
87 /* GREASE PENCIL PANEL-UI DRAWING */
88
89 /* Every space which implements Grease-Pencil functionality should have a panel
90  * for the settings. All of the space-dependent parts should be coded in the panel
91  * code for that space, but the rest is all handled by generic panel here.
92  */
93
94 /* ------- Callbacks ----------- */
95 /* These are just 'dummy wrappers' around gpencil api calls */
96
97 /* make layer active one after being clicked on */
98 void gp_ui_activelayer_cb (void *gpd, void *gpl)
99 {
100         gpencil_layer_setactive(gpd, gpl);
101         
102         scrarea_queue_winredraw(curarea);
103         allqueue(REDRAWACTION, 0);
104 }
105
106 /* rename layer and set active */
107 void gp_ui_renamelayer_cb (void *gpd_arg, void *gpl_arg)
108 {
109         bGPdata *gpd= (bGPdata *)gpd_arg;
110         bGPDlayer *gpl= (bGPDlayer *)gpl_arg;
111         
112         BLI_uniquename(&gpd->layers, gpl, "GP_Layer", offsetof(bGPDlayer, info[0]), 128);
113         gpencil_layer_setactive(gpd, gpl);
114         
115         scrarea_queue_winredraw(curarea);
116         allqueue(REDRAWACTION, 0);
117 }
118
119 /* add a new layer */
120 void gp_ui_addlayer_cb (void *gpd, void *dummy)
121 {
122         gpencil_layer_addnew(gpd);
123         
124         scrarea_queue_winredraw(curarea);
125         allqueue(REDRAWACTION, 0);
126 }
127
128 /* delete active layer */
129 void gp_ui_dellayer_cb (void *gpd, void *dummy)
130 {
131         gpencil_layer_delactive(gpd);
132         
133         scrarea_queue_winredraw(curarea);
134         allqueue(REDRAWACTION, 0);
135 }
136
137 /* delete last stroke of active layer */
138 void gp_ui_delstroke_cb (void *gpd, void *gpl)
139 {
140         bGPDframe *gpf= gpencil_layer_getframe(gpl, CFRA, 0);
141         
142         gpencil_layer_setactive(gpd, gpl);
143         gpencil_frame_delete_laststroke(gpf);
144         
145         scrarea_queue_winredraw(curarea);
146 }
147
148 /* delete active frame of active layer */
149 void gp_ui_delframe_cb (void *gpd, void *gpl)
150 {
151         bGPDframe *gpf= gpencil_layer_getframe(gpl, CFRA, 0);
152         
153         gpencil_layer_setactive(gpd, gpl);
154         gpencil_layer_delframe(gpl, gpf);
155         
156         scrarea_queue_winredraw(curarea);
157         allqueue(REDRAWACTION, 0);
158 }
159
160 /* convert the active layer to geometry */
161 void gp_ui_convertlayer_cb (void *gpd, void *gpl)
162 {
163         gpencil_layer_setactive(gpd, gpl);
164         gpencil_convert_menu();
165         
166         scrarea_queue_winredraw(curarea);
167 }
168
169 /* ------- Drawing Code ------- */
170
171 /* draw the controls for a given layer */
172 static void gp_drawui_layer (uiBlock *block, bGPdata *gpd, bGPDlayer *gpl, short *xco, short *yco)
173 {
174         uiBut *but;
175         short active= (gpl->flag & GP_LAYER_ACTIVE);
176         short width= 314;
177         short height;
178         int rb_col;
179         
180         /* unless button has own callback, it adds this callback to button */
181         uiBlockSetFunc(block, gp_ui_activelayer_cb, gpd, gpl);
182         
183         /* draw header */
184         {
185                 uiBlockSetEmboss(block, UI_EMBOSSN);
186                 
187                 /* rounded header */
188                 if (active) uiBlockSetCol(block, TH_BUT_ACTION);
189                         rb_col= (active)?-20:20;
190                         uiDefBut(block, ROUNDBOX, B_REDR, "", *xco-8, *yco-2, width, 24, NULL, 5.0, 0.0, 15 , rb_col-20, ""); 
191                 if (active) uiBlockSetCol(block, TH_AUTO);
192                 
193                 /* lock toggle */
194                 uiDefIconButBitI(block, ICONTOG, GP_LAYER_LOCKED, B_REDR, ICON_UNLOCKED,        *xco-7, *yco-1, 20, 20, &gpl->flag, 0.0, 0.0, 0, 0, "Layer cannot be modified");
195         }
196         
197         /* when layer is locked or hidden, only draw header */
198         if (gpl->flag & (GP_LAYER_LOCKED|GP_LAYER_HIDE)) {
199                 char name[256]; /* gpl->info is 128, but we need space for 'locked/hidden' as well */
200                 
201                 height= 0;
202                 
203                 /* visibility button (only if hidden but not locked!) */
204                 if ((gpl->flag & GP_LAYER_HIDE) && !(gpl->flag & GP_LAYER_LOCKED))
205                         uiDefIconButBitI(block, ICONTOG, GP_LAYER_HIDE, B_REDR, ICON_RESTRICT_VIEW_OFF, *xco+12, *yco-1, 20, 20, &gpl->flag, 0.0, 0.0, 0, 0, "Visibility of layer");
206                 
207                 /* name */
208                 if (gpl->flag & GP_LAYER_HIDE)
209                         sprintf(name, "%s (Hidden)", gpl->info);
210                 else
211                         sprintf(name, "%s (Locked)", gpl->info);
212                 uiDefBut(block, LABEL, 1, name, *xco+35, *yco, 240, 20, NULL, 0.0, 0.0, 0, 0, "Short description of what this layer is for (optional)");
213                         
214                 /* delete button (only if hidden but not locked!) */
215                 if ((gpl->flag & GP_LAYER_HIDE) & !(gpl->flag & GP_LAYER_LOCKED)) {
216                         but= uiDefIconBut(block, BUT, B_REDR, ICON_X, *xco+(width-30), *yco, 19, 19, NULL, 0.0, 0.0, 0.0, 0.0, "Delete layer");
217                         uiButSetFunc(but, gp_ui_dellayer_cb, gpd, NULL);
218                 }       
219                 uiBlockSetEmboss(block, UI_EMBOSS);
220         }
221         else {
222                 height= 97;
223                 
224                 /* draw rest of header */
225                 {
226                         /* visibility button */
227                         uiDefIconButBitI(block, ICONTOG, GP_LAYER_HIDE, B_REDR, ICON_RESTRICT_VIEW_OFF, *xco+12, *yco-1, 20, 20, &gpl->flag, 0.0, 0.0, 0, 0, "Visibility of layer");
228                         
229                         uiBlockSetEmboss(block, UI_EMBOSS);
230                         
231                         /* name */
232                         but= uiDefButC(block, TEX, B_REDR, "Info:",     *xco+36, *yco, 240, 19, gpl->info, 0, 127, 0, 0, "Short description of what this layer is for (optional)");
233                         uiButSetFunc(but, gp_ui_renamelayer_cb, gpd, gpl);
234                         
235                         /* delete 'button' */
236                         uiBlockSetEmboss(block, UI_EMBOSSN);
237                         
238                         but= uiDefIconBut(block, BUT, B_REDR, ICON_X, *xco+(width-30), *yco, 19, 19, NULL, 0.0, 0.0, 0.0, 0.0, "Delete layer");
239                         uiButSetFunc(but, gp_ui_dellayer_cb, gpd, NULL);
240                         
241                         uiBlockSetEmboss(block, UI_EMBOSS);
242                 }
243                 
244                 /* draw backdrop */
245                 if (active) uiBlockSetCol(block, TH_BUT_ACTION);
246                         uiDefBut(block, ROUNDBOX, B_DIFF, "", *xco-8, *yco-height, width, height-1, NULL, 5.0, 0.0, 12, rb_col, ""); 
247                 if (active) uiBlockSetCol(block, TH_AUTO);
248                 
249                 /* draw settings */
250                 {
251                         /* color */
252                         uiBlockBeginAlign(block);
253                                 uiDefButF(block, COL, B_REDR, "",               *xco, *yco-26, 150, 19, gpl->color, 0, 0, 0, 0, "Color to use for all strokes on this Grease Pencil Layer");
254                                 uiDefButF(block, NUMSLI, B_REDR, "Opacity: ",           *xco,*yco-45,150,19, &gpl->color[3], 0.3, 1.0, 0, 0, "Visibility of stroke (0.3 to 1.0)");
255                         uiBlockEndAlign(block);
256                         
257                         /* stroke thickness */
258                         uiDefButS(block, NUMSLI, B_REDR, "Thickness:",  *xco, *yco-75, 150, 20, &gpl->thickness, 1, 10, 0, 0, "Thickness of strokes (in pixels)");
259                         
260                         /* debugging options */
261                         if (G.f & G_DEBUG) {
262                                 uiDefButBitI(block, TOG, GP_LAYER_DRAWDEBUG, B_REDR, "Show Points", *xco, *yco-95, 150, 20, &gpl->flag, 0, 0, 0, 0, "Show points which form the strokes");
263                         }
264                         
265                         /* onion-skinning */
266                         uiBlockBeginAlign(block);
267                                 uiDefButBitI(block, TOG, GP_LAYER_ONIONSKIN, B_REDR, "Onion-Skin", *xco+160, *yco-26, 140, 20, &gpl->flag, 0, 0, 0, 0, "Ghost frames on either side of frame");
268                                 uiDefButS(block, NUMSLI, B_REDR, "GStep:",      *xco+160, *yco-46, 140, 20, &gpl->gstep, 0, 120, 0, 0, "Max number of frames on either side of active frame to show (0 = just 'first' available sketch on either side)");
269                         uiBlockEndAlign(block);
270                         
271                         /* options */
272                         uiBlockBeginAlign(block);
273                                 if (curarea->spacetype == SPACE_VIEW3D) {
274                                         but= uiDefBut(block, BUT, B_REDR, "Convert to...", *xco+160, *yco-75, 140, 20, NULL, 0, 0, 0, 0, "Converts this layer's strokes to geometry (Hotkey = Alt-Shift-C)");
275                                         uiButSetFunc(but, gp_ui_convertlayer_cb, gpd, gpl);
276                                 }
277                                 else {
278                                         but= uiDefBut(block, BUT, B_REDR, "Del Active Frame", *xco+160, *yco-75, 140, 20, NULL, 0, 0, 0, 0, "Erases the the active frame for this layer (Hotkey = Alt-XKEY/DEL)");
279                                         uiButSetFunc(but, gp_ui_delframe_cb, gpd, gpl);
280                                 }
281                                 
282                                 but= uiDefBut(block, BUT, B_REDR, "Del Last Stroke", *xco+160, *yco-95, 140, 20, NULL, 0, 0, 0, 0, "Erases the last stroke from the active frame (Hotkey = Alt-XKEY/DEL)");
283                                 uiButSetFunc(but, gp_ui_delstroke_cb, gpd, gpl);
284                         uiBlockEndAlign(block);
285                 }
286         }
287         
288         /* adjust height for new to start */
289         (*yco) -= (height + 27); 
290
291
292 /* Draw the contents for a grease-pencil panel. This assumes several things:
293  *      - that panel has been created, is 318 x 204. max yco is 225
294  *      - that a toggle for turning on/off gpencil drawing is 150 x 20, starting from (10,225)
295  *              which is basically the top left-hand corner
296  * It will return the amount of extra space to extend the panel by
297  */
298 short draw_gpencil_panel (uiBlock *block, bGPdata *gpd, ScrArea *sa)
299 {
300         uiBut *but;
301         bGPDlayer *gpl;
302         short xco= 10, yco= 170;
303         
304         /* draw gpd settings first */
305         {
306                 /* add new layer buttons */
307                 but= uiDefBut(block, BUT, B_REDR, "Add New Layer", 10,205,150,20, 0, 0, 0, 0, 0, "Adds a new Grease Pencil Layer");
308                 uiButSetFunc(but, gp_ui_addlayer_cb, gpd, NULL);
309                 
310                 
311                 /* show override lmb-clicks button + painting lock */
312                 uiBlockBeginAlign(block);
313                         if ((gpd->flag & GP_DATA_EDITPAINT)==0) {
314                                 uiDefButBitI(block, TOG, GP_DATA_EDITPAINT, B_REDR, "Draw Mode", 170, 225, 130, 20, &gpd->flag, 0, 0, 0, 0, "Interpret click-drag as new strokes");
315                                 
316                                 uiBlockSetCol(block, TH_BUT_SETTING);
317                                         uiDefIconButBitI(block, ICONTOG, GP_DATA_LMBPLOCK, B_REDR, ICON_UNLOCKED,       300, 225, 20, 20, &gpd->flag, 0.0, 0.0, 0, 0, "Painting cannot occur with Shift-LMB (when making selections)");
318                                 uiBlockSetCol(block, TH_AUTO);
319                         }
320                         else
321                                 uiDefButBitI(block, TOG, GP_DATA_EDITPAINT, B_REDR, "Draw Mode", 170, 225, 150, 20, &gpd->flag, 0, 0, 0, 0, "Interpret click-drag as new strokes");
322                 uiBlockEndAlign(block);
323                 
324                 /* 'view align' button (naming depends on context) */
325                 if (sa->spacetype == SPACE_VIEW3D)
326                         uiDefButBitI(block, TOG, GP_DATA_VIEWALIGN, B_REDR, "Sketch in 3D", 170, 205, 150, 20, &gpd->flag, 0, 0, 0, 0, "New strokes are added in 3D-space");
327                 else
328                         uiDefButBitI(block, TOG, GP_DATA_VIEWALIGN, B_REDR, "Stick to View", 170, 205, 150, 20, &gpd->flag, 0, 0, 0, 0, "New strokes are added on 2d-canvas");
329         }
330         
331         /* draw for each layer */
332         for (gpl= gpd->layers.first; gpl; gpl= gpl->next) {
333                 gp_drawui_layer(block, gpd, gpl, &xco, &yco);
334         }
335         
336         /* return new height if necessary */
337         return (yco < 0) ? (204 - yco) : 204;
338 }       
339
340 /* ************************************************** */
341 /* GREASE PENCIL DRAWING */
342
343 /* ----- General Defines ------ */
344
345 /* flags for sflag */
346 enum {
347         GP_DRAWDATA_NOSTATUS    = (1<<0),       /* don't draw status info */
348         GP_DRAWDATA_ONLY3D              = (1<<1),       /* only draw 3d-strokes */
349         GP_DRAWDATA_ONLYV2D             = (1<<2),       /* only draw 'canvas' strokes */
350         GP_DRAWDATA_ONLYI2D             = (1<<3),       /* only draw 'image' strokes */
351 };
352
353 /* thickness above which we should use special drawing */
354 #define GP_DRAWTHICKNESS_SPECIAL        3
355
356 /* ----- Tool Buffer Drawing ------ */
357
358 /* draw stroke defined in buffer (simple ogl lines/points for now, as dotted lines) */
359 static void gp_draw_stroke_buffer (tGPspoint *points, int totpoints, short thickness, short dflag, short sflag)
360 {
361         tGPspoint *pt;
362         int i;
363         
364         /* error checking */
365         if ((points == NULL) || (totpoints <= 0))
366                 return;
367         
368         /* check if buffer can be drawn */
369         if (dflag & (GP_DRAWDATA_ONLY3D|GP_DRAWDATA_ONLYV2D))
370                 return;
371         
372         /* if drawing a single point, draw it larger */ 
373         if (totpoints == 1) {           
374                 /* draw point */
375                 glBegin(GL_POINTS);
376                         glVertex2f(points->x, points->y);
377                 glEnd();
378         }
379         else if (sflag & GP_STROKE_ERASER) {
380                 /* don't draw stroke at all! */
381         }
382         else {
383                 float oldpressure = 0.0f;
384                 
385                 /* draw stroke curve */
386                 if (G.f & G_DEBUG) setlinestyle(2);
387                 
388                 glBegin(GL_LINE_STRIP);
389                 for (i=0, pt=points; i < totpoints && pt; i++, pt++) {
390                         if (fabs(pt->pressure - oldpressure) > 0.2f) {
391                                 glEnd();
392                                 glLineWidth(pt->pressure * thickness);
393                                 glBegin(GL_LINE_STRIP);
394                                 
395                                 glVertex2f(pt->x, pt->y);
396                                 
397                                 oldpressure = pt->pressure;
398                         }
399                         else
400                                 glVertex2f(pt->x, pt->y);
401                 }
402                 glEnd();
403                 
404                 if (G.f & G_DEBUG) setlinestyle(0);
405         }
406 }
407
408 /* ----- Existing Strokes Drawing (3D and Point) ------ */
409
410 /* draw a given stroke - just a single dot (only one point) */
411 static void gp_draw_stroke_point (bGPDspoint *points, short thickness, short sflag, int offsx, int offsy, int winx, int winy)
412 {
413         /* draw point */
414         if (sflag & GP_STROKE_3DSPACE) {
415                 glBegin(GL_POINTS);
416                         glVertex3f(points->x, points->y, points->z);
417                 glEnd();
418         }
419         else {
420                 float co[2];
421                 
422                 /* get coordinates of point */
423                 if (sflag & GP_STROKE_2DSPACE) {
424                         co[0]= points->x;
425                         co[1]= points->y;
426                 }
427                 else if (sflag & GP_STROKE_2DIMAGE) {
428                         co[0]= (points->x * winx) + offsx;
429                         co[1]= (points->y * winy) + offsy;
430                 }
431                 else {
432                         co[0]= (points->x / 1000 * winx);
433                         co[1]= (points->y / 1000 * winy);
434                 }
435                 
436                 /* if thickness is less than GP_DRAWTHICKNESS_SPECIAL, simple dot looks ok
437                  *      - also mandatory in if Image Editor 'image-based' dot
438                  */
439                 if ( (thickness < GP_DRAWTHICKNESS_SPECIAL) ||
440                          ((curarea->spacetype==SPACE_IMAGE) && (sflag & GP_STROKE_2DSPACE)) )
441                 {
442                         glBegin(GL_POINTS);
443                                 glVertex2fv(co);
444                         glEnd();
445                 }
446                 else 
447                 {
448                         /* draw filled circle as is done in circf (but without the matrix push/pops which screwed things up) */
449                         GLUquadricObj *qobj = gluNewQuadric(); 
450                         
451                         gluQuadricDrawStyle(qobj, GLU_FILL); 
452                         
453                         /* need to translate drawing position, but must reset after too! */
454                         glTranslatef(co[0],  co[1], 0.); 
455                         gluDisk(qobj, 0.0,  thickness, 32, 1); 
456                         glTranslatef(-co[0],  -co[1], 0.);
457                         
458                         gluDeleteQuadric(qobj);
459                 }
460         }
461 }
462
463 /* draw a given stroke in 3d (i.e. in 3d-space), using simple ogl lines */
464 static void gp_draw_stroke_3d (bGPDspoint *points, int totpoints, short thickness, short dflag, short sflag, short debug, int winx, int winy)
465 {
466         bGPDspoint *pt;
467         float oldpressure = 0.0f;
468         int i;
469         
470         /* draw stroke curve */
471         glBegin(GL_LINE_STRIP);
472         for (i=0, pt=points; i < totpoints && pt; i++, pt++) {
473                 if (fabs(pt->pressure - oldpressure) > 0.2f) {
474                         glEnd();
475                         glLineWidth(pt->pressure * thickness);
476                         glBegin(GL_LINE_STRIP);
477                         
478                         glVertex3f(pt->x, pt->y, pt->z);
479                         
480                         oldpressure = pt->pressure;
481                 }
482                 else
483                         glVertex3f(pt->x, pt->y, pt->z);
484         }
485         glEnd();
486         
487         /* draw debug points of curve on top? */
488         if (debug) {
489                 glBegin(GL_POINTS);
490                 for (i=0, pt=points; i < totpoints && pt; i++, pt++)
491                         glVertex3f(pt->x, pt->y, pt->z);
492                 glEnd();
493         }
494 }
495
496 /* ----- Fancy 2D-Stroke Drawing ------ */
497
498 /* draw a given stroke in 2d */
499 static void gp_draw_stroke (bGPDspoint *points, int totpoints, short thickness, short dflag, short sflag, 
500                                                         short debug, int offsx, int offsy, int winx, int winy)
501 {       
502         /* if thickness is less than GP_DRAWTHICKNESS_SPECIAL, 'smooth' opengl lines look better
503          *      - 'smooth' opengl lines are also required if Image Editor 'image-based' stroke
504          */
505         if ( (thickness < GP_DRAWTHICKNESS_SPECIAL) || 
506                  ((curarea->spacetype==SPACE_IMAGE) && (dflag & GP_DRAWDATA_ONLYV2D)) ) 
507         {
508                 bGPDspoint *pt;
509                 int i;
510                 
511                 glBegin(GL_LINE_STRIP);
512                 for (i=0, pt=points; i < totpoints && pt; i++, pt++) {
513                         if (sflag & GP_STROKE_2DSPACE) {
514                                 glVertex2f(pt->x, pt->y);
515                         }
516                         else if (sflag & GP_STROKE_2DIMAGE) {
517                                 const float x= (pt->x * winx) + offsx;
518                                 const float y= (pt->y * winy) + offsy;
519                                 
520                                 glVertex2f(x, y);
521                         }
522                         else {
523                                 const float x= (pt->x / 1000 * winx);
524                                 const float y= (pt->y / 1000 * winy);
525                                 
526                                 glVertex2f(x, y);
527                         }
528                 }
529                 glEnd();
530         }
531         
532         /* tesselation code - draw stroke as series of connected quads with connection
533          * edges rotated to minimise shrinking artifacts, and rounded endcaps
534          */
535         else 
536         { 
537                 bGPDspoint *pt1, *pt2;
538                 float pm[2];
539                 int i;
540                 
541                 glShadeModel(GL_FLAT);
542                 glBegin(GL_QUADS);
543                 
544                 for (i=0, pt1=points, pt2=points+1; i < (totpoints-1); i++, pt1++, pt2++) {
545                         float s0[2], s1[2];             /* segment 'center' points */
546                         float t0[2], t1[2];             /* tesselated coordinates */
547                         float m1[2], m2[2];             /* gradient and normal */
548                         float mt[2], sc[2];             /* gradient for thickness, point for end-cap */
549                         float pthick;                   /* thickness at segment point */
550                         
551                         /* get x and y coordinates from points */
552                         if (sflag & GP_STROKE_2DSPACE) {
553                                 s0[0]= pt1->x;          s0[1]= pt1->y;
554                                 s1[0]= pt2->x;          s1[1]= pt2->y;
555                         }
556                         else if (sflag & GP_STROKE_2DIMAGE) {
557                                 s0[0]= (pt1->x * winx) + offsx;                 
558                                 s0[1]= (pt1->y * winy) + offsy;
559                                 s1[0]= (pt2->x * winx) + offsx;         
560                                 s1[1]= (pt2->y * winy) + offsy;
561                         }
562                         else {
563                                 s0[0]= (pt1->x / 1000 * winx);
564                                 s0[1]= (pt1->y / 1000 * winy);
565                                 s1[0]= (pt2->x / 1000 * winx);
566                                 s1[1]= (pt2->y / 1000 * winy);
567                         }               
568                         
569                         /* calculate gradient and normal - 'angle'=(ny/nx) */
570                         m1[1]= s1[1] - s0[1];           
571                         m1[0]= s1[0] - s0[0];
572                         Normalize2(m1);
573                         m2[1]= -m1[0];
574                         m2[0]= m1[1];
575                         
576                         /* always use pressure from first point here */
577                         pthick= (pt1->pressure * thickness);
578                         
579                         /* if the first segment, start of segment is segment's normal */
580                         if (i == 0) {
581                                 /* draw start cap first 
582                                  *      - make points slightly closer to center (about halfway across) 
583                                  */                             
584                                 mt[0]= m2[0] * pthick * 0.5;
585                                 mt[1]= m2[1] * pthick * 0.5;
586                                 sc[0]= s0[0] - (m1[0] * pthick * 0.75);
587                                 sc[1]= s0[1] - (m1[1] * pthick * 0.75);
588                                 
589                                 t0[0]= sc[0] - mt[0];
590                                 t0[1]= sc[1] - mt[1];
591                                 t1[0]= sc[0] + mt[0];
592                                 t1[1]= sc[1] + mt[1];
593                                 
594                                 glVertex2fv(t0);
595                                 glVertex2fv(t1);
596                                 
597                                 /* calculate points for start of segment */
598                                 mt[0]= m2[0] * pthick;
599                                 mt[1]= m2[1] * pthick;
600                                 
601                                 t0[0]= s0[0] - mt[0];
602                                 t0[1]= s0[1] - mt[1];
603                                 t1[0]= s0[0] + mt[0];
604                                 t1[1]= s0[1] + mt[1];
605                                 
606                                 /* draw this line twice (first to finish off start cap, then for stroke) */
607                                 glVertex2fv(t1);
608                                 glVertex2fv(t0);
609                                 glVertex2fv(t0);
610                                 glVertex2fv(t1);
611                         }
612                         /* if not the first segment, use bisector of angle between segments */
613                         else {
614                                 float mb[2];            /* bisector normal */
615                                 float athick, dfac;             /* actual thickness, difference between thicknesses */
616                                 
617                                 /* calculate gradient of bisector (as average of normals) */
618                                 mb[0]= (pm[0] + m2[0]) / 2;
619                                 mb[1]= (pm[1] + m2[1]) / 2;
620                                 Normalize2(mb);
621                                 
622                                 /* calculate gradient to apply 
623                                  *      - as basis, use just pthick * bisector gradient
624                                  *      - if cross-section not as thick as it should be, add extra padding to fix it
625                                  */
626                                 mt[0]= mb[0] * pthick;
627                                 mt[1]= mb[1] * pthick;
628                                 athick= Vec2Length(mt);
629                                 dfac= pthick - (athick * 2);
630                                 if ( ((athick * 2) < pthick) && (IS_EQ(athick, pthick)==0) ) 
631                                 {
632                                         mt[0] += (mb[0] * dfac);
633                                         mt[1] += (mb[1] * dfac);
634                                 }       
635                                 
636                                 /* calculate points for start of segment */
637                                 t0[0]= s0[0] - mt[0];
638                                 t0[1]= s0[1] - mt[1];
639                                 t1[0]= s0[0] + mt[0];
640                                 t1[1]= s0[1] + mt[1];
641                                 
642                                 /* draw this line twice (once for end of current segment, and once for start of next) */
643                                 glVertex2fv(t1);
644                                 glVertex2fv(t0);
645                                 glVertex2fv(t0);
646                                 glVertex2fv(t1);
647                         }
648                         
649                         /* if last segment, also draw end of segment (defined as segment's normal) */
650                         if (i == totpoints-2) {
651                                 /* for once, we use second point's pressure (otherwise it won't be drawn) */
652                                 pthick= (pt2->pressure * thickness);
653                                 
654                                 /* calculate points for end of segment */
655                                 mt[0]= m2[0] * pthick;
656                                 mt[1]= m2[1] * pthick;
657                                 
658                                 t0[0]= s1[0] - mt[0];
659                                 t0[1]= s1[1] - mt[1];
660                                 t1[0]= s1[0] + mt[0];
661                                 t1[1]= s1[1] + mt[1];
662                                 
663                                 /* draw this line twice (once for end of stroke, and once for endcap)*/
664                                 glVertex2fv(t1);
665                                 glVertex2fv(t0);
666                                 glVertex2fv(t0);
667                                 glVertex2fv(t1);
668                                 
669                                 
670                                 /* draw end cap as last step 
671                                  *      - make points slightly closer to center (about halfway across) 
672                                  */                             
673                                 mt[0]= m2[0] * pthick * 0.5;
674                                 mt[1]= m2[1] * pthick * 0.5;
675                                 sc[0]= s1[0] + (m1[0] * pthick * 0.75);
676                                 sc[1]= s1[1] + (m1[1] * pthick * 0.75);
677                                 
678                                 t0[0]= sc[0] - mt[0];
679                                 t0[1]= sc[1] - mt[1];
680                                 t1[0]= sc[0] + mt[0];
681                                 t1[1]= sc[1] + mt[1];
682                                 
683                                 glVertex2fv(t1);
684                                 glVertex2fv(t0);
685                         }
686                         
687                         /* store stroke's 'natural' normal for next stroke to use */
688                         Vec2Copyf(pm, m2);
689                 }
690                 
691                 glEnd();
692         }
693         
694         /* draw debug points of curve on top? (original stroke points) */
695         if (debug) {
696                 bGPDspoint *pt;
697                 int i;
698                 
699                 glBegin(GL_POINTS);
700                 for (i=0, pt=points; i < totpoints && pt; i++, pt++) {
701                         if (sflag & GP_STROKE_2DSPACE) {
702                                 glVertex2f(pt->x, pt->y);
703                         }
704                         else if (sflag & GP_STROKE_2DIMAGE) {
705                                 const float x= (pt->x * winx) + offsx;
706                                 const float y= (pt->y * winy) + offsy;
707                                 
708                                 glVertex2f(x, y);
709                         }
710                         else {
711                                 const float x= (pt->x / 1000 * winx);
712                                 const float y= (pt->y / 1000 * winy);
713                                 
714                                 glVertex2f(x, y);
715                         }
716                 }
717                 glEnd();
718         }
719 }
720
721 /* ----- General Drawing ------ */
722
723 /* draw a set of strokes */
724 static void gp_draw_strokes (bGPDframe *gpf, int offsx, int offsy, int winx, int winy, int dflag,  
725                                                          short debug, short lthick, float color[4])
726 {
727         bGPDstroke *gps;
728         
729         /* set color first (may need to reset it again later too) */
730         glColor4f(color[0], color[1], color[2], color[3]);
731         
732         for (gps= gpf->strokes.first; gps; gps= gps->next) {
733                 /* check if stroke can be drawn - checks here generally fall into pairs */
734                 if ((dflag & GP_DRAWDATA_ONLY3D) && !(gps->flag & GP_STROKE_3DSPACE))
735                         continue;
736                 if (!(dflag & GP_DRAWDATA_ONLY3D) && (gps->flag & GP_STROKE_3DSPACE))
737                         continue;
738                 if ((dflag & GP_DRAWDATA_ONLYV2D) && !(gps->flag & GP_STROKE_2DSPACE))
739                         continue;
740                 if (!(dflag & GP_DRAWDATA_ONLYV2D) && (gps->flag & GP_STROKE_2DSPACE))
741                         continue;
742                 if ((dflag & GP_DRAWDATA_ONLYI2D) && !(gps->flag & GP_STROKE_2DIMAGE))
743                         continue;
744                 if (!(dflag & GP_DRAWDATA_ONLYI2D) && (gps->flag & GP_STROKE_2DIMAGE))
745                         continue;
746                 if ((gps->points == 0) || (gps->totpoints < 1))
747                         continue;
748                 
749                 /* check which stroke-drawer to use */
750                 if (gps->totpoints == 1)
751                         gp_draw_stroke_point(gps->points, lthick, gps->flag, offsx, offsy, winx, winy);
752                 else if (dflag & GP_DRAWDATA_ONLY3D)
753                         gp_draw_stroke_3d(gps->points, gps->totpoints, lthick, dflag, gps->flag, debug, winx, winy);
754                 else if (gps->totpoints > 1)    
755                         gp_draw_stroke(gps->points, gps->totpoints, lthick, dflag, gps->flag, debug, offsx, offsy, winx, winy);
756         }
757 }
758
759 /* draw grease-pencil datablock */
760 static void gp_draw_data (bGPdata *gpd, int offsx, int offsy, int winx, int winy, int dflag)
761 {
762         bGPDlayer *gpl, *actlay=NULL;
763         
764         /* turn on smooth lines (i.e. anti-aliasing) */
765         glEnable(GL_LINE_SMOOTH);
766         
767         /* turn on alpha-blending */
768         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
769         glEnable(GL_BLEND);
770                 
771         /* loop over layers, drawing them */
772         for (gpl= gpd->layers.first; gpl; gpl= gpl->next) {
773                 bGPDframe *gpf;
774                 
775                 short debug = (gpl->flag & GP_LAYER_DRAWDEBUG) ? 1 : 0;
776                 short lthick= gpl->thickness;
777                 float color[4], tcolor[4];
778                 
779                 /* don't draw layer if hidden */
780                 if (gpl->flag & GP_LAYER_HIDE) 
781                         continue;
782                 
783                 /* if layer is active one, store pointer to it */
784                 if (gpl->flag & GP_LAYER_ACTIVE)
785                         actlay= gpl;
786                 
787                 /* get frame to draw */
788                 gpf= gpencil_layer_getframe(gpl, CFRA, 0);
789                 if (gpf == NULL) 
790                         continue;
791                 
792                 /* set color, stroke thickness, and point size */
793                 glLineWidth(lthick);
794                 QUATCOPY(color, gpl->color); // just for copying 4 array elements
795                 QUATCOPY(tcolor, gpl->color); // additional copy of color (for ghosting)
796                 glColor4f(color[0], color[1], color[2], color[3]);
797                 glPointSize(gpl->thickness + 2);
798                 
799                 /* draw 'onionskins' (frame left + right) */
800                 if (gpl->flag & GP_LAYER_ONIONSKIN) {
801                         /* drawing method - only immediately surrounding (gstep = 0), or within a frame range on either side (gstep > 0)*/                      
802                         if (gpl->gstep) {
803                                 bGPDframe *gf;
804                                 short i;
805                                 
806                                 /* draw previous frames first */
807                                 for (gf=gpf->prev, i=0; gf; gf=gf->prev, i++) {
808                                         /* check if frame is drawable */
809                                         if ((gpf->framenum - gf->framenum) <= gpl->gstep) {
810                                                 /* alpha decreases with distance from curframe index */
811                                                 tcolor[3] = color[3] - (i/gpl->gstep);
812                                                 gp_draw_strokes(gf, offsx, offsy, winx, winy, dflag, debug, lthick, tcolor);
813                                         }
814                                         else 
815                                                 break;
816                                 }
817                                 
818                                 /* now draw next frames */
819                                 for (gf= gpf->next, i=0; gf; gf=gf->next, i++) {
820                                         /* check if frame is drawable */
821                                         if ((gf->framenum - gpf->framenum) <= gpl->gstep) {
822                                                 /* alpha decreases with distance from curframe index */
823                                                 tcolor[3] = color[3] - (i/gpl->gstep);
824                                                 gp_draw_strokes(gf, offsx, offsy, winx, winy, dflag, debug, lthick, tcolor);
825                                         }
826                                         else 
827                                                 break;
828                                 }       
829                                 
830                                 /* restore alpha */
831                                 glColor4f(color[0], color[1], color[2], color[3]);
832                         }
833                         else {
834                                 /* draw the strokes for the ghost frames (at half of the alpha set by user) */
835                                 if (gpf->prev) {
836                                         tcolor[3] = (color[3] / 7);
837                                         gp_draw_strokes(gpf->prev, offsx, offsy, winx, winy, dflag, debug, lthick, tcolor);
838                                 }
839                                 
840                                 if (gpf->next) {
841                                         tcolor[3] = (color[3] / 4);
842                                         gp_draw_strokes(gpf->next, offsx, offsy, winx, winy, dflag, debug, lthick, tcolor);
843                                 }
844                                 
845                                 /* restore alpha */
846                                 glColor4f(color[0], color[1], color[2], color[3]);
847                         }
848                 }
849                 
850                 /* draw the strokes already in active frame */
851                 tcolor[3]= color[3];
852                 gp_draw_strokes(gpf, offsx, offsy, winx, winy, dflag, debug, lthick, tcolor);
853                 
854                 /* Check if may need to draw the active stroke cache, only if this layer is the active layer
855                  * that is being edited. (Stroke buffer is currently stored in gp-data)
856                  */
857                 if ((G.f & G_GREASEPENCIL) && (gpl->flag & GP_LAYER_ACTIVE) &&
858                         (gpf->flag & GP_FRAME_PAINT)) 
859                 {
860                         /* Buffer stroke needs to be drawn with a different linestyle to help differentiate them from normal strokes. */
861                         gp_draw_stroke_buffer(gpd->sbuffer, gpd->sbuffer_size, lthick, dflag, gpd->sbuffer_sflag);
862                 }
863         }
864         
865         /* turn off alpha blending, then smooth lines */
866         glDisable(GL_BLEND); // alpha blending
867         glDisable(GL_LINE_SMOOTH); // smooth lines
868         
869         /* show info for debugging the status of gpencil */
870         if ( ((dflag & GP_DRAWDATA_NOSTATUS)==0) && (gpd->flag & GP_DATA_DISPINFO) ) {
871                 char printable[256];
872                 short xmax;
873                 
874                 /* get text to display */
875                 if (actlay) {
876                         if (gpd->flag & GP_DATA_EDITPAINT)
877                                 BIF_ThemeColor(TH_BONE_POSE); // should be blue-ish
878                         else if (actlay->actframe == NULL)
879                                 BIF_ThemeColor(TH_REDALERT);
880                         else if (actlay->actframe->framenum == CFRA)
881                                 BIF_ThemeColor(TH_VERTEX_SELECT); // should be yellow
882                         else
883                                 BIF_ThemeColor(TH_TEXT_HI);
884                         
885                         if (actlay->actframe) {
886                                 sprintf(printable, "GPencil: Layer ('%s'), Frame (%d)%s", 
887                                         actlay->info, actlay->actframe->framenum,
888                                         ((gpd->flag & GP_DATA_EDITPAINT)?" , Draw Mode On":"") );
889                         }
890                         else {
891                                 sprintf(printable, "GPencil: Layer ('%s'), Frame <None>%s", 
892                                         actlay->info, ((gpd->flag & GP_DATA_EDITPAINT)?" , Draw Mode On":"") );
893                         }
894                 }
895                 else {
896                         BIF_ThemeColor(TH_REDALERT);
897                         sprintf(printable, "GPencil: Layer <None>");
898                 }
899                 xmax= GetButStringLength(printable);
900                 
901                 /* only draw it if view is wide enough (assume padding of 20 is enough for now) */
902                 if (winx > (xmax + 20)) { 
903                         glRasterPos2i(winx-xmax, winy-20);
904                         BMF_DrawString(G.fonts, printable);
905                 }
906         }
907         
908         /* restore initial gl conditions */
909         glLineWidth(1.0);
910         glPointSize(1.0);
911         glColor4f(0, 0, 0, 1);
912 }
913
914 /* ----- Grease Pencil Sketches Drawing API ------ */
915
916 /* draw grease-pencil sketches to specified 2d-view that uses ibuf corrections */
917 void draw_gpencil_2dimage (ScrArea *sa, ImBuf *ibuf)
918 {
919         bGPdata *gpd;
920         int offsx, offsy, sizex, sizey;
921         int dflag = GP_DRAWDATA_NOSTATUS;
922         
923         /* check that we have grease-pencil stuff to draw */
924         if (ELEM(NULL, sa, ibuf)) return;
925         gpd= gpencil_data_getactive(sa);
926         if (gpd == NULL) return;
927         
928         /* calculate rect */
929         switch (sa->spacetype) {
930                 case SPACE_IMAGE: /* image */
931                 {
932                         SpaceImage *sima= (SpaceImage *)sa->spacedata.first;
933                         
934                         /* just draw using standard scaling (settings here are currently ignored anyways) */
935                         // FIXME: the opengl poly-strokes don't draw at right thickness when done this way, so disabled
936                         offsx= 0;
937                         offsy= 0;
938                         sizex= sa->winx;
939                         sizey= sa->winy;
940                         
941                         myortho2(sima->v2d.cur.xmin, sima->v2d.cur.xmax, sima->v2d.cur.ymin, sima->v2d.cur.ymax);
942                         
943                         dflag |= GP_DRAWDATA_ONLYV2D;
944                 }
945                         break;
946                         
947                 case SPACE_SEQ: /* sequence */
948                 {
949                         SpaceSeq *sseq= (SpaceSeq *)sa->spacedata.first;
950                         float zoom, zoomx, zoomy;
951                         
952                         /* calculate accessory values */
953                         zoom= SEQ_ZOOM_FAC(sseq->zoom);
954                         if (sseq->mainb == SEQ_DRAW_IMG_IMBUF) {
955                                 zoomx = zoom * ((float)G.scene->r.xasp / (float)G.scene->r.yasp);
956                                 zoomy = zoom;
957                         } 
958                         else
959                                 zoomx = zoomy = zoom;
960                         
961                         /* calculate transforms (Note: we use ibuf here, as we have it) */
962                         sizex= zoomx * ibuf->x;
963                         sizey= zoomy * ibuf->y;
964                         offsx= (sa->winx-sizex)/2 + sseq->xof;
965                         offsy= (sa->winy-sizey)/2 + sseq->yof;
966                         
967                         dflag |= GP_DRAWDATA_ONLYI2D;
968                 }
969                         break;
970                         
971                 default: /* for spacetype not yet handled */
972                         offsx= 0;
973                         offsy= 0;
974                         sizex= sa->winx;
975                         sizey= sa->winy;
976                         
977                         dflag |= GP_DRAWDATA_ONLYI2D;
978                         break;
979         }
980         
981         
982         /* draw it! */
983         gp_draw_data(gpd, offsx, offsy, sizex, sizey, dflag);
984 }
985
986 /* draw grease-pencil sketches to specified 2d-view assuming that matrices are already set correctly 
987  * Note: this gets called twice - first time with onlyv2d=1 to draw 'canvas' strokes, second time with onlyv2d=0 for screen-aligned strokes
988  */
989 void draw_gpencil_2dview (ScrArea *sa, short onlyv2d)
990 {
991         bGPdata *gpd;
992         int dflag = 0;
993         
994         /* check that we have grease-pencil stuff to draw */
995         if (sa == NULL) return;
996         gpd= gpencil_data_getactive(sa);
997         if (gpd == NULL) return;
998         
999         /* draw it! */
1000         if (onlyv2d) dflag |= (GP_DRAWDATA_ONLYV2D|GP_DRAWDATA_NOSTATUS);
1001         gp_draw_data(gpd, 0, 0, sa->winx, sa->winy, dflag);
1002 }
1003
1004 /* draw grease-pencil sketches to specified 3d-view assuming that matrices are already set correctly 
1005  * Note: this gets called twice - first time with only3d=1 to draw 3d-strokes, second time with only3d=0 for screen-aligned strokes
1006  */
1007 void draw_gpencil_3dview (ScrArea *sa, short only3d)
1008 {
1009         bGPdata *gpd;
1010         int dflag = 0;
1011         
1012         /* check that we have grease-pencil stuff to draw */
1013         gpd= gpencil_data_getactive(sa);
1014         if (gpd == NULL) return;
1015         
1016         /* draw it! */
1017         if (only3d) dflag |= (GP_DRAWDATA_ONLY3D|GP_DRAWDATA_NOSTATUS);
1018         gp_draw_data(gpd, 0, 0, sa->winx, sa->winy, dflag);
1019 }
1020
1021 /* draw grease-pencil sketches to opengl render window assuming that matrices are already set correctly */
1022 void draw_gpencil_oglrender (View3D *v3d, int winx, int winy)
1023 {
1024         bGPdata *gpd;
1025         
1026         /* assume gpencil data comes from v3d */
1027         if (v3d == NULL) return;
1028         gpd= v3d->gpd;
1029         if (gpd == NULL) return;
1030         
1031         /* pass 1: draw 3d-strokes ------------ > */
1032         gp_draw_data(gpd, 0, 0, winx, winy, (GP_DRAWDATA_NOSTATUS|GP_DRAWDATA_ONLY3D));
1033         
1034         /* pass 2: draw 2d-strokes ------------ > */
1035                 /* adjust view matrices */
1036         myortho2(-0.375, (float)(winx)-0.375, -0.375, (float)(winy)-0.375);
1037         glLoadIdentity();
1038         
1039                 /* draw it! */
1040         gp_draw_data(gpd, 0, 0, winx, winy, GP_DRAWDATA_NOSTATUS);
1041 }
1042
1043 /* ************************************************** */