Curves: Changes to the new curves data-block
This patch refactors the "Hair" data-block, which will soon be renamed to "Curves". The larger change is switching from an array of `HairCurve` to find indices in the points array to simply storing an array of offsets. Using a single integer instead of two halves the amount of memory for that particular array. Besides that, there are some other changes in this patch: - Split the data-structure to a separate `CurveGeometry` DNA struct so it is usable for grease pencil too. - Update naming to be more aligned with newer code and the style guide. - Add direct access to some arrays in RNA -- Radius is now retrieved as a regular attribute in Cycles. -- `HairPoint` has been renamed to `CurvePoint` -- `HairCurve` has been renamed to `CurveSlice` - Add comments to the struct in DNA. The next steps are renaming `Hair` -> `Curves`, and adding support for other curve types: Bezier, Poly, and NURBS. Ref T95355 Differential Revision: https://developer.blender.org/D13987
This commit is contained in:
parent
2f591adc1a
commit
f59767ff97
|
@ -14,6 +14,8 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
#include "blender/sync.h"
|
#include "blender/sync.h"
|
||||||
#include "blender/util.h"
|
#include "blender/util.h"
|
||||||
|
|
||||||
|
@ -625,14 +627,35 @@ void BlenderSync::sync_particle_hair(
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef WITH_HAIR_NODES
|
#ifdef WITH_HAIR_NODES
|
||||||
static float4 hair_point_as_float4(BL::HairPoint b_point)
|
|
||||||
|
static std::optional<BL::FloatAttribute> find_curves_radius_attribute(BL::Hair b_hair)
|
||||||
{
|
{
|
||||||
float4 mP = float3_to_float4(get_float3(b_point.co()));
|
for (BL::Attribute &b_attribute : b_hair.attributes) {
|
||||||
mP.w = b_point.radius();
|
if (b_attribute.name() != "radius") {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (b_attribute.domain() != BL::Attribute::domain_POINT) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (b_attribute.data_type() != BL::Attribute::data_type_FLOAT) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
return BL::FloatAttribute{b_attribute};
|
||||||
|
}
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
static float4 hair_point_as_float4(BL::Hair b_hair,
|
||||||
|
std::optional<BL::FloatAttribute> b_attr_radius,
|
||||||
|
const int index)
|
||||||
|
{
|
||||||
|
float4 mP = float3_to_float4(get_float3(b_hair.position_data[index].vector()));
|
||||||
|
mP.w = b_attr_radius ? b_attr_radius->data[index].value() : 0.0f;
|
||||||
return mP;
|
return mP;
|
||||||
}
|
}
|
||||||
|
|
||||||
static float4 interpolate_hair_points(BL::Hair b_hair,
|
static float4 interpolate_hair_points(BL::Hair b_hair,
|
||||||
|
std::optional<BL::FloatAttribute> b_attr_radius,
|
||||||
const int first_point_index,
|
const int first_point_index,
|
||||||
const int num_points,
|
const int num_points,
|
||||||
const float step)
|
const float step)
|
||||||
|
@ -641,8 +664,8 @@ static float4 interpolate_hair_points(BL::Hair b_hair,
|
||||||
const int point_a = clamp((int)curve_t, 0, num_points - 1);
|
const int point_a = clamp((int)curve_t, 0, num_points - 1);
|
||||||
const int point_b = min(point_a + 1, num_points - 1);
|
const int point_b = min(point_a + 1, num_points - 1);
|
||||||
const float t = curve_t - (float)point_a;
|
const float t = curve_t - (float)point_a;
|
||||||
return lerp(hair_point_as_float4(b_hair.points[first_point_index + point_a]),
|
return lerp(hair_point_as_float4(b_hair, b_attr_radius, first_point_index + point_a),
|
||||||
hair_point_as_float4(b_hair.points[first_point_index + point_b]),
|
hair_point_as_float4(b_hair, b_attr_radius, first_point_index + point_b),
|
||||||
t);
|
t);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -671,12 +694,14 @@ static void export_hair_curves(Scene *scene, Hair *hair, BL::Hair b_hair)
|
||||||
|
|
||||||
hair->reserve_curves(num_curves, num_keys);
|
hair->reserve_curves(num_curves, num_keys);
|
||||||
|
|
||||||
|
std::optional<BL::FloatAttribute> b_attr_radius = find_curves_radius_attribute(b_hair);
|
||||||
|
|
||||||
/* Export curves and points. */
|
/* Export curves and points. */
|
||||||
vector<float> points_length;
|
vector<float> points_length;
|
||||||
|
|
||||||
for (BL::HairCurve &b_curve : b_hair.curves) {
|
for (int i = 0; i < num_curves; i++) {
|
||||||
const int first_point_index = b_curve.first_point_index();
|
const int first_point_index = b_hair.curve_offset_data[i].value();
|
||||||
const int num_points = b_curve.num_points();
|
const int num_points = b_hair.curve_offset_data[i + 1].value() - first_point_index;
|
||||||
|
|
||||||
float3 prev_co = zero_float3();
|
float3 prev_co = zero_float3();
|
||||||
float length = 0.0f;
|
float length = 0.0f;
|
||||||
|
@ -687,10 +712,9 @@ static void export_hair_curves(Scene *scene, Hair *hair, BL::Hair b_hair)
|
||||||
|
|
||||||
/* Position and radius. */
|
/* Position and radius. */
|
||||||
for (int i = 0; i < num_points; i++) {
|
for (int i = 0; i < num_points; i++) {
|
||||||
BL::HairPoint b_point = b_hair.points[first_point_index + i];
|
const float3 co = get_float3(b_hair.position_data[first_point_index + i].vector());
|
||||||
|
const float radius = b_attr_radius ? b_attr_radius->data[first_point_index + i].value() :
|
||||||
const float3 co = get_float3(b_point.co());
|
0.0f;
|
||||||
const float radius = b_point.radius();
|
|
||||||
hair->add_curve_key(co, radius);
|
hair->add_curve_key(co, radius);
|
||||||
|
|
||||||
if (attr_intercept) {
|
if (attr_intercept) {
|
||||||
|
@ -715,7 +739,7 @@ static void export_hair_curves(Scene *scene, Hair *hair, BL::Hair b_hair)
|
||||||
|
|
||||||
/* Random number per curve. */
|
/* Random number per curve. */
|
||||||
if (attr_random != NULL) {
|
if (attr_random != NULL) {
|
||||||
attr_random->add(hash_uint2_to_float(b_curve.index(), 0));
|
attr_random->add(hash_uint2_to_float(i, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Curve. */
|
/* Curve. */
|
||||||
|
@ -737,14 +761,17 @@ static void export_hair_curves_motion(Hair *hair, BL::Hair b_hair, int motion_st
|
||||||
|
|
||||||
/* Export motion keys. */
|
/* Export motion keys. */
|
||||||
const int num_keys = hair->get_curve_keys().size();
|
const int num_keys = hair->get_curve_keys().size();
|
||||||
|
const int num_curves = b_hair.curves.length();
|
||||||
float4 *mP = attr_mP->data_float4() + motion_step * num_keys;
|
float4 *mP = attr_mP->data_float4() + motion_step * num_keys;
|
||||||
bool have_motion = false;
|
bool have_motion = false;
|
||||||
int num_motion_keys = 0;
|
int num_motion_keys = 0;
|
||||||
int curve_index = 0;
|
int curve_index = 0;
|
||||||
|
|
||||||
for (BL::HairCurve &b_curve : b_hair.curves) {
|
std::optional<BL::FloatAttribute> b_attr_radius = find_curves_radius_attribute(b_hair);
|
||||||
const int first_point_index = b_curve.first_point_index();
|
|
||||||
const int num_points = b_curve.num_points();
|
for (int i = 0; i < num_curves; i++) {
|
||||||
|
const int first_point_index = b_hair.curve_offset_data[i].value();
|
||||||
|
const int num_points = b_hair.curve_offset_data[i + 1].value() - first_point_index;
|
||||||
|
|
||||||
Hair::Curve curve = hair->get_curve(curve_index);
|
Hair::Curve curve = hair->get_curve(curve_index);
|
||||||
curve_index++;
|
curve_index++;
|
||||||
|
@ -755,7 +782,7 @@ static void export_hair_curves_motion(Hair *hair, BL::Hair b_hair, int motion_st
|
||||||
int point_index = first_point_index + i;
|
int point_index = first_point_index + i;
|
||||||
|
|
||||||
if (point_index < num_keys) {
|
if (point_index < num_keys) {
|
||||||
mP[num_motion_keys] = hair_point_as_float4(b_hair.points[point_index]);
|
mP[num_motion_keys] = hair_point_as_float4(b_hair, b_attr_radius, point_index);
|
||||||
num_motion_keys++;
|
num_motion_keys++;
|
||||||
|
|
||||||
if (!have_motion) {
|
if (!have_motion) {
|
||||||
|
@ -774,7 +801,8 @@ static void export_hair_curves_motion(Hair *hair, BL::Hair b_hair, int motion_st
|
||||||
const float step_size = curve.num_keys > 1 ? 1.0f / (curve.num_keys - 1) : 0.0f;
|
const float step_size = curve.num_keys > 1 ? 1.0f / (curve.num_keys - 1) : 0.0f;
|
||||||
for (int i = 0; i < curve.num_keys; i++) {
|
for (int i = 0; i < curve.num_keys; i++) {
|
||||||
const float step = i * step_size;
|
const float step = i * step_size;
|
||||||
mP[num_motion_keys] = interpolate_hair_points(b_hair, first_point_index, num_points, step);
|
mP[num_motion_keys] = interpolate_hair_points(
|
||||||
|
b_hair, b_attr_radius, first_point_index, num_points, step);
|
||||||
num_motion_keys++;
|
num_motion_keys++;
|
||||||
}
|
}
|
||||||
have_motion = true;
|
have_motion = true;
|
||||||
|
|
|
@ -90,10 +90,10 @@ static void get_domains(const ID *id, DomainInfo info[ATTR_DOMAIN_NUM])
|
||||||
}
|
}
|
||||||
case ID_HA: {
|
case ID_HA: {
|
||||||
Hair *hair = (Hair *)id;
|
Hair *hair = (Hair *)id;
|
||||||
info[ATTR_DOMAIN_POINT].customdata = &hair->pdata;
|
info[ATTR_DOMAIN_POINT].customdata = &hair->geometry.point_data;
|
||||||
info[ATTR_DOMAIN_POINT].length = hair->totpoint;
|
info[ATTR_DOMAIN_POINT].length = hair->geometry.point_size;
|
||||||
info[ATTR_DOMAIN_CURVE].customdata = &hair->cdata;
|
info[ATTR_DOMAIN_CURVE].customdata = &hair->geometry.curve_data;
|
||||||
info[ATTR_DOMAIN_CURVE].length = hair->totcurve;
|
info[ATTR_DOMAIN_CURVE].length = hair->geometry.curve_size;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -1793,10 +1793,10 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
|
||||||
{sizeof(float[3]), "vec3f", 1, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
{sizeof(float[3]), "vec3f", 1, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||||
/* 44: CD_RADIUS */
|
/* 44: CD_RADIUS */
|
||||||
{sizeof(float), "MFloatProperty", 1, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
{sizeof(float), "MFloatProperty", 1, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||||
/* 45: CD_HAIRCURVE */
|
/* 45: CD_HAIRCURVE */ /* DEPRECATED */
|
||||||
{sizeof(HairCurve), "HairCurve", 1, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
{-1, "HairCurve", 1, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||||
/* 46: CD_HAIRMAPPING */
|
/* 46: CD_HAIRMAPPING */ /* DEPRECATED */
|
||||||
{sizeof(HairMapping), "HairMapping", 1, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
{-1, "HairMapping", 1, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||||
/* 47: CD_PROP_COLOR */
|
/* 47: CD_PROP_COLOR */
|
||||||
{sizeof(MPropCol),
|
{sizeof(MPropCol),
|
||||||
"MPropCol",
|
"MPropCol",
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
#include "DNA_material_types.h"
|
#include "DNA_material_types.h"
|
||||||
#include "DNA_object_types.h"
|
#include "DNA_object_types.h"
|
||||||
|
|
||||||
|
#include "BLI_index_range.hh"
|
||||||
#include "BLI_listbase.h"
|
#include "BLI_listbase.h"
|
||||||
#include "BLI_math_base.h"
|
#include "BLI_math_base.h"
|
||||||
#include "BLI_math_vec_types.hh"
|
#include "BLI_math_vec_types.hh"
|
||||||
|
@ -54,6 +55,8 @@
|
||||||
#include "BLO_read_write.h"
|
#include "BLO_read_write.h"
|
||||||
|
|
||||||
using blender::float3;
|
using blender::float3;
|
||||||
|
using blender::IndexRange;
|
||||||
|
using blender::MutableSpan;
|
||||||
using blender::RandomNumberGenerator;
|
using blender::RandomNumberGenerator;
|
||||||
|
|
||||||
static const char *HAIR_ATTR_POSITION = "position";
|
static const char *HAIR_ATTR_POSITION = "position";
|
||||||
|
@ -70,14 +73,22 @@ static void hair_init_data(ID *id)
|
||||||
|
|
||||||
MEMCPY_STRUCT_AFTER(hair, DNA_struct_default_get(Hair), id);
|
MEMCPY_STRUCT_AFTER(hair, DNA_struct_default_get(Hair), id);
|
||||||
|
|
||||||
CustomData_reset(&hair->pdata);
|
CustomData_reset(&hair->geometry.point_data);
|
||||||
CustomData_reset(&hair->cdata);
|
CustomData_reset(&hair->geometry.curve_data);
|
||||||
|
|
||||||
|
CustomData_add_layer_named(&hair->geometry.point_data,
|
||||||
|
CD_PROP_FLOAT3,
|
||||||
|
CD_CALLOC,
|
||||||
|
nullptr,
|
||||||
|
hair->geometry.point_size,
|
||||||
|
HAIR_ATTR_POSITION);
|
||||||
|
CustomData_add_layer_named(&hair->geometry.point_data,
|
||||||
|
CD_PROP_FLOAT,
|
||||||
|
CD_CALLOC,
|
||||||
|
nullptr,
|
||||||
|
hair->geometry.point_size,
|
||||||
|
HAIR_ATTR_RADIUS);
|
||||||
|
|
||||||
CustomData_add_layer_named(
|
|
||||||
&hair->pdata, CD_PROP_FLOAT3, CD_CALLOC, nullptr, hair->totpoint, HAIR_ATTR_POSITION);
|
|
||||||
CustomData_add_layer_named(
|
|
||||||
&hair->pdata, CD_PROP_FLOAT, CD_CALLOC, nullptr, hair->totpoint, HAIR_ATTR_RADIUS);
|
|
||||||
CustomData_add_layer(&hair->cdata, CD_HAIRCURVE, CD_CALLOC, nullptr, hair->totcurve);
|
|
||||||
BKE_hair_update_customdata_pointers(hair);
|
BKE_hair_update_customdata_pointers(hair);
|
||||||
|
|
||||||
hair_random(hair);
|
hair_random(hair);
|
||||||
|
@ -89,11 +100,24 @@ static void hair_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_src, co
|
||||||
const Hair *hair_src = (const Hair *)id_src;
|
const Hair *hair_src = (const Hair *)id_src;
|
||||||
hair_dst->mat = static_cast<Material **>(MEM_dupallocN(hair_src->mat));
|
hair_dst->mat = static_cast<Material **>(MEM_dupallocN(hair_src->mat));
|
||||||
|
|
||||||
|
hair_dst->geometry.point_size = hair_src->geometry.point_size;
|
||||||
|
hair_dst->geometry.curve_size = hair_src->geometry.curve_size;
|
||||||
|
|
||||||
const eCDAllocType alloc_type = (flag & LIB_ID_COPY_CD_REFERENCE) ? CD_REFERENCE : CD_DUPLICATE;
|
const eCDAllocType alloc_type = (flag & LIB_ID_COPY_CD_REFERENCE) ? CD_REFERENCE : CD_DUPLICATE;
|
||||||
CustomData_copy(&hair_src->pdata, &hair_dst->pdata, CD_MASK_ALL, alloc_type, hair_dst->totpoint);
|
CustomData_copy(&hair_src->geometry.point_data,
|
||||||
CustomData_copy(&hair_src->cdata, &hair_dst->cdata, CD_MASK_ALL, alloc_type, hair_dst->totcurve);
|
&hair_dst->geometry.point_data,
|
||||||
|
CD_MASK_ALL,
|
||||||
|
alloc_type,
|
||||||
|
hair_dst->geometry.point_size);
|
||||||
|
CustomData_copy(&hair_src->geometry.curve_data,
|
||||||
|
&hair_dst->geometry.curve_data,
|
||||||
|
CD_MASK_ALL,
|
||||||
|
alloc_type,
|
||||||
|
hair_dst->geometry.curve_size);
|
||||||
BKE_hair_update_customdata_pointers(hair_dst);
|
BKE_hair_update_customdata_pointers(hair_dst);
|
||||||
|
|
||||||
|
hair_dst->geometry.offsets = static_cast<int *>(MEM_dupallocN(hair_src->geometry.offsets));
|
||||||
|
|
||||||
hair_dst->batch_cache = nullptr;
|
hair_dst->batch_cache = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,8 +128,10 @@ static void hair_free_data(ID *id)
|
||||||
|
|
||||||
BKE_hair_batch_cache_free(hair);
|
BKE_hair_batch_cache_free(hair);
|
||||||
|
|
||||||
CustomData_free(&hair->pdata, hair->totpoint);
|
CustomData_free(&hair->geometry.point_data, hair->geometry.point_size);
|
||||||
CustomData_free(&hair->cdata, hair->totcurve);
|
CustomData_free(&hair->geometry.curve_data, hair->geometry.curve_size);
|
||||||
|
|
||||||
|
MEM_SAFE_FREE(hair->geometry.offsets);
|
||||||
|
|
||||||
MEM_SAFE_FREE(hair->mat);
|
MEM_SAFE_FREE(hair->mat);
|
||||||
}
|
}
|
||||||
|
@ -124,16 +150,30 @@ static void hair_blend_write(BlendWriter *writer, ID *id, const void *id_address
|
||||||
|
|
||||||
CustomDataLayer *players = nullptr, players_buff[CD_TEMP_CHUNK_SIZE];
|
CustomDataLayer *players = nullptr, players_buff[CD_TEMP_CHUNK_SIZE];
|
||||||
CustomDataLayer *clayers = nullptr, clayers_buff[CD_TEMP_CHUNK_SIZE];
|
CustomDataLayer *clayers = nullptr, clayers_buff[CD_TEMP_CHUNK_SIZE];
|
||||||
CustomData_blend_write_prepare(&hair->pdata, &players, players_buff, ARRAY_SIZE(players_buff));
|
CustomData_blend_write_prepare(
|
||||||
CustomData_blend_write_prepare(&hair->cdata, &clayers, clayers_buff, ARRAY_SIZE(clayers_buff));
|
&hair->geometry.point_data, &players, players_buff, ARRAY_SIZE(players_buff));
|
||||||
|
CustomData_blend_write_prepare(
|
||||||
|
&hair->geometry.curve_data, &clayers, clayers_buff, ARRAY_SIZE(clayers_buff));
|
||||||
|
|
||||||
/* Write LibData */
|
/* Write LibData */
|
||||||
BLO_write_id_struct(writer, Hair, id_address, &hair->id);
|
BLO_write_id_struct(writer, Hair, id_address, &hair->id);
|
||||||
BKE_id_blend_write(writer, &hair->id);
|
BKE_id_blend_write(writer, &hair->id);
|
||||||
|
|
||||||
/* Direct data */
|
/* Direct data */
|
||||||
CustomData_blend_write(writer, &hair->pdata, players, hair->totpoint, CD_MASK_ALL, &hair->id);
|
CustomData_blend_write(writer,
|
||||||
CustomData_blend_write(writer, &hair->cdata, clayers, hair->totcurve, CD_MASK_ALL, &hair->id);
|
&hair->geometry.point_data,
|
||||||
|
players,
|
||||||
|
hair->geometry.point_size,
|
||||||
|
CD_MASK_ALL,
|
||||||
|
&hair->id);
|
||||||
|
CustomData_blend_write(writer,
|
||||||
|
&hair->geometry.curve_data,
|
||||||
|
clayers,
|
||||||
|
hair->geometry.curve_size,
|
||||||
|
CD_MASK_ALL,
|
||||||
|
&hair->id);
|
||||||
|
|
||||||
|
BLO_write_int32_array(writer, hair->geometry.curve_size + 1, hair->geometry.offsets);
|
||||||
|
|
||||||
BLO_write_pointer_array(writer, hair->totcol, hair->mat);
|
BLO_write_pointer_array(writer, hair->totcol, hair->mat);
|
||||||
if (hair->adt) {
|
if (hair->adt) {
|
||||||
|
@ -156,10 +196,12 @@ static void hair_blend_read_data(BlendDataReader *reader, ID *id)
|
||||||
BKE_animdata_blend_read_data(reader, hair->adt);
|
BKE_animdata_blend_read_data(reader, hair->adt);
|
||||||
|
|
||||||
/* Geometry */
|
/* Geometry */
|
||||||
CustomData_blend_read(reader, &hair->pdata, hair->totpoint);
|
CustomData_blend_read(reader, &hair->geometry.point_data, hair->geometry.point_size);
|
||||||
CustomData_blend_read(reader, &hair->cdata, hair->totcurve);
|
CustomData_blend_read(reader, &hair->geometry.curve_data, hair->geometry.point_size);
|
||||||
BKE_hair_update_customdata_pointers(hair);
|
BKE_hair_update_customdata_pointers(hair);
|
||||||
|
|
||||||
|
BLO_read_int32_array(reader, hair->geometry.curve_size + 1, &hair->geometry.offsets);
|
||||||
|
|
||||||
/* Materials */
|
/* Materials */
|
||||||
BLO_read_pointer_array(reader, (void **)&hair->mat);
|
BLO_read_pointer_array(reader, (void **)&hair->mat);
|
||||||
}
|
}
|
||||||
|
@ -212,38 +254,48 @@ IDTypeInfo IDType_ID_HA = {
|
||||||
|
|
||||||
static void hair_random(Hair *hair)
|
static void hair_random(Hair *hair)
|
||||||
{
|
{
|
||||||
|
CurvesGeometry &geometry = hair->geometry;
|
||||||
const int numpoints = 8;
|
const int numpoints = 8;
|
||||||
|
|
||||||
hair->totcurve = 500;
|
geometry.curve_size = 500;
|
||||||
hair->totpoint = hair->totcurve * numpoints;
|
|
||||||
|
|
||||||
CustomData_realloc(&hair->pdata, hair->totpoint);
|
geometry.curve_size = 500;
|
||||||
CustomData_realloc(&hair->cdata, hair->totcurve);
|
geometry.point_size = geometry.curve_size * numpoints;
|
||||||
|
|
||||||
|
hair->geometry.offsets = (int *)MEM_calloc_arrayN(
|
||||||
|
hair->geometry.curve_size + 1, sizeof(int), __func__);
|
||||||
|
CustomData_realloc(&geometry.point_data, geometry.point_size);
|
||||||
|
CustomData_realloc(&geometry.curve_data, geometry.curve_size);
|
||||||
BKE_hair_update_customdata_pointers(hair);
|
BKE_hair_update_customdata_pointers(hair);
|
||||||
|
|
||||||
|
MutableSpan<int> offsets{geometry.offsets, geometry.curve_size + 1};
|
||||||
|
MutableSpan<float3> positions{(float3 *)geometry.position, geometry.point_size};
|
||||||
|
MutableSpan<float> radii{geometry.radius, geometry.point_size};
|
||||||
|
|
||||||
|
for (const int i : offsets.index_range()) {
|
||||||
|
geometry.offsets[i] = numpoints * i;
|
||||||
|
}
|
||||||
|
|
||||||
RandomNumberGenerator rng;
|
RandomNumberGenerator rng;
|
||||||
|
|
||||||
for (int i = 0; i < hair->totcurve; i++) {
|
for (int i = 0; i < geometry.curve_size; i++) {
|
||||||
HairCurve *curve = &hair->curves[i];
|
const IndexRange curve_range(offsets[i], offsets[i + 1] - offsets[i]);
|
||||||
curve->firstpoint = i * numpoints;
|
MutableSpan<float3> curve_positions = positions.slice(curve_range);
|
||||||
curve->numpoints = numpoints;
|
MutableSpan<float> curve_radii = radii.slice(curve_range);
|
||||||
|
|
||||||
const float theta = 2.0f * M_PI * rng.get_float();
|
const float theta = 2.0f * M_PI * rng.get_float();
|
||||||
const float phi = saacosf(2.0f * rng.get_float() - 1.0f);
|
const float phi = saacosf(2.0f * rng.get_float() - 1.0f);
|
||||||
|
|
||||||
float3 no = {std::sin(theta) * std::sin(phi), std::cos(theta) * std::sin(phi), std::cos(phi)};
|
float3 no = {std::sin(theta) * std::sin(phi), std::cos(theta) * std::sin(phi), std::cos(phi)};
|
||||||
blender::math::normalize(no);
|
no = blender::math::normalize(no);
|
||||||
|
|
||||||
float(*curve_positions)[3] = hair->co + curve->firstpoint;
|
|
||||||
float *curve_radii = hair->radius + curve->firstpoint;
|
|
||||||
float3 co = no;
|
float3 co = no;
|
||||||
for (int key = 0; key < numpoints; key++) {
|
for (int key = 0; key < numpoints; key++) {
|
||||||
float t = key / (float)(numpoints - 1);
|
float t = key / (float)(numpoints - 1);
|
||||||
copy_v3_v3(curve_positions[key], co);
|
curve_positions[key] = co;
|
||||||
curve_radii[key] = 0.02f * (1.0f - t);
|
curve_radii[key] = 0.02f * (1.0f - t);
|
||||||
|
|
||||||
float3 offset = float3(rng.get_float(), rng.get_float(), rng.get_float()) * 2.0f - 1.0f;
|
float3 offset = float3(rng.get_float(), rng.get_float(), rng.get_float()) * 2.0f - 1.0f;
|
||||||
|
|
||||||
co += (offset + no) / numpoints;
|
co += (offset + no) / numpoints;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -271,9 +323,9 @@ BoundBox *BKE_hair_boundbox_get(Object *ob)
|
||||||
float min[3], max[3];
|
float min[3], max[3];
|
||||||
INIT_MINMAX(min, max);
|
INIT_MINMAX(min, max);
|
||||||
|
|
||||||
float(*hair_co)[3] = hair->co;
|
float(*hair_co)[3] = hair->geometry.position;
|
||||||
float *hair_radius = hair->radius;
|
float *hair_radius = hair->geometry.radius;
|
||||||
for (int a = 0; a < hair->totpoint; a++) {
|
for (int a = 0; a < hair->geometry.point_size; a++) {
|
||||||
float *co = hair_co[a];
|
float *co = hair_co[a];
|
||||||
float radius = (hair_radius) ? hair_radius[a] : 0.0f;
|
float radius = (hair_radius) ? hair_radius[a] : 0.0f;
|
||||||
const float co_min[3] = {co[0] - radius, co[1] - radius, co[2] - radius};
|
const float co_min[3] = {co[0] - radius, co[1] - radius, co[2] - radius};
|
||||||
|
@ -290,12 +342,10 @@ BoundBox *BKE_hair_boundbox_get(Object *ob)
|
||||||
|
|
||||||
void BKE_hair_update_customdata_pointers(Hair *hair)
|
void BKE_hair_update_customdata_pointers(Hair *hair)
|
||||||
{
|
{
|
||||||
hair->co = (float(*)[3])CustomData_get_layer_named(
|
hair->geometry.position = (float(*)[3])CustomData_get_layer_named(
|
||||||
&hair->pdata, CD_PROP_FLOAT3, HAIR_ATTR_POSITION);
|
&hair->geometry.point_data, CD_PROP_FLOAT3, HAIR_ATTR_POSITION);
|
||||||
hair->radius = (float *)CustomData_get_layer_named(
|
hair->geometry.radius = (float *)CustomData_get_layer_named(
|
||||||
&hair->pdata, CD_PROP_FLOAT, HAIR_ATTR_RADIUS);
|
&hair->geometry.point_data, CD_PROP_FLOAT, HAIR_ATTR_RADIUS);
|
||||||
hair->curves = (HairCurve *)CustomData_get_layer(&hair->cdata, CD_HAIRCURVE);
|
|
||||||
hair->mapping = (HairMaping *)CustomData_get_layer(&hair->cdata, CD_HAIRMAPPING);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BKE_hair_customdata_required(Hair *UNUSED(hair), CustomDataLayer *layer)
|
bool BKE_hair_customdata_required(Hair *UNUSED(hair), CustomDataLayer *layer)
|
||||||
|
@ -313,10 +363,18 @@ Hair *BKE_hair_new_for_eval(const Hair *hair_src, int totpoint, int totcurve)
|
||||||
hair_dst->mat = static_cast<Material **>(MEM_dupallocN(hair_src->mat));
|
hair_dst->mat = static_cast<Material **>(MEM_dupallocN(hair_src->mat));
|
||||||
hair_dst->totcol = hair_src->totcol;
|
hair_dst->totcol = hair_src->totcol;
|
||||||
|
|
||||||
hair_dst->totpoint = totpoint;
|
hair_dst->geometry.point_size = totpoint;
|
||||||
hair_dst->totcurve = totcurve;
|
hair_dst->geometry.curve_size = totcurve;
|
||||||
CustomData_copy(&hair_src->pdata, &hair_dst->pdata, CD_MASK_ALL, CD_CALLOC, totpoint);
|
CustomData_copy(&hair_src->geometry.point_data,
|
||||||
CustomData_copy(&hair_src->cdata, &hair_dst->cdata, CD_MASK_ALL, CD_CALLOC, totcurve);
|
&hair_dst->geometry.point_data,
|
||||||
|
CD_MASK_ALL,
|
||||||
|
CD_CALLOC,
|
||||||
|
totpoint);
|
||||||
|
CustomData_copy(&hair_src->geometry.curve_data,
|
||||||
|
&hair_dst->geometry.curve_data,
|
||||||
|
CD_MASK_ALL,
|
||||||
|
CD_CALLOC,
|
||||||
|
totcurve);
|
||||||
BKE_hair_update_customdata_pointers(hair_dst);
|
BKE_hair_update_customdata_pointers(hair_dst);
|
||||||
|
|
||||||
return hair_dst;
|
return hair_dst;
|
||||||
|
@ -368,12 +426,14 @@ static Hair *hair_evaluate_modifiers(struct Depsgraph *depsgraph,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Ensure we are not overwriting referenced data. */
|
/* Ensure we are not overwriting referenced data. */
|
||||||
CustomData_duplicate_referenced_layer_named(
|
CustomData_duplicate_referenced_layer_named(&hair->geometry.point_data,
|
||||||
&hair->pdata, CD_PROP_FLOAT3, HAIR_ATTR_POSITION, hair->totpoint);
|
CD_PROP_FLOAT3,
|
||||||
|
HAIR_ATTR_POSITION,
|
||||||
|
hair->geometry.point_size);
|
||||||
BKE_hair_update_customdata_pointers(hair);
|
BKE_hair_update_customdata_pointers(hair);
|
||||||
|
|
||||||
/* Created deformed coordinates array on demand. */
|
/* Created deformed coordinates array on demand. */
|
||||||
mti->deformVerts(md, &mectx, nullptr, hair->co, hair->totpoint);
|
mti->deformVerts(md, &mectx, nullptr, hair->geometry.position, hair->geometry.point_size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1122,7 +1122,7 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain)
|
||||||
|
|
||||||
/* Hair and PointCloud attributes. */
|
/* Hair and PointCloud attributes. */
|
||||||
for (Hair *hair = bmain->hairs.first; hair != NULL; hair = hair->id.next) {
|
for (Hair *hair = bmain->hairs.first; hair != NULL; hair = hair->id.next) {
|
||||||
do_versions_point_attributes(&hair->pdata);
|
do_versions_point_attributes(&hair->geometry.point_data);
|
||||||
}
|
}
|
||||||
for (PointCloud *pointcloud = bmain->pointclouds.first; pointcloud != NULL;
|
for (PointCloud *pointcloud = bmain->pointclouds.first; pointcloud != NULL;
|
||||||
pointcloud = pointcloud->id.next) {
|
pointcloud = pointcloud->id.next) {
|
||||||
|
@ -1424,7 +1424,7 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain)
|
||||||
|
|
||||||
/* Hair and PointCloud attributes names. */
|
/* Hair and PointCloud attributes names. */
|
||||||
LISTBASE_FOREACH (Hair *, hair, &bmain->hairs) {
|
LISTBASE_FOREACH (Hair *, hair, &bmain->hairs) {
|
||||||
do_versions_point_attribute_names(&hair->pdata);
|
do_versions_point_attribute_names(&hair->geometry.point_data);
|
||||||
}
|
}
|
||||||
LISTBASE_FOREACH (PointCloud *, pointcloud, &bmain->pointclouds) {
|
LISTBASE_FOREACH (PointCloud *, pointcloud, &bmain->pointclouds) {
|
||||||
do_versions_point_attribute_names(&pointcloud->pdata);
|
do_versions_point_attribute_names(&pointcloud->pdata);
|
||||||
|
|
|
@ -29,7 +29,10 @@
|
||||||
|
|
||||||
#include "BLI_listbase.h"
|
#include "BLI_listbase.h"
|
||||||
#include "BLI_math_base.h"
|
#include "BLI_math_base.h"
|
||||||
|
#include "BLI_math_vec_types.hh"
|
||||||
#include "BLI_math_vector.h"
|
#include "BLI_math_vector.h"
|
||||||
|
#include "BLI_math_vector.hh"
|
||||||
|
#include "BLI_span.hh"
|
||||||
#include "BLI_utildefines.h"
|
#include "BLI_utildefines.h"
|
||||||
|
|
||||||
#include "DNA_hair_types.h"
|
#include "DNA_hair_types.h"
|
||||||
|
@ -44,6 +47,10 @@
|
||||||
#include "draw_cache_impl.h" /* own include */
|
#include "draw_cache_impl.h" /* own include */
|
||||||
#include "draw_hair_private.h" /* own include */
|
#include "draw_hair_private.h" /* own include */
|
||||||
|
|
||||||
|
using blender::float3;
|
||||||
|
using blender::IndexRange;
|
||||||
|
using blender::Span;
|
||||||
|
|
||||||
static void hair_batch_cache_clear(Hair *hair);
|
static void hair_batch_cache_clear(Hair *hair);
|
||||||
|
|
||||||
/* ---------------------------------------------------------------------- */
|
/* ---------------------------------------------------------------------- */
|
||||||
|
@ -131,17 +138,9 @@ static void ensure_seg_pt_count(Hair *hair, ParticleHairCache *hair_cache)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
hair_cache->strands_len = 0;
|
hair_cache->strands_len = hair->geometry.curve_size;
|
||||||
hair_cache->elems_len = 0;
|
hair_cache->elems_len = hair->geometry.point_size + hair->geometry.curve_size;
|
||||||
hair_cache->point_len = 0;
|
hair_cache->point_len = hair->geometry.point_size;
|
||||||
|
|
||||||
HairCurve *curve = hair->curves;
|
|
||||||
int num_curves = hair->totcurve;
|
|
||||||
for (int i = 0; i < num_curves; i++, curve++) {
|
|
||||||
hair_cache->strands_len++;
|
|
||||||
hair_cache->elems_len += curve->numpoints + 1;
|
|
||||||
hair_cache->point_len += curve->numpoints;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void hair_batch_cache_fill_segments_proc_pos(Hair *hair,
|
static void hair_batch_cache_fill_segments_proc_pos(Hair *hair,
|
||||||
|
@ -149,30 +148,36 @@ static void hair_batch_cache_fill_segments_proc_pos(Hair *hair,
|
||||||
GPUVertBufRaw *length_step)
|
GPUVertBufRaw *length_step)
|
||||||
{
|
{
|
||||||
/* TODO: use hair radius layer if available. */
|
/* TODO: use hair radius layer if available. */
|
||||||
HairCurve *curve = hair->curves;
|
const int curve_size = hair->geometry.curve_size;
|
||||||
int num_curves = hair->totcurve;
|
Span<int> offsets{hair->geometry.offsets, hair->geometry.curve_size + 1};
|
||||||
for (int i = 0; i < num_curves; i++, curve++) {
|
|
||||||
float(*curve_co)[3] = hair->co + curve->firstpoint;
|
Span<float3> positions{(float3 *)hair->geometry.position, hair->geometry.point_size};
|
||||||
|
|
||||||
|
for (const int i : IndexRange(curve_size)) {
|
||||||
|
const IndexRange curve_range(offsets[i], offsets[i + 1] - offsets[i]);
|
||||||
|
|
||||||
|
Span<float3> spline_positions = positions.slice(curve_range);
|
||||||
float total_len = 0.0f;
|
float total_len = 0.0f;
|
||||||
float *co_prev = nullptr, *seg_data_first;
|
float *seg_data_first;
|
||||||
for (int j = 0; j < curve->numpoints; j++) {
|
for (const int i_spline : spline_positions.index_range()) {
|
||||||
float *seg_data = (float *)GPU_vertbuf_raw_step(attr_step);
|
float *seg_data = (float *)GPU_vertbuf_raw_step(attr_step);
|
||||||
copy_v3_v3(seg_data, curve_co[j]);
|
copy_v3_v3(seg_data, spline_positions[i_spline]);
|
||||||
if (co_prev) {
|
if (i_spline == 0) {
|
||||||
total_len += len_v3v3(co_prev, curve_co[j]);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
seg_data_first = seg_data;
|
seg_data_first = seg_data;
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
total_len += blender::math::distance(spline_positions[i_spline - 1],
|
||||||
|
spline_positions[i_spline]);
|
||||||
|
}
|
||||||
seg_data[3] = total_len;
|
seg_data[3] = total_len;
|
||||||
co_prev = curve_co[j];
|
|
||||||
}
|
}
|
||||||
/* Assign length value. */
|
/* Assign length value. */
|
||||||
*(float *)GPU_vertbuf_raw_step(length_step) = total_len;
|
*(float *)GPU_vertbuf_raw_step(length_step) = total_len;
|
||||||
if (total_len > 0.0f) {
|
if (total_len > 0.0f) {
|
||||||
/* Divide by total length to have a [0-1] number. */
|
/* Divide by total length to have a [0-1] number. */
|
||||||
for (int j = 0; j < curve->numpoints; j++, seg_data_first += 4) {
|
for ([[maybe_unused]] const int i_spline : spline_positions.index_range()) {
|
||||||
seg_data_first[3] /= total_len;
|
seg_data_first[3] /= total_len;
|
||||||
|
seg_data_first += 4;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -226,11 +231,14 @@ static void hair_batch_cache_fill_strands_data(Hair *hair,
|
||||||
GPUVertBufRaw *data_step,
|
GPUVertBufRaw *data_step,
|
||||||
GPUVertBufRaw *seg_step)
|
GPUVertBufRaw *seg_step)
|
||||||
{
|
{
|
||||||
HairCurve *curve = hair->curves;
|
const int curve_size = hair->geometry.curve_size;
|
||||||
int num_curves = hair->totcurve;
|
Span<int> offsets{hair->geometry.offsets, hair->geometry.curve_size + 1};
|
||||||
for (int i = 0; i < num_curves; i++, curve++) {
|
|
||||||
*(uint *)GPU_vertbuf_raw_step(data_step) = curve->firstpoint;
|
for (const int i : IndexRange(curve_size)) {
|
||||||
*(ushort *)GPU_vertbuf_raw_step(seg_step) = curve->numpoints - 1;
|
const IndexRange curve_range(offsets[i], offsets[i + 1] - offsets[i]);
|
||||||
|
|
||||||
|
*(uint *)GPU_vertbuf_raw_step(data_step) = curve_range.start();
|
||||||
|
*(ushort *)GPU_vertbuf_raw_step(seg_step) = curve_range.size() - 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -289,10 +297,11 @@ static void hair_batch_cache_fill_segments_indices(Hair *hair,
|
||||||
const int res,
|
const int res,
|
||||||
GPUIndexBufBuilder *elb)
|
GPUIndexBufBuilder *elb)
|
||||||
{
|
{
|
||||||
HairCurve *curve = hair->curves;
|
const int curve_size = hair->geometry.curve_size;
|
||||||
int num_curves = hair->totcurve;
|
|
||||||
uint curr_point = 0;
|
uint curr_point = 0;
|
||||||
for (int i = 0; i < num_curves; i++, curve++) {
|
|
||||||
|
for ([[maybe_unused]] const int i : IndexRange(curve_size)) {
|
||||||
for (int k = 0; k < res; k++) {
|
for (int k = 0; k < res; k++) {
|
||||||
GPU_indexbuf_add_generic_vert(elb, curr_point++);
|
GPU_indexbuf_add_generic_vert(elb, curr_point++);
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,48 +27,71 @@
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef struct HairCurve {
|
/**
|
||||||
/* Index of first point of hair curve. */
|
* A reusable data structure for geometry consisting of many curves. All control point data is
|
||||||
int firstpoint;
|
* stored contiguously for better efficiency. Data for each curve is stored as a slice of the
|
||||||
/* Number of points in hair curve, must be 2 or higher. */
|
* main #point_data array.
|
||||||
int numpoints;
|
*
|
||||||
} HairCurve;
|
* The data structure is meant to be embedded in other data-blocks to allow reusing
|
||||||
|
* curve-processing algorithms for multiple Blender data-block types.
|
||||||
|
*/
|
||||||
|
typedef struct CurvesGeometry {
|
||||||
|
/**
|
||||||
|
* A runtime pointer to the "position" attribute data.
|
||||||
|
* \note This data is owned by #point_data.
|
||||||
|
*/
|
||||||
|
float (*position)[3];
|
||||||
|
/**
|
||||||
|
* A runtime pointer to the "radius" attribute data.
|
||||||
|
* \note This data is owned by #point_data.
|
||||||
|
*/
|
||||||
|
float *radius;
|
||||||
|
|
||||||
/* Hair attachment to a mesh.
|
/**
|
||||||
* TODO: attach to tessellated triangles or polygons?
|
* The start index of each curve in the point data. The size of each curve can be calculated by
|
||||||
* TODO: what type of interpolation to use for uv? */
|
* subtracting the offset from the next offset. That is valid even for the last curve because
|
||||||
typedef struct HairMapping {
|
* this array is allocated with a length one larger than the number of splines.
|
||||||
float uv[2];
|
*
|
||||||
int poly;
|
* \note This is *not* stored in #CustomData because its size is one larger than #curve_data.
|
||||||
} HairMapping;
|
*/
|
||||||
|
int *offsets;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* All attributes stored on control points (#ATTR_DOMAIN_POINT).
|
||||||
|
*/
|
||||||
|
CustomData point_data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* All attributes stored on curves (#ATTR_DOMAIN_CURVE).
|
||||||
|
*/
|
||||||
|
CustomData curve_data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The total number of control points in all curves.
|
||||||
|
*/
|
||||||
|
int point_size;
|
||||||
|
/**
|
||||||
|
* The number of curves in the data-block.
|
||||||
|
*/
|
||||||
|
int curve_size;
|
||||||
|
} CurvesGeometry;
|
||||||
|
|
||||||
typedef struct Hair {
|
typedef struct Hair {
|
||||||
ID id;
|
ID id;
|
||||||
struct AnimData *adt; /* animation data (must be immediately after id) */
|
/* Animation data (must be immediately after id). */
|
||||||
|
struct AnimData *adt;
|
||||||
|
|
||||||
|
CurvesGeometry geometry;
|
||||||
|
|
||||||
int flag;
|
int flag;
|
||||||
int _pad1[1];
|
|
||||||
|
|
||||||
/* Geometry */
|
|
||||||
float (*co)[3];
|
|
||||||
float *radius;
|
|
||||||
struct HairCurve *curves;
|
|
||||||
struct HairMaping *mapping;
|
|
||||||
int totpoint;
|
|
||||||
int totcurve;
|
|
||||||
|
|
||||||
/* Custom Data */
|
|
||||||
struct CustomData pdata;
|
|
||||||
struct CustomData cdata;
|
|
||||||
int attributes_active_index;
|
int attributes_active_index;
|
||||||
int _pad3;
|
|
||||||
|
|
||||||
/* Material */
|
/* Materials. */
|
||||||
struct Material **mat;
|
struct Material **mat;
|
||||||
short totcol;
|
short totcol;
|
||||||
short _pad2[3];
|
short _pad2[3];
|
||||||
|
|
||||||
/* Draw Cache */
|
/* Draw Cache. */
|
||||||
void *batch_cache;
|
void *batch_cache;
|
||||||
} Hair;
|
} Hair;
|
||||||
|
|
||||||
|
|
|
@ -47,71 +47,97 @@ static Hair *rna_hair(PointerRNA *ptr)
|
||||||
return (Hair *)ptr->owner_id;
|
return (Hair *)ptr->owner_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int rna_HairPoint_index_get(PointerRNA *ptr)
|
static int rna_Hair_curve_offset_data_length(PointerRNA *ptr)
|
||||||
|
{
|
||||||
|
const Hair *curves = rna_hair(ptr);
|
||||||
|
return curves->geometry.curve_size + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rna_Hair_curve_offset_data_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
|
||||||
|
{
|
||||||
|
const Hair *curves = rna_hair(ptr);
|
||||||
|
rna_iterator_array_begin(iter,
|
||||||
|
(void *)curves->geometry.offsets,
|
||||||
|
sizeof(int),
|
||||||
|
curves->geometry.curve_size + 1,
|
||||||
|
false,
|
||||||
|
NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rna_CurvePoint_index_get(PointerRNA *ptr)
|
||||||
{
|
{
|
||||||
const Hair *hair = rna_hair(ptr);
|
const Hair *hair = rna_hair(ptr);
|
||||||
const float(*co)[3] = ptr->data;
|
const float(*co)[3] = ptr->data;
|
||||||
return (int)(co - hair->co);
|
return (int)(co - hair->geometry.position);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rna_HairPoint_location_get(PointerRNA *ptr, float value[3])
|
static void rna_CurvePoint_location_get(PointerRNA *ptr, float value[3])
|
||||||
{
|
{
|
||||||
copy_v3_v3(value, (const float *)ptr->data);
|
copy_v3_v3(value, (const float *)ptr->data);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rna_HairPoint_location_set(PointerRNA *ptr, const float value[3])
|
static void rna_CurvePoint_location_set(PointerRNA *ptr, const float value[3])
|
||||||
{
|
{
|
||||||
copy_v3_v3((float *)ptr->data, value);
|
copy_v3_v3((float *)ptr->data, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
static float rna_HairPoint_radius_get(PointerRNA *ptr)
|
static float rna_CurvePoint_radius_get(PointerRNA *ptr)
|
||||||
{
|
{
|
||||||
const Hair *hair = rna_hair(ptr);
|
const Hair *hair = rna_hair(ptr);
|
||||||
if (hair->radius == NULL) {
|
if (hair->geometry.radius == NULL) {
|
||||||
return 0.0f;
|
return 0.0f;
|
||||||
}
|
}
|
||||||
const float(*co)[3] = ptr->data;
|
const float(*co)[3] = ptr->data;
|
||||||
return hair->radius[co - hair->co];
|
return hair->geometry.radius[co - hair->geometry.position];
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rna_HairPoint_radius_set(PointerRNA *ptr, float value)
|
static void rna_CurvePoint_radius_set(PointerRNA *ptr, float value)
|
||||||
{
|
{
|
||||||
const Hair *hair = rna_hair(ptr);
|
const Hair *hair = rna_hair(ptr);
|
||||||
if (hair->radius == NULL) {
|
if (hair->geometry.radius == NULL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const float(*co)[3] = ptr->data;
|
const float(*co)[3] = ptr->data;
|
||||||
hair->radius[co - hair->co] = value;
|
hair->geometry.radius[co - hair->geometry.position] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *rna_HairPoint_path(PointerRNA *ptr)
|
static char *rna_CurvePoint_path(PointerRNA *ptr)
|
||||||
{
|
{
|
||||||
return BLI_sprintfN("points[%d]", rna_HairPoint_index_get(ptr));
|
return BLI_sprintfN("points[%d]", rna_CurvePoint_index_get(ptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int rna_HairCurve_index_get(PointerRNA *ptr)
|
static int rna_CurveSlice_index_get(PointerRNA *ptr)
|
||||||
{
|
{
|
||||||
Hair *hair = rna_hair(ptr);
|
Hair *hair = rna_hair(ptr);
|
||||||
return (int)((HairCurve *)ptr->data - hair->curves);
|
return (int)((int *)ptr->data - hair->geometry.offsets);
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *rna_HairCurve_path(PointerRNA *ptr)
|
static char *rna_CurveSlice_path(PointerRNA *ptr)
|
||||||
{
|
{
|
||||||
return BLI_sprintfN("curves[%d]", rna_HairCurve_index_get(ptr));
|
return BLI_sprintfN("curves[%d]", rna_CurveSlice_index_get(ptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rna_HairCurve_points_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
|
static void rna_CurveSlice_points_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
|
||||||
{
|
{
|
||||||
Hair *hair = rna_hair(ptr);
|
Hair *hair = rna_hair(ptr);
|
||||||
HairCurve *curve = ptr->data;
|
const int *offset_ptr = (int *)ptr->data;
|
||||||
float(*co)[3] = hair->co + curve->firstpoint;
|
const int offset = *offset_ptr;
|
||||||
rna_iterator_array_begin(iter, co, sizeof(float[3]), curve->numpoints, 0, NULL);
|
const int size = *(offset_ptr + 1) - offset;
|
||||||
|
float(*co)[3] = hair->geometry.position + *offset_ptr;
|
||||||
|
rna_iterator_array_begin(iter, co, sizeof(float[3]), size, 0, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int rna_HairCurve_points_length(PointerRNA *ptr)
|
static int rna_CurveSlice_first_point_index_get(PointerRNA *ptr)
|
||||||
{
|
{
|
||||||
HairCurve *curve = ptr->data;
|
const int *offset_ptr = (int *)ptr->data;
|
||||||
return curve->numpoints;
|
return *offset_ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rna_CurveSlice_points_length_get(PointerRNA *ptr)
|
||||||
|
{
|
||||||
|
const int *offset_ptr = (int *)ptr->data;
|
||||||
|
const int offset = *offset_ptr;
|
||||||
|
return *(offset_ptr + 1) - offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rna_Hair_update_data(struct Main *UNUSED(bmain),
|
static void rna_Hair_update_data(struct Main *UNUSED(bmain),
|
||||||
|
@ -134,25 +160,26 @@ static void rna_def_hair_point(BlenderRNA *brna)
|
||||||
StructRNA *srna;
|
StructRNA *srna;
|
||||||
PropertyRNA *prop;
|
PropertyRNA *prop;
|
||||||
|
|
||||||
srna = RNA_def_struct(brna, "HairPoint", NULL);
|
srna = RNA_def_struct(brna, "CurvePoint", NULL);
|
||||||
RNA_def_struct_ui_text(srna, "Hair Point", "Hair curve control point");
|
RNA_def_struct_ui_text(srna, "Curve Point", "Curve curve control point");
|
||||||
RNA_def_struct_path_func(srna, "rna_HairPoint_path");
|
RNA_def_struct_path_func(srna, "rna_CurvePoint_path");
|
||||||
|
|
||||||
prop = RNA_def_property(srna, "co", PROP_FLOAT, PROP_TRANSLATION);
|
prop = RNA_def_property(srna, "position", PROP_FLOAT, PROP_TRANSLATION);
|
||||||
RNA_def_property_array(prop, 3);
|
RNA_def_property_array(prop, 3);
|
||||||
RNA_def_property_float_funcs(
|
RNA_def_property_float_funcs(
|
||||||
prop, "rna_HairPoint_location_get", "rna_HairPoint_location_set", NULL);
|
prop, "rna_CurvePoint_location_get", "rna_CurvePoint_location_set", NULL);
|
||||||
RNA_def_property_ui_text(prop, "Location", "");
|
RNA_def_property_ui_text(prop, "Position", "");
|
||||||
RNA_def_property_update(prop, 0, "rna_Hair_update_data");
|
RNA_def_property_update(prop, 0, "rna_Hair_update_data");
|
||||||
|
|
||||||
prop = RNA_def_property(srna, "radius", PROP_FLOAT, PROP_DISTANCE);
|
prop = RNA_def_property(srna, "radius", PROP_FLOAT, PROP_DISTANCE);
|
||||||
RNA_def_property_float_funcs(prop, "rna_HairPoint_radius_get", "rna_HairPoint_radius_set", NULL);
|
RNA_def_property_float_funcs(
|
||||||
|
prop, "rna_CurvePoint_radius_get", "rna_CurvePoint_radius_set", NULL);
|
||||||
RNA_def_property_ui_text(prop, "Radius", "");
|
RNA_def_property_ui_text(prop, "Radius", "");
|
||||||
RNA_def_property_update(prop, 0, "rna_Hair_update_data");
|
RNA_def_property_update(prop, 0, "rna_Hair_update_data");
|
||||||
|
|
||||||
prop = RNA_def_property(srna, "index", PROP_INT, PROP_UNSIGNED);
|
prop = RNA_def_property(srna, "index", PROP_INT, PROP_UNSIGNED);
|
||||||
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
|
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
|
||||||
RNA_def_property_int_funcs(prop, "rna_HairPoint_index_get", NULL, NULL);
|
RNA_def_property_int_funcs(prop, "rna_CurvePoint_index_get", NULL, NULL);
|
||||||
RNA_def_property_ui_text(prop, "Index", "Index of this points");
|
RNA_def_property_ui_text(prop, "Index", "Index of this points");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -161,35 +188,37 @@ static void rna_def_hair_curve(BlenderRNA *brna)
|
||||||
StructRNA *srna;
|
StructRNA *srna;
|
||||||
PropertyRNA *prop;
|
PropertyRNA *prop;
|
||||||
|
|
||||||
srna = RNA_def_struct(brna, "HairCurve", NULL);
|
srna = RNA_def_struct(brna, "CurveSlice", NULL);
|
||||||
RNA_def_struct_ui_text(srna, "Hair Curve", "Hair curve");
|
RNA_def_struct_ui_text(srna, "Curve Slice", "A single curve from a curves data-block");
|
||||||
RNA_def_struct_path_func(srna, "rna_HairCurve_path");
|
RNA_def_struct_path_func(srna, "rna_CurveSlice_path");
|
||||||
|
|
||||||
prop = RNA_def_property(srna, "points", PROP_COLLECTION, PROP_NONE);
|
prop = RNA_def_property(srna, "points", PROP_COLLECTION, PROP_NONE);
|
||||||
RNA_def_property_struct_type(prop, "HairPoint");
|
RNA_def_property_struct_type(prop, "CurvePoint");
|
||||||
RNA_def_property_ui_text(prop, "Points", "Control points of the curve");
|
RNA_def_property_ui_text(prop, "Points", "Control points of the curve");
|
||||||
RNA_def_property_collection_funcs(prop,
|
RNA_def_property_collection_funcs(prop,
|
||||||
"rna_HairCurve_points_begin",
|
"rna_CurveSlice_points_begin",
|
||||||
"rna_iterator_array_next",
|
"rna_iterator_array_next",
|
||||||
"rna_iterator_array_end",
|
"rna_iterator_array_end",
|
||||||
"rna_iterator_array_get",
|
"rna_iterator_array_get",
|
||||||
"rna_HairCurve_points_length",
|
"rna_CurveSlice_points_length_get",
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
/* TODO: naming consistency, editable? */
|
|
||||||
prop = RNA_def_property(srna, "first_point_index", PROP_INT, PROP_UNSIGNED);
|
prop = RNA_def_property(srna, "first_point_index", PROP_INT, PROP_UNSIGNED);
|
||||||
RNA_def_property_int_sdna(prop, NULL, "firstpoint");
|
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
|
||||||
RNA_def_property_ui_text(prop, "First Point Index", "Index of the first loop of this polygon");
|
RNA_def_property_int_funcs(prop, "rna_CurveSlice_first_point_index_get", NULL, NULL);
|
||||||
|
RNA_def_property_ui_text(
|
||||||
|
prop, "First Point Index", "The index of this curve's first control point");
|
||||||
|
|
||||||
prop = RNA_def_property(srna, "num_points", PROP_INT, PROP_UNSIGNED);
|
prop = RNA_def_property(srna, "points_length", PROP_INT, PROP_UNSIGNED);
|
||||||
RNA_def_property_int_sdna(prop, NULL, "numpoints");
|
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
|
||||||
RNA_def_property_ui_text(prop, "Number of Points", "Number of loops used by this polygon");
|
RNA_def_property_int_funcs(prop, "rna_CurveSlice_points_length_get", NULL, NULL);
|
||||||
|
RNA_def_property_ui_text(prop, "Number of Points", "Number of control points in the curve");
|
||||||
|
|
||||||
prop = RNA_def_property(srna, "index", PROP_INT, PROP_UNSIGNED);
|
prop = RNA_def_property(srna, "index", PROP_INT, PROP_UNSIGNED);
|
||||||
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
|
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
|
||||||
RNA_def_property_int_funcs(prop, "rna_HairCurve_index_get", NULL, NULL);
|
RNA_def_property_int_funcs(prop, "rna_CurveSlice_index_get", NULL, NULL);
|
||||||
RNA_def_property_ui_text(prop, "Index", "Index of this curve");
|
RNA_def_property_ui_text(prop, "Index", "Index of this curve");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -202,20 +231,45 @@ static void rna_def_hair(BlenderRNA *brna)
|
||||||
RNA_def_struct_ui_text(srna, "Hair", "Hair data-block for hair curves");
|
RNA_def_struct_ui_text(srna, "Hair", "Hair data-block for hair curves");
|
||||||
RNA_def_struct_ui_icon(srna, ICON_HAIR_DATA);
|
RNA_def_struct_ui_icon(srna, ICON_HAIR_DATA);
|
||||||
|
|
||||||
/* geometry */
|
/* Point and Curve RNA API helpers. */
|
||||||
|
|
||||||
prop = RNA_def_property(srna, "curves", PROP_COLLECTION, PROP_NONE);
|
prop = RNA_def_property(srna, "curves", PROP_COLLECTION, PROP_NONE);
|
||||||
RNA_def_property_collection_sdna(prop, NULL, "curves", "totcurve");
|
RNA_def_property_collection_sdna(prop, NULL, "geometry.offsets", "geometry.curve_size");
|
||||||
RNA_def_property_struct_type(prop, "HairCurve");
|
RNA_def_property_struct_type(prop, "CurveSlice");
|
||||||
RNA_def_property_ui_text(prop, "Curves", "All hair curves");
|
RNA_def_property_ui_text(prop, "Curves", "All hair curves");
|
||||||
|
|
||||||
/* TODO: better solution for (*co)[3] parsing issue. */
|
/* TODO: better solution for (*co)[3] parsing issue. */
|
||||||
|
|
||||||
RNA_define_verify_sdna(0);
|
RNA_define_verify_sdna(0);
|
||||||
prop = RNA_def_property(srna, "points", PROP_COLLECTION, PROP_NONE);
|
prop = RNA_def_property(srna, "points", PROP_COLLECTION, PROP_NONE);
|
||||||
RNA_def_property_collection_sdna(prop, NULL, "co", "totpoint");
|
RNA_def_property_collection_sdna(prop, NULL, "geometry.position", "geometry.point_size");
|
||||||
RNA_def_property_struct_type(prop, "HairPoint");
|
RNA_def_property_struct_type(prop, "CurvePoint");
|
||||||
RNA_def_property_ui_text(prop, "Points", "Control points of all hair curves");
|
RNA_def_property_ui_text(prop, "Points", "Control points of all hair curves");
|
||||||
RNA_define_verify_sdna(1);
|
RNA_define_verify_sdna(1);
|
||||||
|
|
||||||
|
/* Direct access to built-in attributes. */
|
||||||
|
|
||||||
|
RNA_define_verify_sdna(0);
|
||||||
|
prop = RNA_def_property(srna, "position_data", PROP_COLLECTION, PROP_NONE);
|
||||||
|
RNA_def_property_collection_sdna(prop, NULL, "geometry.position", "geometry.point_size");
|
||||||
|
RNA_def_property_struct_type(prop, "FloatVectorAttributeValue");
|
||||||
|
RNA_def_property_update(prop, 0, "rna_Hair_update_data");
|
||||||
|
RNA_define_verify_sdna(1);
|
||||||
|
|
||||||
|
prop = RNA_def_property(srna, "curve_offset_data", PROP_COLLECTION, PROP_NONE);
|
||||||
|
RNA_def_property_collection_sdna(prop, NULL, "geometry.offsets", NULL);
|
||||||
|
RNA_def_property_struct_type(prop, "IntAttributeValue");
|
||||||
|
RNA_def_property_collection_funcs(prop,
|
||||||
|
"rna_Hair_curve_offset_data_begin",
|
||||||
|
"rna_iterator_array_next",
|
||||||
|
"rna_iterator_array_end",
|
||||||
|
"rna_iterator_array_get",
|
||||||
|
"rna_Hair_curve_offset_data_length",
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL);
|
||||||
|
RNA_def_property_update(prop, 0, "rna_Hair_update_data");
|
||||||
|
|
||||||
/* materials */
|
/* materials */
|
||||||
prop = RNA_def_property(srna, "materials", PROP_COLLECTION, PROP_NONE);
|
prop = RNA_def_property(srna, "materials", PROP_COLLECTION, PROP_NONE);
|
||||||
RNA_def_property_collection_sdna(prop, NULL, "mat", "totcol");
|
RNA_def_property_collection_sdna(prop, NULL, "mat", "totcol");
|
||||||
|
|
Loading…
Reference in New Issue