182 lines
6.8 KiB
C++
182 lines
6.8 KiB
C++
/* SPDX-FileCopyrightText: 2024 Blender Authors
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
|
|
/** \file
|
|
* \ingroup overlay
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include "BKE_anim_path.h"
|
|
|
|
#include "BLI_math_rotation.h"
|
|
|
|
#include "DNA_object_force_types.h"
|
|
|
|
#include "overlay_base.hh"
|
|
|
|
namespace blender::draw::overlay {
|
|
|
|
/**
|
|
* Draw force fields.
|
|
* Controlled by (Physics > Force Field)
|
|
*/
|
|
class ForceFields : Overlay {
|
|
using ForceFieldsInstanceBuf = ShapeInstanceBuf<ExtraInstanceData>;
|
|
|
|
private:
|
|
PassSimple ps_ = {"ForceFields"};
|
|
|
|
struct CallBuffers {
|
|
const SelectionType selection_type_;
|
|
|
|
ForceFieldsInstanceBuf field_force_buf = {selection_type_, "field_force_buf"};
|
|
ForceFieldsInstanceBuf field_wind_buf = {selection_type_, "field_wind_buf"};
|
|
ForceFieldsInstanceBuf field_vortex_buf = {selection_type_, "field_vortex_buf"};
|
|
ForceFieldsInstanceBuf field_curve_buf = {selection_type_, "field_curve_buf"};
|
|
ForceFieldsInstanceBuf field_sphere_limit_buf = {selection_type_, "field_sphere_limit_buf"};
|
|
ForceFieldsInstanceBuf field_tube_limit_buf = {selection_type_, "field_tube_limit_buf"};
|
|
ForceFieldsInstanceBuf field_cone_limit_buf = {selection_type_, "field_cone_limit_buf"};
|
|
} call_buffers_;
|
|
|
|
public:
|
|
ForceFields(const SelectionType selection_type) : call_buffers_{selection_type} {}
|
|
|
|
void begin_sync(Resources & /*res*/, const State & /*state*/) final
|
|
{
|
|
call_buffers_.field_force_buf.clear();
|
|
call_buffers_.field_wind_buf.clear();
|
|
call_buffers_.field_vortex_buf.clear();
|
|
call_buffers_.field_curve_buf.clear();
|
|
call_buffers_.field_sphere_limit_buf.clear();
|
|
call_buffers_.field_tube_limit_buf.clear();
|
|
call_buffers_.field_cone_limit_buf.clear();
|
|
}
|
|
|
|
void object_sync(Manager & /*manager*/,
|
|
const ObjectRef &ob_ref,
|
|
Resources &res,
|
|
const State &state) final
|
|
{
|
|
if (!ob_ref.object->pd || !ob_ref.object->pd->forcefield) {
|
|
return;
|
|
}
|
|
const select::ID select_id = res.select_id(ob_ref);
|
|
const Object *ob = ob_ref.object;
|
|
PartDeflect *pd = ob->pd;
|
|
Curve *cu = (ob->type == OB_CURVES_LEGACY) ? &DRW_object_get_data_for_drawing<Curve>(*ob) :
|
|
nullptr;
|
|
|
|
ExtraInstanceData data(
|
|
ob->object_to_world(), res.object_background_blend_color(ob_ref, state), 1.0f);
|
|
float4x4 &matrix = data.object_to_world;
|
|
float &size_x = matrix[0][3];
|
|
float &size_y = matrix[1][3];
|
|
float &size_z = matrix[2][3];
|
|
|
|
size_x = size_y = size_z = ob->empty_drawsize;
|
|
|
|
switch (pd->forcefield) {
|
|
case PFIELD_FORCE:
|
|
call_buffers_.field_force_buf.append(data, select_id);
|
|
break;
|
|
case PFIELD_WIND:
|
|
size_z = pd->f_strength;
|
|
call_buffers_.field_wind_buf.append(data, select_id);
|
|
break;
|
|
case PFIELD_VORTEX:
|
|
size_y = (pd->f_strength < 0.0f) ? -size_y : size_y;
|
|
call_buffers_.field_vortex_buf.append(data, select_id);
|
|
break;
|
|
case PFIELD_GUIDE:
|
|
if (cu && (cu->flag & CU_PATH) && ob->runtime->curve_cache->anim_path_accum_length) {
|
|
size_x = size_y = size_z = pd->f_strength;
|
|
float4 pos;
|
|
BKE_where_on_path(ob, 0.0f, pos, nullptr, nullptr, nullptr, nullptr);
|
|
matrix.location() = ob->object_to_world().location();
|
|
matrix = math::translate(matrix, pos.xyz());
|
|
call_buffers_.field_curve_buf.append(data, select_id);
|
|
|
|
BKE_where_on_path(ob, 1.0f, pos, nullptr, nullptr, nullptr, nullptr);
|
|
matrix.location() = ob->object_to_world().location();
|
|
matrix = math::translate(matrix, pos.xyz());
|
|
call_buffers_.field_sphere_limit_buf.append(data, select_id);
|
|
/* Restore */
|
|
matrix.location() = ob->object_to_world().location();
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (pd->falloff == PFIELD_FALL_TUBE) {
|
|
if (pd->flag & (PFIELD_USEMAX | PFIELD_USEMAXR)) {
|
|
size_z = (pd->flag & PFIELD_USEMAX) ? pd->maxdist : 0.0f;
|
|
size_x = (pd->flag & PFIELD_USEMAXR) ? pd->maxrad : 1.0f;
|
|
size_y = size_x;
|
|
call_buffers_.field_tube_limit_buf.append(data, select_id);
|
|
}
|
|
if (pd->flag & (PFIELD_USEMIN | PFIELD_USEMINR)) {
|
|
size_z = (pd->flag & PFIELD_USEMIN) ? pd->mindist : 0.0f;
|
|
size_x = (pd->flag & PFIELD_USEMINR) ? pd->minrad : 1.0f;
|
|
size_y = size_x;
|
|
call_buffers_.field_tube_limit_buf.append(data, select_id);
|
|
}
|
|
}
|
|
else if (pd->falloff == PFIELD_FALL_CONE) {
|
|
if (pd->flag & (PFIELD_USEMAX | PFIELD_USEMAXR)) {
|
|
float radius = DEG2RADF((pd->flag & PFIELD_USEMAXR) ? pd->maxrad : 1.0f);
|
|
float distance = (pd->flag & PFIELD_USEMAX) ? pd->maxdist : 0.0f;
|
|
size_x = distance * sinf(radius);
|
|
size_z = distance * cosf(radius);
|
|
size_y = size_x;
|
|
call_buffers_.field_cone_limit_buf.append(data, select_id);
|
|
}
|
|
if (pd->flag & (PFIELD_USEMIN | PFIELD_USEMINR)) {
|
|
float radius = DEG2RADF((pd->flag & PFIELD_USEMINR) ? pd->minrad : 1.0f);
|
|
float distance = (pd->flag & PFIELD_USEMIN) ? pd->mindist : 0.0f;
|
|
size_x = distance * sinf(radius);
|
|
size_z = distance * cosf(radius);
|
|
size_y = size_x;
|
|
call_buffers_.field_cone_limit_buf.append(data, select_id);
|
|
}
|
|
}
|
|
else if (pd->falloff == PFIELD_FALL_SPHERE) {
|
|
if (pd->flag & PFIELD_USEMAX) {
|
|
size_x = size_y = size_z = pd->maxdist;
|
|
call_buffers_.field_sphere_limit_buf.append(data, select_id);
|
|
}
|
|
if (pd->flag & PFIELD_USEMIN) {
|
|
size_x = size_y = size_z = pd->mindist;
|
|
call_buffers_.field_sphere_limit_buf.append(data, select_id);
|
|
}
|
|
}
|
|
}
|
|
|
|
void end_sync(Resources &res, const State &state) final
|
|
{
|
|
ps_.init();
|
|
res.select_bind(ps_);
|
|
ps_.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL,
|
|
state.clipping_plane_count);
|
|
ps_.shader_set(res.shaders->extra_shape.get());
|
|
ps_.bind_ubo(OVERLAY_GLOBALS_SLOT, &res.globals_buf);
|
|
ps_.bind_ubo(DRW_CLIPPING_UBO_SLOT, &res.clip_planes_buf);
|
|
|
|
call_buffers_.field_force_buf.end_sync(ps_, res.shapes.field_force.get());
|
|
call_buffers_.field_wind_buf.end_sync(ps_, res.shapes.field_wind.get());
|
|
call_buffers_.field_vortex_buf.end_sync(ps_, res.shapes.field_vortex.get());
|
|
call_buffers_.field_curve_buf.end_sync(ps_, res.shapes.field_curve.get());
|
|
call_buffers_.field_sphere_limit_buf.end_sync(ps_, res.shapes.field_sphere_limit.get());
|
|
call_buffers_.field_tube_limit_buf.end_sync(ps_, res.shapes.field_tube_limit.get());
|
|
call_buffers_.field_cone_limit_buf.end_sync(ps_, res.shapes.field_cone_limit.get());
|
|
}
|
|
|
|
void draw_line(Framebuffer &framebuffer, Manager &manager, View &view) final
|
|
{
|
|
GPU_framebuffer_bind(framebuffer);
|
|
manager.submit(ps_, view);
|
|
}
|
|
};
|
|
|
|
} // namespace blender::draw::overlay
|