[Bf-blender-cvs] [7dd57300038] temp-cryptomatte-manifest-parser: Cryptomatte manifest reader.

Jeroen Bakker noreply at git.blender.org
Fri Feb 26 10:04:28 CET 2021


Commit: 7dd57300038794255e2cac76b38ff552a9163c4d
Author: Jeroen Bakker
Date:   Fri Feb 26 10:03:14 2021 +0100
Branches: temp-cryptomatte-manifest-parser
https://developer.blender.org/rB7dd57300038794255e2cac76b38ff552a9163c4d

Cryptomatte manifest reader.

With the cryptomatte manifest reader it is possible to construct a
cryptomatte layer from a manifest.

===================================================================

M	source/blender/blenkernel/BKE_cryptomatte.hh
M	source/blender/blenkernel/intern/cryptomatte.cc
M	source/blender/blenkernel/intern/cryptomatte_test.cc

===================================================================

diff --git a/source/blender/blenkernel/BKE_cryptomatte.hh b/source/blender/blenkernel/BKE_cryptomatte.hh
index 00969c0b52c..5849139f2cd 100644
--- a/source/blender/blenkernel/BKE_cryptomatte.hh
+++ b/source/blender/blenkernel/BKE_cryptomatte.hh
@@ -64,10 +64,7 @@ struct CryptomatteLayer {
   MEM_CXX_CLASS_ALLOC_FUNCS("cryptomatte:CryptomatteLayer")
 #endif
 
-  CryptomatteLayer();
-  /** Create a cryptomatte layer from the given manifest. */
-  CryptomatteLayer(blender::StringRefNull manifest);
-
+  static std::unique_ptr<CryptomatteLayer> read_from_manifest(blender::StringRefNull manifest);
   static std::string encode_hash(uint32_t cryptomatte_hash);
   void add_hash(blender::StringRef name, uint32_t cryptomatte_hash);
   void add_encoded_hash(blender::StringRef name, blender::StringRefNull cryptomatte_encoded_hash);
diff --git a/source/blender/blenkernel/intern/cryptomatte.cc b/source/blender/blenkernel/intern/cryptomatte.cc
index 492138b8783..fa5bc157bc1 100644
--- a/source/blender/blenkernel/intern/cryptomatte.cc
+++ b/source/blender/blenkernel/intern/cryptomatte.cc
@@ -315,12 +315,12 @@ StringRef BKE_cryptomatte_extract_layer_name(const StringRef render_pass_name)
   return render_pass_name.substr(0, last_token);
 }
 
