Made minor revisions (no functional changes).
[blender.git] / source / blender / editors / gpencil / drawgpencil.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2008, Blender Foundation
19  * This is a new part of Blender
20  *
21  * Contributor(s): Joshua Leung
22  *
23  * ***** END GPL LICENSE BLOCK *****
24  */
25
26 /** \file blender/editors/gpencil/drawgpencil.c
27  *  \ingroup edgpencil
28  */
29
30  
31 #include <stdio.h>
32 #include <string.h>
33 #include <stdlib.h>
34 #include <stddef.h>
35 #include <math.h>
36 #include <float.h>
37
38 #include "BLO_sys_types.h"
39
40 #include "IMB_imbuf_types.h"
41
42 #include "BLI_math.h"
43 #include "BLI_blenlib.h"
44 #include "BLI_utildefines.h"
45
46 #include "DNA_gpencil_types.h"
47 #include "DNA_scene_types.h"
48 #include "DNA_screen_types.h"
49 #include "DNA_space_types.h"
50 #include "DNA_view3d_types.h"
51
52 #include "BKE_context.h"
53 #include "BKE_global.h"
54 #include "BKE_gpencil.h"
55
56
57
58 #include "WM_api.h"
59
60 #include "BIF_gl.h"
61 #include "BIF_glutil.h"
62
63 #include "ED_gpencil.h"
64 #include "ED_sequencer.h"
65 #include "ED_view3d.h"
66
67
68 #include "gpencil_intern.h"
69
70 /* ************************************************** */
71 /* GREASE PENCIL DRAWING */
72
73 /* ----- General Defines ------ */
74
75 /* flags for sflag */
76 typedef enum eDrawStrokeFlags {
77         GP_DRAWDATA_NOSTATUS    = (1<<0),       /* don't draw status info */
78         GP_DRAWDATA_ONLY3D              = (1<<1),       /* only draw 3d-strokes */
79         GP_DRAWDATA_ONLYV2D             = (1<<2),       /* only draw 'canvas' strokes */
80         GP_DRAWDATA_ONLYI2D             = (1<<3),       /* only draw 'image' strokes */
81         GP_DRAWDATA_IEDITHACK   = (1<<4),       /* special hack for drawing strokes in Image Editor (weird coordinates) */
82         GP_DRAWDATA_NO_XRAY             = (1<<5),       /* dont draw xray in 3D view (which is default) */
83 } eDrawStrokeFlags;
84
85
86
87 /* thickness above which we should use special drawing */
88 #define GP_DRAWTHICKNESS_SPECIAL        3
89
90 /* ----- Tool Buffer Drawing ------ */
91
92 /* draw stroke defined in buffer (simple ogl lines/points for now, as dotted lines) */
93 static void gp_draw_stroke_buffer (tGPspoint *points, int totpoints, short thickness, short dflag, short sflag)
94 {
95         tGPspoint *pt;
96         int i;
97         
98         /* error checking */
99         if ((points == NULL) || (totpoints <= 0))
100                 return;
101         
102         /* check if buffer can be drawn */
103         if (dflag & (GP_DRAWDATA_ONLY3D|GP_DRAWDATA_ONLYV2D))
104                 return;
105         
106         /* if drawing a single point, draw it larger */ 
107         if (totpoints == 1) {           
108                 /* draw point */
109                 glBegin(GL_POINTS);
110                         glVertex2f(points->x, points->y);
111                 glEnd();
112         }
113         else if (sflag & GP_STROKE_ERASER) {
114                 /* don't draw stroke at all! */
115         }
116         else {
117                 float oldpressure = points[0].pressure;
118                 
119                 /* draw stroke curve */
120                 if (G.f & G_DEBUG) setlinestyle(2);
121
122                 glLineWidth(oldpressure * thickness);
123                 glBegin(GL_LINE_STRIP);
124
125                 for (i=0, pt=points; i < totpoints && pt; i++, pt++) {
126                         /* if there was a significant pressure change, stop the curve, change the thickness of the stroke,
127                          * and continue drawing again (since line-width cannot change in middle of GL_LINE_STRIP)
128                          */
129                         if (fabsf(pt->pressure - oldpressure) > 0.2f) {
130                                 glEnd();
131                                 glLineWidth(pt->pressure * thickness);
132                                 glBegin(GL_LINE_STRIP);
133                                 
134                                 /* need to roll-back one point to ensure that there are no gaps in the stroke */
135                                 if (i != 0) {
136                                         pt--;
137                                         glVertex2f(pt->x, pt->y);
138                                         pt++;
139                                 }
140                                 /* now the point we want... */
141                                 glVertex2f(pt->x, pt->y);
142                                 
143                                 oldpressure = pt->pressure;
144                         }
145                         else
146                                 glVertex2f(pt->x, pt->y);
147                 }
148                 glEnd();
149
150                 /* reset for predictable OpenGL context */
151                 glLineWidth(1.0f);
152                 
153                 if (G.f & G_DEBUG) setlinestyle(0);
154         }
155 }
156
157 /* ----- Existing Strokes Drawing (3D and Point) ------ */
158
159 /* draw a given stroke - just a single dot (only one point) */
160 static void gp_draw_stroke_point (bGPDspoint *points, short thickness, short dflag, short sflag, int offsx, int offsy, int winx, int winy)
161 {
162         /* draw point */
163         if (sflag & GP_STROKE_3DSPACE) {
164                 glBegin(GL_POINTS);
165                         glVertex3f(points->x, points->y, points->z);
166                 glEnd();
167         }
168         else {
169                 float co[2];
170                 
171                 /* get coordinates of point */
172                 if (sflag & GP_STROKE_2DSPACE) {
173                         co[0]= points->x;
174                         co[1]= points->y;
175                 }
176                 else if (sflag & GP_STROKE_2DIMAGE) {
177                         co[0]= (points->x * winx) + offsx;
178                         co[1]= (points->y * winy) + offsy;
179                 }
180                 else {
181                         co[0]= (points->x / 100 * winx) + offsx;
182                         co[1]= (points->y / 100 * winy) + offsy;
183                 }
184                 
185                 /* if thickness is less than GP_DRAWTHICKNESS_SPECIAL, simple dot looks ok
186                  *      - also mandatory in if Image Editor 'image-based' dot
187                  */
188                 if ( (thickness < GP_DRAWTHICKNESS_SPECIAL) ||
189                          ((dflag & GP_DRAWDATA_IEDITHACK) && (sflag & GP_STROKE_2DSPACE)) )
190                 {
191                         glBegin(GL_POINTS);
192                                 glVertex2fv(co);
193                         glEnd();
194                 }
195                 else 
196                 {
197                         /* draw filled circle as is done in circf (but without the matrix push/pops which screwed things up) */
198                         GLUquadricObj *qobj = gluNewQuadric(); 
199                         
200                         gluQuadricDrawStyle(qobj, GLU_FILL); 
201                         
202                         /* need to translate drawing position, but must reset after too! */
203                         glTranslatef(co[0],  co[1], 0.); 
204                         gluDisk(qobj, 0.0,  thickness, 32, 1); 
205                         glTranslatef(-co[0],  -co[1], 0.);
206                         
207                         gluDeleteQuadric(qobj);
208                 }
209         }
210 }
211
212 /* draw a given stroke in 3d (i.e. in 3d-space), using simple ogl lines */
213 static void gp_draw_stroke_3d (bGPDspoint *points, int totpoints, short thickness, short debug)
214 {
215         bGPDspoint *pt;
216         float oldpressure = 0.0f;
217         int i;
218         
219         /* draw stroke curve */
220         glBegin(GL_LINE_STRIP);
221         for (i=0, pt=points; i < totpoints && pt; i++, pt++) {
222                 /* if there was a significant pressure change, stop the curve, change the thickness of the stroke,
223                  * and continue drawing again (since line-width cannot change in middle of GL_LINE_STRIP)
224                  */
225                 if (fabsf(pt->pressure - oldpressure) > 0.2f) {
226                         glEnd();
227                         glLineWidth(pt->pressure * thickness);
228                         glBegin(GL_LINE_STRIP);
229                         
230                         /* need to roll-back one point to ensure that there are no gaps in the stroke */
231                         if (i != 0) {
232                                 pt--;
233                                 glVertex3f(pt->x, pt->y, pt->z);
234                                 pt++;
235                         }
236                         /* now the point we want... */
237                         glVertex3f(pt->x, pt->y, pt->z);
238                         
239                         oldpressure = pt->pressure;
240                 }
241                 else
242                         glVertex3f(pt->x, pt->y, pt->z);
243         }
244         glEnd();
245         
246         /* draw debug points of curve on top? */
247         if (debug) {
248                 glBegin(GL_POINTS);
249                 for (i=0, pt=points; i < totpoints && pt; i++, pt++)
250                         glVertex3f(pt->x, pt->y, pt->z);
251                 glEnd();
252         }
253 }
254
255 /* ----- Fancy 2D-Stroke Drawing ------ */
256
257 /* draw a given stroke in 2d */
258 static void gp_draw_stroke (bGPDspoint *points, int totpoints, short thickness_s, short dflag, short sflag, 
259                                                         short debug, int offsx, int offsy, int winx, int winy)
260 {
261         /* otherwise thickness is twice that of the 3D view */
262         float thickness= (float)thickness_s * 0.5f;
263
264         /* if thickness is less than GP_DRAWTHICKNESS_SPECIAL, 'smooth' opengl lines look better
265          *      - 'smooth' opengl lines are also required if Image Editor 'image-based' stroke
266          */
267         if ( (thickness < GP_DRAWTHICKNESS_SPECIAL) || 
268                  ((dflag & GP_DRAWDATA_IEDITHACK) && (dflag & GP_DRAWDATA_ONLYV2D)) ) 
269         {
270                 bGPDspoint *pt;
271                 int i;
272                 
273                 glBegin(GL_LINE_STRIP);
274                 for (i=0, pt=points; i < totpoints && pt; i++, pt++) {
275                         if (sflag & GP_STROKE_2DSPACE) {
276                                 glVertex2f(pt->x, pt->y);
277                         }
278                         else if (sflag & GP_STROKE_2DIMAGE) {
279                                 const float x= (pt->x * winx) + offsx;
280                                 const float y= (pt->y * winy) + offsy;
281                                 
282                                 glVertex2f(x, y);
283                         }
284                         else {
285                                 const float x= (pt->x / 100 * winx) + offsx;
286                                 const float y= (pt->y / 100 * winy) + offsy;
287                                 
288                                 glVertex2f(x, y);
289                         }
290                 }
291                 glEnd();
292         }
293         
294         /* tesselation code - draw stroke as series of connected quads with connection
295          * edges rotated to minimise shrinking artifacts, and rounded endcaps
296          */
297         else 
298         { 
299                 bGPDspoint *pt1, *pt2;
300                 float pm[2];
301                 int i;
302                 
303                 glShadeModel(GL_FLAT);
304                 glBegin(GL_QUADS);
305                 
306                 for (i=0, pt1=points, pt2=points+1; i < (totpoints-1); i++, pt1++, pt2++) {
307                         float s0[2], s1[2];             /* segment 'center' points */
308                         float t0[2], t1[2];             /* tesselated coordinates */
309                         float m1[2], m2[2];             /* gradient and normal */
310                         float mt[2], sc[2];             /* gradient for thickness, point for end-cap */
311                         float pthick;                   /* thickness at segment point */
312                         
313                         /* get x and y coordinates from points */
314                         if (sflag & GP_STROKE_2DSPACE) {
315                                 s0[0]= pt1->x;          s0[1]= pt1->y;
316                                 s1[0]= pt2->x;          s1[1]= pt2->y;
317                         }
318                         else if (sflag & GP_STROKE_2DIMAGE) {
319                                 s0[0]= (pt1->x * winx) + offsx;                 
320                                 s0[1]= (pt1->y * winy) + offsy;
321                                 s1[0]= (pt2->x * winx) + offsx;         
322                                 s1[1]= (pt2->y * winy) + offsy;
323                         }
324                         else {
325                                 s0[0]= (pt1->x / 100 * winx) + offsx;
326                                 s0[1]= (pt1->y / 100 * winy) + offsy;
327                                 s1[0]= (pt2->x / 100 * winx) + offsx;
328                                 s1[1]= (pt2->y / 100 * winy) + offsy;
329                         }               
330                         
331                         /* calculate gradient and normal - 'angle'=(ny/nx) */
332                         m1[1]= s1[1] - s0[1];           
333                         m1[0]= s1[0] - s0[0];
334                         normalize_v2(m1);
335                         m2[1]= -m1[0];
336                         m2[0]= m1[1];
337                         
338                         /* always use pressure from first point here */
339                         pthick= (pt1->pressure * thickness);
340                         
341                         /* if the first segment, start of segment is segment's normal */
342                         if (i == 0) {
343                                 /* draw start cap first 
344                                  *      - make points slightly closer to center (about halfway across) 
345                                  */                             
346                                 mt[0]= m2[0] * pthick * 0.5f;
347                                 mt[1]= m2[1] * pthick * 0.5f;
348                                 sc[0]= s0[0] - (m1[0] * pthick * 0.75f);
349                                 sc[1]= s0[1] - (m1[1] * pthick * 0.75f);
350                                 
351                                 t0[0]= sc[0] - mt[0];
352                                 t0[1]= sc[1] - mt[1];
353                                 t1[0]= sc[0] + mt[0];
354                                 t1[1]= sc[1] + mt[1];
355                                 
356                                 glVertex2fv(t0);
357                                 glVertex2fv(t1);
358                                 
359                                 /* calculate points for start of segment */
360                                 mt[0]= m2[0] * pthick;
361                                 mt[1]= m2[1] * pthick;
362                                 
363                                 t0[0]= s0[0] - mt[0];
364                                 t0[1]= s0[1] - mt[1];
365                                 t1[0]= s0[0] + mt[0];
366                                 t1[1]= s0[1] + mt[1];
367                                 
368                                 /* draw this line twice (first to finish off start cap, then for stroke) */
369                                 glVertex2fv(t1);
370                                 glVertex2fv(t0);
371                                 glVertex2fv(t0);
372                                 glVertex2fv(t1);
373                         }
374                         /* if not the first segment, use bisector of angle between segments */
375                         else {
376                                 float mb[2];            /* bisector normal */
377                                 float athick, dfac;             /* actual thickness, difference between thicknesses */
378                                 
379                                 /* calculate gradient of bisector (as average of normals) */
380                                 mb[0]= (pm[0] + m2[0]) / 2;
381                                 mb[1]= (pm[1] + m2[1]) / 2;
382                                 normalize_v2(mb);
383                                 
384                                 /* calculate gradient to apply 
385                                  *      - as basis, use just pthick * bisector gradient
386                                  *      - if cross-section not as thick as it should be, add extra padding to fix it
387                                  */
388                                 mt[0]= mb[0] * pthick;
389                                 mt[1]= mb[1] * pthick;
390                                 athick= len_v2(mt);
391                                 dfac= pthick - (athick * 2);
392                                 if ( ((athick * 2.0f) < pthick) && (IS_EQF(athick, pthick)==0) )
393                                 {
394                                         mt[0] += (mb[0] * dfac);
395                                         mt[1] += (mb[1] * dfac);
396                                 }       
397                                 
398                                 /* calculate points for start of segment */
399                                 t0[0]= s0[0] - mt[0];
400                                 t0[1]= s0[1] - mt[1];
401                                 t1[0]= s0[0] + mt[0];
402                                 t1[1]= s0[1] + mt[1];
403                                 
404                                 /* draw this line twice (once for end of current segment, and once for start of next) */
405                                 glVertex2fv(t1);
406                                 glVertex2fv(t0);
407                                 glVertex2fv(t0);
408                                 glVertex2fv(t1);
409                         }
410                         
411                         /* if last segment, also draw end of segment (defined as segment's normal) */
412                         if (i == totpoints-2) {
413                                 /* for once, we use second point's pressure (otherwise it won't be drawn) */
414                                 pthick= (pt2->pressure * thickness);
415                                 
416                                 /* calculate points for end of segment */
417                                 mt[0]= m2[0] * pthick;
418                                 mt[1]= m2[1] * pthick;
419                                 
420                                 t0[0]= s1[0] - mt[0];
421                                 t0[1]= s1[1] - mt[1];
422                                 t1[0]= s1[0] + mt[0];
423                                 t1[1]= s1[1] + mt[1];
424                                 
425                                 /* draw this line twice (once for end of stroke, and once for endcap)*/
426                                 glVertex2fv(t1);
427                                 glVertex2fv(t0);
428                                 glVertex2fv(t0);
429                                 glVertex2fv(t1);
430                                 
431                                 
432                                 /* draw end cap as last step 
433                                  *      - make points slightly closer to center (about halfway across) 
434                                  */                             
435                                 mt[0]= m2[0] * pthick * 0.5f;
436                                 mt[1]= m2[1] * pthick * 0.5f;
437                                 sc[0]= s1[0] + (m1[0] * pthick * 0.75f);
438                                 sc[1]= s1[1] + (m1[1] * pthick * 0.75f);
439                                 
440                                 t0[0]= sc[0] - mt[0];
441                                 t0[1]= sc[1] - mt[1];
442                                 t1[0]= sc[0] + mt[0];
443                                 t1[1]= sc[1] + mt[1];
444                                 
445                                 glVertex2fv(t1);
446                                 glVertex2fv(t0);
447                         }
448                         
449                         /* store stroke's 'natural' normal for next stroke to use */
450                         copy_v2_v2(pm, m2);
451                 }
452                 
453                 glEnd();
454         }
455         
456         /* draw debug points of curve on top? (original stroke points) */
457         if (debug) {
458                 bGPDspoint *pt;
459                 int i;
460                 
461                 glBegin(GL_POINTS);
462                 for (i=0, pt=points; i < totpoints && pt; i++, pt++) {
463                         if (sflag & GP_STROKE_2DSPACE) {
464                                 glVertex2f(pt->x, pt->y);
465                         }
466                         else if (sflag & GP_STROKE_2DIMAGE) {
467                                 const float x= (float)((pt->x * winx) + offsx);
468                                 const float y= (float)((pt->y * winy) + offsy);
469                                 
470                                 glVertex2f(x, y);
471                         }
472                         else {
473                                 const float x= (float)(pt->x / 100 * winx) + offsx;
474                                 const float y= (float)(pt->y / 100 * winy) + offsy;
475                                 
476                                 glVertex2f(x, y);
477                         }
478                 }
479                 glEnd();
480         }
481 }
482
483 /* ----- General Drawing ------ */
484
485 /* draw a set of strokes */
486 static void gp_draw_strokes (bGPDframe *gpf, int offsx, int offsy, int winx, int winy, int dflag,  
487                                                          short debug, short lthick, float color[4])
488 {
489         bGPDstroke *gps;
490         
491         /* set color first (may need to reset it again later too) */
492         glColor4fv(color);
493         
494         for (gps= gpf->strokes.first; gps; gps= gps->next) {
495                 /* check if stroke can be drawn - checks here generally fall into pairs */
496                 if ((dflag & GP_DRAWDATA_ONLY3D) && !(gps->flag & GP_STROKE_3DSPACE))
497                         continue;
498                 if (!(dflag & GP_DRAWDATA_ONLY3D) && (gps->flag & GP_STROKE_3DSPACE))
499                         continue;
500                 if ((dflag & GP_DRAWDATA_ONLYV2D) && !(gps->flag & GP_STROKE_2DSPACE))
501                         continue;
502                 if (!(dflag & GP_DRAWDATA_ONLYV2D) && (gps->flag & GP_STROKE_2DSPACE))
503                         continue;
504                 if ((dflag & GP_DRAWDATA_ONLYI2D) && !(gps->flag & GP_STROKE_2DIMAGE))
505                         continue;
506                 if (!(dflag & GP_DRAWDATA_ONLYI2D) && (gps->flag & GP_STROKE_2DIMAGE))
507                         continue;
508                 if ((gps->points == NULL) || (gps->totpoints < 1))
509                         continue;
510                 
511                 /* check which stroke-drawer to use */
512                 if (gps->totpoints == 1)
513                         gp_draw_stroke_point(gps->points, lthick, dflag, gps->flag, offsx, offsy, winx, winy);
514                 else if (dflag & GP_DRAWDATA_ONLY3D) {
515                         const int no_xray= (dflag & GP_DRAWDATA_NO_XRAY);
516                         int mask_orig = 0;
517                         
518                         if (no_xray) {
519                                 glGetIntegerv(GL_DEPTH_WRITEMASK, &mask_orig);
520                                 glDepthMask(0);
521                                 glEnable(GL_DEPTH_TEST);
522                                 
523                                 /* first arg is normally rv3d->dist, but this isnt available here and seems to work quite well without */
524                                 bglPolygonOffset(1.0f, 1.0f);
525                                 /*
526                                 glEnable(GL_POLYGON_OFFSET_LINE);
527                                 glPolygonOffset(-1.0f, -1.0f);
528                                 */
529                         }
530                         
531                         gp_draw_stroke_3d(gps->points, gps->totpoints, lthick, debug);
532                         
533                         if (no_xray) {
534                                 glDepthMask(mask_orig);
535                                 glDisable(GL_DEPTH_TEST);
536                                 
537                                 bglPolygonOffset(0.0, 0.0);
538                                 /*
539                                 glDisable(GL_POLYGON_OFFSET_LINE);
540                                 glPolygonOffset(0, 0);
541                                 */
542                         }
543                 }
544                 else if (gps->totpoints > 1)    
545                         gp_draw_stroke(gps->points, gps->totpoints, lthick, dflag, gps->flag, debug, offsx, offsy, winx, winy);
546         }
547 }
548
549 /* draw grease-pencil datablock */
550 static void gp_draw_data (bGPdata *gpd, int offsx, int offsy, int winx, int winy, int cfra, int dflag)
551 {
552         bGPDlayer *gpl;
553         
554         /* reset line drawing style (in case previous user didn't reset) */
555         setlinestyle(0);
556         
557         /* turn on smooth lines (i.e. anti-aliasing) */
558         glEnable(GL_LINE_SMOOTH);
559         
560         /* turn on alpha-blending */
561         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
562         glEnable(GL_BLEND);
563                 
564         /* loop over layers, drawing them */
565         for (gpl= gpd->layers.first; gpl; gpl= gpl->next) {
566                 bGPDframe *gpf;
567                 
568                 short debug = (gpl->flag & GP_LAYER_DRAWDEBUG) ? 1 : 0;
569                 short lthick= gpl->thickness;
570                 float color[4], tcolor[4];
571                 
572                 /* don't draw layer if hidden */
573                 if (gpl->flag & GP_LAYER_HIDE) 
574                         continue;
575                 
576                 /* get frame to draw */
577                 gpf= gpencil_layer_getframe(gpl, cfra, 0);
578                 if (gpf == NULL) 
579                         continue;
580                 
581                 /* set color, stroke thickness, and point size */
582                 glLineWidth(lthick);
583                 copy_v4_v4(color, gpl->color); // just for copying 4 array elements
584                 copy_v4_v4(tcolor, gpl->color); // additional copy of color (for ghosting)
585                 glColor4fv(color);
586                 glPointSize((float)(gpl->thickness + 2));
587                 
588                 /* apply xray layer setting */
589                 if (gpl->flag & GP_LAYER_NO_XRAY)       dflag |=  GP_DRAWDATA_NO_XRAY;
590                 else                                                            dflag &= ~GP_DRAWDATA_NO_XRAY;
591                 
592                 /* draw 'onionskins' (frame left + right) */
593                 if (gpl->flag & GP_LAYER_ONIONSKIN) {
594                         /* drawing method - only immediately surrounding (gstep = 0), or within a frame range on either side (gstep > 0)*/                      
595                         if (gpl->gstep) {
596                                 bGPDframe *gf;
597                                 float fac;
598                                 
599                                 /* draw previous frames first */
600                                 for (gf=gpf->prev; gf; gf=gf->prev) {
601                                         /* check if frame is drawable */
602                                         if ((gpf->framenum - gf->framenum) <= gpl->gstep) {
603                                                 /* alpha decreases with distance from curframe index */
604                                                 fac= 1.0f - ((float)(gpf->framenum - gf->framenum) / (float)(gpl->gstep + 1));
605                                                 tcolor[3] = color[3] * fac * 0.66f;
606                                                 gp_draw_strokes(gf, offsx, offsy, winx, winy, dflag, debug, lthick, tcolor);
607                                         }
608                                         else 
609                                                 break;
610                                 }
611                                 
612                                 /* now draw next frames */
613                                 for (gf= gpf->next; gf; gf=gf->next) {
614                                         /* check if frame is drawable */
615                                         if ((gf->framenum - gpf->framenum) <= gpl->gstep) {
616                                                 /* alpha decreases with distance from curframe index */
617                                                 fac= 1.0f - ((float)(gf->framenum - gpf->framenum) / (float)(gpl->gstep + 1));
618                                                 tcolor[3] = color[3] * fac * 0.66f;
619                                                 gp_draw_strokes(gf, offsx, offsy, winx, winy, dflag, debug, lthick, tcolor);
620                                         }
621                                         else 
622                                                 break;
623                                 }       
624                                 
625                                 /* restore alpha */
626                                 glColor4fv(color);
627                         }
628                         else {
629                                 /* draw the strokes for the ghost frames (at half of the alpha set by user) */
630                                 if (gpf->prev) {
631                                         tcolor[3] = (color[3] / 7);
632                                         gp_draw_strokes(gpf->prev, offsx, offsy, winx, winy, dflag, debug, lthick, tcolor);
633                                 }
634                                 
635                                 if (gpf->next) {
636                                         tcolor[3] = (color[3] / 4);
637                                         gp_draw_strokes(gpf->next, offsx, offsy, winx, winy, dflag, debug, lthick, tcolor);
638                                 }
639                                 
640                                 /* restore alpha */
641                                 glColor4fv(color);
642                         }
643                 }
644                 
645                 /* draw the strokes already in active frame */
646                 tcolor[3]= color[3];
647                 gp_draw_strokes(gpf, offsx, offsy, winx, winy, dflag, debug, lthick, tcolor);
648                 
649                 /* Check if may need to draw the active stroke cache, only if this layer is the active layer
650                  * that is being edited. (Stroke buffer is currently stored in gp-data)
651                  */
652                 if (ED_gpencil_session_active() && (gpl->flag & GP_LAYER_ACTIVE) &&
653                         (gpf->flag & GP_FRAME_PAINT)) 
654                 {
655                         /* Buffer stroke needs to be drawn with a different linestyle to help differentiate them from normal strokes. */
656                         gp_draw_stroke_buffer(gpd->sbuffer, gpd->sbuffer_size, lthick, dflag, gpd->sbuffer_sflag);
657                 }
658         }
659         
660         /* turn off alpha blending, then smooth lines */
661         glDisable(GL_BLEND); // alpha blending
662         glDisable(GL_LINE_SMOOTH); // smooth lines
663                 
664         /* restore initial gl conditions */
665         glLineWidth(1.0);
666         glPointSize(1.0);
667         glColor4f(0, 0, 0, 1);
668 }
669
670 /* ----- Grease Pencil Sketches Drawing API ------ */
671
672 // ............................
673 // XXX 
674 //      We need to review the calls below, since they may be/are not that suitable for
675 //      the new ways that we intend to be drawing data...
676 // ............................
677
678 /* draw grease-pencil sketches to specified 2d-view that uses ibuf corrections */
679 void draw_gpencil_2dimage (bContext *C, ImBuf *ibuf)
680 {
681         ScrArea *sa= CTX_wm_area(C);
682         ARegion *ar= CTX_wm_region(C);
683         Scene *scene= CTX_data_scene(C);
684         bGPdata *gpd;
685         int offsx, offsy, sizex, sizey;
686         int dflag = GP_DRAWDATA_NOSTATUS;
687         
688         /* check that we have grease-pencil stuff to draw */
689         if (ELEM(NULL, sa, ibuf)) return;
690         gpd= gpencil_data_get_active(C); // XXX
691         if (gpd == NULL) return;
692         
693         /* calculate rect */
694         switch (sa->spacetype) {
695                 case SPACE_IMAGE: /* image */
696                 case SPACE_CLIP: /* clip */
697                 {
698                         
699                         /* just draw using standard scaling (settings here are currently ignored anyways) */
700                         // FIXME: the opengl poly-strokes don't draw at right thickness when done this way, so disabled
701                         offsx= 0;
702                         offsy= 0;
703                         sizex= ar->winx;
704                         sizey= ar->winy;
705                         
706                         wmOrtho2(ar->v2d.cur.xmin, ar->v2d.cur.xmax, ar->v2d.cur.ymin, ar->v2d.cur.ymax);
707                         
708                         dflag |= GP_DRAWDATA_ONLYV2D|GP_DRAWDATA_IEDITHACK;
709                 }
710                         break;
711                         
712                 case SPACE_SEQ: /* sequence */
713                 {
714                         SpaceSeq *sseq= (SpaceSeq *)sa->spacedata.first;
715                         float zoom, zoomx, zoomy;
716                         
717                         /* calculate accessory values */
718                         zoom= (float)(SEQ_ZOOM_FAC(sseq->zoom));
719                         if (sseq->mainb == SEQ_DRAW_IMG_IMBUF) {
720                                 /* XXX sequencer zoom should store it? */
721                                 zoomx = zoom; //  * (G.scene->r.xasp / G.scene->r.yasp);
722                                 zoomy = zoom;
723                         } 
724                         else
725                                 zoomx = zoomy = zoom;
726                         
727                         /* calculate transforms (Note: we use ibuf here, as we have it) */
728                         sizex= (int)(zoomx * ibuf->x);
729                         sizey= (int)(zoomy * ibuf->y);
730                         offsx= (int)( (ar->winx-sizex)/2 + sseq->xof );
731                         offsy= (int)( (ar->winy-sizey)/2 + sseq->yof );
732                         
733                         dflag |= GP_DRAWDATA_ONLYI2D;
734                 }
735                         break;
736                         
737                 default: /* for spacetype not yet handled */
738                         offsx= 0;
739                         offsy= 0;
740                         sizex= ar->winx;
741                         sizey= ar->winy;
742                         
743                         dflag |= GP_DRAWDATA_ONLYI2D;
744                         break;
745         }
746         
747         
748         /* draw it! */
749         gp_draw_data(gpd, offsx, offsy, sizex, sizey, CFRA, dflag);
750 }
751
752 /* draw grease-pencil sketches to specified 2d-view assuming that matrices are already set correctly 
753  * Note: this gets called twice - first time with onlyv2d=1 to draw 'canvas' strokes, second time with onlyv2d=0 for screen-aligned strokes
754  */
755 void draw_gpencil_view2d (bContext *C, short onlyv2d)
756 {
757         ScrArea *sa= CTX_wm_area(C);
758         ARegion *ar= CTX_wm_region(C);
759         Scene *scene= CTX_data_scene(C);
760         bGPdata *gpd;
761         int dflag = 0;
762         
763         /* check that we have grease-pencil stuff to draw */
764         if (sa == NULL) return;
765         gpd= gpencil_data_get_active(C); // XXX
766         if (gpd == NULL) return;
767         
768         /* special hack for Image Editor */
769         // FIXME: the opengl poly-strokes don't draw at right thickness when done this way, so disabled
770         if (ELEM(sa->spacetype, SPACE_IMAGE, SPACE_CLIP))
771                 dflag |= GP_DRAWDATA_IEDITHACK;
772         
773         /* draw it! */
774         if (onlyv2d) dflag |= (GP_DRAWDATA_ONLYV2D|GP_DRAWDATA_NOSTATUS);
775         gp_draw_data(gpd, 0, 0, ar->winx, ar->winy, CFRA, dflag);
776 }
777
778 /* draw grease-pencil sketches to specified 3d-view assuming that matrices are already set correctly 
779  * Note: this gets called twice - first time with only3d=1 to draw 3d-strokes, second time with only3d=0 for screen-aligned strokes
780  */
781
782 void draw_gpencil_view3d (Scene *scene, View3D *v3d, ARegion *ar, short only3d)
783 {
784         bGPdata *gpd;
785         int dflag = 0;
786         rcti rect;
787         RegionView3D *rv3d= ar->regiondata;
788
789         /* check that we have grease-pencil stuff to draw */
790         gpd= gpencil_data_get_active_v3d(scene); // XXX
791         if (gpd == NULL) return;
792
793         /* when rendering to the offscreen buffer we dont want to
794          * deal with the camera border, otherwise map the coords to the camera border. */
795         if ((rv3d->persp == RV3D_CAMOB) && !(G.f & G_RENDER_OGL)) {
796                 rctf rectf;
797                 ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &rectf, TRUE); /* no shift */
798                 BLI_copy_rcti_rctf(&rect, &rectf);
799         }
800         else {
801                 rect.xmin= 0;
802                 rect.ymin= 0;
803                 rect.xmax= ar->winx;
804                 rect.ymax= ar->winy;
805         }
806         
807         /* draw it! */
808         if (only3d) dflag |= (GP_DRAWDATA_ONLY3D|GP_DRAWDATA_NOSTATUS);
809
810         gp_draw_data(gpd, rect.xmin, rect.ymin, rect.xmax, rect.ymax, CFRA, dflag);
811 }
812
813 /* ************************************************** */