Skip to content
Snippets Groups Projects
Commit 8355f2c2 authored by Nicolas Pope's avatar Nicolas Pope
Browse files

Merge branch 'master' into exp/fusionmodel

parents 8aea8645 a60fa0b3
No related branches found
No related tags found
1 merge request!358Updates to SDK and alternative fusion
Showing
with 297 additions and 154 deletions
[submodule "ext/nanogui"]
path = ext/nanogui
url = https://github.com/wjakob/nanogui.git
[submodule "SDK/C++/public/ext/pybind11"]
path = SDK/C++/public/ext/pybind11
[submodule "SDK/CPP/public/ext/pybind11"]
path = SDK/CPP/public/ext/pybind11
url = https://github.com/pybind/pybind11.git
......@@ -11,17 +11,41 @@ add_library(voltu SHARED
private/property_impl.cpp
)
file(READ "public/include/voltu/voltu.hpp" VOLVER)
string(REGEX MATCH "VOLTU_VERSION_MAJOR ([0-9]*)" _ ${VOLVER})
set(VOLTU_MAJOR ${CMAKE_MATCH_1})
string(REGEX MATCH "VOLTU_VERSION_MINOR ([0-9]*)" _ ${VOLVER})
set(VOLTU_MINOR ${CMAKE_MATCH_1})
string(REGEX MATCH "VOLTU_VERSION_PATCH ([0-9]*)" _ ${VOLVER})
set(VOLTU_PATCH ${CMAKE_MATCH_1})
message("VolTu SDK version: ${VOLTU_MAJOR}.${VOLTU_MINOR}.${VOLTU_PATCH}")
set_target_properties( voltu PROPERTIES
VERSION "${VOLTU_MAJOR}.${VOLTU_MINOR}"
SOVERSION "${VOLTU_MAJOR}.${VOLTU_MINOR}"
)
target_include_directories(voltu
PUBLIC public/include
PRIVATE src)
target_link_libraries(voltu ftlcommon ftldata ftlctrl ftlrgbd ftlstreams ftlrender Threads::Threads ${OpenCV_LIBS} openvr ftlnet nanogui ${NANOGUI_EXTRA_LIBS} ceres nvidia-ml)
set(SDK_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/sdk")
ExternalProject_Add(
voltu_sdk
SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/public"
BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/sdk"
BINARY_DIR ${SDK_BINARY_DIR}
INSTALL_COMMAND ""
BUILD_ALWAYS true
CMAKE_ARGS -DOpenCV_DIR=${OpenCV_DIR}
CMAKE_ARGS -DOpenCV_DIR=${OpenCV_DIR} -DWITH_PYTHON=True
)
if (BUILD_TESTS)
add_subdirectory(tests)
endif()
......@@ -16,7 +16,7 @@ RoomImpl::~RoomImpl()
if (filter_) filter_->remove();
}
bool RoomImpl::waitNextFrame(int64_t timeout)
bool RoomImpl::waitNextFrame(int64_t timeout, bool except)
{
if (!filter_)
{
......@@ -40,10 +40,15 @@ bool RoomImpl::waitNextFrame(int64_t timeout)
return last_read_ < last_seen_;
});
if (except && last_read_ >= last_seen_)
{
throw voltu::exceptions::Timeout();
}
return last_read_ < last_seen_;
}
else if (timeout == 0)
{
if (except) throw voltu::exceptions::Timeout();
return false;
}
else
......
......@@ -16,7 +16,7 @@ public:
~RoomImpl() override;
bool waitNextFrame(int64_t) override;
bool waitNextFrame(int64_t, bool except) override;
voltu::FramePtr getFrame() override;
......
......@@ -87,6 +87,11 @@ std::list<voltu::RoomId> SystemImpl::listRooms()
voltu::RoomPtr SystemImpl::getRoom(voltu::RoomId id)
{
if (feed_->getURI(id).size() == 0)
{
throw voltu::exceptions::InvalidRoomId();
}
auto s = std::make_shared<voltu::internal::RoomImpl>(feed_);
s->addFrameSet(id);
return s;
......
......@@ -5,13 +5,13 @@ project (voltu_sdk VERSION 0.0.1)
include(GNUInstallDirs)
option(WITH_OPENCV "Build with OpenCV wrapper" ON)
option(WITH_PYTHON "Build Python module" OFF)
option(WITH_PYTHON "Build Python module" ON)
find_package( Eigen3 REQUIRED NO_MODULE )
find_package( Threads REQUIRED )
find_package(Eigen3 REQUIRED NO_MODULE)
find_package(Threads REQUIRED)
if (WITH_OPENCV)
find_package( OpenCV REQUIRED )
find_package(OpenCV REQUIRED)
endif()
if(WIN32)
......@@ -68,7 +68,30 @@ add_executable(voltu_fusion_evaluator
)
target_link_libraries(voltu_fusion_evaluator voltu_sdk)
find_package (Python COMPONENTS Development.Module Interpreter)
function(find_python_module module)
string(TOUPPER ${module} module_upper)
if(NOT PY_${module_upper})
execute_process(COMMAND "${Python_EXECUTABLE}" "-c"
"import ${module}; print(${module}.__file__.rstrip('__init__.py'))"
RESULT_VARIABLE _${module}_status
OUTPUT_VARIABLE _${module}_location
ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)
if(NOT _${module}_status)
set(PY_${module_upper} ${_${module}_location} CACHE STRING
"Location of Python module ${module}")
endif(NOT _${module}_status)
endif(NOT PY_${module_upper})
find_package_handle_standard_args(PY_${module} DEFAULT_MSG PY_${module_upper})
endfunction(find_python_module)
if (WITH_PYTHON)
add_subdirectory(ext/pybind11)
add_subdirectory(python)
find_python_module(ply)
if (Python_FOUND AND PY_PLY)
add_subdirectory(ext/pybind11)
add_subdirectory(python)
else()
message(WARNING "Python dependencies not found, Python module is not built")
endif()
endif()
Subproject commit 06b673a0daef1db4f921a19676a51abec6fb13e8
/**
* @file system.hpp
* @file defines.hpp
* @copyright Copyright (c) 2020 Sebastian Hahta, MIT License
* @author Sebastian Hahta
*/
......@@ -20,3 +20,15 @@
/// Lifetime of the return value is tied to the lifetime of a parent object
#define PY_RV_LIFETIME_PARENT
#endif
#ifndef PY_SINGLETON
/// Singleton instance, members exported to module. Requires creating the
/// instance in PyModule constructor.
#define PY_SINGLETON
#endif
#ifndef PY_SINGLETON_OBJECT
/// Export as singleton instance instead of exporting members to module
#define PY_SINGLETON_OBJECT
#endif
......@@ -13,34 +13,34 @@ namespace voltu
{
/**
* @brief Get core VolTu instance.
*
*
* This method returns a smart pointer to a singleton VolTu runtime
* instance and must be the first VolTu call. On any given machine it is
* only sensible and possible to have one runtime instance of VolTu due to
* its use of hardware devices. Multiple real instances are not possible.
*
*
* @code
* int main(int argc, char** argv) {
* auto vtu = voltu::instance();
*
*
* vtu->open("device:camera");
* ...
* }
* @endcode
*
*
* @note
* This method must only be called once.
*
*
* @throw voltu::exceptions::LibraryLoadFailed
* If runtime not found or is invalid.
*
* @throw voltu::exceptions::RuntimeVersionMismatch
* If major or minor version does not match the SDK headers.
*
*
* @throw voltu::exceptions::RuntimeAlreadyInUse
* If a runtime instance is in use by another application.
*
*
* @return Singleton VolTu runtime instance.
*/
PY_API std::shared_ptr<voltu::System> instance();
std::shared_ptr<voltu::System> instance();
}
......@@ -70,7 +70,7 @@ public:
* @param timeout Millisecond timeout, or 0 or -1.
* @return True if a new unseen frame is available.
*/
PY_API virtual bool waitNextFrame(int64_t timeout) = 0;
PY_API virtual bool waitNextFrame(int64_t timeout, bool except=false) = 0;
/**
* @brief Check if a new frame is available.
......
......@@ -20,7 +20,7 @@ namespace voltu
/**
* @brief Voltu semantic versioning information.
*/
struct Version
PY_NO_SHARED_PTR struct Version
{
int major; ///< API Incompatible change
int minor; ///< Possible binary incompatible, extensions
......@@ -29,50 +29,51 @@ struct Version
/**
* @brief Singleton Voltu system instance.
*
*
* Provides access to the key components such as opening streams or files and
* creating virtual cameras. Use `voltu::instance()` to obtain the object. All
* object instances in VolTu are managed by shared smart pointers.
* object instances in VolTu are managed by shared smart pointers. Python API
* automatically creates instance available as voltu.System.
*/
class System
PY_SINGLETON_OBJECT class System
{
public:
virtual ~System() = default;
/**
* @brief Get the runtime version information.
*
*
* This method gets the VolTu version of the runtime shared library, which
* may not be the same as the version of the SDK here.
*
*
* @see voltu.hpp
*
*
* @return Always returns semantic versioning structure.
*/
virtual voltu::Version getVersion() const = 0;
/**
* @brief Make a virtual room or composite room.
*
*
* @return A new virtual room instance.
*/
PY_API virtual voltu::RoomPtr createRoom() = 0;
/**
* @brief Create a virtual observer.
*
*
* An observer renderers virtual camera views, audio and other data from
* submitted framesets. It is possible and recommended that a single
* observer instance be used to renderer multiple different views, rather
* than creating lots of observers. This saves memory resources.
*
*
* @return A new observer instance.
*/
PY_API virtual voltu::ObserverPtr createObserver() = 0;
/**
* @brief Open a file, device or network stream using a URI.
*
*
* All data sources in VolTu are represented by Universal Resource
* Identifiers (URIs), with some non-standard additions. A few examples
* are:
......@@ -83,11 +84,11 @@ public:
* * `./file.ftl`
* * `device:camera`
* * `device:screen`
*
*
* Note that returning from this call does not guarantee that the source
* is fully open and operational, this depends on network handshakes or
* file processing that occurs asynchronously.
*
*
* @throw voltu::exceptions::BadSourceURI If an unrecognised URI is given.
* @return A feed management object for the data source.
*/
......@@ -95,14 +96,14 @@ public:
/**
* @brief Get a list of all available rooms.
*
*
* A room is a 3D captured physical space, or a combination of such spaces,
* and is represented by a unique identifier within the local system. This
* method obtains a list of all available rooms from all sources. To obtain
* rooms, either use `open` or `createRoom`.
*
*
* @return A list of room ids, which can be empty.
*
*
* @see getRoom
* @see open
*/
......@@ -110,13 +111,13 @@ public:
/**
* @brief Get a room instance from identifier.
*
*
* A room instance enables access to all data frames associated with that
* room, including image data. Calling `getRoom` with the same ID
* multiple times will return different smart pointers to room instances
* but provides access to the same data regardless and is valid. An invalid
* room ID will throw an exception.
*
*
* @throw voltu::exceptions::InvalidRoomId If the ID does not exist.
* @return Room instance or accessing room data.
*/
......@@ -127,14 +128,14 @@ public:
/**
* @brief Make an empty operator pipeline for frame processing.
*
*
* A pipeline allows a sequence of processing operations to be applied to
* a data frame. These operations include stereo correspondence, fusion,
* data evaluation and various image processing operations. Only some
* of these operators are exposed in the SDK. Once a pipeline instance
* is obtained, you can add specific operators to it, configure them and
* then submit frames from processing.
*
*
* @return A unique pipeline instance.
*/
PY_API virtual voltu::PipelinePtr createPipeline() = 0;
......
......@@ -47,6 +47,7 @@ VOLTU_EXCEPTION(NotImplemented, Exception, "Functionality not implemented");
VOLTU_EXCEPTION(ReadOnly, Exception, "Read only, write not allowed");
VOLTU_EXCEPTION(WriteOnly, Exception, "Write only, read not allowed");
VOLTU_EXCEPTION(IncompatibleOperation, Exception, "The input data and operator are incompatible");
VOLTU_EXCEPTION(Timeout, Exception, "Request timed out");
}
}
set(SDK_AUTO_HEADERS
voltu/types/channel.hpp
voltu/types/frame.hpp
voltu/types/image.hpp
voltu/types/intrinsics.hpp
voltu/observer.hpp
voltu/feed.hpp
voltu/initialise.hpp
voltu/room.hpp
voltu/source.hpp
voltu/system.hpp
voltu/types/channel.hpp
voltu/types/frame.hpp
voltu/types/image.hpp
voltu/types/intrinsics.hpp
voltu/observer.hpp
voltu/feed.hpp
voltu/initialise.hpp
voltu/room.hpp
voltu/source.hpp
voltu/system.hpp
)
add_custom_command(
OUTPUT automatic_bindings.cpp
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/gen.py
automatic_bindings.cpp
${CMAKE_CURRENT_SOURCE_DIR}/../include
${SDK_AUTO_HEADERS}
OUTPUT automatic_bindings.cpp
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/gen.py
automatic_bindings.cpp
${CMAKE_CURRENT_SOURCE_DIR}/../include
${SDK_AUTO_HEADERS}
DEPENDS voltu_sdk
DEPENDS voltu_sdk gen.py
)
pybind11_add_module(voltu_sdk_py MODULE
automatic_bindings.cpp
module.cpp
automatic_bindings.cpp
module.cpp
)
target_include_directories(voltu_sdk_py PUBLIC include)
......@@ -31,14 +31,3 @@ target_include_directories(voltu_sdk_py PRIVATE .)
target_link_libraries(voltu_sdk_py PUBLIC voltu_sdk)
set_target_properties(voltu_sdk_py PROPERTIES OUTPUT_NAME voltu)
enable_testing()
find_package(Python3 COMPONENTS Interpreter)
function(add_python_test TEST_NAME TEST_SCRIPT)
add_test(NAME ${TEST_NAME}
COMMAND Python3::Interpreter -m unittest ${TEST_SCRIPT}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
endfunction()
add_python_test(test_load tests/test_load.py)
# Python API generator
Dependencies
* python3-ply (build only)
* python3-dev
* python3-ply
Build system uses Pybind11 to generate a python module. Most of the bindings are
automatically generated by gen.py script which is automatically called by CMake
......@@ -14,11 +15,13 @@ build. Several (empty) macros are used in headers to annoate Python API details.
* PY_API function/method is to be included in Python API
* PY_NO_SHARED_PTR shared_ptr<> is not used with instances of this class.
https://pybind11.readthedocs.io/en/latest/advanced/smart_ptrs.html?#std-shared-ptr
See [pybind11 documentation](https://pybind11.readthedocs.io/en/latest/advanced/smart_ptrs.html?#std-shared-ptr)
for techncal details. Shared pointers are not used for structs.
* PY_RV_LIFETIME_PARENT lifetime of method's return valued is tied to
lifetime of parent objects (this). (return_value_policy::reference_internal
lifetime of parent objects (this). ([return_value_policy::reference_internal](https://pybind11.readthedocs.io/en/latest/advanced/functions.html#return-value-policies)
is set for this method)
https://pybind11.readthedocs.io/en/latest/advanced/functions.html#return-value-policies
* PY_SINGLETON Singleton class, methods are exported to to module scope.
* PY_SINGLETON_OBJECT Singleton instance is accessible as module attribute.
## Notes:
* Binding to default constructor is generated for structs. Class constructors
......@@ -28,6 +31,10 @@ build. Several (empty) macros are used in headers to annoate Python API details.
* Default arguments are supported (extracted from header).
* Public class properties are available in python, read-only if const,
otherwise read write.
* Singletons have to be created in PyModule constructor and be available
as class members.
* Exceptions have to be included manually in module.cpp
* C++ preprocessor is not used
## Not supported (yet) in automatic binding generation:
* Nested classes
......@@ -35,3 +42,4 @@ build. Several (empty) macros are used in headers to annoate Python API details.
* Constructors
* Automatic documentation (Doxygen)
* Generator does not verify that shared_ptr<> is used consistently/correctly
* Member variables of singleton classes
{includes}
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/eigen.h>
#include "types/image.hpp"
namespace py = pybind11;
using namespace voltu;
void py_automatic_bindings(py::module& m) {{
{code}
}}
......@@ -3,7 +3,6 @@
import cv2
import voltu
import time
import sys
import os
......@@ -11,23 +10,15 @@ if len(sys.argv) != 2:
print("%s filename" % os.path.basename(__file__))
exit(1)
#if not os.path.exists(sys.argv[1]):
# print("can't find %s" % sys.argv[1])
# exit(1)
api = voltu.instance()
api = voltu.System
api.open(sys.argv[1])
room = api.getRoom(0)
while True:
try:
room.waitNextFrame(1000)
if room.waitNextFrame(1000):
frames = room.getFrame().getImageSet(voltu.Channel.kColour)
im = frames[0].getHost()
cv2.imshow("im", im)
if cv2.waitKey(10) == 27:
break
except Exception as e:
print(e)
if cv2.waitKey(10) == 27:
break
......@@ -3,7 +3,6 @@
import cv2
import voltu
import time
import sys
import os
......@@ -11,25 +10,17 @@ if len(sys.argv) != 2:
print("%s filename" % os.path.basename(__file__))
exit(1)
#if not os.path.exists(sys.argv[1]):
# print("can't find %s" % sys.argv[1])
# exit(1)
api = voltu.instance()
api = voltu.System
api.open(sys.argv[1])
room = api.getRoom(0)
cam = api.createCamera()
while True:
try:
room.waitNextFrame(1000)
if room.waitNextFrame(1000):
cam.submit(room.getFrame())
frames = cam.getFrame().getImageSet(voltu.Channel.kColour)
im = frames[0].getHost()
cv2.imshow("im", im)
if cv2.waitKey(10) == 27:
break
except Exception as e:
print(e)
if cv2.waitKey(10) == 27:
break
#!/usr/bin/env python3
"""
Python binding generator. Creates pybind11 bindings for given headers.
See README.md for details.
"""
template = """ /* This file was automatically generated by gen.py. */
{includes}
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/eigen.h>
#include "types/image.hpp"
#include "module.hpp"
namespace py = pybind11;
using namespace voltu;
void PyModule::py_automatic_bindings(py::module& m) {{
{code}
}}
"""
import sys
import os
......@@ -12,23 +37,25 @@ def read_line(file, lineno):
if i == lineno:
return line
def get_loc_msg(data):
return "({0}:{1})".format(data["filename"], data["line_number"])
def print_warn(msg, loc=None):
if loc is not None:
msg += " " + get_loc_msg(loc)
print("WARNING: %s" % msg, file=sys.stderr)
print("gen.py warning: %s" % msg, file=sys.stderr)
def print_err(msg, loc=None):
if loc is not None:
msg += " " + get_loc_msg(loc)
print("ERROR: %s" % msg, file=sys.stderr)
print("gen.py error: %s" % msg, file=sys.stderr)
def include_in_api(data):
return "PY_API" in data["debug"]
def no_shared_ptr_cls(clsdata):
return (clsdata["declaration_method"] == "struct") or ("PY_NO_SHARED_PTR" in clsdata["debug"])
def create_enum_bindigs(enum, parent=[], pybind_handle="", export_values=False):
name_full = parent + [enum["name"]]
name_py = enum["name"]
......@@ -49,23 +76,14 @@ def create_enum_bindigs(enum, parent=[], pybind_handle="", export_values=False):
return "\n\t".join(cpp)
def create_function_bindings(func, parent=[], pybind_handle=None):
func_name = func["name"]
full_name = parent + [func_name]
full_name_cpp = "::".join(full_name)
if "PY_API" not in func["debug"]:
print_err("%s not included in Python API" % full_name_cpp, func)
raise ValueError("No PY_API")
args = ["\"{0}\"".format(func_name), "&{0}".format(full_name_cpp)]
def process_func_args(func):
args = []
for param in func["parameters"]:
param_name = param["name"]
if param_name == "&":
print_warn("Argument name missing for %s" % full_name_cpp, func)
if param_name in ["&", "", "*"]:
print_warn("Argument name missing for %s" % func["name"])
continue
if "default" in param:
......@@ -74,9 +92,50 @@ def create_function_bindings(func, parent=[], pybind_handle=None):
else:
args.append("py::arg(\"{0}\")".format(param_name))
return args
def wrap_lambda(func, instance_ptr, capture=True):
""" Wrap func to instance (singleton) with C++ lambda """
args_lambda = []
args_lambda_sig = []
for i, param in enumerate(func["parameters"]):
argname = "p" + str(i)
args_lambda_sig.append("%s %s" % (param["type"], argname))
args_lambda.append(argname)
return "[%s](%s){ return %s->%s(%s); }" % (
("&" if capture else ""),
", ".join(args_lambda_sig),
instance_ptr,
func["name"],
", ".join(args_lambda))
def create_function_bindings(func, parent=[], pybind_handle=None, bind_to_singleton=None):
""" Create function bindings, if bind_to_singleton is set, C++ lamda is
generated to wrap the call to instance (named by bind_by_singleton).
"""
func_name = func["name"]
full_name = parent + [func_name]
full_name_cpp = "::".join(full_name)
if not include_in_api(func):
print_err("%s not included in Python API" % full_name_cpp, func)
raise ValueError("No PY_API")
args = ["\"{0}\"".format(func_name)]
if bind_to_singleton is None:
args.append("&{0}".format(full_name_cpp))
else:
args.append(wrap_lambda(func, bind_to_singleton))
args += process_func_args(func)
if "PY_RV_LIFETIME_PARENT" in func["debug"]:
if func["parent"] is None:
print_err("PY_RV_LIFETIME_PARENT used for function", func)
if func["parent"] is None or bind_to_singleton is not None:
print_err("PY_RV_LIFETIME_PARENT used for function or singleton", func)
raise ValueError()
args.append("py::return_value_policy::reference_internal")
......@@ -87,25 +146,28 @@ def create_function_bindings(func, parent=[], pybind_handle=None):
return cpp
def create_class_bindings(cls, parent=[], pybind_handle=""):
cls_name = cls["name"]
full_name = parent + [cls_name]
def create_class_bindings(clsdata, parent=[], pybind_handle=""):
""" Create bindings for a class """
clsdata_name = clsdata["name"]
full_name = parent + [clsdata_name]
cpp = []
if "PY_NO_SHARED_PTR" not in cls["debug"]:
cls_cpp = "py::class_<{name}, std::shared_ptr<{name}>>({handle}, \"{name}\")"
else:
if no_shared_ptr_cls(clsdata):
cls_cpp = "py::class_<{name}>({handle}, \"{name}\")"
cpp.append(cls_cpp.format(handle=pybind_handle, name=cls_name))
else:
cls_cpp = "py::class_<{name}, std::shared_ptr<{name}>>({handle}, \"{name}\")"
cpp.append(cls_cpp.format(handle=pybind_handle, name=clsdata_name))
if cls["declaration_method"] == "struct":
if clsdata["declaration_method"] == "struct":
cpp.append(".def(py::init<>())")
for method in cls["methods"]["public"]:
for method in clsdata["methods"]["public"]:
if include_in_api(method):
cpp.append("." + create_function_bindings(method, full_name))
for field in cls["properties"]["public"]:
for field in clsdata["properties"]["public"]:
if field["constant"]:
field_cpp = ".def_property_readonly(\"{name}\", &{cpp_name})"
else:
......@@ -116,8 +178,30 @@ def create_class_bindings(cls, parent=[], pybind_handle=""):
return "\n\t\t".join(cpp)
if __name__ == "__main__":
def create_singleton_bindings(instance_ptr, clsdata, parent=[], pybind_handle="", export=False):
""" Singleton class bindings, either creates a singleton instance or
exports functions directly to module. Singleton pointer available with
instance_ptr, which should be class member of PyModule.
"""
if not export:
# use usual bindings and export as attribute to pybind handle
return "\n\t".join([
create_class_bindings(clsdata, parent, pybind_handle) + ";",
"{0}.attr(\"{1}\") = {2};".format(pybind_handle, clsdata["name"], instance_ptr)
])
else:
# use C++ lambdas to wrap all methods
cpp = []
for func in clsdata["methods"]["public"]:
if not include_in_api(func):
continue
cpp.append(create_function_bindings(func, parent, pybind_handle, instance_ptr) + ";")
return "\n\t".join(cpp)
if __name__ == "__main__":
from pprint import pprint
if (len(sys.argv) < 4):
......@@ -131,6 +215,7 @@ if __name__ == "__main__":
out = []
includes = []
for fname in fsin:
includes.append(fname)
......@@ -145,7 +230,13 @@ if __name__ == "__main__":
ns = data["namespace"]
# workaround: parser does not save debug in same way as for funcs
data["debug"] = read_line(data["filename"], data["line_number"])
out.append(create_class_bindings(data, [ns], handle) + ";")
if "PY_SINGLETON_OBJECT" in data["debug"]:
out.append(create_singleton_bindings("instance_" + data["name"], data, [ns], handle, False))
elif "PY_SINGLETON" in data["debug"]:
out.append(create_singleton_bindings("instance_" + data["name"], data, [ns], handle, True))
else:
out.append(create_class_bindings(data, [ns], handle) + ";")
for data in hdr.functions:
ns = data["namespace"].strip("::") # bug? in parser
......@@ -153,9 +244,7 @@ if __name__ == "__main__":
out.append(create_function_bindings(data, [ns], handle) + ";")
includes = "\n".join("#include <{0}>".format(i) for i in includes)
template_file = os.path.join(os.path.dirname(os.path.realpath(__file__)), "automatic_bindings.cpp.in")
with open(template_file, "r") as f:
template = f.read()
out = template.format(includes=includes, code="\n\t".join(out))
with open(fout, "w",) as f:
f.write(out)
......@@ -6,7 +6,11 @@
namespace py = pybind11;
void py_exceptions(pybind11::module& m) {
PyModule::PyModule() {
instance_System = voltu::instance();
}
void PyModule::py_exceptions(pybind11::module& m) {
py::register_exception<voltu::exceptions::Exception>(m, "Error");
py::register_exception<voltu::exceptions::BadImageChannel>(m, "ErrorBadImageChannel");
py::register_exception<voltu::exceptions::NoFrame>(m, "ErrorNoFrame");
......@@ -14,7 +18,11 @@ void py_exceptions(pybind11::module& m) {
py::register_exception<voltu::exceptions::BadSourceURI>(m, "ErrorBadSourceURI");
}
static auto module = PyModule();
PYBIND11_MODULE(voltu, m) {
py_exceptions(m);
py_automatic_bindings(m);
m.attr("version") = py::make_tuple(VOLTU_VERSION_MAJOR, VOLTU_VERSION_MINOR, VOLTU_VERSION_PATCH);
module.py_exceptions(m);
module.py_automatic_bindings(m);
}
#pragma once
#include <pybind11/pybind11.h>
#include <voltu/voltu.hpp>
#include <voltu/system.hpp>
void py_automatic_bindings(pybind11::module& m);
class PyModule {
public:
PyModule();
void py_automatic_bindings(pybind11::module& m);
void py_exceptions(pybind11::module& m);
private:
std::shared_ptr<voltu::System> instance_System;
};
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment