/* note: also check undo_history_exec() in bottom if you change notifiers */ static int ed_undo_step(bContext *C, int step, const char *undoname) { wmWindowManager *wm = CTX_wm_manager(C); wmWindow *win = CTX_wm_window(C); Scene *scene = CTX_data_scene(C); Object *obedit = CTX_data_edit_object(C); Object *obact = CTX_data_active_object(C); ScrArea *sa = CTX_wm_area(C); /* undo during jobs are running can easily lead to freeing data using by jobs, * or they can just lead to freezing job in some other cases */ if (WM_jobs_test(wm, scene, WM_JOB_TYPE_ANY)) { return OPERATOR_CANCELLED; } /* grease pencil can be can be used in plenty of spaces, so check it first */ if (ED_gpencil_session_active()) { return ED_undo_gpencil_step(C, step, undoname); } if (sa && (sa->spacetype == SPACE_IMAGE)) { SpaceImage *sima = (SpaceImage *)sa->spacedata.first; if ((obact && (obact->mode & OB_MODE_TEXTURE_PAINT)) || (sima->mode == SI_MODE_PAINT)) { if (!ED_undo_paint_step(C, UNDO_PAINT_IMAGE, step, undoname) && undoname) { if (U.uiflag & USER_GLOBALUNDO) { ED_viewport_render_kill_jobs(C, true); BKE_undo_name(C, undoname); } } WM_event_add_notifier(C, NC_WINDOW, NULL); return OPERATOR_FINISHED; } } if (sa && (sa->spacetype == SPACE_TEXT)) { ED_text_undo_step(C, step); } else if (obedit) { if (OB_TYPE_SUPPORT_EDITMODE(obedit->type)) { if (undoname) undo_editmode_name(C, undoname); else undo_editmode_step(C, step); WM_event_add_notifier(C, NC_GEOM | ND_DATA, NULL); } } else { /* Note: we used to do a fall-through here where if the * mode-specific undo system had no more steps to undo (or * redo), the global undo would run. * * That was inconsistent with editmode, and also makes for * unecessarily tricky interaction with the other undo * systems. */ if (obact && obact->mode & OB_MODE_TEXTURE_PAINT) { ED_undo_paint_step(C, UNDO_PAINT_IMAGE, step, undoname); } else if (obact && obact->mode & OB_MODE_SCULPT) { ED_undo_paint_step(C, UNDO_PAINT_MESH, step, undoname); } else if (obact && obact->mode & OB_MODE_PARTICLE_EDIT) { if (step == 1) PE_undo(scene); else PE_redo(scene); } else if (U.uiflag & USER_GLOBALUNDO) { // note python defines not valid here anymore. //#ifdef WITH_PYTHON // XXX BPY_scripts_clear_pyobjects(); //#endif /* for global undo/redo we should just clear the editmode stack */ /* for example, texface stores image pointers */ undo_editmode_clear(); ED_viewport_render_kill_jobs(C, true); if (undoname) BKE_undo_name(C, undoname); else BKE_undo_step(C, step); scene = CTX_data_scene(C); WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, scene); } } WM_event_add_notifier(C, NC_WINDOW, NULL); if (win) { win->addmousemove = true; } return OPERATOR_FINISHED; }
/* loop over gpencil data layers, drawing them */ static void gp_draw_data_layers(bGPdata *gpd, int offsx, int offsy, int winx, int winy, int cfra, int dflag) { bGPDlayer *gpl; for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { bGPDframe *gpf; bool debug = (gpl->flag & GP_LAYER_DRAWDEBUG) ? true : false; short lthick = gpl->thickness; /* don't draw layer if hidden */ if (gpl->flag & GP_LAYER_HIDE) continue; /* get frame to draw */ gpf = gpencil_layer_getframe(gpl, cfra, 0); if (gpf == NULL) continue; /* set basic stroke thickness */ glLineWidth(lthick); /* Add layer drawing settings to the set of "draw flags" * NOTE: If the setting doesn't apply, it *must* be cleared, * as dflag's carry over from the previous layer */ #define GP_DRAWFLAG_APPLY(condition, draw_flag_value) { \ if (condition) dflag |= (draw_flag_value); \ else dflag &= ~(draw_flag_value); \ } (void)0 /* xray... */ GP_DRAWFLAG_APPLY((gpl->flag & GP_LAYER_NO_XRAY), GP_DRAWDATA_NO_XRAY); /* volumetric strokes... */ GP_DRAWFLAG_APPLY((gpl->flag & GP_LAYER_VOLUMETRIC), GP_DRAWDATA_VOLUMETRIC); /* fill strokes... */ // XXX: this is not a very good limit GP_DRAWFLAG_APPLY((gpl->fill[3] > GPENCIL_ALPHA_OPACITY_THRESH), GP_DRAWDATA_FILL); #undef GP_DRAWFLAG_APPLY /* draw 'onionskins' (frame left + right) */ if ((gpl->flag & GP_LAYER_ONIONSKIN) && !(dflag & GP_DRAWDATA_NO_ONIONS)) { /* Drawing method - only immediately surrounding (gstep = 0), * or within a frame range on either side (gstep > 0) */ gp_draw_onionskins(gpl, gpf, offsx, offsy, winx, winy, cfra, dflag, debug, lthick); } /* draw the strokes already in active frame */ gp_draw_strokes(gpf, offsx, offsy, winx, winy, dflag, debug, lthick, gpl->color, gpl->fill); /* Draw verts of selected strokes * - when doing OpenGL renders, we don't want to be showing these, as that ends up flickering * - locked layers can't be edited, so there's no point showing these verts * as they will have no bearings on what gets edited * - only show when in editmode, since operators shouldn't work otherwise * (NOTE: doing it this way means that the toggling editmode shows visible change immediately) */ /* XXX: perhaps we don't want to show these when users are drawing... */ if ((G.f & G_RENDER_OGL) == 0 && (gpl->flag & GP_LAYER_LOCKED) == 0 && (gpd->flag & GP_DATA_STROKE_EDITMODE)) { gp_draw_strokes_edit(gpf, offsx, offsy, winx, winy, dflag, (gpl->color[3] < 0.95f) ? gpl->color : NULL); } /* Check if may need to draw the active stroke cache, only if this layer is the active layer * that is being edited. (Stroke buffer is currently stored in gp-data) */ if (ED_gpencil_session_active() && (gpl->flag & GP_LAYER_ACTIVE) && (gpf->flag & GP_FRAME_PAINT)) { /* Set color for drawing buffer stroke - since this may not be set yet */ glColor4fv(gpl->color); /* Buffer stroke needs to be drawn with a different linestyle * to help differentiate them from normal strokes. * * It should also be noted that sbuffer contains temporary point types * i.e. tGPspoints NOT bGPDspoints */ if (gpl->flag & GP_LAYER_VOLUMETRIC) { gp_draw_stroke_volumetric_buffer(gpd->sbuffer, gpd->sbuffer_size, lthick, dflag, gpd->sbuffer_sflag); } else { gp_draw_stroke_buffer(gpd->sbuffer, gpd->sbuffer_size, lthick, dflag, gpd->sbuffer_sflag); } } } }
/* draw grease-pencil datablock */ static void gp_draw_data (bGPdata *gpd, int offsx, int offsy, int winx, int winy, int cfra, int dflag) { bGPDlayer *gpl; /* reset line drawing style (in case previous user didn't reset) */ setlinestyle(0); /* turn on smooth lines (i.e. anti-aliasing) */ glEnable(GL_LINE_SMOOTH); /* turn on alpha-blending */ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_BLEND); /* loop over layers, drawing them */ for (gpl= gpd->layers.first; gpl; gpl= gpl->next) { bGPDframe *gpf; short debug = (gpl->flag & GP_LAYER_DRAWDEBUG) ? 1 : 0; short lthick= gpl->thickness; float color[4], tcolor[4]; /* don't draw layer if hidden */ if (gpl->flag & GP_LAYER_HIDE) continue; /* get frame to draw */ gpf= gpencil_layer_getframe(gpl, cfra, 0); if (gpf == NULL) continue; /* set color, stroke thickness, and point size */ glLineWidth(lthick); copy_v4_v4(color, gpl->color); // just for copying 4 array elements copy_v4_v4(tcolor, gpl->color); // additional copy of color (for ghosting) glColor4fv(color); glPointSize((float)(gpl->thickness + 2)); /* apply xray layer setting */ if (gpl->flag & GP_LAYER_NO_XRAY) dflag |= GP_DRAWDATA_NO_XRAY; else dflag &= ~GP_DRAWDATA_NO_XRAY; /* draw 'onionskins' (frame left + right) */ if (gpl->flag & GP_LAYER_ONIONSKIN) { /* drawing method - only immediately surrounding (gstep = 0), or within a frame range on either side (gstep > 0)*/ if (gpl->gstep) { bGPDframe *gf; float fac; /* draw previous frames first */ for (gf=gpf->prev; gf; gf=gf->prev) { /* check if frame is drawable */ if ((gpf->framenum - gf->framenum) <= gpl->gstep) { /* alpha decreases with distance from curframe index */ fac= 1.0f - ((float)(gpf->framenum - gf->framenum) / (float)(gpl->gstep + 1)); tcolor[3] = color[3] * fac * 0.66f; gp_draw_strokes(gf, offsx, offsy, winx, winy, dflag, debug, lthick, tcolor); } else break; } /* now draw next frames */ for (gf= gpf->next; gf; gf=gf->next) { /* check if frame is drawable */ if ((gf->framenum - gpf->framenum) <= gpl->gstep) { /* alpha decreases with distance from curframe index */ fac= 1.0f - ((float)(gf->framenum - gpf->framenum) / (float)(gpl->gstep + 1)); tcolor[3] = color[3] * fac * 0.66f; gp_draw_strokes(gf, offsx, offsy, winx, winy, dflag, debug, lthick, tcolor); } else break; } /* restore alpha */ glColor4fv(color); } else { /* draw the strokes for the ghost frames (at half of the alpha set by user) */ if (gpf->prev) { tcolor[3] = (color[3] / 7); gp_draw_strokes(gpf->prev, offsx, offsy, winx, winy, dflag, debug, lthick, tcolor); } if (gpf->next) { tcolor[3] = (color[3] / 4); gp_draw_strokes(gpf->next, offsx, offsy, winx, winy, dflag, debug, lthick, tcolor); } /* restore alpha */ glColor4fv(color); } } /* draw the strokes already in active frame */ tcolor[3]= color[3]; gp_draw_strokes(gpf, offsx, offsy, winx, winy, dflag, debug, lthick, tcolor); /* Check if may need to draw the active stroke cache, only if this layer is the active layer * that is being edited. (Stroke buffer is currently stored in gp-data) */ if (ED_gpencil_session_active() && (gpl->flag & GP_LAYER_ACTIVE) && (gpf->flag & GP_FRAME_PAINT)) { /* Buffer stroke needs to be drawn with a different linestyle to help differentiate them from normal strokes. */ gp_draw_stroke_buffer(gpd->sbuffer, gpd->sbuffer_size, lthick, dflag, gpd->sbuffer_sflag); } } /* turn off alpha blending, then smooth lines */ glDisable(GL_BLEND); // alpha blending glDisable(GL_LINE_SMOOTH); // smooth lines /* restore initial gl conditions */ glLineWidth(1.0); glPointSize(1.0); glColor4f(0, 0, 0, 1); }