Blender V2.61 - r43446

drawgpencil.c

Go to the documentation of this file.
00001 /*
00002  * ***** BEGIN GPL LICENSE BLOCK *****
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License
00006  * as published by the Free Software Foundation; either version 2
00007  * of the License, or (at your option) any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software Foundation,
00016  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  *
00018  * The Original Code is Copyright (C) 2008, Blender Foundation
00019  * This is a new part of Blender
00020  *
00021  * Contributor(s): Joshua Leung
00022  *
00023  * ***** END GPL LICENSE BLOCK *****
00024  */
00025 
00031 #include <stdio.h>
00032 #include <string.h>
00033 #include <stdlib.h>
00034 #include <stddef.h>
00035 #include <math.h>
00036 #include <float.h>
00037 
00038 #include "BLO_sys_types.h"
00039 
00040 #include "IMB_imbuf_types.h"
00041 
00042 #include "BLI_math.h"
00043 #include "BLI_blenlib.h"
00044 #include "BLI_utildefines.h"
00045 
00046 #include "DNA_gpencil_types.h"
00047 #include "DNA_scene_types.h"
00048 #include "DNA_screen_types.h"
00049 #include "DNA_space_types.h"
00050 #include "DNA_view3d_types.h"
00051 
00052 #include "BKE_context.h"
00053 #include "BKE_global.h"
00054 #include "BKE_gpencil.h"
00055 
00056 
00057 
00058 #include "WM_api.h"
00059 
00060 #include "BIF_gl.h"
00061 #include "BIF_glutil.h"
00062 
00063 #include "ED_gpencil.h"
00064 #include "ED_sequencer.h"
00065 #include "ED_view3d.h"
00066 
00067 
00068 #include "gpencil_intern.h"
00069 
00070 /* ************************************************** */
00071 /* GREASE PENCIL DRAWING */
00072 
00073 /* ----- General Defines ------ */
00074 
00075 /* flags for sflag */
00076 typedef enum eDrawStrokeFlags {
00077     GP_DRAWDATA_NOSTATUS    = (1<<0),   /* don't draw status info */
00078     GP_DRAWDATA_ONLY3D      = (1<<1),   /* only draw 3d-strokes */
00079     GP_DRAWDATA_ONLYV2D     = (1<<2),   /* only draw 'canvas' strokes */
00080     GP_DRAWDATA_ONLYI2D     = (1<<3),   /* only draw 'image' strokes */
00081     GP_DRAWDATA_IEDITHACK   = (1<<4),   /* special hack for drawing strokes in Image Editor (weird coordinates) */
00082     GP_DRAWDATA_NO_XRAY     = (1<<5),   /* dont draw xray in 3D view (which is default) */
00083 } eDrawStrokeFlags;
00084 
00085 
00086 
00087 /* thickness above which we should use special drawing */
00088 #define GP_DRAWTHICKNESS_SPECIAL    3
00089 
00090 /* ----- Tool Buffer Drawing ------ */
00091 
00092 /* draw stroke defined in buffer (simple ogl lines/points for now, as dotted lines) */
00093 static void gp_draw_stroke_buffer (tGPspoint *points, int totpoints, short thickness, short dflag, short sflag)
00094 {
00095     tGPspoint *pt;
00096     int i;
00097     
00098     /* error checking */
00099     if ((points == NULL) || (totpoints <= 0))
00100         return;
00101     
00102     /* check if buffer can be drawn */
00103     if (dflag & (GP_DRAWDATA_ONLY3D|GP_DRAWDATA_ONLYV2D))
00104         return;
00105     
00106     /* if drawing a single point, draw it larger */ 
00107     if (totpoints == 1) {       
00108         /* draw point */
00109         glBegin(GL_POINTS);
00110             glVertex2iv(&points->x);
00111         glEnd();
00112     }
00113     else if (sflag & GP_STROKE_ERASER) {
00114         /* don't draw stroke at all! */
00115     }
00116     else {
00117         float oldpressure = points[0].pressure;
00118         
00119         /* draw stroke curve */
00120         if (G.f & G_DEBUG) setlinestyle(2);
00121 
00122         glLineWidth(oldpressure * thickness);
00123         glBegin(GL_LINE_STRIP);
00124 
00125         for (i=0, pt=points; i < totpoints && pt; i++, pt++) {
00126             /* if there was a significant pressure change, stop the curve, change the thickness of the stroke,
00127              * and continue drawing again (since line-width cannot change in middle of GL_LINE_STRIP)
00128              */
00129             if (fabsf(pt->pressure - oldpressure) > 0.2f) {
00130                 glEnd();
00131                 glLineWidth(pt->pressure * thickness);
00132                 glBegin(GL_LINE_STRIP);
00133                 
00134                 /* need to roll-back one point to ensure that there are no gaps in the stroke */
00135                 if (i != 0) glVertex2iv(&(pt - 1)->x);
00136 
00137                 /* now the point we want... */
00138                 glVertex2iv(&pt->x);
00139                 
00140                 oldpressure = pt->pressure;
00141             }
00142             else
00143                 glVertex2iv(&pt->x);
00144         }
00145         glEnd();
00146 
00147         /* reset for predictable OpenGL context */
00148         glLineWidth(1.0f);
00149         
00150         if (G.f & G_DEBUG) setlinestyle(0);
00151     }
00152 }
00153 
00154 /* ----- Existing Strokes Drawing (3D and Point) ------ */
00155 
00156 /* draw a given stroke - just a single dot (only one point) */
00157 static void gp_draw_stroke_point (bGPDspoint *points, short thickness, short dflag, short sflag, int offsx, int offsy, int winx, int winy)
00158 {
00159     /* draw point */
00160     if (sflag & GP_STROKE_3DSPACE) {
00161         glBegin(GL_POINTS);
00162             glVertex3fv(&points->x);
00163         glEnd();
00164     }
00165     else {
00166         float co[2];
00167         
00168         /* get coordinates of point */
00169         if (sflag & GP_STROKE_2DSPACE) {
00170             co[0]= points->x;
00171             co[1]= points->y;
00172         }
00173         else if (sflag & GP_STROKE_2DIMAGE) {
00174             co[0]= (points->x * winx) + offsx;
00175             co[1]= (points->y * winy) + offsy;
00176         }
00177         else {
00178             co[0]= (points->x / 100 * winx) + offsx;
00179             co[1]= (points->y / 100 * winy) + offsy;
00180         }
00181         
00182         /* if thickness is less than GP_DRAWTHICKNESS_SPECIAL, simple dot looks ok
00183          *  - also mandatory in if Image Editor 'image-based' dot
00184          */
00185         if ( (thickness < GP_DRAWTHICKNESS_SPECIAL) ||
00186              ((dflag & GP_DRAWDATA_IEDITHACK) && (sflag & GP_STROKE_2DSPACE)) )
00187         {
00188             glBegin(GL_POINTS);
00189                 glVertex2fv(co);
00190             glEnd();
00191         }
00192         else 
00193         {
00194             /* draw filled circle as is done in circf (but without the matrix push/pops which screwed things up) */
00195             GLUquadricObj *qobj = gluNewQuadric(); 
00196             
00197             gluQuadricDrawStyle(qobj, GLU_FILL); 
00198             
00199             /* need to translate drawing position, but must reset after too! */
00200             glTranslatef(co[0],  co[1], 0.); 
00201             gluDisk(qobj, 0.0,  thickness, 32, 1); 
00202             glTranslatef(-co[0],  -co[1], 0.);
00203             
00204             gluDeleteQuadric(qobj);
00205         }
00206     }
00207 }
00208 
00209 /* draw a given stroke in 3d (i.e. in 3d-space), using simple ogl lines */
00210 static void gp_draw_stroke_3d (bGPDspoint *points, int totpoints, short thickness, short debug)
00211 {
00212     bGPDspoint *pt;
00213     float oldpressure = 0.0f;
00214     int i;
00215     
00216     /* draw stroke curve */
00217     glBegin(GL_LINE_STRIP);
00218     for (i=0, pt=points; i < totpoints && pt; i++, pt++) {
00219         /* if there was a significant pressure change, stop the curve, change the thickness of the stroke,
00220          * and continue drawing again (since line-width cannot change in middle of GL_LINE_STRIP)
00221          */
00222         if (fabsf(pt->pressure - oldpressure) > 0.2f) {
00223             glEnd();
00224             glLineWidth(pt->pressure * thickness);
00225             glBegin(GL_LINE_STRIP);
00226             
00227             /* need to roll-back one point to ensure that there are no gaps in the stroke */
00228             if (i != 0) glVertex3fv(&(pt - 1)->x);
00229 
00230             /* now the point we want... */
00231             glVertex3fv(&pt->x);
00232             
00233             oldpressure = pt->pressure;
00234         }
00235         else {
00236             glVertex3fv(&pt->x);
00237         }
00238     }
00239     glEnd();
00240     
00241     /* draw debug points of curve on top? */
00242     if (debug) {
00243         glBegin(GL_POINTS);
00244         for (i=0, pt=points; i < totpoints && pt; i++, pt++)
00245             glVertex3fv(&pt->x);
00246         glEnd();
00247     }
00248 }
00249 
00250 /* ----- Fancy 2D-Stroke Drawing ------ */
00251 
00252 /* draw a given stroke in 2d */
00253 static void gp_draw_stroke (bGPDspoint *points, int totpoints, short thickness_s, short dflag, short sflag, 
00254                             short debug, int offsx, int offsy, int winx, int winy)
00255 {
00256     /* otherwise thickness is twice that of the 3D view */
00257     float thickness= (float)thickness_s * 0.5f;
00258 
00259     /* if thickness is less than GP_DRAWTHICKNESS_SPECIAL, 'smooth' opengl lines look better
00260      *  - 'smooth' opengl lines are also required if Image Editor 'image-based' stroke
00261      */
00262     if ( (thickness < GP_DRAWTHICKNESS_SPECIAL) || 
00263          ((dflag & GP_DRAWDATA_IEDITHACK) && (dflag & GP_DRAWDATA_ONLYV2D)) ) 
00264     {
00265         bGPDspoint *pt;
00266         int i;
00267         
00268         glBegin(GL_LINE_STRIP);
00269         for (i=0, pt=points; i < totpoints && pt; i++, pt++) {
00270             if (sflag & GP_STROKE_2DSPACE) {
00271                 glVertex2f(pt->x, pt->y);
00272             }
00273             else if (sflag & GP_STROKE_2DIMAGE) {
00274                 const float x= (pt->x * winx) + offsx;
00275                 const float y= (pt->y * winy) + offsy;
00276                 
00277                 glVertex2f(x, y);
00278             }
00279             else {
00280                 const float x= (pt->x / 100 * winx) + offsx;
00281                 const float y= (pt->y / 100 * winy) + offsy;
00282                 
00283                 glVertex2f(x, y);
00284             }
00285         }
00286         glEnd();
00287     }
00288     
00289     /* tesselation code - draw stroke as series of connected quads with connection
00290      * edges rotated to minimise shrinking artifacts, and rounded endcaps
00291      */
00292     else 
00293     { 
00294         bGPDspoint *pt1, *pt2;
00295         float pm[2];
00296         int i;
00297         
00298         glShadeModel(GL_FLAT);
00299         glBegin(GL_QUADS);
00300         
00301         for (i=0, pt1=points, pt2=points+1; i < (totpoints-1); i++, pt1++, pt2++) {
00302             float s0[2], s1[2];     /* segment 'center' points */
00303             float t0[2], t1[2];     /* tesselated coordinates */
00304             float m1[2], m2[2];     /* gradient and normal */
00305             float mt[2], sc[2];     /* gradient for thickness, point for end-cap */
00306             float pthick;           /* thickness at segment point */
00307             
00308             /* get x and y coordinates from points */
00309             if (sflag & GP_STROKE_2DSPACE) {
00310                 s0[0]= pt1->x;      s0[1]= pt1->y;
00311                 s1[0]= pt2->x;      s1[1]= pt2->y;
00312             }
00313             else if (sflag & GP_STROKE_2DIMAGE) {
00314                 s0[0]= (pt1->x * winx) + offsx;         
00315                 s0[1]= (pt1->y * winy) + offsy;
00316                 s1[0]= (pt2->x * winx) + offsx;     
00317                 s1[1]= (pt2->y * winy) + offsy;
00318             }
00319             else {
00320                 s0[0]= (pt1->x / 100 * winx) + offsx;
00321                 s0[1]= (pt1->y / 100 * winy) + offsy;
00322                 s1[0]= (pt2->x / 100 * winx) + offsx;
00323                 s1[1]= (pt2->y / 100 * winy) + offsy;
00324             }       
00325             
00326             /* calculate gradient and normal - 'angle'=(ny/nx) */
00327             m1[1]= s1[1] - s0[1];       
00328             m1[0]= s1[0] - s0[0];
00329             normalize_v2(m1);
00330             m2[1]= -m1[0];
00331             m2[0]= m1[1];
00332             
00333             /* always use pressure from first point here */
00334             pthick= (pt1->pressure * thickness);
00335             
00336             /* if the first segment, start of segment is segment's normal */
00337             if (i == 0) {
00338                 /* draw start cap first 
00339                  *  - make points slightly closer to center (about halfway across) 
00340                  */             
00341                 mt[0]= m2[0] * pthick * 0.5f;
00342                 mt[1]= m2[1] * pthick * 0.5f;
00343                 sc[0]= s0[0] - (m1[0] * pthick * 0.75f);
00344                 sc[1]= s0[1] - (m1[1] * pthick * 0.75f);
00345                 
00346                 t0[0]= sc[0] - mt[0];
00347                 t0[1]= sc[1] - mt[1];
00348                 t1[0]= sc[0] + mt[0];
00349                 t1[1]= sc[1] + mt[1];
00350                 
00351                 glVertex2fv(t0);
00352                 glVertex2fv(t1);
00353                 
00354                 /* calculate points for start of segment */
00355                 mt[0]= m2[0] * pthick;
00356                 mt[1]= m2[1] * pthick;
00357                 
00358                 t0[0]= s0[0] - mt[0];
00359                 t0[1]= s0[1] - mt[1];
00360                 t1[0]= s0[0] + mt[0];
00361                 t1[1]= s0[1] + mt[1];
00362                 
00363                 /* draw this line twice (first to finish off start cap, then for stroke) */
00364                 glVertex2fv(t1);
00365                 glVertex2fv(t0);
00366                 glVertex2fv(t0);
00367                 glVertex2fv(t1);
00368             }
00369             /* if not the first segment, use bisector of angle between segments */
00370             else {
00371                 float mb[2];        /* bisector normal */
00372                 float athick, dfac;     /* actual thickness, difference between thicknesses */
00373                 
00374                 /* calculate gradient of bisector (as average of normals) */
00375                 mb[0]= (pm[0] + m2[0]) / 2;
00376                 mb[1]= (pm[1] + m2[1]) / 2;
00377                 normalize_v2(mb);
00378                 
00379                 /* calculate gradient to apply 
00380                  *  - as basis, use just pthick * bisector gradient
00381                  *  - if cross-section not as thick as it should be, add extra padding to fix it
00382                  */
00383                 mt[0]= mb[0] * pthick;
00384                 mt[1]= mb[1] * pthick;
00385                 athick= len_v2(mt);
00386                 dfac= pthick - (athick * 2);
00387                 if ( ((athick * 2.0f) < pthick) && (IS_EQF(athick, pthick)==0) )
00388                 {
00389                     mt[0] += (mb[0] * dfac);
00390                     mt[1] += (mb[1] * dfac);
00391                 }   
00392                 
00393                 /* calculate points for start of segment */
00394                 t0[0]= s0[0] - mt[0];
00395                 t0[1]= s0[1] - mt[1];
00396                 t1[0]= s0[0] + mt[0];
00397                 t1[1]= s0[1] + mt[1];
00398                 
00399                 /* draw this line twice (once for end of current segment, and once for start of next) */
00400                 glVertex2fv(t1);
00401                 glVertex2fv(t0);
00402                 glVertex2fv(t0);
00403                 glVertex2fv(t1);
00404             }
00405             
00406             /* if last segment, also draw end of segment (defined as segment's normal) */
00407             if (i == totpoints-2) {
00408                 /* for once, we use second point's pressure (otherwise it won't be drawn) */
00409                 pthick= (pt2->pressure * thickness);
00410                 
00411                 /* calculate points for end of segment */
00412                 mt[0]= m2[0] * pthick;
00413                 mt[1]= m2[1] * pthick;
00414                 
00415                 t0[0]= s1[0] - mt[0];
00416                 t0[1]= s1[1] - mt[1];
00417                 t1[0]= s1[0] + mt[0];
00418                 t1[1]= s1[1] + mt[1];
00419                 
00420                 /* draw this line twice (once for end of stroke, and once for endcap)*/
00421                 glVertex2fv(t1);
00422                 glVertex2fv(t0);
00423                 glVertex2fv(t0);
00424                 glVertex2fv(t1);
00425                 
00426                 
00427                 /* draw end cap as last step 
00428                  *  - make points slightly closer to center (about halfway across) 
00429                  */             
00430                 mt[0]= m2[0] * pthick * 0.5f;
00431                 mt[1]= m2[1] * pthick * 0.5f;
00432                 sc[0]= s1[0] + (m1[0] * pthick * 0.75f);
00433                 sc[1]= s1[1] + (m1[1] * pthick * 0.75f);
00434                 
00435                 t0[0]= sc[0] - mt[0];
00436                 t0[1]= sc[1] - mt[1];
00437                 t1[0]= sc[0] + mt[0];
00438                 t1[1]= sc[1] + mt[1];
00439                 
00440                 glVertex2fv(t1);
00441                 glVertex2fv(t0);
00442             }
00443             
00444             /* store stroke's 'natural' normal for next stroke to use */
00445             copy_v2_v2(pm, m2);
00446         }
00447         
00448         glEnd();
00449     }
00450     
00451     /* draw debug points of curve on top? (original stroke points) */
00452     if (debug) {
00453         bGPDspoint *pt;
00454         int i;
00455         
00456         glBegin(GL_POINTS);
00457         for (i=0, pt=points; i < totpoints && pt; i++, pt++) {
00458             if (sflag & GP_STROKE_2DSPACE) {
00459                 glVertex2fv(&pt->x);
00460             }
00461             else if (sflag & GP_STROKE_2DIMAGE) {
00462                 const float x= (float)((pt->x * winx) + offsx);
00463                 const float y= (float)((pt->y * winy) + offsy);
00464                 
00465                 glVertex2f(x, y);
00466             }
00467             else {
00468                 const float x= (float)(pt->x / 100 * winx) + offsx;
00469                 const float y= (float)(pt->y / 100 * winy) + offsy;
00470                 
00471                 glVertex2f(x, y);
00472             }
00473         }
00474         glEnd();
00475     }
00476 }
00477 
00478 /* ----- General Drawing ------ */
00479 
00480 /* draw a set of strokes */
00481 static void gp_draw_strokes (bGPDframe *gpf, int offsx, int offsy, int winx, int winy, int dflag,  
00482                              short debug, short lthick, float color[4])
00483 {
00484     bGPDstroke *gps;
00485     
00486     /* set color first (may need to reset it again later too) */
00487     glColor4fv(color);
00488     
00489     for (gps= gpf->strokes.first; gps; gps= gps->next) {
00490         /* check if stroke can be drawn - checks here generally fall into pairs */
00491         if ((dflag & GP_DRAWDATA_ONLY3D) && !(gps->flag & GP_STROKE_3DSPACE))
00492             continue;
00493         if (!(dflag & GP_DRAWDATA_ONLY3D) && (gps->flag & GP_STROKE_3DSPACE))
00494             continue;
00495         if ((dflag & GP_DRAWDATA_ONLYV2D) && !(gps->flag & GP_STROKE_2DSPACE))
00496             continue;
00497         if (!(dflag & GP_DRAWDATA_ONLYV2D) && (gps->flag & GP_STROKE_2DSPACE))
00498             continue;
00499         if ((dflag & GP_DRAWDATA_ONLYI2D) && !(gps->flag & GP_STROKE_2DIMAGE))
00500             continue;
00501         if (!(dflag & GP_DRAWDATA_ONLYI2D) && (gps->flag & GP_STROKE_2DIMAGE))
00502             continue;
00503         if ((gps->points == NULL) || (gps->totpoints < 1))
00504             continue;
00505         
00506         /* check which stroke-drawer to use */
00507         if (gps->totpoints == 1)
00508             gp_draw_stroke_point(gps->points, lthick, dflag, gps->flag, offsx, offsy, winx, winy);
00509         else if (dflag & GP_DRAWDATA_ONLY3D) {
00510             const int no_xray= (dflag & GP_DRAWDATA_NO_XRAY);
00511             int mask_orig = 0;
00512             
00513             if (no_xray) {
00514                 glGetIntegerv(GL_DEPTH_WRITEMASK, &mask_orig);
00515                 glDepthMask(0);
00516                 glEnable(GL_DEPTH_TEST);
00517                 
00518                 /* first arg is normally rv3d->dist, but this isnt available here and seems to work quite well without */
00519                 bglPolygonOffset(1.0f, 1.0f);
00520                 /*
00521                 glEnable(GL_POLYGON_OFFSET_LINE);
00522                 glPolygonOffset(-1.0f, -1.0f);
00523                 */
00524             }
00525             
00526             gp_draw_stroke_3d(gps->points, gps->totpoints, lthick, debug);
00527             
00528             if (no_xray) {
00529                 glDepthMask(mask_orig);
00530                 glDisable(GL_DEPTH_TEST);
00531                 
00532                 bglPolygonOffset(0.0, 0.0);
00533                 /*
00534                 glDisable(GL_POLYGON_OFFSET_LINE);
00535                 glPolygonOffset(0, 0);
00536                 */
00537             }
00538         }
00539         else if (gps->totpoints > 1)    
00540             gp_draw_stroke(gps->points, gps->totpoints, lthick, dflag, gps->flag, debug, offsx, offsy, winx, winy);
00541     }
00542 }
00543 
00544 /* draw grease-pencil datablock */
00545 static void gp_draw_data (bGPdata *gpd, int offsx, int offsy, int winx, int winy, int cfra, int dflag)
00546 {
00547     bGPDlayer *gpl;
00548     
00549     /* reset line drawing style (in case previous user didn't reset) */
00550     setlinestyle(0);
00551     
00552     /* turn on smooth lines (i.e. anti-aliasing) */
00553     glEnable(GL_LINE_SMOOTH);
00554     
00555     /* turn on alpha-blending */
00556     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
00557     glEnable(GL_BLEND);
00558         
00559     /* loop over layers, drawing them */
00560     for (gpl= gpd->layers.first; gpl; gpl= gpl->next) {
00561         bGPDframe *gpf;
00562         
00563         short debug = (gpl->flag & GP_LAYER_DRAWDEBUG) ? 1 : 0;
00564         short lthick= gpl->thickness;
00565         float color[4], tcolor[4];
00566         
00567         /* don't draw layer if hidden */
00568         if (gpl->flag & GP_LAYER_HIDE) 
00569             continue;
00570         
00571         /* get frame to draw */
00572         gpf= gpencil_layer_getframe(gpl, cfra, 0);
00573         if (gpf == NULL) 
00574             continue;
00575         
00576         /* set color, stroke thickness, and point size */
00577         glLineWidth(lthick);
00578         copy_v4_v4(color, gpl->color); // just for copying 4 array elements
00579         copy_v4_v4(tcolor, gpl->color); // additional copy of color (for ghosting)
00580         glColor4fv(color);
00581         glPointSize((float)(gpl->thickness + 2));
00582         
00583         /* apply xray layer setting */
00584         if (gpl->flag & GP_LAYER_NO_XRAY)   dflag |=  GP_DRAWDATA_NO_XRAY;
00585         else                                dflag &= ~GP_DRAWDATA_NO_XRAY;
00586         
00587         /* draw 'onionskins' (frame left + right) */
00588         if (gpl->flag & GP_LAYER_ONIONSKIN) {
00589             /* drawing method - only immediately surrounding (gstep = 0), or within a frame range on either side (gstep > 0)*/          
00590             if (gpl->gstep) {
00591                 bGPDframe *gf;
00592                 float fac;
00593                 
00594                 /* draw previous frames first */
00595                 for (gf=gpf->prev; gf; gf=gf->prev) {
00596                     /* check if frame is drawable */
00597                     if ((gpf->framenum - gf->framenum) <= gpl->gstep) {
00598                         /* alpha decreases with distance from curframe index */
00599                         fac= 1.0f - ((float)(gpf->framenum - gf->framenum) / (float)(gpl->gstep + 1));
00600                         tcolor[3] = color[3] * fac * 0.66f;
00601                         gp_draw_strokes(gf, offsx, offsy, winx, winy, dflag, debug, lthick, tcolor);
00602                     }
00603                     else 
00604                         break;
00605                 }
00606                 
00607                 /* now draw next frames */
00608                 for (gf= gpf->next; gf; gf=gf->next) {
00609                     /* check if frame is drawable */
00610                     if ((gf->framenum - gpf->framenum) <= gpl->gstep) {
00611                         /* alpha decreases with distance from curframe index */
00612                         fac= 1.0f - ((float)(gf->framenum - gpf->framenum) / (float)(gpl->gstep + 1));
00613                         tcolor[3] = color[3] * fac * 0.66f;
00614                         gp_draw_strokes(gf, offsx, offsy, winx, winy, dflag, debug, lthick, tcolor);
00615                     }
00616                     else 
00617                         break;
00618                 }   
00619                 
00620                 /* restore alpha */
00621                 glColor4fv(color);
00622             }
00623             else {
00624                 /* draw the strokes for the ghost frames (at half of the alpha set by user) */
00625                 if (gpf->prev) {
00626                     tcolor[3] = (color[3] / 7);
00627                     gp_draw_strokes(gpf->prev, offsx, offsy, winx, winy, dflag, debug, lthick, tcolor);
00628                 }
00629                 
00630                 if (gpf->next) {
00631                     tcolor[3] = (color[3] / 4);
00632                     gp_draw_strokes(gpf->next, offsx, offsy, winx, winy, dflag, debug, lthick, tcolor);
00633                 }
00634                 
00635                 /* restore alpha */
00636                 glColor4fv(color);
00637             }
00638         }
00639         
00640         /* draw the strokes already in active frame */
00641         tcolor[3]= color[3];
00642         gp_draw_strokes(gpf, offsx, offsy, winx, winy, dflag, debug, lthick, tcolor);
00643         
00644         /* Check if may need to draw the active stroke cache, only if this layer is the active layer
00645          * that is being edited. (Stroke buffer is currently stored in gp-data)
00646          */
00647         if (ED_gpencil_session_active() && (gpl->flag & GP_LAYER_ACTIVE) &&
00648             (gpf->flag & GP_FRAME_PAINT)) 
00649         {
00650             /* Buffer stroke needs to be drawn with a different linestyle to help differentiate them from normal strokes. */
00651             gp_draw_stroke_buffer(gpd->sbuffer, gpd->sbuffer_size, lthick, dflag, gpd->sbuffer_sflag);
00652         }
00653     }
00654     
00655     /* turn off alpha blending, then smooth lines */
00656     glDisable(GL_BLEND); // alpha blending
00657     glDisable(GL_LINE_SMOOTH); // smooth lines
00658         
00659     /* restore initial gl conditions */
00660     glLineWidth(1.0);
00661     glPointSize(1.0);
00662     glColor4f(0, 0, 0, 1);
00663 }
00664 
00665 /* ----- Grease Pencil Sketches Drawing API ------ */
00666 
00667 // ............................
00668 // XXX 
00669 //  We need to review the calls below, since they may be/are not that suitable for
00670 //  the new ways that we intend to be drawing data...
00671 // ............................
00672 
00673 /* draw grease-pencil sketches to specified 2d-view that uses ibuf corrections */
00674 void draw_gpencil_2dimage (bContext *C, ImBuf *ibuf)
00675 {
00676     ScrArea *sa= CTX_wm_area(C);
00677     ARegion *ar= CTX_wm_region(C);
00678     Scene *scene= CTX_data_scene(C);
00679     bGPdata *gpd;
00680     int offsx, offsy, sizex, sizey;
00681     int dflag = GP_DRAWDATA_NOSTATUS;
00682     
00683     /* check that we have grease-pencil stuff to draw */
00684     if (ELEM(NULL, sa, ibuf)) return;
00685     gpd= gpencil_data_get_active(C); // XXX
00686     if (gpd == NULL) return;
00687     
00688     /* calculate rect */
00689     switch (sa->spacetype) {
00690         case SPACE_IMAGE: /* image */
00691         case SPACE_CLIP: /* clip */
00692         {
00693             
00694             /* just draw using standard scaling (settings here are currently ignored anyways) */
00695             // FIXME: the opengl poly-strokes don't draw at right thickness when done this way, so disabled
00696             offsx= 0;
00697             offsy= 0;
00698             sizex= ar->winx;
00699             sizey= ar->winy;
00700             
00701             wmOrtho2(ar->v2d.cur.xmin, ar->v2d.cur.xmax, ar->v2d.cur.ymin, ar->v2d.cur.ymax);
00702             
00703             dflag |= GP_DRAWDATA_ONLYV2D|GP_DRAWDATA_IEDITHACK;
00704         }
00705             break;
00706 #if 0   /* removed since 2.5x, needs to be added back */
00707         case SPACE_SEQ: /* sequence */
00708         {
00709             SpaceSeq *sseq= (SpaceSeq *)sa->spacedata.first;
00710             float zoom, zoomx, zoomy;
00711             
00712             /* calculate accessory values */
00713             zoom= (float)(SEQ_ZOOM_FAC(sseq->zoom));
00714             if (sseq->mainb == SEQ_DRAW_IMG_IMBUF) {
00715                 /* XXX sequencer zoom should store it? */
00716                 zoomx = zoom; //  * (G.scene->r.xasp / G.scene->r.yasp);
00717                 zoomy = zoom;
00718             } 
00719             else
00720                 zoomx = zoomy = zoom;
00721             
00722             /* calculate transforms (Note: we use ibuf here, as we have it) */
00723             sizex= (int)(zoomx * ibuf->x);
00724             sizey= (int)(zoomy * ibuf->y);
00725             offsx= (int)( (ar->winx-sizex)/2 + sseq->xof );
00726             offsy= (int)( (ar->winy-sizey)/2 + sseq->yof );
00727             
00728             dflag |= GP_DRAWDATA_ONLYI2D;
00729         }
00730             break;
00731 #endif
00732         default: /* for spacetype not yet handled */
00733             offsx= 0;
00734             offsy= 0;
00735             sizex= ar->winx;
00736             sizey= ar->winy;
00737             
00738             dflag |= GP_DRAWDATA_ONLYI2D;
00739             break;
00740     }
00741     
00742     
00743     /* draw it! */
00744     gp_draw_data(gpd, offsx, offsy, sizex, sizey, CFRA, dflag);
00745 }
00746 
00747 /* draw grease-pencil sketches to specified 2d-view assuming that matrices are already set correctly 
00748  * Note: this gets called twice - first time with onlyv2d=1 to draw 'canvas' strokes, second time with onlyv2d=0 for screen-aligned strokes
00749  */
00750 void draw_gpencil_view2d (bContext *C, short onlyv2d)
00751 {
00752     ScrArea *sa= CTX_wm_area(C);
00753     ARegion *ar= CTX_wm_region(C);
00754     Scene *scene= CTX_data_scene(C);
00755     bGPdata *gpd;
00756     int dflag = 0;
00757     
00758     /* check that we have grease-pencil stuff to draw */
00759     if (sa == NULL) return;
00760     gpd= gpencil_data_get_active(C); // XXX
00761     if (gpd == NULL) return;
00762     
00763     /* special hack for Image Editor */
00764     // FIXME: the opengl poly-strokes don't draw at right thickness when done this way, so disabled
00765     if (ELEM(sa->spacetype, SPACE_IMAGE, SPACE_CLIP))
00766         dflag |= GP_DRAWDATA_IEDITHACK;
00767     
00768     /* draw it! */
00769     if (onlyv2d) dflag |= (GP_DRAWDATA_ONLYV2D|GP_DRAWDATA_NOSTATUS);
00770     gp_draw_data(gpd, 0, 0, ar->winx, ar->winy, CFRA, dflag);
00771 }
00772 
00773 /* draw grease-pencil sketches to specified 3d-view assuming that matrices are already set correctly 
00774  * Note: this gets called twice - first time with only3d=1 to draw 3d-strokes, second time with only3d=0 for screen-aligned strokes
00775  */
00776 
00777 void draw_gpencil_view3d (Scene *scene, View3D *v3d, ARegion *ar, short only3d)
00778 {
00779     bGPdata *gpd;
00780     int dflag = 0;
00781     rcti rect;
00782     RegionView3D *rv3d= ar->regiondata;
00783 
00784     /* check that we have grease-pencil stuff to draw */
00785     gpd= gpencil_data_get_active_v3d(scene); // XXX
00786     if (gpd == NULL) return;
00787 
00788     /* when rendering to the offscreen buffer we dont want to
00789      * deal with the camera border, otherwise map the coords to the camera border. */
00790     if ((rv3d->persp == RV3D_CAMOB) && !(G.f & G_RENDER_OGL)) {
00791         rctf rectf;
00792         ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &rectf, TRUE); /* no shift */
00793         BLI_copy_rcti_rctf(&rect, &rectf);
00794     }
00795     else {
00796         rect.xmin= 0;
00797         rect.ymin= 0;
00798         rect.xmax= ar->winx;
00799         rect.ymax= ar->winy;
00800     }
00801     
00802     /* draw it! */
00803     if (only3d) dflag |= (GP_DRAWDATA_ONLY3D|GP_DRAWDATA_NOSTATUS);
00804 
00805     gp_draw_data(gpd, rect.xmin, rect.ymin, rect.xmax, rect.ymax, CFRA, dflag);
00806 }
00807 
00808 /* ************************************************** */