Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
Diffstat (limited to 'source')
-rw-r--r--source/blender/blenkernel/intern/attribute.c8
-rw-r--r--source/blender/blenkernel/intern/customdata.cc8
-rw-r--r--source/blender/blenkernel/intern/hair.cc152
-rw-r--r--source/blender/blenloader/intern/versioning_290.c4
-rw-r--r--source/blender/draw/intern/draw_cache_impl_hair.cc71
-rw-r--r--source/blender/makesdna/DNA_hair_types.h85
-rw-r--r--source/blender/makesrna/intern/rna_hair.c152
7 files changed, 313 insertions, 167 deletions
diff --git a/source/blender/blenkernel/intern/attribute.c b/source/blender/blenkernel/intern/attribute.c
index ee8ef5e97f7..73e00398084 100644
--- a/source/blender/blenkernel/intern/attribute.c
+++ b/source/blender/blenkernel/intern/attribute.c
@@ -90,10 +90,10 @@ static void get_domains(const ID *id, DomainInfo info[ATTR_DOMAIN_NUM])
}
case ID_HA: {
Hair *hair = (Hair *)id;
- info[ATTR_DOMAIN_POINT].customdata = &hair->pdata;
- info[ATTR_DOMAIN_POINT].length = hair->totpoint;
- info[ATTR_DOMAIN_CURVE].customdata = &hair->cdata;
- info[ATTR_DOMAIN_CURVE].length = hair->totcurve;
+ info[ATTR_DOMAIN_POINT].customdata = &hair->geometry.point_data;
+ info[ATTR_DOMAIN_POINT].length = hair->geometry.point_size;
+ info[ATTR_DOMAIN_CURVE].customdata = &hair->geometry.curve_data;
+ info[ATTR_DOMAIN_CURVE].length = hair->geometry.curve_size;
break;
}
default:
diff --git a/source/blender/blenkernel/intern/customdata.cc b/source/blender/blenkernel/intern/customdata.cc
index e4c18325d76..d235e6d15e1 100644
--- a/source/blender/blenkernel/intern/customdata.cc
+++ b/source/blender/blenkernel/intern/customdata.cc
@@ -1793,10 +1793,10 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
{sizeof(float[3]), "vec3f", 1, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
/* 44: CD_RADIUS */
{sizeof(float), "MFloatProperty", 1, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
- /* 45: CD_HAIRCURVE */
- {sizeof(HairCurve), "HairCurve", 1, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
- /* 46: CD_HAIRMAPPING */
- {sizeof(HairMapping), "HairMapping", 1, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
+ /* 45: CD_HAIRCURVE */ /* DEPRECATED */
+ {-1, "HairCurve", 1, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
+ /* 46: CD_HAIRMAPPING */ /* DEPRECATED */
+ {-1, "HairMapping", 1, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
/* 47: CD_PROP_COLOR */
{sizeof(MPropCol),
"MPropCol",
diff --git a/source/blender/blenkernel/intern/hair.cc b/source/blender/blenkernel/intern/hair.cc
index 5e8b81c03a4..bddadc3bcfd 100644
--- a/source/blender/blenkernel/intern/hair.cc
+++ b/source/blender/blenkernel/intern/hair.cc
@@ -28,6 +28,7 @@
#include "DNA_material_types.h"
#include "DNA_object_types.h"
+#include "BLI_index_range.hh"
#include "BLI_listbase.h"
#include "BLI_math_base.h"
#include "BLI_math_vec_types.hh"
@@ -54,6 +55,8 @@
#include "BLO_read_write.h"
using blender::float3;
+using blender::IndexRange;
+using blender::MutableSpan;
using blender::RandomNumberGenerator;
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);
- CustomData_reset(&hair->pdata);
- CustomData_reset(&hair->cdata);
+ CustomData_reset(&hair->geometry.point_data);
+ 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);
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;
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;
- CustomData_copy(&hair_src->pdata, &hair_dst->pdata, CD_MASK_ALL, alloc_type, hair_dst->totpoint);
- CustomData_copy(&hair_src->cdata, &hair_dst->cdata, CD_MASK_ALL, alloc_type, hair_dst->totcurve);
+ CustomData_copy(&hair_src->geometry.point_data,
+ &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);
+ hair_dst->geometry.offsets = static_cast<int *>(MEM_dupallocN(hair_src->geometry.offsets));
+
hair_dst->batch_cache = nullptr;
}
@@ -104,8 +128,10 @@ static void hair_free_data(ID *id)
BKE_hair_batch_cache_free(hair);
- CustomData_free(&hair->pdata, hair->totpoint);
- CustomData_free(&hair->cdata, hair->totcurve);
+ CustomData_free(&hair->geometry.point_data, hair->geometry.point_size);
+ CustomData_free(&hair->geometry.curve_data, hair->geometry.curve_size);
+
+ MEM_SAFE_FREE(hair->geometry.offsets);
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 *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(&hair->cdata, &clayers, clayers_buff, ARRAY_SIZE(clayers_buff));
+ CustomData_blend_write_prepare(
+ &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 */
BLO_write_id_struct(writer, Hair, id_address, &hair->id);
BKE_id_blend_write(writer, &hair->id);
/* Direct data */
- CustomData_blend_write(writer, &hair->pdata, players, hair->totpoint, CD_MASK_ALL, &hair->id);
- CustomData_blend_write(writer, &hair->cdata, clayers, hair->totcurve, CD_MASK_ALL, &hair->id);
+ CustomData_blend_write(writer,
+ &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);
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);
/* Geometry */
- CustomData_blend_read(reader, &hair->pdata, hair->totpoint);
- CustomData_blend_read(reader, &hair->cdata, hair->totcurve);
+ CustomData_blend_read(reader, &hair->geometry.point_data, hair->geometry.point_size);
+ CustomData_blend_read(reader, &hair->geometry.curve_data, hair->geometry.point_size);
BKE_hair_update_customdata_pointers(hair);
+ BLO_read_int32_array(reader, hair->geometry.curve_size + 1, &hair->geometry.offsets);
+
/* Materials */
BLO_read_pointer_array(reader, (void **)&hair->mat);
}
@@ -212,38 +254,48 @@ IDTypeInfo IDType_ID_HA = {
static void hair_random(Hair *hair)
{
+ CurvesGeometry &geometry = hair->geometry;
const int numpoints = 8;
- hair->totcurve = 500;
- hair->totpoint = hair->totcurve * numpoints;
+ geometry.curve_size = 500;
+
+ geometry.curve_size = 500;
+ geometry.point_size = geometry.curve_size * numpoints;
- CustomData_realloc(&hair->pdata, hair->totpoint);
- CustomData_realloc(&hair->cdata, hair->totcurve);
+ 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);
+ 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;
- for (int i = 0; i < hair->totcurve; i++) {
- HairCurve *curve = &hair->curves[i];
- curve->firstpoint = i * numpoints;
- curve->numpoints = numpoints;
+ for (int i = 0; i < geometry.curve_size; i++) {
+ const IndexRange curve_range(offsets[i], offsets[i + 1] - offsets[i]);
+ MutableSpan<float3> curve_positions = positions.slice(curve_range);
+ MutableSpan<float> curve_radii = radii.slice(curve_range);
const float theta = 2.0f * M_PI * rng.get_float();
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)};
- 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;
for (int key = 0; key < numpoints; key++) {
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);
float3 offset = float3(rng.get_float(), rng.get_float(), rng.get_float()) * 2.0f - 1.0f;
-
co += (offset + no) / numpoints;
}
}
@@ -271,9 +323,9 @@ BoundBox *BKE_hair_boundbox_get(Object *ob)
float min[3], max[3];
INIT_MINMAX(min, max);
- float(*hair_co)[3] = hair->co;
- float *hair_radius = hair->radius;
- for (int a = 0; a < hair->totpoint; a++) {
+ float(*hair_co)[3] = hair->geometry.position;
+ float *hair_radius = hair->geometry.radius;
+ for (int a = 0; a < hair->geometry.point_size; a++) {
float *co = hair_co[a];
float radius = (hair_radius) ? hair_radius[a] : 0.0f;
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)
{
- hair->co = (float(*)[3])CustomData_get_layer_named(
- &hair->pdata, CD_PROP_FLOAT3, HAIR_ATTR_POSITION);
- hair->radius = (float *)CustomData_get_layer_named(
- &hair->pdata, 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);
+ hair->geometry.position = (float(*)[3])CustomData_get_layer_named(
+ &hair->geometry.point_data, CD_PROP_FLOAT3, HAIR_ATTR_POSITION);
+ hair->geometry.radius = (float *)CustomData_get_layer_named(
+ &hair->geometry.point_data, CD_PROP_FLOAT, HAIR_ATTR_RADIUS);
}
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->totcol = hair_src->totcol;
- hair_dst->totpoint = totpoint;
- hair_dst->totcurve = totcurve;
- CustomData_copy(&hair_src->pdata, &hair_dst->pdata, CD_MASK_ALL, CD_CALLOC, totpoint);
- CustomData_copy(&hair_src->cdata, &hair_dst->cdata, CD_MASK_ALL, CD_CALLOC, totcurve);
+ hair_dst->geometry.point_size = totpoint;
+ hair_dst->geometry.curve_size = totcurve;
+ CustomData_copy(&hair_src->geometry.point_data,
+ &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);
return hair_dst;
@@ -368,12 +426,14 @@ static Hair *hair_evaluate_modifiers(struct Depsgraph *depsgraph,
}
/* Ensure we are not overwriting referenced data. */
- CustomData_duplicate_referenced_layer_named(
- &hair->pdata, CD_PROP_FLOAT3, HAIR_ATTR_POSITION, hair->totpoint);
+ CustomData_duplicate_referenced_layer_named(&hair->geometry.point_data,
+ CD_PROP_FLOAT3,
+ HAIR_ATTR_POSITION,
+ hair->geometry.point_size);
BKE_hair_update_customdata_pointers(hair);
/* 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);
}
}
diff --git a/source/blender/blenloader/intern/versioning_290.c b/source/blender/blenloader/intern/versioning_290.c
index 888bd244007..ef146606ff0 100644
--- a/source/blender/blenloader/intern/versioning_290.c
+++ b/source/blender/blenloader/intern/versioning_290.c
@@ -1122,7 +1122,7 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain)
/* Hair and PointCloud attributes. */
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;
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. */
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) {
do_versions_point_attribute_names(&pointcloud->pdata);
diff --git a/source/blender/draw/intern/draw_cache_impl_hair.cc b/source/blender/draw/intern/draw_cache_impl_hair.cc
index d236f0c2f59..cdc06b121b0 100644
--- a/source/blender/draw/intern/draw_cache_impl_hair.cc
+++ b/source/blender/draw/intern/draw_cache_impl_hair.cc
@@ -29,7 +29,10 @@
#include "BLI_listbase.h"
#include "BLI_math_base.h"
+#include "BLI_math_vec_types.hh"
#include "BLI_math_vector.h"
+#include "BLI_math_vector.hh"
+#include "BLI_span.hh"
#include "BLI_utildefines.h"
#include "DNA_hair_types.h"
@@ -44,6 +47,10 @@
#include "draw_cache_impl.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);
/* ---------------------------------------------------------------------- */
@@ -131,17 +138,9 @@ static void ensure_seg_pt_count(Hair *hair, ParticleHairCache *hair_cache)
return;
}
- hair_cache->strands_len = 0;
- hair_cache->elems_len = 0;
- hair_cache->point_len = 0;
-
- 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;
- }
+ hair_cache->strands_len = hair->geometry.curve_size;
+ hair_cache->elems_len = hair->geometry.point_size + hair->geometry.curve_size;
+ hair_cache->point_len = hair->geometry.point_size;
}
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)
{
/* TODO: use hair radius layer if available. */
- HairCurve *curve = hair->curves;
- int num_curves = hair->totcurve;
- for (int i = 0; i < num_curves; i++, curve++) {
- float(*curve_co)[3] = hair->co + curve->firstpoint;
+ const int curve_size = hair->geometry.curve_size;
+ Span<int> offsets{hair->geometry.offsets, hair->geometry.curve_size + 1};
+
+ 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 *co_prev = nullptr, *seg_data_first;
- for (int j = 0; j < curve->numpoints; j++) {
+ float *seg_data_first;
+ for (const int i_spline : spline_positions.index_range()) {
float *seg_data = (float *)GPU_vertbuf_raw_step(attr_step);
- copy_v3_v3(seg_data, curve_co[j]);
- if (co_prev) {
- total_len += len_v3v3(co_prev, curve_co[j]);
+ copy_v3_v3(seg_data, spline_positions[i_spline]);
+ if (i_spline == 0) {
+ seg_data_first = seg_data;
}
else {
- seg_data_first = seg_data;
+ total_len += blender::math::distance(spline_positions[i_spline - 1],
+ spline_positions[i_spline]);
}
seg_data[3] = total_len;
- co_prev = curve_co[j];
}
/* Assign length value. */
*(float *)GPU_vertbuf_raw_step(length_step) = total_len;
if (total_len > 0.0f) {
/* 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 += 4;
}
}
}
@@ -226,11 +231,14 @@ static void hair_batch_cache_fill_strands_data(Hair *hair,
GPUVertBufRaw *data_step,
GPUVertBufRaw *seg_step)
{
- HairCurve *curve = hair->curves;
- int num_curves = hair->totcurve;
- for (int i = 0; i < num_curves; i++, curve++) {
- *(uint *)GPU_vertbuf_raw_step(data_step) = curve->firstpoint;
- *(ushort *)GPU_vertbuf_raw_step(seg_step) = curve->numpoints - 1;
+ const int curve_size = hair->geometry.curve_size;
+ Span<int> offsets{hair->geometry.offsets, hair->geometry.curve_size + 1};
+
+ for (const int i : IndexRange(curve_size)) {
+ 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,
GPUIndexBufBuilder *elb)
{
- HairCurve *curve = hair->curves;
- int num_curves = hair->totcurve;
+ const int curve_size = hair->geometry.curve_size;
+
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++) {
GPU_indexbuf_add_generic_vert(elb, curr_point++);
}
diff --git a/source/blender/makesdna/DNA_hair_types.h b/source/blender/makesdna/DNA_hair_types.h
index 2e819b32033..5d54a4bb8cc 100644
--- a/source/blender/makesdna/DNA_hair_types.h
+++ b/source/blender/makesdna/DNA_hair_types.h
@@ -27,48 +27,71 @@
extern "C" {
#endif
-typedef struct HairCurve {
- /* Index of first point of hair curve. */
- int firstpoint;
- /* Number of points in hair curve, must be 2 or higher. */
- int numpoints;
-} HairCurve;
-
-/* Hair attachment to a mesh.
- * TODO: attach to tessellated triangles or polygons?
- * TODO: what type of interpolation to use for uv? */
-typedef struct HairMapping {
- float uv[2];
- int poly;
-} HairMapping;
+/**
+ * A reusable data structure for geometry consisting of many curves. All control point data is
+ * stored contiguously for better efficiency. Data for each curve is stored as a slice of the
+ * main #point_data array.
+ *
+ * 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;
+
+ /**
+ * The start index of each curve in the point data. The size of each curve can be calculated by
+ * subtracting the offset from the next offset. That is valid even for the last curve because
+ * this array is allocated with a length one larger than the number of splines.
+ *
+ * \note This is *not* stored in #CustomData because its size is one larger than #curve_data.
+ */
+ 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 {
ID id;
- struct AnimData *adt; /* animation data (must be immediately after id) */
+ /* Animation data (must be immediately after id). */
+ struct AnimData *adt;
- int flag;
- int _pad1[1];
+ CurvesGeometry geometry;
- /* 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 flag;
int attributes_active_index;
- int _pad3;
- /* Material */
+ /* Materials. */
struct Material **mat;
short totcol;
short _pad2[3];
- /* Draw Cache */
+ /* Draw Cache. */
void *batch_cache;
} Hair;
diff --git a/source/blender/makesrna/intern/rna_hair.c b/source/blender/makesrna/intern/rna_hair.c
index 4ca66c6b583..30e1fd48c03 100644
--- a/source/blender/makesrna/intern/rna_hair.c
+++ b/source/blender/makesrna/intern/rna_hair.c
@@ -47,71 +47,97 @@ static Hair *rna_hair(PointerRNA *ptr)
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 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);
}
-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);
}
-static float rna_HairPoint_radius_get(PointerRNA *ptr)
+static float rna_CurvePoint_radius_get(PointerRNA *ptr)
{
const Hair *hair = rna_hair(ptr);
- if (hair->radius == NULL) {
+ if (hair->geometry.radius == NULL) {
return 0.0f;
}
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);
- if (hair->radius == NULL) {
+ if (hair->geometry.radius == NULL) {
return;
}
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);
- 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);
- HairCurve *curve = ptr->data;
- float(*co)[3] = hair->co + curve->firstpoint;
- rna_iterator_array_begin(iter, co, sizeof(float[3]), curve->numpoints, 0, NULL);
+ const int *offset_ptr = (int *)ptr->data;
+ const int offset = *offset_ptr;
+ 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_CurveSlice_first_point_index_get(PointerRNA *ptr)
+{
+ const int *offset_ptr = (int *)ptr->data;
+ return *offset_ptr;
}
-static int rna_HairCurve_points_length(PointerRNA *ptr)
+static int rna_CurveSlice_points_length_get(PointerRNA *ptr)
{
- HairCurve *curve = ptr->data;
- return curve->numpoints;
+ 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),
@@ -134,25 +160,26 @@ static void rna_def_hair_point(BlenderRNA *brna)
StructRNA *srna;
PropertyRNA *prop;
- srna = RNA_def_struct(brna, "HairPoint", NULL);
- RNA_def_struct_ui_text(srna, "Hair Point", "Hair curve control point");
- RNA_def_struct_path_func(srna, "rna_HairPoint_path");
+ srna = RNA_def_struct(brna, "CurvePoint", NULL);
+ RNA_def_struct_ui_text(srna, "Curve Point", "Curve curve control point");
+ 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_float_funcs(
- prop, "rna_HairPoint_location_get", "rna_HairPoint_location_set", NULL);
- RNA_def_property_ui_text(prop, "Location", "");
+ prop, "rna_CurvePoint_location_get", "rna_CurvePoint_location_set", NULL);
+ RNA_def_property_ui_text(prop, "Position", "");
RNA_def_property_update(prop, 0, "rna_Hair_update_data");
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_update(prop, 0, "rna_Hair_update_data");
prop = RNA_def_property(srna, "index", PROP_INT, PROP_UNSIGNED);
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");
}
@@ -161,35 +188,37 @@ static void rna_def_hair_curve(BlenderRNA *brna)
StructRNA *srna;
PropertyRNA *prop;
- srna = RNA_def_struct(brna, "HairCurve", NULL);
- RNA_def_struct_ui_text(srna, "Hair Curve", "Hair curve");
- RNA_def_struct_path_func(srna, "rna_HairCurve_path");
+ srna = RNA_def_struct(brna, "CurveSlice", NULL);
+ RNA_def_struct_ui_text(srna, "Curve Slice", "A single curve from a curves data-block");
+ RNA_def_struct_path_func(srna, "rna_CurveSlice_path");
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_collection_funcs(prop,
- "rna_HairCurve_points_begin",
+ "rna_CurveSlice_points_begin",
"rna_iterator_array_next",
"rna_iterator_array_end",
"rna_iterator_array_get",
- "rna_HairCurve_points_length",
+ "rna_CurveSlice_points_length_get",
NULL,
NULL,
NULL);
- /* TODO: naming consistency, editable? */
prop = RNA_def_property(srna, "first_point_index", PROP_INT, PROP_UNSIGNED);
- RNA_def_property_int_sdna(prop, NULL, "firstpoint");
- RNA_def_property_ui_text(prop, "First Point Index", "Index of the first loop of this polygon");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ 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);
- RNA_def_property_int_sdna(prop, NULL, "numpoints");
- RNA_def_property_ui_text(prop, "Number of Points", "Number of loops used by this polygon");
+ prop = RNA_def_property(srna, "points_length", PROP_INT, PROP_UNSIGNED);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ 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);
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");
}
@@ -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_icon(srna, ICON_HAIR_DATA);
- /* geometry */
+ /* Point and Curve RNA API helpers. */
+
prop = RNA_def_property(srna, "curves", PROP_COLLECTION, PROP_NONE);
- RNA_def_property_collection_sdna(prop, NULL, "curves", "totcurve");
- RNA_def_property_struct_type(prop, "HairCurve");
+ RNA_def_property_collection_sdna(prop, NULL, "geometry.offsets", "geometry.curve_size");
+ RNA_def_property_struct_type(prop, "CurveSlice");
RNA_def_property_ui_text(prop, "Curves", "All hair curves");
/* TODO: better solution for (*co)[3] parsing issue. */
+
RNA_define_verify_sdna(0);
prop = RNA_def_property(srna, "points", PROP_COLLECTION, PROP_NONE);
- RNA_def_property_collection_sdna(prop, NULL, "co", "totpoint");
- RNA_def_property_struct_type(prop, "HairPoint");
+ RNA_def_property_collection_sdna(prop, NULL, "geometry.position", "geometry.point_size");
+ RNA_def_property_struct_type(prop, "CurvePoint");
RNA_def_property_ui_text(prop, "Points", "Control points of all hair curves");
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 */
prop = RNA_def_property(srna, "materials", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "mat", "totcol");