diff --git a/.gitignore b/.gitignore
index bcef0eee6a2f054e44a09453040c79788da7f460..a50a9e35add69243704432e9171d98e3f37cd3cc 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,6 +2,7 @@ build/
 tests/__pycache__
 tests/OutFiles
 *.pyc
+*.so
 
 .eggs/
 build-setuptools/
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 6034875cf027ee5b048277c70be0db3873c4cc65..add86a402fd09f1e205b59f9cda93778ed20a693 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -3,23 +3,23 @@ stages:
   - test
   - deploy
 
-build-3.7-VS2017:
+build-3.9-VS2017:
   stage:
     build
   tags:
     - VS2017
-    - python37
+    - Python39
   variables:
     BUILD_PLATFORM: "VS2017"
     ARCHITECTURE: "x64"
   before_script:
     - git submodule sync --recursive
     - git submodule update --init --recursive
-  script: "CI\\build-3.7-VS2017.bat"
+  script: "CI\\build-3.9-VS2017.bat"
   artifacts:
     paths:
       - dist3/
-
+      
 build-3.9-linux:
   stage:
     build
@@ -33,9 +33,9 @@ build-3.9-linux:
     - python setup.py bdist_wheel --dist-dir dist3
   artifacts:
     paths:
-      - dist3/
+      - dist3/      
 
-build-3.5-macos:
+build-3.9-macos:
   stage:
     build
   tags:
@@ -44,39 +44,41 @@ build-3.5-macos:
     GIT_SUBMODULE_STRATEGY: recursive
   script:
     - export PATH=/opt/local/bin:$PATH
-    - virtualenv -p python3.5 .
+    - virtualenv -p python3.9 .
     - source bin/activate
     - python setup.py bdist_wheel --dist-dir dist3
   artifacts:
     paths:
       - dist3/
-
-build-2.7-macos:
+      
+build-3.9-macos-m1:
   stage:
     build
   tags:
-    - Apple
+    - AppleM1
   variables:
     GIT_SUBMODULE_STRATEGY: recursive
   script:
     - export PATH=/opt/local/bin:$PATH
-    - virtualenv -p python2.7 .
+    - virtualenv -p python3.9 .
     - source bin/activate
-    - python setup.py bdist_wheel --dist-dir dist2
+    - python setup.py bdist_wheel --dist-dir dist3
   artifacts:
     paths:
-      - dist2/
+      - dist3/
 
-test-3.7-VS2017:
+test-3.9-VS2017:
   stage:
     test
   tags:
     - VS2017
-    - python37
+    - Python39
   dependencies:
-    - build-3.7-VS2017
-  script: "CI\\test-3.7-VS2017.bat"
+    - build-3.9-VS2017
+  needs: [build-3.9-VS2017]
+  script: "CI\\test-3.9-VS2017.bat"
 
+    
 test-3.9-linux:
   stage:
     test
@@ -84,56 +86,60 @@ test-3.9-linux:
     - Linux
   dependencies:
     - build-3.9-linux
