Merge branch 'master' into blender2.8
authorCampbell Barton <ideasman42@gmail.com>
Tue, 31 Jul 2018 22:42:00 +0000 (08:42 +1000)
committerCampbell Barton <ideasman42@gmail.com>
Tue, 31 Jul 2018 22:42:00 +0000 (08:42 +1000)
Move 'View3D.flag3' options into 'gp_flag'.

1  2 
source/blender/blenloader/intern/versioning_280.c
source/blender/blenloader/intern/versioning_defaults.c
source/blender/draw/engines/gpencil/gpencil_draw_utils.c
source/blender/draw/engines/gpencil/gpencil_engine.c
source/blender/editors/space_view3d/space_view3d.c
source/blender/makesdna/DNA_view3d_types.h
source/blender/makesrna/intern/rna_space.c

index d2a1cc1f4f132d097e519891a64cf62c474f9fe1,0000000000000000000000000000000000000000..ab787a52cfd256d428f95a26b3aaeed30d3acf9e
mode 100644,000000..100644
--- /dev/null
@@@ -1,1835 -1,0 +1,1832 @@@
-                                                       v3d->shading.background_type = (
-                                                               (v3d->flag3 & V3D_SHOW_WORLD) ?
-                                                               V3D_SHADING_BACKGROUND_WORLD : V3D_SHADING_BACKGROUND_THEME);
 +/*
 + * ***** BEGIN GPL LICENSE BLOCK *****
 + *
 + * 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): Dalai Felinto
 + *
 + * ***** END GPL LICENSE BLOCK *****
 + *
 + */
 +
 +/** \file blender/blenloader/intern/versioning_280.c
 + *  \ingroup blenloader
 + */
 +
 +/* allow readfile to use deprecated functionality */
 +#define DNA_DEPRECATED_ALLOW
 +
 +#include <string.h>
 +#include <float.h>
 +
 +#include "BLI_listbase.h"
 +#include "BLI_math.h"
 +#include "BLI_mempool.h"
 +#include "BLI_string.h"
 +#include "BLI_string_utf8.h"
 +#include "BLI_utildefines.h"
 +
 +#include "DNA_object_types.h"
 +#include "DNA_camera_types.h"
 +#include "DNA_constraint_types.h"
 +#include "DNA_gpu_types.h"
 +#include "DNA_group_types.h"
 +#include "DNA_lamp_types.h"
 +#include "DNA_layer_types.h"
 +#include "DNA_lightprobe_types.h"
 +#include "DNA_material_types.h"
 +#include "DNA_mesh_types.h"
 +#include "DNA_particle_types.h"
 +#include "DNA_rigidbody_types.h"
 +#include "DNA_scene_types.h"
 +#include "DNA_screen_types.h"
 +#include "DNA_view3d_types.h"
 +#include "DNA_genfile.h"
 +#include "DNA_gpencil_types.h"
 +#include "DNA_workspace_types.h"
 +
 +#include "BKE_collection.h"
 +#include "BKE_constraint.h"
 +#include "BKE_customdata.h"
 +#include "BKE_colortools.h"
 +#include "BKE_freestyle.h"
 +#include "BKE_idprop.h"
 +#include "BKE_image.h"
 +#include "BKE_layer.h"
 +#include "BKE_main.h"
 +#include "BKE_material.h"
 +#include "BKE_mesh.h"
 +#include "BKE_node.h"
 +#include "BKE_pointcache.h"
 +#include "BKE_report.h"
 +#include "BKE_scene.h"
 +#include "BKE_screen.h"
 +#include "BKE_sequencer.h"
 +#include "BKE_studiolight.h"
 +#include "BKE_workspace.h"
 +#include "BKE_gpencil.h"
 +#include "BKE_paint.h"
 +#include "BKE_object.h"
 +
 +#include "BLO_readfile.h"
 +#include "readfile.h"
 +
 +#include "MEM_guardedalloc.h"
 +
 +static bScreen *screen_parent_find(const bScreen *screen)
 +{
 +      /* can avoid lookup if screen state isn't maximized/full (parent and child store the same state) */
 +      if (ELEM(screen->state, SCREENMAXIMIZED, SCREENFULL)) {
 +              for (const ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
 +                      if (sa->full && sa->full != screen) {
 +                              BLI_assert(sa->full->state == screen->state);
 +                              return sa->full;
 +                      }
 +              }
 +      }
 +
 +      return NULL;
 +}
 +
 +static void do_version_workspaces_create_from_screens(Main *bmain)
 +{
 +      for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) {
 +              const bScreen *screen_parent = screen_parent_find(screen);
 +              WorkSpace *workspace;
 +              if (screen->temp) {
 +                      continue;
 +              }
 +
 +              if (screen_parent) {
 +                      /* fullscreen with "Back to Previous" option, don't create
 +                       * a new workspace, add layout workspace containing parent */
 +                      workspace = BLI_findstring(
 +                              &bmain->workspaces, screen_parent->id.name + 2, offsetof(ID, name) + 2);
 +              }
 +              else {
 +                      workspace = BKE_workspace_add(bmain, screen->id.name + 2);
 +              }
 +              if (workspace == NULL) {
 +                      continue;  /* Not much we can do.. */
 +              }
 +              BKE_workspace_layout_add(bmain, workspace, screen, screen->id.name + 2);
 +      }
 +}
 +
 +static void do_version_area_change_space_to_space_action(ScrArea *area, const Scene *scene)
 +{
 +      SpaceType *stype = BKE_spacetype_from_id(SPACE_ACTION);
 +      SpaceAction *saction = (SpaceAction *)stype->new(area, scene);
 +      ARegion *region_channels;
 +
 +      /* Properly free current regions */
 +      for (ARegion *region = area->regionbase.first; region; region = region->next) {
 +              BKE_area_region_free(area->type, region);
 +      }
 +      BLI_freelistN(&area->regionbase);
 +
 +      area->type = stype;
 +      area->spacetype = stype->spaceid;
 +
 +      BLI_addhead(&area->spacedata, saction);
 +      area->regionbase = saction->regionbase;
 +      BLI_listbase_clear(&saction->regionbase);
 +
 +      /* Different defaults for timeline */
 +      region_channels = BKE_area_find_region_type(area, RGN_TYPE_CHANNELS);
 +      region_channels->flag |= RGN_FLAG_HIDDEN;
 +
 +      saction->mode = SACTCONT_TIMELINE;
 +      saction->ads.flag |= ADS_FLAG_SUMMARY_COLLAPSED;
 +      saction->ads.filterflag |= ADS_FILTER_SUMMARY;
 +}
 +
 +/**
 + * \brief After lib-link versioning for new workspace design.
 + *
 + * - Adds a workspace for (almost) each screen of the old file
 + *   and adds the needed workspace-layout to wrap the screen.
 + * - Active screen isn't stored directly in window anymore, but in the active workspace.
 + * - Active scene isn't stored in screen anymore, but in window.
 + * - Create workspace instance hook for each window.
 + *
 + * \note Some of the created workspaces might be deleted again in case of reading the default startup.blend.
 + */
 +static void do_version_workspaces_after_lib_link(Main *bmain)
 +{
 +      BLI_assert(BLI_listbase_is_empty(&bmain->workspaces));
 +
 +      do_version_workspaces_create_from_screens(bmain);
 +
 +      for (wmWindowManager *wm = bmain->wm.first; wm; wm = wm->id.next) {
 +              for (wmWindow *win = wm->windows.first; win; win = win->next) {
 +                      bScreen *screen_parent = screen_parent_find(win->screen);
 +                      bScreen *screen = screen_parent ? screen_parent : win->screen;
 +
 +                      if (screen->temp) {
 +                              /* We do not generate a new workspace for those screens... still need to set some data in win. */
 +                              win->workspace_hook = BKE_workspace_instance_hook_create(bmain);
 +                              win->scene = screen->scene;
 +                              /* Deprecated from now on! */
 +                              win->screen = NULL;
 +                              continue;
 +                      }
 +
 +                      WorkSpace *workspace = BLI_findstring(&bmain->workspaces, screen->id.name + 2, offsetof(ID, name) + 2);
 +                      BLI_assert(workspace != NULL);
 +                      ListBase *layouts = BKE_workspace_layouts_get(workspace);
 +
 +                      win->workspace_hook = BKE_workspace_instance_hook_create(bmain);
 +
 +                      BKE_workspace_active_set(win->workspace_hook, workspace);
 +                      BKE_workspace_active_layout_set(win->workspace_hook, layouts->first);
 +
 +                      /* Move scene and view layer to window. */
 +                      Scene *scene = screen->scene;
 +                      ViewLayer *layer = BLI_findlink(&scene->view_layers, scene->r.actlay);
 +                      if (!layer) {
 +                              layer = BKE_view_layer_default_view(scene);
 +                      }
 +
 +                      win->scene = scene;
 +                      STRNCPY(win->view_layer_name, layer->name);
 +
 +                      /* Deprecated from now on! */
 +                      win->screen = NULL;
 +              }
 +      }
 +
 +      for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) {
 +              /* Deprecated from now on! */
 +              BLI_freelistN(&screen->scene->transform_spaces);
 +              screen->scene = NULL;
 +      }
 +}
 +
 +#ifdef USE_COLLECTION_COMPAT_28
 +enum {
 +      COLLECTION_DEPRECATED_VISIBLE    = (1 << 0),
 +      COLLECTION_DEPRECATED_VIEWPORT   = (1 << 0),
 +      COLLECTION_DEPRECATED_SELECTABLE = (1 << 1),
 +      COLLECTION_DEPRECATED_DISABLED   = (1 << 2),
 +      COLLECTION_DEPRECATED_RENDER     = (1 << 3),
 +};
 +
 +static void do_version_view_layer_visibility(ViewLayer *view_layer)
 +{
 +      /* Convert from deprecated VISIBLE flag to DISABLED */
 +      LayerCollection *lc;
 +      for (lc = view_layer->layer_collections.first;
 +           lc;
 +           lc = lc->next)
 +      {
 +              if (lc->flag & COLLECTION_DEPRECATED_DISABLED) {
 +                      lc->flag &= ~COLLECTION_DEPRECATED_DISABLED;
 +              }
 +
 +              if ((lc->flag & COLLECTION_DEPRECATED_VISIBLE) == 0) {
 +                      lc->flag |= COLLECTION_DEPRECATED_DISABLED;
 +              }
 +
 +              lc->flag |= COLLECTION_DEPRECATED_VIEWPORT | COLLECTION_DEPRECATED_RENDER;
 +      }
 +}
 +
 +static void do_version_layer_collection_pre(
 +        ViewLayer *view_layer,
 +        ListBase *lb,
 +        GSet *enabled_set,
 +        GSet *selectable_set)
 +{
 +      /* Convert from deprecated DISABLED to new layer collection and collection flags */
 +      for (LayerCollection *lc = lb->first; lc; lc = lc->next) {
 +              if (lc->scene_collection) {
 +                      if (!(lc->flag & COLLECTION_DEPRECATED_DISABLED)) {
 +                              BLI_gset_insert(enabled_set, lc->scene_collection);
 +                      }
 +                      if (lc->flag & COLLECTION_DEPRECATED_SELECTABLE) {
 +                              BLI_gset_insert(selectable_set, lc->scene_collection);
 +                      }
 +              }
 +
 +              do_version_layer_collection_pre(view_layer, &lc->layer_collections, enabled_set, selectable_set);
 +      }
 +}
 +
 +static void do_version_layer_collection_post(
 +        ViewLayer *view_layer,
 +        ListBase *lb,
 +        GSet *enabled_set,
 +        GSet *selectable_set,
 +        GHash *collection_map)
 +{
 +      /* Apply layer collection exclude flags. */
 +      for (LayerCollection *lc = lb->first; lc; lc = lc->next) {
 +              if (!(lc->collection->flag & COLLECTION_IS_MASTER)) {
 +                      SceneCollection *sc = BLI_ghash_lookup(collection_map, lc->collection);
 +                      const bool enabled = (sc && BLI_gset_haskey(enabled_set, sc));
 +                      const bool selectable = (sc && BLI_gset_haskey(selectable_set, sc));
 +
 +                      if (!enabled) {
 +                              lc->flag |= LAYER_COLLECTION_EXCLUDE;
 +                      }
 +                      if (enabled && !selectable) {
 +                              lc->collection->flag |= COLLECTION_RESTRICT_SELECT;
 +                      }
 +              }
 +
 +              do_version_layer_collection_post(
 +                      view_layer, &lc->layer_collections, enabled_set, selectable_set, collection_map);
 +      }
 +}
 +
 +static void do_version_scene_collection_convert(
 +        Main *bmain,
 +        ID *id,
 +        SceneCollection *sc,
 +        Collection *collection,
 +        GHash *collection_map)
 +{
 +      if (collection_map) {
 +              BLI_ghash_insert(collection_map, collection, sc);
 +      }
 +
 +      for (SceneCollection *nsc = sc->scene_collections.first; nsc;) {
 +              SceneCollection *nsc_next = nsc->next;
 +              Collection *ncollection = BKE_collection_add(bmain, collection, nsc->name);
 +              ncollection->id.lib = id->lib;
 +              do_version_scene_collection_convert(bmain, id, nsc, ncollection, collection_map);
 +              nsc = nsc_next;
 +      }
 +
 +      for (LinkData *link = sc->objects.first; link; link = link->next) {
 +              Object *ob = link->data;
 +              if (ob) {
 +                      BKE_collection_object_add(bmain, collection, ob);
 +                      id_us_min(&ob->id);
 +              }
 +      }
 +
 +      BLI_freelistN(&sc->objects);
 +      MEM_freeN(sc);
 +}
 +
 +static void do_version_group_collection_to_collection(Main *bmain, Collection *group)
 +{
 +      /* Convert old 2.8 group collections to new unified collections. */
 +      if (group->collection) {
 +              do_version_scene_collection_convert(bmain, &group->id, group->collection, group, NULL);
 +      }
 +
 +      group->collection = NULL;
 +      group->view_layer = NULL;
 +      id_fake_user_set(&group->id);
 +}
 +
 +static void do_version_scene_collection_to_collection(Main *bmain, Scene *scene)
 +{
 +      /* Convert old 2.8 scene collections to new unified collections. */
 +
 +      /* Temporarily clear view layers so we don't do any layer collection syncing
 +       * and destroy old flags that we want to restore. */
 +      ListBase view_layers = scene->view_layers;
 +      BLI_listbase_clear(&scene->view_layers);
 +
 +      if (!scene->master_collection) {
 +              scene->master_collection = BKE_collection_master_add();
 +      }
 +
 +      /* Convert scene collections. */
 +      GHash *collection_map = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__);
 +      if (scene->collection) {
 +              do_version_scene_collection_convert(bmain, &scene->id, scene->collection, scene->master_collection, collection_map);
 +              scene->collection = NULL;
 +      }
 +
 +      scene->view_layers = view_layers;
 +
 +      /* Convert layer collections. */
 +      ViewLayer *view_layer;
 +      for (view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) {
 +              GSet *enabled_set = BLI_gset_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__);
 +              GSet *selectable_set = BLI_gset_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__);
 +
 +              do_version_layer_collection_pre(
 +                      view_layer, &view_layer->layer_collections, enabled_set, selectable_set);
 +
 +              BKE_layer_collection_sync(scene, view_layer);
 +
 +              do_version_layer_collection_post(
 +                      view_layer, &view_layer->layer_collections, enabled_set, selectable_set, collection_map);
 +
 +              BLI_gset_free(enabled_set, NULL);
 +              BLI_gset_free(selectable_set, NULL);
 +
 +              BKE_layer_collection_sync(scene, view_layer);
 +      }
 +
 +      BLI_ghash_free(collection_map, NULL, NULL);
 +}
 +#endif
 +
 +
 +static void do_version_layers_to_collections(Main *bmain, Scene *scene)
 +{
 +      /* Since we don't have access to FileData we check the (always valid) first
 +       * render layer instead. */
 +      if (!scene->master_collection) {
 +              scene->master_collection = BKE_collection_master_add();
 +      }
 +
 +      if (scene->view_layers.first) {
 +              return;
 +      }
 +
 +      /* Create collections from layers. */
 +      Collection *collection_master = BKE_collection_master(scene);
 +      Collection *collections[20] = {NULL};
 +
 +      for (int layer = 0; layer < 20; layer++) {
 +              for (Base *base = scene->base.first; base; base = base->next) {
 +                      if (base->lay & (1 << layer)) {
 +                              /* Create collections when needed only. */
 +                              if (collections[layer] == NULL) {
 +                                      char name[MAX_NAME];
 +
 +                                      BLI_snprintf(name,
 +                                                   sizeof(collection_master->id.name),
 +                                                   "Collection %d",
 +                                                   layer + 1);
 +
 +                                      Collection *collection = BKE_collection_add(bmain, collection_master, name);
 +                                      collection->id.lib = scene->id.lib;
 +                                      collections[layer] = collection;
 +
 +                                      if (!(scene->lay & (1 << layer))) {
 +                                              collection->flag |= COLLECTION_RESTRICT_VIEW | COLLECTION_RESTRICT_RENDER;
 +                                      }
 +                              }
 +
 +                              /* Note usually this would do slow collection syncing for view layers,
 +                               * but since no view layers exists yet at this point it's fast. */
 +                              BKE_collection_object_add(
 +                                      bmain,
 +                                      collections[layer], base->object);
 +                      }
 +
 +                      if (base->flag & SELECT) {
 +                              base->object->flag |= SELECT;
 +                      }
 +                      else {
 +                              base->object->flag &= ~SELECT;
 +                      }
 +              }
 +      }
 +
 +      /* Handle legacy render layers. */
 +      bool have_override = false;
 +
 +      for (SceneRenderLayer *srl = scene->r.layers.first; srl; srl = srl->next) {
 +              ViewLayer *view_layer = BKE_view_layer_add(scene, srl->name);
 +
 +              if (srl->samples != 0) {
 +                      have_override = true;
 +
 +                      /* It is up to the external engine to handle
 +                       * its own doversion in this case. */
 +                      BKE_override_view_layer_int_add(
 +                              view_layer,
 +                              ID_SCE,
 +                              "samples",
 +                              srl->samples);
 +              }
 +
 +              if (srl->mat_override) {
 +                      have_override = true;
 +
 +                      BKE_override_view_layer_datablock_add(
 +                              view_layer,
 +                              ID_MA,
 +                              "self",
 +                              (ID *)srl->mat_override);
 +              }
 +
 +              if (srl->layflag & SCE_LAY_DISABLE) {
 +                      view_layer->flag &= ~VIEW_LAYER_RENDER;
 +              }
 +
 +              if ((srl->layflag & SCE_LAY_FRS) == 0) {
 +                      view_layer->flag &= ~VIEW_LAYER_FREESTYLE;
 +              }
 +
 +              /* XXX If we are to keep layflag it should be merged with flag (dfelinto). */
 +              view_layer->layflag = srl->layflag;
 +              /* XXX Not sure if we should keep the passes (dfelinto). */
 +              view_layer->passflag = srl->passflag;
 +              view_layer->pass_xor = srl->pass_xor;
 +              view_layer->pass_alpha_threshold = srl->pass_alpha_threshold;
 +
 +              BKE_freestyle_config_free(&view_layer->freestyle_config, true);
 +              view_layer->freestyle_config = srl->freestyleConfig;
 +              view_layer->id_properties = srl->prop;
 +
 +              /* Set exclusion and overrides. */
 +              for (int layer = 0; layer < 20; layer++) {
 +                      Collection *collection = collections[layer];
 +                      if (collection) {
 +                              LayerCollection *lc = BKE_layer_collection_first_from_scene_collection(view_layer, collection);
 +
 +                              if (srl->lay_exclude & (1 << layer)) {
 +                                      /* Disable excluded layer. */
 +                                      have_override = true;
 +                                      lc->flag |= LAYER_COLLECTION_EXCLUDE;
 +                                      for (LayerCollection *nlc = lc->layer_collections.first; nlc; nlc = nlc->next) {
 +                                              nlc->flag |= LAYER_COLLECTION_EXCLUDE;
 +                                      }
 +                              }
 +                              else {
 +                                      if (srl->lay_zmask & (1 << layer)) {
 +                                              have_override = true;
 +                                              lc->flag |= LAYER_COLLECTION_HOLDOUT;
 +                                      }
 +
 +                                      if ((srl->lay & (1 << layer)) == 0) {
 +                                              have_override = true;
 +                                              lc->flag |= LAYER_COLLECTION_INDIRECT_ONLY;
 +                                      }
 +                              }
 +                      }
 +              }
 +
 +              /* for convenience set the same active object in all the layers */
 +              if (scene->basact) {
 +                      view_layer->basact = BKE_view_layer_base_find(view_layer, scene->basact->object);
 +              }
 +
 +              for (Base *base = view_layer->object_bases.first; base; base = base->next) {
 +                      if ((base->flag & BASE_SELECTABLE) && (base->object->flag & SELECT)) {
 +                              base->flag |= BASE_SELECTED;
 +                      }
 +              }
 +      }
 +
 +      BLI_freelistN(&scene->r.layers);
 +
 +      /* If render layers included overrides, we also create a vanilla
 +       * viewport layer without them. */
 +      if (have_override) {
 +              ViewLayer *view_layer = BKE_view_layer_add(scene, "Viewport");
 +
 +              /* Make it first in the list. */
 +              BLI_remlink(&scene->view_layers, view_layer);
 +              BLI_addhead(&scene->view_layers, view_layer);
 +
 +              /* If we ported all the original render layers, we don't need to make the viewport layer renderable. */
 +              if (!BLI_listbase_is_single(&scene->view_layers)) {
 +                      view_layer->flag &= ~VIEW_LAYER_RENDER;
 +              }
 +
 +              /* convert active base */
 +              if (scene->basact) {
 +                      view_layer->basact = BKE_view_layer_base_find(view_layer, scene->basact->object);
 +              }
 +
 +              /* convert selected bases */
 +              for (Base *base = view_layer->object_bases.first; base; base = base->next) {
 +                      if ((base->flag & BASE_SELECTABLE) && (base->object->flag & SELECT)) {
 +                              base->flag |= BASE_SELECTED;
 +                      }
 +
 +                      /* keep lay around for forward compatibility (open those files in 2.79) */
 +                      base->lay = base->object->lay;
 +              }
 +      }
 +
 +      /* remove bases once and for all */
 +      for (Base *base = scene->base.first; base; base = base->next) {
 +              id_us_min(&base->object->id);
 +      }
 +
 +      BLI_freelistN(&scene->base);
 +      scene->basact = NULL;
 +}
 +
 +void do_versions_after_linking_280(Main *bmain)
 +{
 +      bool use_collection_compat_28 = true;
 +
 +      if (!MAIN_VERSION_ATLEAST(bmain, 280, 0)) {
 +              use_collection_compat_28 = false;
 +
 +              /* Convert group layer visibility flags to hidden nested collection. */
 +              for (Collection *collection = bmain->collection.first; collection; collection = collection->id.next) {
 +                      /* Add fake user for all existing groups. */
 +                      id_fake_user_set(&collection->id);
 +
 +                      if (collection->flag & (COLLECTION_RESTRICT_VIEW | COLLECTION_RESTRICT_RENDER)) {
 +                              continue;
 +                      }
 +
 +                      Collection *collection_hidden = NULL;
 +                      for (CollectionObject *cob = collection->gobject.first, *cob_next = NULL; cob; cob = cob_next) {
 +                              cob_next = cob->next;
 +                              Object *ob = cob->ob;
 +
 +                              if (!(ob->lay & collection->layer)) {
 +                                      if (collection_hidden == NULL) {
 +                                              collection_hidden = BKE_collection_add(bmain, collection, "Hidden");
 +                                              collection_hidden->id.lib = collection->id.lib;
 +                                              collection_hidden->flag |= COLLECTION_RESTRICT_VIEW | COLLECTION_RESTRICT_RENDER;
 +                                      }
 +
 +                                      BKE_collection_object_add(bmain, collection_hidden, ob);
 +                                      BKE_collection_object_remove(bmain, collection, ob, true);
 +                              }
 +                      }
 +              }
 +
 +              /* Convert layers to collections. */
 +              for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
 +                      do_version_layers_to_collections(bmain, scene);
 +              }
 +      }
 +
 +      if (!MAIN_VERSION_ATLEAST(bmain, 280, 0)) {
 +              for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) {
 +                      /* same render-layer as do_version_workspaces_after_lib_link will activate,
 +                       * so same layer as BKE_view_layer_default_view would return */
 +                      ViewLayer *layer = screen->scene->view_layers.first;
 +
 +                      for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
 +                              for (SpaceLink *space = sa->spacedata.first; space; space = space->next) {
 +                                      if (space->spacetype == SPACE_OUTLINER) {
 +                                              SpaceOops *soutliner = (SpaceOops *)space;
 +
 +                                              soutliner->outlinevis = SO_VIEW_LAYER;
 +
 +                                              if (BLI_listbase_count_at_most(&layer->layer_collections, 2) == 1) {
 +                                                      if (soutliner->treestore == NULL) {
 +                                                              soutliner->treestore = BLI_mempool_create(
 +                                                                      sizeof(TreeStoreElem), 1, 512, BLI_MEMPOOL_ALLOW_ITER);
 +                                                      }
 +
 +                                                      /* Create a tree store element for the collection. This is normally
 +                                                       * done in check_persistent (outliner_tree.c), but we need to access
 +                                                       * it here :/ (expand element if it's the only one) */
 +                                                      TreeStoreElem *tselem = BLI_mempool_calloc(soutliner->treestore);
 +                                                      tselem->type = TSE_LAYER_COLLECTION;
 +                                                      tselem->id = layer->layer_collections.first;
 +                                                      tselem->nr = tselem->used = 0;
 +                                                      tselem->flag &= ~TSE_CLOSED;
 +                                              }
 +                                      }
 +                              }
 +                      }
 +              }
 +      }
 +
 +      /* New workspace design */
 +      if (!MAIN_VERSION_ATLEAST(bmain, 280, 1)) {
 +              do_version_workspaces_after_lib_link(bmain);
 +      }
 +
 +      if (!MAIN_VERSION_ATLEAST(bmain, 280, 2)) {
 +              /* Cleanup any remaining SceneRenderLayer data for files that were created
 +               * with Blender 2.8 before the SceneRenderLayer > RenderLayer refactor. */
 +              for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
 +                      for (SceneRenderLayer *srl = scene->r.layers.first; srl; srl = srl->next) {
 +                              if (srl->prop) {
 +                                      IDP_FreeProperty(srl->prop);
 +                                      MEM_freeN(srl->prop);
 +                              }
 +                              BKE_freestyle_config_free(&srl->freestyleConfig, true);
 +                      }
 +                      BLI_freelistN(&scene->r.layers);
 +              }
 +      }
 +
 +      if (!MAIN_VERSION_ATLEAST(bmain, 280, 3)) {
 +              /* Due to several changes to particle RNA and draw code particles from older files may no longer
 +               * be visible. Here we correct this by setting a default draw size for those files. */
 +              for (Object *object = bmain->object.first; object; object = object->id.next) {
 +                      for (ParticleSystem *psys = object->particlesystem.first; psys; psys = psys->next) {
 +                              if (psys->part->draw_size == 0.0f) {
 +                                      psys->part->draw_size = 0.1f;
 +                              }
 +                      }
 +              }
 +      }
 +
 +      if (!MAIN_VERSION_ATLEAST(bmain, 280, 4)) {
 +              for (Object *object = bmain->object.first; object; object = object->id.next) {
 +#ifndef VERSION_280_SUBVERSION_4
 +                      /* If any object already has an initialized value for
 +                       * duplicator_visibility_flag it means we've already doversioned it.
 +                       * TODO(all) remove the VERSION_280_SUBVERSION_4 code once the subversion was bumped. */
 +                      if (object->duplicator_visibility_flag != 0) {
 +                              break;
 +                      }
 +#endif
 +                      if (object->particlesystem.first) {
 +                              object->duplicator_visibility_flag = OB_DUPLI_FLAG_VIEWPORT;
 +                              for (ParticleSystem *psys = object->particlesystem.first; psys; psys = psys->next) {
 +                                      if (psys->part->draw & PART_DRAW_EMITTER) {
 +                                              object->duplicator_visibility_flag |= OB_DUPLI_FLAG_RENDER;
 +#ifndef VERSION_280_SUBVERSION_4
 +                                              psys->part->draw &= ~PART_DRAW_EMITTER;
 +#else
 +                                              break;
 +#endif
 +                                      }
 +                              }
 +                      }
 +                      else if (object->transflag & OB_DUPLI) {
 +                              object->duplicator_visibility_flag = OB_DUPLI_FLAG_VIEWPORT;
 +                      }
 +                      else {
 +                              object->duplicator_visibility_flag = OB_DUPLI_FLAG_VIEWPORT | OB_DUPLI_FLAG_RENDER;
 +                      }
 +              }
 +      }
 +
 +      /* SpaceTime & SpaceLogic removal/replacing */
 +      if (!MAIN_VERSION_ATLEAST(bmain, 280, 9)) {
 +              const wmWindowManager *wm = bmain->wm.first;
 +              const Scene *scene = bmain->scene.first;
 +
 +              if (wm != NULL) {
 +                      /* Action editors need a scene for creation. First, update active
 +                       * screens using the active scene of the window they're displayed in.
 +                       * Next, update remaining screens using first scene in main listbase. */
 +
 +                      for (wmWindow *win = wm->windows.first; win; win = win->next) {
 +                              const bScreen *screen = BKE_workspace_active_screen_get(win->workspace_hook);
 +                              for (ScrArea *area = screen->areabase.first; area; area = area->next) {
 +                                      if (ELEM(area->butspacetype, SPACE_TIME, SPACE_LOGIC)) {
 +                                              do_version_area_change_space_to_space_action(area, win->scene);
 +
 +                                              /* Don't forget to unset! */
 +                                              area->butspacetype = SPACE_EMPTY;
 +                                      }
 +                              }
 +                      }
 +              }
 +              if (scene != NULL) {
 +                      for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) {
 +                              for (ScrArea *area = screen->areabase.first; area; area = area->next) {
 +                                      if (ELEM(area->butspacetype, SPACE_TIME, SPACE_LOGIC)) {
 +                                              /* Areas that were already handled won't be handled again */
 +                                              do_version_area_change_space_to_space_action(area, scene);
 +
 +                                              /* Don't forget to unset! */
 +                                              area->butspacetype = SPACE_EMPTY;
 +                                      }
 +                              }
 +                      }
 +              }
 +      }
 +
 +#ifdef USE_COLLECTION_COMPAT_28
 +      if (use_collection_compat_28 && !MAIN_VERSION_ATLEAST(bmain, 280, 14)) {
 +              for (Collection *group = bmain->collection.first; group; group = group->id.next) {
 +                      do_version_group_collection_to_collection(bmain, group);
 +              }
 +
 +              for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
 +                      do_version_scene_collection_to_collection(bmain, scene);
 +              }
 +      }
 +#endif
 +
 +}
 +
 +/* NOTE: this version patch is intended for versions < 2.52.2, but was initially introduced in 2.27 already.
 + *       But in 2.79 another case generating non-unique names was discovered (see T55668, involving Meta strips)... */
 +static void do_versions_seq_unique_name_all_strips(Scene *sce, ListBase *seqbasep)
 +{
 +      for (Sequence *seq = seqbasep->first; seq != NULL; seq = seq->next) {
 +              BKE_sequence_base_unique_name_recursive(&sce->ed->seqbase, seq);
 +              if (seq->seqbase.first != NULL) {
 +                      do_versions_seq_unique_name_all_strips(sce, &seq->seqbase);
 +              }
 +      }
 +}
 +
 +void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
 +{
 +      bool use_collection_compat_28 = true;
 +
 +      if (!MAIN_VERSION_ATLEAST(bmain, 280, 0)) {
 +              use_collection_compat_28 = false;
 +
 +              for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
 +                      scene->r.gauss = 1.5f;
 +              }
 +      }
 +
 +      if (!MAIN_VERSION_ATLEAST(bmain, 280, 1)) {
 +              if (!DNA_struct_elem_find(fd->filesdna, "Lamp", "float", "bleedexp")) {
 +                      for (Lamp *la = bmain->lamp.first; la; la = la->id.next) {
 +                              la->bleedexp = 2.5f;
 +                      }
 +              }
 +
 +              if (!DNA_struct_elem_find(fd->filesdna, "GPUDOFSettings", "float", "ratio")) {
 +                      for (Camera *ca = bmain->camera.first; ca; ca = ca->id.next) {
 +                              ca->gpu_dof.ratio = 1.0f;
 +                      }
 +              }
 +
 +              /* MTexPoly now removed. */
 +              if (DNA_struct_find(fd->filesdna, "MTexPoly")) {
 +                      const int cd_mtexpoly = 15;  /* CD_MTEXPOLY, deprecated */
 +                      for (Mesh *me = bmain->mesh.first; me; me = me->id.next) {
 +                              /* If we have UV's, so this file will have MTexPoly layers too! */
 +                              if (me->mloopuv != NULL) {
 +                                      CustomData_update_typemap(&me->pdata);
 +                                      CustomData_free_layers(&me->pdata, cd_mtexpoly, me->totpoly);
 +                                      BKE_mesh_update_customdata_pointers(me, false);
 +                              }
 +                      }
 +              }
 +      }
 +
 +      if (!MAIN_VERSION_ATLEAST(bmain, 280, 2)) {
 +              if (!DNA_struct_elem_find(fd->filesdna, "Lamp", "float", "cascade_max_dist")) {
 +                      for (Lamp *la = bmain->lamp.first; la; la = la->id.next) {
 +                              la->cascade_max_dist = 1000.0f;
 +                              la->cascade_count = 4;
 +                              la->cascade_exponent = 0.8f;
 +                              la->cascade_fade = 0.1f;
 +                      }
 +              }
 +
 +              if (!DNA_struct_elem_find(fd->filesdna, "Lamp", "float", "contact_dist")) {
 +                      for (Lamp *la = bmain->lamp.first; la; la = la->id.next) {
 +                              la->contact_dist = 0.2f;
 +                              la->contact_bias = 0.03f;
 +                              la->contact_spread = 0.2f;
 +                              la->contact_thickness = 0.2f;
 +                      }
 +              }
 +
 +              if (!DNA_struct_elem_find(fd->filesdna, "LightProbe", "float", "vis_bias")) {
 +                      for (LightProbe *probe = bmain->lightprobe.first; probe; probe = probe->id.next) {
 +                              probe->vis_bias = 1.0f;
 +                              probe->vis_blur = 0.2f;
 +                      }
 +              }
 +
 +              typedef enum eNTreeDoVersionErrors {
 +                      NTREE_DOVERSION_NO_ERROR = 0,
 +                      NTREE_DOVERSION_NEED_OUTPUT = (1 << 0),
 +                      NTREE_DOVERSION_TRANSPARENCY_EMISSION = (1 << 1),
 +              } eNTreeDoVersionErrors;
 +
 +              /* Eevee shader nodes renamed because of the output node system.
 +               * Note that a new output node is not being added here, because it would be overkill
 +               * to handle this case in lib_verify_nodetree.
 +               *
 +               * Also, metallic node is now unified into the principled node. */
 +              eNTreeDoVersionErrors error = NTREE_DOVERSION_NO_ERROR;
 +
 +              FOREACH_NODETREE(bmain, ntree, id) {
 +                      if (ntree->type == NTREE_SHADER) {
 +                              for (bNode *node = ntree->nodes.first; node; node = node->next) {
 +                                      if (node->type == 194 /* SH_NODE_EEVEE_METALLIC */ &&
 +                                          STREQ(node->idname, "ShaderNodeOutputMetallic"))
 +                                      {
 +                                              BLI_strncpy(node->idname, "ShaderNodeEeveeMetallic", sizeof(node->idname));
 +                                              error |= NTREE_DOVERSION_NEED_OUTPUT;
 +                                      }
 +
 +                                      else if (node->type == SH_NODE_EEVEE_SPECULAR && STREQ(node->idname, "ShaderNodeOutputSpecular")) {
 +                                              BLI_strncpy(node->idname, "ShaderNodeEeveeSpecular", sizeof(node->idname));
 +                                              error |= NTREE_DOVERSION_NEED_OUTPUT;
 +                                      }
 +
 +                                      else if (node->type == 196 /* SH_NODE_OUTPUT_EEVEE_MATERIAL */ &&
 +                                               STREQ(node->idname, "ShaderNodeOutputEeveeMaterial"))
 +                                      {
 +                                              node->type = SH_NODE_OUTPUT_MATERIAL;
 +                                              BLI_strncpy(node->idname, "ShaderNodeOutputMaterial", sizeof(node->idname));
 +                                      }
 +
 +                                      else if (node->type == 194 /* SH_NODE_EEVEE_METALLIC */ &&
 +                                               STREQ(node->idname, "ShaderNodeEeveeMetallic"))
 +                                      {
 +                                              node->type = SH_NODE_BSDF_PRINCIPLED;
 +                                              BLI_strncpy(node->idname, "ShaderNodeBsdfPrincipled", sizeof(node->idname));
 +                                              node->custom1 = SHD_GLOSSY_MULTI_GGX;
 +                                              error |= NTREE_DOVERSION_TRANSPARENCY_EMISSION;
 +                                      }
 +                              }
 +                      }
 +              } FOREACH_NODETREE_END
 +
 +                      if (error & NTREE_DOVERSION_NEED_OUTPUT) {
 +                              BKE_report(fd->reports, RPT_ERROR, "Eevee material conversion problem. Error in console");
 +                              printf("You need to connect Principled and Eevee Specular shader nodes to new material output nodes.\n");
 +                      }
 +
 +              if (error & NTREE_DOVERSION_TRANSPARENCY_EMISSION) {
 +                      BKE_report(fd->reports, RPT_ERROR, "Eevee material conversion problem. Error in console");
 +                      printf("You need to combine transparency and emission shaders to the converted Principled shader nodes.\n");
 +              }
 +
 +#ifdef USE_COLLECTION_COMPAT_28
 +              if (use_collection_compat_28 &&
 +                  (DNA_struct_elem_find(fd->filesdna, "ViewLayer", "FreestyleConfig", "freestyle_config") == false) &&
 +                  DNA_struct_elem_find(fd->filesdna, "Scene", "ListBase", "view_layers"))
 +              {
 +                      for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
 +                              ViewLayer *view_layer;
 +                              for (view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) {
 +                                      view_layer->flag |= VIEW_LAYER_FREESTYLE;
 +                                      view_layer->layflag = 0x7FFF;   /* solid ztra halo edge strand */
 +                                      view_layer->passflag = SCE_PASS_COMBINED | SCE_PASS_Z;
 +                                      view_layer->pass_alpha_threshold = 0.5f;
 +                                      BKE_freestyle_config_init(&view_layer->freestyle_config);
 +                              }
 +                      }
 +              }
 +#endif
 +
 +              {
 +                      /* Grease pencil sculpt and paint cursors */
 +                      if (!DNA_struct_elem_find(fd->filesdna, "GP_BrushEdit_Settings", "int", "weighttype")) {
 +                              for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
 +                                      /* sculpt brushes */
 +                                      GP_BrushEdit_Settings *gset = &scene->toolsettings->gp_sculpt;
 +                                      if (gset) {
 +                                              gset->weighttype = GP_EDITBRUSH_TYPE_WEIGHT;
 +                                      }
 +                              }
 +                      }
 +
 +                      {
 +                              float curcolor_add[3], curcolor_sub[3];
 +                              ARRAY_SET_ITEMS(curcolor_add, 1.0f, 0.6f, 0.6f);
 +                              ARRAY_SET_ITEMS(curcolor_sub, 0.6f, 0.6f, 1.0f);
 +                              GP_EditBrush_Data *gp_brush;
 +
 +                              for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
 +                                      ToolSettings *ts = scene->toolsettings;
 +                                      /* sculpt brushes */
 +                                      GP_BrushEdit_Settings *gset = &ts->gp_sculpt;
 +                                      for (int i = 0; i < TOT_GP_EDITBRUSH_TYPES; ++i) {
 +                                              gp_brush = &gset->brush[i];
 +                                              gp_brush->flag |= GP_EDITBRUSH_FLAG_ENABLE_CURSOR;
 +                                              copy_v3_v3(gp_brush->curcolor_add, curcolor_add);
 +                                              copy_v3_v3(gp_brush->curcolor_sub, curcolor_sub);
 +                                      }
 +                              }
 +                      }
 +
 +                      /* Init grease pencil edit line color */
 +                      if (!DNA_struct_elem_find(fd->filesdna, "bGPdata", "float", "line_color[4]")) {
 +                              for (bGPdata *gpd = bmain->gpencil.first; gpd; gpd = gpd->id.next) {
 +                                      ARRAY_SET_ITEMS(gpd->line_color, 0.6f, 0.6f, 0.6f, 0.5f);
 +                              }
 +                      }
 +
 +                      /* Init grease pencil pixel size factor */
 +                      if (!DNA_struct_elem_find(fd->filesdna, "bGPDdata", "int", "pixfactor")) {
 +                              for (bGPdata *gpd = bmain->gpencil.first; gpd; gpd = gpd->id.next) {
 +                                      gpd->pixfactor = GP_DEFAULT_PIX_FACTOR;
 +                              }
 +                      }
 +
 +                      /* Grease pencil multiframe falloff curve */
 +                      if (!DNA_struct_elem_find(fd->filesdna, "GP_BrushEdit_Settings", "CurveMapping", "cur_falloff")) {
 +                              for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
 +                                      /* sculpt brushes */
 +                                      GP_BrushEdit_Settings *gset = &scene->toolsettings->gp_sculpt;
 +                                      if ((gset) && (gset->cur_falloff == NULL)) {
 +                                              gset->cur_falloff = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
 +                                              curvemapping_initialize(gset->cur_falloff);
 +                                              curvemap_reset(gset->cur_falloff->cm,
 +                                                      &gset->cur_falloff->clipr,
 +                                                      CURVE_PRESET_GAUSS,
 +                                                      CURVEMAP_SLOPE_POSITIVE);
 +                                      }
 +                              }
 +                      }
 +              }
 +      }
 +
 +#ifdef USE_COLLECTION_COMPAT_28
 +      if (use_collection_compat_28 && !MAIN_VERSION_ATLEAST(bmain, 280, 3)) {
 +              for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
 +                      ViewLayer *view_layer;
 +                      for (view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) {
 +                              do_version_view_layer_visibility(view_layer);
 +                      }
 +              }
 +
 +              for (Collection *group = bmain->collection.first; group; group = group->id.next) {
 +                      if (group->view_layer != NULL) {
 +                              do_version_view_layer_visibility(group->view_layer);
 +                      }
 +              }
 +      }
 +#endif
 +
 +      if (!MAIN_VERSION_ATLEAST(bmain, 280, 3)) {
 +              /* init grease pencil grids and paper */
 +              if (!DNA_struct_elem_find(fd->filesdna, "gp_paper_opacity", "float", "gpencil_paper_color[3]")) {
 +                      for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) {
 +                              for (ScrArea *area = screen->areabase.first; area; area = area->next) {
 +                                      for (SpaceLink *sl = area->spacedata.first; sl; sl = sl->next) {
 +                                              if (sl->spacetype == SPACE_VIEW3D) {
 +                                                      View3D *v3d = (View3D *)sl;
 +                                                      v3d->overlay.gpencil_grid_scale = 1.0f; // Scale
 +                                                      v3d->overlay.gpencil_grid_lines = GP_DEFAULT_GRID_LINES; // NUmber of lines
 +                                                      v3d->overlay.gpencil_paper_opacity = 0.5f;
 +                                                      v3d->overlay.gpencil_grid_axis = V3D_GP_GRID_AXIS_Y;
 +                                                      v3d->overlay.gpencil_grid_opacity = 0.9f;
 +                                              }
 +                                      }
 +                              }
 +                      }
 +              }
 +      }
 +
 +      if (!MAIN_VERSION_ATLEAST(bmain, 280, 6)) {
 +              if (DNA_struct_elem_find(fd->filesdna, "SpaceOops", "int", "filter") == false) {
 +                      bScreen *sc;
 +                      ScrArea *sa;
 +                      SpaceLink *sl;
 +
 +                      /* Update files using invalid (outdated) outlinevis Outliner values. */
 +                      for (sc = bmain->screen.first; sc; sc = sc->id.next) {
 +                              for (sa = sc->areabase.first; sa; sa = sa->next) {
 +                                      for (sl = sa->spacedata.first; sl; sl = sl->next) {
 +                                              if (sl->spacetype == SPACE_OUTLINER) {
 +                                                      SpaceOops *so = (SpaceOops *)sl;
 +
 +                                                      if (!ELEM(so->outlinevis,
 +                                                                SO_SCENES,
 +                                                                SO_LIBRARIES,
 +                                                                SO_SEQUENCE,
 +                                                                SO_DATA_API,
 +                                                                SO_ID_ORPHANS))
 +                                                      {
 +                                                              so->outlinevis = SO_VIEW_LAYER;
 +                                                      }
 +                                              }
 +                                      }
 +                              }
 +                      }
 +              }
 +
 +              if (!DNA_struct_elem_find(fd->filesdna, "LightProbe", "float", "intensity")) {
 +                      for (LightProbe *probe = bmain->lightprobe.first; probe; probe = probe->id.next) {
 +                              probe->intensity = 1.0f;
 +                      }
 +              }
 +
 +              for (Object *ob = bmain->object.first; ob; ob = ob->id.next) {
 +                      bConstraint *con, *con_next;
 +                      con = ob->constraints.first;
 +                      while (con) {
 +                              con_next = con->next;
 +                              if (con->type == 17) { /* CONSTRAINT_TYPE_RIGIDBODYJOINT */
 +                                      BLI_remlink(&ob->constraints, con);
 +                                      BKE_constraint_free_data(con);
 +                                      MEM_freeN(con);
 +                              }
 +                              con = con_next;
 +                      }
 +              }
 +
 +              if (!DNA_struct_elem_find(fd->filesdna, "Scene", "int", "orientation_index_custom")) {
 +                      for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
 +                              scene->orientation_index_custom = -1;
 +                      }
 +              }
 +
 +              for (bScreen *sc = bmain->screen.first; sc; sc = sc->id.next) {
 +                      for (ScrArea *sa = sc->areabase.first; sa; sa = sa->next) {
 +                              for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
 +                                      if (sl->spacetype == SPACE_VIEW3D) {
 +                                              View3D *v3d = (View3D *)sl;
 +                                              v3d->shading.light = V3D_LIGHTING_STUDIO;
 +                                              v3d->shading.flag |= V3D_SHADING_OBJECT_OUTLINE;
 +
 +                                              /* Assume (demo) files written with 2.8 want to show
 +                                               * Eevee renders in the viewport. */
 +                                              if (MAIN_VERSION_ATLEAST(bmain, 280, 0)) {
 +                                                      v3d->drawtype = OB_MATERIAL;
 +                                              }
 +                                      }
 +                              }
 +                      }
 +              }
 +      }
 +
 +      if (!MAIN_VERSION_ATLEAST(bmain, 280, 7)) {
 +              /* Render engine storage moved elsewhere and back during 2.8
 +               * development, we assume any files saved in 2.8 had Eevee set
 +               * as scene render engine. */
 +              if (MAIN_VERSION_ATLEAST(bmain, 280, 0)) {
 +                      for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
 +                              BLI_strncpy(scene->r.engine, RE_engine_id_BLENDER_EEVEE, sizeof(scene->r.engine));
 +                      }
 +              }
 +      }
 +
 +      if (!MAIN_VERSION_ATLEAST(bmain, 280, 8)) {
 +              /* Blender Internal removal */
 +              for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
 +                      if (STREQ(scene->r.engine, "BLENDER_RENDER") ||
 +                          STREQ(scene->r.engine, "BLENDER_GAME"))
 +                      {
 +                              BLI_strncpy(scene->r.engine, RE_engine_id_BLENDER_EEVEE, sizeof(scene->r.engine));
 +                      }
 +
 +                      scene->r.bake_mode = 0;
 +              }
 +
 +              for (Tex *tex = bmain->tex.first; tex; tex = tex->id.next) {
 +                      /* Removed envmap, pointdensity, voxeldata, ocean textures. */
 +                      if (ELEM(tex->type, 10, 14, 15, 16)) {
 +                              tex->type = 0;
 +                      }
 +              }
 +
 +      }
 +
 +      if (!MAIN_VERSION_ATLEAST(bmain, 280, 11)) {
 +
 +              /* Remove info editor, but only if at the top of the window. */
 +              for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) {
 +                      /* Calculate window width/height from screen vertices */
 +                      int win_width = 0, win_height = 0;
 +                      for (ScrVert *vert = screen->vertbase.first; vert; vert = vert->next) {
 +                              win_width  = MAX2(win_width, vert->vec.x);
 +                              win_height = MAX2(win_height, vert->vec.y);
 +                      }
 +
 +                      for (ScrArea *area = screen->areabase.first, *area_next; area; area = area_next) {
 +                              area_next = area->next;
 +
 +                              if (area->spacetype == SPACE_INFO) {
 +                                      if ((area->v2->vec.y == win_height) && (area->v1->vec.x == 0) && (area->v4->vec.x == win_width)) {
 +                                              BKE_screen_area_free(area);
 +
 +                                              BLI_remlink(&screen->areabase, area);
 +
 +                                              BKE_screen_remove_double_scredges(screen);
 +                                              BKE_screen_remove_unused_scredges(screen);
 +                                              BKE_screen_remove_unused_scrverts(screen);
 +
 +                                              MEM_freeN(area);
 +                                      }
 +                              }
 +                              /* AREA_TEMP_INFO is deprecated from now on, it should only be set for info areas
 +                               * which are deleted above, so don't need to unset it. Its slot/bit can be reused */
 +                      }
 +              }
 +      }
 +
 +      if (!MAIN_VERSION_ATLEAST(bmain, 280, 11)) {
 +              for (Lamp *lamp = bmain->lamp.first; lamp; lamp = lamp->id.next) {
 +                      if (lamp->mode & (1 << 13)) { /* LA_SHAD_RAY */
 +                              lamp->mode |= LA_SHADOW;
 +                              lamp->mode &= ~(1 << 13);
 +                      }
 +              }
 +      }
 +
 +      if (!MAIN_VERSION_ATLEAST(bmain, 280, 12)) {
 +              /* Remove tool property regions. */
 +              for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) {
 +                      for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
 +                              for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
 +                                      if (ELEM(sl->spacetype, SPACE_VIEW3D, SPACE_CLIP)) {
 +                                              ListBase *regionbase = (sl == sa->spacedata.first) ? &sa->regionbase : &sl->regionbase;
 +
 +                                              for (ARegion *region = regionbase->first, *region_next; region; region = region_next) {
 +                                                      region_next = region->next;
 +
 +                                                      if (region->regiontype == RGN_TYPE_TOOL_PROPS) {
 +                                                              BKE_area_region_free(NULL, region);
 +                                                              BLI_freelinkN(regionbase, region);
 +                                                      }
 +                                              }
 +                                      }
 +                              }
 +                      }
 +              }
 +      }
 +
 +      if (!MAIN_VERSION_ATLEAST(bmain, 280, 13)) {
 +              /* Initialize specular factor. */
 +              if (!DNA_struct_elem_find(fd->filesdna, "Lamp", "float", "spec_fac")) {
 +                      for (Lamp *la = bmain->lamp.first; la; la = la->id.next) {
 +                              la->spec_fac = 1.0f;
 +                      }
 +              }
 +
 +              /* Initialize new view3D options. */
 +              for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) {
 +                      for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
 +                              for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
 +                                      if (sl->spacetype == SPACE_VIEW3D) {
 +                                              View3D *v3d = (View3D *)sl;
 +                                              v3d->shading.light = V3D_LIGHTING_STUDIO;
 +                                              v3d->shading.color_type = V3D_SHADING_MATERIAL_COLOR;
 +                                              copy_v3_fl(v3d->shading.single_color, 0.8f);
 +                                              v3d->shading.shadow_intensity = 0.5;
 +
 +                                              v3d->overlay.backwire_opacity = 0.5f;
 +                                              v3d->overlay.normals_length = 0.1f;
 +                                              v3d->overlay.flag = 0;
 +                                      }
 +                              }
 +                      }
 +              }
 +
 +              if (!DNA_struct_find(fd->filesdna, "View3DCursor")) {
 +                      for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
 +                              unit_qt(scene->cursor.rotation);
 +                      }
 +                      for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) {
 +                              for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
 +                                      for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
 +                                              if (sl->spacetype == SPACE_VIEW3D) {
 +                                                      View3D *v3d = (View3D *)sl;
 +                                                      unit_qt(v3d->cursor.rotation);
 +                                              }
 +                                      }
 +                              }
 +                      }
 +              }
 +      }
 +
 +      if (!MAIN_VERSION_ATLEAST(bmain, 280, 14)) {
 +              if (!DNA_struct_elem_find(fd->filesdna, "Scene", "SceneDisplay", "display")) {
 +                      /* Initialize new scene.SceneDisplay */
 +                      for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
 +                              copy_v3_v3(scene->display.light_direction, (float[3]){-M_SQRT1_3, -M_SQRT1_3, M_SQRT1_3});
 +                      }
 +              }
 +              if (!DNA_struct_elem_find(fd->filesdna, "SceneDisplay", "float", "shadow_shift")) {
 +                      for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
 +                              scene->display.shadow_shift = 0.1;
 +                      }
 +              }
 +
 +              if (!DNA_struct_elem_find(fd->filesdna, "Object", "ObjectDisplay", "display")) {
 +                      /* Initialize new object.ObjectDisplay */
 +                      for (Object *ob = bmain->object.first; ob; ob = ob->id.next) {
 +                              ob->display.flag = OB_SHOW_SHADOW;
 +                      }
 +              }
 +
 +              if (!DNA_struct_elem_find(fd->filesdna, "ToolSettings", "char", "transform_pivot_point")) {
 +                      for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
 +                              scene->toolsettings->transform_pivot_point = V3D_AROUND_CENTER_MEAN;
 +                      }
 +              }
 +
 +              if (!DNA_struct_find(fd->filesdna, "SceneEEVEE")) {
 +                      for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
 +                              /* First set the default for all the properties. */
 +
 +                              scene->eevee.gi_diffuse_bounces = 3;
 +                              scene->eevee.gi_cubemap_resolution = 512;
 +                              scene->eevee.gi_visibility_resolution = 32;
 +
 +                              scene->eevee.taa_samples = 16;
 +                              scene->eevee.taa_render_samples = 64;
 +
 +                              scene->eevee.sss_samples = 7;
 +                              scene->eevee.sss_jitter_threshold = 0.3f;
 +
 +                              scene->eevee.ssr_quality = 0.25f;
 +                              scene->eevee.ssr_max_roughness = 0.5f;
 +                              scene->eevee.ssr_thickness = 0.2f;
 +                              scene->eevee.ssr_border_fade = 0.075f;
 +                              scene->eevee.ssr_firefly_fac = 10.0f;
 +
 +                              scene->eevee.volumetric_start = 0.1f;
 +                              scene->eevee.volumetric_end = 100.0f;
 +                              scene->eevee.volumetric_tile_size = 8;
 +                              scene->eevee.volumetric_samples = 64;
 +                              scene->eevee.volumetric_sample_distribution = 0.8f;
 +                              scene->eevee.volumetric_light_clamp = 0.0f;
 +                              scene->eevee.volumetric_shadow_samples = 16;
 +
 +                              scene->eevee.gtao_distance = 0.2f;
 +                              scene->eevee.gtao_factor = 1.0f;
 +                              scene->eevee.gtao_quality = 0.25f;
 +
 +                              scene->eevee.bokeh_max_size = 100.0f;
 +                              scene->eevee.bokeh_threshold = 1.0f;
 +
 +                              copy_v3_fl(scene->eevee.bloom_color, 1.0f);
 +                              scene->eevee.bloom_threshold = 0.8f;
 +                              scene->eevee.bloom_knee = 0.5f;
 +                              scene->eevee.bloom_intensity = 0.8f;
 +                              scene->eevee.bloom_radius = 6.5f;
 +                              scene->eevee.bloom_clamp = 1.0f;
 +
 +                              scene->eevee.motion_blur_samples = 8;
 +                              scene->eevee.motion_blur_shutter = 1.0f;
 +
 +                              scene->eevee.shadow_method = SHADOW_ESM;
 +                              scene->eevee.shadow_cube_size = 512;
 +                              scene->eevee.shadow_cascade_size = 1024;
 +
 +                              scene->eevee.flag =
 +                                      SCE_EEVEE_VOLUMETRIC_LIGHTS |
 +                                      SCE_EEVEE_GTAO_BENT_NORMALS |
 +                                      SCE_EEVEE_GTAO_BOUNCE |
 +                                      SCE_EEVEE_TAA_REPROJECTION |
 +                                      SCE_EEVEE_SSR_HALF_RESOLUTION;
 +
 +
 +                              /* If the file is pre-2.80 move on. */
 +                              if (scene->layer_properties == NULL) {
 +                                      continue;
 +                              }
 +
 +                              /* Now we handle eventual properties that may be set in the file. */
 +#define EEVEE_GET_BOOL(_props, _name, _flag) \
 +                              { \
 +                                      IDProperty *_idprop = IDP_GetPropertyFromGroup(_props, #_name); \
 +                                      if (_idprop != NULL) { \
 +                                              const int _value = IDP_Int(_idprop); \
 +                                              if (_value) { \
 +                                                      scene->eevee.flag |= _flag; \
 +                                              } \
 +                                              else { \
 +                                                      scene->eevee.flag &= ~_flag; \
 +                                              } \
 +                                      } \
 +                              }
 +
 +#define EEVEE_GET_INT(_props, _name) \
 +                              { \
 +                                      IDProperty *_idprop = IDP_GetPropertyFromGroup(_props, #_name); \
 +                                      if (_idprop != NULL) { \
 +                                              scene->eevee._name = IDP_Int(_idprop); \
 +                                      } \
 +                              }
 +
 +#define EEVEE_GET_FLOAT(_props, _name) \
 +                              { \
 +                                      IDProperty *_idprop = IDP_GetPropertyFromGroup(_props, #_name); \
 +                                      if (_idprop != NULL) { \
 +                                              scene->eevee._name = IDP_Float(_idprop); \
 +                                      } \
 +                              }
 +
 +#define EEVEE_GET_FLOAT_ARRAY(_props, _name, _length) \
 +                              { \
 +                                      IDProperty *_idprop = IDP_GetPropertyFromGroup(_props, #_name); \
 +                                      if (_idprop != NULL) { \
 +                                              const float *_values = IDP_Array(_idprop); \
 +                                              for (int _i = 0; _i < _length; _i++) { \
 +                                                      scene->eevee._name [_i] = _values[_i]; \
 +                                              } \
 +                                      } \
 +                              }
 +
 +                              IDProperty *props = IDP_GetPropertyFromGroup(scene->layer_properties, RE_engine_id_BLENDER_EEVEE);
 +                              EEVEE_GET_BOOL(props, volumetric_enable, SCE_EEVEE_VOLUMETRIC_ENABLED);
 +                              EEVEE_GET_BOOL(props, volumetric_lights, SCE_EEVEE_VOLUMETRIC_LIGHTS);
 +                              EEVEE_GET_BOOL(props, volumetric_shadows, SCE_EEVEE_VOLUMETRIC_SHADOWS);
 +                              EEVEE_GET_BOOL(props, gtao_enable, SCE_EEVEE_GTAO_ENABLED);
 +                              EEVEE_GET_BOOL(props, gtao_use_bent_normals, SCE_EEVEE_GTAO_BENT_NORMALS);
 +                              EEVEE_GET_BOOL(props, gtao_bounce, SCE_EEVEE_GTAO_BOUNCE);
 +                              EEVEE_GET_BOOL(props, dof_enable, SCE_EEVEE_DOF_ENABLED);
 +                              EEVEE_GET_BOOL(props, bloom_enable, SCE_EEVEE_BLOOM_ENABLED);
 +                              EEVEE_GET_BOOL(props, motion_blur_enable, SCE_EEVEE_MOTION_BLUR_ENABLED);
 +                              EEVEE_GET_BOOL(props, shadow_high_bitdepth, SCE_EEVEE_SHADOW_HIGH_BITDEPTH);
 +                              EEVEE_GET_BOOL(props, taa_reprojection, SCE_EEVEE_TAA_REPROJECTION);
 +                              EEVEE_GET_BOOL(props, sss_enable, SCE_EEVEE_SSS_ENABLED);
 +                              EEVEE_GET_BOOL(props, sss_separate_albedo, SCE_EEVEE_SSS_SEPARATE_ALBEDO);
 +                              EEVEE_GET_BOOL(props, ssr_enable, SCE_EEVEE_SSR_ENABLED);
 +                              EEVEE_GET_BOOL(props, ssr_refraction, SCE_EEVEE_SSR_REFRACTION);
 +                              EEVEE_GET_BOOL(props, ssr_halfres, SCE_EEVEE_SSR_HALF_RESOLUTION);
 +
 +                              EEVEE_GET_INT(props, gi_diffuse_bounces);
 +                              EEVEE_GET_INT(props, gi_diffuse_bounces);
 +                              EEVEE_GET_INT(props, gi_cubemap_resolution);
 +                              EEVEE_GET_INT(props, gi_visibility_resolution);
 +
 +                              EEVEE_GET_INT(props, taa_samples);
 +                              EEVEE_GET_INT(props, taa_render_samples);
 +
 +                              EEVEE_GET_INT(props, sss_samples);
 +                              EEVEE_GET_FLOAT(props, sss_jitter_threshold);
 +
 +                              EEVEE_GET_FLOAT(props, ssr_quality);
 +                              EEVEE_GET_FLOAT(props, ssr_max_roughness);
 +                              EEVEE_GET_FLOAT(props, ssr_thickness);
 +                              EEVEE_GET_FLOAT(props, ssr_border_fade);
 +                              EEVEE_GET_FLOAT(props, ssr_firefly_fac);
 +
 +                              EEVEE_GET_FLOAT(props, volumetric_start);
 +                              EEVEE_GET_FLOAT(props, volumetric_end);
 +                              EEVEE_GET_INT(props, volumetric_tile_size);
 +                              EEVEE_GET_INT(props, volumetric_samples);
 +                              EEVEE_GET_FLOAT(props, volumetric_sample_distribution);
 +                              EEVEE_GET_FLOAT(props, volumetric_light_clamp);
 +                              EEVEE_GET_INT(props, volumetric_shadow_samples);
 +
 +                              EEVEE_GET_FLOAT(props, gtao_distance);
 +                              EEVEE_GET_FLOAT(props, gtao_factor);
 +                              EEVEE_GET_FLOAT(props, gtao_quality);
 +
 +                              EEVEE_GET_FLOAT(props, bokeh_max_size);
 +                              EEVEE_GET_FLOAT(props, bokeh_threshold);
 +
 +                              EEVEE_GET_FLOAT_ARRAY(props, bloom_color, 3);
 +                              EEVEE_GET_FLOAT(props, bloom_threshold);
 +                              EEVEE_GET_FLOAT(props, bloom_knee);
 +                              EEVEE_GET_FLOAT(props, bloom_intensity);
 +                              EEVEE_GET_FLOAT(props, bloom_radius);
 +                              EEVEE_GET_FLOAT(props, bloom_clamp);
 +
 +                              EEVEE_GET_INT(props, motion_blur_samples);
 +                              EEVEE_GET_FLOAT(props, motion_blur_shutter);
 +
 +                              EEVEE_GET_INT(props, shadow_method);
 +                              EEVEE_GET_INT(props, shadow_cube_size);
 +                              EEVEE_GET_INT(props, shadow_cascade_size);
 +
 +                              /* Cleanup. */
 +                              IDP_FreeProperty(scene->layer_properties);
 +                              MEM_freeN(scene->layer_properties);
 +                              scene->layer_properties = NULL;
 +
 +#undef EEVEE_GET_FLOAT_ARRAY
 +#undef EEVEE_GET_FLOAT
 +#undef EEVEE_GET_INT
 +#undef EEVEE_GET_BOOL
 +                      }
 +              }
 +
 +
 +              if (!MAIN_VERSION_ATLEAST(bmain, 280, 15)) {
 +                      for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
 +                              scene->display.matcap_ssao_distance = 0.2f;
 +                              scene->display.matcap_ssao_attenuation = 1.0f;
 +                              scene->display.matcap_ssao_samples = 16;
 +                      }
 +
 +                      for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) {
 +                              for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
 +                                      for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
 +                                              if (sl->spacetype == SPACE_OUTLINER) {
 +                                                      SpaceOops *soops = (SpaceOops *)sl;
 +                                                      soops->filter_id_type = ID_GR;
 +                                                      soops->outlinevis = SO_VIEW_LAYER;
 +                                              }
 +                                      }
 +                              }
 +                      }
 +
 +                      for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
 +                              switch (scene->toolsettings->snap_mode) {
 +                                      case 0: scene->toolsettings->snap_mode = SCE_SNAP_MODE_INCREMENT; break;
 +                                      case 1: scene->toolsettings->snap_mode = SCE_SNAP_MODE_VERTEX   ; break;
 +                                      case 2: scene->toolsettings->snap_mode = SCE_SNAP_MODE_EDGE     ; break;
 +                                      case 3: scene->toolsettings->snap_mode = SCE_SNAP_MODE_FACE     ; break;
 +                                      case 4: scene->toolsettings->snap_mode = SCE_SNAP_MODE_VOLUME   ; break;
 +                              }
 +                              switch (scene->toolsettings->snap_node_mode) {
 +                                      case 5: scene->toolsettings->snap_node_mode = SCE_SNAP_MODE_NODE_X; break;
 +                                      case 6: scene->toolsettings->snap_node_mode = SCE_SNAP_MODE_NODE_Y; break;
 +                                      case 7: scene->toolsettings->snap_node_mode = SCE_SNAP_MODE_NODE_X | SCE_SNAP_MODE_NODE_Y; break;
 +                                      case 8: scene->toolsettings->snap_node_mode = SCE_SNAP_MODE_GRID  ; break;
 +                              }
 +                              switch (scene->toolsettings->snap_uv_mode) {
 +                                      case 0: scene->toolsettings->snap_uv_mode = SCE_SNAP_MODE_INCREMENT; break;
 +                                      case 1: scene->toolsettings->snap_uv_mode = SCE_SNAP_MODE_VERTEX   ; break;
 +                              }
 +                      }
 +
 +                      ParticleSettings *part;
 +                      for (part = bmain->particle.first; part; part = part->id.next) {
 +                              part->shape_flag = PART_SHAPE_CLOSE_TIP;
 +                              part->shape = 0.0f;
 +                              part->rad_root = 1.0f;
 +                              part->rad_tip = 0.0f;
 +                              part->rad_scale = 0.01f;
 +                      }
 +              }
 +
 +      }
 +
 +      if (!MAIN_VERSION_ATLEAST(bmain, 280, 18)) {
 +              if (!DNA_struct_elem_find(fd->filesdna, "Material", "float", "roughness")) {
 +                      for (Material *mat = bmain->mat.first; mat; mat = mat->id.next) {
 +                              if (mat->use_nodes) {
 +                                      if (MAIN_VERSION_ATLEAST(bmain, 280, 0)) {
 +                                              mat->roughness = mat->gloss_mir;
 +                                      }
 +                                      else {
 +                                              mat->roughness = 0.25f;
 +                                      }
 +                              }
 +                              else {
 +                                      mat->roughness = 1.0f - mat->gloss_mir;
 +                              }
 +                              mat->metallic = mat->ray_mirror;
 +                      }
 +
 +                      for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) {
 +                              for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
 +                                      for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
 +                                              if (sl->spacetype == SPACE_VIEW3D) {
 +                                                      View3D *v3d = (View3D *)sl;
 +                                                      v3d->shading.flag |= V3D_SHADING_SPECULAR_HIGHLIGHT;
 +                                              }
 +                                      }
 +                              }
 +                      }
 +              }
 +
 +              if (!DNA_struct_elem_find(fd->filesdna, "View3DShading", "float", "xray_alpha")) {
 +                      for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) {
 +                              for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
 +                                      for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
 +                                              if (sl->spacetype == SPACE_VIEW3D) {
 +                                                      View3D *v3d = (View3D *)sl;
 +                                                      v3d->shading.xray_alpha = 0.5f;
 +                                              }
 +                                      }
 +                              }
 +                      }
 +              }
 +              if (!DNA_struct_elem_find(fd->filesdna, "View3DShading", "char", "matcap[256]")) {
 +                      StudioLight *default_matcap = BKE_studiolight_find_first(STUDIOLIGHT_ORIENTATION_VIEWNORMAL);
 +                      /* when loading the internal file is loaded before the matcaps */
 +                      if (default_matcap) {
 +                              for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) {
 +                                      for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
 +                                              for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
 +                                                      if (sl->spacetype == SPACE_VIEW3D) {
 +                                                              View3D *v3d = (View3D *)sl;
 +                                                              BLI_strncpy(v3d->shading.matcap, default_matcap->name, FILE_MAXFILE);
 +                                                      }
 +                                              }
 +                                      }
 +                              }
 +                      }
 +              }
 +              if (!DNA_struct_elem_find(fd->filesdna, "View3DOverlay", "float", "wireframe_threshold")) {
 +                      for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) {
 +                              for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
 +                                      for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
 +                                              if (sl->spacetype == SPACE_VIEW3D) {
 +                                                      View3D *v3d = (View3D *)sl;
 +                                                      v3d->overlay.wireframe_threshold = 0.5f;
 +                                              }
 +                                      }
 +                              }
 +                      }
 +              }
 +              if (!DNA_struct_elem_find(fd->filesdna, "View3DShading", "float", "cavity_valley_factor")) {
 +                      for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) {
 +                              for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
 +                                      for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
 +                                              if (sl->spacetype == SPACE_VIEW3D) {
 +                                                      View3D *v3d = (View3D *)sl;
 +                                                      v3d->shading.cavity_valley_factor = 1.0f;
 +                                                      v3d->shading.cavity_ridge_factor = 1.0f;
 +                                              }
 +                                      }
 +                              }
 +                      }
 +              }
 +              if (!DNA_struct_elem_find(fd->filesdna, "View3DOverlay", "float", "bone_select_alpha")) {
 +                      for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) {
 +                              for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
 +                                      for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
 +                                              if (sl->spacetype == SPACE_VIEW3D) {
 +                                                      View3D *v3d = (View3D *)sl;
 +                                                      v3d->overlay.bone_select_alpha = 0.5f;
 +                                              }
 +                                      }
 +                              }
 +                      }
 +              }
 +      }
 +
 +      if (!MAIN_VERSION_ATLEAST(bmain, 280, 19)) {
 +              if (!DNA_struct_elem_find(fd->filesdna, "Image", "ListBase", "renderslot")) {
 +                      for (Image *ima = bmain->image.first; ima; ima = ima->id.next) {
 +                              if (ima->type == IMA_TYPE_R_RESULT) {
 +                                      for (int i = 0; i < 8; i++) {
 +                                              RenderSlot *slot = MEM_callocN(sizeof(RenderSlot), "Image Render Slot Init");
 +                                              BLI_snprintf(slot->name, sizeof(slot->name), "Slot %d", i + 1);
 +                                              BLI_addtail(&ima->renderslots, slot);
 +                                      }
 +                              }
 +                      }
 +              }
 +              if (!DNA_struct_elem_find(fd->filesdna, "SpaceAction", "char", "mode_prev")) {
 +                      for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) {
 +                              for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
 +                                      for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
 +                                              if (sl->spacetype == SPACE_ACTION) {
 +                                                      SpaceAction *saction = (SpaceAction *)sl;
 +                                                      /* "Dopesheet" should be default here, unless it looks like the Action Editor was active instead */
 +                                                      if ((saction->mode_prev == 0) && (saction->action == NULL)) {
 +                                                              saction->mode_prev = SACTCONT_DOPESHEET;
 +                                                      }
 +                                              }
 +                                      }
 +                              }
 +                      }
 +              }
 +
 +              for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) {
 +                      for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
 +                              for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
 +                                      if (sl->spacetype == SPACE_VIEW3D) {
 +                                              View3D *v3d = (View3D *)sl;
 +                                              if (v3d->drawtype == OB_TEXTURE) {
 +                                                      v3d->drawtype = OB_SOLID;
 +                                                      v3d->shading.light = V3D_LIGHTING_STUDIO;
 +                                                      v3d->shading.color_type = V3D_SHADING_TEXTURE_COLOR;
 +                                              }
 +                                      }
 +                              }
 +                      }
 +              }
 +
 +      }
 +
 +      if (!MAIN_VERSION_ATLEAST(bmain, 280, 21)) {
 +              for (Scene *sce = bmain->scene.first; sce != NULL; sce = sce->id.next) {
 +                      if (sce->ed != NULL && sce->ed->seqbase.first != NULL) {
 +                              do_versions_seq_unique_name_all_strips(sce, &sce->ed->seqbase);
 +                      }
 +              }
 +
 +              if (!DNA_struct_elem_find(fd->filesdna, "View3DOverlay", "float", "texture_paint_mode_opacity")) {
 +                      for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) {
 +                              for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
 +                                      for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
 +                                              if (sl->spacetype == SPACE_VIEW3D) {
 +                                                      View3D *v3d = (View3D *)sl;
 +                                                      float alpha = v3d->flag2 & V3D_SHOW_MODE_SHADE_OVERRIDE ? 0.0f : 0.8f;
 +                                                      v3d->overlay.texture_paint_mode_opacity = alpha;
 +                                                      v3d->overlay.vertex_paint_mode_opacity = alpha;
 +                                                      v3d->overlay.weight_paint_mode_opacity = alpha;
 +                                              }
 +                                      }
 +                              }
 +                      }
 +              }
 +
 +              if (!DNA_struct_elem_find(fd->filesdna, "View3DShadeing", "short", "background_type")) {
 +                      for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) {
 +                              for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
 +                                      for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
 +                                              if (sl->spacetype == SPACE_VIEW3D) {
 +                                                      View3D *v3d = (View3D *)sl;
-                                                       v3d->flag3 |= V3D_GP_SHOW_EDIT_LINES;
 +                                                      copy_v3_fl(v3d->shading.background_color, 0.05f);
 +                                              }
 +                                      }
 +                              }
 +                      }
 +              }
 +
 +              if (!DNA_struct_elem_find(fd->filesdna, "SceneEEVEE", "float", "gi_cubemap_draw_size")) {
 +                      for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
 +                              scene->eevee.gi_irradiance_draw_size = 0.1f;
 +                              scene->eevee.gi_cubemap_draw_size = 0.3f;
 +                      }
 +              }
 +
 +              for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
 +                      if (scene->toolsettings->gizmo_flag == 0) {
 +                              scene->toolsettings->gizmo_flag = SCE_MANIP_TRANSLATE | SCE_MANIP_ROTATE | SCE_MANIP_SCALE;
 +                      }
 +              }
 +
 +              if (!DNA_struct_elem_find(fd->filesdna, "RigidBodyWorld", "RigidBodyWorld_Shared", "*shared")) {
 +                      for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
 +                              RigidBodyWorld *rbw = scene->rigidbody_world;
 +
 +                              if (rbw == NULL) {
 +                                      continue;
 +                              }
 +
 +                              if (rbw->shared == NULL) {
 +                                      rbw->shared = MEM_callocN(sizeof(*rbw->shared), "RigidBodyWorld_Shared");
 +                              }
 +
 +                              /* Move shared pointers from deprecated location to current location */
 +                              rbw->shared->pointcache = rbw->pointcache;
 +                              rbw->shared->ptcaches = rbw->ptcaches;
 +
 +                              rbw->pointcache = NULL;
 +                              BLI_listbase_clear(&rbw->ptcaches);
 +
 +                              if (rbw->shared->pointcache == NULL) {
 +                                      rbw->shared->pointcache = BKE_ptcache_add(&(rbw->shared->ptcaches));
 +                              }
 +
 +                      }
 +              }
 +
 +              if (!DNA_struct_elem_find(fd->filesdna, "SoftBody", "SoftBody_Shared", "*shared")) {
 +                      for (Object *ob = bmain->object.first; ob; ob = ob->id.next) {
 +                              SoftBody *sb = ob->soft;
 +                              if (sb == NULL) {
 +                                      continue;
 +                              }
 +                              if (sb->shared == NULL) {
 +                                      sb->shared = MEM_callocN(sizeof(*sb->shared), "SoftBody_Shared");
 +                              }
 +
 +                              /* Move shared pointers from deprecated location to current location */
 +                              sb->shared->pointcache = sb->pointcache;
 +                              sb->shared->ptcaches = sb->ptcaches;
 +
 +                              sb->pointcache = NULL;
 +                              BLI_listbase_clear(&sb->ptcaches);
 +                      }
 +              }
 +
 +              if (!DNA_struct_elem_find(fd->filesdna, "View3DShading", "short", "type")) {
 +                      for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) {
 +                              for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
 +                                      for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
 +                                              if (sl->spacetype == SPACE_VIEW3D) {
 +                                                      View3D *v3d = (View3D *)sl;
 +                                                      if (v3d->drawtype == OB_RENDER) {
 +                                                              v3d->drawtype = OB_SOLID;
 +                                                      }
 +                                                      v3d->shading.type = v3d->drawtype;
 +                                                      v3d->shading.prev_type = OB_SOLID;
 +                                              }
 +                                      }
 +                              }
 +                      }
 +              }
 +
 +              if (!DNA_struct_elem_find(fd->filesdna, "SceneDisplay", "View3DShading", "shading")) {
 +                      for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
 +                              BKE_screen_view3d_shading_init(&scene->display.shading);
 +                      }
 +              }
 +              /* initialize grease pencil view data */
 +              if (!DNA_struct_elem_find(fd->filesdna, "SpaceView3D", "float", "vertex_opacity")) {
 +                      for (bScreen *sc = bmain->screen.first; sc; sc = sc->id.next) {
 +                              for (ScrArea *sa = sc->areabase.first; sa; sa = sa->next) {
 +                                      for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
 +                                              if (sl->spacetype == SPACE_VIEW3D) {
 +                                                      View3D *v3d = (View3D *)sl;
 +                                                      v3d->vertex_opacity = 1.0f;
++                                                      v3d->gp_flag |= V3D_GP_SHOW_EDIT_LINES;
 +                                              }
 +                                      }
 +                              }
 +                      }
 +              }
 +
 +      }
 +
 +      if (!MAIN_VERSION_ATLEAST(bmain, 280, 22)) {
 +              if (!DNA_struct_elem_find(fd->filesdna, "ToolSettings", "char", "annotate_v3d_align")) {
 +                      for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
 +                              scene->toolsettings->annotate_v3d_align = GP_PROJECT_VIEWSPACE | GP_PROJECT_CURSOR;
 +                              scene->toolsettings->annotate_thickness = 3;
 +                      }
 +              }
 +              if (!DNA_struct_elem_find(fd->filesdna, "bGPDlayer", "short", "line_change")) {
 +                      for (bGPdata *gpd = bmain->gpencil.first; gpd; gpd = gpd->id.next) {
 +                              for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
 +                                      gpl->line_change = gpl->thickness;
 +                                      if ((gpl->thickness < 1) || (gpl->thickness > 10)) {
 +                                              gpl->thickness = 3;
 +                                      }
 +                              }
 +                      }
 +              }
 +              if (!DNA_struct_elem_find(fd->filesdna, "View3DOverlay", "float", "gpencil_grid_scale")) {
 +                      for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) {
 +                              for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
 +                                      for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
 +                                              if (sl->spacetype == SPACE_VIEW3D) {
 +                                                      View3D *v3d = (View3D *)sl;
 +                                                      v3d->overlay.gpencil_grid_scale = 1.0f;
 +                                              }
 +                                      }
 +                              }
 +                      }
 +              }
 +              if (!DNA_struct_elem_find(fd->filesdna, "View3DOverlay", "float", "gpencil_paper_opacity")) {
 +                      for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) {
 +                              for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
 +                                      for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
 +                                              if (sl->spacetype == SPACE_VIEW3D) {
 +                                                      View3D *v3d = (View3D *)sl;
 +                                                      v3d->overlay.gpencil_paper_opacity = 0.5f;
 +                                              }
 +                                      }
 +                              }
 +                      }
 +              }
 +              if (!DNA_struct_elem_find(fd->filesdna, "View3DOverlay", "float", "gpencil_grid_opacity")) {
 +                      for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) {
 +                              for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
 +                                      for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
 +                                              if (sl->spacetype == SPACE_VIEW3D) {
 +                                                      View3D *v3d = (View3D *)sl;
 +                                                      v3d->overlay.gpencil_grid_opacity = 0.5f;
 +                                              }
 +                                      }
 +                              }
 +                      }
 +              }
 +              if (!DNA_struct_elem_find(fd->filesdna, "View3DOverlay", "int", "gpencil_grid_axis")) {
 +                      for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) {
 +                              for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
 +                                      for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
 +                                              if (sl->spacetype == SPACE_VIEW3D) {
 +                                                      View3D *v3d = (View3D *)sl;
 +                                                      v3d->overlay.gpencil_grid_axis = V3D_GP_GRID_AXIS_Y;
 +                                              }
 +                                      }
 +                              }
 +                      }
 +              }
 +              if (!DNA_struct_elem_find(fd->filesdna, "View3DOverlay", "int", "gpencil_grid_lines")) {
 +                      for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) {
 +                              for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
 +                                      for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
 +                                              if (sl->spacetype == SPACE_VIEW3D) {
 +                                                      View3D *v3d = (View3D *)sl;
 +                                                      v3d->overlay.gpencil_grid_lines = GP_DEFAULT_GRID_LINES;
 +                                              }
 +                                      }
 +                              }
 +                      }
 +              }
 +
 +      }
 +
 +}
