Merge branch 'master' into blender2.8
authorCampbell Barton <ideasman42@gmail.com>
Wed, 29 Aug 2018 15:36:52 +0000 (01:36 +1000)
committerCampbell Barton <ideasman42@gmail.com>
Wed, 29 Aug 2018 15:38:16 +0000 (01:38 +1000)
14 files changed:
1  2 
source/blender/blenkernel/intern/pointcache.c
source/blender/blenloader/intern/readfile.c
source/blender/draw/engines/gpencil/gpencil_render.c
source/blender/editors/gpencil/gpencil_data.c
source/blender/editors/gpencil/gpencil_edit.c
source/blender/editors/physics/particle_edit.c
source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp
source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp
source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp
source/blender/makesrna/intern/rna_brush.c
source/blender/modifiers/intern/MOD_bevel.c
source/blender/render/intern/source/bake_api.c
source/blender/render/intern/source/render_result.c
source/blender/render/intern/source/render_texture.c

index fb9739d88422dfe93d438eb4a5eea4ad41de2590,08a45f367f4c12b5cd0f0b8fa95f9784bf3f44a6..1d030610bf2d5db84ab6014ad92686053697f74d
@@@ -10138,91 -9883,86 +10138,91 @@@ void BLO_expand_main(void *fdhandle, Ma
                                        expand_idprops(fd, mainvar, id->properties);
  
                                        switch (GS(id->name)) {
-                                       case ID_OB:
-                                               expand_object(fd, mainvar, (Object *)id);
-                                               break;
-                                       case ID_ME:
-                                               expand_mesh(fd, mainvar, (Mesh *)id);
-                                               break;
-                                       case ID_CU:
-                                               expand_curve(fd, mainvar, (Curve *)id);
-                                               break;
-                                       case ID_MB:
-                                               expand_mball(fd, mainvar, (MetaBall *)id);
-                                               break;
-                                       case ID_SCE:
-                                               expand_scene(fd, mainvar, (Scene *)id);
-                                               break;
-                                       case ID_MA:
-                                               expand_material(fd, mainvar, (Material *)id);
-                                               break;
-                                       case ID_TE:
-                                               expand_texture(fd, mainvar, (Tex *)id);
-                                               break;
-                                       case ID_WO:
-                                               expand_world(fd, mainvar, (World *)id);
-                                               break;
-                                       case ID_LT:
-                                               expand_lattice(fd, mainvar, (Lattice *)id);
-                                               break;
-                                       case ID_LA:
-                                               expand_lamp(fd, mainvar, (Lamp *)id);
-                                               break;
-                                       case ID_KE:
-                                               expand_key(fd, mainvar, (Key *)id);
-                                               break;
-                                       case ID_CA:
-                                               expand_camera(fd, mainvar, (Camera *)id);
-                                               break;
-                                       case ID_SPK:
-                                               expand_speaker(fd, mainvar, (Speaker *)id);
-                                               break;
-                                       case ID_SO:
-                                               expand_sound(fd, mainvar, (bSound *)id);
-                                               break;
-                                       case ID_LP:
-                                               expand_lightprobe(fd, mainvar, (LightProbe *)id);
-                                               break;
-                                       case ID_AR:
-                                               expand_armature(fd, mainvar, (bArmature *)id);
-                                               break;
-                                       case ID_AC:
-                                               expand_action(fd, mainvar, (bAction *)id); // XXX deprecated - old animation system
-                                               break;
-                                       case ID_GR:
-                                               expand_collection(fd, mainvar, (Collection *)id);
-                                               break;
-                                       case ID_NT:
-                                               expand_nodetree(fd, mainvar, (bNodeTree *)id);
-                                               break;
-                                       case ID_BR:
-                                               expand_brush(fd, mainvar, (Brush *)id);
-                                               break;
-                                       case ID_IP:
-                                               expand_ipo(fd, mainvar, (Ipo *)id); // XXX deprecated - old animation system
-                                               break;
-                                       case ID_PA:
-                                               expand_particlesettings(fd, mainvar, (ParticleSettings *)id);
-                                               break;
-                                       case ID_MC:
-                                               expand_movieclip(fd, mainvar, (MovieClip *)id);
-                                               break;
-                                       case ID_MSK:
-                                               expand_mask(fd, mainvar, (Mask *)id);
-                                               break;
-                                       case ID_LS:
-                                               expand_linestyle(fd, mainvar, (FreestyleLineStyle *)id);
-                                               break;
-                                       case ID_GD:
-                                               expand_gpencil(fd, mainvar, (bGPdata *)id);
-                                               break;
-                                       case ID_CF:
-                                               expand_cachefile(fd, mainvar, (CacheFile *)id);
-                                               break;
-                                       case ID_WS:
-                                               expand_workspace(fd, mainvar, (WorkSpace *)id);
-                                       default:
-                                               break;
+                                               case ID_OB:
+                                                       expand_object(fd, mainvar, (Object *)id);
+                                                       break;
+                                               case ID_ME:
+                                                       expand_mesh(fd, mainvar, (Mesh *)id);
+                                                       break;
+                                               case ID_CU:
+                                                       expand_curve(fd, mainvar, (Curve *)id);
+                                                       break;
+                                               case ID_MB:
+                                                       expand_mball(fd, mainvar, (MetaBall *)id);
+                                                       break;
+                                               case ID_SCE:
+                                                       expand_scene(fd, mainvar, (Scene *)id);
+                                                       break;
+                                               case ID_MA:
+                                                       expand_material(fd, mainvar, (Material *)id);
+                                                       break;
+                                               case ID_TE:
+                                                       expand_texture(fd, mainvar, (Tex *)id);
+                                                       break;
+                                               case ID_WO:
+                                                       expand_world(fd, mainvar, (World *)id);
+                                                       break;
+                                               case ID_LT:
+                                                       expand_lattice(fd, mainvar, (Lattice *)id);
+                                                       break;
+                                               case ID_LA:
+                                                       expand_lamp(fd, mainvar, (Lamp *)id);
+                                                       break;
+                                               case ID_KE:
+                                                       expand_key(fd, mainvar, (Key *)id);
+                                                       break;
+                                               case ID_CA:
+                                                       expand_camera(fd, mainvar, (Camera *)id);
+                                                       break;
+                                               case ID_SPK:
+                                                       expand_speaker(fd, mainvar, (Speaker *)id);
+                                                       break;
+                                               case ID_SO:
+                                                       expand_sound(fd, mainvar, (bSound *)id);
+                                                       break;
++                                              case ID_LP:
++                                                      expand_lightprobe(fd, mainvar, (LightProbe *)id);
++                                                      break;
+                                               case ID_AR:
+                                                       expand_armature(fd, mainvar, (bArmature *)id);
+                                                       break;
+                                               case ID_AC:
+                                                       expand_action(fd, mainvar, (bAction *)id); // XXX deprecated - old animation system
+                                                       break;
+                                               case ID_GR:
 -                                                      expand_group(fd, mainvar, (Group *)id);
++                                                      expand_collection(fd, mainvar, (Collection *)id);
+                                                       break;
+                                               case ID_NT:
+                                                       expand_nodetree(fd, mainvar, (bNodeTree *)id);
+                                                       break;
+                                               case ID_BR:
+                                                       expand_brush(fd, mainvar, (Brush *)id);
+                                                       break;
+                                               case ID_IP:
+                                                       expand_ipo(fd, mainvar, (Ipo *)id); // XXX deprecated - old animation system
+                                                       break;
+                                               case ID_PA:
+                                                       expand_particlesettings(fd, mainvar, (ParticleSettings *)id);
+                                                       break;
+                                               case ID_MC:
+                                                       expand_movieclip(fd, mainvar, (MovieClip *)id);
+                                                       break;
+                                               case ID_MSK:
+                                                       expand_mask(fd, mainvar, (Mask *)id);
+                                                       break;
+                                               case ID_LS:
+                                                       expand_linestyle(fd, mainvar, (FreestyleLineStyle *)id);
+                                                       break;
+                                               case ID_GD:
+                                                       expand_gpencil(fd, mainvar, (bGPdata *)id);
+                                                       break;
+                                               case ID_CF:
+                                                       expand_cachefile(fd, mainvar, (CacheFile *)id);
+                                                       break;
++                                              case ID_WS:
++                                                      expand_workspace(fd, mainvar, (WorkSpace *)id);
+                                               default:
+                                                       break;
                                        }
  
                                        do_it = true;
index 0b90de88ec1103a75ee0519ab3106977a7bfe6ed,0000000000000000000000000000000000000000..3aa94c346df679bf312f042d0d7ffd9281e00568
mode 100644,000000..100644
--- /dev/null
@@@ -1,356 -1,0 +1,356 @@@
-       * Can be used to recreate the world space position easily */
 +/*
 + * Copyright 2017, Blender Foundation.
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU General Public License
 + * as published by the Free Software Foundation; either version 2
 + * of the License, or (at your option) any later version.
 + *
 + * This program is distributed in the hope that it will be useful,
 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 + * GNU General Public License for more details.
 + *
 + * You should have received a copy of the GNU General Public License
 + * along with this program; if not, write to the Free Software Foundation,
 + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 + *
 + * Contributor(s): Antonio Vazquez
 + *
 + */
 +
 +/** \file blender/draw/engines/gpencil/gpencil_render.c
 + *  \ingroup draw
 + */
 +#include "BLI_rect.h"
 +
 +#include "DRW_engine.h"
 +#include "DRW_render.h"
 +
 +#include "BKE_camera.h"
 +
 +#include "DNA_gpencil_types.h"
 +
 +#include "DEG_depsgraph_query.h"
 +
 +#include "draw_mode_engines.h"
 +
 +#include "RE_pipeline.h"
 +
 +#include "gpencil_engine.h"
 +
 +/* Get pixel size for render
 +* This function uses the same calculation used for viewport, because if use
 +* camera pixelsize, the result is not correct.
 +*/
 +static float get_render_pixelsize(float persmat[4][4], int winx, int winy)
 +{
 +      float v1[3], v2[3];
 +      float len_px, len_sc;
 +
 +      v1[0] = persmat[0][0];
 +      v1[1] = persmat[1][0];
 +      v1[2] = persmat[2][0];
 +
 +      v2[0] = persmat[0][1];
 +      v2[1] = persmat[1][1];
 +      v2[2] = persmat[2][1];
 +
 +      len_px = 2.0f / sqrtf(min_ff(len_squared_v3(v1), len_squared_v3(v2)));
 +      len_sc = (float)MAX2(winx, winy);
 +
 +      return len_px / len_sc;
 +}
 +
 +/* init render data */
 +void GPENCIL_render_init(GPENCIL_Data *ved, RenderEngine *engine, struct Depsgraph *depsgraph)
 +{
 +      GPENCIL_Data *vedata = (GPENCIL_Data *)ved;
 +      GPENCIL_StorageList *stl = vedata->stl;
 +      GPENCIL_FramebufferList *fbl = vedata->fbl;
 +
 +      Scene *scene = DEG_get_evaluated_scene(depsgraph);
 +      const float *viewport_size = DRW_viewport_size_get();
 +      const int size[2] = { (int)viewport_size[0], (int)viewport_size[1] };
 +
 +      /* In render mode the default framebuffer is not generated
 +      * because there is no viewport. So we need to manually create one
 +      * NOTE : use 32 bit format for precision in render mode.
 +      */
 +      /* create multiframe framebuffer for AA */
 +      if (U.gpencil_multisamples > 0) {
 +              int rect_w = (int)viewport_size[0];
 +              int rect_h = (int)viewport_size[1];
 +              DRW_gpencil_multisample_ensure(vedata, rect_w, rect_h);
 +      }
 +
 +      vedata->render_depth_tx = DRW_texture_pool_query_2D(
 +              size[0], size[1], GPU_DEPTH24_STENCIL8,
 +              &draw_engine_gpencil_type);
 +      vedata->render_color_tx = DRW_texture_pool_query_2D(
 +              size[0], size[1], GPU_RGBA32F,
 +              &draw_engine_gpencil_type);
 +      GPU_framebuffer_ensure_config(
 +              &fbl->main, {
 +                  GPU_ATTACHMENT_TEXTURE(vedata->render_depth_tx),
 +                  GPU_ATTACHMENT_TEXTURE(vedata->render_color_tx)
 +              });
 +
 +      /* Alloc transient data. */
 +      if (!stl->g_data) {
 +              stl->g_data = MEM_callocN(sizeof(*stl->g_data), __func__);
 +      }
 +
 +      /* Set the pers & view matrix. */
 +      struct Object *camera = DEG_get_evaluated_object(depsgraph, RE_GetCamera(engine->re));
 +      float frame = BKE_scene_frame_get(scene);
 +      RE_GetCameraWindow(engine->re, camera, frame, stl->storage->winmat);
 +      RE_GetCameraModelMatrix(engine->re, camera, stl->storage->viewinv);
 +
 +      invert_m4_m4(stl->storage->viewmat, stl->storage->viewinv);
 +      mul_m4_m4m4(stl->storage->persmat, stl->storage->winmat, stl->storage->viewmat);
 +      invert_m4_m4(stl->storage->persinv, stl->storage->persmat);
 +      invert_m4_m4(stl->storage->wininv, stl->storage->winmat);
 +
 +      DRW_viewport_matrix_override_set(stl->storage->persmat, DRW_MAT_PERS);
 +      DRW_viewport_matrix_override_set(stl->storage->persinv, DRW_MAT_PERSINV);
 +      DRW_viewport_matrix_override_set(stl->storage->winmat, DRW_MAT_WIN);
 +      DRW_viewport_matrix_override_set(stl->storage->wininv, DRW_MAT_WININV);
 +      DRW_viewport_matrix_override_set(stl->storage->viewmat, DRW_MAT_VIEW);
 +      DRW_viewport_matrix_override_set(stl->storage->viewinv, DRW_MAT_VIEWINV);
 +
 +      /* calculate pixel size for render */
 +      stl->storage->render_pixsize = get_render_pixelsize(stl->storage->persmat, viewport_size[0], viewport_size[1]);
 +      /* INIT CACHE */
 +      GPENCIL_cache_init(vedata);
 +}
 +
 +/* render all objects and select only grease pencil */
 +static void GPENCIL_render_cache(
 +      void *vedata, struct Object *ob,
 +      struct RenderEngine *UNUSED(engine), struct Depsgraph *UNUSED(depsgraph))
 +{
 +      if ((ob == NULL) || (DRW_check_object_visible_within_active_context(ob) == false)) {
 +              return;
 +      }
 +
 +      if (ob->type == OB_GPENCIL) {
 +              GPENCIL_cache_populate(vedata, ob);
 +      }
 +}
 +
 +/* TODO: Reuse Eevee code in shared module instead to duplicate here */
 +static void GPENCIL_render_update_viewvecs(float invproj[4][4], float winmat[4][4], float(*r_viewvecs)[4])
 +{
 +      /* view vectors for the corners of the view frustum.
-               { -1.0f, -1.0f, -1.0f, 1.0f },
-       { 1.0f, -1.0f, -1.0f, 1.0f },
-       { -1.0f,  1.0f, -1.0f, 1.0f },
-       { -1.0f, -1.0f,  1.0f, 1.0f }
++       * Can be used to recreate the world space position easily */
 +      float view_vecs[4][4] = {
++              {-1.0f, -1.0f, -1.0f, 1.0f},
++              {1.0f, -1.0f, -1.0f, 1.0f},
++              {-1.0f,  1.0f, -1.0f, 1.0f},
++              {-1.0f, -1.0f,  1.0f, 1.0f}
 +      };
 +
 +      /* convert the view vectors to view space */
 +      const bool is_persp = (winmat[3][3] == 0.0f);
 +      for (int i = 0; i < 4; i++) {
 +              mul_project_m4_v3(invproj, view_vecs[i]);
 +              /* normalized trick see:
 +              * http://www.derschmale.com/2014/01/26/reconstructing-positions-from-the-depth-buffer */
 +              if (is_persp) {
 +                      /* Divide XY by Z. */
 +                      mul_v2_fl(view_vecs[i], 1.0f / view_vecs[i][2]);
 +              }
 +      }
 +
 +      /**
 +      * If ortho : view_vecs[0] is the near-bottom-left corner of the frustum and
 +      *            view_vecs[1] is the vector going from the near-bottom-left corner to
 +      *            the far-top-right corner.
 +      * If Persp : view_vecs[0].xy and view_vecs[1].xy are respectively the bottom-left corner
 +      *            when Z = 1, and top-left corner if Z = 1.
 +      *            view_vecs[0].z the near clip distance and view_vecs[1].z is the (signed)
 +      *            distance from the near plane to the far clip plane.
 +      **/
 +      copy_v4_v4(r_viewvecs[0], view_vecs[0]);
 +
 +      /* we need to store the differences */
 +      r_viewvecs[1][0] = view_vecs[1][0] - view_vecs[0][0];
 +      r_viewvecs[1][1] = view_vecs[2][1] - view_vecs[0][1];
 +      r_viewvecs[1][2] = view_vecs[3][2] - view_vecs[0][2];
 +}
 +
 +/* Update view_vecs */
 +static void GPENCIL_render_update_vecs(GPENCIL_Data *vedata)
 +{
 +      GPENCIL_StorageList *stl = vedata->stl;
 +
 +      float invproj[4][4], winmat[4][4];
 +      DRW_viewport_matrix_get(winmat, DRW_MAT_WIN);
 +      DRW_viewport_matrix_get(invproj, DRW_MAT_WININV);
 +
 +      /* this is separated to keep function equal to Eevee for future reuse of same code */
 +      GPENCIL_render_update_viewvecs(invproj, winmat, stl->storage->view_vecs);
 +}
 +
 +/* read z-depth render result */
 +static void GPENCIL_render_result_z(struct RenderLayer *rl, const char *viewname, GPENCIL_Data *vedata, const rcti *rect)
 +{
 +      const DRWContextState *draw_ctx = DRW_context_state_get();
 +      ViewLayer *view_layer = draw_ctx->view_layer;
 +      GPENCIL_StorageList *stl = vedata->stl;
 +
 +      if ((view_layer->passflag & SCE_PASS_Z) != 0) {
 +              RenderPass *rp = RE_pass_find_by_name(rl, RE_PASSNAME_Z, viewname);
 +
 +              GPU_framebuffer_read_depth(vedata->fbl->main, rect->xmin, rect->ymin, BLI_rcti_size_x(rect), BLI_rcti_size_y(rect), rp->rect);
 +
 +              bool is_persp = DRW_viewport_is_persp_get();
 +
 +              GPENCIL_render_update_vecs(vedata);
 +
 +              /* Convert ogl depth [0..1] to view Z [near..far] */
 +              for (int i = 0; i < BLI_rcti_size_x(rect) * BLI_rcti_size_y(rect); i++) {
 +                      if (rp->rect[i] == 1.0f) {
 +                              rp->rect[i] = 1e10f; /* Background */
 +                      }
 +                      else {
 +                              if (is_persp) {
 +                                      rp->rect[i] = rp->rect[i] * 2.0f - 1.0f;
 +                                      rp->rect[i] = stl->storage->winmat[3][2] / (rp->rect[i] + stl->storage->winmat[2][2]);
 +                              }
 +                              else {
 +                                      rp->rect[i] = -stl->storage->view_vecs[0][2] + rp->rect[i] * -stl->storage->view_vecs[1][2];
 +                              }
 +                      }
 +              }
 +      }
 +}
 +
 +/* read combined render result */
 +static void GPENCIL_render_result_combined(struct RenderLayer *rl, const char *viewname, GPENCIL_Data *vedata, const rcti *rect)
 +{
 +      RenderPass *rp = RE_pass_find_by_name(rl, RE_PASSNAME_COMBINED, viewname);
 +      GPENCIL_FramebufferList *fbl = ((GPENCIL_Data *)vedata)->fbl;
 +
 +      GPU_framebuffer_bind(fbl->main);
 +      GPU_framebuffer_read_color(vedata->fbl->main, rect->xmin, rect->ymin, BLI_rcti_size_x(rect), BLI_rcti_size_y(rect), 4, 0, rp->rect);
 +}
 +
 +/* helper to blend pixels */
 +static void blend_pixel(float src[4], float dst[4])
 +{
 +      float alpha = src[3];
 +
 +      /* use blend: GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA */
 +      dst[0] = (src[0] * alpha) + (dst[0] * (1.0f - alpha));
 +      dst[1] = (src[1] * alpha) + (dst[1] * (1.0f - alpha));
 +      dst[2] = (src[2] * alpha) + (dst[2] * (1.0f - alpha));
 +}
 +
 +/* render grease pencil to image */
 +void GPENCIL_render_to_image(void *vedata, RenderEngine *engine, struct RenderLayer *render_layer, const rcti *rect)
 +{
 +      const char *viewname = RE_GetActiveRenderView(engine->re);
 +      const DRWContextState *draw_ctx = DRW_context_state_get();
 +      int imgsize = BLI_rcti_size_x(rect) * BLI_rcti_size_y(rect);
 +
 +      /* save previous render data */
 +      RenderPass *rpass_color_src = RE_pass_find_by_name(render_layer, RE_PASSNAME_COMBINED, viewname);
 +      RenderPass *rpass_depth_src = RE_pass_find_by_name(render_layer, RE_PASSNAME_Z, viewname);
 +      float *src_rect_color_data = NULL;
 +      float *src_rect_depth_data = NULL;
 +      if ((rpass_color_src) && (rpass_depth_src) && (rpass_color_src->rect) && (rpass_depth_src->rect)) {
 +              src_rect_color_data = MEM_dupallocN(rpass_color_src->rect);
 +              src_rect_depth_data = MEM_dupallocN(rpass_depth_src->rect);
 +      }
 +      else {
 +              /* TODO: put this message in a better place */
 +              printf("Warning: To render grease pencil, enable Combined and Z passes.\n");
 +      }
 +
 +      GPENCIL_engine_init(vedata);
 +      GPENCIL_render_init(vedata, engine, draw_ctx->depsgraph);
 +
 +      GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
 +      Object *camera = DEG_get_evaluated_object(draw_ctx->depsgraph, RE_GetCamera(engine->re));
 +      stl->storage->camera = camera; /* save current camera */
 +
 +      GPENCIL_FramebufferList *fbl = ((GPENCIL_Data *)vedata)->fbl;
 +      if (fbl->main) {
 +              GPU_framebuffer_texture_attach(fbl->main, ((GPENCIL_Data *)vedata)->render_depth_tx, 0, 0);
 +              GPU_framebuffer_texture_attach(fbl->main, ((GPENCIL_Data *)vedata)->render_color_tx, 0, 0);
 +              /* clean first time the buffer */
 +              float clearcol[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
 +              GPU_framebuffer_bind(fbl->main);
 +              GPU_framebuffer_clear_color_depth(fbl->main, clearcol, 1.0f);
 +      }
 +
 +      /* loop all objects and draw */
 +      DRW_render_object_iter(vedata, engine, draw_ctx->depsgraph, GPENCIL_render_cache);
 +
 +      GPENCIL_cache_finish(vedata);
 +      GPENCIL_draw_scene(vedata);
 +
 +      /* combined data */
 +      GPENCIL_render_result_combined(render_layer, viewname, vedata, rect);
 +      /* z-depth data */
 +      GPENCIL_render_result_z(render_layer, viewname, vedata, rect);
 +
 +      /* detach textures */
 +       if (fbl->main) {
 +              GPU_framebuffer_texture_detach(fbl->main, ((GPENCIL_Data *)vedata)->render_depth_tx);
 +              GPU_framebuffer_texture_detach(fbl->main, ((GPENCIL_Data *)vedata)->render_color_tx);
 +       }
 +
 +      /* merge previous render image with new GP image */
 +      if (src_rect_color_data) {
 +              RenderPass *rpass_color_gp = RE_pass_find_by_name(render_layer, RE_PASSNAME_COMBINED, viewname);
 +              RenderPass *rpass_depth_gp = RE_pass_find_by_name(render_layer, RE_PASSNAME_Z, viewname);
 +              float *gp_rect_color_data = rpass_color_gp->rect;
 +              float *gp_rect_depth_data = rpass_depth_gp->rect;
 +              float *gp_pixel_rgba;
 +              float *gp_pixel_depth;
 +              float *src_pixel_rgba;
 +              float *src_pixel_depth;
 +              float tmp[4];
 +
 +              for (int i = 0; i < imgsize; i++) {
 +                      gp_pixel_rgba = &gp_rect_color_data[i * 4];
 +                      gp_pixel_depth = &gp_rect_depth_data[i];
 +
 +                      src_pixel_rgba = &src_rect_color_data[i * 4];
 +                      src_pixel_depth = &src_rect_depth_data[i];
 +
 +                      /* check grease pencil render transparency */
 +                      if (gp_pixel_rgba[3] > 0.0f) {
 +                              copy_v4_v4(tmp, gp_pixel_rgba);
 +                              if (src_pixel_rgba[3] > 0.0f) {
 +                                      /* copy source color on back */
 +                                      copy_v4_v4(gp_pixel_rgba, src_pixel_rgba);
 +                                      /* check z-depth */
 +                                      if (gp_pixel_depth[0] > src_pixel_depth[0]) {
 +                                              /* copy source z-depth */
 +                                              gp_pixel_depth[0] = src_pixel_depth[0];
 +                                              /* blend gp render */
 +                                              blend_pixel(tmp, gp_pixel_rgba);
 +                                              /* blend object on top */
 +                                              blend_pixel(src_pixel_rgba, gp_pixel_rgba);
 +                                      }
 +                                      else {
 +                                              /* blend gp render */
 +                                              blend_pixel(tmp, gp_pixel_rgba);
 +                                      }
 +                              }
 +                      }
 +                      else {
 +                              copy_v4_v4(gp_pixel_rgba, src_pixel_rgba);
 +                              gp_pixel_depth[0] = src_pixel_depth[0];
 +                      }
 +              }
 +
 +              /* free memory */
 +              MEM_SAFE_FREE(src_rect_color_data);
 +              MEM_SAFE_FREE(src_rect_depth_data);
 +      }
 +}
index 548294df388bcfe9fcf134bc72bbaa7c5a8a1ae6,c28fea0fc4175e8bc328beb3866ac43d2a92cf70..3321bec38465da4739576aff302c2899faaed760
@@@ -418,376 -366,6 +418,376 @@@ void GPENCIL_OT_layer_duplicate(wmOpera
        ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
  }
  
-       { GP_FRAME_CLEAN_FILL_ACTIVE, "ACTIVE", 0, "Active Frame Only", "Clean active frame only" },
-       { GP_FRAME_CLEAN_FILL_ALL, "ALL", 0, "All Frames", "Clean all frames in all layers" },
-       { 0, NULL, 0, NULL, NULL }
 +/* ********************* Duplicate Layer in a new object ************************** */
 +enum {
 +      GP_LAYER_COPY_OBJECT_ALL_FRAME = 0,
 +      GP_LAYER_COPY_OBJECT_ACT_FRAME = 1
 +};
 +
 +static bool gp_layer_duplicate_object_poll(bContext *C)
 +{
 +      ViewLayer *view_layer = CTX_data_view_layer(C);
 +      Object *ob = CTX_data_active_object(C);
 +      if ((ob == NULL) || (ob->type != OB_GPENCIL))
 +              return false;
 +
 +      bGPdata *gpd = (bGPdata *)ob->data;
 +      bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
 +
 +      if (gpl == NULL)
 +              return false;
 +
 +      /* check there are more grease pencil objects */
 +      for (Base *base = view_layer->object_bases.first; base; base = base->next) {
 +              if ((base->object != ob) && (base->object->type == OB_GPENCIL))
 +                      return true;
 +      }
 +
 +      return false;
 +}
 +
 +static int gp_layer_duplicate_object_exec(bContext *C, wmOperator *op)
 +{
 +      Main *bmain = CTX_data_main(C);
 +      Scene *scene = CTX_data_scene(C);
 +      char name[MAX_ID_NAME - 2];
 +      RNA_string_get(op->ptr, "object", name);
 +
 +      if (name[0] == '\0') {
 +              return OPERATOR_CANCELLED;
 +      }
 +
 +      Object *ob_dst = (Object *)BKE_scene_object_find_by_name(scene, name);
 +
 +      int mode = RNA_enum_get(op->ptr, "mode");
 +
 +      Object *ob_src = CTX_data_active_object(C);
 +      bGPdata *gpd_src = (bGPdata *)ob_src->data;
 +      bGPDlayer *gpl_src = BKE_gpencil_layer_getactive(gpd_src);
 +
 +      /* sanity checks */
 +      if (ELEM(NULL, gpd_src, gpl_src, ob_dst)) {
 +              return OPERATOR_CANCELLED;
 +      }
 +      /* cannot copy itself and check destination type */
 +      if ((ob_src == ob_dst) || (ob_dst->type != OB_GPENCIL)) {
 +              return OPERATOR_CANCELLED;
 +      }
 +
 +      bGPdata *gpd_dst = (bGPdata *)ob_dst->data;
 +
 +      /* make copy of layer */
 +      bGPDlayer *gpl_dst = MEM_dupallocN(gpl_src);
 +      gpl_dst->prev = gpl_dst->next = NULL;
 +      gpl_dst->runtime.derived_data = NULL;
 +      BLI_addtail(&gpd_dst->layers, gpl_dst);
 +      BLI_uniquename(&gpd_dst->layers, gpl_dst, DATA_("GP_Layer"), '.', offsetof(bGPDlayer, info), sizeof(gpl_dst->info));
 +
 +      /* copy frames */
 +      BLI_listbase_clear(&gpl_dst->frames);
 +      for (bGPDframe *gpf_src = gpl_src->frames.first; gpf_src; gpf_src = gpf_src->next) {
 +
 +              if ((mode == GP_LAYER_COPY_OBJECT_ACT_FRAME) && (gpf_src != gpl_src->actframe)) {
 +                      continue;
 +              }
 +
 +              /* make a copy of source frame */
 +              bGPDframe *gpf_dst = MEM_dupallocN(gpf_src);
 +              gpf_dst->prev = gpf_dst->next = NULL;
 +              BLI_addtail(&gpl_dst->frames, gpf_dst);
 +
 +              /* copy strokes */
 +              BLI_listbase_clear(&gpf_dst->strokes);
 +              for (bGPDstroke *gps_src = gpf_src->strokes.first; gps_src; gps_src = gps_src->next) {
 +
 +                      /* make copy of source stroke */
 +                      bGPDstroke *gps_dst = BKE_gpencil_stroke_duplicate(gps_src);
 +
 +                      /* check if material is in destination object,
 +                       * otherwise add the slot with the material
 +                       */
 +                      Material *ma_src = give_current_material(ob_src, gps_src->mat_nr + 1);
 +                      int idx = BKE_gpencil_get_material_index(ob_dst, ma_src);
 +                      if (idx == 0) {
 +                              BKE_object_material_slot_add(bmain, ob_dst);
 +                              assign_material(bmain, ob_dst, ma_src, ob_dst->totcol, BKE_MAT_ASSIGN_USERPREF);
 +                              idx = ob_dst->totcol;
 +                      }
 +
 +                      /* reasign the stroke material to the right slot in destination object */
 +                      gps_dst->mat_nr = idx - 1;
 +
 +                      /* add new stroke to frame */
 +                      BLI_addtail(&gpf_dst->strokes, gps_dst);
 +              }
 +      }
 +
 +      /* notifiers */
 +      DEG_id_tag_update(&gpd_dst->id, OB_RECALC_OB | OB_RECALC_DATA | DEG_TAG_COPY_ON_WRITE);
 +      DEG_id_tag_update(&ob_dst->id, DEG_TAG_COPY_ON_WRITE);
 +      WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
 +
 +      return OPERATOR_FINISHED;
 +}
 +
 +void GPENCIL_OT_layer_duplicate_object(wmOperatorType *ot)
 +{
 +      static const EnumPropertyItem copy_mode[] = {
 +              {GP_LAYER_COPY_OBJECT_ALL_FRAME, "ALL", 0, "All Frames", ""},
 +              {GP_LAYER_COPY_OBJECT_ACT_FRAME, "ACTIVE", 0, "Active Frame", ""},
 +              {0, NULL, 0, NULL, NULL}
 +      };
 +
 +      /* identifiers */
 +      ot->name = "Duplicate Layer to new Object";
 +      ot->idname = "GPENCIL_OT_layer_duplicate_object";
 +      ot->description = "Make a copy of the active Grease Pencil layer to new object";
 +
 +      /* callbacks */
 +      ot->exec = gp_layer_duplicate_object_exec;
 +      ot->poll = gp_layer_duplicate_object_poll;
 +
 +      /* flags */
 +      ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 +
 +      ot->prop = RNA_def_string(ot->srna, "object", NULL, MAX_ID_NAME - 2, "Object", "Name of the destination object");
 +      RNA_def_property_flag(ot->prop, PROP_HIDDEN | PROP_SKIP_SAVE);
 +
 +      RNA_def_enum(ot->srna, "mode", copy_mode, GP_LAYER_COPY_OBJECT_ALL_FRAME, "Mode", "");
 +}
 +
 +/* ********************* Duplicate Frame ************************** */
 +enum {
 +      GP_FRAME_DUP_ACTIVE = 0,
 +      GP_FRAME_DUP_ALL = 1
 +};
 +
 +static int gp_frame_duplicate_exec(bContext *C, wmOperator *op)
 +{
 +      bGPdata *gpd = ED_gpencil_data_get_active(C);
 +      bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
 +      Depsgraph *depsgraph = CTX_data_depsgraph(C);
 +      int cfra_eval = (int)DEG_get_ctime(depsgraph);
 +
 +      int mode = RNA_enum_get(op->ptr, "mode");
 +
 +      /* sanity checks */
 +      if (ELEM(NULL, gpd, gpl))
 +              return OPERATOR_CANCELLED;
 +
 +      if (mode == 0) {
 +              BKE_gpencil_frame_addcopy(gpl, cfra_eval);
 +      }
 +      else {
 +              for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
 +                      if ((gpl->flag & GP_LAYER_LOCKED) == 0) {
 +                              BKE_gpencil_frame_addcopy(gpl, cfra_eval);
 +                      }
 +              }
 +
 +      }
 +      /* notifiers */
 +      DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
 +      WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
 +
 +      return OPERATOR_FINISHED;
 +}
 +
 +void GPENCIL_OT_frame_duplicate(wmOperatorType *ot)
 +{
 +      static const EnumPropertyItem duplicate_mode[] = {
 +              { GP_FRAME_DUP_ACTIVE, "ACTIVE", 0, "Active", "Duplicate frame in active layer only" },
 +              { GP_FRAME_DUP_ALL, "ALL", 0, "All", "Duplicate active frames in all layers" },
 +              { 0, NULL, 0, NULL, NULL }
 +      };
 +
 +      /* identifiers */
 +      ot->name = "Duplicate Frame";
 +      ot->idname = "GPENCIL_OT_frame_duplicate";
 +      ot->description = "Make a copy of the active Grease Pencil Frame";
 +
 +      /* callbacks */
 +      ot->exec = gp_frame_duplicate_exec;
 +      ot->poll = gp_active_layer_poll;
 +
 +      /* flags */
 +      ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 +
 +      ot->prop = RNA_def_enum(ot->srna, "mode", duplicate_mode, GP_FRAME_DUP_ACTIVE, "Mode", "");
 +}
 +
 +/* ********************* Clean Fill Boundaries on Frame ************************** */
 +enum {
 +      GP_FRAME_CLEAN_FILL_ACTIVE = 0,
 +      GP_FRAME_CLEAN_FILL_ALL = 1
 +};
 +
 +static int gp_frame_clean_fill_exec(bContext *C, wmOperator *op)
 +{
 +      bool changed = false;
 +      bGPdata *gpd = ED_gpencil_data_get_active(C);
 +      int mode = RNA_enum_get(op->ptr, "mode");
 +
 +      CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
 +      {
 +              bGPDframe *init_gpf = gpl->actframe;
 +              if (mode == GP_FRAME_CLEAN_FILL_ALL) {
 +                      init_gpf = gpl->frames.first;
 +              }
 +
 +              for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
 +                      if ((gpf == gpl->actframe) || (mode == GP_FRAME_CLEAN_FILL_ALL)) {
 +                              bGPDstroke *gps, *gpsn;
 +
 +                              if (gpf == NULL)
 +                                      continue;
 +
 +                              /* simply delete strokes which are no fill */
 +                              for (gps = gpf->strokes.first; gps; gps = gpsn) {
 +                                      gpsn = gps->next;
 +
 +                                      /* skip strokes that are invalid for current view */
 +                                      if (ED_gpencil_stroke_can_use(C, gps) == false)
 +                                              continue;
 +
 +                                      /* free stroke */
 +                                      if (gps->flag & GP_STROKE_NOFILL) {
 +                                              /* free stroke memory arrays, then stroke itself */
 +                                              if (gps->points) {
 +                                                      MEM_freeN(gps->points);
 +                                              }
 +                                              if (gps->dvert) {
 +                                                      BKE_gpencil_free_stroke_weights(gps);
 +                                                      MEM_freeN(gps->dvert);
 +                                              }
 +                                              MEM_SAFE_FREE(gps->triangles);
 +                                              BLI_freelinkN(&gpf->strokes, gps);
 +
 +                                              changed = true;
 +                                      }
 +                              }
 +                      }
 +              }
 +      }
 +      CTX_DATA_END;
 +
 +      /* notifiers */
 +      if (changed) {
 +              DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
 +              WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
 +      }
 +
 +      return OPERATOR_FINISHED;
 +}
 +
 +void GPENCIL_OT_frame_clean_fill(wmOperatorType *ot)
 +{
 +      static const EnumPropertyItem duplicate_mode[] = {
++              {GP_FRAME_CLEAN_FILL_ACTIVE, "ACTIVE", 0, "Active Frame Only", "Clean active frame only"},
++              {GP_FRAME_CLEAN_FILL_ALL, "ALL", 0, "All Frames", "Clean all frames in all layers"},
++              {0, NULL, 0, NULL, NULL}
 +      };
 +
 +      /* identifiers */
 +      ot->name = "Clean Fill Boundaries";
 +      ot->idname = "GPENCIL_OT_frame_clean_fill";
 +      ot->description = "Remove 'no fill' boundary strokes";
 +
 +      /* callbacks */
 +      ot->exec = gp_frame_clean_fill_exec;
 +      ot->poll = gp_active_layer_poll;
 +
 +      /* flags */
 +      ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 +
 +      ot->prop = RNA_def_enum(ot->srna, "mode", duplicate_mode, GP_FRAME_DUP_ACTIVE, "Mode", "");
 +}
 +
 +/* ********************* Clean Loose Boundaries on Frame ************************** */
 +static int gp_frame_clean_loose_exec(bContext *C, wmOperator *op)
 +{
 +      bool changed = false;
 +      bGPdata *gpd = ED_gpencil_data_get_active(C);
 +      int limit = RNA_int_get(op->ptr, "limit");
 +      bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
 +
 +      CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
 +      {
 +              bGPDframe *init_gpf = gpl->actframe;
 +              bGPDstroke *gps = NULL;
 +              bGPDstroke *gpsn = NULL;
 +              if (is_multiedit) {
 +                      init_gpf = gpl->frames.first;
 +              }
 +
 +              for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
 +                      if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
 +                              if (gpf == NULL)
 +                                      continue;
 +
 +                              if (gpf == NULL)
 +                                      continue;
 +
 +                              /* simply delete strokes which are no loose */
 +                              for (gps = gpf->strokes.first; gps; gps = gpsn) {
 +                                      gpsn = gps->next;
 +
 +                                      /* skip strokes that are invalid for current view */
 +                                      if (ED_gpencil_stroke_can_use(C, gps) == false)
 +                                              continue;
 +
 +                                      /* free stroke */
 +                                      if (gps->totpoints <= limit) {
 +                                              /* free stroke memory arrays, then stroke itself */
 +                                              if (gps->points) {
 +                                                      MEM_freeN(gps->points);
 +                                              }
 +                                              if (gps->dvert) {
 +                                                      BKE_gpencil_free_stroke_weights(gps);
 +                                                      MEM_freeN(gps->dvert);
 +                                              }
 +                                              MEM_SAFE_FREE(gps->triangles);
 +                                              BLI_freelinkN(&gpf->strokes, gps);
 +
 +                                              changed = true;
 +                                      }
 +                              }
 +                      }
 +
 +                      /* if not multiedit, exit loop*/
 +                      if (!is_multiedit) {
 +                              break;
 +                      }
 +              }
 +      }
 +      CTX_DATA_END;
 +
 +      /* notifiers */
 +      if (changed) {
 +              DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
 +              WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
 +      }
 +
 +      return OPERATOR_FINISHED;
 +}
 +
 +void GPENCIL_OT_frame_clean_loose(wmOperatorType *ot)
 +{
 +      /* identifiers */
 +      ot->name = "Clean Loose points";
 +      ot->idname = "GPENCIL_OT_frame_clean_loose";
 +      ot->description = "Remove loose points";
 +
 +      /* callbacks */
 +      ot->exec = gp_frame_clean_loose_exec;
 +      ot->poll = gp_active_layer_poll;
 +
 +      /* flags */
 +      ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 +
 +      RNA_def_int(ot->srna, "limit", 1, 1, INT_MAX, "Limit", "Number of points to consider stroke as loose", 1, INT_MAX);
 +}
 +
  /* *********************** Hide Layers ******************************** */
  
  static int gp_hide_exec(bContext *C, wmOperator *op)
