2020-06-16 15:28:46 +02:00
|
|
|
/*
|
|
|
|
|
* 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.
|
|
|
|
|
*
|
|
|
|
|
* The Original Code is Copyright (C) 2008, Blender Foundation
|
|
|
|
|
* This is a new part of Blender
|
|
|
|
|
* Operator for converting Grease Pencil data to geometry
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/** \file
|
|
|
|
|
* \ingroup edgpencil
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
|
|
|
|
|
|
#include "BLI_blenlib.h"
|
2020-10-21 19:15:18 +02:00
|
|
|
#include "BLI_ghash.h"
|
2020-06-16 15:28:46 +02:00
|
|
|
#include "BLI_math.h"
|
|
|
|
|
|
2020-10-21 19:15:18 +02:00
|
|
|
#include "DNA_anim_types.h"
|
2020-06-16 15:28:46 +02:00
|
|
|
#include "DNA_gpencil_types.h"
|
|
|
|
|
#include "DNA_scene_types.h"
|
|
|
|
|
#include "DNA_screen_types.h"
|
|
|
|
|
|
2020-10-21 19:15:18 +02:00
|
|
|
#include "BKE_anim_data.h"
|
2020-06-16 15:28:46 +02:00
|
|
|
#include "BKE_context.h"
|
|
|
|
|
#include "BKE_duplilist.h"
|
|
|
|
|
#include "BKE_global.h"
|
|
|
|
|
#include "BKE_gpencil.h"
|
|
|
|
|
#include "BKE_gpencil_geom.h"
|
2020-11-13 13:17:17 +01:00
|
|
|
#include "BKE_layer.h"
|
2020-06-16 15:28:46 +02:00
|
|
|
#include "BKE_main.h"
|
|
|
|
|
#include "BKE_material.h"
|
|
|
|
|
#include "BKE_object.h"
|
|
|
|
|
#include "BKE_report.h"
|
|
|
|
|
#include "BKE_scene.h"
|
|
|
|
|
|
|
|
|
|
#include "DEG_depsgraph.h"
|
|
|
|
|
#include "DEG_depsgraph_query.h"
|
|
|
|
|
|
|
|
|
|
#include "WM_api.h"
|
|
|
|
|
#include "WM_types.h"
|
|
|
|
|
|
|
|
|
|
#include "RNA_access.h"
|
|
|
|
|
#include "RNA_define.h"
|
|
|
|
|
|
|
|
|
|
#include "ED_gpencil.h"
|
|
|
|
|
#include "ED_transform_snap_object_context.h"
|
|
|
|
|
|
|
|
|
|
#include "gpencil_intern.h"
|
|
|
|
|
|
|
|
|
|
/* Check frame_end is always > start frame! */
|
2020-06-29 15:28:38 +02:00
|
|
|
static void gpencil_bake_set_frame_end(struct Main *UNUSED(main),
|
|
|
|
|
struct Scene *UNUSED(scene),
|
|
|
|
|
struct PointerRNA *ptr)
|
2020-06-16 15:28:46 +02:00
|
|
|
{
|
|
|
|
|
int frame_start = RNA_int_get(ptr, "frame_start");
|
|
|
|
|
int frame_end = RNA_int_get(ptr, "frame_end");
|
|
|
|
|
|
|
|
|
|
if (frame_end <= frame_start) {
|
|
|
|
|
RNA_int_set(ptr, "frame_end", frame_start + 1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Extract mesh animation to Grease Pencil. */
|
2020-06-29 15:28:38 +02:00
|
|
|
static bool gpencil_bake_mesh_animation_poll(bContext *C)
|
2020-06-16 15:28:46 +02:00
|
|
|
{
|
|
|
|
|
if (CTX_data_mode_enum(C) != CTX_MODE_OBJECT) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Only if the current view is 3D View. */
|
|
|
|
|
ScrArea *area = CTX_wm_area(C);
|
|
|
|
|
return (area && area->spacetype);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
typedef struct GpBakeOb {
|
2020-07-15 12:47:45 +02:00
|
|
|
struct GpBakeOb *next, *prev;
|
2020-06-16 15:28:46 +02:00
|
|
|
Object *ob;
|
|
|
|
|
} GpBakeOb;
|
|
|
|
|
|
2020-10-21 19:15:18 +02:00
|
|
|
/* Get list of keyframes used by selected objects. */
|
|
|
|
|
static void animdata_keyframe_list_get(ListBase *ob_list,
|
|
|
|
|
const bool only_selected,
|
|
|
|
|
GHash *r_keyframes)
|
|
|
|
|
{
|
|
|
|
|
/* Loop all objects to get the list of keyframes used. */
|
|
|
|
|
LISTBASE_FOREACH (GpBakeOb *, elem, ob_list) {
|
|
|
|
|
Object *ob = elem->ob;
|
|
|
|
|
AnimData *adt = BKE_animdata_from_id(&ob->id);
|
|
|
|
|
if ((adt == NULL) || (adt->action == NULL)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
LISTBASE_FOREACH (FCurve *, fcurve, &adt->action->curves) {
|
|
|
|
|
int i;
|
|
|
|
|
BezTriple *bezt;
|
|
|
|
|
for (i = 0, bezt = fcurve->bezt; i < fcurve->totvert; i++, bezt++) {
|
|
|
|
|
/* Keyframe number is x value of point. */
|
|
|
|
|
if ((bezt->f2 & SELECT) || (!only_selected)) {
|
|
|
|
|
/* Insert only one key for each keyframe number. */
|
|
|
|
|
int key = (int)bezt->vec[1][0];
|
|
|
|
|
if (!BLI_ghash_haskey(r_keyframes, POINTER_FROM_INT(key))) {
|
|
|
|
|
BLI_ghash_insert(r_keyframes, POINTER_FROM_INT(key), POINTER_FROM_INT(key));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-29 15:28:38 +02:00
|
|
|
static void gpencil_bake_duplilist(Depsgraph *depsgraph, Scene *scene, Object *ob, ListBase *list)
|
2020-06-16 15:28:46 +02:00
|
|
|
{
|
|
|
|
|
GpBakeOb *elem = NULL;
|
|
|
|
|
ListBase *lb;
|
|
|
|
|
DupliObject *dob;
|
|
|
|
|
lb = object_duplilist(depsgraph, scene, ob);
|
|
|
|
|
for (dob = lb->first; dob; dob = dob->next) {
|
|
|
|
|
if (dob->ob->type != OB_MESH) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
elem = MEM_callocN(sizeof(GpBakeOb), __func__);
|
|
|
|
|
elem->ob = dob->ob;
|
|
|
|
|
BLI_addtail(list, elem);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
free_object_duplilist(lb);
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-15 17:25:07 +02:00
|
|
|
static bool gpencil_bake_ob_list(bContext *C, Depsgraph *depsgraph, Scene *scene, ListBase *list)
|
2020-06-16 15:28:46 +02:00
|
|
|
{
|
|
|
|
|
GpBakeOb *elem = NULL;
|
2020-07-15 17:25:07 +02:00
|
|
|
bool simple_material = false;
|
2020-06-16 15:28:46 +02:00
|
|
|
|
|
|
|
|
/* Add active object. In some files this could not be in selected array. */
|
|
|
|
|
Object *obact = CTX_data_active_object(C);
|
|
|
|
|
|
|
|
|
|
if (obact->type == OB_MESH) {
|
|
|
|
|
elem = MEM_callocN(sizeof(GpBakeOb), __func__);
|
|
|
|
|
elem->ob = obact;
|
|
|
|
|
BLI_addtail(list, elem);
|
|
|
|
|
}
|
|
|
|
|
/* Add duplilist. */
|
|
|
|
|
else if (obact->type == OB_EMPTY) {
|
2020-06-29 15:28:38 +02:00
|
|
|
gpencil_bake_duplilist(depsgraph, scene, obact, list);
|
2020-07-15 17:25:07 +02:00
|
|
|
simple_material |= true;
|
2020-06-16 15:28:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Add other selected objects. */
|
|
|
|
|
CTX_DATA_BEGIN (C, Object *, ob, selected_objects) {
|
|
|
|
|
if (ob == obact) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
/* Add selected meshes.*/
|
|
|
|
|
if (ob->type == OB_MESH) {
|
|
|
|
|
elem = MEM_callocN(sizeof(GpBakeOb), __func__);
|
|
|
|
|
elem->ob = ob;
|
|
|
|
|
BLI_addtail(list, elem);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Add duplilist. */
|
|
|
|
|
if (ob->type == OB_EMPTY) {
|
2020-06-29 15:28:38 +02:00
|
|
|
gpencil_bake_duplilist(depsgraph, scene, obact, list);
|
2020-06-16 15:28:46 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
CTX_DATA_END;
|
2020-07-15 17:25:07 +02:00
|
|
|
|
|
|
|
|
return simple_material;
|
2020-06-16 15:28:46 +02:00
|
|
|
}
|
|
|
|
|
|
2020-06-29 15:28:38 +02:00
|
|
|
static void gpencil_bake_free_ob_list(ListBase *list)
|
2020-06-16 15:28:46 +02:00
|
|
|
{
|
|
|
|
|
LISTBASE_FOREACH_MUTABLE (GpBakeOb *, elem, list) {
|
|
|
|
|
MEM_SAFE_FREE(elem);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-29 15:28:38 +02:00
|
|
|
static int gpencil_bake_mesh_animation_exec(bContext *C, wmOperator *op)
|
2020-06-16 15:28:46 +02:00
|
|
|
{
|
|
|
|
|
Main *bmain = CTX_data_main(C);
|
|
|
|
|
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
|
|
|
|
|
Scene *scene = CTX_data_scene(C);
|
|
|
|
|
ARegion *region = CTX_wm_region(C);
|
|
|
|
|
View3D *v3d = CTX_wm_view3d(C);
|
|
|
|
|
|
2020-10-21 19:15:18 +02:00
|
|
|
ListBase ob_selected_list = {NULL, NULL};
|
|
|
|
|
gpencil_bake_ob_list(C, depsgraph, scene, &ob_selected_list);
|
2020-06-16 15:28:46 +02:00
|
|
|
|
|
|
|
|
/* Cannot check this in poll because the active object changes. */
|
2020-10-21 19:15:18 +02:00
|
|
|
if (ob_selected_list.first == NULL) {
|
2020-06-16 15:28:46 +02:00
|
|
|
BKE_report(op->reports, RPT_INFO, "No valid object selected");
|
2020-10-21 19:15:18 +02:00
|
|
|
gpencil_bake_free_ob_list(&ob_selected_list);
|
2020-06-16 15:28:46 +02:00
|
|
|
return OPERATOR_CANCELLED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Grab all relevant settings. */
|
|
|
|
|
const int step = RNA_int_get(op->ptr, "step");
|
|
|
|
|
|
|
|
|
|
const int frame_start = (scene->r.sfra > RNA_int_get(op->ptr, "frame_start")) ?
|
|
|
|
|
scene->r.sfra :
|
|
|
|
|
RNA_int_get(op->ptr, "frame_start");
|
|
|
|
|
|
|
|
|
|
const int frame_end = (scene->r.efra < RNA_int_get(op->ptr, "frame_end")) ?
|
|
|
|
|
scene->r.efra :
|
|
|
|
|
RNA_int_get(op->ptr, "frame_end");
|
|
|
|
|
|
|
|
|
|
const float angle = RNA_float_get(op->ptr, "angle");
|
|
|
|
|
const int thickness = RNA_int_get(op->ptr, "thickness");
|
|
|
|
|
const bool use_seams = RNA_boolean_get(op->ptr, "seams");
|
|
|
|
|
const bool use_faces = RNA_boolean_get(op->ptr, "faces");
|
2020-10-21 19:15:18 +02:00
|
|
|
const bool only_selected = RNA_boolean_get(op->ptr, "only_selected");
|
2020-06-16 15:28:46 +02:00
|
|
|
const float offset = RNA_float_get(op->ptr, "offset");
|
|
|
|
|
const int frame_offset = RNA_int_get(op->ptr, "frame_target") - frame_start;
|
|
|
|
|
const int project_type = RNA_enum_get(op->ptr, "project_type");
|
2020-11-13 13:17:17 +01:00
|
|
|
eGP_TargetObjectMode target = RNA_enum_get(op->ptr, "target");
|
2020-06-16 15:28:46 +02:00
|
|
|
|
2020-11-16 16:48:44 +11:00
|
|
|
/* Create a new grease pencil object in origin or reuse selected. */
|
2020-11-13 13:17:17 +01:00
|
|
|
Object *ob_gpencil = NULL;
|
2020-06-16 15:28:46 +02:00
|
|
|
bool newob = false;
|
2020-11-16 16:48:44 +11:00
|
|
|
|
2020-11-13 13:17:17 +01:00
|
|
|
if (target == GP_TARGET_OB_SELECTED) {
|
2020-11-16 16:48:44 +11:00
|
|
|
ob_gpencil = BKE_view_layer_non_active_selected_object(CTX_data_view_layer(C), v3d);
|
|
|
|
|
if (ob_gpencil != NULL) {
|
|
|
|
|
if (ob_gpencil->type != OB_GPENCIL) {
|
|
|
|
|
BKE_report(op->reports, RPT_WARNING, "Target object not a grease pencil, ignoring!");
|
|
|
|
|
ob_gpencil = NULL;
|
|
|
|
|
}
|
|
|
|
|
else if (BKE_object_obdata_is_libdata(ob_gpencil)) {
|
|
|
|
|
BKE_report(op->reports, RPT_WARNING, "Target object library-data, ignoring!");
|
|
|
|
|
ob_gpencil = NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-11-13 13:17:17 +01:00
|
|
|
}
|
|
|
|
|
|
2020-10-23 19:19:13 +02:00
|
|
|
if (ob_gpencil == NULL) {
|
2020-06-16 15:28:46 +02:00
|
|
|
ushort local_view_bits = (v3d && v3d->localvd) ? v3d->local_view_uuid : 0;
|
2020-08-07 22:36:11 +10:00
|
|
|
const float loc[3] = {0.0f, 0.0f, 0.0f};
|
2020-06-16 15:28:46 +02:00
|
|
|
ob_gpencil = ED_gpencil_add_object(C, loc, local_view_bits);
|
|
|
|
|
newob = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bGPdata *gpd = (bGPdata *)ob_gpencil->data;
|
|
|
|
|
gpd->draw_mode = (project_type == GP_REPROJECT_KEEP) ? GP_DRAWMODE_3D : GP_DRAWMODE_2D;
|
|
|
|
|
|
|
|
|
|
/* Set cursor to indicate working. */
|
|
|
|
|
WM_cursor_wait(1);
|
|
|
|
|
|
|
|
|
|
GP_SpaceConversion gsc = {NULL};
|
|
|
|
|
SnapObjectContext *sctx = NULL;
|
|
|
|
|
if (project_type != GP_REPROJECT_KEEP) {
|
|
|
|
|
/* Init space conversion stuff. */
|
2020-06-29 12:49:30 +02:00
|
|
|
gpencil_point_conversion_init(C, &gsc);
|
2020-11-13 13:17:17 +01:00
|
|
|
/* Move the grease pencil object to conversion data. */
|
|
|
|
|
gsc.ob = ob_gpencil;
|
|
|
|
|
|
2020-06-16 15:28:46 +02:00
|
|
|
/* Init snap context for geometry projection. */
|
|
|
|
|
sctx = ED_transform_snap_object_context_create_view3d(scene, 0, region, CTX_wm_view3d(C));
|
|
|
|
|
|
|
|
|
|
/* Tag all existing strokes to avoid reprojections. */
|
|
|
|
|
LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
|
|
|
|
|
LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
|
|
|
|
|
LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
|
|
|
|
|
gps->flag |= GP_STROKE_TAG;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Loop all frame range. */
|
|
|
|
|
int oldframe = (int)DEG_get_ctime(depsgraph);
|
|
|
|
|
int key = -1;
|
2020-10-21 19:15:18 +02:00
|
|
|
|
|
|
|
|
/* Get list of keyframes. */
|
|
|
|
|
GHash *keyframe_list = BLI_ghash_int_new(__func__);
|
|
|
|
|
if (only_selected) {
|
|
|
|
|
animdata_keyframe_list_get(&ob_selected_list, only_selected, keyframe_list);
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-16 15:28:46 +02:00
|
|
|
for (int i = frame_start; i < frame_end + 1; i++) {
|
|
|
|
|
key++;
|
|
|
|
|
/* Jump if not step limit but include last frame always. */
|
|
|
|
|
if ((key % step != 0) && (i != frame_end)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-21 19:15:18 +02:00
|
|
|
/* Check if frame is in the list of frames to be exported. */
|
|
|
|
|
if ((only_selected) && (!BLI_ghash_haskey(keyframe_list, POINTER_FROM_INT(i)))) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-16 15:28:46 +02:00
|
|
|
/* Move scene to new frame. */
|
|
|
|
|
CFRA = i;
|
2020-08-18 15:45:58 +02:00
|
|
|
BKE_scene_graph_update_for_newframe(depsgraph);
|
2020-06-16 15:28:46 +02:00
|
|
|
|
|
|
|
|
/* Loop all objects in the list. */
|
2020-10-21 19:15:18 +02:00
|
|
|
LISTBASE_FOREACH (GpBakeOb *, elem, &ob_selected_list) {
|
2020-06-16 15:28:46 +02:00
|
|
|
Object *ob_eval = (Object *)DEG_get_evaluated_object(depsgraph, elem->ob);
|
|
|
|
|
|
|
|
|
|
/* Generate strokes. */
|
|
|
|
|
BKE_gpencil_convert_mesh(bmain,
|
|
|
|
|
depsgraph,
|
|
|
|
|
scene,
|
|
|
|
|
ob_gpencil,
|
|
|
|
|
elem->ob,
|
|
|
|
|
angle,
|
|
|
|
|
thickness,
|
|
|
|
|
offset,
|
|
|
|
|
ob_eval->obmat,
|
|
|
|
|
frame_offset,
|
|
|
|
|
use_seams,
|
2020-09-10 20:04:38 +02:00
|
|
|
use_faces);
|
2020-06-16 15:28:46 +02:00
|
|
|
|
|
|
|
|
/* Reproject all untaged created strokes. */
|
|
|
|
|
if (project_type != GP_REPROJECT_KEEP) {
|
|
|
|
|
LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
|
|
|
|
|
bGPDframe *gpf = gpl->actframe;
|
2020-10-21 19:15:18 +02:00
|
|
|
if (gpf == NULL) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
|
|
|
|
|
if ((gps->flag & GP_STROKE_TAG) == 0) {
|
|
|
|
|
ED_gpencil_stroke_reproject(
|
|
|
|
|
depsgraph, &gsc, sctx, gpl, gpf, gps, project_type, false);
|
|
|
|
|
gps->flag |= GP_STROKE_TAG;
|
2020-06-16 15:28:46 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Return scene frame state and DB to original state. */
|
|
|
|
|
CFRA = oldframe;
|
2020-08-18 15:45:58 +02:00
|
|
|
BKE_scene_graph_update_for_newframe(depsgraph);
|
2020-06-16 15:28:46 +02:00
|
|
|
|
|
|
|
|
/* Remove unused materials. */
|
|
|
|
|
int actcol = ob_gpencil->actcol;
|
|
|
|
|
for (int slot = 1; slot <= ob_gpencil->totcol; slot++) {
|
|
|
|
|
while (slot <= ob_gpencil->totcol && !BKE_object_material_slot_used(ob_gpencil->data, slot)) {
|
|
|
|
|
ob_gpencil->actcol = slot;
|
|
|
|
|
BKE_object_material_slot_remove(CTX_data_main(C), ob_gpencil);
|
|
|
|
|
|
|
|
|
|
if (actcol >= slot) {
|
|
|
|
|
actcol--;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
ob_gpencil->actcol = actcol;
|
|
|
|
|
|
|
|
|
|
/* Untag all strokes. */
|
|
|
|
|
if (project_type != GP_REPROJECT_KEEP) {
|
|
|
|
|
LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
|
|
|
|
|
LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
|
|
|
|
|
LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
|
|
|
|
|
gps->flag &= ~GP_STROKE_TAG;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Free memory. */
|
2020-10-21 19:15:18 +02:00
|
|
|
gpencil_bake_free_ob_list(&ob_selected_list);
|
2020-06-16 15:28:46 +02:00
|
|
|
if (sctx != NULL) {
|
|
|
|
|
ED_transform_snap_object_context_destroy(sctx);
|
|
|
|
|
}
|
2020-10-21 19:15:18 +02:00
|
|
|
/* Free temp hash table. */
|
|
|
|
|
if (keyframe_list != NULL) {
|
|
|
|
|
BLI_ghash_free(keyframe_list, NULL, NULL);
|
|
|
|
|
}
|
2020-06-16 15:28:46 +02:00
|
|
|
|
|
|
|
|
/* notifiers */
|
|
|
|
|
if (newob) {
|
|
|
|
|
DEG_relations_tag_update(bmain);
|
|
|
|
|
}
|
|
|
|
|
DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
|
|
|
|
|
WM_event_add_notifier(C, NC_OBJECT | NA_ADDED, NULL);
|
|
|
|
|
WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
|
|
|
|
|
|
|
|
|
|
/* Reset cursor. */
|
|
|
|
|
WM_cursor_wait(0);
|
|
|
|
|
|
|
|
|
|
/* done */
|
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-23 19:19:13 +02:00
|
|
|
static int gpencil_bake_mesh_animation_invoke(bContext *C,
|
|
|
|
|
wmOperator *op,
|
|
|
|
|
const wmEvent *UNUSED(event))
|
|
|
|
|
{
|
|
|
|
|
/* Show popup dialog to allow editing. */
|
|
|
|
|
/* FIXME: hard-coded dimensions here are just arbitrary. */
|
|
|
|
|
return WM_operator_props_dialog_popup(C, op, 250);
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-16 15:28:46 +02:00
|
|
|
void GPENCIL_OT_bake_mesh_animation(wmOperatorType *ot)
|
|
|
|
|
{
|
|
|
|
|
static const EnumPropertyItem reproject_type[] = {
|
|
|
|
|
{GP_REPROJECT_KEEP, "KEEP", 0, "No Reproject", ""},
|
|
|
|
|
{GP_REPROJECT_FRONT, "FRONT", 0, "Front", "Reproject the strokes using the X-Z plane"},
|
|
|
|
|
{GP_REPROJECT_SIDE, "SIDE", 0, "Side", "Reproject the strokes using the Y-Z plane"},
|
|
|
|
|
{GP_REPROJECT_TOP, "TOP", 0, "Top", "Reproject the strokes using the X-Y plane"},
|
|
|
|
|
{GP_REPROJECT_VIEW,
|
|
|
|
|
"VIEW",
|
|
|
|
|
0,
|
|
|
|
|
"View",
|
|
|
|
|
"Reproject the strokes to end up on the same plane, as if drawn from the current viewpoint "
|
|
|
|
|
"using 'Cursor' Stroke Placement"},
|
|
|
|
|
{GP_REPROJECT_CURSOR,
|
|
|
|
|
"CURSOR",
|
|
|
|
|
0,
|
|
|
|
|
"Cursor",
|
|
|
|
|
"Reproject the strokes using the orientation of 3D cursor"},
|
|
|
|
|
{0, NULL, 0, NULL, NULL},
|
|
|
|
|
};
|
|
|
|
|
|
2020-11-13 13:17:17 +01:00
|
|
|
static const EnumPropertyItem target_object_modes[] = {
|
|
|
|
|
{GP_TARGET_OB_NEW, "NEW", 0, "New Object", ""},
|
|
|
|
|
{GP_TARGET_OB_SELECTED, "SELECTED", 0, "Selected Object", ""},
|
|
|
|
|
{0, NULL, 0, NULL, NULL},
|
|
|
|
|
};
|
|
|
|
|
|
2020-06-16 15:28:46 +02:00
|
|
|
PropertyRNA *prop;
|
|
|
|
|
|
|
|
|
|
/* identifiers */
|
|
|
|
|
ot->name = "Bake Mesh Animation to Grease Pencil";
|
|
|
|
|
ot->idname = "GPENCIL_OT_bake_mesh_animation";
|
2020-12-24 11:07:32 -06:00
|
|
|
ot->description = "Bake mesh animation to grease pencil strokes";
|
2020-06-16 15:28:46 +02:00
|
|
|
|
|
|
|
|
/* callbacks */
|
2020-10-23 19:19:13 +02:00
|
|
|
ot->invoke = gpencil_bake_mesh_animation_invoke;
|
2020-06-29 15:28:38 +02:00
|
|
|
ot->exec = gpencil_bake_mesh_animation_exec;
|
|
|
|
|
ot->poll = gpencil_bake_mesh_animation_poll;
|
2020-06-16 15:28:46 +02:00
|
|
|
|
|
|
|
|
/* flags */
|
|
|
|
|
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
|
|
|
|
|
|
|
|
|
/* properties */
|
2020-11-13 13:17:17 +01:00
|
|
|
ot->prop = RNA_def_enum(ot->srna,
|
|
|
|
|
"target",
|
|
|
|
|
target_object_modes,
|
|
|
|
|
GP_TARGET_OB_NEW,
|
|
|
|
|
"Target Object",
|
|
|
|
|
"Target grease pencil");
|
2020-10-23 19:19:13 +02:00
|
|
|
RNA_def_property_flag(ot->prop, PROP_SKIP_SAVE);
|
|
|
|
|
|
|
|
|
|
prop = RNA_def_int(
|
2020-06-16 15:28:46 +02:00
|
|
|
ot->srna, "frame_start", 1, 1, 100000, "Start Frame", "The start frame", 1, 100000);
|
|
|
|
|
|
|
|
|
|
prop = RNA_def_int(
|
|
|
|
|
ot->srna, "frame_end", 250, 1, 100000, "End Frame", "The end frame of animation", 1, 100000);
|
2020-06-29 15:28:38 +02:00
|
|
|
RNA_def_property_update_runtime(prop, gpencil_bake_set_frame_end);
|
2020-06-16 15:28:46 +02:00
|
|
|
|
|
|
|
|
prop = RNA_def_int(ot->srna, "step", 1, 1, 100, "Step", "Step between generated frames", 1, 100);
|
|
|
|
|
|
2020-10-23 19:44:38 +02:00
|
|
|
RNA_def_int(ot->srna, "thickness", 1, 1, 100, "Thickness", "", 1, 100);
|
|
|
|
|
|
2020-06-16 15:28:46 +02:00
|
|
|
prop = RNA_def_float_rotation(ot->srna,
|
|
|
|
|
"angle",
|
|
|
|
|
0,
|
|
|
|
|
NULL,
|
|
|
|
|
DEG2RADF(0.0f),
|
|
|
|
|
DEG2RADF(180.0f),
|
|
|
|
|
"Threshold Angle",
|
|
|
|
|
"Threshold to determine ends of the strokes",
|
|
|
|
|
DEG2RADF(0.0f),
|
|
|
|
|
DEG2RADF(180.0f));
|
|
|
|
|
RNA_def_property_float_default(prop, DEG2RADF(70.0f));
|
|
|
|
|
|
2020-10-23 19:44:38 +02:00
|
|
|
RNA_def_float_distance(ot->srna,
|
|
|
|
|
"offset",
|
|
|
|
|
0.001f,
|
|
|
|
|
0.0,
|
|
|
|
|
100.0,
|
|
|
|
|
"Stroke Offset",
|
|
|
|
|
"Offset strokes from fill",
|
|
|
|
|
0.0,
|
|
|
|
|
100.00);
|
|
|
|
|
|
2020-06-16 15:28:46 +02:00
|
|
|
RNA_def_boolean(ot->srna, "seams", 0, "Only Seam Edges", "Convert only seam edges");
|
|
|
|
|
RNA_def_boolean(ot->srna, "faces", 1, "Export Faces", "Export faces as filled strokes");
|
2020-10-21 19:15:18 +02:00
|
|
|
RNA_def_boolean(
|
|
|
|
|
ot->srna, "only_selected", 0, "Only Selected Keyframes", "Convert only selected keyframes");
|
2020-10-23 19:44:38 +02:00
|
|
|
RNA_def_int(
|
|
|
|
|
ot->srna, "frame_target", 1, 1, 100000, "Target Frame", "Destination frame", 1, 100000);
|
2020-06-16 15:28:46 +02:00
|
|
|
|
|
|
|
|
RNA_def_enum(ot->srna, "project_type", reproject_type, GP_REPROJECT_VIEW, "Projection Type", "");
|
|
|
|
|
}
|