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
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/blenkernel/intern/strands.c')
-rw-r--r--source/blender/blenkernel/intern/strands.c407
1 files changed, 407 insertions, 0 deletions
diff --git a/source/blender/blenkernel/intern/strands.c b/source/blender/blenkernel/intern/strands.c
new file mode 100644
index 00000000000..38d35a7309e
--- /dev/null
+++ b/source/blender/blenkernel/intern/strands.c
@@ -0,0 +1,407 @@
+/*
+ * Copyright 2015, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+#include "BLI_string.h"
+
+#include "BKE_strands.h"
+
+Strands *BKE_strands_new(int curves, int verts)
+{
+ Strands *strands = MEM_mallocN(sizeof(Strands), "strands");
+
+ strands->totcurves = curves;
+ strands->curves = MEM_mallocN(sizeof(StrandsCurve) * curves, "strand curves");
+
+ strands->totverts = verts;
+ strands->verts = MEM_mallocN(sizeof(StrandsVertex) * verts, "strand vertices");
+
+ /* must be added explicitly */
+ strands->state = NULL;
+
+ return strands;
+}
+
+Strands *BKE_strands_copy(Strands *strands)
+{
+ Strands *new_strands = MEM_dupallocN(strands);
+ if (new_strands->curves)
+ new_strands->curves = MEM_dupallocN(new_strands->curves);
+ if (new_strands->verts)
+ new_strands->verts = MEM_dupallocN(new_strands->verts);
+ if (new_strands->state)
+ new_strands->state = MEM_dupallocN(new_strands->state);
+ return new_strands;
+}
+
+void BKE_strands_free(Strands *strands)
+{
+ if (strands) {
+ if (strands->curves)
+ MEM_freeN(strands->curves);
+ if (strands->verts)
+ MEM_freeN(strands->verts);
+ if (strands->state)
+ MEM_freeN(strands->state);
+ MEM_freeN(strands);
+ }
+}
+
+/* copy the rest positions to initialize the motion state */
+void BKE_strands_state_copy_rest_positions(Strands *strands)
+{
+ if (strands->state) {
+ int i;
+ for (i = 0; i < strands->totverts; ++i) {
+ copy_v3_v3(strands->state[i].co, strands->verts[i].co);
+ }
+ }
+}
+
+/* copy the rest positions to initialize the motion state */
+void BKE_strands_state_clear_velocities(Strands *strands)
+{
+ if (strands->state) {
+ int i;
+
+ for (i = 0; i < strands->totverts; ++i) {
+ zero_v3(strands->state[i].vel);
+ }
+ }
+}
+
+void BKE_strands_add_motion_state(Strands *strands)
+{
+ if (!strands->state) {
+ int i;
+
+ strands->state = MEM_mallocN(sizeof(StrandsMotionState) * strands->totverts, "strand motion states");
+
+ BKE_strands_state_copy_rest_positions(strands);
+ BKE_strands_state_clear_velocities(strands);
+
+ /* initialize normals */
+ for (i = 0; i < strands->totverts; ++i) {
+ copy_v3_v3(strands->state[i].nor, strands->verts[i].nor);
+ }
+ }
+}
+
+void BKE_strands_remove_motion_state(Strands *strands)
+{
+ if (strands) {
+ if (strands->state) {
+ MEM_freeN(strands->state);
+ strands->state = NULL;
+ }
+ }
+}
+
+static void calc_normals(Strands *strands, bool use_motion_state)
+{
+ StrandIterator it_strand;
+ for (BKE_strand_iter_init(&it_strand, strands); BKE_strand_iter_valid(&it_strand); BKE_strand_iter_next(&it_strand)) {
+ StrandEdgeIterator it_edge;
+ int numverts = it_strand.curve->numverts;
+ if (use_motion_state) {
+ for (BKE_strand_edge_iter_init(&it_edge, &it_strand); BKE_strand_edge_iter_valid(&it_edge); BKE_strand_edge_iter_next(&it_edge)) {
+ sub_v3_v3v3(it_edge.state0->nor, it_edge.state1->co, it_edge.state0->co);
+ normalize_v3(it_edge.state0->nor);
+ }
+ if (numverts > 1)
+ copy_v3_v3(it_strand.state[numverts-1].nor, it_strand.state[numverts-2].nor);
+ }
+ else {
+ for (BKE_strand_edge_iter_init(&it_edge, &it_strand); BKE_strand_edge_iter_valid(&it_edge); BKE_strand_edge_iter_next(&it_edge)) {
+ sub_v3_v3v3(it_edge.vertex0->nor, it_edge.vertex1->co, it_edge.vertex0->co);
+ normalize_v3(it_edge.vertex0->nor);
+ }
+ if (numverts > 1)
+ copy_v3_v3(it_strand.verts[numverts-1].nor, it_strand.verts[numverts-2].nor);
+ }
+ }
+}
+
+void BKE_strands_ensure_normals(Strands *strands)
+{
+ const bool use_motion_state = (strands->state);
+
+ calc_normals(strands, false);
+
+ if (use_motion_state)
+ calc_normals(strands, true);
+}
+
+void BKE_strands_get_minmax(Strands *strands, float min[3], float max[3], bool use_motion_state)
+{
+ int numverts = strands->totverts;
+ int i;
+
+ if (use_motion_state && strands->state) {
+ for (i = 0; i < numverts; ++i) {
+ minmax_v3v3_v3(min, max, strands->state[i].co);
+ }
+ }
+ else {
+ for (i = 0; i < numverts; ++i) {
+ minmax_v3v3_v3(min, max, strands->verts[i].co);
+ }
+ }
+}
+
+/* ------------------------------------------------------------------------- */
+
+StrandsChildren *BKE_strands_children_new(int curves, int verts)
+{
+ StrandsChildren *strands = MEM_mallocN(sizeof(StrandsChildren), "strands children");
+
+ strands->totcurves = curves;
+ strands->curves = MEM_mallocN(sizeof(StrandsChildCurve) * curves, "strand children curves");
+
+ strands->totverts = verts;
+ strands->verts = MEM_mallocN(sizeof(StrandsChildVertex) * verts, "strand children vertices");
+
+ /* must be added explicitly */
+ strands->curve_uvs = NULL;
+ strands->numuv = 0;
+ strands->curve_vcols = NULL;
+ strands->numvcol = 0;
+
+ return strands;
+}
+
+StrandsChildren *BKE_strands_children_copy(StrandsChildren *strands)
+{
+ StrandsChildren *new_strands = MEM_dupallocN(strands);
+ if (new_strands->curves)
+ new_strands->curves = MEM_dupallocN(new_strands->curves);
+ if (new_strands->curve_uvs)
+ new_strands->curve_uvs = MEM_dupallocN(new_strands->curve_uvs);
+ if (new_strands->curve_vcols)
+ new_strands->curve_vcols = MEM_dupallocN(new_strands->curve_vcols);
+ if (new_strands->verts)
+ new_strands->verts = MEM_dupallocN(new_strands->verts);
+ return new_strands;
+}
+
+void BKE_strands_children_free(StrandsChildren *strands)
+{
+ if (strands) {
+ if (strands->curves)
+ MEM_freeN(strands->curves);
+ if (strands->curve_uvs)
+ MEM_freeN(strands->curve_uvs);
+ if (strands->curve_vcols)
+ MEM_freeN(strands->curve_vcols);
+ if (strands->verts)
+ MEM_freeN(strands->verts);
+ MEM_freeN(strands);
+ }
+}
+
+void BKE_strands_children_add_uvs(StrandsChildren *strands, int num_layers)
+{
+ if (strands->curve_uvs && strands->numuv != num_layers) {
+ MEM_freeN(strands->curve_uvs);
+ strands->curve_uvs = NULL;
+ strands->numuv = 0;
+ }
+
+ if (!strands->curve_uvs) {
+ strands->curve_uvs = MEM_callocN(sizeof(StrandsChildCurveUV) * strands->totcurves * num_layers, "strands children uv layers");
+ strands->numuv = num_layers;
+ }
+}
+
+void BKE_strands_children_add_vcols(StrandsChildren *strands, int num_layers)
+{
+ if (strands->curve_vcols && strands->numvcol != num_layers) {
+ MEM_freeN(strands->curve_vcols);
+ strands->curve_vcols = NULL;
+ strands->numvcol = 0;
+ }
+
+ if (!strands->curve_vcols) {
+ strands->curve_vcols = MEM_callocN(sizeof(StrandsChildCurveVCol) * strands->totcurves * num_layers, "strands children vcol layers");
+ strands->numvcol = num_layers;
+ }
+}
+
+static int *strands_calc_vertex_start(Strands *strands)
+{
+ int *vertstart = MEM_mallocN(sizeof(int) * strands->totcurves, "strand curves vertex start");
+ StrandIterator it_strand;
+ int start;
+
+ start = 0;
+ for (BKE_strand_iter_init(&it_strand, strands); BKE_strand_iter_valid(&it_strand); BKE_strand_iter_next(&it_strand)) {
+ vertstart[it_strand.index] = start;
+ start += it_strand.curve->numverts;
+ }
+
+ return vertstart;
+}
+
+
+/* 'out' is an optional array to write final positions to, instead of writing back to vertex locations.
+ * It must be at least as large as the number of vertices.
+ */
+static void strands_children_strand_deform(StrandChildIterator *it_strand, Strands *parents, int *vertstart, bool use_motion, float (*out)[3])
+{
+ int i;
+
+ if (!parents || !vertstart)
+ return;
+
+ if (!parents->state)
+ use_motion = false;
+
+ for (i = 0; i < 4; ++i) {
+ int p = it_strand->curve->parents[i];
+ float w = it_strand->curve->parent_weights[i];
+ if (p >= 0 && w > 0.0f) {
+ StrandsCurve *parent = &parents->curves[p];
+ StrandsVertex *pverts;
+ StrandsMotionState *pstate;
+ int pv0, pv1;
+ StrandChildVertexIterator it_vert;
+
+ if (parent->numverts <= 0)
+ continue;
+
+ pverts = &parents->verts[vertstart[p]];
+ pstate = &parents->state[vertstart[p]];
+ pv0 = 0;
+ for (BKE_strand_child_vertex_iter_init(&it_vert, it_strand); BKE_strand_child_vertex_iter_valid(&it_vert); BKE_strand_child_vertex_iter_next(&it_vert)) {
+ float time = it_vert.vertex->time;
+ float dt, x;
+ float poffset0[3], poffset1[3], offset[3];
+
+ /* advance to the matching parent edge for interpolation */
+ while (pv0 < parent->numverts-1 && pverts[pv0+1].time < time)
+ ++pv0;
+ pv1 = (pv0 < parent->numverts-1)? pv0+1 : pv0;
+
+ if (use_motion) {
+ sub_v3_v3v3(poffset0, pstate[pv0].co, pverts[pv0].base);
+ sub_v3_v3v3(poffset1, pstate[pv1].co, pverts[pv1].base);
+ }
+ else {
+ sub_v3_v3v3(poffset0, pverts[pv0].co, pverts[pv0].base);
+ sub_v3_v3v3(poffset1, pverts[pv1].co, pverts[pv1].base);
+ }
+
+ dt = pverts[pv1].time - pverts[pv0].time;
+ x = dt > 0.0f ? (time - pverts[pv0].time) / dt : 0.0f;
+ CLAMP(x, 0.0f, 1.0f);
+ interp_v3_v3v3(offset, poffset0, poffset1, x);
+
+ if (out)
+ madd_v3_v3fl(out[it_vert.index], offset, w);
+ else
+ madd_v3_v3fl(it_vert.vertex->co, offset, w);
+ }
+ }
+ }
+}
+
+void BKE_strands_children_deform(StrandsChildren *strands, Strands *parents, bool use_motion)
+{
+ int *vertstart = NULL;
+ StrandChildIterator it_strand;
+
+ if (parents)
+ vertstart = strands_calc_vertex_start(parents);
+
+ for (BKE_strand_child_iter_init(&it_strand, strands); BKE_strand_child_iter_valid(&it_strand); BKE_strand_child_iter_next(&it_strand)) {
+ /* move child strands from their local root space to object space */
+ StrandChildVertexIterator it_vert;
+ for (BKE_strand_child_vertex_iter_init(&it_vert, &it_strand); BKE_strand_child_vertex_iter_valid(&it_vert); BKE_strand_child_vertex_iter_next(&it_vert)) {
+ mul_v3_m4v3(it_vert.vertex->co, it_strand.curve->root_matrix, it_vert.vertex->base);
+ }
+
+ strands_children_strand_deform(&it_strand, parents, vertstart, use_motion, NULL);
+ }
+
+ if (vertstart)
+ MEM_freeN(vertstart);
+}
+
+static void calc_child_normals(StrandsChildren *strands)
+{
+ StrandChildIterator it_strand;
+ for (BKE_strand_child_iter_init(&it_strand, strands); BKE_strand_child_iter_valid(&it_strand); BKE_strand_child_iter_next(&it_strand)) {
+ StrandChildEdgeIterator it_edge;
+ int numverts = it_strand.curve->numverts;
+ for (BKE_strand_child_edge_iter_init(&it_edge, &it_strand); BKE_strand_child_edge_iter_valid(&it_edge); BKE_strand_child_edge_iter_next(&it_edge)) {
+ sub_v3_v3v3(it_edge.vertex0->nor, it_edge.vertex1->co, it_edge.vertex0->co);
+ normalize_v3(it_edge.vertex0->nor);
+ }
+ if (numverts > 1)
+ copy_v3_v3(it_strand.verts[numverts-1].nor, it_strand.verts[numverts-2].nor);
+ }
+}
+
+void BKE_strands_children_ensure_normals(StrandsChildren *strands)
+{
+ calc_child_normals(strands);
+}
+
+void BKE_strands_children_get_minmax(StrandsChildren *strands, float min[3], float max[3])
+{
+ int numverts = strands->totverts;
+ int i;
+
+ for (i = 0; i < numverts; ++i) {
+ minmax_v3v3_v3(min, max, strands->verts[i].co);
+ }
+}
+
+/* ------------------------------------------------------------------------- */
+
+void BKE_strand_bend_iter_transform_rest(StrandBendIterator *iter, float mat[3][3])
+{
+ float dir0[3], dir1[3];
+
+ sub_v3_v3v3(dir0, iter->vertex1->co, iter->vertex0->co);
+ sub_v3_v3v3(dir1, iter->vertex2->co, iter->vertex1->co);
+ normalize_v3(dir0);
+ normalize_v3(dir1);
+
+ /* rotation between segments */
+ rotation_between_vecs_to_mat3(mat, dir0, dir1);
+}
+
+void BKE_strand_bend_iter_transform_state(StrandBendIterator *iter, float mat[3][3])
+{
+ if (iter->state0) {
+ float dir0[3], dir1[3];
+
+ sub_v3_v3v3(dir0, iter->state1->co, iter->state0->co);
+ sub_v3_v3v3(dir1, iter->state2->co, iter->state1->co);
+ normalize_v3(dir0);
+ normalize_v3(dir1);
+
+ /* rotation between segments */
+ rotation_between_vecs_to_mat3(mat, dir0, dir1);
+ }
+ else
+ unit_m3(mat);
+}