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/hair_draw.c')
-rw-r--r--source/blender/blenkernel/intern/hair_draw.c360
1 files changed, 360 insertions, 0 deletions
diff --git a/source/blender/blenkernel/intern/hair_draw.c b/source/blender/blenkernel/intern/hair_draw.c
new file mode 100644
index 00000000000..37de8bc742d
--- /dev/null
+++ b/source/blender/blenkernel/intern/hair_draw.c
@@ -0,0 +1,360 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * 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.
+ *
+ * The Original Code is Copyright (C) Blender Foundation
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Lukas Toenne
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/hair_draw.c
+ * \ingroup bke
+ */
+
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+#include "BLI_kdtree.h"
+#include "BLI_rand.h"
+
+#include "DNA_hair_types.h"
+
+#include "BKE_DerivedMesh.h"
+#include "BKE_mesh_sample.h"
+#include "BKE_hair.h"
+
+/* === Draw Settings === */
+
+HairDrawSettings* BKE_hair_draw_settings_new(void)
+{
+ HairDrawSettings *draw_settings = MEM_callocN(sizeof(HairDrawSettings), "hair draw settings");
+
+ draw_settings->follicle_mode = HAIR_DRAW_FOLLICLE_NONE;
+
+ return draw_settings;
+}
+
+HairDrawSettings* BKE_hair_draw_settings_copy(HairDrawSettings *draw_settings)
+{
+ HairDrawSettings *ndraw_settings = MEM_dupallocN(draw_settings);
+ return ndraw_settings;
+}
+
+void BKE_hair_draw_settings_free(HairDrawSettings *draw_settings)
+{
+ MEM_freeN(draw_settings);
+}
+
+/* === Draw Cache === */
+
+static int hair_get_strand_subdiv_numverts(int numstrands, int numverts, int subdiv)
+{
+ return ((numverts - numstrands) << subdiv) + numstrands;
+}
+
+BLI_INLINE int hair_get_strand_subdiv_length(int orig_length, int subdiv)
+{
+ return ((orig_length - 1) << subdiv) + 1;
+}
+
+int* BKE_hair_get_fiber_lengths(const HairSystem *hsys, int subdiv)
+{
+ if (!hsys->pattern) {
+ return NULL;
+ }
+
+ const int totfibers = hsys->pattern->num_follicles;
+ int *fiber_length = MEM_mallocN(sizeof(int) * totfibers, "fiber length");
+
+ const int num_strands = hsys->totcurves;
+ /* Cache subdivided lengths for repeated lookup */
+ int *lengths = MEM_mallocN(sizeof(int) * num_strands, "strand length");
+ for (int i = 0; i < hsys->totcurves; ++i) {
+ lengths[i] = hair_get_strand_subdiv_length(hsys->curves[i].numverts, subdiv);
+ }
+
+ // Calculate the length of the fiber from the weighted average of its guide strands
+ HairFollicle *follicle = hsys->pattern->follicles;
+ for (int i = 0; i < totfibers; ++i, ++follicle) {
+ float fiblen = 0.0f;
+
+ for (int k = 0; k < 4; ++k) {
+ int si = follicle->parent_index[k];
+ float sw = follicle->parent_weight[k];
+ if (si == HAIR_STRAND_INDEX_NONE || sw == 0.0f) {
+ break;
+ }
+ BLI_assert(si < num_strands);
+
+ fiblen += (float)lengths[si] * sw;
+ }
+
+ // use rounded number of segments
+ fiber_length[i] = (int)(fiblen + 0.5f);
+ }
+
+ MEM_freeN(lengths);
+
+ return fiber_length;
+}
+
+typedef struct HairFiberTextureBuffer {
+ unsigned int parent_index[4];
+ float parent_weight[4];
+ float root_position[3];
+ int pad;
+} HairFiberTextureBuffer;
+BLI_STATIC_ASSERT_ALIGN(HairFiberTextureBuffer, 8)
+
+typedef struct HairStrandVertexTextureBuffer {
+ float co[3];
+ float nor[3];
+ float tang[3];
+ int pad;
+} HairStrandVertexTextureBuffer;
+BLI_STATIC_ASSERT_ALIGN(HairStrandVertexTextureBuffer, 8)
+
+typedef struct HairStrandMapTextureBuffer {
+ unsigned int vertex_start;
+ unsigned int vertex_count;
+} HairStrandMapTextureBuffer;
+BLI_STATIC_ASSERT_ALIGN(HairStrandMapTextureBuffer, 8)
+
+static void hair_strand_transport_frame(const float co1[3], const float co2[3],
+ float prev_tang[3], float prev_nor[3],
+ float r_tang[3], float r_nor[3])
+{
+ /* segment direction */
+ sub_v3_v3v3(r_tang, co2, co1);
+ normalize_v3(r_tang);
+
+ /* rotate the frame */
+ float rot[3][3];
+ rotation_between_vecs_to_mat3(rot, prev_tang, r_tang);
+ mul_v3_m3v3(r_nor, rot, prev_nor);
+
+ copy_v3_v3(prev_tang, r_tang);
+ copy_v3_v3(prev_nor, r_nor);
+}
+
+static void hair_strand_calc_vectors(const float (*positions)[3], int num_verts, float rootmat[3][3],
+ HairStrandVertexTextureBuffer *strand)
+{
+ for (int i = 0; i < num_verts; ++i) {
+ copy_v3_v3(strand[i].co, positions[i]);
+ }
+
+ // Calculate tangent and normal vectors
+ {
+ BLI_assert(num_verts >= 2);
+
+ float prev_tang[3], prev_nor[3];
+
+ copy_v3_v3(prev_tang, rootmat[2]);
+ copy_v3_v3(prev_nor, rootmat[0]);
+
+ hair_strand_transport_frame(strand[0].co, strand[1].co,
+ prev_tang, prev_nor,
+ strand[0].tang, strand[0].nor);
+
+ for (int i = 1; i < num_verts - 1; ++i)
+ {
+ hair_strand_transport_frame(strand[i-1].co, strand[i+1].co,
+ prev_tang, prev_nor,
+ strand[i].tang, strand[i].nor);
+ }
+
+ hair_strand_transport_frame(strand[num_verts-2].co, strand[num_verts-1].co,
+ prev_tang, prev_nor,
+ strand[num_verts-1].tang, strand[num_verts-1].nor);
+ }
+}
+
+static int hair_strand_subdivide(const HairSystem *hsys, const HairGuideCurve* curve, int subdiv, float (*verts)[3])
+{
+ {
+ /* Move vertex positions from the dense array to their initial configuration for subdivision. */
+ const int step = (1 << subdiv);
+ float (*dst)[3] = verts;
+ int vertend = curve->vertstart + curve->numverts;
+ for (int i = curve->vertstart; i < vertend; ++i) {
+ copy_v3_v3(*dst, hsys->verts[i].co);
+ dst += step;
+ }
+ }
+
+ /* Subdivide */
+ for (int d = 0; d < subdiv; ++d) {
+ const int num_edges = (curve->numverts - 1) << d;
+ const int hstep = 1 << (subdiv - d - 1);
+ const int step = 1 << (subdiv - d);
+
+ /* Calculate edge points */
+ {
+ int index = 0;
+ for (int k = 0; k < num_edges; ++k, index += step) {
+ add_v3_v3v3(verts[index + hstep], verts[index], verts[index + step]);
+ mul_v3_fl(verts[index + hstep], 0.5f);
+ }
+ }
+
+ /* Move original points */
+ {
+ int index = step;
+ for (int k = 1; k < num_edges; ++k, index += step) {
+ add_v3_v3v3(verts[index], verts[index - hstep], verts[index + hstep]);
+ mul_v3_fl(verts[index], 0.5f);
+ }
+ }
+ }
+
+ const int num_verts = ((curve->numverts - 1) << subdiv) + 1;
+ return num_verts;
+}
+
+static void hair_get_strand_buffer(
+ const HairSystem *hsys,
+ DerivedMesh *scalp,
+ int subdiv,
+ HairStrandMapTextureBuffer *strand_map_buffer,
+ HairStrandVertexTextureBuffer *strand_vertex_buffer)
+{
+ const int numverts = hair_get_strand_subdiv_numverts(hsys->totcurves, hsys->totverts, subdiv);
+
+ float (*vertco)[3] = MEM_mallocN(sizeof(float[3]) * numverts, "strand vertex positions subdivided");
+
+ HairStrandMapTextureBuffer *smap = strand_map_buffer;
+ HairStrandVertexTextureBuffer *svert = strand_vertex_buffer;
+ int vertex_start = 0;
+ for (int i = 0; i < hsys->totcurves; ++i) {
+ const HairGuideCurve *curve = &hsys->curves[i];
+ const int len_orig = curve->numverts;
+ const int len = hair_get_strand_subdiv_length(len_orig, subdiv);
+ smap->vertex_start = vertex_start;
+ smap->vertex_count = len;
+
+ hair_strand_subdivide(hsys, curve, subdiv, vertco + vertex_start);
+
+ {
+ float pos[3];
+ float matrix[3][3];
+ BKE_mesh_sample_eval(scalp, &hsys->curves[i].mesh_sample, pos, matrix[2], matrix[0]);
+ cross_v3_v3v3(matrix[1], matrix[2], matrix[0]);
+ hair_strand_calc_vectors(vertco + vertex_start, len, matrix, svert);
+ }
+
+ vertex_start += len;
+ ++smap;
+ svert += len;
+ }
+
+ MEM_freeN(vertco);
+}
+
+static void hair_get_fiber_buffer(const HairSystem* hsys, DerivedMesh *scalp,
+ HairFiberTextureBuffer *fiber_buf)
+{
+ if (hsys->pattern)
+ {
+ const int totfibers = hsys->pattern->num_follicles;
+ HairFiberTextureBuffer *fb = fiber_buf;
+
+ HairFollicle *follicle = hsys->pattern->follicles;
+ float nor[3], tang[3];
+ for (int i = 0; i < totfibers; ++i, ++fb, ++follicle) {
+ BKE_mesh_sample_eval(scalp, &follicle->mesh_sample, fb->root_position, nor, tang);
+ for (int k = 0; k < 4; ++k)
+ {
+ fb->parent_index[k] = follicle->parent_index[k];
+ fb->parent_weight[k] = follicle->parent_weight[k];
+ }
+ }
+ }
+}
+
+void BKE_hair_get_texture_buffer_size(
+ const HairSystem *hsys,
+ int subdiv,
+ int *r_size,
+ int *r_strand_map_start,
+ int *r_strand_vertex_start,
+ int *r_fiber_start)
+{
+ int numstrands = hsys->totcurves;
+ int numverts_orig = hsys->totverts;
+ int numfibers = hsys->pattern ? hsys->pattern->num_follicles : 0;
+ const int numverts = hair_get_strand_subdiv_numverts(numstrands, numverts_orig, subdiv);
+ *r_strand_map_start = 0;
+ *r_strand_vertex_start = *r_strand_map_start + numstrands * sizeof(HairStrandMapTextureBuffer);
+ *r_fiber_start = *r_strand_vertex_start + numverts * sizeof(HairStrandVertexTextureBuffer);
+ *r_size = *r_fiber_start + numfibers * sizeof(HairFiberTextureBuffer);
+}
+
+void BKE_hair_get_texture_buffer(
+ const HairSystem *hsys,
+ DerivedMesh *scalp,
+ int subdiv,
+ void *buffer)
+{
+ int size, strand_map_start, strand_vertex_start, fiber_start;
+ BKE_hair_get_texture_buffer_size(hsys, subdiv, &size, &strand_map_start, &strand_vertex_start, &fiber_start);
+
+ if (scalp)
+ {
+ HairStrandMapTextureBuffer *strand_map = (HairStrandMapTextureBuffer*)((char*)buffer + strand_map_start);
+ HairStrandVertexTextureBuffer *strand_verts = (HairStrandVertexTextureBuffer*)((char*)buffer + strand_vertex_start);
+ HairFiberTextureBuffer *fibers = (HairFiberTextureBuffer*)((char*)buffer + fiber_start);
+
+ hair_get_strand_buffer(
+ hsys,
+ scalp,
+ subdiv,
+ strand_map,
+ strand_verts);
+ hair_get_fiber_buffer(
+ hsys,
+ scalp,
+ fibers);
+ }
+ else
+ {
+ memset(buffer, 0, size);
+ }
+}
+
+void (*BKE_hair_batch_cache_dirty_cb)(HairSystem* hsys, int mode) = NULL;
+void (*BKE_hair_batch_cache_free_cb)(HairSystem* hsys) = NULL;
+
+void BKE_hair_batch_cache_dirty(HairSystem* hsys, int mode)
+{
+ if (hsys->draw_batch_cache) {
+ BKE_hair_batch_cache_dirty_cb(hsys, mode);
+ }
+}
+
+void BKE_hair_batch_cache_free(HairSystem* hsys)
+{
+ if (hsys->draw_batch_cache || hsys->draw_texture_cache) {
+ BKE_hair_batch_cache_free_cb(hsys);
+ }
+}