-struct CryptomatteManifestParser {
-  int skip_whitespaces_len_(blender::StringRef manifest)
+struct CryptomatteManifestReader {
+  static constexpr int skip_whitespaces_len_(blender::StringRef ref)
   {
     int skip_len = 0;
-    while (!manifest.is_empty()) {
-      char front = manifest[skip_len];
+    while (skip_len < ref.size()) {
+      char front = ref[skip_len];
       if (!std::isspace<char>(front, std::locale::classic())) {
         break;
       }
@@ -329,24 +329,56 @@ struct CryptomatteManifestParser {
     return skip_len;
   }
 
-  int quoted_string_len_(blender::StringRef ref)
+  static constexpr blender::StringRef skip_whitespaces_(blender::StringRef ref)
+  {
+    return ref.drop_prefix(skip_whitespaces_len_(ref));
+  }
+
+  static constexpr int quoted_string_len_(blender::StringRef ref)
   {
     int len = 1;
+    bool skip_next = false;
     while (len < ref.size()) {
       char current_char = ref[len];
-      if (current_char == '\"') {
-        len += 1;
-        break;
+      if (skip_next) {
+        skip_next = false;
+      }
+      else {
+        if (current_char == '\\') {
+          skip_next = true;
+        }
+        if (current_char == '\"') {
+          len += 1;
+          break;
+        }
       }
       len += 1;
     }
     return len;
   }
 
-  bool parse(CryptomatteLayer &layer, blender::StringRefNull manifest)
+  static std::string unquote_(const blender::StringRef ref)
+  {
+    std::ostringstream stream;
+    for (char c : ref) {
+      if (c != '\\') {
+        stream << c;
+      }
+    }
+    return stream.str();
+  }
+
+  static uint32_t decode_hash_(const blender::StringRef ref)
+  {
+    uint32_t result;
+    std::istringstream(ref) >> std::hex >> result;
+    return result;
+  }
+
+  static bool parse(CryptomatteLayer &layer, blender::StringRefNull manifest)
   {
     StringRef ref = manifest;
-    ref = ref.drop_prefix(skip_whitespaces_len_(ref));
+    ref = skip_whitespaces_(ref);
     if (ref.is_empty() || ref.front() != '{') {
       return false;
     }
@@ -357,32 +389,36 @@ struct CryptomatteManifestParser {
       if (front == '\"') {
         const int quoted_name_len = quoted_string_len_(ref);
         const int name_len = quoted_name_len - 2;
-        blender::StringRef name = ref.substr(1, name_len);
+        std::string name = unquote_(ref.substr(1, name_len));
         ref = ref.drop_prefix(quoted_name_len);
-        ref = ref.drop_prefix(skip_whitespaces_len_(ref));
+        ref = skip_whitespaces_(ref);
 
         char colon = ref.front();
         if (colon != ':') {
           return false;
         }
-        ref = ref.drop_prefix(skip_whitespaces_len_(ref));
+        ref = ref.drop_prefix(1);
+        ref = skip_whitespaces_(ref);
+
+        if (ref.front() != '\"') {
+          return false;
+        }
 
         const int quoted_hash_len = quoted_string_len_(ref);
         const int hash_len = quoted_hash_len - 2;
-        blender::StringRef hash = ref.substr(1, hash_len);
+        uint32_t hash = decode_hash_(ref.substr(1, hash_len));
         ref = ref.drop_prefix(quoted_hash_len);
-        layer.add_encoded_hash(name, blender::StringRefNull(hash));
+        layer.add_hash(name, hash);
       }
-      if (front == ',') {
+      else if (front == ',') {
         ref = ref.drop_prefix(1);
       }
-      if (front == '}') {
+      else if (front == '}') {
         ref = ref.drop_prefix(1);
-        ref = ref.drop_prefix(skip_whitespaces_len_(ref));
-
+        ref = skip_whitespaces_(ref);
         break;
       }
-      ref = ref.drop_prefix(skip_whitespaces_len_(ref));
+      ref = skip_whitespaces_(ref);
     }
 
     if (!ref.is_empty()) {
@@ -393,14 +429,12 @@ struct CryptomatteManifestParser {
   }
 };
 
-CryptomatteLayer::CryptomatteLayer()
-{
-}
-
-CryptomatteLayer::CryptomatteLayer(blender::StringRefNull manifest)
+std::unique_ptr<CryptomatteLayer> CryptomatteLayer::read_from_manifest(
+    blender::StringRefNull manifest)
 {
-  CryptomatteManifestParser parser;
-  parser.parse(*this, manifest);
+  std::unique_ptr<CryptomatteLayer> layer = std::make_unique<CryptomatteLayer>();
+  CryptomatteManifestReader::parse(*layer.get(), manifest);
+  return layer;
 }
 
 std::string CryptomatteLayer::encode_hash(uint32_t cryptomatte_hash)
diff --git a/source/blender/blenkernel/intern/cryptomatte_test.cc b/source/blender/blenkernel/intern/cryptomatte_test.cc
index fe80d919d23..010c809eed5 100644
--- a/source/blender/blenkernel/intern/cryptomatte_test.cc
+++ b/source/blender/blenkernel/intern/cryptomatte_test.cc
@@ -60,9 +60,25 @@ TEST(cryptomatte, cryptomatte_layer_quoted)
   ASSERT_EQ("{\"\\\"Object\\\"\":\"0000007b\"}", layer.manifest());
 }
 
+static void test_cryptomatte_manifest(std::string expected, std::string manifest)
+{
+  EXPECT_EQ(expected, blender::CryptomatteLayer::read_from_manifest(manifest)->manifest());
+}
+
 TEST(cryptomatte, cryptomatte_layer_from_manifest)
 {
-  ASSERT_EQ("{}", blender::CryptomatteLayer("{}").manifest());
+  test_cryptomatte_manifest("{}", "{}");
+  test_cryptomatte_manifest("{\"Object\":\"12345678\"}", "{\"Object\": \"12345678\"}");
+  test_cryptomatte_manifest("{\"Object\":\"12345678\",\"Object2\":\"87654321\"}",
+                            "{\"Object\":\"12345678\",\"Object2\":\"87654321\"}");
+  test_cryptomatte_manifest(
+      "{\"Object\":\"12345678\",\"Object2\":\"87654321\"}",
+      "  {  \"Object\"  :  \"12345678\"  ,  \"Object2\"  :  \"87654321\"  }  ");
+  test_cryptomatte_manifest("{\"Object\\\"01\\\"\":\"12345678\"}",
+                            "{\"Object\\\"01\\\"\": \"12345678\"}");
+  test_cryptomatte_manifest(
+      "{\"Object\\\"01\\\"\":\"12345678\",\"Object\":\"12345678\",\"Object2\":\"87654321\"}",
+      "{\"Object\\\"01\\\"\":\"12345678\",\"Object\":\"12345678\", \"Object2\":\"87654321\"}");
 }
 
 }  // namespace blender::bke::tests



More information about the Bf-blender-cvs mailing list