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