index df786b4e6755f479c901a7389da04cf7a952f124,936cf571b4ad1bd6e1814548f5f11a13e5cd26a7..3b2404415a7020a7b17c6b33a793d9b62f7b560c
@@@ -3044,414 -2334,3 +3044,414 @@@ void GPENCIL_OT_stroke_subdivide(wmOper
        RNA_def_property_flag(prop, PROP_SKIP_SAVE);
  
  }
-       {GP_SEPARATE_POINT, "POINT", 0, "Selected Points", "Separate the selected points" },
-       {GP_SEPARATE_STROKE, "STROKE", 0, "Selected Strokes", "Separate the selected strokes"},
-       {GP_SEPARATE_LAYER, "LAYER", 0, "Active Layer", "Separate the strokes of the current layer" },
-       { 0, NULL, 0, NULL, NULL }
 +
 +/* ** simplify stroke *** */
 +static int gp_stroke_simplify_exec(bContext *C, wmOperator *op)
 +{
 +      bGPdata *gpd = ED_gpencil_data_get_active(C);
 +      float factor = RNA_float_get(op->ptr, "factor");
 +
 +      /* sanity checks */
 +      if (ELEM(NULL, gpd))
 +              return OPERATOR_CANCELLED;
 +
 +      /* Go through each editable + selected stroke */
 +      GP_EDITABLE_STROKES_BEGIN(C, gpl, gps)
 +      {
 +              if (gps->flag & GP_STROKE_SELECT) {
 +                      /* simplify stroke using Ramer-Douglas-Peucker algorithm */
 +                      BKE_gpencil_simplify_stroke(gps, factor);
 +              }
 +      }
 +      GP_EDITABLE_STROKES_END;
 +
 +      /* notifiers */
 +      DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
 +      WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
 +
 +      return OPERATOR_FINISHED;
 +}
 +
 +void GPENCIL_OT_stroke_simplify(wmOperatorType *ot)
 +{
 +      PropertyRNA *prop;
 +
 +      /* identifiers */
 +      ot->name = "Simplify Stroke";
 +      ot->idname = "GPENCIL_OT_stroke_simplify";
 +      ot->description = "Simplify selected stroked reducing number of points";
 +
 +      /* api callbacks */
 +      ot->exec = gp_stroke_simplify_exec;
 +      ot->poll = gp_active_layer_poll;
 +
 +      /* flags */
 +      ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 +
 +      /* properties */
 +      prop = RNA_def_float(ot->srna, "factor", 0.0f, 0.0f, 100.0f, "Factor", "", 0.0f, 100.0f);
 +      /* avoid re-using last var */
 +      RNA_def_property_flag(prop, PROP_SKIP_SAVE);
 +}
 +
 +/* ** simplify stroke using fixed algorith *** */
 +static int gp_stroke_simplify_fixed_exec(bContext *C, wmOperator *op)
 +{
 +      bGPdata *gpd = ED_gpencil_data_get_active(C);
 +      int steps = RNA_int_get(op->ptr, "step");
 +
 +      /* sanity checks */
 +      if (ELEM(NULL, gpd))
 +              return OPERATOR_CANCELLED;
 +
 +      /* Go through each editable + selected stroke */
 +      GP_EDITABLE_STROKES_BEGIN(C, gpl, gps)
 +      {
 +              if (gps->flag & GP_STROKE_SELECT) {
 +                      for (int i = 0; i < steps; i++) {
 +                              BKE_gpencil_simplify_fixed(gps);
 +                      }
 +              }
 +      }
 +      GP_EDITABLE_STROKES_END;
 +
 +      /* notifiers */
 +      DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
 +      WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
 +
 +      return OPERATOR_FINISHED;
 +}
 +
 +void GPENCIL_OT_stroke_simplify_fixed(wmOperatorType *ot)
 +{
 +      PropertyRNA *prop;
 +
 +      /* identifiers */
 +      ot->name = "Simplify Fixed Stroke";
 +      ot->idname = "GPENCIL_OT_stroke_simplify_fixed";
 +      ot->description = "Simplify selected stroked reducing number of points using fixed algorithm";
 +
 +      /* api callbacks */
 +      ot->exec = gp_stroke_simplify_fixed_exec;
 +      ot->poll = gp_active_layer_poll;
 +
 +      /* flags */
 +      ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 +
 +      /* properties */
 +      prop = RNA_def_int(ot->srna, "step", 1, 1, 100, "Steps", "Number of simplify steps", 1, 10);
 +
 +      /* avoid re-using last var */
 +      RNA_def_property_flag(prop, PROP_SKIP_SAVE);
 +
 +}
 +
 +/* ***************** Separate Strokes ********************** */
 +typedef enum eGP_SeparateModes {
 +      /* Points */
 +      GP_SEPARATE_POINT = 0,
 +      /* Selected Strokes */
 +      GP_SEPARATE_STROKE,
 +      /* Current Layer */
 +      GP_SEPARATE_LAYER,
 +} eGP_SeparateModes;
 +
 +static int gp_stroke_separate_exec(bContext *C, wmOperator *op)
 +{
 +      Base *base_new;
 +      Main *bmain = CTX_data_main(C);
 +      Scene *scene = CTX_data_scene(C);
 +      ViewLayer *view_layer = CTX_data_view_layer(C);
 +      Base *base_old = CTX_data_active_base(C);
 +      bGPdata *gpd_src = ED_gpencil_data_get_active(C);
 +      Object *ob = CTX_data_active_object(C);
 +
 +      Object *ob_dst = NULL;
 +      bGPdata *gpd_dst = NULL;
 +      bGPDlayer *gpl_dst = NULL;
 +      bGPDframe *gpf_dst = NULL;
 +      bGPDspoint *pt;
 +      Material *ma = NULL;
 +      int i, idx;
 +
 +      eGP_SeparateModes mode = RNA_enum_get(op->ptr, "mode");
 +
 +      /* sanity checks */
 +      if (ELEM(NULL, gpd_src)) {
 +              return OPERATOR_CANCELLED;
 +      }
 +      bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd_src);
 +
 +      /* create a new object */
 +      base_new = ED_object_add_duplicate(bmain, scene, view_layer, base_old, 0);
 +      ob_dst = base_new->object;
 +
 +      /* create new grease pencil datablock */
 +      // XXX: check usercounts
 +      gpd_dst = BKE_gpencil_data_addnew(bmain, "GPencil");
 +      ob_dst->data = (bGPdata *)gpd_dst;
 +
 +      int totslots = ob_dst->totcol;
 +      int totadd = 0;
 +
 +      /* loop old datablock and separate parts */
 +      if ((mode == GP_SEPARATE_POINT) || (mode == GP_SEPARATE_STROKE)) {
 +              CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
 +              {
 +                      gpl_dst = NULL;
 +                      bGPDframe *init_gpf = gpl->actframe;
 +                      if (is_multiedit) {
 +                              init_gpf = gpl->frames.first;
 +                      }
 +
 +                      for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
 +                              if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
 +                                      bGPDstroke *gps, *gpsn;
 +
 +                                      if (gpf == NULL) {
 +                                              continue;
 +                                      }
 +
 +                                      gpf_dst = NULL;
 +
 +                                      for (gps = gpf->strokes.first; gps; gps = gpsn) {
 +                                              gpsn = gps->next;
 +
 +                                              /* skip strokes that are invalid for current view */
 +                                              if (ED_gpencil_stroke_can_use(C, gps) == false) {
 +                                                      continue;
 +                                              }
 +                                              /* check if the color is editable */
 +                                              if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false) {
 +                                                      continue;
 +                                              }
 +                                              /*  separate selected strokes */
 +                                              if (gps->flag & GP_STROKE_SELECT) {
 +                                                      /* add layer if not created before */
 +                                                      if (gpl_dst == NULL) {
 +                                                              gpl_dst = BKE_gpencil_layer_addnew(gpd_dst, gpl->info, false);
 +                                                      }
 +
 +                                                      /* add frame if not created before */
 +                                                      if (gpf_dst == NULL) {
 +                                                              gpf_dst = BKE_gpencil_layer_getframe(gpl_dst, gpf->framenum, GP_GETFRAME_ADD_NEW);
 +                                                      }
 +
 +                                                      /* add duplicate materials */
 +                                                      ma = give_current_material(ob, gps->mat_nr + 1);
 +                                                      idx = BKE_gpencil_get_material_index(ob_dst, ma);
 +                                                      if (idx == 0) {
 +
 +                                                              totadd++;
 +                                                              ob_dst->actcol = totadd;
 +                                                              ob_dst->totcol = totadd;
 +
 +                                                              if (totadd > totslots) {
 +                                                                      BKE_object_material_slot_add(bmain, ob_dst);
 +                                                              }
 +
 +                                                              assign_material(bmain, ob_dst, ma, ob_dst->totcol, BKE_MAT_ASSIGN_USERPREF);
 +                                                              idx = totadd;
 +                                                      }
 +
 +                                                      /* selected points mode */
 +                                                      if (mode == GP_SEPARATE_POINT) {
 +                                                              /* make copy of source stroke */
 +                                                              bGPDstroke *gps_dst = BKE_gpencil_stroke_duplicate(gps);
 +
 +                                                              /* reasign material */
 +                                                              gps_dst->mat_nr = idx - 1;
 +
 +                                                              /* link to destination frame */
 +                                                              BLI_addtail(&gpf_dst->strokes, gps_dst);
 +
 +                                                              /* Invert selection status of all points in destination stroke */
 +                                                              for (i = 0, pt = gps_dst->points; i < gps_dst->totpoints; i++, pt++) {
 +                                                                      pt->flag ^= GP_SPOINT_SELECT;
 +                                                              }
 +
 +                                                              /* delete selected points from destination stroke */
 +                                                              gp_stroke_delete_tagged_points(gpf_dst, gps_dst, NULL, GP_SPOINT_SELECT, false);
 +
 +                                                              /* delete selected points from origin stroke */
 +                                                              gp_stroke_delete_tagged_points(gpf, gps, gpsn, GP_SPOINT_SELECT, false);
 +                                                      }
 +                                                      /* selected strokes mode */
 +                                                      else if (mode == GP_SEPARATE_STROKE) {
 +                                                              /* deselect old stroke */
 +                                                              gps->flag &= ~GP_STROKE_SELECT;
 +                                                              /* unlink from source frame */
 +                                                              BLI_remlink(&gpf->strokes, gps);
 +                                                              gps->prev = gps->next = NULL;
 +                                                              /* relink to destination frame */
 +                                                              BLI_addtail(&gpf_dst->strokes, gps);
 +                                                              /* reasign material */
 +                                                              gps->mat_nr = idx - 1;
 +                                                      }
 +                                              }
 +                                      }
 +                              }
 +
 +                              /* if not multiedit, exit loop*/
 +                              if (!is_multiedit) {
 +                                      break;
 +                              }
 +                      }
 +              }
 +              CTX_DATA_END;
 +      }
 +      else if (mode == GP_SEPARATE_LAYER) {
 +              bGPDlayer *gpl = CTX_data_active_gpencil_layer(C);
 +              if (gpl) {
 +                      /* try to set a new active layer in source datablock */
 +                      if (gpl->prev) {
 +                              BKE_gpencil_layer_setactive(gpd_src, gpl->prev);
 +                      }
 +                      else if (gpl->next) {
 +                              BKE_gpencil_layer_setactive(gpd_src, gpl->next);
 +                      }
 +                      /* unlink from source datablock */
 +                      BLI_remlink(&gpd_src->layers, gpl);
 +                      gpl->prev = gpl->next = NULL;
 +                      /* relink to destination datablock */
 +                      BLI_addtail(&gpd_dst->layers, gpl);
 +              }
 +      }
 +      DEG_id_tag_update(&gpd_src->id, OB_RECALC_OB | OB_RECALC_DATA);
 +      DEG_id_tag_update(&gpd_dst->id, OB_RECALC_OB | OB_RECALC_DATA);
 +
 +      DEG_relations_tag_update(bmain);
 +      WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, NULL);
 +      WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
 +
 +      return OPERATOR_FINISHED;
 +}
 +
 +void GPENCIL_OT_stroke_separate(wmOperatorType *ot)
 +{
 +      static const EnumPropertyItem separate_type[] = {
++              {GP_SEPARATE_POINT, "POINT", 0, "Selected Points", "Separate the selected points"},
++              {GP_SEPARATE_STROKE, "STROKE", 0, "Selected Strokes", "Separate the selected strokes"},
++              {GP_SEPARATE_LAYER, "LAYER", 0, "Active Layer", "Separate the strokes of the current layer"},
++              {0, NULL, 0, NULL, NULL}
 +      };
 +
 +      /* identifiers */
 +      ot->name = "Separate Strokes";
 +      ot->idname = "GPENCIL_OT_stroke_separate";
 +      ot->description = "Separate the selected strokes or layer in a new grease pencil object";
 +
 +      /* callbacks */
 +      ot->invoke = WM_menu_invoke;
 +      ot->exec = gp_stroke_separate_exec;
 +      ot->poll = gp_strokes_edit3d_poll;
 +
 +      /* flags */
 +      ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 +
 +      /* properties */
 +      ot->prop = RNA_def_enum(ot->srna, "mode", separate_type, GP_SEPARATE_POINT, "Mode", "");
 +}
 +
 +/* ***************** Split Strokes ********************** */
 +static int gp_stroke_split_exec(bContext *C, wmOperator *UNUSED(op))
 +{
 +      Object *ob = CTX_data_active_object(C);
 +      bGPdata *gpd = ED_gpencil_data_get_active(C);
 +      bGPDspoint *pt;
 +      int i;
 +
 +      /* sanity checks */
 +      if (ELEM(NULL, gpd)) {
 +              return OPERATOR_CANCELLED;
 +      }
 +      bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
 +
 +      /* loop strokes and split parts */
 +      CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
 +      {
 +              bGPDframe *init_gpf = gpl->actframe;
 +              if (is_multiedit) {
 +                      init_gpf = gpl->frames.first;
 +              }
 +
 +              for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
 +                      if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
 +                              bGPDstroke *gps, *gpsn;
 +
 +                              if (gpf == NULL) {
 +                                      continue;
 +                              }
 +
 +                              for (gps = gpf->strokes.first; gps; gps = gpsn) {
 +                                      gpsn = gps->next;
 +
 +                                      /* skip strokes that are invalid for current view */
 +                                      if (ED_gpencil_stroke_can_use(C, gps) == false) {
 +                                              continue;
 +                                      }
 +                                      /* check if the color is editable */
 +                                      if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false) {
 +                                              continue;
 +                                      }
 +                                      /*  split selected strokes */
 +                                      if (gps->flag & GP_STROKE_SELECT) {
 +                                              /* make copy of source stroke */
 +                                              bGPDstroke *gps_dst = BKE_gpencil_stroke_duplicate(gps);
 +
 +                                              /* link to same frame */
 +                                              BLI_addtail(&gpf->strokes, gps_dst);
 +
 +                                              /* invert selection status of all points in destination stroke */
 +                                              for (i = 0, pt = gps_dst->points; i < gps_dst->totpoints; i++, pt++) {
 +                                                      pt->flag ^= GP_SPOINT_SELECT;
 +                                              }
 +
 +                                              /* delete selected points from destination stroke */
 +                                              gp_stroke_delete_tagged_points(gpf, gps_dst, NULL, GP_SPOINT_SELECT, true);
 +
 +                                              /* delete selected points from origin stroke */
 +                                              gp_stroke_delete_tagged_points(gpf, gps, gpsn, GP_SPOINT_SELECT, false);
 +                                      }
 +                              }
 +                              /* select again tagged points */
 +                              for (gps = gpf->strokes.first; gps; gps = gps->next) {
 +                                      bGPDspoint *ptn = gps->points;
 +                                      for (int i2 = 0; i2 < gps->totpoints; i2++, ptn++) {
 +                                              if (ptn->flag & GP_SPOINT_TAG) {
 +                                                      ptn->flag |= GP_SPOINT_SELECT;
 +                                                      ptn->flag &= ~GP_SPOINT_TAG;
 +                                              }
 +                                      }
 +                              }
 +                      }
 +
 +                      /* if not multiedit, exit loop*/
 +                      if (!is_multiedit) {
 +                              break;
 +                      }
 +              }
 +      }
 +      CTX_DATA_END;
 +
 +      DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
 +
 +      WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
 +
 +      return OPERATOR_FINISHED;
 +}
 +
 +void GPENCIL_OT_stroke_split(wmOperatorType *ot)
 +{
 +      /* identifiers */
 +      ot->name = "Split Strokes";
 +      ot->idname = "GPENCIL_OT_stroke_split";
 +      ot->description = "Split selected points as new stroke on same frame";
 +
 +      /* callbacks */
 +      ot->exec = gp_stroke_split_exec;
 +      ot->poll = gp_strokes_edit3d_poll;
 +
 +      /* flags */
 +      ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 +}