index da3787816d2457d3702bdc225f62bd9e22a13639,558c709d14cf5983621153065a3b58c63fd8f44d..c120eed695c2f494ec01b480bf532e7936c631ae
@@@ -391,72 -310,4 +391,72 @@@ void BLO_update_defaults_startup_blend(
                        br->flag |= BRUSH_ACCUMULATE;
                }
        }
-                                               v3d->flag3 |= V3D_GP_SHOW_EDIT_LINES;
-                                               v3d->flag3 |= V3D_GP_SHOW_MULTIEDIT_LINES;
-                                               v3d->flag3 |= V3D_GP_SHOW_ONION_SKIN;
 +
 +      /* Defaults from T54943. */
 +      {
 +              for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
 +                      scene->r.displaymode = R_OUTPUT_WINDOW;
 +                      scene->r.size = 100;
 +                      scene->r.dither_intensity = 1.0f;
 +                      scene->unit.system = USER_UNIT_METRIC;
 +                      STRNCPY(scene->view_settings.view_transform, "Filmic");
 +              }
 +
 +              for (bScreen *sc = bmain->screen.first; sc; sc = sc->id.next) {
 +                      for (ScrArea *sa = sc->areabase.first; sa; sa = sa->next) {
 +                              for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
 +                                      switch (sl->spacetype) {
 +                                              case SPACE_VIEW3D:
 +                                              {
 +                                                      View3D *v3d = (View3D *)sl;
 +                                                      v3d->lens = 50;
 +                                                      break;
 +                                              }
 +                                              case SPACE_BUTS:
 +                                              {
 +                                                      SpaceButs *sbuts = (SpaceButs *)sl;
 +                                                      sbuts->mainb = sbuts->mainbuser = BCONTEXT_OBJECT;
 +                                                      break;
 +                                              }
 +                                      }
 +
 +                                      ListBase *lb = (sl == sa->spacedata.first) ? &sa->regionbase : &sl->regionbase;
 +                                      for (ARegion *ar = lb->first; ar; ar = ar->next) {
 +                                              if (ar->regiontype == RGN_TYPE_HEADER) {
 +                                                      if (sl->spacetype != SPACE_ACTION) {
 +                                                              ar->alignment = RGN_ALIGN_TOP;
 +                                                      }
 +                                              }
 +                                      }
 +                              }
 +                      }
 +              }
 +
 +              for (Camera *ca = bmain->camera.first; ca; ca = ca->id.next) {
 +                      ca->lens = 50;
 +                      ca->sensor_x = DEFAULT_SENSOR_WIDTH;
 +                      ca->sensor_y = DEFAULT_SENSOR_HEIGHT;
 +              }
 +
 +              for (Lamp *la = bmain->lamp.first; la; la = la->id.next) {
 +                      la->energy = 10.0;
 +              }
 +      }
 +      /* default grease pencil settings */
 +      {
 +              for (bScreen *sc = bmain->screen.first; sc; sc = sc->id.next) {
 +                      for (ScrArea *sa = sc->areabase.first; sa; sa = sa->next) {
 +                              for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
 +                                      if (sl->spacetype == SPACE_VIEW3D) {
 +                                              View3D *v3d = (View3D *)sl;
++                                              v3d->gp_flag |= V3D_GP_SHOW_EDIT_LINES;
++                                              v3d->gp_flag |= V3D_GP_SHOW_MULTIEDIT_LINES;
++                                              v3d->gp_flag |= V3D_GP_SHOW_ONION_SKIN;
 +                                              v3d->vertex_opacity = 0.9f;
 +                                              break;
 +                                      }
 +                              }
 +                      }
 +              }
 +      }
  }
