Add Chromium-only Blender WebEngine parity work
This commit is contained in:
63
blender-5.2.0/source/blender/editors/physics/CMakeLists.txt
Normal file
63
blender-5.2.0/source/blender/editors/physics/CMakeLists.txt
Normal file
@@ -0,0 +1,63 @@
|
||||
# SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
set(INC
|
||||
../include
|
||||
../../makesrna
|
||||
../../../../intern/mantaflow/extern
|
||||
# RNA_prototypes.hh
|
||||
${CMAKE_BINARY_DIR}/source/blender/makesrna
|
||||
)
|
||||
|
||||
set(INC_SYS
|
||||
)
|
||||
|
||||
set(SRC
|
||||
dynamicpaint_ops.cc
|
||||
particle_boids.cc
|
||||
particle_edit.cc
|
||||
particle_edit_undo.cc
|
||||
particle_object.cc
|
||||
physics_fluid.cc
|
||||
physics_ops.cc
|
||||
physics_pointcache.cc
|
||||
rigidbody_constraint.cc
|
||||
rigidbody_object.cc
|
||||
rigidbody_world.cc
|
||||
|
||||
particle_edit_utildefines.h
|
||||
physics_intern.hh
|
||||
)
|
||||
|
||||
set(LIB
|
||||
PRIVATE bf::blenkernel
|
||||
PRIVATE bf::blenlib
|
||||
PRIVATE bf::blentranslation
|
||||
PRIVATE bf::depsgraph
|
||||
PRIVATE bf::dna
|
||||
PRIVATE bf::gpu
|
||||
PRIVATE bf::intern::clog
|
||||
PRIVATE bf::intern::guardedalloc
|
||||
PRIVATE bf::windowmanager
|
||||
)
|
||||
|
||||
if(WITH_MOD_FLUID)
|
||||
list(APPEND LIB
|
||||
bf_intern_mantaflow
|
||||
)
|
||||
add_definitions(-DWITH_FLUID)
|
||||
endif()
|
||||
|
||||
if(WITH_BULLET)
|
||||
list(APPEND INC
|
||||
../../../../intern/rigidbody
|
||||
)
|
||||
add_definitions(-DWITH_BULLET)
|
||||
endif()
|
||||
|
||||
|
||||
blender_add_lib(bf_editor_physics "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
|
||||
|
||||
# RNA_prototypes.hh
|
||||
add_dependencies(bf_editor_physics bf_rna)
|
||||
534
blender-5.2.0/source/blender/editors/physics/dynamicpaint_ops.cc
Normal file
534
blender-5.2.0/source/blender/editors/physics/dynamicpaint_ops.cc
Normal file
@@ -0,0 +1,534 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup edphys
|
||||
*/
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "BLI_path_utils.hh"
|
||||
#include "BLI_string_utf8.h"
|
||||
#include "BLI_time.h"
|
||||
|
||||
#include "BLT_translation.hh"
|
||||
|
||||
#include "DNA_dynamicpaint_types.h"
|
||||
#include "DNA_mesh_types.h"
|
||||
#include "DNA_modifier_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
#include "DNA_scene_types.h"
|
||||
|
||||
#include "BKE_attribute.h"
|
||||
#include "BKE_attribute.hh"
|
||||
#include "BKE_context.hh"
|
||||
#include "BKE_deform.hh"
|
||||
#include "BKE_dynamicpaint.h"
|
||||
#include "BKE_global.hh"
|
||||
#include "BKE_main.hh"
|
||||
#include "BKE_modifier.hh"
|
||||
#include "BKE_object_deform.h"
|
||||
#include "BKE_report.hh"
|
||||
#include "BKE_screen.hh"
|
||||
|
||||
#include "DEG_depsgraph.hh"
|
||||
#include "DEG_depsgraph_build.hh"
|
||||
#include "DEG_depsgraph_query.hh"
|
||||
|
||||
#include "ED_mesh.hh"
|
||||
#include "ED_object.hh"
|
||||
#include "ED_screen.hh"
|
||||
|
||||
#include "RNA_access.hh"
|
||||
#include "RNA_define.hh"
|
||||
#include "RNA_enum_types.hh"
|
||||
|
||||
#include "WM_api.hh"
|
||||
#include "WM_types.hh"
|
||||
|
||||
#include "physics_intern.hh" /* own include */
|
||||
|
||||
namespace blender {
|
||||
|
||||
static wmOperatorStatus surface_slot_add_exec(bContext *C, wmOperator * /*op*/)
|
||||
{
|
||||
DynamicPaintModifierData *pmd = nullptr;
|
||||
Object *cObject = ed::object::context_active_object(C);
|
||||
DynamicPaintCanvasSettings *canvas;
|
||||
DynamicPaintSurface *surface;
|
||||
|
||||
/* Make sure we're dealing with a canvas */
|
||||
pmd = reinterpret_cast<DynamicPaintModifierData *>(
|
||||
BKE_modifiers_findby_type(cObject, eModifierType_DynamicPaint));
|
||||
if (!pmd || !pmd->canvas) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
canvas = pmd->canvas;
|
||||
surface = dynamicPaint_createNewSurface(canvas, CTX_data_scene(C));
|
||||
|
||||
if (!surface) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
canvas->active_sur = 0;
|
||||
for (surface = surface->prev; surface; surface = surface->prev) {
|
||||
canvas->active_sur++;
|
||||
}
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
void DPAINT_OT_surface_slot_add(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name = "Add Surface Slot";
|
||||
ot->idname = "DPAINT_OT_surface_slot_add";
|
||||
ot->description = "Add a new Dynamic Paint surface slot";
|
||||
|
||||
/* API callbacks. */
|
||||
ot->exec = surface_slot_add_exec;
|
||||
ot->poll = ED_operator_object_active_local_editable;
|
||||
|
||||
/* flags */
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
}
|
||||
|
||||
static wmOperatorStatus surface_slot_remove_exec(bContext *C, wmOperator * /*op*/)
|
||||
{
|
||||
DynamicPaintModifierData *pmd = nullptr;
|
||||
Object *obj_ctx = ed::object::context_active_object(C);
|
||||
DynamicPaintCanvasSettings *canvas;
|
||||
DynamicPaintSurface *surface;
|
||||
int id = 0;
|
||||
|
||||
/* Make sure we're dealing with a canvas */
|
||||
pmd = reinterpret_cast<DynamicPaintModifierData *>(
|
||||
BKE_modifiers_findby_type(obj_ctx, eModifierType_DynamicPaint));
|
||||
if (!pmd || !pmd->canvas) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
canvas = pmd->canvas;
|
||||
surface = static_cast<DynamicPaintSurface *>(canvas->surfaces.first);
|
||||
|
||||
/* find active surface and remove it */
|
||||
for (; surface; surface = surface->next) {
|
||||
if (id == canvas->active_sur) {
|
||||
canvas->active_sur -= 1;
|
||||
dynamicPaint_freeSurface(pmd, surface);
|
||||
break;
|
||||
}
|
||||
id++;
|
||||
}
|
||||
|
||||
DEG_id_tag_update(&obj_ctx->id, ID_RECALC_GEOMETRY);
|
||||
WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, obj_ctx);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
void DPAINT_OT_surface_slot_remove(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name = "Remove Surface Slot";
|
||||
ot->idname = "DPAINT_OT_surface_slot_remove";
|
||||
ot->description = "Remove the selected surface slot";
|
||||
|
||||
/* API callbacks. */
|
||||
ot->exec = surface_slot_remove_exec;
|
||||
ot->poll = ED_operator_object_active_local_editable;
|
||||
|
||||
/* flags */
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
}
|
||||
|
||||
static wmOperatorStatus type_toggle_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
|
||||
Object *cObject = ed::object::context_active_object(C);
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
DynamicPaintModifierData *pmd = reinterpret_cast<DynamicPaintModifierData *>(
|
||||
BKE_modifiers_findby_type(cObject, eModifierType_DynamicPaint));
|
||||
int type = RNA_enum_get(op->ptr, "type");
|
||||
|
||||
if (!pmd) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
/* if type is already enabled, toggle it off */
|
||||
if (type == MOD_DYNAMICPAINT_TYPE_CANVAS && pmd->canvas) {
|
||||
dynamicPaint_freeCanvas(pmd);
|
||||
}
|
||||
else if (type == MOD_DYNAMICPAINT_TYPE_BRUSH && pmd->brush) {
|
||||
dynamicPaint_freeBrush(pmd);
|
||||
}
|
||||
/* else create a new type */
|
||||
else {
|
||||
if (!dynamicPaint_createType(pmd, type, scene)) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
}
|
||||
|
||||
/* update dependency */
|
||||
DEG_id_tag_update(&cObject->id, ID_RECALC_GEOMETRY);
|
||||
DEG_relations_tag_update(CTX_data_main(C));
|
||||
WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, cObject);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
void DPAINT_OT_type_toggle(wmOperatorType *ot)
|
||||
{
|
||||
PropertyRNA *prop;
|
||||
|
||||
/* identifiers */
|
||||
ot->name = "Toggle Type Active";
|
||||
ot->idname = "DPAINT_OT_type_toggle";
|
||||
ot->description = "Toggle whether given type is active or not";
|
||||
|
||||
/* API callbacks. */
|
||||
ot->exec = type_toggle_exec;
|
||||
ot->poll = ED_operator_object_active_local_editable;
|
||||
|
||||
/* flags */
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
|
||||
/* properties */
|
||||
prop = RNA_def_enum(ot->srna,
|
||||
"type",
|
||||
rna_enum_prop_dynamicpaint_type_items,
|
||||
MOD_DYNAMICPAINT_TYPE_CANVAS,
|
||||
"Type",
|
||||
"");
|
||||
RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_SIMULATION);
|
||||
ot->prop = prop;
|
||||
}
|
||||
|
||||
static wmOperatorStatus output_toggle_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
Object *ob = ed::object::context_active_object(C);
|
||||
DynamicPaintSurface *surface;
|
||||
DynamicPaintModifierData *pmd = reinterpret_cast<DynamicPaintModifierData *>(
|
||||
BKE_modifiers_findby_type(ob, eModifierType_DynamicPaint));
|
||||
int output = RNA_enum_get(op->ptr, "output"); /* currently only 1/0 */
|
||||
|
||||
if (!pmd || !pmd->canvas) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
surface = get_activeSurface(pmd->canvas);
|
||||
|
||||
/* if type is already enabled, toggle it off */
|
||||
if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
|
||||
bool exists = dynamicPaint_outputLayerExists(surface, ob, output);
|
||||
const char *name;
|
||||
|
||||
if (output == 0) {
|
||||
name = surface->output_name;
|
||||
}
|
||||
else {
|
||||
name = surface->output_name2;
|
||||
}
|
||||
|
||||
/* Vertex Color Layer */
|
||||
if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
|
||||
if (!exists) {
|
||||
ED_mesh_color_add(id_cast<Mesh *>(ob->data), name, true, true, op->reports);
|
||||
}
|
||||
else {
|
||||
AttributeOwner owner = AttributeOwner::from_id(ob->data);
|
||||
BKE_attribute_remove(owner, name, nullptr);
|
||||
}
|
||||
}
|
||||
/* Vertex Weight Layer */
|
||||
else if (surface->type == MOD_DPAINT_SURFACE_T_WEIGHT) {
|
||||
if (!exists) {
|
||||
BKE_object_defgroup_add_name(ob, name);
|
||||
DEG_relations_tag_update(CTX_data_main(C));
|
||||
}
|
||||
else {
|
||||
bDeformGroup *defgroup = BKE_object_defgroup_find_name(ob, name);
|
||||
if (defgroup) {
|
||||
BKE_object_defgroup_remove(ob, defgroup);
|
||||
DEG_relations_tag_update(CTX_data_main(C));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
void DPAINT_OT_output_toggle(wmOperatorType *ot)
|
||||
{
|
||||
static const EnumPropertyItem prop_output_toggle_types[] = {
|
||||
{0, "A", 0, "Output A", ""},
|
||||
{1, "B", 0, "Output B", ""},
|
||||
{0, nullptr, 0, nullptr, nullptr},
|
||||
};
|
||||
|
||||
/* identifiers */
|
||||
ot->name = "Toggle Output Layer";
|
||||
ot->idname = "DPAINT_OT_output_toggle";
|
||||
ot->description = "Add or remove Dynamic Paint output data layer";
|
||||
|
||||
/* API callbacks. */
|
||||
ot->exec = output_toggle_exec;
|
||||
ot->poll = ED_operator_object_active_local_editable;
|
||||
|
||||
/* flags */
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
|
||||
/* properties */
|
||||
ot->prop = RNA_def_enum(ot->srna, "output", prop_output_toggle_types, 0, "Output Toggle", "");
|
||||
}
|
||||
|
||||
/***************************** Image Sequence Baking ******************************/
|
||||
|
||||
struct DynamicPaintBakeJob {
|
||||
/* from wmJob */
|
||||
void *owner;
|
||||
bool *stop, *do_update;
|
||||
float *progress;
|
||||
|
||||
Main *bmain;
|
||||
Scene *scene;
|
||||
Depsgraph *depsgraph;
|
||||
Object *ob;
|
||||
|
||||
DynamicPaintSurface *surface;
|
||||
DynamicPaintCanvasSettings *canvas;
|
||||
|
||||
int success;
|
||||
double start;
|
||||
};
|
||||
|
||||
static void dpaint_bake_free(void *customdata)
|
||||
{
|
||||
DynamicPaintBakeJob *job = static_cast<DynamicPaintBakeJob *>(customdata);
|
||||
MEM_delete(job);
|
||||
}
|
||||
|
||||
static void dpaint_bake_endjob(void *customdata)
|
||||
{
|
||||
DynamicPaintBakeJob *job = static_cast<DynamicPaintBakeJob *>(customdata);
|
||||
DynamicPaintCanvasSettings *canvas = job->canvas;
|
||||
|
||||
canvas->flags &= ~MOD_DPAINT_BAKING;
|
||||
|
||||
dynamicPaint_freeSurfaceData(job->surface);
|
||||
|
||||
G.is_rendering = false;
|
||||
|
||||
WM_locked_interface_set(static_cast<wmWindowManager *>(G_MAIN->wm.first), false);
|
||||
|
||||
/* Bake was successful:
|
||||
* Report for ended bake and how long it took */
|
||||
if (job->success) {
|
||||
/* Show bake info */
|
||||
WM_global_reportf(
|
||||
RPT_INFO, "DynamicPaint: Bake complete! (%.2f)", BLI_time_now_seconds() - job->start);
|
||||
}
|
||||
else {
|
||||
if (strlen(canvas->error)) { /* If an error occurred */
|
||||
WM_global_reportf(RPT_ERROR, "DynamicPaint: Bake failed: %s", canvas->error);
|
||||
}
|
||||
else { /* User canceled the bake */
|
||||
WM_global_report(RPT_WARNING, "Baking canceled!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Do actual bake operation. Loop through to-be-baked frames.
|
||||
* Returns 0 on failure.
|
||||
*/
|
||||
static void dynamicPaint_bakeImageSequence(DynamicPaintBakeJob *job)
|
||||
{
|
||||
DynamicPaintSurface *surface = job->surface;
|
||||
Object *cObject = job->ob;
|
||||
DynamicPaintCanvasSettings *canvas = surface->canvas;
|
||||
Scene *input_scene = DEG_get_input_scene(job->depsgraph);
|
||||
Scene *scene = job->scene;
|
||||
int frame = 1, orig_frame;
|
||||
int frames;
|
||||
|
||||
frames = surface->end_frame - surface->start_frame + 1;
|
||||
if (frames <= 0) {
|
||||
STRNCPY_UTF8(canvas->error, N_("No frames to bake"));
|
||||
return;
|
||||
}
|
||||
|
||||
/* Show progress bar. */
|
||||
*(job->do_update) = true;
|
||||
|
||||
/* Set frame to start point (also initializes modifier data). */
|
||||
frame = surface->start_frame;
|
||||
orig_frame = input_scene->r.cfra;
|
||||
input_scene->r.cfra = frame;
|
||||
ED_update_for_newframe(job->bmain, job->depsgraph);
|
||||
|
||||
/* Init surface */
|
||||
if (!dynamicPaint_createUVSurface(scene, surface, job->progress, job->do_update)) {
|
||||
job->success = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Loop through selected frames */
|
||||
for (frame = surface->start_frame; frame <= surface->end_frame; frame++) {
|
||||
/* The first 10% are for createUVSurface... */
|
||||
const float progress = 0.1f + 0.9f * (frame - surface->start_frame) / float(frames);
|
||||
surface->current_frame = frame;
|
||||
|
||||
/* If user requested stop, quit baking */
|
||||
if (G.is_break) {
|
||||
job->success = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Update progress bar */
|
||||
*(job->do_update) = true;
|
||||
*(job->progress) = progress;
|
||||
|
||||
/* calculate a frame */
|
||||
input_scene->r.cfra = frame;
|
||||
ED_update_for_newframe(job->bmain, job->depsgraph);
|
||||
if (!dynamicPaint_calculateFrame(surface, job->depsgraph, scene, cObject, frame)) {
|
||||
job->success = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Save output images
|
||||
*/
|
||||
{
|
||||
char filepath[FILE_MAX];
|
||||
|
||||
/* primary output layer */
|
||||
if (surface->flags & MOD_DPAINT_OUT1) {
|
||||
/* set filepath */
|
||||
BLI_path_join(
|
||||
filepath, sizeof(filepath), surface->image_output_path, surface->output_name);
|
||||
BLI_path_frame(filepath, sizeof(filepath), frame, 4);
|
||||
|
||||
/* save image */
|
||||
dynamicPaint_outputSurfaceImage(surface, filepath, 0);
|
||||
}
|
||||
/* secondary output */
|
||||
if (surface->flags & MOD_DPAINT_OUT2 && surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
|
||||
/* set filepath */
|
||||
BLI_path_join(
|
||||
filepath, sizeof(filepath), surface->image_output_path, surface->output_name2);
|
||||
BLI_path_frame(filepath, sizeof(filepath), frame, 4);
|
||||
|
||||
/* save image */
|
||||
dynamicPaint_outputSurfaceImage(surface, filepath, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
input_scene->r.cfra = orig_frame;
|
||||
ED_update_for_newframe(job->bmain, job->depsgraph);
|
||||
}
|
||||
|
||||
static void dpaint_bake_startjob(void *customdata, wmJobWorkerStatus *worker_status)
|
||||
{
|
||||
DynamicPaintBakeJob *job = static_cast<DynamicPaintBakeJob *>(customdata);
|
||||
|
||||
job->stop = &worker_status->stop;
|
||||
job->do_update = &worker_status->do_update;
|
||||
job->progress = &worker_status->progress;
|
||||
job->start = BLI_time_now_seconds();
|
||||
job->success = 1;
|
||||
|
||||
G.is_break = false;
|
||||
|
||||
/* XXX annoying hack: needed to prevent data corruption when changing
|
||||
* scene frame in separate threads
|
||||
*/
|
||||
G.is_rendering = true;
|
||||
BKE_spacedata_draw_locks(REGION_DRAW_LOCK_BAKING);
|
||||
|
||||
dynamicPaint_bakeImageSequence(job);
|
||||
|
||||
worker_status->do_update = true;
|
||||
worker_status->stop = false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Bake Dynamic Paint image sequence surface
|
||||
*/
|
||||
static wmOperatorStatus dynamicpaint_bake_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
|
||||
Object *ob_ = ed::object::context_active_object(C);
|
||||
Object *object_eval = DEG_get_evaluated(depsgraph, ob_);
|
||||
Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
|
||||
|
||||
DynamicPaintSurface *surface;
|
||||
|
||||
/*
|
||||
* Get modifier data
|
||||
*/
|
||||
DynamicPaintModifierData *pmd = reinterpret_cast<DynamicPaintModifierData *>(
|
||||
BKE_modifiers_findby_type(object_eval, eModifierType_DynamicPaint));
|
||||
if (pmd == nullptr) {
|
||||
BKE_report(op->reports, RPT_ERROR, "Bake failed: no Dynamic Paint modifier found");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
/* Make sure we're dealing with a canvas */
|
||||
DynamicPaintCanvasSettings *canvas = pmd->canvas;
|
||||
if (canvas == nullptr) {
|
||||
BKE_report(op->reports, RPT_ERROR, "Bake failed: invalid canvas");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
surface = get_activeSurface(canvas);
|
||||
|
||||
/* Set state to baking and init surface */
|
||||
canvas->error[0] = '\0';
|
||||
canvas->flags |= MOD_DPAINT_BAKING;
|
||||
|
||||
DynamicPaintBakeJob *job = MEM_new_uninitialized<DynamicPaintBakeJob>("DynamicPaintBakeJob");
|
||||
job->bmain = CTX_data_main(C);
|
||||
job->scene = scene_eval;
|
||||
job->depsgraph = depsgraph;
|
||||
job->ob = object_eval;
|
||||
job->canvas = canvas;
|
||||
job->surface = surface;
|
||||
|
||||
wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C),
|
||||
CTX_wm_window(C),
|
||||
CTX_data_scene(C),
|
||||
"Baking Dynamic Paint...",
|
||||
WM_JOB_PROGRESS,
|
||||
WM_JOB_TYPE_DPAINT_BAKE);
|
||||
|
||||
WM_jobs_customdata_set(wm_job, job, dpaint_bake_free);
|
||||
WM_jobs_timer(wm_job, 0.1, NC_OBJECT | ND_MODIFIER, NC_OBJECT | ND_MODIFIER);
|
||||
WM_jobs_callbacks(wm_job, dpaint_bake_startjob, nullptr, nullptr, dpaint_bake_endjob);
|
||||
|
||||
WM_locked_interface_set_with_flags(CTX_wm_manager(C), REGION_DRAW_LOCK_BAKING);
|
||||
|
||||
/* Bake Dynamic Paint */
|
||||
WM_jobs_start(CTX_wm_manager(C), wm_job);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
void DPAINT_OT_bake(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name = "Dynamic Paint Bake";
|
||||
ot->description = "Bake dynamic paint image sequence surface";
|
||||
ot->idname = "DPAINT_OT_bake";
|
||||
|
||||
/* API callbacks. */
|
||||
ot->exec = dynamicpaint_bake_exec;
|
||||
ot->poll = ED_operator_object_active_local_editable;
|
||||
}
|
||||
|
||||
} // namespace blender
|
||||
359
blender-5.2.0/source/blender/editors/physics/particle_boids.cc
Normal file
359
blender-5.2.0/source/blender/editors/physics/particle_boids.cc
Normal file
@@ -0,0 +1,359 @@
|
||||
/* SPDX-FileCopyrightText: 2009 Janne Karhu. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup edphys
|
||||
*/
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "DNA_particle_types.h"
|
||||
|
||||
#include "BLI_listbase.h"
|
||||
|
||||
#include "BKE_boids.h"
|
||||
#include "BKE_context.hh"
|
||||
|
||||
#include "DEG_depsgraph.hh"
|
||||
#include "DEG_depsgraph_build.hh"
|
||||
|
||||
#include "RNA_access.hh"
|
||||
#include "RNA_define.hh"
|
||||
#include "RNA_enum_types.hh"
|
||||
#include "RNA_prototypes.hh"
|
||||
|
||||
#include "WM_api.hh"
|
||||
#include "WM_types.hh"
|
||||
|
||||
#include "physics_intern.hh"
|
||||
|
||||
namespace blender {
|
||||
|
||||
/************************ add/del boid rule operators *********************/
|
||||
static wmOperatorStatus rule_add_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_settings", RNA_ParticleSettings);
|
||||
ParticleSettings *part = static_cast<ParticleSettings *>(ptr.data);
|
||||
eBoidRuleType type = eBoidRuleType(RNA_enum_get(op->ptr, "type"));
|
||||
|
||||
BoidRule *rule;
|
||||
BoidState *state;
|
||||
|
||||
if (!part || part->phystype != PART_PHYS_BOIDS) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
state = boid_get_current_state(part->boids);
|
||||
|
||||
for (BoidRule &rule : state->rules) {
|
||||
rule.flag &= ~BOIDRULE_CURRENT;
|
||||
}
|
||||
|
||||
rule = boid_new_rule(type);
|
||||
rule->flag |= BOIDRULE_CURRENT;
|
||||
|
||||
BLI_addtail(&state->rules, rule);
|
||||
|
||||
DEG_id_tag_update(&part->id, ID_RECALC_GEOMETRY | ID_RECALC_PSYS_RESET);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
void BOID_OT_rule_add(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name = "Add Boid Rule";
|
||||
ot->description = "Add a boid rule to the current boid state";
|
||||
ot->idname = "BOID_OT_rule_add";
|
||||
|
||||
/* API callbacks. */
|
||||
ot->invoke = WM_menu_invoke;
|
||||
ot->exec = rule_add_exec;
|
||||
|
||||
/* flags */
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
|
||||
ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_boidrule_type_items, 0, "Type", "");
|
||||
}
|
||||
static wmOperatorStatus rule_del_exec(bContext *C, wmOperator * /*op*/)
|
||||
{
|
||||
Main *bmain = CTX_data_main(C);
|
||||
PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_settings", RNA_ParticleSettings);
|
||||
ParticleSettings *part = static_cast<ParticleSettings *>(ptr.data);
|
||||
BoidRule *rule;
|
||||
BoidState *state;
|
||||
|
||||
if (!part || part->phystype != PART_PHYS_BOIDS) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
state = boid_get_current_state(part->boids);
|
||||
|
||||
for (BoidRule &rule : state->rules) {
|
||||
if (rule.flag & BOIDRULE_CURRENT) {
|
||||
BLI_remlink(&state->rules, &rule);
|
||||
MEM_delete(&rule);
|
||||
break;
|
||||
}
|
||||
}
|
||||
rule = static_cast<BoidRule *>(state->rules.first);
|
||||
|
||||
if (rule) {
|
||||
rule->flag |= BOIDRULE_CURRENT;
|
||||
}
|
||||
|
||||
DEG_relations_tag_update(bmain);
|
||||
DEG_id_tag_update(&part->id, ID_RECALC_GEOMETRY | ID_RECALC_PSYS_RESET);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
void BOID_OT_rule_del(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name = "Remove Boid Rule";
|
||||
ot->idname = "BOID_OT_rule_del";
|
||||
ot->description = "Delete current boid rule";
|
||||
|
||||
/* API callbacks. */
|
||||
ot->exec = rule_del_exec;
|
||||
|
||||
/* flags */
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
}
|
||||
|
||||
/************************ move up/down boid rule operators *********************/
|
||||
static wmOperatorStatus rule_move_up_exec(bContext *C, wmOperator * /*op*/)
|
||||
{
|
||||
PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_settings", RNA_ParticleSettings);
|
||||
ParticleSettings *part = static_cast<ParticleSettings *>(ptr.data);
|
||||
BoidState *state;
|
||||
|
||||
if (!part || part->phystype != PART_PHYS_BOIDS) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
state = boid_get_current_state(part->boids);
|
||||
for (BoidRule &rule : state->rules) {
|
||||
if (rule.flag & BOIDRULE_CURRENT && rule.prev) {
|
||||
BLI_remlink(&state->rules, &rule);
|
||||
BLI_insertlinkbefore(&state->rules, rule.prev, &rule);
|
||||
|
||||
DEG_id_tag_update(&part->id, ID_RECALC_GEOMETRY | ID_RECALC_PSYS_RESET);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
void BOID_OT_rule_move_up(wmOperatorType *ot)
|
||||
{
|
||||
ot->name = "Move Up Boid Rule";
|
||||
ot->description = "Move boid rule up in the list";
|
||||
ot->idname = "BOID_OT_rule_move_up";
|
||||
|
||||
ot->exec = rule_move_up_exec;
|
||||
|
||||
/* flags */
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
}
|
||||
|
||||
static wmOperatorStatus rule_move_down_exec(bContext *C, wmOperator * /*op*/)
|
||||
{
|
||||
PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_settings", RNA_ParticleSettings);
|
||||
ParticleSettings *part = static_cast<ParticleSettings *>(ptr.data);
|
||||
BoidState *state;
|
||||
|
||||
if (!part || part->phystype != PART_PHYS_BOIDS) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
state = boid_get_current_state(part->boids);
|
||||
for (BoidRule &rule : state->rules) {
|
||||
if (rule.flag & BOIDRULE_CURRENT && rule.next) {
|
||||
BLI_remlink(&state->rules, &rule);
|
||||
BLI_insertlinkafter(&state->rules, rule.next, &rule);
|
||||
|
||||
DEG_id_tag_update(&part->id, ID_RECALC_GEOMETRY | ID_RECALC_PSYS_RESET);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
void BOID_OT_rule_move_down(wmOperatorType *ot)
|
||||
{
|
||||
ot->name = "Move Down Boid Rule";
|
||||
ot->description = "Move boid rule down in the list";
|
||||
ot->idname = "BOID_OT_rule_move_down";
|
||||
|
||||
ot->exec = rule_move_down_exec;
|
||||
|
||||
/* flags */
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
}
|
||||
|
||||
/************************ add/del boid state operators *********************/
|
||||
static wmOperatorStatus state_add_exec(bContext *C, wmOperator * /*op*/)
|
||||
{
|
||||
PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_settings", RNA_ParticleSettings);
|
||||
ParticleSettings *part = static_cast<ParticleSettings *>(ptr.data);
|
||||
BoidState *state;
|
||||
|
||||
if (!part || part->phystype != PART_PHYS_BOIDS) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
for (BoidState &state : part->boids->states) {
|
||||
state.flag &= ~BOIDSTATE_CURRENT;
|
||||
}
|
||||
|
||||
state = boid_new_state(part->boids);
|
||||
state->flag |= BOIDSTATE_CURRENT;
|
||||
|
||||
BLI_addtail(&part->boids->states, state);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
void BOID_OT_state_add(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name = "Add Boid State";
|
||||
ot->description = "Add a boid state to the particle system";
|
||||
ot->idname = "BOID_OT_state_add";
|
||||
|
||||
/* API callbacks. */
|
||||
ot->exec = state_add_exec;
|
||||
|
||||
/* flags */
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
}
|
||||
static wmOperatorStatus state_del_exec(bContext *C, wmOperator * /*op*/)
|
||||
{
|
||||
Main *bmain = CTX_data_main(C);
|
||||
PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_settings", RNA_ParticleSettings);
|
||||
ParticleSettings *part = static_cast<ParticleSettings *>(ptr.data);
|
||||
BoidState *state;
|
||||
|
||||
if (!part || part->phystype != PART_PHYS_BOIDS) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
for (BoidState &state : part->boids->states) {
|
||||
if (state.flag & BOIDSTATE_CURRENT) {
|
||||
BLI_remlink(&part->boids->states, &state);
|
||||
MEM_delete(&state);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* there must be at least one state */
|
||||
if (!part->boids->states.first) {
|
||||
state = boid_new_state(part->boids);
|
||||
BLI_addtail(&part->boids->states, state);
|
||||
}
|
||||
else {
|
||||
state = static_cast<BoidState *>(part->boids->states.first);
|
||||
}
|
||||
|
||||
state->flag |= BOIDSTATE_CURRENT;
|
||||
|
||||
DEG_relations_tag_update(bmain);
|
||||
DEG_id_tag_update(&part->id, ID_RECALC_GEOMETRY | ID_RECALC_PSYS_RESET);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
void BOID_OT_state_del(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name = "Remove Boid State";
|
||||
ot->idname = "BOID_OT_state_del";
|
||||
ot->description = "Delete current boid state";
|
||||
|
||||
/* API callbacks. */
|
||||
ot->exec = state_del_exec;
|
||||
|
||||
/* flags */
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
}
|
||||
|
||||
/************************ move up/down boid state operators *********************/
|
||||
static wmOperatorStatus state_move_up_exec(bContext *C, wmOperator * /*op*/)
|
||||
{
|
||||
PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_settings", RNA_ParticleSettings);
|
||||
ParticleSettings *part = static_cast<ParticleSettings *>(ptr.data);
|
||||
BoidSettings *boids;
|
||||
|
||||
if (!part || part->phystype != PART_PHYS_BOIDS) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
boids = part->boids;
|
||||
|
||||
for (BoidState &state : boids->states) {
|
||||
if (state.flag & BOIDSTATE_CURRENT && state.prev) {
|
||||
BLI_remlink(&boids->states, &state);
|
||||
BLI_insertlinkbefore(&boids->states, state.prev, &state);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
void BOID_OT_state_move_up(wmOperatorType *ot)
|
||||
{
|
||||
ot->name = "Move Up Boid State";
|
||||
ot->description = "Move boid state up in the list";
|
||||
ot->idname = "BOID_OT_state_move_up";
|
||||
|
||||
ot->exec = state_move_up_exec;
|
||||
|
||||
/* flags */
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
}
|
||||
|
||||
static wmOperatorStatus state_move_down_exec(bContext *C, wmOperator * /*op*/)
|
||||
{
|
||||
PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_settings", RNA_ParticleSettings);
|
||||
ParticleSettings *part = static_cast<ParticleSettings *>(ptr.data);
|
||||
BoidSettings *boids;
|
||||
|
||||
if (!part || part->phystype != PART_PHYS_BOIDS) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
boids = part->boids;
|
||||
|
||||
for (BoidState &state : boids->states) {
|
||||
if (state.flag & BOIDSTATE_CURRENT && state.next) {
|
||||
BLI_remlink(&boids->states, &state);
|
||||
BLI_insertlinkafter(&boids->states, state.next, &state);
|
||||
DEG_id_tag_update(&part->id, ID_RECALC_GEOMETRY | ID_RECALC_PSYS_RESET);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
void BOID_OT_state_move_down(wmOperatorType *ot)
|
||||
{
|
||||
ot->name = "Move Down Boid State";
|
||||
ot->description = "Move boid state down in the list";
|
||||
ot->idname = "BOID_OT_state_move_down";
|
||||
|
||||
ot->exec = state_move_down_exec;
|
||||
|
||||
/* flags */
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
}
|
||||
|
||||
} // namespace blender
|
||||
5746
blender-5.2.0/source/blender/editors/physics/particle_edit.cc
Normal file
5746
blender-5.2.0/source/blender/editors/physics/particle_edit.cc
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,308 @@
|
||||
/* SPDX-FileCopyrightText: 2007 by Janne Karhu. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup edphys
|
||||
*/
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "CLG_log.h"
|
||||
|
||||
#include "DNA_scene_types.h"
|
||||
#include "DNA_windowmanager_types.h"
|
||||
|
||||
#include "BLI_listbase.h"
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
#include "BKE_context.hh"
|
||||
#include "BKE_layer.hh"
|
||||
#include "BKE_particle.h"
|
||||
#include "BKE_pointcache.h"
|
||||
#include "BKE_undo_system.hh"
|
||||
|
||||
#include "DEG_depsgraph.hh"
|
||||
|
||||
#include "ED_object.hh"
|
||||
#include "ED_particle.hh"
|
||||
#include "ED_physics.hh"
|
||||
#include "ED_undo.hh"
|
||||
|
||||
#include "particle_edit_utildefines.h"
|
||||
|
||||
namespace blender {
|
||||
|
||||
/** Only needed this locally. */
|
||||
static CLG_LogRef LOG = {"undo.particle"};
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Undo Conversion
|
||||
* \{ */
|
||||
|
||||
static void undoptcache_from_editcache(PTCacheUndo *undo, PTCacheEdit *edit)
|
||||
{
|
||||
PTCacheEditPoint *point;
|
||||
|
||||
size_t mem_used_prev = MEM_get_memory_in_use();
|
||||
|
||||
undo->totpoint = edit->totpoint;
|
||||
|
||||
if (edit->psys) {
|
||||
ParticleData *pa;
|
||||
|
||||
pa = undo->particles = MEM_dupalloc(edit->psys->particles);
|
||||
|
||||
for (int i = 0; i < edit->totpoint; i++, pa++) {
|
||||
pa->hair = MEM_dupalloc(pa->hair);
|
||||
}
|
||||
|
||||
undo->psys_flag = edit->psys->flag;
|
||||
}
|
||||
else {
|
||||
PTCacheMem *pm;
|
||||
|
||||
BLI_duplicatelist(&undo->mem_cache, &edit->pid.cache->mem_cache);
|
||||
pm = static_cast<PTCacheMem *>(undo->mem_cache.first);
|
||||
|
||||
for (; pm; pm = pm->next) {
|
||||
for (int i = 0; i < BPHYS_TOT_DATA; i++) {
|
||||
pm->data[i] = MEM_dupalloc_void(pm->data[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
point = undo->points = MEM_dupalloc(edit->points);
|
||||
undo->totpoint = edit->totpoint;
|
||||
|
||||
for (int i = 0; i < edit->totpoint; i++, point++) {
|
||||
point->keys = MEM_dupalloc(point->keys);
|
||||
/* no need to update edit key->co & key->time pointers here */
|
||||
}
|
||||
|
||||
size_t mem_used_curr = MEM_get_memory_in_use();
|
||||
|
||||
undo->undo_size = mem_used_prev < mem_used_curr ? mem_used_curr - mem_used_prev :
|
||||
sizeof(PTCacheUndo);
|
||||
}
|
||||
|
||||
static void undoptcache_to_editcache(PTCacheUndo *undo, PTCacheEdit *edit)
|
||||
{
|
||||
ParticleSystem *psys = edit->psys;
|
||||
ParticleData *pa;
|
||||
HairKey *hkey;
|
||||
POINT_P;
|
||||
KEY_K;
|
||||
|
||||
LOOP_POINTS {
|
||||
if (psys && psys->particles[p].hair) {
|
||||
MEM_delete(psys->particles[p].hair);
|
||||
}
|
||||
|
||||
if (point->keys) {
|
||||
MEM_delete(point->keys);
|
||||
}
|
||||
}
|
||||
if (psys && psys->particles) {
|
||||
MEM_delete(psys->particles);
|
||||
}
|
||||
if (edit->points) {
|
||||
MEM_delete(edit->points);
|
||||
}
|
||||
MEM_SAFE_DELETE(edit->mirror_cache);
|
||||
|
||||
edit->points = MEM_dupalloc(undo->points);
|
||||
edit->totpoint = undo->totpoint;
|
||||
|
||||
LOOP_POINTS {
|
||||
point->keys = MEM_dupalloc(point->keys);
|
||||
}
|
||||
|
||||
if (psys) {
|
||||
psys->particles = MEM_dupalloc(undo->particles);
|
||||
|
||||
psys->totpart = undo->totpoint;
|
||||
|
||||
LOOP_POINTS {
|
||||
pa = psys->particles + p;
|
||||
hkey = pa->hair = MEM_dupalloc(pa->hair);
|
||||
|
||||
LOOP_KEYS {
|
||||
key->co = hkey->co;
|
||||
key->time = &hkey->time;
|
||||
hkey++;
|
||||
}
|
||||
}
|
||||
|
||||
psys->flag = undo->psys_flag;
|
||||
}
|
||||
else {
|
||||
PTCacheMem *pm;
|
||||
int i;
|
||||
|
||||
BKE_ptcache_free_mem(&edit->pid.cache->mem_cache);
|
||||
|
||||
BLI_duplicatelist(&edit->pid.cache->mem_cache, &undo->mem_cache);
|
||||
|
||||
pm = static_cast<PTCacheMem *>(edit->pid.cache->mem_cache.first);
|
||||
|
||||
for (; pm; pm = pm->next) {
|
||||
for (i = 0; i < BPHYS_TOT_DATA; i++) {
|
||||
pm->data[i] = MEM_dupalloc_void(pm->data[i]);
|
||||
}
|
||||
void *cur[BPHYS_TOT_DATA];
|
||||
BKE_ptcache_mem_pointers_init(pm, cur);
|
||||
|
||||
LOOP_POINTS {
|
||||
LOOP_KEYS {
|
||||
if (int(key->ftime) == int(pm->frame)) {
|
||||
key->co = static_cast<float *>(cur[BPHYS_DATA_LOCATION]);
|
||||
key->vel = static_cast<float *>(cur[BPHYS_DATA_VELOCITY]);
|
||||
key->rot = static_cast<float *>(cur[BPHYS_DATA_ROTATION]);
|
||||
key->time = &key->ftime;
|
||||
}
|
||||
}
|
||||
BKE_ptcache_mem_pointers_incr(cur);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void undoptcache_free_data(PTCacheUndo *undo)
|
||||
{
|
||||
PTCacheEditPoint *point;
|
||||
int i;
|
||||
|
||||
for (i = 0, point = undo->points; i < undo->totpoint; i++, point++) {
|
||||
if (undo->particles && (undo->particles + i)->hair) {
|
||||
MEM_delete((undo->particles + i)->hair);
|
||||
}
|
||||
if (point->keys) {
|
||||
MEM_delete(point->keys);
|
||||
}
|
||||
}
|
||||
if (undo->points) {
|
||||
MEM_delete(undo->points);
|
||||
}
|
||||
if (undo->particles) {
|
||||
MEM_delete(undo->particles);
|
||||
}
|
||||
BKE_ptcache_free_mem(&undo->mem_cache);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Implements ED Undo System
|
||||
* \{ */
|
||||
|
||||
struct ParticleUndoStep {
|
||||
UndoStep step;
|
||||
/** See #ED_undo_object_editmode_validate_scene_from_windows code comment for details. */
|
||||
UndoRefID_Scene scene_ref;
|
||||
UndoRefID_Object object_ref;
|
||||
PTCacheUndo data;
|
||||
};
|
||||
|
||||
static bool particle_undosys_poll(bContext *C)
|
||||
{
|
||||
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
|
||||
const Main *bmain = CTX_data_main(C);
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
ViewLayer *view_layer = CTX_data_view_layer(C);
|
||||
BKE_view_layer_synced_ensure(*bmain, scene, view_layer);
|
||||
Object *ob = BKE_view_layer_active_object_get(view_layer);
|
||||
PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
|
||||
|
||||
return (edit != nullptr);
|
||||
}
|
||||
|
||||
static bool particle_undosys_step_encode(bContext *C, Main *bmain, UndoStep *us_p)
|
||||
{
|
||||
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
|
||||
ParticleUndoStep *us = reinterpret_cast<ParticleUndoStep *>(us_p);
|
||||
ViewLayer *view_layer = CTX_data_view_layer(C);
|
||||
us->scene_ref.ptr = CTX_data_scene(C);
|
||||
BKE_view_layer_synced_ensure(*bmain, us->scene_ref.ptr, view_layer);
|
||||
us->object_ref.ptr = BKE_view_layer_active_object_get(view_layer);
|
||||
PTCacheEdit *edit = PE_get_current(depsgraph, us->scene_ref.ptr, us->object_ref.ptr);
|
||||
undoptcache_from_editcache(&us->data, edit);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void particle_undosys_step_decode(
|
||||
bContext *C, Main *bmain, UndoStep *us_p, const eUndoStepDir /*dir*/, bool /*is_final*/)
|
||||
{
|
||||
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
|
||||
|
||||
ParticleUndoStep *us = reinterpret_cast<ParticleUndoStep *>(us_p);
|
||||
Scene *scene = us->scene_ref.ptr;
|
||||
ViewLayer *view_layer = CTX_data_view_layer(C);
|
||||
|
||||
/* Only to correct the `view_layer` which might not match the scene
|
||||
* (in the case of undoing with multiple windows). */
|
||||
ED_undo_object_editmode_validate_scene_from_windows(
|
||||
CTX_wm_manager(C), us->scene_ref.ptr, &scene, &view_layer);
|
||||
|
||||
Object *ob = us->object_ref.ptr;
|
||||
ED_object_particle_edit_mode_enter_ex(depsgraph, scene, ob);
|
||||
|
||||
PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
|
||||
|
||||
/* While this shouldn't happen, entering particle edit-mode uses a more complex
|
||||
* setup compared to most other modes which we can't ensure succeeds. */
|
||||
if (UNLIKELY(edit == nullptr)) {
|
||||
BLI_assert(0);
|
||||
return;
|
||||
}
|
||||
|
||||
undoptcache_to_editcache(&us->data, edit);
|
||||
ParticleEditSettings *pset = &scene->toolsettings->particle;
|
||||
if ((pset->flag & PE_DRAW_PART) != 0) {
|
||||
psys_free_path_cache(nullptr, edit);
|
||||
BKE_particle_batch_cache_dirty_tag(edit->psys, BKE_PARTICLE_BATCH_DIRTY_ALL);
|
||||
}
|
||||
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
|
||||
|
||||
ED_undo_object_set_active_or_warn(*bmain, scene, view_layer, ob, us_p->name, &LOG);
|
||||
|
||||
/* Check after setting active (unless undoing into another scene). */
|
||||
BLI_assert(particle_undosys_poll(C) || (scene != CTX_data_scene(C)));
|
||||
}
|
||||
|
||||
static void particle_undosys_step_free(UndoStep *us_p)
|
||||
{
|
||||
ParticleUndoStep *us = reinterpret_cast<ParticleUndoStep *>(us_p);
|
||||
undoptcache_free_data(&us->data);
|
||||
}
|
||||
|
||||
static void particle_undosys_foreach_ID_ref(UndoStep *us_p,
|
||||
UndoTypeForEachIDRefFn foreach_ID_ref_fn,
|
||||
void *user_data)
|
||||
{
|
||||
ParticleUndoStep *us = reinterpret_cast<ParticleUndoStep *>(us_p);
|
||||
foreach_ID_ref_fn(user_data, (reinterpret_cast<UndoRefID *>(&us->scene_ref)));
|
||||
foreach_ID_ref_fn(user_data, (reinterpret_cast<UndoRefID *>(&us->object_ref)));
|
||||
}
|
||||
|
||||
void ED_particle_undosys_type(UndoType *ut)
|
||||
{
|
||||
ut->name = "Edit Particle";
|
||||
ut->poll = particle_undosys_poll;
|
||||
ut->step_encode = particle_undosys_step_encode;
|
||||
ut->step_decode = particle_undosys_step_decode;
|
||||
ut->step_free = particle_undosys_step_free;
|
||||
|
||||
ut->step_foreach_ID_ref = particle_undosys_foreach_ID_ref;
|
||||
|
||||
ut->flags = UNDOTYPE_FLAG_NEED_CONTEXT_FOR_ENCODE;
|
||||
|
||||
ut->step_size = sizeof(ParticleUndoStep);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
} // namespace blender
|
||||
@@ -0,0 +1,44 @@
|
||||
/* SPDX-FileCopyrightText: 2007 by Janne Karhu. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup edphys
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#define KEY_K \
|
||||
PTCacheEditKey *key; \
|
||||
int k
|
||||
#define POINT_P \
|
||||
[[maybe_unused]] PTCacheEditPoint *point; \
|
||||
int p
|
||||
#define LOOP_POINTS for (p = 0, point = edit->points; p < edit->totpoint; p++, point++)
|
||||
#define LOOP_VISIBLE_POINTS \
|
||||
for (p = 0, point = edit->points; p < edit->totpoint; p++, point++) \
|
||||
if (!(point->flag & PEP_HIDE))
|
||||
#define LOOP_SELECTED_POINTS \
|
||||
for (p = 0, point = edit->points; p < edit->totpoint; p++, point++) \
|
||||
if (point_is_selected(point))
|
||||
#define LOOP_UNSELECTED_POINTS \
|
||||
for (p = 0, point = edit->points; p < edit->totpoint; p++, point++) \
|
||||
if (!point_is_selected(point))
|
||||
#define LOOP_EDITED_POINTS \
|
||||
for (p = 0, point = edit->points; p < edit->totpoint; p++, point++) \
|
||||
if (point->flag & PEP_EDIT_RECALC)
|
||||
#define LOOP_TAGGED_POINTS \
|
||||
for (p = 0, point = edit->points; p < edit->totpoint; p++, point++) \
|
||||
if (point->flag & PEP_TAG)
|
||||
#define LOOP_KEYS for (k = 0, key = point->keys; k < point->totkey; k++, key++)
|
||||
#define LOOP_VISIBLE_KEYS \
|
||||
for (k = 0, key = point->keys; k < point->totkey; k++, key++) \
|
||||
if (!(key->flag & PEK_HIDE))
|
||||
#define LOOP_SELECTED_KEYS \
|
||||
for (k = 0, key = point->keys; k < point->totkey; k++, key++) \
|
||||
if ((key->flag & PEK_SELECT) && !(key->flag & PEK_HIDE))
|
||||
#define LOOP_TAGGED_KEYS \
|
||||
for (k = 0, key = point->keys; k < point->totkey; k++, key++) \
|
||||
if (key->flag & PEK_TAG)
|
||||
|
||||
#define KEY_WCO ((key->flag & PEK_USE_WCO) ? key->world_co : key->co)
|
||||
1444
blender-5.2.0/source/blender/editors/physics/particle_object.cc
Normal file
1444
blender-5.2.0/source/blender/editors/physics/particle_object.cc
Normal file
File diff suppressed because it is too large
Load Diff
867
blender-5.2.0/source/blender/editors/physics/physics_fluid.cc
Normal file
867
blender-5.2.0/source/blender/editors/physics/physics_fluid.cc
Normal file
@@ -0,0 +1,867 @@
|
||||
/* SPDX-FileCopyrightText: Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup edphys
|
||||
*/
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
/* types */
|
||||
#include "DNA_object_types.h"
|
||||
|
||||
#include "BLI_fileops.h"
|
||||
#include "BLI_path_utils.hh"
|
||||
#include "BLI_string.h"
|
||||
#include "BLI_string_utf8.h"
|
||||
#include "BLI_time.h"
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
#include "BLT_translation.hh"
|
||||
|
||||
#include "BKE_context.hh"
|
||||
#include "BKE_fluid.h"
|
||||
#include "BKE_global.hh"
|
||||
#include "BKE_main.hh"
|
||||
#include "BKE_modifier.hh"
|
||||
#include "BKE_report.hh"
|
||||
#include "BKE_screen.hh"
|
||||
|
||||
#include "DEG_depsgraph.hh"
|
||||
|
||||
#include "ED_object.hh"
|
||||
#include "ED_screen.hh"
|
||||
|
||||
#include "WM_api.hh"
|
||||
#include "WM_types.hh"
|
||||
|
||||
#include "physics_intern.hh" /* own include */
|
||||
|
||||
#include "DNA_fluid_types.h"
|
||||
#include "DNA_scene_types.h"
|
||||
|
||||
namespace blender {
|
||||
|
||||
#define FLUID_JOB_BAKE_ALL "FLUID_OT_bake_all"
|
||||
#define FLUID_JOB_BAKE_DATA "FLUID_OT_bake_data"
|
||||
#define FLUID_JOB_BAKE_NOISE "FLUID_OT_bake_noise"
|
||||
#define FLUID_JOB_BAKE_MESH "FLUID_OT_bake_mesh"
|
||||
#define FLUID_JOB_BAKE_PARTICLES "FLUID_OT_bake_particles"
|
||||
#define FLUID_JOB_BAKE_GUIDES "FLUID_OT_bake_guides"
|
||||
#define FLUID_JOB_FREE_ALL "FLUID_OT_free_all"
|
||||
#define FLUID_JOB_FREE_DATA "FLUID_OT_free_data"
|
||||
#define FLUID_JOB_FREE_NOISE "FLUID_OT_free_noise"
|
||||
#define FLUID_JOB_FREE_MESH "FLUID_OT_free_mesh"
|
||||
#define FLUID_JOB_FREE_PARTICLES "FLUID_OT_free_particles"
|
||||
#define FLUID_JOB_FREE_GUIDES "FLUID_OT_free_guides"
|
||||
#define FLUID_JOB_BAKE_PAUSE "FLUID_OT_pause_bake"
|
||||
|
||||
struct FluidJob {
|
||||
/* from wmJob */
|
||||
void *owner;
|
||||
bool *stop, *do_update;
|
||||
float *progress;
|
||||
const char *type;
|
||||
const char *name;
|
||||
|
||||
Main *bmain;
|
||||
Scene *scene;
|
||||
Depsgraph *depsgraph;
|
||||
Object *ob;
|
||||
|
||||
FluidModifierData *fmd;
|
||||
|
||||
int success;
|
||||
double start;
|
||||
|
||||
int *pause_frame;
|
||||
};
|
||||
|
||||
static inline bool fluid_is_bake_all(FluidJob *job)
|
||||
{
|
||||
return STREQ(job->type, FLUID_JOB_BAKE_ALL);
|
||||
}
|
||||
static inline bool fluid_is_bake_data(FluidJob *job)
|
||||
{
|
||||
return STREQ(job->type, FLUID_JOB_BAKE_DATA);
|
||||
}
|
||||
static inline bool fluid_is_bake_noise(FluidJob *job)
|
||||
{
|
||||
return STREQ(job->type, FLUID_JOB_BAKE_NOISE);
|
||||
}
|
||||
static inline bool fluid_is_bake_mesh(FluidJob *job)
|
||||
{
|
||||
return STREQ(job->type, FLUID_JOB_BAKE_MESH);
|
||||
}
|
||||
static inline bool fluid_is_bake_particle(FluidJob *job)
|
||||
{
|
||||
return STREQ(job->type, FLUID_JOB_BAKE_PARTICLES);
|
||||
}
|
||||
static inline bool fluid_is_bake_guiding(FluidJob *job)
|
||||
{
|
||||
return STREQ(job->type, FLUID_JOB_BAKE_GUIDES);
|
||||
}
|
||||
static inline bool fluid_is_free_all(FluidJob *job)
|
||||
{
|
||||
return STREQ(job->type, FLUID_JOB_FREE_ALL);
|
||||
}
|
||||
static inline bool fluid_is_free_data(FluidJob *job)
|
||||
{
|
||||
return STREQ(job->type, FLUID_JOB_FREE_DATA);
|
||||
}
|
||||
static inline bool fluid_is_free_noise(FluidJob *job)
|
||||
{
|
||||
return STREQ(job->type, FLUID_JOB_FREE_NOISE);
|
||||
}
|
||||
static inline bool fluid_is_free_mesh(FluidJob *job)
|
||||
{
|
||||
return STREQ(job->type, FLUID_JOB_FREE_MESH);
|
||||
}
|
||||
static inline bool fluid_is_free_particles(FluidJob *job)
|
||||
{
|
||||
return STREQ(job->type, FLUID_JOB_FREE_PARTICLES);
|
||||
}
|
||||
static inline bool fluid_is_free_guiding(FluidJob *job)
|
||||
{
|
||||
return STREQ(job->type, FLUID_JOB_FREE_GUIDES);
|
||||
}
|
||||
|
||||
static bool fluid_job_init(
|
||||
bContext *C, FluidJob *job, wmOperator *op, char *error_msg, int error_size)
|
||||
{
|
||||
FluidModifierData *fmd = nullptr;
|
||||
FluidDomainSettings *fds;
|
||||
Object *ob = ed::object::context_active_object(C);
|
||||
|
||||
fmd = reinterpret_cast<FluidModifierData *>(BKE_modifiers_findby_type(ob, eModifierType_Fluid));
|
||||
if (!fmd) {
|
||||
BLI_strncpy_utf8(error_msg, N_("No Fluid modifier found"), error_size);
|
||||
return false;
|
||||
}
|
||||
fds = fmd->domain;
|
||||
if (!fds) {
|
||||
BLI_strncpy_utf8(error_msg, N_("Invalid domain"), error_size);
|
||||
return false;
|
||||
}
|
||||
if (fds->cache_flag & (FLUID_DOMAIN_BAKING_DATA | FLUID_DOMAIN_BAKING_NOISE |
|
||||
FLUID_DOMAIN_BAKING_MESH | FLUID_DOMAIN_BAKING_PARTICLES))
|
||||
{
|
||||
BKE_report(op->reports, RPT_ERROR, "Pending bake jobs found");
|
||||
return false;
|
||||
}
|
||||
|
||||
job->bmain = CTX_data_main(C);
|
||||
job->scene = CTX_data_scene(C);
|
||||
job->depsgraph = CTX_data_depsgraph_pointer(C);
|
||||
job->ob = ob;
|
||||
job->fmd = fmd;
|
||||
job->type = op->type->idname;
|
||||
job->name = op->type->name;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool fluid_validate_paths(FluidJob *job, ReportList *reports)
|
||||
{
|
||||
FluidDomainSettings *fds = job->fmd->domain;
|
||||
char temp_dir[FILE_MAX];
|
||||
temp_dir[0] = '\0';
|
||||
bool is_relative = false;
|
||||
|
||||
const char *relbase = BKE_modifier_path_relbase(job->bmain, job->ob);
|
||||
|
||||
/* We do not accept empty paths, they can end in random places silently, see #51176. */
|
||||
if (fds->cache_directory[0] == '\0') {
|
||||
char cache_name[64];
|
||||
BKE_fluid_cache_new_name_for_current_session(sizeof(cache_name), cache_name);
|
||||
BKE_modifier_path_init(fds->cache_directory, sizeof(fds->cache_directory), cache_name);
|
||||
BKE_reportf(reports,
|
||||
RPT_WARNING,
|
||||
"Fluid: Empty cache path, reset to default '%s'",
|
||||
fds->cache_directory);
|
||||
}
|
||||
|
||||
BLI_strncpy(temp_dir, fds->cache_directory, FILE_MAXDIR);
|
||||
is_relative = BLI_path_abs(temp_dir, relbase);
|
||||
|
||||
/* Ensure whole path exists */
|
||||
const bool dir_exists = BLI_dir_create_recursive(temp_dir);
|
||||
|
||||
/* We change path to some presumably valid default value, but do not allow bake process to
|
||||
* continue, this gives user chance to set manually another path. */
|
||||
if (!dir_exists) {
|
||||
char cache_name[64];
|
||||
BKE_fluid_cache_new_name_for_current_session(sizeof(cache_name), cache_name);
|
||||
BKE_modifier_path_init(fds->cache_directory, sizeof(fds->cache_directory), cache_name);
|
||||
|
||||
BKE_reportf(reports,
|
||||
RPT_ERROR,
|
||||
"Fluid: Could not create cache directory '%s', reset to default '%s'",
|
||||
temp_dir,
|
||||
fds->cache_directory);
|
||||
|
||||
/* Ensure whole path exists and is writable. */
|
||||
if (!BLI_dir_create_recursive(temp_dir)) {
|
||||
BKE_reportf(reports,
|
||||
RPT_ERROR,
|
||||
"Fluid: Could not use default cache directory '%s', "
|
||||
"please define a valid cache path manually",
|
||||
temp_dir);
|
||||
return false;
|
||||
}
|
||||
/* Copy final dir back into domain settings */
|
||||
BLI_strncpy(fds->cache_directory, temp_dir, FILE_MAXDIR);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Change path back to is original state (ie relative or absolute). */
|
||||
if (is_relative) {
|
||||
BLI_path_rel(temp_dir, relbase);
|
||||
}
|
||||
|
||||
/* Copy final dir back into domain settings */
|
||||
BLI_strncpy(fds->cache_directory, temp_dir, FILE_MAXDIR);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void fluid_job_free(void *customdata)
|
||||
{
|
||||
FluidJob *job = static_cast<FluidJob *>(customdata);
|
||||
MEM_delete(job);
|
||||
}
|
||||
|
||||
static FluidJob *fluid_job_create(bContext *C, wmOperator *op)
|
||||
{
|
||||
FluidJob *job = MEM_new_uninitialized<FluidJob>("FluidJob");
|
||||
char error_msg[256] = "\0";
|
||||
|
||||
if (!fluid_job_init(C, job, op, error_msg, sizeof(error_msg))) {
|
||||
if (error_msg[0]) {
|
||||
BKE_report(op->reports, RPT_ERROR, error_msg);
|
||||
}
|
||||
fluid_job_free(job);
|
||||
return nullptr;
|
||||
}
|
||||
if (!fluid_validate_paths(job, op->reports)) {
|
||||
fluid_job_free(job);
|
||||
return nullptr;
|
||||
}
|
||||
WM_report_banners_cancel(job->bmain);
|
||||
return job;
|
||||
}
|
||||
|
||||
static void fluid_bake_sequence(FluidJob *job)
|
||||
{
|
||||
FluidDomainSettings *fds = job->fmd->domain;
|
||||
Scene *scene = job->scene;
|
||||
int frame = 1, orig_frame;
|
||||
int frames;
|
||||
int *pause_frame = nullptr;
|
||||
bool is_first_frame;
|
||||
|
||||
frames = fds->cache_frame_end - fds->cache_frame_start + 1;
|
||||
|
||||
if (frames <= 0) {
|
||||
STRNCPY_UTF8(fds->error, N_("No frames to bake"));
|
||||
return;
|
||||
}
|
||||
|
||||
/* Show progress bar. */
|
||||
if (job->do_update) {
|
||||
*(job->do_update) = true;
|
||||
}
|
||||
|
||||
/* Get current pause frame (pointer) - depending on bake type. */
|
||||
pause_frame = job->pause_frame;
|
||||
|
||||
/* Set frame to start point (depending on current pause frame value). */
|
||||
is_first_frame = ((*pause_frame) == 0);
|
||||
frame = is_first_frame ? fds->cache_frame_start : (*pause_frame);
|
||||
|
||||
/* Save orig frame and update scene frame. */
|
||||
orig_frame = scene->r.cfra;
|
||||
scene->r.cfra = frame;
|
||||
|
||||
/* Loop through selected frames. */
|
||||
for (; frame <= fds->cache_frame_end; frame++) {
|
||||
const float progress = (frame - fds->cache_frame_start) / float(frames);
|
||||
|
||||
/* Keep track of pause frame - needed to init future loop. */
|
||||
(*pause_frame) = frame;
|
||||
|
||||
/* If user requested stop, quit baking. */
|
||||
if (G.is_break) {
|
||||
job->success = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Update progress bar. */
|
||||
if (job->do_update) {
|
||||
*(job->do_update) = true;
|
||||
}
|
||||
if (job->progress) {
|
||||
*(job->progress) = progress;
|
||||
}
|
||||
|
||||
scene->r.cfra = frame;
|
||||
|
||||
/* Update animation system. */
|
||||
ED_update_for_newframe(job->bmain, job->depsgraph);
|
||||
|
||||
/* If user requested stop, quit baking. */
|
||||
if (G.is_break) {
|
||||
job->success = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Restore frame position that we were on before bake. */
|
||||
scene->r.cfra = orig_frame;
|
||||
}
|
||||
|
||||
static void fluid_bake_endjob(void *customdata)
|
||||
{
|
||||
FluidJob *job = static_cast<FluidJob *>(customdata);
|
||||
FluidDomainSettings *fds = job->fmd->domain;
|
||||
|
||||
if (fluid_is_bake_noise(job) || fluid_is_bake_all(job)) {
|
||||
fds->cache_flag &= ~FLUID_DOMAIN_BAKING_NOISE;
|
||||
fds->cache_flag |= FLUID_DOMAIN_BAKED_NOISE;
|
||||
fds->cache_flag &= ~FLUID_DOMAIN_OUTDATED_NOISE;
|
||||
}
|
||||
if (fluid_is_bake_mesh(job) || fluid_is_bake_all(job)) {
|
||||
fds->cache_flag &= ~FLUID_DOMAIN_BAKING_MESH;
|
||||
fds->cache_flag |= FLUID_DOMAIN_BAKED_MESH;
|
||||
fds->cache_flag &= ~FLUID_DOMAIN_OUTDATED_MESH;
|
||||
}
|
||||
if (fluid_is_bake_particle(job) || fluid_is_bake_all(job)) {
|
||||
fds->cache_flag &= ~FLUID_DOMAIN_BAKING_PARTICLES;
|
||||
fds->cache_flag |= FLUID_DOMAIN_BAKED_PARTICLES;
|
||||
fds->cache_flag &= ~FLUID_DOMAIN_OUTDATED_PARTICLES;
|
||||
}
|
||||
if (fluid_is_bake_guiding(job) || fluid_is_bake_all(job)) {
|
||||
fds->cache_flag &= ~FLUID_DOMAIN_BAKING_GUIDE;
|
||||
fds->cache_flag |= FLUID_DOMAIN_BAKED_GUIDE;
|
||||
fds->cache_flag &= ~FLUID_DOMAIN_OUTDATED_GUIDE;
|
||||
}
|
||||
if (fluid_is_bake_data(job) || fluid_is_bake_all(job)) {
|
||||
fds->cache_flag &= ~FLUID_DOMAIN_BAKING_DATA;
|
||||
fds->cache_flag |= FLUID_DOMAIN_BAKED_DATA;
|
||||
fds->cache_flag &= ~FLUID_DOMAIN_OUTDATED_DATA;
|
||||
}
|
||||
DEG_id_tag_update(&job->ob->id, ID_RECALC_GEOMETRY);
|
||||
|
||||
G.is_rendering = false;
|
||||
WM_locked_interface_set(static_cast<wmWindowManager *>(G_MAIN->wm.first), false);
|
||||
|
||||
/* Bake was successful:
|
||||
* Report for ended bake and how long it took. */
|
||||
if (job->success) {
|
||||
/* Show bake info. */
|
||||
WM_global_reportf(RPT_INFO,
|
||||
"Fluid: %s complete (%.2fs)",
|
||||
CTX_RPT_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, job->name),
|
||||
BLI_time_now_seconds() - job->start);
|
||||
}
|
||||
else {
|
||||
if (fds->error[0] != '\0') {
|
||||
WM_global_reportf(RPT_ERROR,
|
||||
"Fluid: %s failed at frame %d: %s",
|
||||
CTX_RPT_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, job->name),
|
||||
*job->pause_frame,
|
||||
fds->error);
|
||||
}
|
||||
else { /* User canceled the bake. */
|
||||
WM_global_reportf(RPT_WARNING,
|
||||
"Fluid: %s canceled at frame %d!",
|
||||
CTX_RPT_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, job->name),
|
||||
*job->pause_frame);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void fluid_bake_startjob(void *customdata, wmJobWorkerStatus *worker_status)
|
||||
{
|
||||
FluidJob *job = static_cast<FluidJob *>(customdata);
|
||||
FluidDomainSettings *fds = job->fmd->domain;
|
||||
|
||||
char temp_dir[FILE_MAX];
|
||||
const char *relbase = BKE_modifier_path_relbase_from_global(job->ob);
|
||||
|
||||
job->stop = &worker_status->stop;
|
||||
job->do_update = &worker_status->do_update;
|
||||
job->progress = &worker_status->progress;
|
||||
job->start = BLI_time_now_seconds();
|
||||
job->success = 1;
|
||||
|
||||
G.is_break = false;
|
||||
G.is_rendering = true;
|
||||
BKE_spacedata_draw_locks(REGION_DRAW_LOCK_BAKING);
|
||||
|
||||
if (fluid_is_bake_noise(job) || fluid_is_bake_all(job)) {
|
||||
BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_NOISE);
|
||||
BLI_path_abs(temp_dir, relbase);
|
||||
BLI_dir_create_recursive(temp_dir); /* Create 'noise' subdir if it does not exist already */
|
||||
fds->cache_flag &= ~(FLUID_DOMAIN_BAKED_NOISE | FLUID_DOMAIN_OUTDATED_NOISE);
|
||||
fds->cache_flag |= FLUID_DOMAIN_BAKING_NOISE;
|
||||
job->pause_frame = &fds->cache_frame_pause_noise;
|
||||
}
|
||||
if (fluid_is_bake_mesh(job) || fluid_is_bake_all(job)) {
|
||||
BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_MESH);
|
||||
BLI_path_abs(temp_dir, relbase);
|
||||
BLI_dir_create_recursive(temp_dir); /* Create 'mesh' subdir if it does not exist already */
|
||||
fds->cache_flag &= ~(FLUID_DOMAIN_BAKED_MESH | FLUID_DOMAIN_OUTDATED_MESH);
|
||||
fds->cache_flag |= FLUID_DOMAIN_BAKING_MESH;
|
||||
job->pause_frame = &fds->cache_frame_pause_mesh;
|
||||
}
|
||||
if (fluid_is_bake_particle(job) || fluid_is_bake_all(job)) {
|
||||
BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_PARTICLES);
|
||||
BLI_path_abs(temp_dir, relbase);
|
||||
|
||||
/* Create 'particles' subdir if it does not exist already */
|
||||
BLI_dir_create_recursive(temp_dir);
|
||||
|
||||
fds->cache_flag &= ~(FLUID_DOMAIN_BAKED_PARTICLES | FLUID_DOMAIN_OUTDATED_PARTICLES);
|
||||
fds->cache_flag |= FLUID_DOMAIN_BAKING_PARTICLES;
|
||||
job->pause_frame = &fds->cache_frame_pause_particles;
|
||||
}
|
||||
if (fluid_is_bake_guiding(job) || fluid_is_bake_all(job)) {
|
||||
BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_GUIDE);
|
||||
BLI_path_abs(temp_dir, relbase);
|
||||
BLI_dir_create_recursive(temp_dir); /* Create 'guiding' subdir if it does not exist already */
|
||||
fds->cache_flag &= ~(FLUID_DOMAIN_BAKED_GUIDE | FLUID_DOMAIN_OUTDATED_GUIDE);
|
||||
fds->cache_flag |= FLUID_DOMAIN_BAKING_GUIDE;
|
||||
job->pause_frame = &fds->cache_frame_pause_guide;
|
||||
}
|
||||
if (fluid_is_bake_data(job) || fluid_is_bake_all(job)) {
|
||||
BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_CONFIG);
|
||||
BLI_path_abs(temp_dir, relbase);
|
||||
BLI_dir_create_recursive(temp_dir); /* Create 'config' subdir if it does not exist already */
|
||||
|
||||
BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_DATA);
|
||||
BLI_path_abs(temp_dir, relbase);
|
||||
BLI_dir_create_recursive(temp_dir); /* Create 'data' subdir if it does not exist already */
|
||||
fds->cache_flag &= ~(FLUID_DOMAIN_BAKED_DATA | FLUID_DOMAIN_OUTDATED_DATA);
|
||||
fds->cache_flag |= FLUID_DOMAIN_BAKING_DATA;
|
||||
job->pause_frame = &fds->cache_frame_pause_data;
|
||||
|
||||
if (fds->flags & FLUID_DOMAIN_EXPORT_MANTA_SCRIPT) {
|
||||
BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_SCRIPT);
|
||||
BLI_path_abs(temp_dir, relbase);
|
||||
BLI_dir_create_recursive(temp_dir); /* Create 'script' subdir if it does not exist already */
|
||||
}
|
||||
}
|
||||
DEG_id_tag_update(&job->ob->id, ID_RECALC_GEOMETRY);
|
||||
|
||||
fluid_bake_sequence(job);
|
||||
|
||||
worker_status->do_update = true;
|
||||
worker_status->stop = false;
|
||||
}
|
||||
|
||||
static void fluid_free_endjob(void *customdata)
|
||||
{
|
||||
FluidJob *job = static_cast<FluidJob *>(customdata);
|
||||
FluidDomainSettings *fds = job->fmd->domain;
|
||||
|
||||
G.is_rendering = false;
|
||||
WM_locked_interface_set(static_cast<wmWindowManager *>(G_MAIN->wm.first), false);
|
||||
|
||||
/* Reflect the now empty cache in the viewport too. */
|
||||
DEG_id_tag_update(&job->ob->id, ID_RECALC_GEOMETRY);
|
||||
|
||||
/* Free was successful:
|
||||
* Report for ended free job and how long it took */
|
||||
if (job->success) {
|
||||
/* Show free job info */
|
||||
WM_global_reportf(RPT_INFO,
|
||||
"Fluid: %s complete (%.2fs)",
|
||||
CTX_RPT_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, job->name),
|
||||
BLI_time_now_seconds() - job->start);
|
||||
}
|
||||
else {
|
||||
if (fds->error[0] != '\0') {
|
||||
WM_global_reportf(RPT_ERROR,
|
||||
"Fluid: %s failed at frame %d: %s",
|
||||
CTX_RPT_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, job->name),
|
||||
*job->pause_frame,
|
||||
fds->error);
|
||||
}
|
||||
else { /* User canceled the free job */
|
||||
WM_global_reportf(RPT_WARNING,
|
||||
"Fluid: %s canceled at frame %d!",
|
||||
CTX_RPT_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, job->name),
|
||||
*job->pause_frame);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void fluid_free_startjob(void *customdata, wmJobWorkerStatus *worker_status)
|
||||
{
|
||||
FluidJob *job = static_cast<FluidJob *>(customdata);
|
||||
FluidDomainSettings *fds = job->fmd->domain;
|
||||
|
||||
job->stop = &worker_status->stop;
|
||||
job->do_update = &worker_status->do_update;
|
||||
job->progress = &worker_status->progress;
|
||||
job->start = BLI_time_now_seconds();
|
||||
job->success = 1;
|
||||
|
||||
G.is_break = false;
|
||||
G.is_rendering = true;
|
||||
BKE_spacedata_draw_locks(REGION_DRAW_LOCK_BAKING);
|
||||
|
||||
int cache_map = 0;
|
||||
|
||||
if (fluid_is_free_data(job) || fluid_is_free_all(job)) {
|
||||
cache_map |= (FLUID_DOMAIN_OUTDATED_DATA | FLUID_DOMAIN_OUTDATED_NOISE |
|
||||
FLUID_DOMAIN_OUTDATED_MESH | FLUID_DOMAIN_OUTDATED_PARTICLES);
|
||||
}
|
||||
if (fluid_is_free_noise(job) || fluid_is_free_all(job)) {
|
||||
cache_map |= FLUID_DOMAIN_OUTDATED_NOISE;
|
||||
}
|
||||
if (fluid_is_free_mesh(job) || fluid_is_free_all(job)) {
|
||||
cache_map |= FLUID_DOMAIN_OUTDATED_MESH;
|
||||
}
|
||||
if (fluid_is_free_particles(job) || fluid_is_free_all(job)) {
|
||||
cache_map |= FLUID_DOMAIN_OUTDATED_PARTICLES;
|
||||
}
|
||||
if (fluid_is_free_guiding(job) || fluid_is_free_all(job)) {
|
||||
cache_map |= (FLUID_DOMAIN_OUTDATED_DATA | FLUID_DOMAIN_OUTDATED_NOISE |
|
||||
FLUID_DOMAIN_OUTDATED_MESH | FLUID_DOMAIN_OUTDATED_PARTICLES |
|
||||
FLUID_DOMAIN_OUTDATED_GUIDE);
|
||||
}
|
||||
#ifdef WITH_FLUID
|
||||
BKE_fluid_cache_free(fds, job->ob, cache_map);
|
||||
#else
|
||||
UNUSED_VARS(fds);
|
||||
UNUSED_VARS(cache_map);
|
||||
#endif
|
||||
|
||||
worker_status->do_update = true;
|
||||
worker_status->stop = false;
|
||||
|
||||
/* Update scene so that viewport shows freed up scene */
|
||||
ED_update_for_newframe(job->bmain, job->depsgraph);
|
||||
}
|
||||
|
||||
/***************************** Operators ******************************/
|
||||
|
||||
static wmOperatorStatus fluid_bake_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
FluidJob *job = fluid_job_create(C, op);
|
||||
if (job == nullptr) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
wmJobWorkerStatus worker_status = {};
|
||||
fluid_bake_startjob(job, &worker_status);
|
||||
fluid_bake_endjob(job);
|
||||
fluid_job_free(job);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
static wmOperatorStatus fluid_bake_invoke(bContext *C, wmOperator *op, const wmEvent * /*_event*/)
|
||||
{
|
||||
FluidJob *job = fluid_job_create(C, op);
|
||||
if (job == nullptr) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C),
|
||||
CTX_wm_window(C),
|
||||
CTX_data_scene(C),
|
||||
"Baking fluid...",
|
||||
WM_JOB_PROGRESS,
|
||||
WM_JOB_TYPE_OBJECT_SIM_FLUID);
|
||||
|
||||
WM_jobs_customdata_set(wm_job, job, fluid_job_free);
|
||||
WM_jobs_timer(wm_job, 0.01, NC_OBJECT | ND_MODIFIER, NC_OBJECT | ND_MODIFIER);
|
||||
WM_jobs_callbacks(wm_job, fluid_bake_startjob, nullptr, nullptr, fluid_bake_endjob);
|
||||
|
||||
WM_locked_interface_set_with_flags(CTX_wm_manager(C), REGION_DRAW_LOCK_BAKING);
|
||||
|
||||
WM_jobs_start(CTX_wm_manager(C), wm_job);
|
||||
WM_event_add_modal_handler(C, op);
|
||||
|
||||
return OPERATOR_RUNNING_MODAL;
|
||||
}
|
||||
|
||||
static wmOperatorStatus fluid_bake_modal(bContext *C, wmOperator * /*op*/, const wmEvent *event)
|
||||
{
|
||||
/* No running blender, remove handler and pass through. */
|
||||
if (0 == WM_jobs_test(CTX_wm_manager(C), CTX_data_scene(C), WM_JOB_TYPE_OBJECT_SIM_FLUID)) {
|
||||
return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH;
|
||||
}
|
||||
|
||||
switch (event->type) {
|
||||
case EVT_ESCKEY:
|
||||
return OPERATOR_RUNNING_MODAL;
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return OPERATOR_PASS_THROUGH;
|
||||
}
|
||||
|
||||
static wmOperatorStatus fluid_free_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
FluidJob *job = fluid_job_create(C, op);
|
||||
if (job == nullptr) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
wmJobWorkerStatus worker_status = {};
|
||||
fluid_free_startjob(job, &worker_status);
|
||||
fluid_free_endjob(job);
|
||||
fluid_job_free(job);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
static wmOperatorStatus fluid_free_invoke(bContext *C, wmOperator *op, const wmEvent * /*_event*/)
|
||||
{
|
||||
FluidJob *job = fluid_job_create(C, op);
|
||||
if (job == nullptr) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C),
|
||||
CTX_wm_window(C),
|
||||
CTX_data_scene(C),
|
||||
"Freeing fluid...",
|
||||
WM_JOB_PROGRESS,
|
||||
WM_JOB_TYPE_OBJECT_SIM_FLUID);
|
||||
|
||||
WM_jobs_customdata_set(wm_job, job, fluid_job_free);
|
||||
WM_jobs_timer(wm_job, 0.01, NC_OBJECT | ND_MODIFIER, NC_OBJECT | ND_MODIFIER);
|
||||
WM_jobs_callbacks(wm_job, fluid_free_startjob, nullptr, nullptr, fluid_free_endjob);
|
||||
|
||||
WM_locked_interface_set_with_flags(CTX_wm_manager(C), REGION_DRAW_LOCK_BAKING);
|
||||
|
||||
WM_jobs_start(CTX_wm_manager(C), wm_job);
|
||||
WM_event_add_modal_handler(C, op);
|
||||
|
||||
return OPERATOR_RUNNING_MODAL;
|
||||
}
|
||||
|
||||
static wmOperatorStatus fluid_free_modal(bContext *C, wmOperator * /*op*/, const wmEvent *event)
|
||||
{
|
||||
/* No running blender, remove handler and pass through. */
|
||||
if (0 == WM_jobs_test(CTX_wm_manager(C), CTX_data_scene(C), WM_JOB_TYPE_OBJECT_SIM_FLUID)) {
|
||||
return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH;
|
||||
}
|
||||
|
||||
switch (event->type) {
|
||||
case EVT_ESCKEY:
|
||||
return OPERATOR_RUNNING_MODAL;
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return OPERATOR_PASS_THROUGH;
|
||||
}
|
||||
|
||||
static wmOperatorStatus fluid_pause_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
FluidModifierData *fmd = nullptr;
|
||||
FluidDomainSettings *fds;
|
||||
Object *ob = ed::object::context_active_object(C);
|
||||
|
||||
/*
|
||||
* Get modifier data
|
||||
*/
|
||||
fmd = reinterpret_cast<FluidModifierData *>(BKE_modifiers_findby_type(ob, eModifierType_Fluid));
|
||||
if (!fmd) {
|
||||
BKE_report(op->reports, RPT_ERROR, "Bake free failed: no Fluid modifier found");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
fds = fmd->domain;
|
||||
if (!fds) {
|
||||
BKE_report(op->reports, RPT_ERROR, "Bake free failed: invalid domain");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
G.is_break = true;
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
void FLUID_OT_bake_all(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name = "Bake All";
|
||||
ot->description = "Bake Entire Fluid Simulation";
|
||||
ot->idname = FLUID_JOB_BAKE_ALL;
|
||||
|
||||
/* API callbacks. */
|
||||
ot->exec = fluid_bake_exec;
|
||||
ot->invoke = fluid_bake_invoke;
|
||||
ot->modal = fluid_bake_modal;
|
||||
ot->poll = ED_operator_object_active_editable;
|
||||
}
|
||||
|
||||
void FLUID_OT_free_all(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name = "Free All";
|
||||
ot->description = "Free Entire Fluid Simulation";
|
||||
ot->idname = FLUID_JOB_FREE_ALL;
|
||||
|
||||
/* API callbacks. */
|
||||
ot->exec = fluid_free_exec;
|
||||
ot->invoke = fluid_free_invoke;
|
||||
ot->modal = fluid_free_modal;
|
||||
ot->poll = ED_operator_object_active_editable;
|
||||
}
|
||||
|
||||
void FLUID_OT_bake_data(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name = "Bake Data";
|
||||
ot->description = "Bake Fluid Data";
|
||||
ot->idname = FLUID_JOB_BAKE_DATA;
|
||||
|
||||
/* API callbacks. */
|
||||
ot->exec = fluid_bake_exec;
|
||||
ot->invoke = fluid_bake_invoke;
|
||||
ot->modal = fluid_bake_modal;
|
||||
ot->poll = ED_operator_object_active_editable;
|
||||
}
|
||||
|
||||
void FLUID_OT_free_data(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name = "Free Data";
|
||||
ot->description = "Free Fluid Data";
|
||||
ot->idname = FLUID_JOB_FREE_DATA;
|
||||
|
||||
/* API callbacks. */
|
||||
ot->exec = fluid_free_exec;
|
||||
ot->poll = ED_operator_object_active_editable;
|
||||
}
|
||||
|
||||
void FLUID_OT_bake_noise(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name = "Bake Noise";
|
||||
ot->description = "Bake Fluid Noise";
|
||||
ot->idname = FLUID_JOB_BAKE_NOISE;
|
||||
|
||||
/* API callbacks. */
|
||||
ot->exec = fluid_bake_exec;
|
||||
ot->invoke = fluid_bake_invoke;
|
||||
ot->modal = fluid_bake_modal;
|
||||
ot->poll = ED_operator_object_active_editable;
|
||||
}
|
||||
|
||||
void FLUID_OT_free_noise(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name = "Free Noise";
|
||||
ot->description = "Free Fluid Noise";
|
||||
ot->idname = FLUID_JOB_FREE_NOISE;
|
||||
|
||||
/* API callbacks. */
|
||||
ot->exec = fluid_free_exec;
|
||||
ot->poll = ED_operator_object_active_editable;
|
||||
}
|
||||
|
||||
void FLUID_OT_bake_mesh(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name = "Bake Mesh";
|
||||
ot->description = "Bake Fluid Mesh";
|
||||
ot->idname = FLUID_JOB_BAKE_MESH;
|
||||
|
||||
/* API callbacks. */
|
||||
ot->exec = fluid_bake_exec;
|
||||
ot->invoke = fluid_bake_invoke;
|
||||
ot->modal = fluid_bake_modal;
|
||||
ot->poll = ED_operator_object_active_editable;
|
||||
}
|
||||
|
||||
void FLUID_OT_free_mesh(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name = "Free Mesh";
|
||||
ot->description = "Free Fluid Mesh";
|
||||
ot->idname = FLUID_JOB_FREE_MESH;
|
||||
|
||||
/* API callbacks. */
|
||||
ot->exec = fluid_free_exec;
|
||||
ot->poll = ED_operator_object_active_editable;
|
||||
}
|
||||
|
||||
void FLUID_OT_bake_particles(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name = "Bake Particles";
|
||||
ot->description = "Bake Fluid Particles";
|
||||
ot->idname = FLUID_JOB_BAKE_PARTICLES;
|
||||
|
||||
/* API callbacks. */
|
||||
ot->exec = fluid_bake_exec;
|
||||
ot->invoke = fluid_bake_invoke;
|
||||
ot->modal = fluid_bake_modal;
|
||||
ot->poll = ED_operator_object_active_editable;
|
||||
}
|
||||
|
||||
void FLUID_OT_free_particles(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name = "Free Particles";
|
||||
ot->description = "Free Fluid Particles";
|
||||
ot->idname = FLUID_JOB_FREE_PARTICLES;
|
||||
|
||||
/* API callbacks. */
|
||||
ot->exec = fluid_free_exec;
|
||||
ot->poll = ED_operator_object_active_editable;
|
||||
}
|
||||
|
||||
void FLUID_OT_bake_guides(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name = "Bake Guides";
|
||||
ot->description = "Bake Fluid Guiding";
|
||||
ot->idname = FLUID_JOB_BAKE_GUIDES;
|
||||
|
||||
/* API callbacks. */
|
||||
ot->exec = fluid_bake_exec;
|
||||
ot->invoke = fluid_bake_invoke;
|
||||
ot->modal = fluid_bake_modal;
|
||||
ot->poll = ED_operator_object_active_editable;
|
||||
}
|
||||
|
||||
void FLUID_OT_free_guides(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name = "Free Guides";
|
||||
ot->description = "Free Fluid Guiding";
|
||||
ot->idname = FLUID_JOB_FREE_GUIDES;
|
||||
|
||||
/* API callbacks. */
|
||||
ot->exec = fluid_free_exec;
|
||||
ot->poll = ED_operator_object_active_editable;
|
||||
}
|
||||
|
||||
void FLUID_OT_pause_bake(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name = "Pause Bake";
|
||||
ot->description = "Pause Bake";
|
||||
ot->idname = FLUID_JOB_BAKE_PAUSE;
|
||||
|
||||
/* API callbacks. */
|
||||
ot->exec = fluid_pause_exec;
|
||||
ot->poll = ED_operator_object_active_editable;
|
||||
}
|
||||
|
||||
} // namespace blender
|
||||
162
blender-5.2.0/source/blender/editors/physics/physics_intern.hh
Normal file
162
blender-5.2.0/source/blender/editors/physics/physics_intern.hh
Normal file
@@ -0,0 +1,162 @@
|
||||
/* SPDX-FileCopyrightText: 2007 by Janne Karhu. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup edphys
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace blender {
|
||||
|
||||
struct Depsgraph;
|
||||
struct Object;
|
||||
struct PTCacheEdit;
|
||||
struct ParticleSystem;
|
||||
struct PointCache;
|
||||
struct Scene;
|
||||
struct wmOperatorType;
|
||||
|
||||
/* `particle_edit.cc` */
|
||||
|
||||
void PARTICLE_OT_select_all(wmOperatorType *ot);
|
||||
void PARTICLE_OT_select_roots(wmOperatorType *ot);
|
||||
void PARTICLE_OT_select_tips(wmOperatorType *ot);
|
||||
void PARTICLE_OT_select_random(wmOperatorType *ot);
|
||||
void PARTICLE_OT_select_linked(wmOperatorType *ot);
|
||||
void PARTICLE_OT_select_linked_pick(wmOperatorType *ot);
|
||||
void PARTICLE_OT_select_less(wmOperatorType *ot);
|
||||
void PARTICLE_OT_select_more(wmOperatorType *ot);
|
||||
|
||||
void PARTICLE_OT_hide(wmOperatorType *ot);
|
||||
void PARTICLE_OT_reveal(wmOperatorType *ot);
|
||||
|
||||
void PARTICLE_OT_rekey(wmOperatorType *ot);
|
||||
void PARTICLE_OT_subdivide(wmOperatorType *ot);
|
||||
void PARTICLE_OT_remove_doubles(wmOperatorType *ot);
|
||||
void PARTICLE_OT_weight_set(wmOperatorType *ot);
|
||||
void PARTICLE_OT_delete(wmOperatorType *ot);
|
||||
void PARTICLE_OT_mirror(wmOperatorType *ot);
|
||||
|
||||
void PARTICLE_OT_brush_edit(wmOperatorType *ot);
|
||||
|
||||
void PARTICLE_OT_shape_cut(wmOperatorType *ot);
|
||||
|
||||
void PARTICLE_OT_particle_edit_toggle(wmOperatorType *ot);
|
||||
void PARTICLE_OT_edited_clear(wmOperatorType *ot);
|
||||
|
||||
void PARTICLE_OT_unify_length(wmOperatorType *ot);
|
||||
|
||||
/**
|
||||
* Initialize needed data for bake edit.
|
||||
*/
|
||||
void PE_create_particle_edit(
|
||||
Depsgraph *depsgraph, Scene *scene, Object *ob, PointCache *cache, ParticleSystem *psys);
|
||||
/**
|
||||
* Set current distances to be kept between neighboring keys.
|
||||
*/
|
||||
void recalc_lengths(PTCacheEdit *edit);
|
||||
/**
|
||||
* Calculate a tree for finding nearest emitter's vertices.
|
||||
*/
|
||||
void recalc_emitter_field(Depsgraph *depsgraph, Object *ob, ParticleSystem *psys);
|
||||
void update_world_cos(Object *ob, PTCacheEdit *edit);
|
||||
|
||||
/* `particle_object.cc` */
|
||||
|
||||
void OBJECT_OT_particle_system_add(wmOperatorType *ot);
|
||||
void OBJECT_OT_particle_system_remove(wmOperatorType *ot);
|
||||
|
||||
void PARTICLE_OT_new(wmOperatorType *ot);
|
||||
void PARTICLE_OT_new_target(wmOperatorType *ot);
|
||||
void PARTICLE_OT_target_remove(wmOperatorType *ot);
|
||||
void PARTICLE_OT_target_move_up(wmOperatorType *ot);
|
||||
void PARTICLE_OT_target_move_down(wmOperatorType *ot);
|
||||
void PARTICLE_OT_connect_hair(wmOperatorType *ot);
|
||||
void PARTICLE_OT_disconnect_hair(wmOperatorType *ot);
|
||||
void PARTICLE_OT_copy_particle_systems(wmOperatorType *ot);
|
||||
void PARTICLE_OT_duplicate_particle_system(wmOperatorType *ot);
|
||||
void PARTICLE_OT_particle_system_remove_all(wmOperatorType *ot);
|
||||
|
||||
void PARTICLE_OT_dupliob_copy(wmOperatorType *ot);
|
||||
void PARTICLE_OT_dupliob_remove(wmOperatorType *ot);
|
||||
void PARTICLE_OT_dupliob_move_up(wmOperatorType *ot);
|
||||
void PARTICLE_OT_dupliob_move_down(wmOperatorType *ot);
|
||||
void PARTICLE_OT_dupliob_refresh(wmOperatorType *ot);
|
||||
|
||||
/* `particle_boids.cc` */
|
||||
|
||||
void BOID_OT_rule_add(wmOperatorType *ot);
|
||||
void BOID_OT_rule_del(wmOperatorType *ot);
|
||||
void BOID_OT_rule_move_up(wmOperatorType *ot);
|
||||
void BOID_OT_rule_move_down(wmOperatorType *ot);
|
||||
|
||||
void BOID_OT_state_add(wmOperatorType *ot);
|
||||
void BOID_OT_state_del(wmOperatorType *ot);
|
||||
void BOID_OT_state_move_up(wmOperatorType *ot);
|
||||
void BOID_OT_state_move_down(wmOperatorType *ot);
|
||||
|
||||
/* `physics_fluid.cc` */
|
||||
|
||||
void FLUID_OT_bake_all(wmOperatorType *ot);
|
||||
void FLUID_OT_free_all(wmOperatorType *ot);
|
||||
void FLUID_OT_bake_data(wmOperatorType *ot);
|
||||
void FLUID_OT_free_data(wmOperatorType *ot);
|
||||
void FLUID_OT_bake_noise(wmOperatorType *ot);
|
||||
void FLUID_OT_free_noise(wmOperatorType *ot);
|
||||
void FLUID_OT_bake_mesh(wmOperatorType *ot);
|
||||
void FLUID_OT_free_mesh(wmOperatorType *ot);
|
||||
void FLUID_OT_bake_particles(wmOperatorType *ot);
|
||||
void FLUID_OT_free_particles(wmOperatorType *ot);
|
||||
void FLUID_OT_bake_guides(wmOperatorType *ot);
|
||||
void FLUID_OT_free_guides(wmOperatorType *ot);
|
||||
void FLUID_OT_pause_bake(wmOperatorType *ot);
|
||||
|
||||
/* `dynamicpaint.cc` */
|
||||
|
||||
void DPAINT_OT_bake(wmOperatorType *ot);
|
||||
/**
|
||||
* Add surface slot.
|
||||
*/
|
||||
void DPAINT_OT_surface_slot_add(wmOperatorType *ot);
|
||||
/**
|
||||
* Remove surface slot.
|
||||
*/
|
||||
void DPAINT_OT_surface_slot_remove(wmOperatorType *ot);
|
||||
void DPAINT_OT_type_toggle(wmOperatorType *ot);
|
||||
void DPAINT_OT_output_toggle(wmOperatorType *ot);
|
||||
|
||||
/* `physics_pointcache.cc` */
|
||||
|
||||
void PTCACHE_OT_bake_all(wmOperatorType *ot);
|
||||
void PTCACHE_OT_free_bake_all(wmOperatorType *ot);
|
||||
void PTCACHE_OT_bake(wmOperatorType *ot);
|
||||
void PTCACHE_OT_free_bake(wmOperatorType *ot);
|
||||
void PTCACHE_OT_bake_from_cache(wmOperatorType *ot);
|
||||
void PTCACHE_OT_add(wmOperatorType *ot);
|
||||
void PTCACHE_OT_remove(wmOperatorType *ot);
|
||||
|
||||
/* `rigidbody_object.cc` */
|
||||
|
||||
void RIGIDBODY_OT_object_add(wmOperatorType *ot);
|
||||
void RIGIDBODY_OT_object_remove(wmOperatorType *ot);
|
||||
|
||||
void RIGIDBODY_OT_objects_add(wmOperatorType *ot);
|
||||
void RIGIDBODY_OT_objects_remove(wmOperatorType *ot);
|
||||
|
||||
void RIGIDBODY_OT_shape_change(wmOperatorType *ot);
|
||||
void RIGIDBODY_OT_mass_calculate(wmOperatorType *ot);
|
||||
|
||||
/* `rigidbody_constraint.cc` */
|
||||
|
||||
void RIGIDBODY_OT_constraint_add(wmOperatorType *ot);
|
||||
void RIGIDBODY_OT_constraint_remove(wmOperatorType *ot);
|
||||
|
||||
/* `rigidbody_world.cc` */
|
||||
|
||||
void RIGIDBODY_OT_world_add(wmOperatorType *ot);
|
||||
void RIGIDBODY_OT_world_remove(wmOperatorType *ot);
|
||||
void RIGIDBODY_OT_world_export(wmOperatorType *ot);
|
||||
|
||||
} // namespace blender
|
||||
194
blender-5.2.0/source/blender/editors/physics/physics_ops.cc
Normal file
194
blender-5.2.0/source/blender/editors/physics/physics_ops.cc
Normal file
@@ -0,0 +1,194 @@
|
||||
/* SPDX-FileCopyrightText: 2009 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup edphys
|
||||
*/
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
#include "DNA_space_types.h"
|
||||
|
||||
#include "WM_api.hh"
|
||||
|
||||
#include "ED_physics.hh"
|
||||
|
||||
#include "physics_intern.hh" /* own include */
|
||||
|
||||
namespace blender {
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Particles
|
||||
* \{ */
|
||||
|
||||
static void operatortypes_particle()
|
||||
{
|
||||
WM_operatortype_append(PARTICLE_OT_select_all);
|
||||
WM_operatortype_append(PARTICLE_OT_select_roots);
|
||||
WM_operatortype_append(PARTICLE_OT_select_tips);
|
||||
WM_operatortype_append(PARTICLE_OT_select_random);
|
||||
WM_operatortype_append(PARTICLE_OT_select_linked);
|
||||
WM_operatortype_append(PARTICLE_OT_select_linked_pick);
|
||||
WM_operatortype_append(PARTICLE_OT_select_less);
|
||||
WM_operatortype_append(PARTICLE_OT_select_more);
|
||||
|
||||
WM_operatortype_append(PARTICLE_OT_hide);
|
||||
WM_operatortype_append(PARTICLE_OT_reveal);
|
||||
|
||||
WM_operatortype_append(PARTICLE_OT_rekey);
|
||||
WM_operatortype_append(PARTICLE_OT_subdivide);
|
||||
WM_operatortype_append(PARTICLE_OT_remove_doubles);
|
||||
WM_operatortype_append(PARTICLE_OT_weight_set);
|
||||
WM_operatortype_append(PARTICLE_OT_delete);
|
||||
WM_operatortype_append(PARTICLE_OT_mirror);
|
||||
|
||||
WM_operatortype_append(PARTICLE_OT_brush_edit);
|
||||
|
||||
WM_operatortype_append(PARTICLE_OT_shape_cut);
|
||||
|
||||
WM_operatortype_append(PARTICLE_OT_particle_edit_toggle);
|
||||
WM_operatortype_append(PARTICLE_OT_edited_clear);
|
||||
|
||||
WM_operatortype_append(PARTICLE_OT_unify_length);
|
||||
|
||||
WM_operatortype_append(OBJECT_OT_particle_system_add);
|
||||
WM_operatortype_append(OBJECT_OT_particle_system_remove);
|
||||
|
||||
WM_operatortype_append(PARTICLE_OT_new);
|
||||
WM_operatortype_append(PARTICLE_OT_new_target);
|
||||
WM_operatortype_append(PARTICLE_OT_target_remove);
|
||||
WM_operatortype_append(PARTICLE_OT_target_move_up);
|
||||
WM_operatortype_append(PARTICLE_OT_target_move_down);
|
||||
WM_operatortype_append(PARTICLE_OT_connect_hair);
|
||||
WM_operatortype_append(PARTICLE_OT_disconnect_hair);
|
||||
WM_operatortype_append(PARTICLE_OT_copy_particle_systems);
|
||||
WM_operatortype_append(PARTICLE_OT_duplicate_particle_system);
|
||||
WM_operatortype_append(PARTICLE_OT_particle_system_remove_all);
|
||||
|
||||
WM_operatortype_append(PARTICLE_OT_dupliob_refresh);
|
||||
WM_operatortype_append(PARTICLE_OT_dupliob_copy);
|
||||
WM_operatortype_append(PARTICLE_OT_dupliob_remove);
|
||||
WM_operatortype_append(PARTICLE_OT_dupliob_move_up);
|
||||
WM_operatortype_append(PARTICLE_OT_dupliob_move_down);
|
||||
|
||||
WM_operatortype_append(RIGIDBODY_OT_object_add);
|
||||
WM_operatortype_append(RIGIDBODY_OT_object_remove);
|
||||
|
||||
WM_operatortype_append(RIGIDBODY_OT_objects_add);
|
||||
WM_operatortype_append(RIGIDBODY_OT_objects_remove);
|
||||
|
||||
WM_operatortype_append(RIGIDBODY_OT_shape_change);
|
||||
WM_operatortype_append(RIGIDBODY_OT_mass_calculate);
|
||||
|
||||
WM_operatortype_append(RIGIDBODY_OT_constraint_add);
|
||||
WM_operatortype_append(RIGIDBODY_OT_constraint_remove);
|
||||
|
||||
WM_operatortype_append(RIGIDBODY_OT_world_add);
|
||||
WM_operatortype_append(RIGIDBODY_OT_world_remove);
|
||||
// WM_operatortype_append(RIGIDBODY_OT_world_export);
|
||||
}
|
||||
|
||||
static void keymap_particle(wmKeyConfig *keyconf)
|
||||
{
|
||||
wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Particle", SPACE_EMPTY, RGN_TYPE_WINDOW);
|
||||
keymap->poll = PE_poll;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Boids
|
||||
* \{ */
|
||||
|
||||
static void operatortypes_boids()
|
||||
{
|
||||
WM_operatortype_append(BOID_OT_rule_add);
|
||||
WM_operatortype_append(BOID_OT_rule_del);
|
||||
WM_operatortype_append(BOID_OT_rule_move_up);
|
||||
WM_operatortype_append(BOID_OT_rule_move_down);
|
||||
|
||||
WM_operatortype_append(BOID_OT_state_add);
|
||||
WM_operatortype_append(BOID_OT_state_del);
|
||||
WM_operatortype_append(BOID_OT_state_move_up);
|
||||
WM_operatortype_append(BOID_OT_state_move_down);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Fluid
|
||||
* \{ */
|
||||
|
||||
static void operatortypes_fluid()
|
||||
{
|
||||
WM_operatortype_append(FLUID_OT_bake_all);
|
||||
WM_operatortype_append(FLUID_OT_free_all);
|
||||
WM_operatortype_append(FLUID_OT_bake_data);
|
||||
WM_operatortype_append(FLUID_OT_free_data);
|
||||
WM_operatortype_append(FLUID_OT_bake_noise);
|
||||
WM_operatortype_append(FLUID_OT_free_noise);
|
||||
WM_operatortype_append(FLUID_OT_bake_mesh);
|
||||
WM_operatortype_append(FLUID_OT_free_mesh);
|
||||
WM_operatortype_append(FLUID_OT_bake_particles);
|
||||
WM_operatortype_append(FLUID_OT_free_particles);
|
||||
WM_operatortype_append(FLUID_OT_bake_guides);
|
||||
WM_operatortype_append(FLUID_OT_free_guides);
|
||||
WM_operatortype_append(FLUID_OT_pause_bake);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Point Cache
|
||||
* \{ */
|
||||
|
||||
static void operatortypes_pointcache()
|
||||
{
|
||||
WM_operatortype_append(PTCACHE_OT_bake_all);
|
||||
WM_operatortype_append(PTCACHE_OT_free_bake_all);
|
||||
WM_operatortype_append(PTCACHE_OT_bake);
|
||||
WM_operatortype_append(PTCACHE_OT_free_bake);
|
||||
WM_operatortype_append(PTCACHE_OT_bake_from_cache);
|
||||
WM_operatortype_append(PTCACHE_OT_add);
|
||||
WM_operatortype_append(PTCACHE_OT_remove);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Dynamic Paint
|
||||
* \{ */
|
||||
|
||||
static void operatortypes_dynamicpaint()
|
||||
{
|
||||
WM_operatortype_append(DPAINT_OT_bake);
|
||||
WM_operatortype_append(DPAINT_OT_surface_slot_add);
|
||||
WM_operatortype_append(DPAINT_OT_surface_slot_remove);
|
||||
WM_operatortype_append(DPAINT_OT_type_toggle);
|
||||
WM_operatortype_append(DPAINT_OT_output_toggle);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Registration
|
||||
* \{ */
|
||||
|
||||
void ED_operatortypes_physics()
|
||||
{
|
||||
operatortypes_particle();
|
||||
operatortypes_boids();
|
||||
operatortypes_fluid();
|
||||
operatortypes_pointcache();
|
||||
operatortypes_dynamicpaint();
|
||||
}
|
||||
|
||||
void ED_keymap_physics(wmKeyConfig *keyconf)
|
||||
{
|
||||
keymap_particle(keyconf);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
} // namespace blender
|
||||
@@ -0,0 +1,466 @@
|
||||
/* SPDX-FileCopyrightText: 2007 by Janne Karhu. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup edphys
|
||||
*/
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "BLI_listbase.h"
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
#include "BKE_context.hh"
|
||||
#include "BKE_duplilist.hh"
|
||||
#include "BKE_global.hh"
|
||||
#include "BKE_layer.hh"
|
||||
#include "BKE_library.hh"
|
||||
#include "BKE_pointcache.h"
|
||||
|
||||
#include "DEG_depsgraph.hh"
|
||||
|
||||
#include "ED_particle.hh"
|
||||
|
||||
#include "WM_api.hh"
|
||||
#include "WM_types.hh"
|
||||
|
||||
#include "RNA_access.hh"
|
||||
#include "RNA_define.hh"
|
||||
#include "RNA_prototypes.hh"
|
||||
|
||||
#include "physics_intern.hh"
|
||||
|
||||
namespace blender {
|
||||
|
||||
static bool ptcache_bake_all_poll(bContext *C)
|
||||
{
|
||||
return CTX_data_scene(C) != nullptr;
|
||||
}
|
||||
|
||||
static bool ptcache_poll(bContext *C)
|
||||
{
|
||||
PointerRNA ptr = CTX_data_pointer_get_type(C, "point_cache", RNA_PointCache);
|
||||
|
||||
ID *id = ptr.owner_id;
|
||||
PointCache *point_cache = static_cast<PointCache *>(ptr.data);
|
||||
|
||||
if (id == nullptr || point_cache == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ID_IS_OVERRIDE_LIBRARY_REAL(id) && (point_cache->flag & PTCACHE_DISK_CACHE) == false) {
|
||||
CTX_wm_operator_poll_msg_set(C,
|
||||
"Library override data-blocks only support Disk Cache storage");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ID_IS_EDITABLE(id) && (point_cache->flag & PTCACHE_DISK_CACHE) == false) {
|
||||
CTX_wm_operator_poll_msg_set(C, "Linked data-blocks do not allow editing caches");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool ptcache_add_remove_poll(bContext *C)
|
||||
{
|
||||
PointerRNA ptr = CTX_data_pointer_get_type(C, "point_cache", RNA_PointCache);
|
||||
|
||||
ID *id = ptr.owner_id;
|
||||
PointCache *point_cache = static_cast<PointCache *>(ptr.data);
|
||||
|
||||
if (id == nullptr || point_cache == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ID_IS_OVERRIDE_LIBRARY_REAL(id) || !ID_IS_EDITABLE(id)) {
|
||||
CTX_wm_operator_poll_msg_set(
|
||||
C, "Linked or library override data-blocks do not allow adding or removing caches");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
struct PointCacheJob {
|
||||
wmWindowManager *wm;
|
||||
void *owner;
|
||||
bool *stop, *do_update;
|
||||
float *progress;
|
||||
|
||||
PTCacheBaker *baker;
|
||||
};
|
||||
|
||||
static void ptcache_job_free(void *customdata)
|
||||
{
|
||||
PointCacheJob *job = static_cast<PointCacheJob *>(customdata);
|
||||
MEM_delete(job->baker);
|
||||
MEM_delete(job);
|
||||
}
|
||||
|
||||
static int ptcache_job_break(void *customdata)
|
||||
{
|
||||
PointCacheJob *job = static_cast<PointCacheJob *>(customdata);
|
||||
|
||||
if (G.is_break) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (job->stop && *(job->stop)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ptcache_job_update(void *customdata, float progress, int *cancel)
|
||||
{
|
||||
PointCacheJob *job = static_cast<PointCacheJob *>(customdata);
|
||||
|
||||
if (ptcache_job_break(job)) {
|
||||
*cancel = 1;
|
||||
}
|
||||
|
||||
*(job->do_update) = true;
|
||||
*(job->progress) = progress;
|
||||
}
|
||||
|
||||
static void ptcache_job_startjob(void *customdata, wmJobWorkerStatus *worker_status)
|
||||
{
|
||||
PointCacheJob *job = static_cast<PointCacheJob *>(customdata);
|
||||
|
||||
job->stop = &worker_status->stop;
|
||||
job->do_update = &worker_status->do_update;
|
||||
job->progress = &worker_status->progress;
|
||||
|
||||
G.is_break = false;
|
||||
|
||||
/* XXX annoying hack: needed to prevent data corruption when changing
|
||||
* scene frame in separate threads
|
||||
*/
|
||||
WM_locked_interface_set(job->wm, true);
|
||||
|
||||
BKE_ptcache_bake(job->baker);
|
||||
|
||||
worker_status->do_update = true;
|
||||
worker_status->stop = false;
|
||||
}
|
||||
|
||||
static void ptcache_job_endjob(void *customdata)
|
||||
{
|
||||
PointCacheJob *job = static_cast<PointCacheJob *>(customdata);
|
||||
Scene *scene = job->baker->scene;
|
||||
|
||||
WM_locked_interface_set(job->wm, false);
|
||||
|
||||
WM_main_add_notifier(NC_SCENE | ND_FRAME, scene);
|
||||
WM_main_add_notifier(NC_OBJECT | ND_POINTCACHE, job->baker->pid.owner_id);
|
||||
}
|
||||
|
||||
static void ptcache_free_bake(PointCache *cache)
|
||||
{
|
||||
if (cache->edit) {
|
||||
if (!cache->edit->edited || true) { // XXX okee("Lose changes done in particle mode?")) {
|
||||
PE_free_ptcache_edit(cache->edit);
|
||||
cache->edit = nullptr;
|
||||
cache->flag &= ~PTCACHE_BAKED;
|
||||
}
|
||||
}
|
||||
else {
|
||||
cache->flag &= ~PTCACHE_BAKED;
|
||||
}
|
||||
}
|
||||
|
||||
static PTCacheBaker *ptcache_baker_create(bContext *C, wmOperator *op, bool all)
|
||||
{
|
||||
PTCacheBaker *baker = MEM_new_zeroed<PTCacheBaker>("PTCacheBaker");
|
||||
|
||||
baker->bmain = CTX_data_main(C);
|
||||
baker->scene = CTX_data_scene(C);
|
||||
baker->view_layer = CTX_data_view_layer(C);
|
||||
/* Depsgraph is used to sweep the frame range and evaluate scene at different times. */
|
||||
baker->depsgraph = CTX_data_depsgraph_pointer(C);
|
||||
baker->bake = RNA_boolean_get(op->ptr, "bake");
|
||||
baker->render = false;
|
||||
baker->anim_init = false;
|
||||
baker->quick_step = 1;
|
||||
|
||||
if (!all) {
|
||||
PointerRNA ptr = CTX_data_pointer_get_type(C, "point_cache", RNA_PointCache);
|
||||
ID *id = ptr.owner_id;
|
||||
Object *ob = (GS(id->name) == ID_OB) ? id_cast<Object *>(id) : nullptr;
|
||||
PointCache *cache = static_cast<PointCache *>(ptr.data);
|
||||
baker->pid = BKE_ptcache_id_find(ob, baker->scene, cache);
|
||||
}
|
||||
|
||||
return baker;
|
||||
}
|
||||
|
||||
static wmOperatorStatus ptcache_bake_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
bool all = STREQ(op->type->idname, "PTCACHE_OT_bake_all");
|
||||
|
||||
PTCacheBaker *baker = ptcache_baker_create(C, op, all);
|
||||
BKE_ptcache_bake(baker);
|
||||
MEM_delete(baker);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
static wmOperatorStatus ptcache_bake_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/)
|
||||
{
|
||||
bool all = STREQ(op->type->idname, "PTCACHE_OT_bake_all");
|
||||
|
||||
PointCacheJob *job = MEM_new_uninitialized<PointCacheJob>("PointCacheJob");
|
||||
job->wm = CTX_wm_manager(C);
|
||||
job->baker = ptcache_baker_create(C, op, all);
|
||||
job->baker->bake_job = job;
|
||||
job->baker->update_progress = ptcache_job_update;
|
||||
|
||||
wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C),
|
||||
CTX_wm_window(C),
|
||||
CTX_data_scene(C),
|
||||
"Baking point cache...",
|
||||
WM_JOB_PROGRESS,
|
||||
WM_JOB_TYPE_POINTCACHE);
|
||||
|
||||
WM_jobs_customdata_set(wm_job, job, ptcache_job_free);
|
||||
WM_jobs_timer(wm_job, 0.1, NC_OBJECT | ND_POINTCACHE, NC_OBJECT | ND_POINTCACHE);
|
||||
WM_jobs_callbacks(wm_job, ptcache_job_startjob, nullptr, nullptr, ptcache_job_endjob);
|
||||
|
||||
WM_locked_interface_set(CTX_wm_manager(C), true);
|
||||
|
||||
WM_jobs_start(CTX_wm_manager(C), wm_job);
|
||||
|
||||
WM_event_add_modal_handler(C, op);
|
||||
|
||||
/* we must run modal until the bake job is done, otherwise the undo push
|
||||
* happens before the job ends, which can lead to race conditions between
|
||||
* the baking and file writing code */
|
||||
return OPERATOR_RUNNING_MODAL;
|
||||
}
|
||||
|
||||
static wmOperatorStatus ptcache_bake_modal(bContext *C, wmOperator *op, const wmEvent * /*event*/)
|
||||
{
|
||||
Scene *scene = static_cast<Scene *>(op->customdata);
|
||||
|
||||
/* no running blender, remove handler and pass through */
|
||||
if (0 == WM_jobs_test(CTX_wm_manager(C), scene, WM_JOB_TYPE_POINTCACHE)) {
|
||||
return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH;
|
||||
}
|
||||
|
||||
return OPERATOR_PASS_THROUGH;
|
||||
}
|
||||
|
||||
static void ptcache_bake_cancel(bContext *C, wmOperator *op)
|
||||
{
|
||||
wmWindowManager *wm = CTX_wm_manager(C);
|
||||
Scene *scene = static_cast<Scene *>(op->customdata);
|
||||
|
||||
/* kill on cancel, because job is using op->reports */
|
||||
WM_jobs_kill_type(wm, scene, WM_JOB_TYPE_POINTCACHE);
|
||||
}
|
||||
|
||||
static wmOperatorStatus ptcache_free_bake_all_exec(bContext *C, wmOperator * /*op*/)
|
||||
{
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
ListBaseT<PTCacheID> pidlist;
|
||||
|
||||
FOREACH_SCENE_OBJECT_BEGIN (scene, ob) {
|
||||
BKE_ptcache_ids_from_object(&pidlist, ob, scene, MAX_DUPLI_RECUR);
|
||||
|
||||
for (PTCacheID &pid : pidlist) {
|
||||
ptcache_free_bake(pid.cache);
|
||||
}
|
||||
|
||||
pidlist.free_no_destruct();
|
||||
|
||||
WM_event_add_notifier(C, NC_OBJECT | ND_POINTCACHE, ob);
|
||||
}
|
||||
FOREACH_SCENE_OBJECT_END;
|
||||
|
||||
WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
void PTCACHE_OT_bake_all(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name = "Bake All Physics";
|
||||
ot->description = "Bake all physics simulations in the current scene";
|
||||
ot->idname = "PTCACHE_OT_bake_all";
|
||||
|
||||
/* API callbacks. */
|
||||
ot->exec = ptcache_bake_exec;
|
||||
ot->invoke = ptcache_bake_invoke;
|
||||
ot->modal = ptcache_bake_modal;
|
||||
ot->cancel = ptcache_bake_cancel;
|
||||
ot->poll = ptcache_bake_all_poll;
|
||||
|
||||
/* flags */
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
|
||||
RNA_def_boolean(ot->srna, "bake", true, "Bake", "");
|
||||
}
|
||||
void PTCACHE_OT_free_bake_all(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name = "Delete All Physics Bakes";
|
||||
ot->idname = "PTCACHE_OT_free_bake_all";
|
||||
ot->description = "Delete all baked caches of all objects in the current scene";
|
||||
|
||||
/* API callbacks. */
|
||||
ot->exec = ptcache_free_bake_all_exec;
|
||||
ot->poll = ptcache_bake_all_poll;
|
||||
|
||||
/* flags */
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
}
|
||||
|
||||
static wmOperatorStatus ptcache_free_bake_exec(bContext *C, wmOperator * /*op*/)
|
||||
{
|
||||
PointerRNA ptr = CTX_data_pointer_get_type(C, "point_cache", RNA_PointCache);
|
||||
PointCache *cache = static_cast<PointCache *>(ptr.data);
|
||||
Object *ob = id_cast<Object *>(ptr.owner_id);
|
||||
|
||||
ptcache_free_bake(cache);
|
||||
|
||||
WM_event_add_notifier(C, NC_OBJECT | ND_POINTCACHE, ob);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
static wmOperatorStatus ptcache_bake_from_cache_exec(bContext *C, wmOperator * /*op*/)
|
||||
{
|
||||
PointerRNA ptr = CTX_data_pointer_get_type(C, "point_cache", RNA_PointCache);
|
||||
PointCache *cache = static_cast<PointCache *>(ptr.data);
|
||||
Object *ob = id_cast<Object *>(ptr.owner_id);
|
||||
|
||||
cache->flag |= PTCACHE_BAKED;
|
||||
|
||||
WM_event_add_notifier(C, NC_OBJECT | ND_POINTCACHE, ob);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
void PTCACHE_OT_bake(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name = "Bake Physics";
|
||||
ot->description = "Bake physics";
|
||||
ot->idname = "PTCACHE_OT_bake";
|
||||
|
||||
/* API callbacks. */
|
||||
ot->exec = ptcache_bake_exec;
|
||||
ot->invoke = ptcache_bake_invoke;
|
||||
ot->modal = ptcache_bake_modal;
|
||||
ot->cancel = ptcache_bake_cancel;
|
||||
ot->poll = ptcache_poll;
|
||||
|
||||
/* flags */
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
|
||||
RNA_def_boolean(ot->srna, "bake", false, "Bake", "");
|
||||
}
|
||||
void PTCACHE_OT_free_bake(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name = "Delete Physics Bake";
|
||||
ot->description = "Delete physics bake";
|
||||
ot->idname = "PTCACHE_OT_free_bake";
|
||||
|
||||
/* API callbacks. */
|
||||
ot->exec = ptcache_free_bake_exec;
|
||||
ot->poll = ptcache_poll;
|
||||
|
||||
/* flags */
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
}
|
||||
void PTCACHE_OT_bake_from_cache(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name = "Bake from Cache";
|
||||
ot->description = "Bake from cache";
|
||||
ot->idname = "PTCACHE_OT_bake_from_cache";
|
||||
|
||||
/* API callbacks. */
|
||||
ot->exec = ptcache_bake_from_cache_exec;
|
||||
ot->poll = ptcache_poll;
|
||||
|
||||
/* flags */
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
}
|
||||
|
||||
static wmOperatorStatus ptcache_add_new_exec(bContext *C, wmOperator * /*op*/)
|
||||
{
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
PointerRNA ptr = CTX_data_pointer_get_type(C, "point_cache", RNA_PointCache);
|
||||
Object *ob = id_cast<Object *>(ptr.owner_id);
|
||||
PointCache *cache = static_cast<PointCache *>(ptr.data);
|
||||
PTCacheID pid = BKE_ptcache_id_find(ob, scene, cache);
|
||||
|
||||
if (pid.cache) {
|
||||
PointCache *cache_new = BKE_ptcache_add(pid.ptcaches);
|
||||
cache_new->step = pid.default_step;
|
||||
*(pid.cache_ptr) = cache_new;
|
||||
|
||||
DEG_id_tag_update(&ob->id, ID_RECALC_POINT_CACHE);
|
||||
WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene);
|
||||
WM_event_add_notifier(C, NC_OBJECT | ND_POINTCACHE, ob);
|
||||
}
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
static wmOperatorStatus ptcache_remove_exec(bContext *C, wmOperator * /*op*/)
|
||||
{
|
||||
PointerRNA ptr = CTX_data_pointer_get_type(C, "point_cache", RNA_PointCache);
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
Object *ob = id_cast<Object *>(ptr.owner_id);
|
||||
PointCache *cache = static_cast<PointCache *>(ptr.data);
|
||||
PTCacheID pid = BKE_ptcache_id_find(ob, scene, cache);
|
||||
|
||||
/* don't delete last cache */
|
||||
if (pid.cache && pid.ptcaches->first != pid.ptcaches->last) {
|
||||
BLI_remlink(pid.ptcaches, pid.cache);
|
||||
BKE_ptcache_free(pid.cache);
|
||||
*(pid.cache_ptr) = static_cast<PointCache *>(pid.ptcaches->first);
|
||||
|
||||
DEG_id_tag_update(&ob->id, ID_RECALC_SYNC_TO_EVAL);
|
||||
WM_event_add_notifier(C, NC_OBJECT | ND_POINTCACHE, ob);
|
||||
}
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
void PTCACHE_OT_add(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name = "Add New Cache";
|
||||
ot->description = "Add new cache";
|
||||
ot->idname = "PTCACHE_OT_add";
|
||||
|
||||
/* API callbacks. */
|
||||
ot->exec = ptcache_add_new_exec;
|
||||
ot->poll = ptcache_add_remove_poll;
|
||||
|
||||
/* flags */
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
}
|
||||
void PTCACHE_OT_remove(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name = "Delete Current Cache";
|
||||
ot->description = "Delete current cache";
|
||||
ot->idname = "PTCACHE_OT_remove";
|
||||
|
||||
/* API callbacks. */
|
||||
ot->exec = ptcache_remove_exec;
|
||||
ot->poll = ptcache_add_remove_poll;
|
||||
|
||||
/* flags */
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
}
|
||||
|
||||
} // namespace blender
|
||||
@@ -0,0 +1,219 @@
|
||||
/* SPDX-FileCopyrightText: 2013 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup editor_physics
|
||||
* \brief Rigid Body constraint editing operators
|
||||
*/
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
#include "DNA_collection_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
#include "DNA_rigidbody_types.h"
|
||||
#include "DNA_scene_types.h"
|
||||
|
||||
#include "BKE_collection.hh"
|
||||
#include "BKE_context.hh"
|
||||
#include "BKE_layer.hh"
|
||||
#include "BKE_lib_id.hh"
|
||||
#include "BKE_library.hh"
|
||||
#include "BKE_report.hh"
|
||||
#include "BKE_rigidbody.h"
|
||||
#include "BKE_scene.hh"
|
||||
|
||||
#include "DEG_depsgraph.hh"
|
||||
#include "DEG_depsgraph_build.hh"
|
||||
|
||||
#include "RNA_access.hh"
|
||||
#include "RNA_define.hh"
|
||||
#include "RNA_enum_types.hh"
|
||||
|
||||
#include "WM_api.hh"
|
||||
#include "WM_types.hh"
|
||||
|
||||
#include "ED_object.hh"
|
||||
#include "ED_physics.hh"
|
||||
#include "ED_screen.hh"
|
||||
|
||||
#include "physics_intern.hh"
|
||||
|
||||
namespace blender {
|
||||
|
||||
/* ********************************************** */
|
||||
/* Helper API's for RigidBody Constraint Editing */
|
||||
|
||||
static bool operator_rigidbody_constraints_editable_poll(Scene *scene)
|
||||
{
|
||||
if (scene == nullptr || !ID_IS_EDITABLE(scene) || ID_IS_OVERRIDE_LIBRARY(scene) ||
|
||||
(scene->rigidbody_world != nullptr && scene->rigidbody_world->constraints != nullptr &&
|
||||
(!ID_IS_EDITABLE(scene->rigidbody_world->constraints) ||
|
||||
ID_IS_OVERRIDE_LIBRARY(scene->rigidbody_world->constraints))))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool operator_rigidbody_con_active_poll(bContext *C)
|
||||
{
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
if (!operator_rigidbody_constraints_editable_poll(scene)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Object *ob = ed::object::context_active_object(C);
|
||||
return (ob && ob->rigidbody_constraint && ED_operator_object_active_editable_ex(C, ob));
|
||||
}
|
||||
|
||||
static bool operator_rigidbody_con_add_poll(bContext *C)
|
||||
{
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
if (!operator_rigidbody_constraints_editable_poll(scene)) {
|
||||
return false;
|
||||
}
|
||||
return ED_operator_object_active_editable(C);
|
||||
}
|
||||
|
||||
bool ED_rigidbody_constraint_add(
|
||||
Main *bmain, Scene *scene, Object *ob, eRigidBodyCon_Type type, ReportList *reports)
|
||||
{
|
||||
RigidBodyWorld *rbw = BKE_rigidbody_get_world(scene);
|
||||
|
||||
/* check that object doesn't already have a constraint */
|
||||
if (ob->rigidbody_constraint) {
|
||||
BKE_reportf(
|
||||
reports, RPT_INFO, "Object '%s' already has a Rigid Body Constraint", ob->id.name + 2);
|
||||
return false;
|
||||
}
|
||||
/* create constraint group if it doesn't already exits */
|
||||
if (rbw->constraints == nullptr) {
|
||||
rbw->constraints = BKE_collection_add(bmain, nullptr, "RigidBodyConstraints");
|
||||
id_us_plus(&rbw->constraints->id);
|
||||
}
|
||||
/* make rigidbody constraint settings */
|
||||
ob->rigidbody_constraint = BKE_rigidbody_create_constraint(scene, ob, type);
|
||||
|
||||
/* add constraint to rigid body constraint group */
|
||||
BKE_collection_object_add(bmain, rbw->constraints, ob);
|
||||
|
||||
DEG_relations_tag_update(bmain);
|
||||
DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM);
|
||||
DEG_id_tag_update(&rbw->constraints->id, ID_RECALC_SYNC_TO_EVAL);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ED_rigidbody_constraint_remove(Main *bmain, Scene *scene, Object *ob)
|
||||
{
|
||||
BKE_rigidbody_remove_constraint(bmain, scene, ob, false);
|
||||
|
||||
DEG_relations_tag_update(bmain);
|
||||
DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM);
|
||||
}
|
||||
|
||||
/* ********************************************** */
|
||||
/* Active Object Add/Remove Operators */
|
||||
|
||||
/* ************ Add Rigid Body Constraint ************** */
|
||||
|
||||
static wmOperatorStatus rigidbody_con_add_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
Main *bmain = CTX_data_main(C);
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
RigidBodyWorld *rbw = BKE_rigidbody_get_world(scene);
|
||||
Object *ob = ed::object::context_active_object(C);
|
||||
eRigidBodyCon_Type type = eRigidBodyCon_Type(RNA_enum_get(op->ptr, "type"));
|
||||
bool changed;
|
||||
/* Poll ensures. */
|
||||
BLI_assert(scene && ob);
|
||||
|
||||
/* The rigid body world is not ensured by the poll. */
|
||||
if (rbw == nullptr) {
|
||||
BKE_report(op->reports, RPT_ERROR, "No Rigid Body World to add Rigid Body Constraint to");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
/* Pinned objects could be from another scene. */
|
||||
if (!BKE_scene_object_find(*bmain, scene, ob)) {
|
||||
BKE_report(op->reports, RPT_ERROR, "No object in the scene to add Rigid Body Constraint to");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
/* apply to active object */
|
||||
changed = ED_rigidbody_constraint_add(bmain, scene, ob, type, op->reports);
|
||||
|
||||
if (changed) {
|
||||
/* send updates */
|
||||
WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, nullptr);
|
||||
|
||||
/* done */
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
void RIGIDBODY_OT_constraint_add(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->idname = "RIGIDBODY_OT_constraint_add";
|
||||
ot->name = "Add Rigid Body Constraint";
|
||||
ot->description = "Add Rigid Body Constraint to active object";
|
||||
|
||||
/* callbacks */
|
||||
ot->exec = rigidbody_con_add_exec;
|
||||
ot->poll = operator_rigidbody_con_add_poll;
|
||||
|
||||
/* flags */
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
|
||||
/* properties */
|
||||
ot->prop = RNA_def_enum(ot->srna,
|
||||
"type",
|
||||
rna_enum_rigidbody_constraint_type_items,
|
||||
RBC_TYPE_FIXED,
|
||||
"Rigid Body Constraint Type",
|
||||
"");
|
||||
}
|
||||
|
||||
/* ************ Remove Rigid Body Constraint ************** */
|
||||
|
||||
static wmOperatorStatus rigidbody_con_remove_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
Main *bmain = CTX_data_main(C);
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
Object *ob = ed::object::context_active_object(C);
|
||||
/* Poll ensures. */
|
||||
BLI_assert(scene && ob && ob->rigidbody_constraint);
|
||||
|
||||
/* Pinned objects could be from another scene. */
|
||||
if (!BKE_scene_object_find(*bmain, scene, ob)) {
|
||||
BKE_report(
|
||||
op->reports, RPT_ERROR, "No object in the scene to remove Rigid Body Constraint from");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
ED_rigidbody_constraint_remove(bmain, scene, ob);
|
||||
|
||||
/* send updates */
|
||||
WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, nullptr);
|
||||
|
||||
/* done */
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
void RIGIDBODY_OT_constraint_remove(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->idname = "RIGIDBODY_OT_constraint_remove";
|
||||
ot->name = "Remove Rigid Body Constraint";
|
||||
ot->description = "Remove Rigid Body Constraint from Object";
|
||||
|
||||
/* callbacks */
|
||||
ot->exec = rigidbody_con_remove_exec;
|
||||
ot->poll = operator_rigidbody_con_active_poll;
|
||||
|
||||
/* flags */
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
}
|
||||
|
||||
} // namespace blender
|
||||
575
blender-5.2.0/source/blender/editors/physics/rigidbody_object.cc
Normal file
575
blender-5.2.0/source/blender/editors/physics/rigidbody_object.cc
Normal file
@@ -0,0 +1,575 @@
|
||||
/* SPDX-FileCopyrightText: 2013 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup editor_physics
|
||||
* \brief Rigid Body object editing operators
|
||||
*/
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
#include "DNA_collection_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
#include "DNA_rigidbody_types.h"
|
||||
#include "DNA_scene_types.h"
|
||||
|
||||
#include "BLT_translation.hh"
|
||||
|
||||
#include "BKE_context.hh"
|
||||
#include "BKE_library.hh"
|
||||
#include "BKE_report.hh"
|
||||
#include "BKE_rigidbody.h"
|
||||
|
||||
#include "DEG_depsgraph.hh"
|
||||
#include "DEG_depsgraph_build.hh"
|
||||
#include "DEG_depsgraph_query.hh"
|
||||
|
||||
#include "RNA_access.hh"
|
||||
#include "RNA_define.hh"
|
||||
#include "RNA_enum_types.hh"
|
||||
#include "RNA_prototypes.hh"
|
||||
|
||||
#include "WM_api.hh"
|
||||
#include "WM_types.hh"
|
||||
|
||||
#include "ED_object.hh"
|
||||
#include "ED_physics.hh"
|
||||
#include "ED_screen.hh"
|
||||
|
||||
#include "physics_intern.hh"
|
||||
|
||||
namespace blender {
|
||||
|
||||
/* ********************************************** */
|
||||
/* Helper API's for RigidBody Objects Editing */
|
||||
|
||||
static bool operator_rigidbody_editable_poll(Scene *scene)
|
||||
{
|
||||
if (scene == nullptr || !ID_IS_EDITABLE(scene) || ID_IS_OVERRIDE_LIBRARY(scene) ||
|
||||
(scene->rigidbody_world != nullptr && scene->rigidbody_world->group != nullptr &&
|
||||
(!ID_IS_EDITABLE(scene->rigidbody_world->group) ||
|
||||
ID_IS_OVERRIDE_LIBRARY(scene->rigidbody_world->group))))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool operator_rigidbody_active_poll(bContext *C)
|
||||
{
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
if (!operator_rigidbody_editable_poll(scene)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ED_operator_object_active_editable(C)) {
|
||||
Object *ob = ed::object::context_active_object(C);
|
||||
return (ob && ob->rigidbody_object);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool operator_rigidbody_add_poll(bContext *C)
|
||||
{
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
if (!operator_rigidbody_editable_poll(scene)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ED_operator_object_active_editable(C)) {
|
||||
Object *ob = ed::object::context_active_object(C);
|
||||
return (ob && ob->type == OB_MESH);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* ----------------- */
|
||||
|
||||
bool ED_rigidbody_object_add(
|
||||
Main *bmain, Scene *scene, Object *ob, eRigidBodyOb_Type type, ReportList *reports)
|
||||
{
|
||||
return BKE_rigidbody_add_object(bmain, scene, ob, type, reports);
|
||||
}
|
||||
|
||||
void ED_rigidbody_object_remove(Main *bmain, Scene *scene, Object *ob)
|
||||
{
|
||||
BKE_rigidbody_remove_object(bmain, scene, ob, false);
|
||||
}
|
||||
|
||||
/* ********************************************** */
|
||||
/* Active Object Add/Remove Operators */
|
||||
|
||||
/* ************ Add Rigid Body ************** */
|
||||
|
||||
static wmOperatorStatus rigidbody_object_add_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
Main *bmain = CTX_data_main(C);
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
Object *ob = ed::object::context_active_object(C);
|
||||
eRigidBodyOb_Type type = eRigidBodyOb_Type(RNA_enum_get(op->ptr, "type"));
|
||||
bool changed;
|
||||
|
||||
/* apply to active object */
|
||||
changed = ED_rigidbody_object_add(bmain, scene, ob, type, op->reports);
|
||||
|
||||
if (changed) {
|
||||
/* send updates */
|
||||
WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, nullptr);
|
||||
WM_event_add_notifier(C, NC_OBJECT | ND_POINTCACHE, nullptr);
|
||||
|
||||
/* done */
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
void RIGIDBODY_OT_object_add(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->idname = "RIGIDBODY_OT_object_add";
|
||||
ot->name = "Add Rigid Body";
|
||||
ot->description = "Add active object as Rigid Body";
|
||||
|
||||
/* callbacks */
|
||||
ot->exec = rigidbody_object_add_exec;
|
||||
ot->poll = operator_rigidbody_add_poll;
|
||||
|
||||
/* flags */
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
|
||||
/* properties */
|
||||
ot->prop = RNA_def_enum(ot->srna,
|
||||
"type",
|
||||
rna_enum_rigidbody_object_type_items,
|
||||
RBO_TYPE_ACTIVE,
|
||||
"Rigid Body Type",
|
||||
"");
|
||||
}
|
||||
|
||||
/* ************ Remove Rigid Body ************** */
|
||||
|
||||
static wmOperatorStatus rigidbody_object_remove_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
Main *bmain = CTX_data_main(C);
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
Object *ob = ed::object::context_active_object(C);
|
||||
bool changed = false;
|
||||
|
||||
/* apply to active object */
|
||||
if (!ELEM(nullptr, ob, ob->rigidbody_object)) {
|
||||
ED_rigidbody_object_remove(bmain, scene, ob);
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
/* send updates */
|
||||
WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, nullptr);
|
||||
WM_event_add_notifier(C, NC_OBJECT | ND_POINTCACHE, nullptr);
|
||||
|
||||
/* done */
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
BKE_report(op->reports, RPT_ERROR, "Object has no Rigid Body settings to remove");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
void RIGIDBODY_OT_object_remove(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->idname = "RIGIDBODY_OT_object_remove";
|
||||
ot->name = "Remove Rigid Body";
|
||||
ot->description = "Remove Rigid Body settings from Object";
|
||||
|
||||
/* callbacks */
|
||||
ot->exec = rigidbody_object_remove_exec;
|
||||
ot->poll = operator_rigidbody_active_poll;
|
||||
|
||||
/* flags */
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
}
|
||||
|
||||
/* ********************************************** */
|
||||
/* Selected Object Add/Remove Operators */
|
||||
|
||||
/* ************ Add Rigid Bodies ************** */
|
||||
|
||||
static wmOperatorStatus rigidbody_objects_add_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
Main *bmain = CTX_data_main(C);
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
eRigidBodyOb_Type type = eRigidBodyOb_Type(RNA_enum_get(op->ptr, "type"));
|
||||
bool changed = false;
|
||||
|
||||
/* create rigid body objects and add them to the world's group */
|
||||
CTX_DATA_BEGIN (C, Object *, ob, selected_objects) {
|
||||
changed |= ED_rigidbody_object_add(bmain, scene, ob, type, op->reports);
|
||||
}
|
||||
CTX_DATA_END;
|
||||
|
||||
if (changed) {
|
||||
/* send updates */
|
||||
WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, nullptr);
|
||||
WM_event_add_notifier(C, NC_OBJECT | ND_POINTCACHE, nullptr);
|
||||
|
||||
/* done */
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
void RIGIDBODY_OT_objects_add(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->idname = "RIGIDBODY_OT_objects_add";
|
||||
ot->name = "Add Rigid Bodies";
|
||||
ot->description = "Add selected objects as Rigid Bodies";
|
||||
|
||||
/* callbacks */
|
||||
ot->exec = rigidbody_objects_add_exec;
|
||||
ot->poll = operator_rigidbody_add_poll;
|
||||
|
||||
/* flags */
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
|
||||
/* properties */
|
||||
ot->prop = RNA_def_enum(ot->srna,
|
||||
"type",
|
||||
rna_enum_rigidbody_object_type_items,
|
||||
RBO_TYPE_ACTIVE,
|
||||
"Rigid Body Type",
|
||||
"");
|
||||
}
|
||||
|
||||
/* ************ Remove Rigid Bodies ************** */
|
||||
|
||||
static wmOperatorStatus rigidbody_objects_remove_exec(bContext *C, wmOperator * /*op*/)
|
||||
{
|
||||
Main *bmain = CTX_data_main(C);
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
bool changed = false;
|
||||
|
||||
/* apply this to all selected objects... */
|
||||
CTX_DATA_BEGIN (C, Object *, ob, selected_objects) {
|
||||
if (ob->rigidbody_object) {
|
||||
ED_rigidbody_object_remove(bmain, scene, ob);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
CTX_DATA_END;
|
||||
|
||||
if (changed) {
|
||||
/* send updates */
|
||||
WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, nullptr);
|
||||
WM_event_add_notifier(C, NC_OBJECT | ND_POINTCACHE, nullptr);
|
||||
|
||||
/* done */
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
void RIGIDBODY_OT_objects_remove(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->idname = "RIGIDBODY_OT_objects_remove";
|
||||
ot->name = "Remove Rigid Bodies";
|
||||
ot->description = "Remove selected objects from Rigid Body simulation";
|
||||
|
||||
/* callbacks */
|
||||
ot->exec = rigidbody_objects_remove_exec;
|
||||
ot->poll = operator_rigidbody_active_poll;
|
||||
|
||||
/* flags */
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
}
|
||||
|
||||
/* ********************************************** */
|
||||
/* Utility Operators */
|
||||
|
||||
/* ************ Change Collision Shapes ************** */
|
||||
|
||||
static wmOperatorStatus rigidbody_objects_shape_change_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
int shape = RNA_enum_get(op->ptr, "type");
|
||||
bool changed = false;
|
||||
|
||||
/* apply this to all selected objects... */
|
||||
CTX_DATA_BEGIN (C, Object *, ob, selected_objects) {
|
||||
if (ob->rigidbody_object) {
|
||||
/* use RNA-system to change the property and perform all necessary changes */
|
||||
PointerRNA ptr = RNA_pointer_create_discrete(
|
||||
&ob->id, RNA_RigidBodyObject, ob->rigidbody_object);
|
||||
RNA_enum_set(&ptr, "collision_shape", shape);
|
||||
|
||||
DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM);
|
||||
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
CTX_DATA_END;
|
||||
|
||||
if (changed) {
|
||||
/* send updates */
|
||||
WM_event_add_notifier(C, NC_OBJECT | ND_POINTCACHE, nullptr);
|
||||
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, nullptr);
|
||||
|
||||
/* done */
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
void RIGIDBODY_OT_shape_change(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->idname = "RIGIDBODY_OT_shape_change";
|
||||
ot->name = "Change Collision Shape";
|
||||
ot->description = "Change collision shapes for selected Rigid Body Objects";
|
||||
|
||||
/* callbacks */
|
||||
ot->invoke = WM_menu_invoke;
|
||||
ot->exec = rigidbody_objects_shape_change_exec;
|
||||
ot->poll = operator_rigidbody_active_poll;
|
||||
|
||||
/* flags */
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
|
||||
/* properties */
|
||||
ot->prop = RNA_def_enum(ot->srna,
|
||||
"type",
|
||||
rna_enum_rigidbody_object_shape_items,
|
||||
RB_SHAPE_TRIMESH,
|
||||
"Rigid Body Shape",
|
||||
"");
|
||||
}
|
||||
|
||||
/* ************ Calculate Mass ************** */
|
||||
|
||||
/* Entry in material density table */
|
||||
struct rbMaterialDensityItem {
|
||||
const char *name; /* Name of material */
|
||||
float density; /* Density (kg/m^3) */
|
||||
};
|
||||
|
||||
/* Preset density values for materials (kg/m^3)
|
||||
* Selected values obtained from:
|
||||
* 1) http://www.jaredzone.info/2010/09/densities.html
|
||||
* 2) http://www.avlandesign.com/density_construction.htm
|
||||
* 3) http://www.avlandesign.com/density_metal.htm
|
||||
*/
|
||||
static rbMaterialDensityItem RB_MATERIAL_DENSITY_TABLE[] = {
|
||||
{N_("Air"), 1.0f}, /* not quite; adapted from 1.43 for oxygen for use as default */
|
||||
{N_("Acrylic"), 1400.0f},
|
||||
{N_("Asphalt (Crushed)"), 721.0f},
|
||||
{N_("Bark"), 240.0f},
|
||||
{N_("Beans (Cocoa)"), 593.0f},
|
||||
{N_("Beans (Soy)"), 721.0f},
|
||||
{N_("Brick (Pressed)"), 2400.0f},
|
||||
{N_("Brick (Common)"), 2000.0f},
|
||||
{N_("Brick (Soft)"), 1600.0f},
|
||||
{N_("Brass"), 8216.0f},
|
||||
{N_("Bronze"), 8860.0f},
|
||||
{N_("Carbon (Solid)"), 2146.0f},
|
||||
{N_("Cardboard"), 689.0f},
|
||||
{N_("Cast Iron"), 7150.0f}, /* {N_("Cement"), 1442.0f}, */
|
||||
{N_("Chalk (Solid)"), 2499.0f}, /* {N_("Coffee (Fresh/Roast)"), ~500}, */
|
||||
{N_("Concrete"), 2320.0f},
|
||||
{N_("Charcoal"), 208.0f},
|
||||
{N_("Cork"), 240.0f},
|
||||
{N_("Copper"), 8933.0f},
|
||||
{N_("Garbage"), 481.0f},
|
||||
{N_("Glass (Broken)"), 1940.0f},
|
||||
{N_("Glass (Solid)"), 2190.0f},
|
||||
{N_("Gold"), 19282.0f},
|
||||
{N_("Granite (Broken)"), 1650.0f},
|
||||
{N_("Granite (Solid)"), 2691.0f},
|
||||
{N_("Gravel"), 2780.0f},
|
||||
{N_("Ice (Crushed)"), 593.0f},
|
||||
{N_("Ice (Solid)"), 919.0f},
|
||||
{N_("Iron"), 7874.0f},
|
||||
{N_("Lead"), 11342.0f},
|
||||
{N_("Limestone (Broken)"), 1554.0f},
|
||||
{N_("Limestone (Solid)"), 2611.0f},
|
||||
{N_("Marble (Broken)"), 1570.0f},
|
||||
{N_("Marble (Solid)"), 2563.0f},
|
||||
{N_("Paper"), 1201.0f},
|
||||
{N_("Peanuts (Shelled)"), 641.0f},
|
||||
{N_("Peanuts (Not Shelled)"), 272.0f},
|
||||
{N_("Plaster"), 849.0f},
|
||||
{N_("Plastic"), 1200.0f},
|
||||
{N_("Polystyrene"), 1050.0f},
|
||||
{N_("Rubber"), 1522.0f},
|
||||
{N_("Silver"), 10501.0f},
|
||||
{N_("Steel"), 7860.0f},
|
||||
{N_("Stone"), 2515.0f},
|
||||
{N_("Stone (Crushed)"), 1602.0f},
|
||||
{N_("Timber"), 610.0f},
|
||||
};
|
||||
static const int NUM_RB_MATERIAL_PRESETS = sizeof(RB_MATERIAL_DENSITY_TABLE) /
|
||||
sizeof(rbMaterialDensityItem);
|
||||
|
||||
/* dynamically generate list of items
|
||||
* - Although there is a runtime cost, this has a lower maintenance cost
|
||||
* in the long run than other two-list solutions...
|
||||
*/
|
||||
static const EnumPropertyItem *rigidbody_materials_itemf(bContext * /*C*/,
|
||||
PointerRNA * /*ptr*/,
|
||||
PropertyRNA * /*prop*/,
|
||||
bool *r_free)
|
||||
{
|
||||
EnumPropertyItem item_tmp = {0};
|
||||
EnumPropertyItem *item = nullptr;
|
||||
int totitem = 0;
|
||||
int i = 0;
|
||||
|
||||
/* add each preset to the list */
|
||||
for (i = 0; i < NUM_RB_MATERIAL_PRESETS; i++) {
|
||||
rbMaterialDensityItem *preset = &RB_MATERIAL_DENSITY_TABLE[i];
|
||||
|
||||
item_tmp.identifier = preset->name;
|
||||
item_tmp.name = IFACE_(preset->name);
|
||||
item_tmp.value = i;
|
||||
RNA_enum_item_add(&item, &totitem, &item_tmp);
|
||||
}
|
||||
|
||||
/* add special "custom" entry to the end of the list */
|
||||
{
|
||||
item_tmp.identifier = "Custom";
|
||||
item_tmp.name = IFACE_("Custom");
|
||||
item_tmp.value = -1;
|
||||
RNA_enum_item_add(&item, &totitem, &item_tmp);
|
||||
}
|
||||
|
||||
RNA_enum_item_end(&item, &totitem);
|
||||
*r_free = true;
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
/* ------------------------------------------ */
|
||||
|
||||
static wmOperatorStatus rigidbody_objects_calc_mass_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
|
||||
int material = RNA_enum_get(op->ptr, "material");
|
||||
float density;
|
||||
bool changed = false;
|
||||
|
||||
/* get density (kg/m^3) to apply */
|
||||
if (material >= 0) {
|
||||
/* get density from table, and store in props for later repeating */
|
||||
if (material >= NUM_RB_MATERIAL_PRESETS) {
|
||||
material = 0;
|
||||
}
|
||||
|
||||
density = RB_MATERIAL_DENSITY_TABLE[material].density;
|
||||
RNA_float_set(op->ptr, "density", density);
|
||||
}
|
||||
else {
|
||||
/* custom - grab from whatever value is set */
|
||||
density = RNA_float_get(op->ptr, "density");
|
||||
}
|
||||
|
||||
/* Apply this to all selected objects (with rigid-bodies). */
|
||||
CTX_DATA_BEGIN (C, Object *, ob, selected_objects) {
|
||||
if (ob->rigidbody_object) {
|
||||
float volume; /* m^3 */
|
||||
float mass; /* kg */
|
||||
|
||||
/* mass is calculated from the approximate volume of the object,
|
||||
* and the density of the material we're simulating
|
||||
*/
|
||||
Object *ob_eval = DEG_get_evaluated(depsgraph, ob);
|
||||
BKE_rigidbody_calc_volume(ob_eval, &volume);
|
||||
mass = volume * density;
|
||||
|
||||
/* use RNA-system to change the property and perform all necessary changes */
|
||||
PointerRNA ptr = RNA_pointer_create_discrete(
|
||||
&ob->id, RNA_RigidBodyObject, ob->rigidbody_object);
|
||||
RNA_float_set(&ptr, "mass", mass);
|
||||
|
||||
DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM);
|
||||
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
CTX_DATA_END;
|
||||
|
||||
if (changed) {
|
||||
/* send updates */
|
||||
WM_event_add_notifier(C, NC_OBJECT | ND_POINTCACHE, nullptr);
|
||||
|
||||
/* done */
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
static bool mass_calculate_poll_property(const bContext * /*C*/,
|
||||
wmOperator *op,
|
||||
const PropertyRNA *prop)
|
||||
{
|
||||
const char *prop_id = RNA_property_identifier(prop);
|
||||
|
||||
/* Disable density input when not using the 'Custom' preset. */
|
||||
if (STREQ(prop_id, "density")) {
|
||||
int material = RNA_enum_get(op->ptr, "material");
|
||||
if (material >= 0) {
|
||||
RNA_def_property_clear_flag(const_cast<PropertyRNA *>(prop), PROP_EDITABLE);
|
||||
}
|
||||
else {
|
||||
RNA_def_property_flag(const_cast<PropertyRNA *>(prop), PROP_EDITABLE);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void RIGIDBODY_OT_mass_calculate(wmOperatorType *ot)
|
||||
{
|
||||
PropertyRNA *prop;
|
||||
|
||||
/* identifiers */
|
||||
ot->idname = "RIGIDBODY_OT_mass_calculate";
|
||||
ot->name = "Calculate Mass";
|
||||
ot->description = "Automatically calculate mass values for Rigid Body Objects based on volume";
|
||||
|
||||
/* callbacks */
|
||||
ot->invoke = WM_menu_invoke; /* XXX */
|
||||
ot->exec = rigidbody_objects_calc_mass_exec;
|
||||
ot->poll = operator_rigidbody_active_poll;
|
||||
ot->poll_property = mass_calculate_poll_property;
|
||||
|
||||
/* flags */
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
|
||||
/* properties */
|
||||
ot->prop = prop = RNA_def_enum(
|
||||
ot->srna,
|
||||
"material",
|
||||
rna_enum_dummy_DEFAULT_items,
|
||||
0,
|
||||
"Material Preset",
|
||||
"Type of material that objects are made of (determines material density)");
|
||||
RNA_def_enum_funcs(prop, rigidbody_materials_itemf);
|
||||
RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE);
|
||||
|
||||
RNA_def_float(ot->srna,
|
||||
"density",
|
||||
1.0,
|
||||
FLT_MIN,
|
||||
FLT_MAX,
|
||||
"Density",
|
||||
"Density value (kg/m^3), allows custom value if the 'Custom' preset is used",
|
||||
1.0f,
|
||||
2500.0f);
|
||||
}
|
||||
|
||||
/* ********************************************** */
|
||||
|
||||
} // namespace blender
|
||||
205
blender-5.2.0/source/blender/editors/physics/rigidbody_world.cc
Normal file
205
blender-5.2.0/source/blender/editors/physics/rigidbody_world.cc
Normal file
@@ -0,0 +1,205 @@
|
||||
/* SPDX-FileCopyrightText: 2013 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup editor_physics
|
||||
* \brief Rigid Body world editing operators
|
||||
*/
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
#include "DNA_rigidbody_types.h"
|
||||
#include "DNA_scene_types.h"
|
||||
|
||||
#ifdef WITH_BULLET
|
||||
# include "RBI_api.h"
|
||||
#endif
|
||||
|
||||
#include "BKE_context.hh"
|
||||
#include "BKE_report.hh"
|
||||
#include "BKE_rigidbody.h"
|
||||
|
||||
#include "DEG_depsgraph.hh"
|
||||
#include "DEG_depsgraph_build.hh"
|
||||
|
||||
#include "RNA_access.hh"
|
||||
|
||||
#include "WM_api.hh"
|
||||
#include "WM_types.hh"
|
||||
|
||||
#include "ED_screen.hh"
|
||||
|
||||
#include "physics_intern.hh"
|
||||
|
||||
namespace blender {
|
||||
|
||||
/* ********************************************** */
|
||||
/* API */
|
||||
|
||||
/* check if there is an active rigid body world */
|
||||
static bool rigidbody_world_active_poll(bContext *C)
|
||||
{
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
return (scene && scene->rigidbody_world);
|
||||
}
|
||||
static bool rigidbody_world_add_poll(bContext *C)
|
||||
{
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
return (scene && scene->rigidbody_world == nullptr);
|
||||
}
|
||||
|
||||
/* ********************************************** */
|
||||
/* OPERATORS - Management */
|
||||
|
||||
/* ********** Add RigidBody World **************** */
|
||||
|
||||
static wmOperatorStatus rigidbody_world_add_exec(bContext *C, wmOperator * /*op*/)
|
||||
{
|
||||
Main *bmain = CTX_data_main(C);
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
RigidBodyWorld *rbw;
|
||||
|
||||
rbw = BKE_rigidbody_create_world(scene);
|
||||
// BKE_rigidbody_validate_sim_world(scene, rbw, false);
|
||||
scene->rigidbody_world = rbw;
|
||||
|
||||
/* Full rebuild of DEG! */
|
||||
DEG_relations_tag_update(bmain);
|
||||
DEG_id_tag_update_ex(bmain, &scene->id, ID_RECALC_ANIMATION);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
void RIGIDBODY_OT_world_add(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->idname = "RIGIDBODY_OT_world_add";
|
||||
ot->name = "Add Rigid Body World";
|
||||
ot->description = "Add Rigid Body simulation world to the current scene";
|
||||
|
||||
/* callbacks */
|
||||
ot->exec = rigidbody_world_add_exec;
|
||||
ot->poll = rigidbody_world_add_poll;
|
||||
|
||||
/* flags */
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
}
|
||||
|
||||
/* ********** Remove RigidBody World ************* */
|
||||
|
||||
static wmOperatorStatus rigidbody_world_remove_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
Main *bmain = CTX_data_main(C);
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
RigidBodyWorld *rbw = scene->rigidbody_world;
|
||||
|
||||
/* sanity checks */
|
||||
if (ELEM(nullptr, scene, rbw)) {
|
||||
BKE_report(op->reports, RPT_ERROR, "No Rigid Body World to remove");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
BKE_rigidbody_free_world(scene);
|
||||
|
||||
/* Full rebuild of DEG! */
|
||||
DEG_relations_tag_update(bmain);
|
||||
DEG_id_tag_update_ex(bmain, &scene->id, ID_RECALC_ANIMATION);
|
||||
|
||||
/* done */
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
void RIGIDBODY_OT_world_remove(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->idname = "RIGIDBODY_OT_world_remove";
|
||||
ot->name = "Remove Rigid Body World";
|
||||
ot->description = "Remove Rigid Body simulation world from the current scene";
|
||||
|
||||
/* callbacks */
|
||||
ot->exec = rigidbody_world_remove_exec;
|
||||
ot->poll = rigidbody_world_active_poll;
|
||||
|
||||
/* flags */
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
}
|
||||
|
||||
/* ********************************************** */
|
||||
/* UTILITY OPERATORS */
|
||||
|
||||
/* ********** Export RigidBody World ************* */
|
||||
|
||||
static wmOperatorStatus rigidbody_world_export_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
RigidBodyWorld *rbw = scene->rigidbody_world;
|
||||
char filepath[FILE_MAX];
|
||||
|
||||
/* sanity checks */
|
||||
if (ELEM(nullptr, scene, rbw)) {
|
||||
BKE_report(op->reports, RPT_ERROR, "No Rigid Body World to export");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
rbDynamicsWorld *physics_world = BKE_rigidbody_world_physics(rbw);
|
||||
if (physics_world == nullptr) {
|
||||
BKE_report(
|
||||
op->reports, RPT_ERROR, "Rigid Body World has no associated physics data to export");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
RNA_string_get(op->ptr, "filepath", filepath);
|
||||
#ifdef WITH_BULLET
|
||||
RB_dworld_export(physics_world, filepath);
|
||||
#endif
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
static wmOperatorStatus rigidbody_world_export_invoke(bContext *C,
|
||||
wmOperator *op,
|
||||
const wmEvent * /*event*/)
|
||||
{
|
||||
if (!RNA_struct_property_is_set(op->ptr, "relative_path")) {
|
||||
RNA_boolean_set(op->ptr, "relative_path", (U.flag & USER_RELPATHS) != 0);
|
||||
}
|
||||
|
||||
if (RNA_struct_property_is_set(op->ptr, "filepath")) {
|
||||
return rigidbody_world_export_exec(C, op);
|
||||
}
|
||||
|
||||
/* TODO: use the actual rigidbody world's name + .bullet instead of this temp crap */
|
||||
RNA_string_set(op->ptr, "filepath", "rigidbodyworld_export.bullet");
|
||||
WM_event_add_fileselect(C, op);
|
||||
|
||||
return OPERATOR_RUNNING_MODAL;
|
||||
}
|
||||
|
||||
void RIGIDBODY_OT_world_export(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->idname = "RIGIDBODY_OT_world_export";
|
||||
ot->name = "Export Rigid Body World";
|
||||
ot->description =
|
||||
"Export Rigid Body world to the simulator's own file-format "
|
||||
"(i.e. '.bullet' for Bullet Physics)";
|
||||
|
||||
/* callbacks */
|
||||
ot->invoke = rigidbody_world_export_invoke;
|
||||
ot->exec = rigidbody_world_export_exec;
|
||||
ot->poll = rigidbody_world_active_poll;
|
||||
|
||||
/* flags */
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
|
||||
/* properties */
|
||||
WM_operator_properties_filesel(ot,
|
||||
FILE_TYPE_FOLDER,
|
||||
FILE_SPECIAL,
|
||||
FILE_SAVE,
|
||||
WM_FILESEL_RELPATH,
|
||||
FILE_DEFAULTDISPLAY,
|
||||
FILE_SORT_DEFAULT);
|
||||
}
|
||||
|
||||
} // namespace blender
|
||||
Reference in New Issue
Block a user