index f73cdc30292c0f8ecf364949008f5468507cc4ab,a03892a26d1401c8f08b1164b90995f886ed0736..9c7c9fde0661dd8d5bc09bb0d13395e14ae7091c
@@@ -3693,115 -3460,11 +3693,116 @@@ static int particle_intersect_mesh(Deps
        return intersect;
  }
  
 -static int brush_add(PEData *data, short number)
 +typedef struct BrushAddCountIterData {
 +      Depsgraph *depsgraph;
 +      Scene *scene;
 +      Object *object;
 +      Mesh *mesh;
 +      PEData *data;
 +      int number;
 +      short size;
 +      float imat[4][4];
 +      ParticleData *add_pars;
 +      int num_added;
 +} BrushAddCountIterData;
 +
 +typedef struct BrushAddCountIterTLSData {
 +      RNG *rng;
 +      int num_added;
 +} BrushAddCountIterTLSData;
 +
 +static void brush_add_count_iter(
 +        void *__restrict iter_data_v,
 +        const int iter,
 +        const ParallelRangeTLS *__restrict tls_v)
  {
-                                   0, 0, 0, 0)) {
 +      BrushAddCountIterData *iter_data = (BrushAddCountIterData *)iter_data_v;
 +      Depsgraph *depsgraph = iter_data->depsgraph;
 +      PEData *data = iter_data->data;
 +      PTCacheEdit *edit = data->edit;
 +      ParticleSystem *psys = edit->psys;
 +      ParticleSystemModifierData *psmd_eval = edit->psmd_eval;
 +      ParticleData *add_pars = iter_data->add_pars;
 +      BrushAddCountIterTLSData *tls = tls_v->userdata_chunk;
 +      const int number = iter_data->number;
 +      const short size = iter_data->size;
 +      const short size2 = size * size;
 +      float dmx, dmy;
 +      if (number > 1) {
 +              dmx = size;
 +              dmy = size;
 +              if (tls->rng == NULL) {
 +                      tls->rng = BLI_rng_new_srandom(
 +                              psys->seed + data->mval[0] + data->mval[1] + tls_v->thread_id);
 +              }
 +              /* rejection sampling to get points in circle */
 +              while (dmx * dmx + dmy * dmy > size2) {
 +                      dmx = (2.0f * BLI_rng_get_float(tls->rng) - 1.0f) * size;
 +                      dmy = (2.0f * BLI_rng_get_float(tls->rng) - 1.0f) * size;
 +              }
 +      }
 +      else {
 +              dmx = 0.0f;
 +              dmy = 0.0f;
 +      }
 +
 +      float mco[2];
 +      mco[0] = data->mval[0] + dmx;
 +      mco[1] = data->mval[1] + dmy;
 +
 +      float co1[3], co2[3];
 +      ED_view3d_win_to_segment(depsgraph, data->vc.ar, data->vc.v3d, mco, co1, co2, true);
 +
 +      mul_m4_v3(iter_data->imat, co1);
 +      mul_m4_v3(iter_data->imat, co2);
 +      float min_d = 2.0;
 +
 +      /* warning, returns the derived mesh face */
 +      BLI_assert(iter_data->mesh != NULL);
 +      if (particle_intersect_mesh(depsgraph, iter_data->scene, iter_data->object, iter_data->mesh,
 +                                  0, co1, co2,
 +                                  &min_d,
 +                                  &add_pars[iter].num_dmcache,
 +                                  add_pars[iter].fuv,
++                                  0, 0, 0, 0))
++      {
 +              if (psys->part->use_modifier_stack && !psmd_eval->mesh_final->runtime.deformed_only) {
 +                      add_pars[iter].num = add_pars[iter].num_dmcache;
 +                      add_pars[iter].num_dmcache = DMCACHE_ISCHILD;
 +              }
 +              else if (iter_data->mesh == psmd_eval->mesh_original) {
 +                      /* Final DM is not same topology as orig mesh, we have to map num_dmcache to real final dm. */
 +                      add_pars[iter].num = add_pars[iter].num_dmcache;
 +                      add_pars[iter].num_dmcache = psys_particle_dm_face_lookup(
 +                              psmd_eval->mesh_final, psmd_eval->mesh_original,
 +                              add_pars[iter].num, add_pars[iter].fuv, NULL);
 +              }
 +              else {
 +                      add_pars[iter].num = add_pars[iter].num_dmcache;
 +              }
 +              if (add_pars[iter].num != DMCACHE_NOTFOUND) {
 +                      tls->num_added++;
 +              }
 +      }
 +}
 +
 +static void brush_add_count_iter_finalize(void *__restrict userdata_v,
 +                                          void *__restrict userdata_chunk_v)
 +{
 +      BrushAddCountIterData *iter_data = (BrushAddCountIterData *)userdata_v;
 +      BrushAddCountIterTLSData *tls = (BrushAddCountIterTLSData *)userdata_chunk_v;
 +      iter_data->num_added += tls->num_added;
 +      if (tls->rng != NULL) {
 +              BLI_rng_free(tls->rng);
 +      }
 +}
 +
 +static int brush_add(const bContext *C, PEData *data, short number)
 +{
 +      Depsgraph *depsgraph = CTX_data_depsgraph(C);
        Scene *scene = data->scene;
        Object *ob = data->ob;
 -      DerivedMesh *dm;
 +      Mesh *mesh;
        PTCacheEdit *edit = data->edit;
        ParticleSystem *psys = edit->psys;
        ParticleData *add_pars;
@@@ -4642,32 -4298,11 +4643,33 @@@ int PE_minmax(Scene *scene, ViewLayer *
  
  /************************ particle edit toggle operator ************************/
  
-         ParticleSystem *psys){
 +static struct ParticleSystem *psys_eval_get(
 +        Depsgraph *depsgraph,
 +        Object *object,
++        ParticleSystem *psys)
++{
 +      Object *object_eval = DEG_get_evaluated_object(depsgraph, object);
 +      if (object_eval == object) {
 +              return psys;
 +      }
 +      ParticleSystem *psys_eval = object_eval->particlesystem.first;
 +      while (psys_eval != NULL) {
 +              if (psys_eval->orig_psys == psys) {
 +                      return psys_eval;
 +              }
 +              psys_eval = psys_eval->next;
 +      }
 +      return psys_eval;
 +}
 +
  /* initialize needed data for bake edit */
 -void PE_create_particle_edit(Main *bmain, Scene *scene, Object *ob, PointCache *cache, ParticleSystem *psys)
 +void PE_create_particle_edit(
 +        Depsgraph *depsgraph, Scene *scene, Object *ob, PointCache *cache, ParticleSystem *psys)
  {
 +      Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
        PTCacheEdit *edit;
        ParticleSystemModifierData *psmd = (psys) ? psys_get_modifier(ob, psys) : NULL;
 +      ParticleSystemModifierData *psmd_eval = NULL;
        POINT_P; KEY_K;
        ParticleData *pa = NULL;
        HairKey *hkey;
index a21b3aa7387e7e037b64a67893102af7c16bee49,9c3ff8999b7c8c5a843775b4d956b7cd135159e8..07776bfc1b7d142eca8008ad6bde51fe23572eb8
@@@ -193,22 -176,20 +193,22 @@@ BlenderStrokeRenderer::~BlenderStrokeRe
                }
  #endif
                switch (ob->type) {
-               case OB_MESH:
-                       BKE_libblock_free(freestyle_bmain, ob);
-                       BKE_libblock_free(freestyle_bmain, data);
-                       break;
-               case OB_CAMERA:
-                       BKE_libblock_free(freestyle_bmain, ob);
-                       BKE_libblock_free(freestyle_bmain, data);
-                       freestyle_scene->camera = NULL;
-                       break;
-               default:
-                       cerr << "Warning: unexpected object in the scene: " << name[0] << name[1] << ":" << (name + 2) << endl;
+                       case OB_MESH:
+                               BKE_libblock_free(freestyle_bmain, ob);
+                               BKE_libblock_free(freestyle_bmain, data);
+                               break;
+                       case OB_CAMERA:
+                               BKE_libblock_free(freestyle_bmain, ob);
+                               BKE_libblock_free(freestyle_bmain, data);
+                               freestyle_scene->camera = NULL;
+                               break;
+                       default:
+                               cerr << "Warning: unexpected object in the scene: " << name[0] << name[1] << ":" << (name + 2) << endl;
                }
        }
 -      BLI_freelistN(&freestyle_scene->base);
 +
 +      // Make sure we don't have any bases which might reference freed objects.
 +      BKE_main_collection_sync(freestyle_bmain);
  
        // release materials
        Link *lnk = (Link *)freestyle_bmain->mat.first;
index 858f6771a456b14fda9a3994ed1497747467a6a2,6e65b021805a68d926470ca50b92c085add33c4c..21b4411fe7981c2b77e77620a7792d2914517966
@@@ -303,115 -303,115 +303,158 @@@ static void prepare(Render *re, ViewLay
        int layer_count = 0;
  
        switch (config->mode) {
-       case FREESTYLE_CONTROL_SCRIPT_MODE:
-               if (G.debug & G_DEBUG_FREESTYLE) {
-                       cout << "Modules :" << endl;
-               }
-               for (FreestyleModuleConfig *module_conf = (FreestyleModuleConfig *)config->modules.first;
-                    module_conf;
-                    module_conf = module_conf->next)
-               {
-                       if (module_conf->script && module_conf->is_displayed) {
-                               const char *id_name = module_conf->script->id.name + 2;
-                               if (G.debug & G_DEBUG_FREESTYLE) {
-                                       cout << "  " << layer_count + 1 << ": " << id_name;
-                                       if (module_conf->script->name)
-                                               cout << " (" << module_conf->script->name << ")";
-                                       cout << endl;
-                               }
-                               controller->InsertStyleModule(layer_count, id_name, module_conf->script);
-                               controller->toggleLayer(layer_count, true);
-                               layer_count++;
+               case FREESTYLE_CONTROL_SCRIPT_MODE:
+                       if (G.debug & G_DEBUG_FREESTYLE) {
+                               cout << "Modules :" << endl;
                        }
 -                      for (FreestyleModuleConfig *module_conf = (FreestyleModuleConfig *)config->modules.first;
 -                           module_conf;
 -                           module_conf = module_conf->next)
 -                      {
 -                              if (module_conf->script && module_conf->is_displayed) {
 -                                      const char *id_name = module_conf->script->id.name + 2;
 -                                      if (G.debug & G_DEBUG_FREESTYLE) {
 -                                              cout << "  " << layer_count + 1 << ": " << id_name;
 -                                              if (module_conf->script->name)
 -                                                      cout << " (" << module_conf->script->name << ")";
 -                                              cout << endl;
 +              }
 +              if (G.debug & G_DEBUG_FREESTYLE) {
 +                      cout << endl;
 +              }
 +              controller->setComputeRidgesAndValleysFlag((config->flags & FREESTYLE_RIDGES_AND_VALLEYS_FLAG) ? true : false);
 +              controller->setComputeSuggestiveContoursFlag((config->flags & FREESTYLE_SUGGESTIVE_CONTOURS_FLAG) ? true : false);
 +              controller->setComputeMaterialBoundariesFlag((config->flags & FREESTYLE_MATERIAL_BOUNDARIES_FLAG) ? true : false);
 +              break;
 +      case FREESTYLE_CONTROL_EDITOR_MODE:
 +              int use_ridges_and_valleys = 0;
 +              int use_suggestive_contours = 0;
 +              int use_material_boundaries = 0;
 +              struct edge_type_condition conditions[] = {
 +                      {FREESTYLE_FE_SILHOUETTE, 0},
 +                      {FREESTYLE_FE_BORDER, 0},
 +                      {FREESTYLE_FE_CREASE, 0},
 +                      {FREESTYLE_FE_RIDGE_VALLEY, 0},
 +                      {FREESTYLE_FE_SUGGESTIVE_CONTOUR, 0},
 +                      {FREESTYLE_FE_MATERIAL_BOUNDARY, 0},
 +                      {FREESTYLE_FE_CONTOUR, 0},
 +                      {FREESTYLE_FE_EXTERNAL_CONTOUR, 0},
 +                      {FREESTYLE_FE_EDGE_MARK, 0}
 +              };
 +              int num_edge_types = sizeof(conditions) / sizeof(struct edge_type_condition);
 +              if (G.debug & G_DEBUG_FREESTYLE) {
 +                      cout << "Linesets:" << endl;
 +              }
 +              for (FreestyleLineSet *lineset = (FreestyleLineSet *)config->linesets.first;
 +                   lineset;
 +                   lineset = lineset->next)
 +              {
 +                      if (lineset->flags & FREESTYLE_LINESET_ENABLED) {
 +                              if (G.debug & G_DEBUG_FREESTYLE) {
 +                                      cout << "  " << layer_count+1 << ": " << lineset->name << " - " <<
 +                                              (lineset->linestyle ? (lineset->linestyle->id.name + 2) : "<NULL>") << endl;
 +                              }
 +                              char *buffer = create_lineset_handler(view_layer->name, lineset->name);
 +                              controller->InsertStyleModule(layer_count, lineset->name, buffer);
 +                              controller->toggleLayer(layer_count, true);
 +                              MEM_freeN(buffer);
 +                              if (!(lineset->selection & FREESTYLE_SEL_EDGE_TYPES) || !lineset->edge_types) {
 +                                      ++use_ridges_and_valleys;
 +                                      ++use_suggestive_contours;
 +                                      ++use_material_boundaries;
 +                              }
 +                              else {
 +                                      // conditions for feature edge selection by edge types
 +                                      for (int i = 0; i < num_edge_types; i++) {
 +                                              if (!(lineset->edge_types & conditions[i].edge_type))
 +                                                      conditions[i].value = 0; // no condition specified
 +                                              else if (!(lineset->exclude_edge_types & conditions[i].edge_type))
 +                                                      conditions[i].value = 1; // condition: X
 +                                              else
 +                                                      conditions[i].value = -1; // condition: NOT X
                                        }
-                                       // logical operator for the selection conditions
-                                       bool logical_and = ((lineset->flags & FREESTYLE_LINESET_FE_AND) != 0);
-                                       // negation operator
-                                       if (lineset->flags & FREESTYLE_LINESET_FE_NOT) {
-                                               // convert an Exclusive condition into an Inclusive equivalent using De Morgan's laws:
-                                               //   NOT (X OR Y) --> (NOT X) AND (NOT Y)
-                                               //   NOT (X AND Y) --> (NOT X) OR (NOT Y)
-                                               for (int i = 0; i < num_edge_types; i++)
-                                                       conditions[i].value *= -1;
-                                               logical_and = !logical_and;
+                                       controller->InsertStyleModule(layer_count, id_name, module_conf->script);
+                                       controller->toggleLayer(layer_count, true);
+                                       layer_count++;
+                               }
+                       }
+                       if (G.debug & G_DEBUG_FREESTYLE) {
+                               cout << endl;
+                       }
+                       controller->setComputeRidgesAndValleysFlag((config->flags & FREESTYLE_RIDGES_AND_VALLEYS_FLAG) ? true : false);
+                       controller->setComputeSuggestiveContoursFlag((config->flags & FREESTYLE_SUGGESTIVE_CONTOURS_FLAG) ? true : false);
+                       controller->setComputeMaterialBoundariesFlag((config->flags & FREESTYLE_MATERIAL_BOUNDARIES_FLAG) ? true : false);
+                       break;
+               case FREESTYLE_CONTROL_EDITOR_MODE:
+                       int use_ridges_and_valleys = 0;
+                       int use_suggestive_contours = 0;
+                       int use_material_boundaries = 0;
+                       struct edge_type_condition conditions[] = {
+                               {FREESTYLE_FE_SILHOUETTE, 0},
+                               {FREESTYLE_FE_BORDER, 0},
+                               {FREESTYLE_FE_CREASE, 0},
+                               {FREESTYLE_FE_RIDGE_VALLEY, 0},
+                               {FREESTYLE_FE_SUGGESTIVE_CONTOUR, 0},
+                               {FREESTYLE_FE_MATERIAL_BOUNDARY, 0},
+                               {FREESTYLE_FE_CONTOUR, 0},
+                               {FREESTYLE_FE_EXTERNAL_CONTOUR, 0},
+                               {FREESTYLE_FE_EDGE_MARK, 0}
+                       };
+                       int num_edge_types = sizeof(conditions) / sizeof(struct edge_type_condition);
+                       if (G.debug & G_DEBUG_FREESTYLE) {
+                               cout << "Linesets:" << endl;
+                       }
+                       for (FreestyleLineSet *lineset = (FreestyleLineSet *)config->linesets.first;
+                            lineset;
+                            lineset = lineset->next)
+                       {
+                               if (lineset->flags & FREESTYLE_LINESET_ENABLED) {
+                                       if (G.debug & G_DEBUG_FREESTYLE) {
+                                               cout << "  " << layer_count+1 << ": " << lineset->name << " - " <<
+                                                       (lineset->linestyle ? (lineset->linestyle->id.name + 2) : "<NULL>") << endl;
                                        }
-                                       if (test_edge_type_conditions(conditions, num_edge_types, logical_and,
-                                                                     FREESTYLE_FE_RIDGE_VALLEY, true))
-                                       {
+                                       char *buffer = create_lineset_handler(srl->name, lineset->name);
+                                       controller->InsertStyleModule(layer_count, lineset->name, buffer);
+                                       controller->toggleLayer(layer_count, true);
+                                       MEM_freeN(buffer);
+                                       if (!(lineset->selection & FREESTYLE_SEL_EDGE_TYPES) || !lineset->edge_types) {
                                                ++use_ridges_and_valleys;
-                                       }
-                                       if (test_edge_type_conditions(conditions, num_edge_types, logical_and,
-                                                                     FREESTYLE_FE_SUGGESTIVE_CONTOUR, true))
-                                       {
                                                ++use_suggestive_contours;
-                                       }
-                                       if (test_edge_type_conditions(conditions, num_edge_types, logical_and,
-                                                                     FREESTYLE_FE_MATERIAL_BOUNDARY, true))
-                                       {
                                                ++use_material_boundaries;
                                        }
+                                       else {
+                                               // conditions for feature edge selection by edge types
+                                               for (int i = 0; i < num_edge_types; i++) {
+                                                       if (!(lineset->edge_types & conditions[i].edge_type))
+                                                               conditions[i].value = 0; // no condition specified
+                                                       else if (!(lineset->exclude_edge_types & conditions[i].edge_type))
+                                                               conditions[i].value = 1; // condition: X
+                                                       else
+                                                               conditions[i].value = -1; // condition: NOT X
+                                               }
+                                               // logical operator for the selection conditions
+                                               bool logical_and = ((lineset->flags & FREESTYLE_LINESET_FE_AND) != 0);
+                                               // negation operator
+                                               if (lineset->flags & FREESTYLE_LINESET_FE_NOT) {
+                                                       // convert an Exclusive condition into an Inclusive equivalent using De Morgan's laws:
+                                                       //   NOT (X OR Y) --> (NOT X) AND (NOT Y)
+                                                       //   NOT (X AND Y) --> (NOT X) OR (NOT Y)
+                                                       for (int i = 0; i < num_edge_types; i++)
+                                                               conditions[i].value *= -1;
+                                                       logical_and = !logical_and;
+                                               }
+                                               if (test_edge_type_conditions(conditions, num_edge_types, logical_and,
+                                                                             FREESTYLE_FE_RIDGE_VALLEY, true))
+                                               {
+                                                       ++use_ridges_and_valleys;
+                                               }
+                                               if (test_edge_type_conditions(conditions, num_edge_types, logical_and,
+                                                                             FREESTYLE_FE_SUGGESTIVE_CONTOUR, true))
+                                               {
+                                                       ++use_suggestive_contours;
+                                               }
+                                               if (test_edge_type_conditions(conditions, num_edge_types, logical_and,
+                                                                             FREESTYLE_FE_MATERIAL_BOUNDARY, true))
+                                               {
+                                                       ++use_material_boundaries;
+                                               }
+                                       }
+                                       layer_count++;
                                }
-                               layer_count++;
                        }
-               }
-               controller->setComputeRidgesAndValleysFlag(use_ridges_and_valleys > 0);
-               controller->setComputeSuggestiveContoursFlag(use_suggestive_contours > 0);
-               controller->setComputeMaterialBoundariesFlag(use_material_boundaries > 0);
-               break;
+                       controller->setComputeRidgesAndValleysFlag(use_ridges_and_valleys > 0);
+                       controller->setComputeSuggestiveContoursFlag(use_suggestive_contours > 0);
+                       controller->setComputeMaterialBoundariesFlag(use_material_boundaries > 0);
+                       break;
        }
  
        // set parameters
@@@ -540,25 -540,25 +583,25 @@@ static int displayed_layer_count(ViewLa
  {
        int count = 0;
  
 -      switch (srl->freestyleConfig.mode) {
 +      switch (view_layer->freestyle_config.mode) {
-       case FREESTYLE_CONTROL_SCRIPT_MODE:
-               for (FreestyleModuleConfig *module = (FreestyleModuleConfig *)view_layer->freestyle_config.modules.first;
-                    module;
-                    module = module->next)
-               {
-                       if (module->script && module->is_displayed)
-                               count++;
-               }
-               break;
-       case FREESTYLE_CONTROL_EDITOR_MODE:
-               for (FreestyleLineSet *lineset = (FreestyleLineSet *)view_layer->freestyle_config.linesets.first;
-                    lineset;
-                    lineset = lineset->next)
-               {
-                       if (lineset->flags & FREESTYLE_LINESET_ENABLED)
-                               count++;
-               }
-               break;
+               case FREESTYLE_CONTROL_SCRIPT_MODE:
 -                      for (FreestyleModuleConfig *module = (FreestyleModuleConfig *)srl->freestyleConfig.modules.first;
++                      for (FreestyleModuleConfig *module = (FreestyleModuleConfig *)view_layer->freestyle_config.modules.first;
+                            module;
+                            module = module->next)
+                       {
+                               if (module->script && module->is_displayed)
+                                       count++;
+                       }
+                       break;
+               case FREESTYLE_CONTROL_EDITOR_MODE:
 -                      for (FreestyleLineSet *lineset = (FreestyleLineSet *)srl->freestyleConfig.linesets.first;
++                      for (FreestyleLineSet *lineset = (FreestyleLineSet *)view_layer->freestyle_config.linesets.first;
+                            lineset;
+                            lineset = lineset->next)
+                       {
+                               if (lineset->flags & FREESTYLE_LINESET_ENABLED)
+                                       count++;
+                       }
+                       break;
        }
        return count;
  }
index 87a67cb0e79bc9b1bb50dde9084b26193034439d,bb204bf8c815e28b411cfa49dd8ff660e1f9a002..680ed346b5413216a49120000960d4b8e528b5fe
@@@ -954,322 -793,6 +954,322 @@@ static void rna_def_image_paint_capabil
  #undef IMAPAINT_TOOL_CAPABILITY
  }
  
-               { 1, "DRAW", 0, "Draw", "" },
-       { 0, NULL, 0, NULL, NULL }
 +static void rna_def_gpencil_options(BlenderRNA *brna)
 +{
 +      StructRNA *srna;
 +      PropertyRNA *prop;
 +
 +      /*  Grease Pencil Drawing - generated dynamically */
 +      static const EnumPropertyItem prop_dynamic_gpencil_type[] = {
++              {1, "DRAW", 0, "Draw", ""},
++              {0, NULL, 0, NULL, NULL}
 +      };
 +
 +      srna = RNA_def_struct(brna, "BrushGpencilSettings", NULL);
 +      RNA_def_struct_sdna(srna, "BrushGpencilSettings");
 +      RNA_def_struct_ui_text(srna, "Grease Pencil Brush Settings", "Settings for grease pencil brush");
 +
 +      /* grease pencil drawing brushes */
 +      prop = RNA_def_property(srna, "grease_pencil_tool", PROP_ENUM, PROP_NONE);
 +      RNA_def_property_enum_sdna(prop, NULL, "brush_type");
 +      RNA_def_property_enum_items(prop, prop_dynamic_gpencil_type);
 +      RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_DynamicGpencil_type_itemf");
 +      RNA_def_property_ui_text(prop, "Grease Pencil Tool", "");
 +      /* TODO: GPXX review update */
 +      RNA_def_property_update(prop, 0, NULL);
 +      //RNA_def_property_update(prop, 0, "rna_Brush_gpencil_tool_update");
 +
 +      /* Sensitivity factor for new strokes */
 +      prop = RNA_def_property(srna, "pen_sensitivity_factor", PROP_FLOAT, PROP_NONE);
 +      RNA_def_property_float_sdna(prop, NULL, "draw_sensitivity");
 +      RNA_def_property_range(prop, 0.1f, 3.0f);
 +      RNA_def_property_ui_text(prop, "Sensitivity", "Pressure sensitivity factor for new strokes");
 +      RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
 +      RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
 +
 +      /* Strength factor for new strokes */
 +      prop = RNA_def_property(srna, "pen_strength", PROP_FLOAT, PROP_NONE);
 +      RNA_def_property_float_sdna(prop, NULL, "draw_strength");
 +      RNA_def_property_range(prop, 0.0f, 1.0f);
 +      RNA_def_property_ui_text(prop, "Strength", "Color strength for new strokes (affect alpha factor of color)");
 +      RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
 +      RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
 +
 +      /* Jitter factor for new strokes */
 +      prop = RNA_def_property(srna, "pen_jitter", PROP_FLOAT, PROP_NONE);
 +      RNA_def_property_float_sdna(prop, NULL, "draw_jitter");
 +      RNA_def_property_range(prop, 0.0f, 1.0f);
 +      RNA_def_property_ui_text(prop, "Jitter", "Jitter factor for new strokes");
 +      RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
 +      RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
 +
 +      /* Randomnes factor for pressure */
 +      prop = RNA_def_property(srna, "random_pressure", PROP_FLOAT, PROP_NONE);
 +      RNA_def_property_float_sdna(prop, NULL, "draw_random_press");
 +      RNA_def_property_range(prop, 0.0f, 1.0f);
 +      RNA_def_property_ui_text(prop, "Pressure Randomness", "Randomness factor for pressure in new strokes");
 +      RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
 +      RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
 +
 +      /* Randomnes factor for strength */
 +      prop = RNA_def_property(srna, "random_strength", PROP_FLOAT, PROP_NONE);
 +      RNA_def_property_float_sdna(prop, NULL, "draw_random_strength");
 +      RNA_def_property_range(prop, 0.0f, 1.0f);
 +      RNA_def_property_ui_text(prop, "Strength Randomness", "Randomness factor strength in new strokes");
 +      RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
 +      RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
 +
 +      /* Randomnes factor for subdivision */
 +      prop = RNA_def_property(srna, "random_subdiv", PROP_FLOAT, PROP_NONE);
 +      RNA_def_property_float_sdna(prop, NULL, "draw_random_sub");
 +      RNA_def_property_range(prop, 0.0f, 1.0f);
 +      RNA_def_property_ui_text(prop, "Random Subdivision", "Randomness factor for new strokes after subdivision");
 +      RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
 +      RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
 +
 +      /* Angle when brush is full size */
 +      prop = RNA_def_property(srna, "angle", PROP_FLOAT, PROP_ANGLE);
 +      RNA_def_property_float_sdna(prop, NULL, "draw_angle");
 +      RNA_def_property_range(prop, -M_PI_2, M_PI_2);
 +      RNA_def_property_ui_text(prop, "Angle",
 +              "Direction of the stroke at which brush gives maximal thickness "
 +              "(0° for horizontal)");
 +      RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
 +      RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
 +
 +      /* Factor to change brush size depending of angle */
 +      prop = RNA_def_property(srna, "angle_factor", PROP_FLOAT, PROP_NONE);
 +      RNA_def_property_float_sdna(prop, NULL, "draw_angle_factor");
 +      RNA_def_property_range(prop, 0.0f, 1.0f);
 +      RNA_def_property_ui_text(prop, "Angle Factor",
 +              "Reduce brush thickness by this factor when stroke is perpendicular to 'Angle' direction");
 +      RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
 +      RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
 +
 +      /* Smoothing factor for new strokes */
 +      prop = RNA_def_property(srna, "pen_smooth_factor", PROP_FLOAT, PROP_NONE);
 +      RNA_def_property_float_sdna(prop, NULL, "draw_smoothfac");
 +      RNA_def_property_range(prop, 0.0, 2.0f);
 +      RNA_def_property_ui_text(prop, "Smooth",
 +              "Amount of smoothing to apply after finish newly created strokes, to reduce jitter/noise");
 +      RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
 +      RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
 +
 +      /* Iterations of the Smoothing factor */
 +      prop = RNA_def_property(srna, "pen_smooth_steps", PROP_INT, PROP_NONE);
 +      RNA_def_property_int_sdna(prop, NULL, "draw_smoothlvl");
 +      RNA_def_property_range(prop, 1, 3);
 +      RNA_def_property_ui_text(prop, "Iterations",
 +              "Number of times to smooth newly created strokes");
 +      RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
 +      RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
 +
 +      /* Thickness smoothing factor for new strokes */
 +      prop = RNA_def_property(srna, "pen_thick_smooth_factor", PROP_FLOAT, PROP_NONE);
 +      RNA_def_property_float_sdna(prop, NULL, "thick_smoothfac");
 +      RNA_def_property_range(prop, 0.0, 2.0f);
 +      RNA_def_property_ui_text(prop, "Smooth Thickness",
 +              "Amount of thickness smoothing to apply after finish newly created strokes, to reduce jitter/noise");
 +      RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
 +      RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
 +
 +      /* Thickness iterations of the Smoothing factor */
 +      prop = RNA_def_property(srna, "pen_thick_smooth_steps", PROP_INT, PROP_NONE);
 +      RNA_def_property_int_sdna(prop, NULL, "thick_smoothlvl");
 +      RNA_def_property_range(prop, 1, 3);
 +      RNA_def_property_ui_text(prop, "Iterations Thickness",
 +              "Number of times to smooth thickness for newly created strokes");
 +      RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
 +      RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
 +
 +      /* Subdivision level for new strokes */
 +      prop = RNA_def_property(srna, "pen_subdivision_steps", PROP_INT, PROP_NONE);
 +      RNA_def_property_int_sdna(prop, NULL, "draw_subdivide");
 +      RNA_def_property_range(prop, 0, 3);
 +      RNA_def_property_ui_text(prop, "Subdivision Steps",
 +              "Number of times to subdivide newly created strokes, for less jagged strokes");
 +      RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
 +      RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
 +
 +      /* Curves for pressure */
 +      prop = RNA_def_property(srna, "curve_sensitivity", PROP_POINTER, PROP_NONE);
 +      RNA_def_property_pointer_sdna(prop, NULL, "curve_sensitivity");
 +      RNA_def_property_struct_type(prop, "CurveMapping");
 +      RNA_def_property_ui_text(prop, "Curve Sensitivity", "Curve used for the sensitivity");
 +      RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
 +      RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
 +
 +      prop = RNA_def_property(srna, "curve_strength", PROP_POINTER, PROP_NONE);
 +      RNA_def_property_pointer_sdna(prop, NULL, "curve_strength");
 +      RNA_def_property_struct_type(prop, "CurveMapping");
 +      RNA_def_property_ui_text(prop, "Curve Strength", "Curve used for the strength");
 +      RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
 +      RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
 +
 +      prop = RNA_def_property(srna, "curve_jitter", PROP_POINTER, PROP_NONE);
 +      RNA_def_property_pointer_sdna(prop, NULL, "curve_jitter");
 +      RNA_def_property_struct_type(prop, "CurveMapping");
 +      RNA_def_property_ui_text(prop, "Curve Jitter", "Curve used for the jitter effect");
 +      RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
 +      RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
 +
 +      /* fill threshold for transparence */
 +      prop = RNA_def_property(srna, "gpencil_fill_threshold", PROP_FLOAT, PROP_NONE);
 +      RNA_def_property_float_sdna(prop, NULL, "fill_threshold");
 +      RNA_def_property_range(prop, 0.0f, 1.0f);
 +      RNA_def_property_ui_text(prop, "Threshold",
 +              "Threshold to consider color transparent for filling");
 +      RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
 +      RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
 +
 +      /* fill leak size */
 +      prop = RNA_def_property(srna, "gpencil_fill_leak", PROP_INT, PROP_PIXEL);
 +      RNA_def_property_int_sdna(prop, NULL, "fill_leak");
 +      RNA_def_property_range(prop, 0, 100);
 +      RNA_def_property_ui_text(prop, "Leak Size",
 +              "Size in pixels to consider the leak closed");
 +      RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
 +      RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
 +
 +      /* fill simplify steps */
 +      prop = RNA_def_property(srna, "gpencil_fill_simplyfy_level", PROP_INT, PROP_NONE);
 +      RNA_def_property_int_sdna(prop, NULL, "fill_simplylvl");
 +      RNA_def_property_range(prop, 0, 10);
 +      RNA_def_property_ui_text(prop, "Simplify",
 +              "Number of simplify steps (large values reduce fill accuracy)");
 +      RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
 +      RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
 +
 +      prop = RNA_def_property(srna, "uv_random", PROP_FLOAT, PROP_FACTOR);
 +      RNA_def_property_float_sdna(prop, NULL, "uv_random");
 +      RNA_def_property_range(prop, 0.0, 1.0);
 +      RNA_def_property_ui_text(prop, "UV Random", "Random factor for autogenerated UV rotation");
 +      RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
 +      RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
 +
 +      prop = RNA_def_property(srna, "input_samples", PROP_INT, PROP_NONE);
 +      RNA_def_property_int_sdna(prop, NULL, "input_samples");
 +      RNA_def_property_range(prop, 0, GP_MAX_INPUT_SAMPLES);
 +      RNA_def_property_ui_text(prop, "Input Samples", "Generate intermediate points for very fast mouse movements. Set to 0 to disable");
 +      RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
 +      RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
 +
 +      /* active smooth factor while drawing */
 +      prop = RNA_def_property(srna, "active_smooth_factor", PROP_FLOAT, PROP_NONE);
 +      RNA_def_property_float_sdna(prop, NULL, "active_smooth");
 +      RNA_def_property_range(prop, 0.0f, 1.0f);
 +      RNA_def_property_ui_text(prop, "Active Smooth",
 +              "Amount of smoothing while drawing ");
 +      RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
 +      RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
 +
 +      /* brush standard icon */
 +      prop = RNA_def_property(srna, "gp_icon", PROP_ENUM, PROP_NONE);
 +      RNA_def_property_enum_sdna(prop, NULL, "icon_id");
 +      RNA_def_property_enum_items(prop, rna_enum_gpencil_brush_icons_items);
 +      RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
 +      RNA_def_property_ui_text(prop, "Grease Pencil Icon", "");
 +
 +      /* Flags */
 +      prop = RNA_def_property(srna, "use_pressure", PROP_BOOLEAN, PROP_NONE);
 +      RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSH_USE_PRESSURE);
 +      RNA_def_property_ui_icon(prop, ICON_STYLUS_PRESSURE, 0);
 +      RNA_def_property_ui_text(prop, "Use Pressure", "Use tablet pressure");
 +      RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
 +      RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
 +
 +      prop = RNA_def_property(srna, "use_strength_pressure", PROP_BOOLEAN, PROP_NONE);
 +      RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSH_USE_STENGTH_PRESSURE);
 +      RNA_def_property_ui_icon(prop, ICON_STYLUS_PRESSURE, 0);
 +      RNA_def_property_ui_text(prop, "Use Pressure Strength", "Use tablet pressure for color strength");
 +      RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
 +      RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
 +
 +      prop = RNA_def_property(srna, "use_jitter_pressure", PROP_BOOLEAN, PROP_NONE);
 +      RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSH_USE_JITTER_PRESSURE);
 +      RNA_def_property_ui_icon(prop, ICON_STYLUS_PRESSURE, 0);
 +      RNA_def_property_ui_text(prop, "Use Pressure Jitter", "Use tablet pressure for jitter");
 +      RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
 +      RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
 +
 +      prop = RNA_def_property(srna, "use_stabilizer", PROP_BOOLEAN, PROP_NONE);
 +      RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSH_STABILIZE_MOUSE);
 +      RNA_def_property_boolean_default(prop, true);
 +      RNA_def_property_ui_text(prop, "Stabilizer",
 +              "Draw lines with a delay to allow smooth strokes. Press Shift key to override while drawing");
 +      RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
 +
 +      prop = RNA_def_property(srna, "use_cursor", PROP_BOOLEAN, PROP_NONE);
 +      RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSH_ENABLE_CURSOR);
 +      RNA_def_property_boolean_default(prop, true);
 +      RNA_def_property_ui_text(prop, "Enable Cursor", "Enable cursor on screen");
 +      RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
 +
 +      prop = RNA_def_property(srna, "gpencil_brush_type", PROP_ENUM, PROP_NONE);
 +      RNA_def_property_enum_sdna(prop, NULL, "brush_type");
 +      RNA_def_property_enum_items(prop, rna_enum_gpencil_brush_types_items);
 +      RNA_def_property_ui_text(prop, "Type", "Category of the brush");
 +      RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
 +
 +      prop = RNA_def_property(srna, "eraser_mode", PROP_ENUM, PROP_NONE);
 +      RNA_def_property_enum_sdna(prop, NULL, "eraser_mode");
 +      RNA_def_property_enum_items(prop, rna_enum_gpencil_brush_eraser_modes_items);
 +      RNA_def_property_ui_text(prop, "Mode", "Eraser Mode");
 +      RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
 +      RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_BrushGpencilSettings_eraser_mode_update");
 +
 +      prop = RNA_def_property(srna, "gpencil_fill_draw_mode", PROP_ENUM, PROP_NONE);
 +      RNA_def_property_enum_sdna(prop, NULL, "fill_draw_mode");
 +      RNA_def_property_enum_items(prop, rna_enum_gpencil_fill_draw_modes_items);
 +      RNA_def_property_ui_text(prop, "Mode", "Mode to draw boundary limits");
 +      RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
 +
 +      /* Material */
 +      prop = RNA_def_property(srna, "material", PROP_POINTER, PROP_NONE);
 +      RNA_def_property_struct_type(prop, "Material");
 +      RNA_def_property_pointer_funcs(prop, NULL, NULL, NULL, "rna_BrushGpencilSettings_material_poll");
 +      RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK | PROP_CONTEXT_UPDATE);
 +      RNA_def_property_ui_text(prop, "Material", "Material used for strokes drawn using this brush");
 +      RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
 +      RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_Brush_material_update");
 +
 +      prop = RNA_def_property(srna, "gpencil_fill_show_boundary", PROP_BOOLEAN, PROP_NONE);
 +      RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSH_FILL_SHOW_HELPLINES);
 +      RNA_def_property_boolean_default(prop, true);
 +      RNA_def_property_ui_text(prop, "Show Lines", "Show help lines for filling to see boundaries");
 +      RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
 +
 +      prop = RNA_def_property(srna, "gpencil_fill_hide", PROP_BOOLEAN, PROP_NONE);
 +      RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSH_FILL_HIDE);
 +      RNA_def_property_boolean_default(prop, true);
 +      RNA_def_property_ui_text(prop, "Hide", "Hide transparent lines to use as boundary for filling");
 +      RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
 +
 +      prop = RNA_def_property(srna, "default_eraser", PROP_BOOLEAN, PROP_NONE);
 +      RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSH_DEFAULT_ERASER);
 +      RNA_def_property_boolean_default(prop, true);
 +      RNA_def_property_ui_icon(prop, ICON_UNPINNED, 1);
 +      RNA_def_property_ui_text(prop, "Default Eraser", "Use this brush when enable eraser with fast switch key");
 +      RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
 +      RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_BrushGpencilSettings_default_eraser_update");
 +
 +      prop = RNA_def_property(srna, "enable_settings", PROP_BOOLEAN, PROP_NONE);
 +      RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSH_GROUP_SETTINGS);
 +      RNA_def_property_ui_text(prop, "Settings", "Enable additional post processing options for new strokes");
 +      RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
 +
 +      prop = RNA_def_property(srna, "enable_random", PROP_BOOLEAN, PROP_NONE);
 +      RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSH_GROUP_RANDOM);
 +      RNA_def_property_ui_text(prop, "Random Settings", "Enable random settings for brush");
 +      RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
 +
 +      prop = RNA_def_property(srna, "pin_material", PROP_BOOLEAN, PROP_NONE);
 +      RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSH_MATERIAL_PINNED);
 +      RNA_def_property_ui_icon(prop, ICON_UNPINNED, 1);
 +      RNA_def_property_ui_text(prop, "Pin Material", "Keep material assigned to brush");
 +      RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
 +}
 +
  static void rna_def_brush(BlenderRNA *brna)
  {
        StructRNA *srna;
index ef447ff30ecc77d5dc92afb5d9061e6d9ce988c6,c70870d56712fba23b00e5f514d45ffc0b6bbbe3..a961208755d1b464d4298c6d6860ad25c64da115
@@@ -95,254 -74,6 +95,254 @@@ static CustomDataMask requiredDataMask(
        return dataMask;
  }
  
-               /* If one of both faces is present in faceHash then we are at a border
-               *  between new vmesh created and reconstructed face */
 +static void bevel_set_weighted_normal_face_strength(BMesh *bm, Scene *scene)
 +{
 +      BMFace *f;
 +      BMIter fiter;
 +      const char *wn_layer_id = MOD_WEIGHTEDNORMALS_FACEWEIGHT_CDLAYER_ID;
 +      int cd_prop_int_idx = CustomData_get_named_layer_index(&bm->pdata, CD_PROP_INT, wn_layer_id);
 +
 +      if (cd_prop_int_idx == -1) {
 +              BM_data_layer_add_named(bm, &bm->pdata, CD_PROP_INT, wn_layer_id);
 +              cd_prop_int_idx = CustomData_get_named_layer_index(&bm->pdata, CD_PROP_INT, wn_layer_id);
 +      }
 +      cd_prop_int_idx -= CustomData_get_layer_index(&bm->pdata, CD_PROP_INT);
 +      const int cd_prop_int_offset = CustomData_get_n_offset(&bm->pdata, CD_PROP_INT, cd_prop_int_idx);
 +
 +      const int face_strength = scene->toolsettings->face_strength;
 +
 +      BM_ITER_MESH(f, &fiter, bm, BM_FACES_OF_MESH) {
 +              if (BM_elem_flag_test(f, BM_ELEM_TAG)) {
 +                      int *strength = BM_ELEM_CD_GET_VOID_P(f, cd_prop_int_offset);
 +                      *strength = face_strength;
 +              }
 +      }
 +}
 +
 +static void bevel_mod_harden_normals(
 +        BevelModifierData *bmd, BMesh *bm, const float hn_strength,
 +        const int hnmode, MDeformVert *dvert, int vgroup)
 +{
 +      if (bmd->res > 20 || bmd->value == 0)
 +              return;
 +
 +      BM_mesh_normals_update(bm);
 +      BM_lnorspace_update(bm);
 +      BM_normals_loops_edges_tag(bm, true);
 +
 +      const bool vertex_only = (bmd->flags & MOD_BEVEL_VERT) != 0;
 +      const int cd_clnors_offset = CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL);
 +      const bool do_normal_to_recon = (hn_strength == 1.0f);
 +
 +      BMFace *f;
 +      BMLoop *l, *l_cur, *l_first;
 +      BMIter fiter;
 +      GHash *faceHash = bmd->clnordata.faceHash;
 +
 +      /* Iterate throught all loops of a face */
 +      BM_ITER_MESH(f, &fiter, bm, BM_FACES_OF_MESH) {
 +
 +              l_cur = l_first = BM_FACE_FIRST_LOOP(f);
 +              do {
 +                      if ((!BM_elem_flag_test(l_cur->e, BM_ELEM_TAG)) ||
 +                          (!BM_elem_flag_test(l_cur, BM_ELEM_TAG) && BM_loop_check_cyclic_smooth_fan(l_cur)))
 +                      {
 +
 +                              /* previous and next edge is sharp, accumulate face normals into loop */
 +                              if (!BM_elem_flag_test(l_cur->e, BM_ELEM_TAG) && !BM_elem_flag_test(l_cur->prev->e, BM_ELEM_TAG)) {
 +                                      const int loop_index = BM_elem_index_get(l_cur);
 +                                      short *clnors = BM_ELEM_CD_GET_VOID_P(l_cur, cd_clnors_offset);
 +                                      BKE_lnor_space_custom_normal_to_data(bm->lnor_spacearr->lspacearr[loop_index], f->no, clnors);
 +                              }
 +                              else {
 +                                      BMVert *v_pivot = l_cur->v;
 +                                      BMEdge *e_next;
 +                                      const BMEdge *e_org = l_cur->e;
 +                                      BMLoop *lfan_pivot, *lfan_pivot_next;
 +                                      UNUSED_VARS_NDEBUG(v_pivot);
 +
 +                                      lfan_pivot = l_cur;
 +                                      e_next = lfan_pivot->e;
 +                                      BLI_SMALLSTACK_DECLARE(loops, BMLoop *);
 +                                      float cn_wght[3] = { 0.0f, 0.0f, 0.0f };
 +                                      int recon_face_count = 0;               /* Counts number of reconstructed faces current vert is connected to */
 +                                      BMFace *recon_face = NULL;              /* Reconstructed face */
 +
 +                                      while (true) {
 +                                              lfan_pivot_next = BM_vert_step_fan_loop(lfan_pivot, &e_next);
 +                                              if (lfan_pivot_next) {
 +                                                      BLI_assert(lfan_pivot_next->v == v_pivot);
 +                                              }
 +                                              else {
 +                                                      e_next = (lfan_pivot->e == e_next) ? lfan_pivot->prev->e : lfan_pivot->e;
 +                                              }
 +
 +                                              BLI_SMALLSTACK_PUSH(loops, lfan_pivot);
 +
 +                                              if (bmd->lim_flags & MOD_BEVEL_WEIGHT) {
 +                                                      int weight = BM_elem_float_data_get(&bm->edata, lfan_pivot->f, CD_BWEIGHT);
 +                                                      if (weight) {
 +                                                              if (hnmode == MOD_BEVEL_HN_FACE) {
 +                                                                      float cur[3];                                   //Add area weighted face normals
 +                                                                      mul_v3_v3fl(cur, lfan_pivot->f->no, BM_face_calc_area(lfan_pivot->f));
 +                                                                      add_v3_v3(cn_wght, cur);
 +                                                              }
 +                                                              else
 +                                                                      add_v3_v3(cn_wght, lfan_pivot->f->no);          //Else simply add face normals
 +                                                      }
 +                                                      else
 +                                                              add_v3_v3(cn_wght, lfan_pivot->f->no);
 +
 +                                              }
 +                                              else if (bmd->lim_flags & MOD_BEVEL_VGROUP) {
 +                                                      const bool has_vgroup = dvert != NULL;
 +                                                      const bool vert_of_group = (
 +                                                              has_vgroup &&
 +                                                              (defvert_find_index(&dvert[BM_elem_index_get(l->v)], vgroup) != NULL));
 +
 +                                                      if (vert_of_group && hnmode == MOD_BEVEL_HN_FACE) {
 +                                                              float cur[3];
 +                                                              mul_v3_v3fl(cur, lfan_pivot->f->no, BM_face_calc_area(lfan_pivot->f));
 +                                                              add_v3_v3(cn_wght, cur);
 +                                                      }
 +                                                      else
 +                                                              add_v3_v3(cn_wght, lfan_pivot->f->no);
 +                                              }
 +                                              else {
 +                                                      float cur[3];
 +                                                      mul_v3_v3fl(cur, lfan_pivot->f->no, BM_face_calc_area(lfan_pivot->f));
 +                                                      add_v3_v3(cn_wght, cur);
 +                                              }
 +                                              if (!BLI_ghash_haskey(faceHash, lfan_pivot->f)) {
 +                                                      recon_face = f;
 +                                                      recon_face_count++;
 +                                              }
 +                                              if (!BM_elem_flag_test(e_next, BM_ELEM_TAG) || (e_next == e_org)) {
 +                                                      break;
 +                                              }
 +                                              lfan_pivot = lfan_pivot_next;
 +                                      }
 +
 +                                      normalize_v3(cn_wght);
 +                                      mul_v3_fl(cn_wght, hn_strength);
 +                                      float n_final[3];
 +
 +                                      while ((l = BLI_SMALLSTACK_POP(loops))) {
 +                                              const int l_index = BM_elem_index_get(l);
 +                                              short *clnors = BM_ELEM_CD_GET_VOID_P(l, cd_clnors_offset);
 +
 +                                              /* If vertex is edge vert with 1 reconnected face */
 +                                              if (recon_face_count == 1 || (recon_face != NULL && do_normal_to_recon)) {
 +                                                      BKE_lnor_space_custom_normal_to_data(
 +                                                              bm->lnor_spacearr->lspacearr[l_index], recon_face->no, clnors);
 +                                              }
 +                                              else if (vertex_only == false || recon_face_count == 0) {
 +                                                      copy_v3_v3(n_final, l->f->no);
 +                                                      mul_v3_fl(n_final, 1.0f - hn_strength);
 +                                                      add_v3_v3(n_final, cn_wght);
 +                                                      normalize_v3(n_final);
 +                                                      BKE_lnor_space_custom_normal_to_data(
 +                                                              bm->lnor_spacearr->lspacearr[l_index], n_final, clnors);
 +                                              }
 +                                              else if (BLI_ghash_haskey(faceHash, l->f)) {
 +                                                      BKE_lnor_space_custom_normal_to_data(
 +                                                              bm->lnor_spacearr->lspacearr[l_index], l->v->no, clnors);
 +                                              }
 +                                      }
 +                              }
 +                      }
 +              } while ((l_cur = l_cur->next) != l_first);
 +      }
 +}
 +
 +static void bevel_fix_normal_shading_continuity(BevelModifierData *bmd, BMesh *bm)
 +{
 +      const bool vertex_only = (bmd->flags & MOD_BEVEL_VERT) != 0;
 +      if (bmd->value == 0 || (bmd->clnordata.faceHash == NULL && vertex_only))
 +              return;
 +
 +      BM_mesh_normals_update(bm);
 +      BM_lnorspace_update(bm);
 +
 +      GHash *faceHash = bmd->clnordata.faceHash;
 +      BMEdge *e;
 +      BMLoop *l;
 +      BMIter liter, eiter;
 +
 +      const int cd_clnors_offset = CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL);
 +      const float hn_strength = bmd->hn_strength;
 +      float ref = 10.0f;
 +
 +      BM_ITER_MESH(e, &eiter, bm, BM_EDGES_OF_MESH) {
 +              BMFace *f_a, *f_b;
 +              BM_edge_face_pair(e, &f_a, &f_b);
 +
 +              bool has_f_a = false, has_f_b = false;
 +              if (f_a)
 +                      has_f_a = BLI_ghash_haskey(faceHash, f_a);
 +              if (f_b)
 +                      has_f_b = BLI_ghash_haskey(faceHash, f_b);
 +              if (has_f_a ^ has_f_b) {
-               /* Else if both faces are present we assign clnor corresponding
-               *  to vert normal and face normal */
++                      /* If one of both faces is present in faceHash then we are at a border
++                       * between new vmesh created and reconstructed face */
 +
 +                      for (int i = 0; i < 2; i++) {
 +                              BMVert *v = (i == 0) ? e->v1 : e->v2;
 +                              BM_ITER_ELEM(l, &liter, v, BM_LOOPS_OF_VERT) {
 +
 +                                      if (l->f == f_a || l->f == f_b) {
 +                                              const int l_index = BM_elem_index_get(l);
 +                                              short *clnors = BM_ELEM_CD_GET_VOID_P(l, cd_clnors_offset);
 +                                              float n_final[3], pow_a[3], pow_b[3];
 +
 +                                              zero_v3(n_final);
 +                                              copy_v3_v3(pow_a, f_a->no);
 +                                              copy_v3_v3(pow_b, f_b->no);
 +                                              if (has_f_a) {
 +                                                      mul_v3_fl(pow_a, bmd->res / ref);
 +                                                      mul_v3_fl(pow_b, ref / bmd->res);
 +                                              }
 +                                              else {
 +                                                      mul_v3_fl(pow_b, bmd->res / ref);
 +                                                      mul_v3_fl(pow_a, ref / bmd->res);
 +                                              }
 +                                              add_v3_v3(n_final, pow_a);
 +                                              add_v3_v3(n_final, pow_b);
 +                                              normalize_v3(n_final);
 +
 +                                              BKE_lnor_space_custom_normal_to_data(bm->lnor_spacearr->lspacearr[l_index], n_final, clnors);
 +                                      }
 +                              }
 +                      }
 +              }
 +              else if (has_f_a == true  && has_f_b == true) {
++                      /* Else if both faces are present we assign clnor corresponding
++                       * to vert normal and face normal */
 +                      for (int i = 0; i < 2; i++) {
 +                              BMVert *v = (i == 0) ? e->v1 : e->v2;
 +                              BM_ITER_ELEM(l, &liter, v, BM_LOOPS_OF_VERT) {
 +
 +                                      if (l->f == f_a || l->f == f_b) {
 +                                              const int l_index = BM_elem_index_get(l);
 +                                              short *clnors = BM_ELEM_CD_GET_VOID_P(l, cd_clnors_offset);
 +                                              float n_final[3], cn_wght[3];
 +
 +                                              copy_v3_v3(n_final, v->no);
 +                                              mul_v3_fl(n_final, hn_strength);
 +
 +                                              copy_v3_v3(cn_wght, l->f->no);
 +                                              mul_v3_fl(cn_wght, 1.0f - hn_strength);
 +
 +                                              add_v3_v3(n_final, cn_wght);
 +                                              normalize_v3(n_final);
 +                                              BKE_lnor_space_custom_normal_to_data(bm->lnor_spacearr->lspacearr[l_index], n_final, clnors);
 +                                      }
 +                              }
 +                      }
 +              }
 +      }
 +}
 +
  /*
   * This calls the new bevel code (added since 2.64)
   */