Cleanup: remove redundant doxygen \file argument
[blender.git] / source / blender / blenkernel / intern / subdiv.c
index b2736ed..44990f6 100644 (file)
@@ -1,6 +1,4 @@
 /*
- * ***** 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
  *
  * 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.c
- *  \ingroup bke
+/** \file \ingroup bke
  */
 
 #include "BKE_subdiv.h"
 
 #include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
 #include "DNA_modifier_types.h"
 
 #include "BLI_utildefines.h"
@@ -43,6 +37,8 @@
 #include "opensubdiv_evaluator_capi.h"
 #include "opensubdiv_topology_refiner_capi.h"
 
+/* ========================== CONVERSION HELPERS ============================ */
+
 eSubdivFVarLinearInterpolation
 BKE_subdiv_fvar_interpolation_from_uv_smooth(int uv_smooth)
 {
@@ -64,6 +60,47 @@ BKE_subdiv_fvar_interpolation_from_uv_smooth(int uv_smooth)
        return SUBDIV_FVAR_LINEAR_INTERPOLATION_ALL;
 }
 
+/* ================================ SETTINGS ================================ */
+
+static bool check_mesh_has_non_quad(const Mesh *mesh)
+{
+       for (int poly_index = 0; poly_index < mesh->totpoly; poly_index++) {
+               const MPoly *poly = &mesh->mpoly[poly_index];
+               if (poly->totloop != 4) {
+                       return true;
+               }
+       }
+       return false;
+}
+
+void BKE_subdiv_settings_validate_for_mesh(SubdivSettings *settings,
+                                           const Mesh *mesh)
+{
+       if (settings->level != 1) {
+               return;
+       }
+       if (check_mesh_has_non_quad(mesh)) {
+               settings->level = 2;
+       }
+}
+
+bool BKE_subdiv_settings_equal(const SubdivSettings *settings_a,
+                               const SubdivSettings *settings_b)
+{
+       return
+               (settings_a->is_simple == settings_b->is_simple &&
+                settings_a->is_adaptive == settings_b->is_adaptive &&
+                settings_a->level == settings_b->level &&
+                settings_a->vtx_boundary_interpolation ==
+                        settings_b->vtx_boundary_interpolation &&
+                settings_a->fvar_linear_interpolation ==
+                        settings_b->fvar_linear_interpolation);
+}
+
+/* ============================== CONSTRUCTION ============================== */
+
+/* Creation from scratch. */
+
 Subdiv *BKE_subdiv_new_from_converter(const SubdivSettings *settings,
                                       struct OpenSubdiv_Converter *converter)
 {
@@ -78,13 +115,11 @@ Subdiv *BKE_subdiv_new_from_converter(const SubdivSettings *settings,
                osd_topology_refiner =
                        openSubdiv_createTopologyRefinerFromConverter(
                                converter, &topology_refiner_settings);
-
        }
        else {
                /* TODO(sergey): Check whether original geometry had any vertices.
                 * The thing here is: OpenSubdiv can only deal with faces, but our
-                * side of subdiv also deals with loose vertices and edges.
-                */
+                * side of subdiv also deals with loose vertices and edges. */
        }
        Subdiv *subdiv = MEM_callocN(sizeof(Subdiv), "subdiv from converetr");
        subdiv->settings = *settings;
@@ -97,7 +132,7 @@ Subdiv *BKE_subdiv_new_from_converter(const SubdivSettings *settings,
 }
 
 Subdiv *BKE_subdiv_new_from_mesh(const SubdivSettings *settings,
-                                 struct Mesh *mesh)
+                                 const Mesh *mesh)
 {
        if (mesh->totvert == 0) {
                return NULL;
@@ -109,6 +144,53 @@ Subdiv *BKE_subdiv_new_from_mesh(const SubdivSettings *settings,
        return subdiv;
 }
 
+/* Creation with cached-aware semantic. */
+
+Subdiv *BKE_subdiv_update_from_converter(Subdiv *subdiv,
+                                         const SubdivSettings *settings,
+                                         OpenSubdiv_Converter *converter)
+{
+       /* Check if the existing descriptor can be re-used. */
+       bool can_reuse_subdiv = true;
+       if (subdiv != NULL && subdiv->topology_refiner != NULL) {
+               if (!BKE_subdiv_settings_equal(&subdiv->settings, settings)) {
+                       can_reuse_subdiv = false;
+               }
+               else {
+                       BKE_subdiv_stats_begin(
+                               &subdiv->stats, SUBDIV_STATS_TOPOLOGY_COMPARE);
+                       can_reuse_subdiv = openSubdiv_topologyRefinerCompareWithConverter(
+                               subdiv->topology_refiner, converter);
+                       BKE_subdiv_stats_end(
+                               &subdiv->stats, SUBDIV_STATS_TOPOLOGY_COMPARE);
+               }
+       }
+       else {
+               can_reuse_subdiv = false;
+       }
+       if (can_reuse_subdiv) {
+               return subdiv;
+       }
+       /* Create new subdiv. */
+       if (subdiv != NULL) {
+               BKE_subdiv_free(subdiv);
+       }
+       return BKE_subdiv_new_from_converter(settings, converter);
+}
+
+Subdiv *BKE_subdiv_update_from_mesh(Subdiv *subdiv,
+                                    const SubdivSettings *settings,
+                                    const Mesh *mesh)
+{
+       OpenSubdiv_Converter converter;
+       BKE_subdiv_converter_init_for_mesh(&converter, settings, mesh);
+       subdiv = BKE_subdiv_update_from_converter(subdiv, settings, &converter);
+       BKE_subdiv_converter_free(&converter);
+       return subdiv;
+}
+
+/* Memory release. */
+
 void BKE_subdiv_free(Subdiv *subdiv)
 {
        if (subdiv->evaluator != NULL) {
@@ -124,6 +206,8 @@ void BKE_subdiv_free(Subdiv *subdiv)
        MEM_freeN(subdiv);
 }
 
+/* =========================== PTEX FACES AND GRIDS ========================= */
+
 int *BKE_subdiv_face_ptex_offset_get(Subdiv *subdiv)
 {
        if (subdiv->cache_.face_ptex_offset != NULL) {