Files
test/source/blender/modifiers/intern/MOD_particlesystem.cc
Damien Picard 3bd41cf9bc I18n: Go over TIP_ and IFACE_ usages, change to RPT_ when relevant
The previous commit introduced a new `RPT_()` macro to translate
strings which are not tooltips or regular interface elements, but
longer reports or statuses.

This commit uses the new macro to translate many strings all over the
UI.

Most of it is a simple replace from `TIP_()` or `IFACE_()` to
`RPT_()`, but there are some additional changes:
- A few translations inside `BKE_report()` are removed altogether
  because they are already handled by the translation system.
- Messages inside `UI_but_disable()` are no longer translated
  manually, but they are handled by a new regex in the translation
  system.

Pull Request: https://projects.blender.org/blender/blender/pulls/116804

Pull Request: https://projects.blender.org/blender/blender/pulls/116804
2024-01-12 13:37:32 +01:00

300 lines
9.6 KiB
C++

/* SPDX-FileCopyrightText: 2005 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup modifiers
*/
#include <cstddef>
#include <cstring>
#include "BLI_utildefines.h"
#include "BLT_translation.h"
#include "DNA_defaults.h"
#include "DNA_material_types.h"
#include "DNA_mesh_types.h"
#include "DNA_screen_types.h"
#include "BKE_context.hh"
#include "BKE_editmesh.hh"
#include "BKE_lib_id.h"
#include "BKE_mesh.hh"
#include "BKE_mesh_legacy_convert.hh"
#include "BKE_modifier.hh"
#include "BKE_particle.h"
#include "BKE_screen.hh"
#include "UI_interface.hh"
#include "UI_resources.hh"
#include "RNA_access.hh"
#include "RNA_prototypes.h"
#include "DEG_depsgraph_query.hh"
#include "BLO_read_write.hh"
#include "MOD_ui_common.hh"
#include "MOD_util.hh"
static void init_data(ModifierData *md)
{
ParticleSystemModifierData *psmd = (ParticleSystemModifierData *)md;
BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(psmd, modifier));
MEMCPY_STRUCT_AFTER(psmd, DNA_struct_default_get(ParticleSystemModifierData), modifier);
}
static void free_data(ModifierData *md)
{
ParticleSystemModifierData *psmd = (ParticleSystemModifierData *)md;
if (psmd->mesh_final) {
BKE_id_free(nullptr, psmd->mesh_final);
psmd->mesh_final = nullptr;
if (psmd->mesh_original) {
BKE_id_free(nullptr, psmd->mesh_original);
psmd->mesh_original = nullptr;
}
}
psmd->totdmvert = psmd->totdmedge = psmd->totdmface = 0;
/* ED_object_modifier_remove may have freed this first before calling
* BKE_modifier_free (which calls this function) */
if (psmd->psys) {
psmd->psys->flag |= PSYS_DELETE;
}
}
static void copy_data(const ModifierData *md, ModifierData *target, const int flag)
{
#if 0
const ParticleSystemModifierData *psmd = (const ParticleSystemModifierData *)md;
#endif
ParticleSystemModifierData *tpsmd = (ParticleSystemModifierData *)target;
BKE_modifier_copydata_generic(md, target, flag);
/* NOTE: `psys` pointer here is just copied over from `md` to `target`. This is dangerous, as it
* will generate invalid data in case we are copying between different objects. Extra external
* code has to be called then to ensure proper remapping of that pointer. See e.g.
* `BKE_object_copy_particlesystems` or `BKE_object_copy_modifier`. */
tpsmd->mesh_final = nullptr;
tpsmd->mesh_original = nullptr;
tpsmd->totdmvert = tpsmd->totdmedge = tpsmd->totdmface = 0;
}
static void required_data_mask(ModifierData *md, CustomData_MeshMasks *r_cddata_masks)
{
ParticleSystemModifierData *psmd = (ParticleSystemModifierData *)md;
psys_emitter_customdata_mask(psmd->psys, r_cddata_masks);
}
/* saves the current emitter state for a particle system and calculates particles */
static void deform_verts(ModifierData *md,
const ModifierEvalContext *ctx,
Mesh *mesh,
blender::MutableSpan<blender::float3> positions)
{
ParticleSystemModifierData *psmd = (ParticleSystemModifierData *)md;
ParticleSystem *psys = nullptr;
if (ctx->object->particlesystem.first) {
psys = psmd->psys;
}
else {
return;
}
if (!psys_check_enabled(ctx->object, psys, (ctx->flag & MOD_APPLY_RENDER) != 0)) {
return;
}
/* Clear old evaluated mesh. */
bool had_mesh_final = (psmd->mesh_final != nullptr);
if (psmd->mesh_final) {
BKE_id_free(nullptr, psmd->mesh_final);
psmd->mesh_final = nullptr;
if (psmd->mesh_original) {
BKE_id_free(nullptr, psmd->mesh_original);
psmd->mesh_original = nullptr;
}
}
else if (psmd->flag & eParticleSystemFlag_file_loaded) {
/* in file read mesh just wasn't saved in file so no need to reset everything */
psmd->flag &= ~eParticleSystemFlag_file_loaded;
if (psys->particles == nullptr) {
psys->recalc |= ID_RECALC_PSYS_RESET;
}
/* TODO(sergey): This is not how particles were working prior to copy on
* write, but now evaluation is similar to case when one duplicates the
* object. In that case particles were doing reset here.
*
* Don't do reset when entering particle edit mode, as that will destroy the edit mode data.
* Shouldn't be an issue, since particles are supposed to be evaluated once prior to entering
* edit mode anyway.
* Could in theory be an issue when everything is done in a script, but then solution is
* not known to me. */
if (ctx->object->mode != OB_MODE_PARTICLE_EDIT) {
psys->recalc |= ID_RECALC_PSYS_RESET;
}
}
/* make new mesh */
psmd->mesh_final = BKE_mesh_copy_for_eval(mesh);
psmd->mesh_final->vert_positions_for_write().copy_from(positions);
psmd->mesh_final->tag_positions_changed();
BKE_mesh_tessface_ensure(psmd->mesh_final);
if (!psmd->mesh_final->runtime->deformed_only) {
/* Get the original mesh from the object, this is what the particles
* are attached to so in case of non-deform modifiers we need to remap
* them to the final mesh (typically subdivision surfaces). */
Mesh *mesh_original = nullptr;
if (ctx->object->type == OB_MESH) {
BMEditMesh *em = BKE_editmesh_from_object(ctx->object);
if (em) {
/* In edit mode get directly from the edit mesh. */
psmd->mesh_original = BKE_mesh_from_bmesh_for_eval_nomain(em->bm, nullptr, mesh);
}
else {
/* Otherwise get regular mesh. */
mesh_original = static_cast<Mesh *>(ctx->object->data);
}
}
else {
mesh_original = mesh;
}
if (mesh_original) {
/* Make a persistent copy of the mesh. We don't actually need
* all this data, just some topology for remapping. Could be
* optimized once. */
psmd->mesh_original = BKE_mesh_copy_for_eval(mesh_original);
}
BKE_mesh_tessface_ensure(psmd->mesh_original);
}
/* Report change in mesh structure.
* This is an unreliable check for the topology check, but allows some
* handy configuration like emitting particles from inside particle
* instance. */
if (had_mesh_final && (psmd->mesh_final->verts_num != psmd->totdmvert ||
psmd->mesh_final->edges_num != psmd->totdmedge ||
psmd->mesh_final->totface_legacy != psmd->totdmface))
{
psys->recalc |= ID_RECALC_PSYS_RESET;
}
psmd->totdmvert = psmd->mesh_final->verts_num;
psmd->totdmedge = psmd->mesh_final->edges_num;
psmd->totdmface = psmd->mesh_final->totface_legacy;
{
Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph);
psmd->flag &= ~eParticleSystemFlag_psys_updated;
particle_system_update(
ctx->depsgraph, scene, ctx->object, psys, (ctx->flag & MOD_APPLY_RENDER) != 0);
psmd->flag |= eParticleSystemFlag_psys_updated;
}
if (DEG_is_active(ctx->depsgraph)) {
Object *object_orig = DEG_get_original_object(ctx->object);
ModifierData *md_orig = BKE_modifiers_findby_name(object_orig, psmd->modifier.name);
BLI_assert(md_orig != nullptr);
ParticleSystemModifierData *psmd_orig = (ParticleSystemModifierData *)md_orig;
psmd_orig->flag = psmd->flag;
}
}
static void panel_draw(const bContext * /*C*/, Panel *panel)
{
uiLayout *layout = panel->layout;
PointerRNA ob_ptr;
PointerRNA *ptr = modifier_panel_get_property_pointers(panel, &ob_ptr);
Object *ob = static_cast<Object *>(ob_ptr.data);
ModifierData *md = (ModifierData *)ptr->data;
ParticleSystem *psys = ((ParticleSystemModifierData *)md)->psys;
uiItemL(layout, RPT_("Settings are in the particle tab"), ICON_NONE);
if (!(ob->mode & OB_MODE_PARTICLE_EDIT)) {
if (ELEM(psys->part->ren_as, PART_DRAW_GR, PART_DRAW_OB)) {
uiItemO(layout,
CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Make Instances Real"),
ICON_NONE,
"OBJECT_OT_duplicates_make_real");
}
else if (psys->part->ren_as == PART_DRAW_PATH) {
uiItemO(layout,
CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Convert to Mesh"),
ICON_NONE,
"OBJECT_OT_modifier_convert");
}
}
modifier_panel_end(layout, ptr);
}
static void panel_register(ARegionType *region_type)
{
modifier_panel_register(region_type, eModifierType_ParticleSystem, panel_draw);
}
static void blend_read(BlendDataReader *reader, ModifierData *md)
{
ParticleSystemModifierData *psmd = (ParticleSystemModifierData *)md;
psmd->mesh_final = nullptr;
psmd->mesh_original = nullptr;
/* This is written as part of ob->particlesystem. */
BLO_read_data_address(reader, &psmd->psys);
psmd->flag &= ~eParticleSystemFlag_psys_updated;
psmd->flag |= eParticleSystemFlag_file_loaded;
}
ModifierTypeInfo modifierType_ParticleSystem = {
/*idname*/ "ParticleSystem",
/*name*/ N_("ParticleSystem"),
/*struct_name*/ "ParticleSystemModifierData",
/*struct_size*/ sizeof(ParticleSystemModifierData),
/*srna*/ &RNA_ParticleSystemModifier,
/*type*/ ModifierTypeType::OnlyDeform,
/*flags*/ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_SupportsMapping |
eModifierTypeFlag_UsesPointCache,
/*icon*/ ICON_MOD_PARTICLES,
/*copy_data*/ copy_data,
/*deform_verts*/ deform_verts,
/*deform_matrices*/ nullptr,
/*deform_verts_EM*/ nullptr,
/*deform_matrices_EM*/ nullptr,
/*modify_mesh*/ nullptr,
/*modify_geometry_set*/ nullptr,
/*init_data*/ init_data,
/*required_data_mask*/ required_data_mask,
/*free_data*/ free_data,
/*is_disabled*/ nullptr,
/*update_depsgraph*/ nullptr,
/*depends_on_time*/ nullptr,
/*depends_on_normals*/ nullptr,
/*foreach_ID_link*/ nullptr,
/*foreach_tex_link*/ nullptr,
/*free_runtime_data*/ nullptr,
/*panel_register*/ panel_register,
/*blend_write*/ nullptr,
/*blend_read*/ blend_read,
};