+  needs: [build-3.9-linux]
   script:
     - virtualenv -p python3.9 .
     - source bin/activate
     - pip install dist3/*.whl
     - cd tests
-    - python -m unittest discover
+    - python -m unittest discover    
 
-test-3.5-macos:
+test-3.9-macos:
   stage:
     test
   tags:
     - Apple
   dependencies:
-    - build-3.5-macos
+    - build-3.9-macos
+  needs: [build-3.9-macos]
   script:
     - export PATH=/opt/local/bin:$PATH
-    - virtualenv -p python3.5 .
+    - virtualenv -p python3.9 .
     - source bin/activate
     - pip install dist3/*.whl
     - cd tests
     - python -m unittest discover
 
-test-2.7-macos:
+test-3.9-macos-m1:
   stage:
     test
   tags:
-    - Apple
+    - AppleM1
   dependencies:
-    - build-2.7-macos
+    - build-3.9-macos-m1
+  needs: [build-3.9-macos-m1]
   script:
     - export PATH=/opt/local/bin:$PATH
-    - virtualenv -p python2.7 .
+    - virtualenv -p python3.9 .
     - source bin/activate
-    - pip install dist2/*.whl
+    - pip install dist3/*.whl
     - cd tests
-    - python -m unittest discover
+    - python -m unittest discover    
 
-deploy-3.7-VS2017:
+deploy-3.9-VS2017:
   stage:
     deploy
   tags:
     - VS2017
-    - python37
+    - Python39
   dependencies:
-    - build-3.7-VS2017
-  script: "CI\\deploy-3.7-VS2017.bat"
+    - build-3.9-VS2017
+  needs: [build-3.9-VS2017]
+  script: "CI\\deploy-3.9-VS2017.bat"
   artifacts:
     paths:
       - release/*.whl
-
+     
 deploy-3.9-linux:
   stage:
     deploy
@@ -141,40 +147,43 @@ deploy-3.9-linux:
     - Linux
   dependencies:
     - build-3.9-linux
+  needs: [build-3.9-linux]
   script:
     - mkdir release
     - cp dist3/*.whl release
   artifacts:
     paths:
-      - release/*.whl
+      - release/*.whl      
 
-deploy-3.5-macos:
+deploy-3.9-macos:
   stage:
     deploy
   tags:
     - Apple
   dependencies:
-    - build-3.5-macos
+    - build-3.9-macos
+  needs: [build-3.9-macos]
   script:
     - mkdir release
     - cp dist3/*.whl release
   artifacts:
     paths:
       - release/*.whl
-
-deploy-2.7-macos:
+      
+deploy-3.9-macos-m1:
   stage:
     deploy
   tags:
-    - Apple
+    - AppleM1
   dependencies:
-    - build-2.7-macos
+    - build-3.9-macos-m1
+  needs: [build-3.9-macos-m1]
   script:
     - mkdir release
-    - cp dist2/*.whl release
+    - cp dist3/*.whl release
   artifacts:
     paths:
-      - release/*.whl
+      - release/*.whl      
 
 deploy-sdist:
   stage:
@@ -198,6 +207,7 @@ deploy-documentation:
     - Linux
   dependencies:
     - build-3.9-linux
+  needs: [build-3.9-linux]
   script:
     - virtualenv -p python3.9 .
     - source bin/activate
diff --git a/CI/build-3.7-VS2017.bat b/CI/build-3.7-VS2017.bat
deleted file mode 100644
index f23dd8d1a1db8f8b5034c12050d9a088c41653c4..0000000000000000000000000000000000000000
--- a/CI/build-3.7-VS2017.bat
+++ /dev/null
@@ -1,4 +0,0 @@
-set PATH=C:\Program Files\Python37;C:\Program Files\Python37\Scripts;C:\Program Files\CMake\bin;%PATH%
-virtualenv -p "C:\Program Files\Python37\python.exe" .
-call .\Scripts\activate
-python setup.py bdist_wheel --dist-dir dist3
diff --git a/CI/build-3.9-VS2017.bat b/CI/build-3.9-VS2017.bat
new file mode 100644
index 0000000000000000000000000000000000000000..ffcfd2ac7b141710d36915f3cdf0dbc896ddecb1
--- /dev/null
+++ b/CI/build-3.9-VS2017.bat
@@ -0,0 +1,4 @@
+set PATH=C:\Program Files\Python39;C:\Program Files\Python39\Scripts;C:\Program Files\CMake\bin;%PATH%
+virtualenv.exe -p "C:\Program Files\Python39\python.exe" .
+call .\Scripts\activate
+python setup.py bdist_wheel --dist-dir dist3
diff --git a/CI/deploy-3.7-VS2017.bat b/CI/deploy-3.9-VS2017.bat
similarity index 100%
rename from CI/deploy-3.7-VS2017.bat
rename to CI/deploy-3.9-VS2017.bat
diff --git a/CI/test-3.7-VS2017.bat b/CI/test-3.9-VS2017.bat
similarity index 57%
rename from CI/test-3.7-VS2017.bat
rename to CI/test-3.9-VS2017.bat
index 0e50e09bfe831d6ce6b18d82124ced8c24269563..ea6b67407ad9956c38ba50ff640cdc5edbf2f62e 100644
--- a/CI/test-3.7-VS2017.bat
+++ b/CI/test-3.9-VS2017.bat
@@ -1,5 +1,5 @@
-set PATH=C:\Program Files\Python37;C:\Program Files\Python37\Scripts;%PATH%
-virtualenv -p "C:\Program Files\Python37\python.exe" .
+set PATH=C:\Program Files\Python39;C:\Program Files\Python39\Scripts;%PATH%
+virtualenv -p "C:\Program Files\Python39\python.exe" .
 call .\Scripts\activate
 python -m pip install numpy==1.19.3
 cd dist3
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 38b78674c824d54aa2a9a23cb7667d56adc02a82..569a6198135032baf0d287a80999aa3a7ad884f8 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -16,8 +16,8 @@ if (NOT WIN32)
 	)
 endif ()
 
-acg_append_files(HEADERS "src/*.hh" .)
-acg_append_files(SOURCES "src/*.cc" .)
+vci_append_files(HEADERS "src/*.hh" .)
+vci_append_files(SOURCES "src/*.cc" .)
 
 include_directories(${OPENMESH_INCLUDE_DIRS})
 pybind11_add_module(openmesh ${HEADERS} ${SOURCES})
diff --git a/OpenMesh b/OpenMesh
index 87f2365d20bd742f1a9f1dd876e9de956f584210..c36d8a304c5ab2457eb7969ad440c4b1ea74407b 160000
--- a/OpenMesh
+++ b/OpenMesh
@@ -1 +1 @@
-Subproject commit 87f2365d20bd742f1a9f1dd876e9de956f584210
+Subproject commit c36d8a304c5ab2457eb7969ad440c4b1ea74407b
diff --git a/docs/readwrite.rst b/docs/readwrite.rst
index 75dffb709c6166366dba9981b2f6dcf5f8da787c..c47743e3de741d25a7f4ac39cab62a1b9dbb51d8 100644
--- a/docs/readwrite.rst
+++ b/docs/readwrite.rst
@@ -16,3 +16,15 @@ OpenMesh provides functions that read and write meshes from and to files:
     om.write_mesh(trimesh, "bunny.ply")
 
 OpenMesh currently supports five file types: .obj, .off, .ply, .stl and .om
+
+For writing .obj files there is also support for textures. You can pass the path of a texture image and
+optionally the suffix for the material file, default is ".mat", but some programs, e.g. Blender expect ".mtl" as suffix
+
+.. code:: python
+
+    om.write_mesh(
+        "out.obj",
+        trimesh,
+        texture_file="moon.png",
+        material_file_extension=".mtl"  # default is ".mat", blender needs ".mtl"
+    )
diff --git a/pybind11 b/pybind11
index f1abf5d9159b805674197f6bc443592e631c9130..2dd52544942be4bef80811ef18c8fcf1d3c7e246 160000
--- a/pybind11
+++ b/pybind11
@@ -1 +1 @@
-Subproject commit f1abf5d9159b805674197f6bc443592e631c9130
+Subproject commit 2dd52544942be4bef80811ef18c8fcf1d3c7e246
diff --git a/setup.py b/setup.py
index f5b9888773f8c24a37321e1dae507d00dcf2808a..c916177bfa9760d92a9fc345466541fd87ce6a73 100644
--- a/setup.py
+++ b/setup.py
@@ -100,6 +100,7 @@ setup(
         'Programming Language :: Python :: 2.7',
         'Programming Language :: Python :: 3.5',
         'Programming Language :: Python :: 3.6',
+        'Programming Language :: Python :: 3.9',
         'Topic :: Multimedia :: Graphics',
     ],
     project_urls={
diff --git a/src/InputOutput.cc b/src/InputOutput.cc
index 0c840c0c915a2aa1659bb40f196467b811be8a1c..2012297f9919a6d4e913a66ace308fbb02b2e669 100644
--- a/src/InputOutput.cc
+++ b/src/InputOutput.cc
@@ -24,7 +24,11 @@ void def_read_mesh(py::module& m, const char *_name) {
 			bool _face_color,
 			bool _face_texture_index,
 			bool _color_alpha,
-			bool _color_float
+			bool _color_float,
+			bool _vertex_status,
+			bool _halfedge_status,
+			bool _edge_status,
+			bool _face_status
 		)
 		{
 			Mesh mesh;
@@ -70,6 +74,24 @@ void def_read_mesh(py::module& m, const char *_name) {
 			if (_face_texture_index) {
 				mesh.request_face_texture_index();
 			}
+			if (_vertex_status) {
+				mesh.request_vertex_status();
+			}
+			if (_edge_status) {
+				mesh.request_vertex_status();
+			}
+			if (_halfedge_status) {
+				mesh.request_halfedge_status();
+			}
+			if (_edge_status) {
+				mesh.request_edge_status();
+			}
+			if (_face_status) {
+				mesh.request_face_status();
+			}
+			if (_face_status || _halfedge_status || _edge_status || _face_status) {
+				options += OM::IO::Options::Status;
+			}
 
 			if (_color_alpha) options += OM::IO::Options::ColorAlpha;
 			if (_color_float) options += OM::IO::Options::ColorFloat;
@@ -126,7 +148,11 @@ void def_read_mesh(py::module& m, const char *_name) {
 		py::arg("face_color")=false,
 		py::arg("face_texture_index")=false,
 		py::arg("color_alpha")=false,
-		py::arg("color_float")=false
+		py::arg("color_float")=false,
+		py::arg("vertex_status")=false,
+		py::arg("halfedge_status")=false,
+		py::arg("edge_status")=false,
+		py::arg("face_status")=false
 	);
 }
 
@@ -148,7 +174,10 @@ void def_write_mesh(py::module& m) {
 			bool _face_normal,
 			bool _face_color,
 			bool _color_alpha,
-			bool _color_float
+			bool _color_float,
+			bool _status,
+			const std::string& _texture_file = "",
+			const std::string& _material_file_extension = ".mat"
 		)
 		{
 			OM::IO::Options options;
@@ -168,6 +197,10 @@ void def_write_mesh(py::module& m) {
 
 			if (_color_alpha) options += OM::IO::Options::ColorAlpha;
 			if (_color_float) options += OM::IO::Options::ColorFloat;
+			options.texture_file = _texture_file;
+			options.material_file_extension = _material_file_extension;
+
+			if (_status) options += OM::IO::Options::Status;
 
 			const bool ok = OM::IO::write_mesh(_mesh, _filename, options);
 
@@ -191,7 +224,10 @@ void def_write_mesh(py::module& m) {
 		py::arg("face_normal")=false,
 		py::arg("face_color")=false,
 		py::arg("color_alpha")=false,
-		py::arg("color_float")=false
+		py::arg("color_float")=false,
+		py::arg("status")=false,
+		py::arg("texture_file")="",
+		py::arg("material_file_extension")=".mat"
 	);
 }
 
diff --git a/src/Mesh.hh b/src/Mesh.hh
index 7af6043c78890c0324da9ea0bdef47293a6b0a06..0a9f6a74bb156c8cb8139acfc1ec1b05b499ffd8 100644
--- a/src/Mesh.hh
+++ b/src/Mesh.hh
@@ -719,10 +719,21 @@ void expose_mesh(py::module& m, const char *_name) {
 				_self.status(_h).set_deleted(_val);
 			})
 
-		.def("is_deleted", [](Mesh& _self, OM::HalfedgeHandle _h) {
-				if (!_self.has_halfedge_status()) return false;
-				return _self.status(_h).deleted();
-			})
+        .def("is_locked", [](Mesh& _self, OM::VertexHandle _h) {
+            if (!_self.has_vertex_status()) return false;
+            return _self.status(_h).locked();
+        })
+
+        .def("set_locked", [](Mesh& _self, OM::VertexHandle _h, bool _val) {
+            if (!_self.has_vertex_status()) _self.request_vertex_status();
+            _self.status(_h).set_locked(_val);
+
+        })
+
+        .def("is_deleted", [](Mesh& _self, OM::HalfedgeHandle _h) {
+            if (!_self.has_halfedge_status()) return false;
+            return _self.status(_h).deleted();
+        })
 
 		.def("set_deleted", [](Mesh& _self, OM::HalfedgeHandle _h, bool _val) {
 				if (!_self.has_halfedge_status()) _self.request_halfedge_status();
@@ -843,6 +854,23 @@ void expose_mesh(py::module& m, const char *_name) {
 				}
 			})
 
+		.def("set_feature", [](Mesh& _self, OM::EdgeHandle _h, bool val) {
+				if (!_self.has_edge_status()) _self.request_edge_status();
+				return _self.status(_h).set_feature(val);
+			})
+		.def("feature", [](Mesh& _self, OM::EdgeHandle _h) {
+				if (!_self.has_edge_status()) _self.request_edge_status();
+				return _self.status(_h).feature();
+			})
+		.def("set_feature", [](Mesh& _self, OM::VertexHandle _h, bool val) {
+				if (!_self.has_vertex_status()) _self.request_vertex_status();
+				return _self.status(_h).set_feature(val);
+			})
+		.def("feature", [](Mesh& _self, OM::VertexHandle _h) {
+				if (!_self.has_vertex_status()) _self.request_vertex_status();
+				return _self.status(_h).feature();
+			})
+
 		//======================================================================
 		//  BaseKernel
 		//======================================================================
@@ -893,13 +921,21 @@ void expose_mesh(py::module& m, const char *_name) {
 		.def("valence", valence_fh)
 		.def("is_simple_link", &Mesh::is_simple_link)
 		.def("is_simply_connected", &Mesh::is_simply_connected)
-		.def("remove_edge", &Mesh::remove_edge)
-		.def("reinsert_edge", &Mesh::reinsert_edge)
 		.def("triangulate", triangulate_fh)
 		.def("triangulate", triangulate_void)
 		.def("split_edge", &Mesh::split_edge)
 		.def("split_edge_copy", &Mesh::split_edge_copy)
 
+		.def("remove_edge", [](Mesh& _self, OM::EdgeHandle _eh) {
+				if (!_self.has_edge_status()) _self.request_edge_status();
+				if (!_self.has_face_status()) _self.request_face_status();
+				return _self.remove_edge(_eh);
+			})
+		.def("reinsert_edge", [](Mesh& _self, OM::EdgeHandle _eh) {
+				if (!_self.has_edge_status()) _self.request_edge_status();
+				if (!_self.has_face_status()) _self.request_face_status();
+				_self.reinsert_edge(_eh);
+			})
 		.def("is_collapse_ok", [](Mesh& _self, OM::HalfedgeHandle _heh) {
 				if (!_self.has_vertex_status()) _self.request_vertex_status();
 				if (!_self.has_halfedge_status()) _self.request_halfedge_status();