index 04399d1cad75d3be143ee7b810201500fa0b8380,0000000000000000000000000000000000000000..4d2942e08fd770e7e4342ba9c1f924b3082ade4f
mode 100644,000000..100644
--- /dev/null
@@@ -1,1337 -1,0 +1,1337 @@@
-                           (v3d->flag3 & V3D_GP_SHOW_EDIT_LINES))
 +/*
 + * 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_draw_utils.c
 + *  \ingroup draw
 + */
 +
 +#include "BLI_polyfill_2d.h"
 +
 +#include "DRW_engine.h"
 +#include "DRW_render.h"
 +
 +#include "BKE_brush.h"
 +#include "BKE_gpencil.h"
 +#include "BKE_gpencil_modifier.h"
 +#include "BKE_image.h"
 +#include "BKE_material.h"
 +
 +#include "ED_gpencil.h"
 +#include "ED_view3d.h"
 +
 +#include "DNA_gpencil_types.h"
 +#include "DNA_material_types.h"
 +#include "DNA_view3d_types.h"
 +#include "DNA_gpencil_modifier_types.h"
 +
 + /* If builtin shaders are needed */
 +#include "GPU_shader.h"
 +#include "GPU_texture.h"
 +
 +/* For EvaluationContext... */
 +#include "DEG_depsgraph.h"
 +#include "DEG_depsgraph_query.h"
 +
 +#include "IMB_imbuf_types.h"
 +
 +#include "gpencil_engine.h"
 +
 +/* fill type to communicate to shader */
 +#define SOLID 0
 +#define GRADIENT 1
 +#define RADIAL 2
 +#define CHESS 3
 +#define TEXTURE 4
 +#define PATTERN 5
 +
 +/* Helper for doing all the checks on whether a stroke can be drawn */
 +static bool gpencil_can_draw_stroke(
 +        struct MaterialGPencilStyle *gp_style, const bGPDstroke *gps,
 +        const bool onion, const bool is_mat_preview)
 +{
 +      /* skip stroke if it doesn't have any valid data */
 +      if ((gps->points == NULL) || (gps->totpoints < 1) || (gp_style == NULL))
 +              return false;
 +
 +      /* if mat preview render always visible */
 +      if (is_mat_preview) {
 +              return true;
 +      }
 +
 +      /* check if the color is visible */
 +      if ((gp_style == NULL) ||
 +          (gp_style->flag & GP_STYLE_COLOR_HIDE) ||
 +          (onion && (gp_style->flag & GP_STYLE_COLOR_ONIONSKIN)))
 +      {
 +              return false;
 +      }
 +
 +      /* stroke can be drawn */
 +      return true;
 +}
 +
 +/* calc bounding box in 2d using flat projection data */
 +static void gpencil_calc_2d_bounding_box(
 +        const float(*points2d)[2], int totpoints, float minv[2], float maxv[2], bool expand)
 +{
 +      minv[0] = points2d[0][0];
 +      minv[1] = points2d[0][1];
 +      maxv[0] = points2d[0][0];
 +      maxv[1] = points2d[0][1];
 +
 +      for (int i = 1; i < totpoints; i++) {
 +              /* min */
 +              if (points2d[i][0] < minv[0]) {
 +                      minv[0] = points2d[i][0];
 +              }
 +              if (points2d[i][1] < minv[1]) {
 +                      minv[1] = points2d[i][1];
 +              }
 +              /* max */
 +              if (points2d[i][0] > maxv[0]) {
 +                      maxv[0] = points2d[i][0];
 +              }
 +              if (points2d[i][1] > maxv[1]) {
 +                      maxv[1] = points2d[i][1];
 +              }
 +      }
 +      /* If not expanded, use a perfect square */
 +      if (expand == false) {
 +              if (maxv[0] > maxv[1]) {
 +                      maxv[1] = maxv[0];
 +              }
 +              else {
 +                      maxv[0] = maxv[1];
 +              }
 +      }
 +}
 +
 +/* calc texture coordinates using flat projected points */
 +static void gpencil_calc_stroke_fill_uv(
 +        const float(*points2d)[2], int totpoints, float minv[2], float maxv[2], float(*r_uv)[2])
 +{
 +      float d[2];
 +      d[0] = maxv[0] - minv[0];
 +      d[1] = maxv[1] - minv[1];
 +      for (int i = 0; i < totpoints; i++) {
 +              r_uv[i][0] = (points2d[i][0] - minv[0]) / d[0];
 +              r_uv[i][1] = (points2d[i][1] - minv[1]) / d[1];
 +      }
 +}
 +
 +/* Get points of stroke always flat to view not affected by camera view or view position */
 +static void gpencil_stroke_2d_flat(const bGPDspoint *points, int totpoints, float(*points2d)[2], int *r_direction)
 +{
 +      const bGPDspoint *pt0 = &points[0];
 +      const bGPDspoint *pt1 = &points[1];
 +      const bGPDspoint *pt3 = &points[(int)(totpoints * 0.75)];
 +
 +      float locx[3];
 +      float locy[3];
 +      float loc3[3];
 +      float normal[3];
 +
 +      /* local X axis (p0 -> p1) */
 +      sub_v3_v3v3(locx, &pt1->x, &pt0->x);
 +
 +      /* point vector at 3/4 */
 +      sub_v3_v3v3(loc3, &pt3->x, &pt0->x);
 +
 +      /* vector orthogonal to polygon plane */
 +      cross_v3_v3v3(normal, locx, loc3);
 +
 +      /* local Y axis (cross to normal/x axis) */
 +      cross_v3_v3v3(locy, normal, locx);
 +
 +      /* Normalize vectors */
 +      normalize_v3(locx);
 +      normalize_v3(locy);
 +
 +      /* Get all points in local space */
 +      for (int i = 0; i < totpoints; i++) {
 +              const bGPDspoint *pt = &points[i];
 +              float loc[3];
 +
 +              /* Get local space using first point as origin */
 +              sub_v3_v3v3(loc, &pt->x, &pt0->x);
 +
 +              points2d[i][0] = dot_v3v3(loc, locx);
 +              points2d[i][1] = dot_v3v3(loc, locy);
 +      }
 +
 +      /* Concave (-1), Convex (1), or Autodetect (0)? */
 +      *r_direction = (int)locy[2];
 +}
 +
 +/* Triangulate stroke for high quality fill (this is done only if cache is null or stroke was modified) */
 +void DRW_gpencil_triangulate_stroke_fill(bGPDstroke *gps)
 +{
 +      BLI_assert(gps->totpoints >= 3);
 +
 +      /* allocate memory for temporary areas */
 +      gps->tot_triangles = gps->totpoints - 2;
 +      uint(*tmp_triangles)[3] = MEM_mallocN(sizeof(*tmp_triangles) * gps->tot_triangles, "GP Stroke temp triangulation");
 +      float(*points2d)[2] = MEM_mallocN(sizeof(*points2d) * gps->totpoints, "GP Stroke temp 2d points");
 +      float(*uv)[2] = MEM_mallocN(sizeof(*uv) * gps->totpoints, "GP Stroke temp 2d uv data");
 +
 +      int direction = 0;
 +
 +      /* convert to 2d and triangulate */
 +      gpencil_stroke_2d_flat(gps->points, gps->totpoints, points2d, &direction);
 +      BLI_polyfill_calc(points2d, (uint)gps->totpoints, direction, tmp_triangles);
 +
 +      /* calc texture coordinates automatically */
 +      float minv[2];
 +      float maxv[2];
 +      /* first needs bounding box data */
 +      gpencil_calc_2d_bounding_box(points2d, gps->totpoints, minv, maxv, false);
 +      /* calc uv data */
 +      gpencil_calc_stroke_fill_uv(points2d, gps->totpoints, minv, maxv, uv);
 +
 +      /* Number of triangles */
 +      gps->tot_triangles = gps->totpoints - 2;
 +      /* save triangulation data in stroke cache */
 +      if (gps->tot_triangles > 0) {
 +              if (gps->triangles == NULL) {
 +                      gps->triangles = MEM_callocN(sizeof(*gps->triangles) * gps->tot_triangles, "GP Stroke triangulation");
 +              }
 +              else {
 +                      gps->triangles = MEM_recallocN(gps->triangles, sizeof(*gps->triangles) * gps->tot_triangles);
 +              }
 +
 +              for (int i = 0; i < gps->tot_triangles; i++) {
 +                      bGPDtriangle *stroke_triangle = &gps->triangles[i];
 +                      memcpy(gps->triangles[i].verts, tmp_triangles[i], sizeof(uint[3]));
 +                      /* copy texture coordinates */
 +                      copy_v2_v2(stroke_triangle->uv[0], uv[tmp_triangles[i][0]]);
 +                      copy_v2_v2(stroke_triangle->uv[1], uv[tmp_triangles[i][1]]);
 +                      copy_v2_v2(stroke_triangle->uv[2], uv[tmp_triangles[i][2]]);
 +              }
 +      }
 +      else {
 +              /* No triangles needed - Free anything allocated previously */
 +              if (gps->triangles)
 +                      MEM_freeN(gps->triangles);
 +
 +              gps->triangles = NULL;
 +      }
 +
 +      /* disable recalculation flag */
 +      if (gps->flag & GP_STROKE_RECALC_CACHES) {
 +              gps->flag &= ~GP_STROKE_RECALC_CACHES;
 +      }
 +
 +      /* clear memory */
 +      MEM_SAFE_FREE(tmp_triangles);
 +      MEM_SAFE_FREE(points2d);
 +      MEM_SAFE_FREE(uv);
 +}
 +
 +/* recalc the internal geometry caches for fill and uvs */
 +static void DRW_gpencil_recalc_geometry_caches(Object *ob, MaterialGPencilStyle *gp_style, bGPDstroke *gps)
 +{
 +      if (gps->flag & GP_STROKE_RECALC_CACHES) {
 +              /* Calculate triangles cache for filling area (must be done only after changes) */
 +              if ((gps->tot_triangles == 0) || (gps->triangles == NULL)) {
 +                      if ((gps->totpoints > 2) &&
 +                          ((gp_style->fill_rgba[3] > GPENCIL_ALPHA_OPACITY_THRESH) || (gp_style->fill_style > 0)))
 +                      {
 +                              DRW_gpencil_triangulate_stroke_fill(gps);
 +                      }
 +              }
 +
 +              /* calc uv data along the stroke */
 +              ED_gpencil_calc_stroke_uv(ob, gps);
 +
 +              /* clear flag */
 +              gps->flag &= ~GP_STROKE_RECALC_CACHES;
 +      }
 +}
 +
 +/* create shading group for filling */
 +static DRWShadingGroup *DRW_gpencil_shgroup_fill_create(
 +        GPENCIL_e_data *e_data, GPENCIL_Data *vedata, DRWPass *pass,
 +        GPUShader *shader, bGPdata *gpd, MaterialGPencilStyle *gp_style, int id)
 +{
 +      GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
 +
 +      /* e_data.gpencil_fill_sh */
 +      DRWShadingGroup *grp = DRW_shgroup_create(shader, pass);
 +
 +      DRW_shgroup_uniform_vec4(grp, "color2", gp_style->mix_rgba, 1);
 +
 +      /* set style type */
 +      switch (gp_style->fill_style) {
 +              case GP_STYLE_FILL_STYLE_SOLID:
 +                      stl->shgroups[id].fill_style = SOLID;
 +                      break;
 +              case GP_STYLE_FILL_STYLE_GRADIENT:
 +                      if (gp_style->gradient_type == GP_STYLE_GRADIENT_LINEAR) {
 +                              stl->shgroups[id].fill_style = GRADIENT;
 +                      }
 +                      else {
 +                              stl->shgroups[id].fill_style = RADIAL;
 +                      }
 +                      break;
 +              case GP_STYLE_FILL_STYLE_CHESSBOARD:
 +                      stl->shgroups[id].fill_style = CHESS;
 +                      break;
 +              case GP_STYLE_FILL_STYLE_TEXTURE:
 +                      if (gp_style->flag & GP_STYLE_FILL_PATTERN) {
 +                              stl->shgroups[id].fill_style = PATTERN;
 +                      }
 +                      else {
 +                              stl->shgroups[id].fill_style = TEXTURE;
 +                      }
 +                      break;
 +              default:
 +                      stl->shgroups[id].fill_style = GP_STYLE_FILL_STYLE_SOLID;
 +                      break;
 +      }
 +      DRW_shgroup_uniform_int(grp, "fill_type", &stl->shgroups[id].fill_style, 1);
 +
 +      DRW_shgroup_uniform_float(grp, "mix_factor", &gp_style->mix_factor, 1);
 +
 +      DRW_shgroup_uniform_float(grp, "gradient_angle", &gp_style->gradient_angle, 1);
 +      DRW_shgroup_uniform_float(grp, "gradient_radius", &gp_style->gradient_radius, 1);
 +      DRW_shgroup_uniform_float(grp, "pattern_gridsize", &gp_style->pattern_gridsize, 1);
 +      DRW_shgroup_uniform_vec2(grp, "gradient_scale", gp_style->gradient_scale, 1);
 +      DRW_shgroup_uniform_vec2(grp, "gradient_shift", gp_style->gradient_shift, 1);
 +
 +      DRW_shgroup_uniform_float(grp, "texture_angle", &gp_style->texture_angle, 1);
 +      DRW_shgroup_uniform_vec2(grp, "texture_scale", gp_style->texture_scale, 1);
 +      DRW_shgroup_uniform_vec2(grp, "texture_offset", gp_style->texture_offset, 1);
 +      DRW_shgroup_uniform_float(grp, "texture_opacity", &gp_style->texture_opacity, 1);
 +
 +      stl->shgroups[id].texture_mix = gp_style->flag & GP_STYLE_COLOR_TEX_MIX ? 1 : 0;
 +      DRW_shgroup_uniform_int(grp, "texture_mix", &stl->shgroups[id].texture_mix, 1);
 +
 +      stl->shgroups[id].texture_flip = gp_style->flag & GP_STYLE_COLOR_FLIP_FILL ? 1 : 0;
 +      DRW_shgroup_uniform_int(grp, "texture_flip", &stl->shgroups[id].texture_flip, 1);
 +
 +      DRW_shgroup_uniform_int(grp, "xraymode", (const int *) &gpd->xray_mode, 1);
 +      /* image texture */
 +      if ((gp_style->flag & GP_STYLE_COLOR_TEX_MIX) ||
 +          (gp_style->fill_style & GP_STYLE_FILL_STYLE_TEXTURE))
 +      {
 +              ImBuf *ibuf;
 +              Image *image = gp_style->ima;
 +              ImageUser iuser = { NULL };
 +              void *lock;
 +
 +              iuser.ok = true;
 +
 +              ibuf = BKE_image_acquire_ibuf(image, &iuser, &lock);
 +
 +              if (ibuf == NULL || ibuf->rect == NULL) {
 +                      BKE_image_release_ibuf(image, ibuf, NULL);
 +              }
 +              else {
 +                      GPUTexture *texture = GPU_texture_from_blender(gp_style->ima, &iuser, GL_TEXTURE_2D, true, 0.0);
 +                      DRW_shgroup_uniform_texture(grp, "myTexture", texture);
 +
 +                      stl->shgroups[id].texture_clamp = gp_style->flag & GP_STYLE_COLOR_TEX_CLAMP ? 1 : 0;
 +                      DRW_shgroup_uniform_int(grp, "texture_clamp", &stl->shgroups[id].texture_clamp, 1);
 +
 +                      BKE_image_release_ibuf(image, ibuf, NULL);
 +              }
 +      }
 +      else {
 +              /* if no texture defined, need a blank texture to avoid errors in draw manager */
 +              DRW_shgroup_uniform_texture(grp, "myTexture", e_data->gpencil_blank_texture);
 +              stl->shgroups[id].texture_clamp = 0;
 +              DRW_shgroup_uniform_int(grp, "texture_clamp", &stl->shgroups[id].texture_clamp, 1);
 +      }
 +
 +      return grp;
 +}
 +
 +/* create shading group for strokes */
 +DRWShadingGroup *DRW_gpencil_shgroup_stroke_create(
 +        GPENCIL_e_data *e_data, GPENCIL_Data *vedata, DRWPass *pass, GPUShader *shader, Object *ob,
 +        bGPdata *gpd, MaterialGPencilStyle *gp_style, int id, bool onion)
 +{
 +      GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
 +      const float *viewport_size = DRW_viewport_size_get();
 +
 +      /* e_data.gpencil_stroke_sh */
 +      DRWShadingGroup *grp = DRW_shgroup_create(shader, pass);
 +
 +      DRW_shgroup_uniform_vec2(grp, "Viewport", viewport_size, 1);
 +
 +      DRW_shgroup_uniform_float(grp, "pixsize", stl->storage->pixsize, 1);
 +      DRW_shgroup_uniform_float(grp, "pixelsize", &U.pixelsize, 1);
 +
 +      /* avoid wrong values */
 +      if ((gpd) && (gpd->pixfactor == 0)) {
 +              gpd->pixfactor = GP_DEFAULT_PIX_FACTOR;
 +      }
 +
 +      /* object scale and depth */
 +      if ((ob) && (id > -1)) {
 +              stl->shgroups[id].obj_scale = (ob->size[0] + ob->size[1] + ob->size[2]) / 3.0f;
 +              DRW_shgroup_uniform_float(grp, "objscale", &stl->shgroups[id].obj_scale, 1);
 +              stl->shgroups[id].keep_size = (int)((gpd) && (gpd->flag & GP_DATA_STROKE_KEEPTHICKNESS));
 +              DRW_shgroup_uniform_int(grp, "keep_size", &stl->shgroups[id].keep_size, 1);
 +
 +              stl->shgroups[id].stroke_style = gp_style->stroke_style;
 +              stl->shgroups[id].color_type = GPENCIL_COLOR_SOLID;
 +              if ((gp_style->stroke_style == GP_STYLE_STROKE_STYLE_TEXTURE) && (!onion)) {
 +                      stl->shgroups[id].color_type = GPENCIL_COLOR_TEXTURE;
 +                      if (gp_style->flag & GP_STYLE_STROKE_PATTERN) {
 +                              stl->shgroups[id].color_type = GPENCIL_COLOR_PATTERN;
 +                      }
 +              }
 +              DRW_shgroup_uniform_int(grp, "color_type", &stl->shgroups[id].color_type, 1);
 +              DRW_shgroup_uniform_float(grp, "pixfactor", &gpd->pixfactor, 1);
 +      }
 +      else {
 +              stl->storage->obj_scale = 1.0f;
 +              stl->storage->keep_size = 0;
 +              stl->storage->pixfactor = GP_DEFAULT_PIX_FACTOR;
 +              DRW_shgroup_uniform_float(grp, "objscale", &stl->storage->obj_scale, 1);
 +              DRW_shgroup_uniform_int(grp, "keep_size", &stl->storage->keep_size, 1);
 +              DRW_shgroup_uniform_int(grp, "color_type", &stl->storage->color_type, 1);
 +              if (gpd) {
 +                      DRW_shgroup_uniform_float(grp, "pixfactor", &gpd->pixfactor, 1);
 +              }
 +              else {
 +                      DRW_shgroup_uniform_float(grp, "pixfactor", &stl->storage->pixfactor, 1);
 +              }
 +      }
 +
 +      if ((gpd) && (id > -1)) {
 +              DRW_shgroup_uniform_int(grp, "xraymode", (const int *) &gpd->xray_mode, 1);
 +      }
 +      else {
 +              /* for drawing always on front */
 +              DRW_shgroup_uniform_int(grp, "xraymode", &stl->storage->xray, 1);
 +      }
 +
 +      /* image texture for pattern */
 +      if ((gp_style) && (gp_style->stroke_style == GP_STYLE_STROKE_STYLE_TEXTURE) && (!onion)) {
 +              ImBuf *ibuf;
 +              Image *image = gp_style->sima;
 +              ImageUser iuser = { NULL };
 +              void *lock;
 +
 +              iuser.ok = true;
 +
 +              ibuf = BKE_image_acquire_ibuf(image, &iuser, &lock);
 +
 +              if (ibuf == NULL || ibuf->rect == NULL) {
 +                      BKE_image_release_ibuf(image, ibuf, NULL);
 +              }
 +              else {
 +                      GPUTexture *texture = GPU_texture_from_blender(gp_style->sima, &iuser, GL_TEXTURE_2D, true, 0.0f);
 +                      DRW_shgroup_uniform_texture(grp, "myTexture", texture);
 +
 +                      BKE_image_release_ibuf(image, ibuf, NULL);
 +              }
 +      }
 +      else {
 +              /* if no texture defined, need a blank texture to avoid errors in draw manager */
 +              DRW_shgroup_uniform_texture(grp, "myTexture", e_data->gpencil_blank_texture);
 +      }
 +
 +      return grp;
 +}
 +
 +/* create shading group for volumetrics */
 +static DRWShadingGroup *DRW_gpencil_shgroup_point_create(
 +        GPENCIL_e_data *e_data, GPENCIL_Data *vedata, DRWPass *pass, GPUShader *shader, Object *ob,
 +        bGPdata *gpd, MaterialGPencilStyle *gp_style, int id, bool onion)
 +{
 +      GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
 +      const float *viewport_size = DRW_viewport_size_get();
 +
 +      /* e_data.gpencil_stroke_sh */
 +      DRWShadingGroup *grp = DRW_shgroup_create(shader, pass);
 +
 +      DRW_shgroup_uniform_vec2(grp, "Viewport", viewport_size, 1);
 +      DRW_shgroup_uniform_float(grp, "pixsize", stl->storage->pixsize, 1);
 +      DRW_shgroup_uniform_float(grp, "pixelsize", &U.pixelsize, 1);
 +
 +      /* avoid wrong values */
 +      if ((gpd) && (gpd->pixfactor == 0)) {
 +              gpd->pixfactor = GP_DEFAULT_PIX_FACTOR;
 +      }
 +
 +      /* object scale and depth */
 +      if ((ob) && (id > -1)) {
 +              stl->shgroups[id].obj_scale = (ob->size[0] + ob->size[1] + ob->size[2]) / 3.0f;
 +              DRW_shgroup_uniform_float(grp, "objscale", &stl->shgroups[id].obj_scale, 1);
 +              stl->shgroups[id].keep_size = (int)((gpd) && (gpd->flag & GP_DATA_STROKE_KEEPTHICKNESS));
 +              DRW_shgroup_uniform_int(grp, "keep_size", &stl->shgroups[id].keep_size, 1);
 +
 +              stl->shgroups[id].mode = gp_style->mode;
 +              stl->shgroups[id].stroke_style = gp_style->stroke_style;
 +              stl->shgroups[id].color_type = GPENCIL_COLOR_SOLID;
 +              if ((gp_style->stroke_style == GP_STYLE_STROKE_STYLE_TEXTURE) && (!onion)) {
 +                      stl->shgroups[id].color_type = GPENCIL_COLOR_TEXTURE;
 +                      if (gp_style->flag & GP_STYLE_STROKE_PATTERN) {
 +                              stl->shgroups[id].color_type = GPENCIL_COLOR_PATTERN;
 +                      }
 +              }
 +              DRW_shgroup_uniform_int(grp, "color_type", &stl->shgroups[id].color_type, 1);
 +              DRW_shgroup_uniform_int(grp, "mode", &stl->shgroups[id].mode, 1);
 +              DRW_shgroup_uniform_float(grp, "pixfactor", &gpd->pixfactor, 1);
 +      }
 +      else {
 +              stl->storage->obj_scale = 1.0f;
 +              stl->storage->keep_size = 0;
 +              stl->storage->pixfactor = GP_DEFAULT_PIX_FACTOR;
 +              stl->storage->mode = gp_style->mode;
 +              DRW_shgroup_uniform_float(grp, "objscale", &stl->storage->obj_scale, 1);
 +              DRW_shgroup_uniform_int(grp, "keep_size", &stl->storage->keep_size, 1);
 +              DRW_shgroup_uniform_int(grp, "color_type", &stl->storage->color_type, 1);
 +              DRW_shgroup_uniform_int(grp, "mode", &stl->storage->mode, 1);
 +              if (gpd) {
 +                      DRW_shgroup_uniform_float(grp, "pixfactor", &gpd->pixfactor, 1);
 +              }
 +              else {
 +                      DRW_shgroup_uniform_float(grp, "pixfactor", &stl->storage->pixfactor, 1);
 +              }
 +      }
 +
 +      if (gpd) {
 +              DRW_shgroup_uniform_int(grp, "xraymode", (const int *)&gpd->xray_mode, 1);
 +      }
 +      else {
 +              /* for drawing always on front */
 +              DRW_shgroup_uniform_int(grp, "xraymode", &stl->storage->xray, 1);
 +      }
 +
 +      /* image texture */
 +      if ((gp_style) && (gp_style->stroke_style == GP_STYLE_STROKE_STYLE_TEXTURE) && (!onion)) {
 +              ImBuf *ibuf;
 +              Image *image = gp_style->sima;
 +              ImageUser iuser = { NULL };
 +              void *lock;
 +
 +              iuser.ok = true;
 +
 +              ibuf = BKE_image_acquire_ibuf(image, &iuser, &lock);
 +
 +              if (ibuf == NULL || ibuf->rect == NULL) {
 +                      BKE_image_release_ibuf(image, ibuf, NULL);
 +              }
 +              else {
 +                      GPUTexture *texture = GPU_texture_from_blender(gp_style->sima, &iuser, GL_TEXTURE_2D, true, 0.0f);
 +                      DRW_shgroup_uniform_texture(grp, "myTexture", texture);
 +
 +                      BKE_image_release_ibuf(image, ibuf, NULL);
 +              }
 +      }
 +      else {
 +              /* if no texture defined, need a blank texture to avoid errors in draw manager */
 +              DRW_shgroup_uniform_texture(grp, "myTexture", e_data->gpencil_blank_texture);
 +      }
 +
 +      return grp;
 +}
 +
 +/* add fill shading group to pass */
 +static void gpencil_add_fill_shgroup(
 +        GpencilBatchCache *cache, DRWShadingGroup *fillgrp,
 +        Object *ob, bGPDlayer *gpl, bGPDframe *gpf, bGPDstroke *gps,
 +        const float tintcolor[4], const bool onion, const bool custonion)
 +{
 +      MaterialGPencilStyle *gp_style = BKE_material_gpencil_settings_get(ob, gps->mat_nr + 1);
 +      if (gps->totpoints >= 3) {
 +              float tfill[4];
 +              /* set color using material, tint color and opacity */
 +              interp_v3_v3v3(tfill, gps->runtime.tmp_fill_rgba, tintcolor, tintcolor[3]);
 +              tfill[3] = gps->runtime.tmp_fill_rgba[3] * gpl->opacity;
 +              if ((tfill[3] > GPENCIL_ALPHA_OPACITY_THRESH) || (gp_style->fill_style > 0)) {
 +                      const float *color;
 +                      if (!onion) {
 +                              color = tfill;
 +                      }
 +                      else {
 +                              if (custonion) {
 +                                      color = tintcolor;
 +                              }
 +                              else {
 +                                      ARRAY_SET_ITEMS(tfill, UNPACK3(gps->runtime.tmp_fill_rgba), tintcolor[3]);
 +                                      color = tfill;
 +                              }
 +                      }
 +                      if (cache->is_dirty) {
 +                              gpencil_batch_cache_check_free_slots(ob);
 +                              cache->batch_fill[cache->cache_idx] = DRW_gpencil_get_fill_geom(ob, gps, color);
 +                      }
 +                      DRW_shgroup_call_add(fillgrp, cache->batch_fill[cache->cache_idx], gpf->runtime.viewmatrix);
 +              }
 +      }
 +}
 +
 +/* add stroke shading group to pass */
 +static void gpencil_add_stroke_shgroup(GpencilBatchCache *cache, DRWShadingGroup *strokegrp,
 +      Object *ob, bGPDlayer *gpl, bGPDframe *gpf, bGPDstroke *gps,
 +      const float opacity, const float tintcolor[4], const bool onion, const bool custonion)
 +{
 +      float tcolor[4];
 +      float ink[4];
 +      short sthickness;
 +      MaterialGPencilStyle *gp_style = BKE_material_gpencil_settings_get(ob, gps->mat_nr + 1);
 +
 +      /* set color using base color, tint color and opacity */
 +      if (!onion) {
 +              /* if special stroke, use fill color as stroke color */
 +              if (gps->flag & GP_STROKE_NOFILL) {
 +                      interp_v3_v3v3(tcolor, gps->runtime.tmp_fill_rgba, tintcolor, tintcolor[3]);
 +                      tcolor[3] = gps->runtime.tmp_fill_rgba[3] * opacity;
 +              }
 +              else {
 +                      interp_v3_v3v3(tcolor, gps->runtime.tmp_stroke_rgba, tintcolor, tintcolor[3]);
 +                      tcolor[3] = gps->runtime.tmp_stroke_rgba[3] * opacity;
 +              }
 +              copy_v4_v4(ink, tcolor);
 +      }
 +      else {
 +              if (custonion) {
 +                      copy_v4_v4(ink, tintcolor);
 +              }
 +              else {
 +                      ARRAY_SET_ITEMS(tcolor, UNPACK3(gps->runtime.tmp_stroke_rgba), opacity);
 +                      copy_v4_v4(ink, tcolor);
 +              }
 +      }
 +
 +      sthickness = gps->thickness + gpl->line_change;
 +      CLAMP_MIN(sthickness, 1);
 +      if (cache->is_dirty) {
 +              gpencil_batch_cache_check_free_slots(ob);
 +              if ((gps->totpoints > 1) && (gp_style->mode == GP_STYLE_MODE_LINE)) {
 +                      cache->batch_stroke[cache->cache_idx] = DRW_gpencil_get_stroke_geom(gpf, gps, sthickness, ink);
 +              }
 +              else {
 +                      cache->batch_stroke[cache->cache_idx] = DRW_gpencil_get_point_geom(gps, sthickness, ink);
 +              }
 +      }
 +      DRW_shgroup_call_add(strokegrp, cache->batch_stroke[cache->cache_idx], gpf->runtime.viewmatrix);
 +}
 +
 +/* add edit points shading group to pass */
 +static void gpencil_add_editpoints_shgroup(
 +        GPENCIL_StorageList *stl, GpencilBatchCache *cache, ToolSettings *UNUSED(ts), Object *ob,
 +        bGPdata *gpd, bGPDlayer *gpl, bGPDframe *gpf, bGPDstroke *gps)
 +{
 +      const DRWContextState *draw_ctx = DRW_context_state_get();
 +      View3D *v3d = draw_ctx->v3d;
 +      MaterialGPencilStyle *gp_style = BKE_material_gpencil_settings_get(ob, gps->mat_nr + 1);
 +
 +      /* alpha factor for edit points/line to make them more subtle */
 +      float edit_alpha = v3d->vertex_opacity;
 +
 +      if (GPENCIL_ANY_EDIT_MODE(gpd)) {
 +              Object *obact = DRW_context_state_get()->obact;
 +              if ((!obact) || (obact->type != OB_GPENCIL)) {
 +                      return;
 +              }
 +              const bool is_weight_paint = (gpd) && (gpd->flag & GP_DATA_STROKE_WEIGHTMODE);
 +
 +              /* line of the original stroke */
 +              if (cache->is_dirty) {
 +                      gpencil_batch_cache_check_free_slots(ob);
 +                      cache->batch_edlin[cache->cache_idx] = DRW_gpencil_get_edlin_geom(gps, edit_alpha, gpd->flag);
 +              }
 +              if (cache->batch_edlin[cache->cache_idx]) {
 +                      if ((obact) && (obact == ob) &&
 +                          ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) &&
-       const bool overlay_multiedit = v3d != NULL ? (v3d->flag3 & V3D_GP_SHOW_MULTIEDIT_LINES) : true;
++                          (v3d->gp_flag & V3D_GP_SHOW_EDIT_LINES))
 +                      {
 +                              DRW_shgroup_call_add(
 +                                      stl->g_data->shgrps_edit_line,
 +                                      cache->batch_edlin[cache->cache_idx],
 +                                      gpf->runtime.viewmatrix);
 +                      }
 +              }
 +              /* edit points */
 +              if ((gps->flag & GP_STROKE_SELECT) || (is_weight_paint)) {
 +                      if ((gpl->flag & GP_LAYER_UNLOCK_COLOR) || ((gp_style->flag & GP_STYLE_COLOR_LOCKED) == 0)) {
 +                              if (cache->is_dirty) {
 +                                      gpencil_batch_cache_check_free_slots(ob);
 +                                      cache->batch_edit[cache->cache_idx] = DRW_gpencil_get_edit_geom(gps, edit_alpha, gpd->flag);
 +                              }
 +                              if (cache->batch_edit[cache->cache_idx]) {
 +                                      if ((obact) && (obact == ob)) {
 +                                              /* edit pass */
 +                                              DRW_shgroup_call_add(
 +                                                      stl->g_data->shgrps_edit_point,
 +                                                      cache->batch_edit[cache->cache_idx],
 +                                                      gpf->runtime.viewmatrix);
 +                                      }
 +                              }
 +                      }
 +              }
 +      }
 +}
 +
 +/* function to draw strokes for onion only */
 +static void gpencil_draw_onion_strokes(
 +        GpencilBatchCache *cache, GPENCIL_e_data *e_data, void *vedata, Object *ob,
 +        bGPdata *gpd, bGPDlayer *gpl, bGPDframe *gpf,
 +        const float opacity, const float tintcolor[4], const bool custonion)
 +{
 +      GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl;
 +      GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
 +      Depsgraph *depsgraph = DRW_context_state_get()->depsgraph;
 +
 +      float viewmatrix[4][4];
 +
 +      /* get parent matrix and save as static data */
 +      ED_gpencil_parent_location(depsgraph, ob, gpd, gpl, viewmatrix);
 +      copy_m4_m4(gpf->runtime.viewmatrix, viewmatrix);
 +
 +      for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
 +              MaterialGPencilStyle *gp_style = BKE_material_gpencil_settings_get(ob, gps->mat_nr + 1);
 +              copy_v4_v4(gps->runtime.tmp_stroke_rgba, gp_style->stroke_rgba);
 +              copy_v4_v4(gps->runtime.tmp_fill_rgba, gp_style->fill_rgba);
 +
 +              int id = stl->storage->shgroup_id;
 +              /* check if stroke can be drawn */
 +              if (gpencil_can_draw_stroke(gp_style, gps, true, false) == false) {
 +                      continue;
 +              }
 +              /* limit the number of shading groups */
 +              if (id >= GPENCIL_MAX_SHGROUPS) {
 +                      continue;
 +              }
 +
 +              stl->shgroups[id].shgrps_fill = NULL;
 +              if ((gps->totpoints > 1) && (gp_style->mode == GP_STYLE_MODE_LINE)) {
 +                      stl->shgroups[id].shgrps_stroke = DRW_gpencil_shgroup_stroke_create(
 +                              e_data, vedata, psl->stroke_pass, e_data->gpencil_stroke_sh, ob, gpd, gp_style, id, true);
 +              }
 +              else {
 +                      stl->shgroups[id].shgrps_stroke = DRW_gpencil_shgroup_point_create(
 +                              e_data, vedata, psl->stroke_pass, e_data->gpencil_point_sh, ob, gpd, gp_style, id, true);
 +              }
 +
 +              /* stroke */
 +              gpencil_add_stroke_shgroup(
 +                      cache, stl->shgroups[id].shgrps_stroke, ob, gpl, gpf, gps, opacity, tintcolor, true, custonion);
 +
 +              stl->storage->shgroup_id++;
 +              cache->cache_idx++;
 +      }
 +}
 +
 +
 +/* main function to draw strokes */
 +static void gpencil_draw_strokes(
 +        GpencilBatchCache *cache, GPENCIL_e_data *e_data, void *vedata, ToolSettings *ts, Object *ob,
 +        bGPdata *gpd, bGPDlayer *gpl, bGPDframe *src_gpf, bGPDframe *derived_gpf,
 +        const float opacity, const float tintcolor[4], const bool custonion)
 +{
 +      GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl;
 +      GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
 +      const DRWContextState *draw_ctx = DRW_context_state_get();
 +      Scene *scene = draw_ctx->scene;
 +      View3D *v3d = draw_ctx->v3d;
 +      bGPDstroke *gps, *src_gps;
 +      DRWShadingGroup *fillgrp;
 +      DRWShadingGroup *strokegrp;
 +      float viewmatrix[4][4];
 +      const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
 +      const bool playing = (bool)stl->storage->playing;
 +      const bool is_render = (bool)stl->storage->is_render;
 +      const bool is_mat_preview = (bool)stl->storage->is_mat_preview;
-       const bool main_onion = v3d != NULL ? ((v3d->flag3 & V3D_GP_SHOW_ONION_SKIN) == 0) : true;
++      const bool overlay_multiedit = v3d != NULL ? (v3d->gp_flag & V3D_GP_SHOW_MULTIEDIT_LINES) : true;
 +
 +      /* Get evaluation context */
 +      /* NOTE: We must check if C is valid, otherwise we get crashes when trying to save files
 +       * (i.e. the thumbnail offscreen rendering fails)
 +       */
 +      Depsgraph *depsgraph = DRW_context_state_get()->depsgraph;
 +
 +      /* get parent matrix and save as static data */
 +      ED_gpencil_parent_location(depsgraph, ob, gpd, gpl, viewmatrix);
 +      copy_m4_m4(derived_gpf->runtime.viewmatrix, viewmatrix);
 +
 +      /* apply geometry modifiers */
 +      if ((cache->is_dirty) && (ob->greasepencil_modifiers.first) && (!is_multiedit)) {
 +              if (!stl->storage->simplify_modif) {
 +                      if (BKE_gpencil_has_geometry_modifiers(ob)) {
 +                              BKE_gpencil_geometry_modifiers(depsgraph, ob, gpl, derived_gpf, stl->storage->is_render);
 +                      }
 +              }
 +      }
 +
 +      if (src_gpf) {
 +              src_gps = src_gpf->strokes.first;
 +      }
 +      else {
 +              src_gps = NULL;
 +      }
 +
 +      for (gps = derived_gpf->strokes.first; gps; gps = gps->next) {
 +              MaterialGPencilStyle *gp_style = BKE_material_gpencil_settings_get(ob, gps->mat_nr + 1);
 +
 +              /* check if stroke can be drawn */
 +              if (gpencil_can_draw_stroke(gp_style, gps, false, is_mat_preview) == false) {
 +                      continue;
 +              }
 +              /* limit the number of shading groups */
 +              if (stl->storage->shgroup_id >= GPENCIL_MAX_SHGROUPS) {
 +                      continue;
 +              }
 +
 +              /* be sure recalc all chache in source stroke to avoid recalculation when frame change
 +               * and improve fps */
 +              if (src_gps) {
 +                      DRW_gpencil_recalc_geometry_caches(ob, gp_style, src_gps);
 +              }
 +
 +              /* if the fill has any value, it's considered a fill and is not drawn if simplify fill is enabled */
 +              if ((stl->storage->simplify_fill) && (scene->r.simplify_gpencil & SIMPLIFY_GPENCIL_REMOVE_FILL_LINE)) {
 +                      if ((gp_style->fill_rgba[3] > GPENCIL_ALPHA_OPACITY_THRESH) ||
 +                          (gp_style->fill_style > GP_STYLE_FILL_STYLE_SOLID))
 +                      {
 +                              continue;
 +                      }
 +              }
 +
 +              if ((gpl->actframe->framenum == derived_gpf->framenum) ||
 +                  (!is_multiedit) || (overlay_multiedit))
 +              {
 +                      int id = stl->storage->shgroup_id;
 +                      if (gps->totpoints > 0) {
 +                              if ((gps->totpoints > 2) && (!stl->storage->simplify_fill) &&
 +                                  ((gp_style->fill_rgba[3] > GPENCIL_ALPHA_OPACITY_THRESH) || (gp_style->fill_style > 0)) &&
 +                                  ((gps->flag & GP_STROKE_NOFILL) == 0))
 +                              {
 +                                      stl->shgroups[id].shgrps_fill = DRW_gpencil_shgroup_fill_create(
 +                                              e_data, vedata, psl->stroke_pass, e_data->gpencil_fill_sh, gpd, gp_style, id);
 +                              }
 +                              else {
 +                                      stl->shgroups[id].shgrps_fill = NULL;
 +                              }
 +                              if ((gp_style->mode == GP_STYLE_MODE_LINE) && (gps->totpoints > 1)) {
 +                                      stl->shgroups[id].shgrps_stroke = DRW_gpencil_shgroup_stroke_create(
 +                                              e_data, vedata, psl->stroke_pass, e_data->gpencil_stroke_sh, ob, gpd, gp_style, id, false);
 +                              }
 +                              else {
 +                                      stl->shgroups[id].shgrps_stroke = DRW_gpencil_shgroup_point_create(
 +                                              e_data, vedata, psl->stroke_pass, e_data->gpencil_point_sh, ob, gpd, gp_style, id, false);
 +                              }
 +                      }
 +                      else {
 +                              stl->shgroups[id].shgrps_fill = NULL;
 +                              stl->shgroups[id].shgrps_stroke = NULL;
 +                      }
 +                      stl->storage->shgroup_id++;
 +
 +                      fillgrp = stl->shgroups[id].shgrps_fill;
 +                      strokegrp = stl->shgroups[id].shgrps_stroke;
 +
 +                      /* copy color to temp fields to apply temporal changes in the stroke */
 +                      copy_v4_v4(gps->runtime.tmp_stroke_rgba, gp_style->stroke_rgba);
 +                      copy_v4_v4(gps->runtime.tmp_fill_rgba, gp_style->fill_rgba);
 +
 +                      /* apply modifiers (only modify geometry, but not create ) */
 +                      if ((cache->is_dirty) && (ob->greasepencil_modifiers.first) && (!is_multiedit)) {
 +                              if (!stl->storage->simplify_modif) {
 +                                      BKE_gpencil_stroke_modifiers(depsgraph, ob, gpl, derived_gpf, gps, stl->storage->is_render);
 +                              }
 +                      }
 +
 +                      /* fill */
 +                      if ((fillgrp) && (!stl->storage->simplify_fill)) {
 +                              gpencil_add_fill_shgroup(
 +                                      cache, fillgrp, ob, gpl, derived_gpf, gps, tintcolor, false, custonion);
 +                      }
 +                      /* stroke */
 +                      if (strokegrp) {
 +                              gpencil_add_stroke_shgroup(
 +                                      cache, strokegrp, ob, gpl, derived_gpf, gps, opacity, tintcolor, false, custonion);
 +                      }
 +              }
 +
 +              /* edit points (only in edit mode and not play animation not render) */
 +              if ((src_gps) && (!playing) && (!is_render)) {
 +                      if (!stl->g_data->shgrps_edit_line) {
 +                              stl->g_data->shgrps_edit_line = DRW_shgroup_create(e_data->gpencil_line_sh, psl->edit_pass);
 +                      }
 +                      if (!stl->g_data->shgrps_edit_point) {
 +                              stl->g_data->shgrps_edit_point = DRW_shgroup_create(e_data->gpencil_edit_point_sh, psl->edit_pass);
 +                              const float *viewport_size = DRW_viewport_size_get();
 +                              DRW_shgroup_uniform_vec2(stl->g_data->shgrps_edit_point, "Viewport", viewport_size, 1);
 +                      }
 +
 +                      gpencil_add_editpoints_shgroup(stl, cache, ts, ob, gpd, gpl, derived_gpf, src_gps);
 +              }
 +
 +              if (src_gps) {
 +                      src_gps = src_gps->next;
 +              }
 +
 +              cache->cache_idx++;
 +      }
 +}
 +
 + /* draw stroke in drawing buffer */
 +void DRW_gpencil_populate_buffer_strokes(GPENCIL_e_data *e_data, void *vedata, ToolSettings *ts, Object *ob)
 +{
 +      GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl;
 +      GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
 +      Brush *brush = BKE_brush_getactive_gpencil(ts);
 +      bGPdata *gpd = ob->data;
 +      MaterialGPencilStyle *gp_style = NULL;
 +
 +      float obscale = (ob->size[0] + ob->size[1] + ob->size[2]) / 3.0f;
 +
 +      /* use the brush material */
 +      Material *ma = BKE_gpencil_get_material_from_brush(brush);
 +      if (ma != NULL) {
 +              gp_style = ma->gp_style;
 +      }
 +      /* this is not common, but avoid any special situations when brush could be without material */
 +      if (gp_style == NULL) {
 +              gp_style = BKE_material_gpencil_settings_get(ob, ob->actcol);
 +      }
 +
 +      /* drawing strokes */
 +      /* Check if may need to draw the active stroke cache, only if this layer is the active layer
 +       * that is being edited. (Stroke buffer is currently stored in gp-data)
 +       */
 +      if (ED_gpencil_session_active() && (gpd->runtime.sbuffer_size > 0)) {
 +              if ((gpd->runtime.sbuffer_sflag & GP_STROKE_ERASER) == 0) {
 +                      /* It should also be noted that sbuffer contains temporary point types
 +                      * i.e. tGPspoints NOT bGPDspoints
 +                      */
 +                      short lthick = brush->size * obscale;
 +                      /* if only one point, don't need to draw buffer because the user has no time to see it */
 +                      if (gpd->runtime.sbuffer_size > 1) {
 +                              if ((gp_style) && (gp_style->mode == GP_STYLE_MODE_LINE)) {
 +                                      stl->g_data->shgrps_drawing_stroke = DRW_gpencil_shgroup_stroke_create(
 +                                              e_data, vedata, psl->drawing_pass, e_data->gpencil_stroke_sh, NULL, gpd, gp_style, -1, false);
 +                              }
 +                              else {
 +                                      stl->g_data->shgrps_drawing_stroke = DRW_gpencil_shgroup_point_create(
 +                                              e_data, vedata, psl->drawing_pass, e_data->gpencil_point_sh, NULL, gpd, gp_style, -1, false);
 +                              }
 +
 +                              /* use unit matrix because the buffer is in screen space and does not need conversion */
 +                              if (gpd->runtime.mode == GP_STYLE_MODE_LINE) {
 +                                      stl->g_data->batch_buffer_stroke = DRW_gpencil_get_buffer_stroke_geom(
 +                                              gpd, stl->storage->unit_matrix, lthick);
 +                              }
 +                              else {
 +                                      stl->g_data->batch_buffer_stroke = DRW_gpencil_get_buffer_point_geom(
 +                                              gpd, stl->storage->unit_matrix, lthick);
 +                              }
 +
 +                              DRW_shgroup_call_add(
 +                                      stl->g_data->shgrps_drawing_stroke,
 +                                      stl->g_data->batch_buffer_stroke,
 +                                      stl->storage->unit_matrix);
 +
 +                              if ((gpd->runtime.sbuffer_size >= 3) && (gpd->runtime.sfill[3] > GPENCIL_ALPHA_OPACITY_THRESH) &&
 +                                  ((gpd->runtime.sbuffer_sflag & GP_STROKE_NOFILL) == 0))
 +                              {
 +                                      /* if not solid, fill is simulated with solid color */
 +                                      if (gpd->runtime.bfill_style > 0) {
 +                                              gpd->runtime.sfill[3] = 0.5f;
 +                                      }
 +                                      stl->g_data->shgrps_drawing_fill = DRW_shgroup_create(
 +                                              e_data->gpencil_drawing_fill_sh, psl->drawing_pass);
 +                                      stl->g_data->batch_buffer_fill = DRW_gpencil_get_buffer_fill_geom(gpd);
 +                                      DRW_shgroup_call_add(
 +                                              stl->g_data->shgrps_drawing_fill,
 +                                              stl->g_data->batch_buffer_fill,
 +                                              stl->storage->unit_matrix);
 +                              }
 +                      }
 +              }
 +      }
 +}
 +
 +/* get alpha factor for onion strokes */
 +static void gpencil_get_onion_alpha(float color[4], bGPdata *gpd)
 +{
 +#define MIN_ALPHA_VALUE 0.01f
 +
 +      /* if fade is disabled, opacity is equal in all frames */
 +      if ((gpd->onion_flag & GP_ONION_FADE) == 0) {
 +              color[3] = gpd->onion_factor;
 +      }
 +      else {
 +              /* add override opacity factor */
 +              color[3] += gpd->onion_factor - 0.5f;
 +      }
 +
 +      CLAMP(color[3], MIN_ALPHA_VALUE, 1.0f);
 +}
 +
 +/* draw onion-skinning for a layer */
 +static void gpencil_draw_onionskins(
 +      GpencilBatchCache *cache, GPENCIL_e_data *e_data, void *vedata,
 +      Object *ob, bGPdata *gpd, bGPDlayer *gpl, bGPDframe *gpf)
 +{
 +
 +      const float default_color[3] = { UNPACK3(U.gpencil_new_layer_col) };
 +      const float alpha = 1.0f;
 +      float color[4];
 +      int idx;
 +      float fac = 1.0f;
 +      int step = 0;
 +      int mode = 0;
 +      bool colflag = false;
 +      bGPDframe *gpf_loop = NULL;
 +      int last = gpf->framenum;
 +
 +      colflag = (bool)gpd->onion_flag & GP_ONION_GHOST_PREVCOL;
 +
 +
 +      /* -------------------------------
 +       * 1) Draw Previous Frames First
 +       * ------------------------------- */
 +      step = gpd->gstep;
 +      mode = gpd->onion_mode;
 +
 +      if (gpd->onion_flag & GP_ONION_GHOST_PREVCOL) {
 +              copy_v3_v3(color, gpd->gcolor_prev);
 +      }
 +      else {
 +              copy_v3_v3(color, default_color);
 +      }
 +
 +      idx = 0;
 +      for (bGPDframe *gf = gpf->prev; gf; gf = gf->prev) {
 +              /* only selected frames */
 +              if ((mode == GP_ONION_MODE_SELECTED) && ((gf->flag & GP_FRAME_SELECT) == 0)) {
 +                      continue;
 +              }
 +              /* absolute range */
 +              if (mode == GP_ONION_MODE_ABSOLUTE) {
 +                      if ((gpf->framenum - gf->framenum) > step) {
 +                              break;
 +                      }
 +              }
 +              /* relative range */
 +              if (mode == GP_ONION_MODE_RELATIVE) {
 +                      idx++;
 +                      if (idx > step) {
 +                              break;
 +                      }
 +
 +              }
 +              /* alpha decreases with distance from curframe index */
 +              if (mode != GP_ONION_MODE_SELECTED) {
 +                      if (mode == GP_ONION_MODE_ABSOLUTE) {
 +                              fac = 1.0f - ((float)(gpf->framenum - gf->framenum) / (float)(step + 1));
 +                      }
 +                      else {
 +                              fac = 1.0f - ((float)idx / (float)(step + 1));
 +                      }
 +                      color[3] = alpha * fac * 0.66f;
 +              }
 +              else {
 +                      idx++;
 +                      fac = alpha - ((1.1f - (1.0f / (float)idx)) * 0.66f);
 +                      color[3] = fac;
 +              }
 +
 +              /* if loop option, save the frame to use later */
 +              if ((mode != GP_ONION_MODE_ABSOLUTE) && (gpd->onion_flag & GP_ONION_LOOP)) {
 +                      gpf_loop = gf;
 +              }
 +
 +              gpencil_get_onion_alpha(color, gpd);
 +              gpencil_draw_onion_strokes(cache, e_data, vedata, ob, gpd, gpl, gf, color[3], color, colflag);
 +      }
 +      /* -------------------------------
 +       * 2) Now draw next frames
 +       * ------------------------------- */
 +      step = gpd->gstep_next;
 +      mode = gpd->onion_mode;
 +
 +      if (gpd->onion_flag & GP_ONION_GHOST_NEXTCOL) {
 +              copy_v3_v3(color, gpd->gcolor_next);
 +      }
 +      else {
 +              copy_v3_v3(color, default_color);
 +      }
 +
 +      idx = 0;
 +      for (bGPDframe *gf = gpf->next; gf; gf = gf->next) {
 +              /* only selected frames */
 +              if ((mode == GP_ONION_MODE_SELECTED) && ((gf->flag & GP_FRAME_SELECT) == 0)) {
 +                      continue;
 +              }
 +              /* absolute range */
 +              if (mode == GP_ONION_MODE_ABSOLUTE) {
 +                      if ((gf->framenum - gpf->framenum) > step) {
 +                              break;
 +                      }
 +              }
 +              /* relative range */
 +              if (mode == GP_ONION_MODE_RELATIVE) {
 +                      idx++;
 +                      if (idx > step) {
 +                              break;
 +                      }
 +
 +              }
 +              /* alpha decreases with distance from curframe index */
 +              if (mode != GP_ONION_MODE_SELECTED) {
 +                      if (mode == GP_ONION_MODE_ABSOLUTE) {
 +                              fac = 1.0f - ((float)(gf->framenum - gpf->framenum) / (float)(step + 1));
 +                      }
 +                      else {
 +                              fac = 1.0f - ((float)idx / (float)(step + 1));
 +                      }
 +                      color[3] = alpha * fac * 0.66f;
 +              }
 +              else {
 +                      idx++;
 +                      fac = alpha - ((1.1f - (1.0f / (float)idx)) * 0.66f);
 +                      color[3] = fac;
 +              }
 +
 +              gpencil_get_onion_alpha(color, gpd);
 +              gpencil_draw_onion_strokes(cache, e_data, vedata, ob, gpd, gpl, gf, color[3], color, colflag);
 +              if (last < gf->framenum) {
 +                      last = gf->framenum;
 +              }
 +      }
 +
 +      /* Draw first frame in blue for loop mode */
 +      if ((gpd->onion_flag & GP_ONION_LOOP) && (gpf_loop != NULL)) {
 +              if ((last == gpf->framenum) || (gpf->next == NULL)) {
 +                      gpencil_get_onion_alpha(color, gpd);
 +                      gpencil_draw_onion_strokes(
 +                              cache, e_data, vedata, ob, gpd, gpl,
 +                              gpf_loop, color[3], color, colflag);
 +              }
 +      }
 +}
 +
 +/* populate a datablock for multiedit (no onions, no modifiers) */
 +void DRW_gpencil_populate_multiedit(GPENCIL_e_data *e_data, void *vedata, Scene *scene, Object *ob, bGPdata *gpd)
 +{
 +      bGPDframe *gpf = NULL;
 +
 +      GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
 +      const DRWContextState *draw_ctx = DRW_context_state_get();
 +      int cfra_eval = (int)DEG_get_ctime(draw_ctx->depsgraph);
 +      GpencilBatchCache *cache = gpencil_batch_cache_get(ob, cfra_eval);
 +      ToolSettings *ts = scene->toolsettings;
 +      cache->cache_idx = 0;
 +
 +      /* check if playing animation */
 +      bool playing = (bool)stl->storage->playing;
 +
 +      /* draw strokes */
 +      for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
 +              /* don't draw layer if hidden */
 +              if (gpl->flag & GP_LAYER_HIDE)
 +                      continue;
 +
 +              /* list of frames to draw */
 +              if (!playing) {
 +                      for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
 +                              if ((gpf == gpl->actframe) || (gpf->flag & GP_FRAME_SELECT)) {
 +                                      gpencil_draw_strokes(
 +                                              cache, e_data, vedata, ts, ob, gpd, gpl, gpf, gpf,
 +                                              gpl->opacity, gpl->tintcolor, false);
 +                              }
 +                      }
 +              }
 +              else {
 +                      gpf = BKE_gpencil_layer_getframe(gpl, cfra_eval, 0);
 +                      if (gpf) {
 +                              gpencil_draw_strokes(
 +                                      cache, e_data, vedata, ts, ob, gpd, gpl, gpf, gpf,
 +                                      gpl->opacity, gpl->tintcolor, false);
 +                      }
 +              }
 +
 +      }
 +
 +      cache->is_dirty = false;
 +}
 +
 +/* helper for populate a complete grease pencil datablock */
 +void DRW_gpencil_populate_datablock(GPENCIL_e_data *e_data, void *vedata, Scene *scene, Object *ob, bGPdata *gpd)
 +{
 +      GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
 +      const DRWContextState *draw_ctx = DRW_context_state_get();
 +      View3D *v3d = draw_ctx->v3d;
 +      int cfra_eval = (int)DEG_get_ctime(draw_ctx->depsgraph);
 +      ToolSettings *ts = scene->toolsettings;
 +      bGPDframe *derived_gpf = NULL;
++      const bool main_onion = v3d != NULL ? ((v3d->gp_flag & V3D_GP_SHOW_ONION_SKIN) == 0) : true;
 +      const bool no_onion = (bool)(gpd->flag & GP_DATA_STROKE_WEIGHTMODE) || main_onion;
 +      const bool overlay = v3d != NULL ? (bool)((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) : true;
 +
 +      /* check if playing animation */
 +      bool playing = (bool)stl->storage->playing;
 +
 +      GpencilBatchCache *cache = gpencil_batch_cache_get(ob, cfra_eval);
 +      cache->cache_idx = 0;
 +
 +      /* init general modifiers data */
 +      if (!stl->storage->simplify_modif) {
 +              if ((cache->is_dirty) && (ob->greasepencil_modifiers.first)) {
 +                      BKE_gpencil_lattice_init(ob);
 +              }
 +      }
 +      /* draw normal strokes */
 +      for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
 +              /* don't draw layer if hidden */
 +              if (gpl->flag & GP_LAYER_HIDE)
 +                      continue;
 +
 +              bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, cfra_eval, 0);
 +              if (gpf == NULL)
 +                      continue;
 +
 +              /* create GHash if need */
 +              if (gpl->runtime.derived_data == NULL) {
 +                      gpl->runtime.derived_data = (GHash *)BLI_ghash_str_new(gpl->info);
 +              }
 +
 +              derived_gpf = BLI_ghash_lookup(gpl->runtime.derived_data, ob->id.name);
 +              if (derived_gpf == NULL) {
 +                      cache->is_dirty = true;
 +              }
 +              if (cache->is_dirty) {
 +                      if (derived_gpf != NULL) {
 +                              /* first clear temp data */
 +                              BKE_gpencil_free_frame_runtime_data(derived_gpf);
 +                              BLI_ghash_remove(gpl->runtime.derived_data, ob->id.name, NULL, NULL);
 +                      }
 +                      /* create new data */
 +                      derived_gpf = BKE_gpencil_frame_duplicate(gpf);
 +                      BLI_ghash_insert(gpl->runtime.derived_data, ob->id.name, derived_gpf);
 +              }
 +
 +              /* draw onion skins */
 +              if ((gpd->flag & GP_DATA_SHOW_ONIONSKINS) &&
 +                  (!no_onion) && (overlay) &&
 +                  (gpl->onion_flag & GP_LAYER_ONIONSKIN) &&
 +                  ((!playing) || (gpd->onion_flag & GP_ONION_GHOST_ALWAYS)))
 +              {
 +                      if ((!stl->storage->is_render) ||
 +                          ((stl->storage->is_render) && (gpd->onion_flag & GP_ONION_GHOST_ALWAYS)))
 +                      {
 +                              gpencil_draw_onionskins(cache, e_data, vedata, ob, gpd, gpl, gpf);
 +                      }
 +              }
 +
 +              /* draw normal strokes */
 +              gpencil_draw_strokes(
 +                      cache, e_data, vedata, ts, ob, gpd, gpl, gpf, derived_gpf,
 +                      gpl->opacity, gpl->tintcolor, false);
 +
 +      }
 +
 +      /* clear any lattice data */
 +      if ((cache->is_dirty) && (ob->greasepencil_modifiers.first)) {
 +              BKE_gpencil_lattice_clear(ob);
 +      }
 +
 +      cache->is_dirty = false;
 +}
 +
 +/* Helper for gpencil_instance_modifiers()
 + * See also MOD_gpencilinstance.c -> bakeModifier()
 + */
 +static void gp_instance_modifier_make_instances(GPENCIL_StorageList *stl, Object *ob, InstanceGpencilModifierData *mmd)
 +{
 +      /* reset random */
 +      mmd->rnd[0] = 1;
 +
 +      /* Generate instances */
 +      for (int x = 0; x < mmd->count[0]; x++) {
 +              for (int y = 0; y < mmd->count[1]; y++) {
 +                      for (int z = 0; z < mmd->count[2]; z++) {
 +                              Object *newob;
 +
 +                              const int elem_idx[3] = {x, y, z};
 +                              float mat[4][4];
 +                              int sh;
 +
 +                              /* original strokes are at index = 0,0,0 */
 +                              if ((x == 0) && (y == 0) && (z == 0)) {
 +                                      continue;
 +                              }
 +
 +                              /* compute transform for instance */
 +                              BKE_gpencil_instance_modifier_instance_tfm(mmd, elem_idx, mat);
 +
 +                              /* add object to cache */
 +                              newob = MEM_dupallocN(ob);
 +                              mul_m4_m4m4(newob->obmat, ob->obmat, mat);
 +
 +                              /* apply scale */
 +                              ARRAY_SET_ITEMS(newob->size, mat[0][0], mat[1][1], mat[2][2]);
 +
 +                              /* apply shift */
 +                              sh = x;
 +                              if (mmd->lock_axis == GP_LOCKAXIS_Y) {
 +                                      sh = y;
 +                              }
 +                              if (mmd->lock_axis == GP_LOCKAXIS_Z) {
 +                                      sh = z;
 +                              }
 +                              madd_v3_v3fl(newob->obmat[3], mmd->shift, sh);
 +
 +                              /* add temp object to cache */
 +                              stl->g_data->gp_object_cache = gpencil_object_cache_add(
 +                                      stl->g_data->gp_object_cache, newob, true,
 +                                      &stl->g_data->gp_cache_size, &stl->g_data->gp_cache_used);
 +                      }
 +              }
 +      }
 +}
 +
 +/* create instances using instance modifiers */
 +void gpencil_instance_modifiers(GPENCIL_StorageList *stl, Object *ob)
 +{
 +      if ((ob) && (ob->data)) {
 +              bGPdata *gpd = ob->data;
 +              if (GPENCIL_ANY_EDIT_MODE(gpd)) {
 +                      return;
 +              }
 +      }
 +
 +      for (GpencilModifierData *md = ob->greasepencil_modifiers.first; md; md = md->next) {
 +              if (((md->mode & eGpencilModifierMode_Realtime) && (stl->storage->is_render == false)) ||
 +                  ((md->mode & eGpencilModifierMode_Render) && (stl->storage->is_render == true)))
 +              {
 +                      if (md->type == eGpencilModifierType_Instance) {
 +                              InstanceGpencilModifierData *mmd = (InstanceGpencilModifierData *)md;
 +
 +                              /* Only add instances if the "Make Objects" flag is set
 +                               * FIXME: This is a workaround for z-ordering weirdness when all instances are in the same object
 +                               */
 +                              if (mmd->flag & GP_INSTANCE_MAKE_OBJECTS) {
 +                                      gp_instance_modifier_make_instances(stl, ob, mmd);
 +                              }
 +                      }
 +              }
 +      }
 +}
