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/subdiv_eval.c')
-rw-r--r--source/blender/blenkernel/intern/subdiv_eval.c319
1 files changed, 319 insertions, 0 deletions
diff --git a/source/blender/blenkernel/intern/subdiv_eval.c b/source/blender/blenkernel/intern/subdiv_eval.c
new file mode 100644
index 00000000000..0ab19fc8df5
--- /dev/null
+++ b/source/blender/blenkernel/intern/subdiv_eval.c
@@ -0,0 +1,319 @@
+/*
+ * ***** 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) 2018 by Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Sergey Sharybin.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/subdiv_eval.c
+ * \ingroup bke
+ */
+
+#include "BKE_subdiv.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_math_vector.h"
+
+#include "BKE_customdata.h"
+
+#ifdef WITH_OPENSUBDIV
+# include "opensubdiv_evaluator_capi.h"
+# include "opensubdiv_topology_refiner_capi.h"
+#endif
+
+void BKE_subdiv_eval_begin(Subdiv *subdiv)
+{
+#ifdef WITH_OPENSUBDIV
+ if (subdiv->evaluator == NULL) {
+ subdiv->evaluator = openSubdiv_createEvaluatorFromTopologyRefiner(
+ subdiv->topology_refiner);
+ }
+ else {
+ /* TODO(sergey): Check for topology change. */
+ }
+#else
+ UNUSED_VARS(subdiv);
+#endif
+}
+
+#ifdef WITH_OPENSUBDIV
+static void set_face_varying_data_from_uv(Subdiv *subdiv,
+ const MLoopUV *mloopuv,
+ const int layer_index)
+{
+ OpenSubdiv_TopologyRefiner *topology_refiner = subdiv->topology_refiner;
+ OpenSubdiv_Evaluator *evaluator = subdiv->evaluator;
+ const int num_faces = topology_refiner->getNumFaces(topology_refiner);
+ const MLoopUV *mluv = mloopuv;
+ /* TODO(sergey): OpenSubdiv's C-API converter can change winding of
+ * loops of a face, need to watch for that, to prevent wrong UVs assigned.
+ */
+ for (int face_index = 0; face_index < num_faces; ++face_index) {
+ const int num_face_vertices = topology_refiner->getNumFaceVertices(
+ topology_refiner, face_index);
+ const int *uv_indicies = topology_refiner->getFaceFVarValueIndices(
+ topology_refiner, face_index, layer_index);
+ for (int vertex_index = 0;
+ vertex_index < num_face_vertices;
+ vertex_index++, mluv++)
+ {
+ evaluator->setFaceVaryingData(evaluator,
+ mluv->uv,
+ uv_indicies[vertex_index],
+ 1);
+ }
+ }
+}
+#endif
+
+void BKE_subdiv_eval_update_from_mesh(Subdiv *subdiv, const Mesh *mesh)
+{
+#ifdef WITH_OPENSUBDIV
+ BKE_subdiv_eval_begin(subdiv);
+ /* Set coordinates of base mesh vertices. */
+ subdiv->evaluator->setCoarsePositionsFromBuffer(
+ subdiv->evaluator,
+ mesh->mvert,
+ offsetof(MVert, co),
+ sizeof(MVert),
+ 0, mesh->totvert);
+ /* Set face-varyign data to UV maps. */
+ const int num_uv_layers =
+ CustomData_number_of_layers(&mesh->ldata, CD_MLOOPUV);
+ for (int layer_index = 0; layer_index < num_uv_layers; layer_index++) {
+ const MLoopUV *mloopuv = CustomData_get_layer_n(
+ &mesh->ldata, CD_MLOOPUV, layer_index);
+ set_face_varying_data_from_uv(subdiv, mloopuv, layer_index);
+ /* NOTE: Currently evaluator can only handle single face varying layer.
+ * This is a limitation of C-API and some underlying helper classes from
+ * our side which will get fixed.
+ */
+ break;
+ }
+ /* Update evaluator to the new coarse geometry. */
+ subdiv->evaluator->refine(subdiv->evaluator);
+#else
+ UNUSED_VARS(subdiv, mesh);
+#endif
+}
+
+/* ========================== Single point queries ========================== */
+
+void BKE_subdiv_eval_limit_point(
+ Subdiv *subdiv,
+ const int ptex_face_index,
+ const float u, const float v,
+ float P[3])
+{
+ BKE_subdiv_eval_limit_point_and_derivatives(subdiv,
+ ptex_face_index,
+ u, v,
+ P, NULL, NULL);
+}
+
+void BKE_subdiv_eval_limit_point_and_derivatives(
+ Subdiv *subdiv,
+ const int ptex_face_index,
+ const float u, const float v,
+ float P[3], float dPdu[3], float dPdv[3])
+{
+#ifdef WITH_OPENSUBDIV
+ subdiv->evaluator->evaluateLimit(subdiv->evaluator,
+ ptex_face_index,
+ u, v,
+ P, dPdu, dPdv);
+#else
+ UNUSED_VARS(subdiv, ptex_face_index, u, v, P, dPdu, dPdv);
+#endif
+}
+
+void BKE_subdiv_eval_limit_point_and_normal(
+ Subdiv *subdiv,
+ const int ptex_face_index,
+ const float u, const float v,
+ float P[3], float N[3])
+{
+ float dPdu[3], dPdv[3];
+ BKE_subdiv_eval_limit_point_and_derivatives(subdiv,
+ ptex_face_index,
+ u, v,
+ P, dPdu, dPdv);
+ cross_v3_v3v3(N, dPdu, dPdv);
+ normalize_v3(N);
+}
+
+void BKE_subdiv_eval_limit_point_and_short_normal(
+ Subdiv *subdiv,
+ const int ptex_face_index,
+ const float u, const float v,
+ float P[3], short N[3])
+{
+ float N_float[3];
+ BKE_subdiv_eval_limit_point_and_normal(subdiv,
+ ptex_face_index,
+ u, v,
+ P, N_float);
+ normal_float_to_short_v3(N, N_float);
+}
+
+void BKE_subdiv_eval_face_varying(
+ Subdiv *subdiv,
+ const int ptex_face_index,
+ const float u, const float v,
+ float face_varying[2])
+{
+#ifdef WITH_OPENSUBDIV
+ subdiv->evaluator->evaluateFaceVarying(subdiv->evaluator,
+ ptex_face_index,
+ u, v,
+ face_varying);
+#else
+ UNUSED_VARS(subdiv, ptex_face_index, u, v, face_varying);
+#endif
+}
+
+/* =================== Patch queries at given resolution =================== */
+
+/* Move buffer forward by a given number of bytes. */
+static void buffer_apply_offset(void **buffer, const int offset)
+{
+ *buffer = ((unsigned char *)*buffer) + offset;
+}
+
+/* Write given number of floats to the beginning of given buffer. */
+static void buffer_write_float_value(void **buffer,
+ const float *values_buffer, int num_values)
+{
+ memcpy(*buffer, values_buffer, sizeof(float) * num_values);
+}
+
+/* Similar to above, just operates with short values. */
+static void buffer_write_short_value(void **buffer,
+ const short *values_buffer, int num_values)
+{
+ memcpy(*buffer, values_buffer, sizeof(short) * num_values);
+}
+
+void BKE_subdiv_eval_limit_patch_resolution_point(
+ Subdiv *subdiv,
+ const int ptex_face_index,
+ const int resolution,
+ void *buffer, const int offset, const int stride)
+{
+ buffer_apply_offset(&buffer, offset);
+ const float inv_resolution_1 = 1.0f / (float)(resolution - 1);
+ for (int y = 0; y < resolution; y++) {
+ const float v = y * inv_resolution_1;
+ for (int x = 0; x < resolution; x++) {
+ const float u = x * inv_resolution_1;
+ BKE_subdiv_eval_limit_point(subdiv,
+ ptex_face_index,
+ u, v,
+ buffer);
+ buffer_apply_offset(&buffer, stride);
+ }
+ }
+}
+
+void BKE_subdiv_eval_limit_patch_resolution_point_and_derivatives(
+ Subdiv *subdiv,
+ const int ptex_face_index,
+ const int resolution,
+ void *point_buffer, const int point_offset, const int point_stride,
+ void *du_buffer, const int du_offset, const int du_stride,
+ void *dv_buffer, const int dv_offset, const int dv_stride)
+{
+ buffer_apply_offset(&point_buffer, point_offset);
+ buffer_apply_offset(&du_buffer, du_offset);
+ buffer_apply_offset(&dv_buffer, dv_offset);
+ const float inv_resolution_1 = 1.0f / (float)(resolution - 1);
+ for (int y = 0; y < resolution; y++) {
+ const float v = y * inv_resolution_1;
+ for (int x = 0; x < resolution; x++) {
+ const float u = x * inv_resolution_1;
+ BKE_subdiv_eval_limit_point_and_derivatives(
+ subdiv,
+ ptex_face_index,
+ u, v,
+ point_buffer, du_buffer, dv_buffer);
+ buffer_apply_offset(&point_buffer, point_stride);
+ buffer_apply_offset(&du_buffer, du_stride);
+ buffer_apply_offset(&dv_buffer, dv_stride);
+ }
+ }
+}
+
+void BKE_subdiv_eval_limit_patch_resolution_point_and_normal(
+ Subdiv *subdiv,
+ const int ptex_face_index,
+ const int resolution,
+ void *point_buffer, const int point_offset, const int point_stride,
+ void *normal_buffer, const int normal_offset, const int normal_stride)
+{
+ buffer_apply_offset(&point_buffer, point_offset);
+ buffer_apply_offset(&normal_buffer, normal_offset);
+ const float inv_resolution_1 = 1.0f / (float)(resolution - 1);
+ for (int y = 0; y < resolution; y++) {
+ const float v = y * inv_resolution_1;
+ for (int x = 0; x < resolution; x++) {
+ const float u = x * inv_resolution_1;
+ float normal[3];
+ BKE_subdiv_eval_limit_point_and_normal(
+ subdiv,
+ ptex_face_index,
+ u, v,
+ point_buffer, normal);
+ buffer_write_float_value(&normal_buffer, normal, 3);
+ buffer_apply_offset(&point_buffer, point_stride);
+ buffer_apply_offset(&normal_buffer, normal_stride);
+ }
+ }
+}
+
+void BKE_subdiv_eval_limit_patch_resolution_point_and_short_normal(
+ Subdiv *subdiv,
+ const int ptex_face_index,
+ const int resolution,
+ void *point_buffer, const int point_offset, const int point_stride,
+ void *normal_buffer, const int normal_offset, const int normal_stride)
+{
+ buffer_apply_offset(&point_buffer, point_offset);
+ buffer_apply_offset(&normal_buffer, normal_offset);
+ const float inv_resolution_1 = 1.0f / (float)(resolution - 1);
+ for (int y = 0; y < resolution; y++) {
+ const float v = y * inv_resolution_1;
+ for (int x = 0; x < resolution; x++) {
+ const float u = x * inv_resolution_1;
+ short normal[3];
+ BKE_subdiv_eval_limit_point_and_short_normal(
+ subdiv,
+ ptex_face_index,
+ u, v,
+ point_buffer, normal);
+ buffer_write_short_value(&normal_buffer, normal, 3);
+ buffer_apply_offset(&point_buffer, point_stride);
+ buffer_apply_offset(&normal_buffer, normal_stride);
+ }
+ }
+}