index 0c76971ac4b6888d2baae7af48fe5490e7fbd7f7,0000000000000000000000000000000000000000..8b8da3f20652aae10f2aaa45583234a3ce55bee9
mode 100644,000000..100644
--- /dev/null
@@@ -1,803 -1,0 +1,803 @@@
-                   (v3d->flag3 & V3D_GP_SHOW_GRID) &&
 +/*
 + * 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_engine.c
 + *  \ingroup draw
 + */
 +#include "DRW_engine.h"
 +#include "DRW_render.h"
 +
 +#include "BKE_camera.h"
 +#include "BKE_object.h"
 +#include "BKE_paint.h"
 +#include "BKE_gpencil.h"
 +#include "BKE_shader_fx.h"
 +
 +#include "DNA_gpencil_types.h"
 +#include "DNA_view3d_types.h"
 +
 +#include "draw_mode_engines.h"
 +
 +#include "UI_resources.h"
 +
 +#include "GPU_texture.h"
 +
 +#include "gpencil_engine.h"
 +
 +#include "ED_screen.h"
 +#include "ED_gpencil.h"
 +
 +extern char datatoc_gpencil_fill_vert_glsl[];
 +extern char datatoc_gpencil_fill_frag_glsl[];
 +extern char datatoc_gpencil_stroke_vert_glsl[];
 +extern char datatoc_gpencil_stroke_geom_glsl[];
 +extern char datatoc_gpencil_stroke_frag_glsl[];
 +extern char datatoc_gpencil_zdepth_mix_frag_glsl[];
 +extern char datatoc_gpencil_simple_mix_frag_glsl[];
 +extern char datatoc_gpencil_point_vert_glsl[];
 +extern char datatoc_gpencil_point_geom_glsl[];
 +extern char datatoc_gpencil_point_frag_glsl[];
 +extern char datatoc_gpencil_background_frag_glsl[];
 +extern char datatoc_gpencil_paper_frag_glsl[];
 +extern char datatoc_gpencil_edit_point_vert_glsl[];
 +extern char datatoc_gpencil_edit_point_geom_glsl[];
 +extern char datatoc_gpencil_edit_point_frag_glsl[];
 +
 +/* *********** STATIC *********** */
 +static GPENCIL_e_data e_data = {NULL}; /* Engine data */
 +
 +/* *********** FUNCTIONS *********** */
 +
 +/* create a multisample buffer if not present */
 +void DRW_gpencil_multisample_ensure(GPENCIL_Data *vedata, int rect_w, int rect_h)
 +{
 +      GPENCIL_FramebufferList *fbl = vedata->fbl;
 +      GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
 +      GPENCIL_TextureList *txl = ((GPENCIL_Data *)vedata)->txl;
 +
 +      short samples = stl->storage->multisamples;
 +
 +      if (samples > 0) {
 +              if (!fbl->multisample_fb) {
 +                      fbl->multisample_fb = GPU_framebuffer_create();
 +                      if (fbl->multisample_fb) {
 +                              if (txl->multisample_color == NULL) {
 +                                      txl->multisample_color = GPU_texture_create_2D_multisample(
 +                                              rect_w, rect_h, GPU_RGBA16F, NULL, samples, NULL);
 +                              }
 +                              if (txl->multisample_depth == NULL) {
 +                                      txl->multisample_depth = GPU_texture_create_2D_multisample(
 +                                              rect_w, rect_h, GPU_DEPTH24_STENCIL8, NULL, samples, NULL);
 +                              }
 +                              GPU_framebuffer_ensure_config(
 +                                      &fbl->multisample_fb, {
 +                                          GPU_ATTACHMENT_TEXTURE(txl->multisample_depth),
 +                                          GPU_ATTACHMENT_TEXTURE(txl->multisample_color)
 +                                      });
 +                      }
 +              }
 +      }
 +}
 +
 +static void GPENCIL_create_framebuffers(void *vedata)
 +{
 +      GPENCIL_FramebufferList *fbl = ((GPENCIL_Data *)vedata)->fbl;
 +      GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
 +
 +      /* Go full 32bits for rendering */
 +      GPUTextureFormat fb_format = DRW_state_is_image_render() ? GPU_RGBA32F : GPU_RGBA16F;
 +
 +      if (DRW_state_is_fbo()) {
 +              const float *viewport_size = DRW_viewport_size_get();
 +              const int size[2] = { (int)viewport_size[0], (int)viewport_size[1] };
 +
 +              /* create multiframe framebuffer for AA */
 +              if (stl->storage->multisamples > 0) {
 +                      DRW_gpencil_multisample_ensure(vedata, size[0], size[1]);
 +              }
 +
 +              /* temp textures */
 +              e_data.temp_depth_tx_a = DRW_texture_pool_query_2D(size[0], size[1], GPU_DEPTH24_STENCIL8,
 +                      &draw_engine_gpencil_type);
 +              e_data.temp_color_tx_a = DRW_texture_pool_query_2D(size[0], size[1], fb_format,
 +                      &draw_engine_gpencil_type);
 +              GPU_framebuffer_ensure_config(
 +                      &fbl->temp_fb_a, {
 +                          GPU_ATTACHMENT_TEXTURE(e_data.temp_depth_tx_a),
 +                          GPU_ATTACHMENT_TEXTURE(e_data.temp_color_tx_a)
 +                      });
 +
 +              e_data.temp_depth_tx_b = DRW_texture_pool_query_2D(
 +                      size[0], size[1], GPU_DEPTH24_STENCIL8,
 +                      &draw_engine_gpencil_type);
 +              e_data.temp_color_tx_b = DRW_texture_pool_query_2D(
 +                      size[0], size[1], fb_format,
 +                      &draw_engine_gpencil_type);
 +              GPU_framebuffer_ensure_config(
 +                      &fbl->temp_fb_b, {
 +                          GPU_ATTACHMENT_TEXTURE(e_data.temp_depth_tx_b),
 +                          GPU_ATTACHMENT_TEXTURE(e_data.temp_color_tx_b)
 +                      });
 +
 +              /* used for rim FX effect */
 +              e_data.temp_depth_tx_rim = DRW_texture_pool_query_2D(
 +                      size[0], size[1], GPU_DEPTH24_STENCIL8,
 +                      &draw_engine_gpencil_type);
 +              e_data.temp_color_tx_rim = DRW_texture_pool_query_2D(
 +                      size[0], size[1], fb_format,
 +                      &draw_engine_gpencil_type);
 +              GPU_framebuffer_ensure_config(
 +                      &fbl->temp_fb_rim, {
 +                          GPU_ATTACHMENT_TEXTURE(e_data.temp_depth_tx_rim),
 +                          GPU_ATTACHMENT_TEXTURE(e_data.temp_color_tx_rim),
 +                      });
 +
 +              /* background framebuffer to speed up drawing process (always 16 bits) */
 +              e_data.background_depth_tx = DRW_texture_pool_query_2D(
 +                      size[0], size[1], GPU_DEPTH24_STENCIL8,
 +                      &draw_engine_gpencil_type);
 +              e_data.background_color_tx = DRW_texture_pool_query_2D(
 +                      size[0], size[1], GPU_RGBA32F,
 +                      &draw_engine_gpencil_type);
 +              GPU_framebuffer_ensure_config(
 +                      &fbl->background_fb, {
 +                          GPU_ATTACHMENT_TEXTURE(e_data.background_depth_tx),
 +                          GPU_ATTACHMENT_TEXTURE(e_data.background_color_tx)
 +                      });
 +      }
 +}
 +
 +static void GPENCIL_create_shaders(void)
 +{
 +      /* normal fill shader */
 +      if (!e_data.gpencil_fill_sh) {
 +              e_data.gpencil_fill_sh = DRW_shader_create(
 +                      datatoc_gpencil_fill_vert_glsl, NULL,
 +                      datatoc_gpencil_fill_frag_glsl, NULL);
 +      }
 +
 +      /* normal stroke shader using geometry to display lines (line mode) */
 +      if (!e_data.gpencil_stroke_sh) {
 +              e_data.gpencil_stroke_sh = DRW_shader_create(
 +                      datatoc_gpencil_stroke_vert_glsl,
 +                      datatoc_gpencil_stroke_geom_glsl,
 +                      datatoc_gpencil_stroke_frag_glsl,
 +                      NULL);
 +      }
 +
 +      /* dot/rectangle mode for normal strokes using geometry */
 +      if (!e_data.gpencil_point_sh) {
 +              e_data.gpencil_point_sh = DRW_shader_create(
 +                      datatoc_gpencil_point_vert_glsl,
 +                      datatoc_gpencil_point_geom_glsl,
 +                      datatoc_gpencil_point_frag_glsl,
 +                      NULL);
 +      }
 +      /* used for edit points or strokes with one point only */
 +      if (!e_data.gpencil_edit_point_sh) {
 +              e_data.gpencil_edit_point_sh = DRW_shader_create(
 +                      datatoc_gpencil_edit_point_vert_glsl,
 +                      datatoc_gpencil_edit_point_geom_glsl,
 +                      datatoc_gpencil_edit_point_frag_glsl, NULL);
 +      }
 +
 +      /* used for edit lines for edit modes */
 +      if (!e_data.gpencil_line_sh) {
 +              e_data.gpencil_line_sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_FLAT_COLOR);
 +      }
 +
 +      /* used to filling during drawing */
 +      if (!e_data.gpencil_drawing_fill_sh) {
 +              e_data.gpencil_drawing_fill_sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_SMOOTH_COLOR);
 +      }
 +
 +      /* full screen for mix zdepth*/
 +      if (!e_data.gpencil_fullscreen_sh) {
 +              e_data.gpencil_fullscreen_sh = DRW_shader_create_fullscreen(datatoc_gpencil_zdepth_mix_frag_glsl, NULL);
 +      }
 +      if (!e_data.gpencil_simple_fullscreen_sh) {
 +              e_data.gpencil_simple_fullscreen_sh = DRW_shader_create_fullscreen(datatoc_gpencil_simple_mix_frag_glsl, NULL);
 +      }
 +
 +      /* shaders for use when drawing */
 +      if (!e_data.gpencil_background_sh) {
 +              e_data.gpencil_background_sh = DRW_shader_create_fullscreen(datatoc_gpencil_background_frag_glsl, NULL);
 +      }
 +      if (!e_data.gpencil_paper_sh) {
 +              e_data.gpencil_paper_sh = DRW_shader_create_fullscreen(datatoc_gpencil_paper_frag_glsl, NULL);
 +      }
 +}
 +
 +void GPENCIL_engine_init(void *vedata)
 +{
 +      GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
 +      /* init storage */
 +      if (!stl->storage) {
 +              stl->storage = MEM_callocN(sizeof(GPENCIL_Storage), "GPENCIL_Storage");
 +
 +              /* unit matrix */
 +              unit_m4(stl->storage->unit_matrix);
 +      }
 +
 +      stl->storage->multisamples = U.gpencil_multisamples;
 +
 +      /* create framebuffers */
 +      GPENCIL_create_framebuffers(vedata);
 +
 +      /* create shaders */
 +      GPENCIL_create_shaders();
 +      GPENCIL_create_fx_shaders(&e_data);
 +
 +      /* blank texture used if no texture defined for fill shader */
 +      if (!e_data.gpencil_blank_texture) {
 +              float rect[16][16][4] = {{{0.0f}}};
 +              e_data.gpencil_blank_texture = DRW_texture_create_2D(16, 16, GPU_RGBA8, DRW_TEX_FILTER, (float *)rect);
 +      }
 +}
 +
 +static void GPENCIL_engine_free(void)
 +{
 +      /* only free custom shaders, builtin shaders are freed in blender close */
 +      DRW_SHADER_FREE_SAFE(e_data.gpencil_fill_sh);
 +      DRW_SHADER_FREE_SAFE(e_data.gpencil_stroke_sh);
 +      DRW_SHADER_FREE_SAFE(e_data.gpencil_point_sh);
 +      DRW_SHADER_FREE_SAFE(e_data.gpencil_edit_point_sh);
 +      DRW_SHADER_FREE_SAFE(e_data.gpencil_fullscreen_sh);
 +      DRW_SHADER_FREE_SAFE(e_data.gpencil_simple_fullscreen_sh);
 +      DRW_SHADER_FREE_SAFE(e_data.gpencil_background_sh);
 +      DRW_SHADER_FREE_SAFE(e_data.gpencil_paper_sh);
 +
 +      DRW_TEXTURE_FREE_SAFE(e_data.gpencil_blank_texture);
 +
 +      /* effects */
 +      GPENCIL_delete_fx_shaders(&e_data);
 +}
 +
 +void GPENCIL_cache_init(void *vedata)
 +{
 +      GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl;
 +      GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
 +      const DRWContextState *draw_ctx = DRW_context_state_get();
 +      Scene *scene = draw_ctx->scene;
 +      View3D *v3d = draw_ctx->v3d;
 +
 +      /* Special handling for when active object is GP object (e.g. for draw mode) */
 +      Object *obact = draw_ctx->obact;
 +      bGPdata *obact_gpd = NULL;
 +      MaterialGPencilStyle *gp_style = NULL;
 +
 +      if (obact && (obact->type == OB_GPENCIL) && (obact->data)) {
 +              obact_gpd = (bGPdata *)obact->data;
 +              gp_style = BKE_material_gpencil_settings_get(obact, obact->actcol);
 +      }
 +
 +      if (!stl->g_data) {
 +              /* Alloc transient pointers */
 +              stl->g_data = MEM_mallocN(sizeof(g_data), "g_data");
 +              stl->storage->xray = GP_XRAY_FRONT; /* used for drawing */
 +              stl->storage->stroke_style = GP_STYLE_STROKE_STYLE_SOLID; /* used for drawing */
 +      }
 +      stl->storage->tonemapping = 0;
 +
 +      stl->g_data->shgrps_edit_line = NULL;
 +      stl->g_data->shgrps_edit_point = NULL;
 +
 +      if (!stl->shgroups) {
 +              /* Alloc maximum size because count strokes is very slow and can be very complex due onion skinning.
 +                 I tried to allocate only one block and using realloc, increasing the size when read a new strokes
 +                 in cache_finish, but the realloc produce weird things on screen, so we keep as is while we found
 +                 a better solution
 +               */
 +              stl->shgroups = MEM_mallocN(sizeof(GPENCIL_shgroup) * GPENCIL_MAX_SHGROUPS, "GPENCIL_shgroup");
 +      }
 +
 +      /* init gp objects cache */
 +      stl->g_data->gp_cache_used = 0;
 +      stl->g_data->gp_cache_size = 0;
 +      stl->g_data->gp_object_cache = NULL;
 +
 +      {
 +              /* Stroke pass */
 +              psl->stroke_pass = DRW_pass_create(
 +                      "GPencil Stroke Pass",
 +                      DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS | DRW_STATE_BLEND);
 +              stl->storage->shgroup_id = 0;
 +
 +              /* edit pass */
 +              psl->edit_pass = DRW_pass_create(
 +                      "GPencil Edit Pass",
 +                      DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND);
 +
 +              /* detect if playing animation */
 +              stl->storage->playing = 0;
 +              if (draw_ctx->evil_C) {
 +                      stl->storage->playing = ED_screen_animation_playing(CTX_wm_manager(draw_ctx->evil_C)) != NULL ? 1 : 0;
 +              }
 +
 +              if (obact_gpd) {
 +                      /* for some reason, when press play there is a delay in the animation flag check
 +                      * and this produces errors. To be sure, we set cache as dirty because the frame
 +                      * is changing.
 +                      */
 +                      if (stl->storage->playing == 1) {
 +                              obact_gpd->flag |= GP_DATA_CACHE_IS_DIRTY;
 +                      }
 +                      /* if render, set as dirty to update all data */
 +                      else if (stl->storage->is_render == true) {
 +                              obact_gpd->flag |= GP_DATA_CACHE_IS_DIRTY;
 +                      }
 +              }
 +
 +              /* save render state */
 +              stl->storage->is_render = DRW_state_is_image_render();
 +              stl->storage->is_mat_preview = (bool)stl->storage->is_render && STREQ(scene->id.name + 2, "preview");
 +
 +              /* save simplify flags (can change while drawing, so it's better to save) */
 +              stl->storage->simplify_fill = GP_SIMPLIFY_FILL(scene, stl->storage->playing);
 +              stl->storage->simplify_modif = GP_SIMPLIFY_MODIF(scene, stl->storage->playing);
 +
 +              /* save pixsize */
 +              stl->storage->pixsize = DRW_viewport_pixelsize_get();
 +              if ((!DRW_state_is_opengl_render()) && (stl->storage->is_render)) {
 +                      stl->storage->pixsize = &stl->storage->render_pixsize;
 +              }
 +
 +              /* detect if painting session */
 +              if ((obact_gpd) &&
 +                  (obact_gpd->flag & GP_DATA_STROKE_PAINTMODE) &&
 +                  (stl->storage->playing == 0))
 +              {
 +                      if (((obact_gpd->runtime.sbuffer_sflag & GP_STROKE_ERASER) == 0) &&
 +                          (obact_gpd->runtime.sbuffer_size > 1))
 +                      {
 +                              stl->g_data->session_flag = GP_DRW_PAINT_PAINTING;
 +                      }
 +                      else {
 +                              stl->g_data->session_flag = GP_DRW_PAINT_IDLE;
 +                      }
 +              }
 +              else {
 +                      /* if not drawing mode */
 +                      stl->g_data->session_flag = GP_DRW_PAINT_HOLD;
 +              }
 +
 +              if (gp_style) {
 +                      stl->storage->stroke_style = gp_style->stroke_style;
 +                      stl->storage->color_type = GPENCIL_COLOR_SOLID;
 +                      if (gp_style->stroke_style == GP_STYLE_STROKE_STYLE_TEXTURE) {
 +                              stl->storage->color_type = GPENCIL_COLOR_TEXTURE;
 +                              if (gp_style->flag & GP_STYLE_STROKE_PATTERN) {
 +                                      stl->storage->color_type = GPENCIL_COLOR_PATTERN;
 +                              }
 +                      }
 +              }
 +              else {
 +                      stl->storage->stroke_style = GP_STYLE_STROKE_STYLE_SOLID;
 +                      stl->storage->color_type = GPENCIL_COLOR_SOLID;
 +              }
 +
 +              /* drawing buffer pass for drawing the stroke that is beeing drawing by the user. The data
 +               * is stored in sbuffer
 +               */
 +              psl->drawing_pass = DRW_pass_create(
 +                      "GPencil Drawing Pass",
 +                      DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS);
 +
 +              /* full screen pass to combine the result with default framebuffer */
 +              struct GPUBatch *quad = DRW_cache_fullscreen_quad_get();
 +              psl->mix_pass = DRW_pass_create(
 +                      "GPencil Mix Pass",
 +                      DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS);
 +              DRWShadingGroup *mix_shgrp = DRW_shgroup_create(e_data.gpencil_fullscreen_sh, psl->mix_pass);
 +              DRW_shgroup_call_add(mix_shgrp, quad, NULL);
 +              DRW_shgroup_uniform_texture_ref(mix_shgrp, "strokeColor", &e_data.input_color_tx);
 +              DRW_shgroup_uniform_texture_ref(mix_shgrp, "strokeDepth", &e_data.input_depth_tx);
 +              DRW_shgroup_uniform_int(mix_shgrp, "tonemapping", &stl->storage->tonemapping, 1);
 +
 +              /* mix pass no blend used to copy between passes. A separated pass is required
 +               * because if mix_pass is used, the acumulation of blend degrade the colors.
 +               *
 +               * This pass is used too to take the snapshot used for background_pass. This image
 +               * will be used as the background while the user is drawing.
 +               */
 +              psl->mix_pass_noblend = DRW_pass_create(
 +                      "GPencil Mix Pass no blend",
 +                      DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS);
 +              DRWShadingGroup *mix_shgrp_noblend = DRW_shgroup_create(e_data.gpencil_fullscreen_sh, psl->mix_pass_noblend);
 +              DRW_shgroup_call_add(mix_shgrp_noblend, quad, NULL);
 +              DRW_shgroup_uniform_texture_ref(mix_shgrp_noblend, "strokeColor", &e_data.input_color_tx);
 +              DRW_shgroup_uniform_texture_ref(mix_shgrp_noblend, "strokeDepth", &e_data.input_depth_tx);
 +              DRW_shgroup_uniform_int(mix_shgrp_noblend, "tonemapping", &stl->storage->tonemapping, 1);
 +
 +              /* Painting session pass (used only to speedup while the user is drawing )
 +               * This pass is used to show the snapshot of the current grease pencil strokes captured
 +               * when the user starts to draw (see comments above).
 +               * In this way, the previous strokes don't need to be redraw and the drawing process
 +               * is far to agile.
 +               */
 +              psl->background_pass = DRW_pass_create(
 +                      "GPencil Background Painting Session Pass",
 +                      DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS);
 +              DRWShadingGroup *background_shgrp = DRW_shgroup_create(e_data.gpencil_background_sh, psl->background_pass);
 +              DRW_shgroup_call_add(background_shgrp, quad, NULL);
 +              DRW_shgroup_uniform_texture_ref(background_shgrp, "strokeColor", &e_data.background_color_tx);
 +              DRW_shgroup_uniform_texture_ref(background_shgrp, "strokeDepth", &e_data.background_depth_tx);
 +
 +              /* pass for drawing paper (only if viewport)
 +               * In render, the v3d is null so the paper is disabled
 +               * The paper is way to isolate the drawing in complex scene and to have a cleaner
 +               * drawing area.
 +               */
 +              if (v3d) {
 +                      psl->paper_pass = DRW_pass_create(
 +                              "GPencil Paper Pass",
 +                              DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND);
 +                      DRWShadingGroup *paper_shgrp = DRW_shgroup_create(e_data.gpencil_paper_sh, psl->paper_pass);
 +                      DRW_shgroup_call_add(paper_shgrp, quad, NULL);
 +                      DRW_shgroup_uniform_vec3(paper_shgrp, "color", v3d->shading.background_color, 1);
 +                      DRW_shgroup_uniform_float(paper_shgrp, "opacity", &v3d->overlay.gpencil_paper_opacity, 1);
 +              }
 +
 +              /* grid pass */
 +              if (v3d) {
 +                      psl->grid_pass = DRW_pass_create(
 +                              "GPencil Grid Pass",
 +                              DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS);
 +                      stl->g_data->shgrps_grid = DRW_shgroup_create(e_data.gpencil_line_sh, psl->grid_pass);
 +              }
 +
 +              /* create effects passes */
 +              GPENCIL_create_fx_passes(psl);
 +      }
 +}
 +
 +void GPENCIL_cache_populate(void *vedata, Object *ob)
 +{
 +      /* object must be visible */
 +      if (!DRW_check_object_visible_within_active_context(ob)) {
 +              return;
 +      }
 +
 +      GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
 +      const DRWContextState *draw_ctx = DRW_context_state_get();
 +      Scene *scene = draw_ctx->scene;
 +      ToolSettings *ts = scene->toolsettings;
 +      View3D *v3d = draw_ctx->v3d;
 +
 +      /* object datablock (this is not draw now) */
 +      if (ob->type == OB_GPENCIL && ob->data) {
 +              bGPdata *gpd = (bGPdata *)ob->data;
 +              if ((stl->g_data->session_flag & GP_DRW_PAINT_READY) == 0) {
 +
 +                      /* if render set as dirty */
 +                      if (stl->storage->is_render == true) {
 +                              gpd->flag |= GP_DATA_CACHE_IS_DIRTY;
 +                      }
 +
 +                      /* allocate memory for saving gp objects for drawing later */
 +                      stl->g_data->gp_object_cache = gpencil_object_cache_add(
 +                              stl->g_data->gp_object_cache, ob, false,
 +                              &stl->g_data->gp_cache_size, &stl->g_data->gp_cache_used);
 +
 +                      /* generate instances as separate cache objects for instance modifiers
 +                       * with the "Make as Objects" option enabled
 +                       */
 +                      if (!stl->storage->simplify_modif) {
 +                              gpencil_instance_modifiers(stl, ob);
 +                      }
 +              }
 +              /* draw current painting strokes */
 +              DRW_gpencil_populate_buffer_strokes(&e_data, vedata, ts, ob);
 +
 +              /* grid */
 +              if ((v3d) &&
 +                  ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) &&
-                   (v3d->flag3 & V3D_GP_SHOW_PAPER) &&
++                  (v3d->gp_flag & V3D_GP_SHOW_GRID) &&
 +                  (ob->type == OB_GPENCIL) && (ob == draw_ctx->obact))
 +              {
 +                      stl->g_data->batch_grid = DRW_gpencil_get_grid();
 +                      DRW_shgroup_call_add(stl->g_data->shgrps_grid,
 +                              stl->g_data->batch_grid,
 +                              ob->obmat);
 +              }
 +      }
 +}
 +
 +void GPENCIL_cache_finish(void *vedata)
 +{
 +      GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
 +      const DRWContextState *draw_ctx = DRW_context_state_get();
 +      Scene *scene = draw_ctx->scene;
 +      bool is_multiedit = false;
 +
 +      /* if painting session, don't need to do more */
 +      if (stl->g_data->session_flag & GP_DRW_PAINT_PAINTING) {
 +              return;
 +      }
 +
 +      /* Draw all pending objects */
 +      if (stl->g_data->gp_cache_used > 0) {
 +              for (int i = 0; i < stl->g_data->gp_cache_used; i++) {
 +                      Object *ob = stl->g_data->gp_object_cache[i].ob;
 +                      bGPdata *gpd = ob->data;
 +
 +                      /* save init shading group */
 +                      stl->g_data->gp_object_cache[i].init_grp = stl->storage->shgroup_id;
 +
 +                      /* fill shading groups */
 +                      is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
 +                      if (!is_multiedit) {
 +                              DRW_gpencil_populate_datablock(&e_data, vedata, scene, ob, gpd);
 +                      }
 +                      else {
 +                              DRW_gpencil_populate_multiedit(&e_data, vedata, scene, ob, gpd);
 +                      }
 +
 +                      /* save end shading group */
 +                      stl->g_data->gp_object_cache[i].end_grp = stl->storage->shgroup_id - 1;
 +                      /* if render set to dirty to refresh viewport */
 +                      if (stl->storage->is_render == true) {
 +                              gpd->flag |= GP_DATA_CACHE_IS_DIRTY;
 +                      }
 +                      /* FX passses */
 +                      tGPencilObjectCache *cache = &stl->g_data->gp_object_cache[i];
 +                      if (!is_multiedit) {
 +                              DRW_gpencil_fx_prepare(&e_data, vedata, cache);
 +                      }
 +              }
 +      }
 +}
 +
 +/* helper function to sort inverse gpencil objects using qsort */
 +static int gpencil_object_cache_compare_zdepth(const void *a1, const void *a2)
 +{
 +      const tGPencilObjectCache *ps1 = a1, *ps2 = a2;
 +
 +      if (ps1->zdepth < ps2->zdepth) return 1;
 +      else if (ps1->zdepth > ps2->zdepth) return -1;
 +
 +      return 0;
 +}
 +
 +/* prepare a texture with full viewport screenshot for fast drawing */
 +static void gpencil_prepare_fast_drawing(
 +        GPENCIL_StorageList *stl, DefaultFramebufferList *dfbl,
 +        GPENCIL_FramebufferList *fbl, DRWPass *pass,
 +        const float clearcol[4])
 +{
 +      if (stl->g_data->session_flag & (GP_DRW_PAINT_IDLE | GP_DRW_PAINT_FILLING)) {
 +              GPU_framebuffer_bind(fbl->background_fb);
 +              /* clean only in first loop cycle */
 +              if (stl->g_data->session_flag & GP_DRW_PAINT_IDLE) {
 +                      GPU_framebuffer_clear_color_depth(fbl->background_fb, clearcol, 1.0f);
 +                      stl->g_data->session_flag = GP_DRW_PAINT_FILLING;
 +              }
 +              /* repeat pass to fill temp texture */
 +              DRW_draw_pass(pass);
 +              /* set default framebuffer again */
 +              GPU_framebuffer_bind(dfbl->default_fb);
 +      }
 +}
 +
 +static void gpencil_free_obj_list(GPENCIL_StorageList *stl)
 +{
 +      /* Clear temp objects created for display instances only. These objects are created
 +       * while the draw manager draw the scene, but only to hold the strokes data.
 +       * see: gp_instance_modifier_make_instances()
 +       *
 +       * the normal objects are not freed because they are not tagged as temp objects
 +       */
 +      for (int i = 0; i < stl->g_data->gp_cache_used; i++) {
 +              Object *ob = stl->g_data->gp_object_cache[i].ob;
 +              if (stl->g_data->gp_object_cache[i].temp_ob) {
 +                      MEM_SAFE_FREE(ob);
 +              }
 +      }
 +
 +      /* free the cache itself */
 +      MEM_SAFE_FREE(stl->g_data->gp_object_cache);
 +}
 +
 +/* draw scene */
 +void GPENCIL_draw_scene(void *ved)
 +{
 +      GPENCIL_Data *vedata = (GPENCIL_Data *)ved;
 +      GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
 +
 +      GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl;
 +      GPENCIL_FramebufferList *fbl = ((GPENCIL_Data *)vedata)->fbl;
 +      DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
 +      GPENCIL_TextureList *txl = ((GPENCIL_Data *)vedata)->txl;
 +
 +      int init_grp, end_grp;
 +      tGPencilObjectCache *cache;
 +      const float clearcol[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
 +
 +      const DRWContextState *draw_ctx = DRW_context_state_get();
 +      View3D *v3d = draw_ctx->v3d;
 +      Object *obact = draw_ctx->obact;
 +      const bool playing = (bool)stl->storage->playing;
 +      const bool is_render = stl->storage->is_render;
 +
 +      /* paper pass to display a confortable area to draw over complex scenes with geometry */
 +      if ((!is_render) && (obact) && (obact->type == OB_GPENCIL)) {
 +              if (((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) &&
-                           (v3d->flag3 & V3D_GP_SHOW_GRID))
++                  (v3d->gp_flag & V3D_GP_SHOW_PAPER) &&
 +                  (stl->g_data->gp_cache_used > 0))
 +              {
 +                      DRW_draw_pass(psl->paper_pass);
 +              }
 +      }
 +
 +      /* if we have a painting session, we use fast viewport drawing method */
 +      if ((!is_render) && (stl->g_data->session_flag & GP_DRW_PAINT_PAINTING)) {
 +              GPU_framebuffer_bind(dfbl->default_fb);
 +
 +              MULTISAMPLE_GP_SYNC_ENABLE(stl->storage->multisamples, fbl);
 +
 +              DRW_draw_pass(psl->background_pass);
 +              DRW_draw_pass(psl->drawing_pass);
 +
 +              MULTISAMPLE_GP_SYNC_DISABLE(stl->storage->multisamples, fbl, dfbl->default_fb, txl);
 +
 +              /* free memory */
 +              gpencil_free_obj_list(stl);
 +
 +              /* grid pass */
 +              if ((!is_render) && (obact) && (obact->type == OB_GPENCIL)) {
 +                      if (((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) &&
-                           (v3d->flag3 & V3D_GP_SHOW_GRID))
++                          (v3d->gp_flag & V3D_GP_SHOW_GRID))
 +                      {
 +                              DRW_draw_pass(psl->grid_pass);
 +                      }
 +              }
 +
 +              return;
 +      }
 +
 +      if (DRW_state_is_fbo()) {
 +              /* attach temp textures */
 +              GPU_framebuffer_texture_attach(fbl->temp_fb_a, e_data.temp_depth_tx_a, 0, 0);
 +              GPU_framebuffer_texture_attach(fbl->temp_fb_a, e_data.temp_color_tx_a, 0, 0);
 +              GPU_framebuffer_texture_attach(fbl->temp_fb_b, e_data.temp_depth_tx_b, 0, 0);
 +              GPU_framebuffer_texture_attach(fbl->temp_fb_b, e_data.temp_color_tx_b, 0, 0);
 +
 +              GPU_framebuffer_texture_attach(fbl->background_fb, e_data.background_depth_tx, 0, 0);
 +              GPU_framebuffer_texture_attach(fbl->background_fb, e_data.background_color_tx, 0, 0);
 +
 +              /* Draw all pending objects */
 +              if (stl->g_data->gp_cache_used > 0) {
 +
 +                      /* sort by zdepth */
 +                      qsort(stl->g_data->gp_object_cache, stl->g_data->gp_cache_used,
 +                            sizeof(tGPencilObjectCache), gpencil_object_cache_compare_zdepth);
 +
 +                      for (int i = 0; i < stl->g_data->gp_cache_used; i++) {
 +                              cache = &stl->g_data->gp_object_cache[i];
 +                              Object *ob = cache->ob;
 +                              bGPdata *gpd = ob->data;
 +                              init_grp = cache->init_grp;
 +                              end_grp = cache->end_grp;
 +                              /* Render stroke in separated framebuffer */
 +                              GPU_framebuffer_bind(fbl->temp_fb_a);
 +                              GPU_framebuffer_clear_color_depth(fbl->temp_fb_a, clearcol, 1.0f);
 +
 +                              /* Stroke Pass: DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND | DRW_STATE_WRITE_DEPTH
 +                               * draw only a subset that usually start with a fill and end with stroke because the
 +                               * shading groups are created by pairs */
 +                              if (end_grp >= init_grp) {
 +                                      MULTISAMPLE_GP_SYNC_ENABLE(stl->storage->multisamples, fbl);
 +
 +                                      DRW_draw_pass_subset(
 +                                              psl->stroke_pass,
 +                                              stl->shgroups[init_grp].shgrps_fill != NULL ?
 +                                              stl->shgroups[init_grp].shgrps_fill : stl->shgroups[init_grp].shgrps_stroke,
 +                                              stl->shgroups[end_grp].shgrps_stroke);
 +
 +                                      MULTISAMPLE_GP_SYNC_DISABLE(stl->storage->multisamples, fbl, fbl->temp_fb_a, txl);
 +                              }
 +
 +                              /* Current buffer drawing */
 +                              if ((!is_render) && (gpd->runtime.sbuffer_size > 0)) {
 +                                      DRW_draw_pass(psl->drawing_pass);
 +                              }
 +                              /* fx passes */
 +                              if (BKE_shaderfx_has_gpencil(ob)) {
 +                                      stl->storage->tonemapping = 0;
 +                                      DRW_gpencil_fx_draw(&e_data, vedata, cache);
 +                              }
 +
 +                              e_data.input_depth_tx = e_data.temp_depth_tx_a;
 +                              e_data.input_color_tx = e_data.temp_color_tx_a;
 +
 +                              /* Combine with scene buffer */
 +                              if ((!is_render) || (fbl->main == NULL)) {
 +                                      GPU_framebuffer_bind(dfbl->default_fb);
 +                              }
 +                              else {
 +                                      GPU_framebuffer_bind(fbl->main);
 +                              }
 +                              /* tonemapping */
 +                              stl->storage->tonemapping = stl->storage->is_render ? 1 : 0;
 +
 +                              DRW_draw_pass(psl->mix_pass);
 +
 +                              /* prepare for fast drawing */
 +                              if (!is_render) {
 +                                      gpencil_prepare_fast_drawing(stl, dfbl, fbl, psl->mix_pass_noblend, clearcol);
 +                              }
 +                      }
 +                      /* edit points */
 +                      if ((!is_render) && (!playing)) {
 +                              DRW_draw_pass(psl->edit_pass);
 +                      }
 +              }
 +              /* grid pass */
 +              if ((!is_render) && (obact) && (obact->type == OB_GPENCIL)) {
 +                      if (((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) &&
++                          (v3d->gp_flag & V3D_GP_SHOW_GRID))
 +                      {
 +                              DRW_draw_pass(psl->grid_pass);
 +                      }
 +              }
 +      }
 +      /* free memory */
 +      gpencil_free_obj_list(stl);
 +
 +      /* detach temp textures */
 +      if (DRW_state_is_fbo()) {
 +              GPU_framebuffer_texture_detach(fbl->temp_fb_a, e_data.temp_depth_tx_a);
 +              GPU_framebuffer_texture_detach(fbl->temp_fb_a, e_data.temp_color_tx_a);
 +              GPU_framebuffer_texture_detach(fbl->temp_fb_b, e_data.temp_depth_tx_b);
 +              GPU_framebuffer_texture_detach(fbl->temp_fb_b, e_data.temp_color_tx_b);
 +
 +              GPU_framebuffer_texture_detach(fbl->background_fb, e_data.background_depth_tx);
 +              GPU_framebuffer_texture_detach(fbl->background_fb, e_data.background_color_tx);
 +
 +              /* attach again default framebuffer after detach textures */
 +              if (!is_render) {
 +                      GPU_framebuffer_bind(dfbl->default_fb);
 +              }
 +
 +              /* the temp texture is ready. Now we can use fast screen drawing */
 +              if (stl->g_data->session_flag & GP_DRW_PAINT_FILLING) {
 +                      stl->g_data->session_flag = GP_DRW_PAINT_READY;
 +              }
 +      }
 +}
 +
 +static const DrawEngineDataSize GPENCIL_data_size = DRW_VIEWPORT_DATA_SIZE(GPENCIL_Data);
 +
 +DrawEngineType draw_engine_gpencil_type = {
 +      NULL, NULL,
 +      N_("GpencilMode"),
 +      &GPENCIL_data_size,
 +      &GPENCIL_engine_init,
 +      &GPENCIL_engine_free,
 +      &GPENCIL_cache_init,
 +      &GPENCIL_cache_populate,
 +      &GPENCIL_cache_finish,
 +      NULL,
 +      &GPENCIL_draw_scene,
 +      NULL,
 +      NULL,
 +      &GPENCIL_render_to_image,
 +};
index c1776ef18e7fd50934eafeb5aebd6151c2711b9b,7f3a36c7ba6b37e5b27fde89cd0828432d5104b5..eaa6f03c533d0f729eb655794e5214a9369d112b
@@@ -357,10 -348,6 +357,10 @@@ static SpaceLink *view3d_new(const ScrA
        v3d->stereo3d_convergence_alpha = 0.15f;
        v3d->stereo3d_volume_alpha = 0.05f;
  
-       v3d->flag3 |= V3D_GP_SHOW_EDIT_LINES;
 +      /* grease pencil settings */
 +      v3d->vertex_opacity = 1.0f;
++      v3d->gp_flag |= V3D_GP_SHOW_EDIT_LINES;
 +
        /* header */
        ar = MEM_callocN(sizeof(ARegion), "header for view3d");
  
index 27b07a317ed0680b319f819013706ae7e9aca8af,1b3eef0f3ec7d9b1b8616588b15d76512ce65dd0..317cde9009de00fe2cfc630c8b391b330a87db6f
@@@ -235,9 -179,14 +235,11 @@@ typedef struct View3D 
        unsigned int lay;
        int layact;
  
 -      /**
 -       * The drawing mode for the 3d display. Set to OB_BOUNDBOX, OB_WIRE, OB_SOLID,
 -       * OB_TEXTURE, OB_MATERIAL or OB_RENDER */
 -      char drawtype;
 -      char ob_centre_cursor;          /* optional bool for 3d cursor to define center */
 -      short scenelock, around;
 +      short ob_centre_cursor;         /* optional bool for 3d cursor to define center */
-       short scenelock, _pad1;
-       short flag, flag2, pad2;
++      short scenelock;
++      short gp_flag;
+       short flag;
+       int flag2;
  
        float lens, grid;
        float near, far;
        short gridsubdiv;       /* Number of subdivisions in the grid between each highlighted grid line */
        char gridflag;
  
 -      /* transform widget info */
 -      char twtype, twmode, twflag;
 -
 -      short _pad1;
 +      /* transform gizmo info */
 +      char _pad5[2], gizmo_flag;
  
-       short flag3;
 -      /* afterdraw, for xray & transparent */
 -      struct ListBase afterdraw_transp;
 -      struct ListBase afterdraw_xray;
 -      struct ListBase afterdraw_xraytransp;
++      short _pad2;
  
        /* drawflags, denoting state */
-       char _pad2;
 -      char zbuf, transp, xray;
++      char _pad3;
 +      char transp, xray;
  
        char multiview_eye;                             /* multiview current eye - for internal use */
  
 -      /* built-in shader effects (eGPUFXFlags) */
 -      char pad3[4];
 +      /* actually only used to define the opacity of the grease pencil vertex in edit mode */
-       float vertex_opacity;                  
++      float vertex_opacity;
  
        /* note, 'fx_settings.dof' is currently _not_ allocated,
         * instead set (temporarily) from camera */
  #define RV3D_VIEW_IS_AXIS(view) \
        (((view) >= RV3D_VIEW_FRONT) && ((view) <= RV3D_VIEW_BOTTOM))
  
- /* View3d->flag2 (short) */
+ /* View3d->flag2 (int) */
  #define V3D_RENDER_OVERRIDE           (1 << 2)
  #define V3D_SOLID_TEX                 (1 << 3)
 -#define V3D_SHOW_GPENCIL              (1 << 4)
 +#define V3D_SHOW_ANNOTATION     (1 << 4)
  #define V3D_LOCK_CAMERA                       (1 << 5)
  #define V3D_RENDER_SHADOW             (1 << 6)                /* This is a runtime only flag that's used to tell draw_mesh_object() that we're doing a shadow pass instead of a regular draw */
  #define V3D_SHOW_RECONSTRUCTION       (1 << 7)
  #define V3D_SOLID_MATCAP              (1 << 12)       /* user flag */
  #define V3D_SHOW_SOLID_MATCAP (1 << 13)       /* runtime flag */
  #define V3D_OCCLUDE_WIRE              (1 << 14)
 -#define V3D_SHADELESS_TEX             (1 << 15)
 -#define V3D_SHOW_WORLD                        (1 << 16)
 +#define V3D_SHOW_MODE_SHADE_OVERRIDE (1 << 15) /* XXX: DNA deprecated */
 +
- /* View3d->flag3 (short) */
- #define V3D_SHOW_WORLD                         (1 << 0) /* LEGACY replaced by V3D_SHADING_BACKGROUND_WORLD */
- #define V3D_GP_SHOW_PAPER            (1 << 2) /* Activate paper to cover all viewport */
- #define V3D_GP_SHOW_GRID             (1 << 3) /* Activate paper grid */
- #define V3D_GP_SHOW_EDIT_LINES       (1 << 4)
- #define V3D_GP_SHOW_MULTIEDIT_LINES  (1 << 5)
- #define V3D_GP_SHOW_ONION_SKIN       (1 << 6) /* main switch at view level */
++/* View3d->gp_flag (short) */
++#define V3D_GP_SHOW_PAPER            (1 << 0) /* Activate paper to cover all viewport */
++#define V3D_GP_SHOW_GRID             (1 << 1) /* Activate paper grid */
++#define V3D_GP_SHOW_EDIT_LINES       (1 << 2)
++#define V3D_GP_SHOW_MULTIEDIT_LINES  (1 << 3)
++#define V3D_GP_SHOW_ONION_SKIN       (1 << 4) /* main switch at view level */
 +
 +/* View3DShading->light */
 +enum {
 +      V3D_LIGHTING_FLAT   = 0,
 +      V3D_LIGHTING_STUDIO = 1,
 +      V3D_LIGHTING_MATCAP = 2,
 +};
 +
 +/* View3DShading->flag */
 +enum {
 +      V3D_SHADING_OBJECT_OUTLINE      = (1 << 0),
 +      V3D_SHADING_XRAY                = (1 << 1),
 +      V3D_SHADING_SHADOW              = (1 << 2),
 +      V3D_SHADING_SCENE_LIGHTS        = (1 << 3),
 +      V3D_SHADING_SPECULAR_HIGHLIGHT  = (1 << 4),
 +      V3D_SHADING_CAVITY              = (1 << 5),
 +      V3D_SHADING_MATCAP_FLIP_X       = (1 << 6),
 +      V3D_SHADING_SCENE_WORLD         = (1 << 7),
 +};
 +
 +/* View3DShading->color_type */
 +enum {
 +      V3D_SHADING_MATERIAL_COLOR = 0,
 +      V3D_SHADING_RANDOM_COLOR   = 1,
 +      V3D_SHADING_SINGLE_COLOR   = 2,
 +      V3D_SHADING_TEXTURE_COLOR  = 3,
 +};
 +
 +/* View3DShading->background_type */
 +enum {
 +      V3D_SHADING_BACKGROUND_THEME    = 0,
 +      V3D_SHADING_BACKGROUND_WORLD    = 1,
 +      V3D_SHADING_BACKGROUND_VIEWPORT = 2,
 +};
 +
 +/* View3DOverlay->flag */
 +enum {
 +      V3D_OVERLAY_FACE_ORIENTATION  = (1 << 0),
 +      V3D_OVERLAY_HIDE_CURSOR       = (1 << 1),
 +      V3D_OVERLAY_BONE_SELECT       = (1 << 2),
 +      V3D_OVERLAY_LOOK_DEV          = (1 << 3),
 +      V3D_OVERLAY_WIREFRAMES        = (1 << 4),
 +      V3D_OVERLAY_HIDE_TEXT         = (1 << 5),
 +      V3D_OVERLAY_HIDE_MOTION_PATHS = (1 << 6),
 +      V3D_OVERLAY_ONION_SKINS       = (1 << 7),
 +      V3D_OVERLAY_HIDE_BONES        = (1 << 8),
 +      V3D_OVERLAY_HIDE_OBJECT_XTRAS = (1 << 9),
 +      V3D_OVERLAY_HIDE_OBJECT_ORIGINS = (1 << 10),
 +};
  
 +/* View3DOverlay->edit_flag */
 +enum {
 +      V3D_OVERLAY_EDIT_VERT_NORMALS = (1 << 0),
 +      V3D_OVERLAY_EDIT_LOOP_NORMALS = (1 << 1),
 +      V3D_OVERLAY_EDIT_FACE_NORMALS = (1 << 2),
 +
 +      V3D_OVERLAY_EDIT_OCCLUDE_WIRE = (1 << 3),
 +
 +      V3D_OVERLAY_EDIT_WEIGHT       = (1 << 4),
 +};
 +
 +/* View3DOverlay->arm_flag */
 +enum {
 +      V3D_OVERLAY_ARM_TRANSP_BONES  = (1 << 0),
 +};
 +
 +/* View3DOverlay->paint_flag */
 +enum {
 +      V3D_OVERLAY_PAINT_WIRE        = (1 << 0),
 +};
  
  /* View3D->around */
  enum {
index ab662e71380d2a46cf1baa8e9e4812ae8ce84768,ae1761faec1bd1597b20365e17ce9a5178c4399a..d7563f13dc27f90cd3c827b98ce27959d2a9e933
@@@ -2452,492 -2173,189 +2452,492 @@@ static void rna_def_space_view3d_shadin
        StructRNA *srna;
        PropertyRNA *prop;
  
 -      /* note: combinations work but don't flip so arnt that useful */
 -      static const EnumPropertyItem bgpic_axis_items[] = {
 -              {0, "", 0, N_("X Axis"), ""},
 -              {(1 << RV3D_VIEW_LEFT), "LEFT", 0, "Left", "Show background image while looking to the left"},
 -              {(1 << RV3D_VIEW_RIGHT), "RIGHT", 0, "Right", "Show background image while looking to the right"},
 -              /*{(1<<RV3D_VIEW_LEFT)|(1<<RV3D_VIEW_RIGHT), "LEFT_RIGHT", 0, "Left/Right", ""},*/
 -              {0, "", 0, N_("Y Axis"), ""},
 -              {(1 << RV3D_VIEW_BACK), "BACK", 0, "Back", "Show background image in back view"},
 -              {(1 << RV3D_VIEW_FRONT), "FRONT", 0, "Front", "Show background image in front view"},
 -              /*{(1<<RV3D_VIEW_BACK)|(1<<RV3D_VIEW_FRONT), "BACK_FRONT", 0, "Back/Front", ""},*/
 -              {0, "", 0, N_("Z Axis"), ""},
 -              {(1 << RV3D_VIEW_BOTTOM), "BOTTOM", 0, "Bottom", "Show background image in bottom view"},
 -              {(1 << RV3D_VIEW_TOP), "TOP", 0, "Top", "Show background image in top view"},
 -              /*{(1<<RV3D_VIEW_BOTTOM)|(1<<RV3D_VIEW_TOP), "BOTTOM_TOP", 0, "Top/Bottom", ""},*/
 -              {0, "", 0, N_("Other"), ""},
 -              {0, "ALL", 0, "All Views", "Show background image in all views"},
 -              {(1 << RV3D_VIEW_CAMERA), "CAMERA", 0, "Camera", "Show background image in camera view"},
 +      static const EnumPropertyItem background_type_items[] = {
 +              {V3D_SHADING_BACKGROUND_THEME,    "THEME",    0, "Theme",    "Use the theme for background color"},
 +              {V3D_SHADING_BACKGROUND_WORLD,    "WORLD",    0, "World",    "Use the world for background color"},
 +              {V3D_SHADING_BACKGROUND_VIEWPORT, "VIEWPORT", 0, "Viewport", "Use a custom color limited to this viewport only"},
                {0, NULL, 0, NULL, NULL}
        };
 +      static const float default_background_color[] = {0.05f, 0.05f, 0.05f};
  
 -      static const EnumPropertyItem bgpic_source_items[] = {
 -              {V3D_BGPIC_IMAGE, "IMAGE", 0, "Image", ""},
 -              {V3D_BGPIC_MOVIE, "MOVIE_CLIP", 0, "Movie Clip", ""},
 -              {0, NULL, 0, NULL, NULL}
 -      };
  
 -      static const EnumPropertyItem bgpic_camera_frame_items[] = {
 -              {0, "STRETCH", 0, "Stretch", ""},
 -              {V3D_BGPIC_CAMERA_ASPECT, "FIT", 0, "Fit", ""},
 -              {V3D_BGPIC_CAMERA_ASPECT | V3D_BGPIC_CAMERA_CROP, "CROP", 0, "Crop", ""},
 -              {0, NULL, 0, NULL, NULL}
 -      };
 +      /* Note these settings are used for both 3D viewport and the OpenGL render
 +       * engine in the scene, so can't assume to always be part of a screen. */
 +      srna = RNA_def_struct(brna, "View3DShading", NULL);
 +      RNA_def_struct_path_func(srna, "rna_View3DShading_path");
 +      RNA_def_struct_ui_text(srna, "3D View Shading Settings", "Settings for shading in the 3D viewport");
  
 -      static const EnumPropertyItem bgpic_draw_depth_items[] = {
 -              {0, "BACK", 0, "Back", ""},
 -              {V3D_BGPIC_FOREGROUND, "FRONT", 0, "Front", ""},
 -              {0, NULL, 0, NULL, NULL}
 -      };
 +      prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
 +      RNA_def_property_enum_items(prop, rna_enum_shading_type_items);
 +      RNA_def_property_enum_funcs(prop, "rna_3DViewShading_type_get", "rna_3DViewShading_type_set",
 +                                  "rna_3DViewShading_type_itemf");
 +      RNA_def_property_ui_text(prop, "Viewport Shading", "Method to display/shade objects in the 3D View");
 +      RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_3DViewShading_type_update");
  
 -      srna = RNA_def_struct(brna, "BackgroundImage", NULL);
 -      RNA_def_struct_sdna(srna, "BGpic");
 -      RNA_def_struct_ui_text(srna, "Background Image", "Image and settings for display in the 3D View background");
 +      prop = RNA_def_property(srna, "light", PROP_ENUM, PROP_NONE);
 +      RNA_def_property_enum_sdna(prop, NULL, "light");
 +      RNA_def_property_enum_items(prop, rna_enum_viewport_lighting_items);
 +      RNA_def_property_enum_funcs(prop, "rna_View3DShading_light_get", "rna_View3DShading_light_set", NULL);
 +      RNA_def_property_ui_text(prop, "Lighting", "Lighting Method for Solid/Texture Viewport Shading");
 +      RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
  
 -      prop = RNA_def_property(srna, "source", PROP_ENUM, PROP_NONE);
 -      RNA_def_property_enum_sdna(prop, NULL, "source");
 -      RNA_def_property_enum_items(prop, bgpic_source_items);
 -      RNA_def_property_ui_text(prop, "Background Source", "Data source used for background");
 +      prop = RNA_def_property(srna, "show_object_outline", PROP_BOOLEAN, PROP_NONE);
 +      RNA_def_property_boolean_sdna(prop, NULL, "flag", V3D_SHADING_OBJECT_OUTLINE);
 +      RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
 +      RNA_def_property_ui_text(prop, "Outline", "Show Object Outline");
        RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
  
 -      prop = RNA_def_property(srna, "image", PROP_POINTER, PROP_NONE);
 -      RNA_def_property_pointer_sdna(prop, NULL, "ima");
 -      RNA_def_property_ui_text(prop, "Image", "Image displayed and edited in this space");
 -      RNA_def_property_flag(prop, PROP_EDITABLE);
 +      prop = RNA_def_property(srna, "studio_light", PROP_ENUM, PROP_NONE);
 +      RNA_def_property_enum_items(prop, rna_enum_studio_light_items);
 +      RNA_def_property_enum_default(prop, 0);
 +      RNA_def_property_enum_funcs(prop, "rna_View3DShading_studio_light_get", "rna_View3DShading_studio_light_set", "rna_View3DShading_studio_light_itemf");
 +      RNA_def_property_ui_text(prop, "Studiolight", "Studio lighting setup");
        RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
  
 -      prop = RNA_def_property(srna, "clip", PROP_POINTER, PROP_NONE);
 -      RNA_def_property_pointer_sdna(prop, NULL, "clip");
 -      RNA_def_property_ui_text(prop, "MovieClip", "Movie clip displayed and edited in this space");
 -      RNA_def_property_flag(prop, PROP_EDITABLE);
 +      prop = RNA_def_property(srna, "show_cavity", PROP_BOOLEAN, PROP_NONE);
 +      RNA_def_property_boolean_sdna(prop, NULL, "flag", V3D_SHADING_CAVITY);
 +      RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
 +      RNA_def_property_ui_text(prop, "Cavity", "Show Cavity");
        RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
  
 -      prop = RNA_def_property(srna, "image_user", PROP_POINTER, PROP_NONE);
 -      RNA_def_property_flag(prop, PROP_NEVER_NULL);
 -      RNA_def_property_pointer_sdna(prop, NULL, "iuser");
 -      RNA_def_property_ui_text(prop, "Image User",
 -                               "Parameters defining which layer, pass and frame of the image is displayed");
 +      prop = RNA_def_property(srna, "cavity_ridge_factor", PROP_FLOAT, PROP_FACTOR);
 +      RNA_def_property_float_sdna(prop, NULL, "cavity_ridge_factor");
 +      RNA_def_property_float_default(prop, 1.0f);
 +      RNA_def_property_ui_text(prop, "Ridge", "Factor for the ridges");
 +      RNA_def_property_range(prop, 0.0f, 250.0f);
 +      RNA_def_property_ui_range(prop, 0.00f, 2.5f, 1, 3);
 +      RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
 +      RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
 +
 +      prop = RNA_def_property(srna, "cavity_valley_factor", PROP_FLOAT, PROP_FACTOR);
 +      RNA_def_property_float_sdna(prop, NULL, "cavity_valley_factor");
 +      RNA_def_property_float_default(prop, 1.0);
 +      RNA_def_property_ui_text(prop, "Valley", "Factor for the valleys");
 +      RNA_def_property_range(prop, 0.0f, 250.0f);
 +      RNA_def_property_ui_range(prop, 0.00f, 2.5f, 1, 3);
 +      RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
 +      RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
 +
 +      prop = RNA_def_property(srna, "selected_studio_light", PROP_POINTER, PROP_NONE);
 +      RNA_def_property_struct_type(prop, "StudioLight");
 +      RNA_define_verify_sdna(0);
 +      RNA_def_property_ui_text(prop, "Studio Light", "Selected StudioLight");
 +      RNA_def_property_pointer_funcs(prop, "rna_View3DShading_selected_studio_light_get", NULL, NULL, NULL);
 +      RNA_def_property_clear_flag(prop, PROP_ANIMATABLE | PROP_EDITABLE);
 +      RNA_define_verify_sdna(1);
 +
 +      prop = RNA_def_property(srna, "studiolight_rotate_z", PROP_FLOAT, PROP_ANGLE);
 +      RNA_def_property_float_sdna(prop, NULL, "studiolight_rot_z");
 +      RNA_def_property_float_default(prop, 0.0);
 +      RNA_def_property_ui_text(prop, "Studiolight Rotation", "Rotation of the studiolight around the Z-Axis");
 +      RNA_def_property_range(prop, -M_PI, M_PI);
 +      RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
 +      RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
 +
 +      prop = RNA_def_property(srna, "color_type", PROP_ENUM, PROP_NONE);
 +      RNA_def_property_enum_sdna(prop, NULL, "color_type");
 +      RNA_def_property_enum_items(prop, rna_enum_shading_color_type_items);
 +      RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_View3DShading_color_type_itemf");
 +      RNA_def_property_ui_text(prop, "Color", "Color Type");
 +      RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
 +
 +      prop = RNA_def_property(srna, "single_color", PROP_FLOAT, PROP_COLOR);
 +      RNA_def_property_float_sdna(prop, NULL, "single_color");
 +      RNA_def_property_array(prop, 3);
 +      RNA_def_property_ui_text(prop, "Color", "Color for single color mode");
 +      RNA_def_property_range(prop, 0.0f, 1.0f);
 +      RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
 +
 +      prop = RNA_def_property(srna, "background_type", PROP_ENUM, PROP_NONE);
 +      RNA_def_property_enum_items(prop, background_type_items);
 +      RNA_def_property_ui_text(prop, "Background", "Way to draw the background");
 +      RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
 +
 +      prop = RNA_def_property(srna, "background_color", PROP_FLOAT, PROP_COLOR);
 +      RNA_def_property_array(prop, 3);
 +      RNA_def_property_float_array_default(prop, default_background_color);
 +      RNA_def_property_ui_text(prop, "Background Color", "Color for custom background color");
 +      RNA_def_property_range(prop, 0.0f, 1.0f);
 +      RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
 +
 +      prop = RNA_def_property(srna, "show_shadows", PROP_BOOLEAN, PROP_NONE);
 +      RNA_def_property_boolean_sdna(prop, NULL, "flag", V3D_SHADING_SHADOW);
 +      RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
 +      RNA_def_property_ui_text(prop, "Shadow", "Show Shadow");
 +      RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
 +
 +      prop = RNA_def_property(srna, "show_xray", PROP_BOOLEAN, PROP_NONE);
 +      RNA_def_property_boolean_sdna(prop, NULL, "flag", V3D_SHADING_XRAY);
 +      RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
 +      RNA_def_property_ui_text(prop, "X-Ray", "Show whole scene transparent");
 +      RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
 +
 +      prop = RNA_def_property(srna, "xray_alpha", PROP_FLOAT, PROP_FACTOR);
 +      RNA_def_property_float_sdna(prop, NULL, "xray_alpha");
 +      RNA_def_property_float_default(prop, 0.5);
 +      RNA_def_property_ui_text(prop, "X-Ray Alpha", "Amount of alpha to use");
 +      RNA_def_property_range(prop, 0.0f, 1.0f);
 +      RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
 +      RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
 +
 +      prop = RNA_def_property(srna, "use_scene_lights", PROP_BOOLEAN, PROP_NONE);
 +      RNA_def_property_boolean_sdna(prop, NULL, "flag", V3D_SHADING_SCENE_LIGHTS);
 +      RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
 +      RNA_def_property_ui_text(prop, "Scene Lights", "Render lights and light probes of the scene");
 +      RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
 +
 +      prop = RNA_def_property(srna, "use_scene_world", PROP_BOOLEAN, PROP_NONE);
 +      RNA_def_property_boolean_sdna(prop, NULL, "flag", V3D_SHADING_SCENE_WORLD);
 +      RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
 +      RNA_def_property_ui_text(prop, "Scene World", "Use scene world for lighting");
 +      RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
 +
 +      prop = RNA_def_property(srna, "show_specular_highlight", PROP_BOOLEAN, PROP_NONE);
 +      RNA_def_property_boolean_sdna(prop, NULL, "flag", V3D_SHADING_SPECULAR_HIGHLIGHT);
 +      RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
 +      RNA_def_property_ui_text(prop, "Specular Highlights", "Render specular highlights");
 +      RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
 +
 +      prop = RNA_def_property(srna, "object_outline_color", PROP_FLOAT, PROP_COLOR);
 +      RNA_def_property_float_sdna(prop, NULL, "object_outline_color");
 +      RNA_def_property_array(prop, 3);
 +      RNA_def_property_ui_text(prop, "Outline Color", "Color for object outline");
 +      RNA_def_property_range(prop, 0.0f, 1.0f);
 +      RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
 +
 +      prop = RNA_def_property(srna, "shadow_intensity", PROP_FLOAT, PROP_FACTOR);
 +      RNA_def_property_float_sdna(prop, NULL, "shadow_intensity");
 +      RNA_def_property_float_default(prop, 0.5);
 +      RNA_def_property_ui_text(prop, "Shadow Intensity", "Darkness of shadows");
 +      RNA_def_property_range(prop, 0.0f, 1.0f);
 +      RNA_def_property_ui_range(prop, 0.00f, 1.0f, 1, 3);
 +      RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
 +      RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
 +
 +      prop = RNA_def_property(srna, "studiolight_background_alpha", PROP_FLOAT, PROP_FACTOR);
 +      RNA_def_property_float_sdna(prop, NULL, "studiolight_background");
 +      RNA_def_property_float_default(prop, 0.0);
 +      RNA_def_property_ui_text(prop, "Background", "Show the studiolight in the background");
 +      RNA_def_property_range(prop, 0.0f, 1.0f);
 +      RNA_def_property_ui_range(prop, 0.00f, 1.0f, 1, 3);
 +      RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
 +      RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
 +}
 +
 +static void rna_def_space_view3d_overlay(BlenderRNA *brna)
 +{
 +      StructRNA *srna;
 +      PropertyRNA *prop;
 +
 +      srna = RNA_def_struct(brna, "View3DOverlay", NULL);
 +      RNA_def_struct_sdna(srna, "View3D");
 +      RNA_def_struct_nested(brna, srna, "SpaceView3D");
 +      RNA_def_struct_path_func(srna, "rna_View3DOverlay_path");
 +      RNA_def_struct_ui_text(srna, "3D View Overlay Settings", "Settings for display of overlays in the 3D viewport");
 +
 +      prop = RNA_def_property(srna, "show_overlays", PROP_BOOLEAN, PROP_NONE);
 +      RNA_def_property_boolean_negative_sdna(prop, NULL, "flag2", V3D_RENDER_OVERRIDE);
 +      RNA_def_property_ui_text(prop, "Show Overlays", "Display overlays like gizmos and outlines");
 +      RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_GPencil_update");
 +
 +      prop = RNA_def_property(srna, "show_floor", PROP_BOOLEAN, PROP_NONE);
 +      RNA_def_property_boolean_sdna(prop, NULL, "gridflag", V3D_SHOW_FLOOR);
 +      RNA_def_property_ui_text(prop, "Display Grid Floor", "Show the ground plane grid in perspective view");
 +      RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
 +
 +      prop = RNA_def_property(srna, "show_axis_x", PROP_BOOLEAN, PROP_NONE);
 +      RNA_def_property_boolean_sdna(prop, NULL, "gridflag", V3D_SHOW_X);
 +      RNA_def_property_ui_text(prop, "Display X Axis", "Show the X axis line in perspective view");
 +      RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
 +
 +      prop = RNA_def_property(srna, "show_axis_y", PROP_BOOLEAN, PROP_NONE);
 +      RNA_def_property_boolean_sdna(prop, NULL, "gridflag", V3D_SHOW_Y);
 +      RNA_def_property_ui_text(prop, "Display Y Axis", "Show the Y axis line in perspective view");
 +      RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
 +
 +      prop = RNA_def_property(srna, "show_axis_z", PROP_BOOLEAN, PROP_NONE);
 +      RNA_def_property_boolean_sdna(prop, NULL, "gridflag", V3D_SHOW_Z);
 +      RNA_def_property_ui_text(prop, "Display Z Axis", "Show the Z axis line in perspective view");
 +      RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
 +
 +      prop = RNA_def_property(srna, "grid_scale", PROP_FLOAT, PROP_NONE);
 +      RNA_def_property_float_sdna(prop, NULL, "grid");
 +      RNA_def_property_ui_text(prop, "Grid Scale", "Distance between 3D View grid lines");
 +      RNA_def_property_range(prop, 0.0f, FLT_MAX);
 +      RNA_def_property_ui_range(prop, 0.001f, 1000.0f, 0.1f, 3);
 +      RNA_def_property_float_default(prop, 1.0f);
 +      RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
 +
 +      prop = RNA_def_property(srna, "grid_lines", PROP_INT, PROP_NONE);
 +      RNA_def_property_int_sdna(prop, NULL, "gridlines");
 +      RNA_def_property_ui_text(prop, "Grid Lines", "Number of grid lines to display in perspective view");
 +      RNA_def_property_range(prop, 0, 1024);
 +      RNA_def_property_int_default(prop, 16);
 +      RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
 +
 +      prop = RNA_def_property(srna, "grid_subdivisions", PROP_INT, PROP_NONE);
 +      RNA_def_property_int_sdna(prop, NULL, "gridsubdiv");
 +      RNA_def_property_ui_text(prop, "Grid Subdivisions", "Number of subdivisions between grid lines");
 +      RNA_def_property_range(prop, 1, 1024);
 +      RNA_def_property_int_default(prop, 10);
 +      RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
 +
 +      prop = RNA_def_property(srna, "grid_scale_unit", PROP_FLOAT, PROP_NONE);
 +      RNA_def_property_clear_flag(prop, PROP_EDITABLE);
 +      RNA_def_property_float_funcs(prop, "rna_View3DOverlay_GridScaleUnit_get", NULL, NULL);
 +      RNA_def_property_ui_text(prop, "Grid Scale Unit", "Grid cell size scaled by scene unit system settings");
 +
 +      prop = RNA_def_property(srna, "show_outline_selected", PROP_BOOLEAN, PROP_NONE);
 +      RNA_def_property_boolean_sdna(prop, NULL, "flag", V3D_SELECT_OUTLINE);
 +      RNA_def_property_ui_text(prop, "Outline Selected",
 +                               "Show an outline highlight around selected objects in non-wireframe views");
 +      RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
 +
 +      prop = RNA_def_property(srna, "show_object_origins", PROP_BOOLEAN, PROP_NONE);
 +      RNA_def_property_boolean_negative_sdna(prop, NULL, "overlay.flag", V3D_OVERLAY_HIDE_OBJECT_ORIGINS);
 +      RNA_def_property_ui_text(prop, "Object Origins", "Show object center dots");
 +      RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
 +
 +      prop = RNA_def_property(srna, "show_object_origins_all", PROP_BOOLEAN, PROP_NONE);
 +      RNA_def_property_boolean_sdna(prop, NULL, "flag", V3D_DRAW_CENTERS);
 +      RNA_def_property_ui_text(prop, "All Object Origins",
 +                               "Show the object origin center dot for all (selected and unselected) objects");
 +      RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
 +
 +      prop = RNA_def_property(srna, "show_relationship_lines", PROP_BOOLEAN, PROP_NONE);
 +      RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", V3D_HIDE_HELPLINES);
 +      RNA_def_property_ui_text(prop, "Relationship Lines",
 +                               "Show dashed lines indicating parent or constraint relationships");
 +      RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
 +
 +      /* TODO: this should become a per object setting? */
 +      prop = RNA_def_property(srna, "show_backface_culling", PROP_BOOLEAN, PROP_NONE);
 +      RNA_def_property_boolean_sdna(prop, NULL, "flag2", V3D_BACKFACE_CULLING);
 +      RNA_def_property_ui_text(prop, "Backface Culling", "Use back face culling to hide the back side of faces");
 +      RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
 +
 +      prop = RNA_def_property(srna, "show_cursor", PROP_BOOLEAN, PROP_NONE);
 +      RNA_def_property_boolean_negative_sdna(prop, NULL, "overlay.flag", V3D_OVERLAY_HIDE_CURSOR);
 +      RNA_def_property_ui_text(prop, "Show 3D Cursor", "Display 3D Cursor Overlay");
 +      RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
 +
 +      prop = RNA_def_property(srna, "show_text", PROP_BOOLEAN, PROP_NONE);
 +      RNA_def_property_boolean_negative_sdna(prop, NULL, "overlay.flag", V3D_OVERLAY_HIDE_TEXT);
 +      RNA_def_property_ui_text(prop, "Show Text", "Display overlay text");
 +      RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
 +
 +      prop = RNA_def_property(srna, "show_ornaments", PROP_BOOLEAN, PROP_NONE);
 +      RNA_def_property_boolean_negative_sdna(prop, NULL, "overlay.flag", V3D_OVERLAY_HIDE_OBJECT_XTRAS);
 +      RNA_def_property_ui_text(prop, "Ornaments", "Object details, including empty wire, cameras and other extras");
 +      RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
 +
 +      prop = RNA_def_property(srna, "show_bones", PROP_BOOLEAN, PROP_NONE);
 +      RNA_def_property_boolean_negative_sdna(prop, NULL, "overlay.flag", V3D_OVERLAY_HIDE_BONES);
 +      RNA_def_property_ui_text(prop, "Show Bones", "Display bones");
 +      RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
 +
 +      prop = RNA_def_property(srna, "show_face_orientation", PROP_BOOLEAN, PROP_NONE);
 +      RNA_def_property_boolean_sdna(prop, NULL, "overlay.flag", V3D_OVERLAY_FACE_ORIENTATION);
 +      RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
 +      RNA_def_property_ui_text(prop, "Face Orientation", "Show the Face Orientation Overlay");
 +      RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
 +
 +      prop = RNA_def_property(srna, "show_bone_select", PROP_BOOLEAN, PROP_NONE);
 +      RNA_def_property_boolean_sdna(prop, NULL, "overlay.flag", V3D_OVERLAY_BONE_SELECT);
 +      RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
 +      RNA_def_property_ui_text(prop, "Bone Selection", "Show the Bone Selection Overlay");
 +      RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
 +
 +      prop = RNA_def_property(srna, "bone_select_alpha", PROP_FLOAT, PROP_FACTOR);
 +      RNA_def_property_float_sdna(prop, NULL, "overlay.bone_select_alpha");
 +      RNA_def_property_float_default(prop, 0.5f);
 +      RNA_def_property_ui_text(prop, "Opacity", "Opacity to use for bone selection");
 +      RNA_def_property_range(prop, 0.0f, 1.0f);
 +      RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
 +      RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
 +
 +      prop = RNA_def_property(srna, "show_motion_paths", PROP_BOOLEAN, PROP_NONE);
 +      RNA_def_property_boolean_negative_sdna(prop, NULL, "overlay.flag", V3D_OVERLAY_HIDE_MOTION_PATHS);
 +      RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
 +      RNA_def_property_ui_text(prop, "Motion Paths", "Show the Motion Paths Overlay");
 +      RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
 +
 +      prop = RNA_def_property(srna, "show_onion_skins", PROP_BOOLEAN, PROP_NONE);
 +      RNA_def_property_boolean_sdna(prop, NULL, "overlay.flag", V3D_OVERLAY_ONION_SKINS);
 +      RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
 +      RNA_def_property_ui_text(prop, "Onion Skins", "Show the Onion Skinning Overlay");
 +      RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
 +
 +      prop = RNA_def_property(srna, "show_look_dev", PROP_BOOLEAN, PROP_NONE);
 +      RNA_def_property_boolean_sdna(prop, NULL, "overlay.flag", V3D_OVERLAY_LOOK_DEV);
 +      RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
 +      RNA_def_property_ui_text(prop, "Look Dev Preview", "Show look development balls and palette");
 +      RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
 +
 +      prop = RNA_def_property(srna, "show_wireframes", PROP_BOOLEAN, PROP_NONE);
 +      RNA_def_property_boolean_sdna(prop, NULL, "overlay.flag", V3D_OVERLAY_WIREFRAMES);
 +      RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
 +      RNA_def_property_ui_text(prop, "Wireframe", "Show face edges wires");
 +      RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
 +
 +      prop = RNA_def_property(srna, "wireframe_threshold", PROP_FLOAT, PROP_FACTOR);
 +      RNA_def_property_float_sdna(prop, NULL, "overlay.wireframe_threshold");
 +      RNA_def_property_float_default(prop, 0.5f);
 +      RNA_def_property_ui_text(prop, "Wireframe Threshold", "Adjust the number of wires displayed (1 for all wires)");
 +      RNA_def_property_range(prop, 0.0f, 1.0f);
 +      RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
 +      RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
 +
 +      prop = RNA_def_property(srna, "show_paint_wire", PROP_BOOLEAN, PROP_NONE);
 +      RNA_def_property_boolean_sdna(prop, NULL, "overlay.paint_flag", V3D_OVERLAY_PAINT_WIRE);
 +      RNA_def_property_ui_text(prop, "Show Wire", "Use wireframe display in painting modes");
 +      RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
 +
 +      prop = RNA_def_property(srna, "show_occlude_wire", PROP_BOOLEAN, PROP_NONE);
 +      RNA_def_property_boolean_sdna(prop, NULL, "overlay.edit_flag", V3D_OVERLAY_EDIT_OCCLUDE_WIRE);
 +      RNA_def_property_ui_text(prop, "Hidden Wire", "Use hidden wireframe display in edit mode");
        RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
  
 -      prop = RNA_def_property(srna, "clip_user", PROP_POINTER, PROP_NONE);
 -      RNA_def_property_flag(prop, PROP_NEVER_NULL);
 -      RNA_def_property_struct_type(prop, "MovieClipUser");
 -      RNA_def_property_pointer_sdna(prop, NULL, "cuser");
 -      RNA_def_property_ui_text(prop, "Clip User", "Parameters defining which frame of the movie clip is displayed");
 +      prop = RNA_def_property(srna, "show_weight", PROP_BOOLEAN, PROP_NONE);
 +      RNA_def_property_boolean_sdna(prop, NULL, "overlay.edit_flag", V3D_OVERLAY_EDIT_WEIGHT);
 +      RNA_def_property_ui_text(prop, "Show Weights", "Draw weights in editmode");
        RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
  
 -      prop = RNA_def_property(srna, "offset_x", PROP_FLOAT, PROP_NONE);
 -      RNA_def_property_float_sdna(prop, NULL, "xof");
 -      RNA_def_property_ui_text(prop, "X Offset", "Offset image horizontally from the world origin");
 +      prop = RNA_def_property(srna, "show_face_normals", PROP_BOOLEAN, PROP_NONE);
 +      RNA_def_property_boolean_sdna(prop, NULL, "overlay.edit_flag", V3D_OVERLAY_EDIT_FACE_NORMALS);
 +      RNA_def_property_ui_text(prop, "Draw Normals", "Display face normals as lines");
        RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
  
 -      prop = RNA_def_property(srna, "offset_y", PROP_FLOAT, PROP_NONE);
 -      RNA_def_property_float_sdna(prop, NULL, "yof");
 -      RNA_def_property_ui_text(prop, "Y Offset", "Offset image vertically from the world origin");
 +      prop = RNA_def_property(srna, "show_vertex_normals", PROP_BOOLEAN, PROP_NONE);
 +      RNA_def_property_boolean_sdna(prop, NULL, "overlay.edit_flag", V3D_OVERLAY_EDIT_VERT_NORMALS);
 +      RNA_def_property_ui_text(prop, "Draw Vertex Normals", "Display vertex normals as lines");
        RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
  
 -      prop = RNA_def_property(srna, "size", PROP_FLOAT, PROP_DISTANCE);
 -      RNA_def_property_float_sdna(prop, NULL, "size");
 -      RNA_def_property_float_funcs(prop, "rna_BackgroundImage_size_get", "rna_BackgroundImage_size_set", NULL);
 -      RNA_def_property_ui_text(prop, "Size", "Size of the background image (ortho view only)");
 -      RNA_def_property_range(prop, 0.0, FLT_MAX);
 +      prop = RNA_def_property(srna, "show_split_normals", PROP_BOOLEAN, PROP_NONE);
 +      RNA_def_property_boolean_sdna(prop, NULL, "overlay.edit_flag", V3D_OVERLAY_EDIT_LOOP_NORMALS);
 +      RNA_def_property_ui_text(prop, "Draw Split Normals", "Display vertex-per-face normals as lines");
        RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
  
 -      prop = RNA_def_property(srna, "rotation", PROP_FLOAT, PROP_EULER);
 -      RNA_def_property_float_sdna(prop, NULL, "rotation");
 -      RNA_def_property_ui_text(prop, "Rotation", "Rotation for the background image (ortho view only)");
 +      prop = RNA_def_property(srna, "normals_length", PROP_FLOAT, PROP_FACTOR);
 +      RNA_def_property_float_sdna(prop, NULL, "overlay.normals_length");
 +      RNA_def_property_ui_text(prop, "Normal Size", "Display size for normals in the 3D view");
 +      RNA_def_property_range(prop, 0.00001, 1000.0);
 +      RNA_def_property_ui_range(prop, 0.01, 10.0, 10.0, 2);
        RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
  
 -      prop = RNA_def_property(srna, "use_flip_x", PROP_BOOLEAN, PROP_NONE);
 -      RNA_def_property_boolean_sdna(prop, NULL, "flag", V3D_BGPIC_FLIP_X);
 -      RNA_def_property_ui_text(prop, "Flip Horizontally", "Flip the background image horizontally");
 +      prop = RNA_def_property(srna, "backwire_opacity", PROP_FLOAT, PROP_FACTOR);
 +      RNA_def_property_float_sdna(prop, NULL, "overlay.backwire_opacity");
 +      RNA_def_property_ui_text(prop, "Backwire Opacity", "Opacity when rendering transparent wires");
 +      RNA_def_property_range(prop, 0.0f, 1.0f);
        RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
  
 -      prop = RNA_def_property(srna, "use_flip_y", PROP_BOOLEAN, PROP_NONE);
 -      RNA_def_property_boolean_sdna(prop, NULL, "flag", V3D_BGPIC_FLIP_Y);
 -      RNA_def_property_ui_text(prop, "Flip Vertically", "Flip the background image vertically");
 +      prop = RNA_def_property(srna, "show_transparent_bones", PROP_BOOLEAN, PROP_NONE);
 +      RNA_def_property_boolean_sdna(prop, NULL, "overlay.arm_flag", V3D_OVERLAY_ARM_TRANSP_BONES);
 +      RNA_def_property_ui_text(prop, "Transparent Bones", "Display bones as transparent");
        RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
  
 -      prop = RNA_def_property(srna, "opacity", PROP_FLOAT, PROP_NONE);
 -      RNA_def_property_float_sdna(prop, NULL, "blend");
 -      RNA_def_property_float_funcs(prop, "rna_BackgroundImage_opacity_get", "rna_BackgroundImage_opacity_set", NULL);
 -      RNA_def_property_ui_text(prop, "Opacity", "Image opacity to blend the image against the background color");
 -      RNA_def_property_range(prop, 0.0, 1.0);
 +      prop = RNA_def_property(srna, "texture_paint_mode_opacity", PROP_FLOAT, PROP_FACTOR);
 +      RNA_def_property_float_sdna(prop, NULL, "overlay.texture_paint_mode_opacity");
 +      RNA_def_property_float_default(prop, 0.8f);
 +      RNA_def_property_ui_text(prop, "Texture Opacity", "Opacity of the texture paint mode overlay");
 +      RNA_def_property_range(prop, 0.0f, 1.0f);
        RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
  
 -      prop = RNA_def_property(srna, "view_axis", PROP_ENUM, PROP_NONE);
 -      RNA_def_property_enum_sdna(prop, NULL, "view");
 -      RNA_def_property_enum_items(prop, bgpic_axis_items);
 -      RNA_def_property_ui_text(prop, "Image Axis", "The axis to display the image on");
 +      prop = RNA_def_property(srna, "vertex_paint_mode_opacity", PROP_FLOAT, PROP_FACTOR);
 +      RNA_def_property_float_sdna(prop, NULL, "overlay.vertex_paint_mode_opacity");
 +      RNA_def_property_float_default(prop, 0.8f);
 +      RNA_def_property_ui_text(prop, "Vertex Paint Opacity", "Opacity of the vertex paint mode overlay");
 +      RNA_def_property_range(prop, 0.0f, 1.0f);
        RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
  
 -      prop = RNA_def_property(srna, "show_expanded", PROP_BOOLEAN, PROP_NONE);
 -      RNA_def_property_boolean_sdna(prop, NULL, "flag", V3D_BGPIC_EXPANDED);
 -      RNA_def_property_ui_text(prop, "Show Expanded", "Show the expanded in the user interface");
 -      RNA_def_property_ui_icon(prop, ICON_TRIA_RIGHT, 1);
 +      prop = RNA_def_property(srna, "weight_paint_mode_opacity", PROP_FLOAT, PROP_FACTOR);
 +      RNA_def_property_float_sdna(prop, NULL, "overlay.weight_paint_mode_opacity");
 +      RNA_def_property_float_default(prop, 0.8f);
 +      RNA_def_property_ui_text(prop, "Weight Paint Opacity", "Opacity of the weight paint mode overlay");
 +      RNA_def_property_range(prop, 0.0f, 1.0f);
 +      RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
  
 -      prop = RNA_def_property(srna, "use_camera_clip", PROP_BOOLEAN, PROP_NONE);
 -      RNA_def_property_boolean_sdna(prop, NULL, "flag", V3D_BGPIC_CAMERACLIP);
 -      RNA_def_property_ui_text(prop, "Camera Clip", "Use movie clip from active scene camera");
 +      /* grease pencil paper settings */
 +      prop = RNA_def_property(srna, "show_annotation", PROP_BOOLEAN, PROP_NONE);
 +      RNA_def_property_boolean_sdna(prop, NULL, "flag2", V3D_SHOW_ANNOTATION);
 +      RNA_def_property_ui_text(prop, "Show Annotation",
 +              "Show annotations for this view");
        RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
  
 -      prop = RNA_def_property(srna, "show_background_image", PROP_BOOLEAN, PROP_NONE);
 -      RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", V3D_BGPIC_DISABLED);
 -      RNA_def_property_ui_text(prop, "Show Background Image", "Show this image as background");
 +      prop = RNA_def_property(srna, "use_gpencil_paper", PROP_BOOLEAN, PROP_NONE);
-       RNA_def_property_boolean_sdna(prop, NULL, "flag3", V3D_GP_SHOW_PAPER);
++      RNA_def_property_boolean_sdna(prop, NULL, "gp_flag", V3D_GP_SHOW_PAPER);
 +      RNA_def_property_ui_text(prop, "Use Paper",
 +              "Cover all viewport with a full color layer to improve visibility while drawing over complex scenes");
        RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
  
 -      prop = RNA_def_property(srna, "show_on_foreground", PROP_BOOLEAN, PROP_NONE);
 -      RNA_def_property_boolean_sdna(prop, NULL, "flag", V3D_BGPIC_FOREGROUND);
 -      RNA_def_property_ui_text(prop, "Show On Foreground", "Show this image in front of objects in viewport");
 +      prop = RNA_def_property(srna, "use_gpencil_grid", PROP_BOOLEAN, PROP_NONE);
-       RNA_def_property_boolean_sdna(prop, NULL, "flag3", V3D_GP_SHOW_GRID);
++      RNA_def_property_boolean_sdna(prop, NULL, "gp_flag", V3D_GP_SHOW_GRID);
 +      RNA_def_property_ui_text(prop, "Use Grid",
 +              "Draw a grid over grease pencil paper");
        RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
  
 -      /* expose 1 flag as a enum of 2 items */
 -      prop = RNA_def_property(srna, "draw_depth", PROP_ENUM, PROP_NONE);
 -      RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag");
 -      RNA_def_property_enum_items(prop, bgpic_draw_depth_items);
 -      RNA_def_property_ui_text(prop, "Depth", "Draw under or over everything");
 +      prop = RNA_def_property(srna, "gpencil_grid_scale", PROP_FLOAT, PROP_NONE);
 +      RNA_def_property_float_sdna(prop, NULL, "overlay.gpencil_grid_scale");
 +      RNA_def_property_range(prop, 0.01f, FLT_MAX);
 +      RNA_def_property_float_default(prop, 1.0f);
 +      RNA_def_property_ui_text(prop, "Scale", "Grid scale");
        RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
  
 -      /* expose 2 flags as a enum of 3 items */
 -      prop = RNA_def_property(srna, "frame_method", PROP_ENUM, PROP_NONE);
 -      RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag");
 -      RNA_def_property_enum_items(prop, bgpic_camera_frame_items);
 -      RNA_def_property_ui_text(prop, "Frame Method", "How the image fits in the camera frame");
 +      prop = RNA_def_property(srna, "gpencil_grid_lines", PROP_INT, PROP_NONE);
 +      RNA_def_property_int_sdna(prop, NULL, "overlay.gpencil_grid_lines");
 +      RNA_def_property_range(prop, 1, INT_MAX);
 +      RNA_def_property_int_default(prop, GP_DEFAULT_GRID_LINES);
 +      RNA_def_property_ui_text(prop, "Subdivisions", "Number of subdivisions in each side of symmetry line");
        RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
 -}
  
 -static void rna_def_backgroundImages(BlenderRNA *brna, PropertyRNA *cprop)
 -{
 -      StructRNA *srna;
 -      FunctionRNA *func;
 -      PropertyRNA *parm;
 +      prop = RNA_def_property(srna, "gpencil_grid_axis", PROP_ENUM, PROP_NONE);
 +      RNA_def_property_enum_sdna(prop, NULL, "overlay.gpencil_grid_axis");
 +      RNA_def_property_enum_items(prop, rna_enum_gpencil_grid_axis_items);
 +      RNA_def_property_ui_text(prop, "Axis", "Axis to display grid");
 +      RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
  
 -      RNA_def_property_srna(cprop, "BackgroundImages");
 -      srna = RNA_def_struct(brna, "BackgroundImages", NULL);
 -      RNA_def_struct_sdna(srna, "View3D");
 -      RNA_def_struct_ui_text(srna, "Background Images", "Collection of background images");
 +      prop = RNA_def_property(srna, "gpencil_grid_opacity", PROP_FLOAT, PROP_NONE);
 +      RNA_def_property_float_sdna(prop, NULL, "overlay.gpencil_grid_opacity");
 +      RNA_def_property_range(prop, 0.1f, 1.0f);
 +      RNA_def_property_float_default(prop, 0.9f);
 +      RNA_def_property_ui_text(prop, "Opacity", "Grid opacity");
 +      RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
  
 -      func = RNA_def_function(srna, "new", "rna_BackgroundImage_new");
 -      RNA_def_function_ui_description(func, "Add new background image");
 -      parm = RNA_def_pointer(func, "image", "BackgroundImage", "", "Image displayed as viewport background");
 -      RNA_def_function_return(func, parm);
 +      /* Paper opacity factor */
 +      prop = RNA_def_property(srna, "gpencil_paper_opacity", PROP_FLOAT, PROP_NONE);
 +      RNA_def_property_float_sdna(prop, NULL, "overlay.gpencil_paper_opacity");
 +      RNA_def_property_range(prop, 0.0f, 1.0f);
 +      RNA_def_property_float_default(prop, 0.5f);
 +      RNA_def_property_ui_text(prop, "Opacity", "Paper opacity");
 +      RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
  
 -      func = RNA_def_function(srna, "remove", "rna_BackgroundImage_remove");
 -      RNA_def_function_ui_description(func, "Remove background image");
 -      RNA_def_function_flag(func, FUNC_USE_REPORTS);
 -      parm = RNA_def_pointer(func, "image", "BackgroundImage", "", "Image displayed as viewport background");
 -      RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
 -      RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
 +      /* show edit lines */
 +      prop = RNA_def_property(srna, "use_gpencil_edit_lines", PROP_BOOLEAN, PROP_NONE);
-       RNA_def_property_boolean_sdna(prop, NULL, "flag3", V3D_GP_SHOW_EDIT_LINES);
++      RNA_def_property_boolean_sdna(prop, NULL, "gp_flag", V3D_GP_SHOW_EDIT_LINES);
 +      RNA_def_property_ui_text(prop, "Edit Lines", "Show edit lines when edit strokes");
 +      RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_GPencil_update");
 +
 +      prop = RNA_def_property(srna, "use_gpencil_multiedit_line_only", PROP_BOOLEAN, PROP_NONE);
-       RNA_def_property_boolean_sdna(prop, NULL, "flag3", V3D_GP_SHOW_MULTIEDIT_LINES);
++      RNA_def_property_boolean_sdna(prop, NULL, "gp_flag", V3D_GP_SHOW_MULTIEDIT_LINES);
 +      RNA_def_property_ui_text(prop, "Lines Only", "Show only edit lines for additional frames");
 +      RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_GPencil_update");
 +
 +      /* main grease pencil onion switch */
 +      prop = RNA_def_property(srna, "use_gpencil_onion_skin", PROP_BOOLEAN, PROP_NONE);
-       RNA_def_property_boolean_sdna(prop, NULL, "flag3", V3D_GP_SHOW_ONION_SKIN);
++      RNA_def_property_boolean_sdna(prop, NULL, "gp_flag", V3D_GP_SHOW_ONION_SKIN);
 +      RNA_def_property_ui_text(prop, "Onion Skins", "Show ghosts of the frames before and after the current frame");
 +      RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_GPencil_update");
 +
 +      /* vertex opacity */
 +      prop = RNA_def_property(srna, "vertex_opacity", PROP_FLOAT, PROP_NONE);
 +      RNA_def_property_float_sdna(prop, NULL, "vertex_opacity");
 +      RNA_def_property_range(prop, 0.0f, 1.0f);
 +      RNA_def_property_ui_text(prop, "Vertex Opacity", "Opacity for edit vertices");
 +      RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
 +      RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, "rna_GPencil_update");
  
 -      func = RNA_def_function(srna, "clear", "rna_BackgroundImage_clear");
 -      RNA_def_function_ui_description(func, "Remove all background images");
  }
  
 -
  static void rna_def_space_view3d(BlenderRNA *brna)
  {
        StructRNA *srna;