├── src ├── qmldir ├── CameraLocatorEntity.hpp ├── PointCloudEntity.hpp ├── IOThread.cpp ├── IOThread.hpp ├── plugin.hpp ├── CMakeLists.txt ├── BaseAlembicObject.hpp ├── AlembicEntity.hpp ├── PointCloudEntity.cpp ├── CameraLocatorEntity.cpp ├── BaseAlembicObject.cpp └── AlembicEntity.cpp ├── docs └── img │ └── qmlAlembic.jpg ├── COPYING.md ├── .gitignore ├── CMakeLists.txt ├── appveyor.yml ├── README.md ├── INSTALL.md └── LICENSE-MPL2.md /src/qmldir: -------------------------------------------------------------------------------- 1 | module AlembicEntity 2 | 3 | plugin alembicEntityQmlPlugin 4 | -------------------------------------------------------------------------------- /docs/img/qmlAlembic.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alicevision/qmlAlembic/HEAD/docs/img/qmlAlembic.jpg -------------------------------------------------------------------------------- /COPYING.md: -------------------------------------------------------------------------------- 1 | ## qmlAlembic License 2 | 3 | qmlAlembic is licensed under the [MPL2 license](LICENSE-MPL2.md). 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | *.slo 3 | *.lo 4 | *.o 5 | *.obj 6 | 7 | # Precompiled Headers 8 | *.gch 9 | *.pch 10 | 11 | # Compiled Dynamic libraries 12 | *.so 13 | *.dylib 14 | *.dll 15 | 16 | # Compiled Static libraries 17 | *.lai 18 | *.la 19 | *.a 20 | *.lib 21 | 22 | # Executables 23 | *.exe 24 | *.out 25 | *.app 26 | 27 | # Build directories 28 | build* 29 | -------------------------------------------------------------------------------- /src/CameraLocatorEntity.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "BaseAlembicObject.hpp" 4 | 5 | namespace abcentity 6 | { 7 | 8 | class CameraLocatorEntity : public BaseAlembicObject 9 | { 10 | Q_OBJECT 11 | 12 | public: 13 | explicit CameraLocatorEntity(Qt3DCore::QNode* = nullptr); 14 | ~CameraLocatorEntity() override = default; 15 | }; 16 | 17 | } // namespace 18 | -------------------------------------------------------------------------------- /src/PointCloudEntity.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "BaseAlembicObject.hpp" 4 | 5 | 6 | namespace abcentity 7 | { 8 | 9 | class PointCloudEntity : public BaseAlembicObject 10 | { 11 | Q_OBJECT 12 | 13 | public: 14 | explicit PointCloudEntity(Qt3DCore::QNode* = nullptr); 15 | ~PointCloudEntity() override = default; 16 | 17 | public: 18 | void setData(const Alembic::Abc::IObject&); 19 | }; 20 | 21 | } // namespace 22 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.3) 2 | project(alembicEntityQmlPlugin LANGUAGES CXX VERSION 0.1.0) 3 | 4 | set(CMAKE_CXX_STANDARD 11) 5 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 6 | 7 | # Qt dependency 8 | if(POLICY CMP0043) 9 | cmake_policy(SET CMP0043 OLD) 10 | endif() 11 | 12 | set(CMAKE_AUTOMOC ON) 13 | set(CMAKE_INCLUDE_CURRENT_DIR ON) 14 | 15 | find_package(Qt5Core REQUIRED) 16 | find_package(Qt5Qml REQUIRED) 17 | find_package(Qt53DCore REQUIRED) 18 | find_package(Qt53DExtras REQUIRED) 19 | find_package(Qt53DRender REQUIRED) 20 | add_definitions(-DQT_NO_KEYWORDS) 21 | 22 | # Alembic dependency 23 | find_package(Alembic 1.7 REQUIRED) 24 | 25 | add_subdirectory(src) 26 | -------------------------------------------------------------------------------- /src/IOThread.cpp: -------------------------------------------------------------------------------- 1 | #include "IOThread.hpp" 2 | #include 3 | 4 | namespace abcentity 5 | { 6 | 7 | void IOThread::read(const QUrl& source) 8 | { 9 | _source = source; 10 | start(); 11 | } 12 | 13 | void IOThread::run() 14 | { 15 | // ensure file exists and is valid 16 | if(!_source.isValid() || !QFile::exists(_source.toLocalFile())) 17 | return; 18 | QMutexLocker lock(&_mutex); 19 | _archive = _factory.getArchive(_source.toLocalFile().toStdString(), _coreType); 20 | } 21 | 22 | void IOThread::clear() 23 | { 24 | QMutexLocker lock(&_mutex); 25 | _archive.reset(); 26 | } 27 | 28 | const Alembic::Abc::IArchive& IOThread::archive() const 29 | { 30 | // mutex is mutable and can be locked in const methods 31 | QMutexLocker lock(&_mutex); 32 | return _archive; 33 | } 34 | 35 | } -------------------------------------------------------------------------------- /src/IOThread.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace abcentity 10 | { 11 | 12 | /** 13 | * @brief Handle Alembic IO in a separate thread. 14 | */ 15 | class IOThread : public QThread 16 | { 17 | Q_OBJECT 18 | 19 | public: 20 | /// Read the given source. Starts the thread main loop. 21 | void read(const QUrl& source); 22 | /// Thread main loop. 23 | void run() override; 24 | /// Reset internal members. 25 | void clear(); 26 | /// Get the Alembic archive. 27 | const Alembic::Abc::IArchive& archive() const; 28 | 29 | private: 30 | QUrl _source; 31 | mutable QMutex _mutex; 32 | Alembic::AbcCoreFactory::IFactory _factory; 33 | Alembic::AbcCoreFactory::IFactory::CoreType _coreType; 34 | Alembic::Abc::IArchive _archive; 35 | }; 36 | 37 | } -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | version: '1.0.{build}' 2 | 3 | image: Visual Studio 2017 4 | 5 | configuration: 6 | - Release 7 | 8 | platform: 9 | - x64 10 | 11 | environment: 12 | QT5: C:\Qt\5.12\msvc2017_64 13 | APPVEYOR_SAVE_CACHE_ON_ERROR: true 14 | 15 | install: 16 | - vcpkg list 17 | - vcpkg install 18 | alembic 19 | --triplet %PLATFORM%-windows 20 | - vcpkg list 21 | 22 | before_build: 23 | - md build 24 | - cd build 25 | - cmake .. -G "Visual Studio 15 2017 Win64" 26 | -DCMAKE_BUILD_TYPE=%CONFIGURATION% 27 | -DCMAKE_PREFIX_PATH=%QT5% 28 | -DCMAKE_TOOLCHAIN_FILE=c:/tools/vcpkg/scripts/buildsystems/vcpkg.cmake 29 | 30 | build: 31 | project: $(APPVEYOR_BUILD_FOLDER)\build\INSTALL.vcxproj 32 | verbosity: minimal 33 | 34 | # comment the above and uncomment the following to just build the dependencies 35 | # build_script: 36 | # - echo "Dependencies installed." 37 | 38 | cache: 39 | c:\tools\vcpkg\installed\ 40 | 41 | -------------------------------------------------------------------------------- /src/plugin.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "AlembicEntity.hpp" 4 | #include 5 | #include 6 | 7 | namespace abcentity 8 | { 9 | 10 | class AlembicEntityQmlPlugin : public QQmlExtensionPlugin 11 | { 12 | Q_OBJECT 13 | Q_PLUGIN_METADATA(IID "alembicEntity.qmlPlugin") 14 | 15 | public: 16 | void initializeEngine(QQmlEngine*, const char*) override {} 17 | void registerTypes(const char* uri) override 18 | { 19 | Q_ASSERT(uri == QLatin1String("AlembicEntity")); 20 | qmlRegisterType(uri, 2, 0, "AlembicEntity"); 21 | qmlRegisterUncreatableType(uri, 2, 0, "CameraLocatorEntity", 22 | "Cannot create CameraLocatorEntity instances from QML."); 23 | qmlRegisterUncreatableType(uri, 2, 0, "PointCloudEntity", 24 | "Cannot create PointCloudEntity instances from QML."); 25 | } 26 | }; 27 | 28 | } // namespace 29 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Target srcs 2 | set(PLUGIN_SOURCES AlembicEntity.cpp BaseAlembicObject.cpp CameraLocatorEntity.cpp IOThread.cpp PointCloudEntity.cpp) 3 | set(PLUGIN_HEADERS AlembicEntity.hpp BaseAlembicObject.hpp CameraLocatorEntity.hpp IOThread.hpp PointCloudEntity.hpp plugin.hpp) 4 | 5 | # Target properties 6 | add_library(alembicEntityQmlPlugin SHARED ${PLUGIN_SOURCES} ${PLUGIN_HEADERS}) 7 | 8 | target_link_libraries(alembicEntityQmlPlugin 9 | PUBLIC 10 | Qt5::Core 11 | Qt5::Qml 12 | Qt5::3DCore 13 | Qt5::3DRender 14 | Alembic::Alembic 15 | PRIVATE 16 | Qt5::3DExtras 17 | ) 18 | 19 | set_target_properties(alembicEntityQmlPlugin 20 | PROPERTIES 21 | DEBUG_POSTFIX "d" 22 | FOLDER "alembicEntityQmlPlugin" 23 | SOVERSION ${PROJECT_VERSION_MAJOR} 24 | VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}" 25 | ) 26 | 27 | target_include_directories(alembicEntityQmlPlugin PUBLIC ${ILMBASE_INCLUDE_DIR}) 28 | 29 | # Install settings 30 | install(FILES "qmldir" 31 | DESTINATION ${CMAKE_INSTALL_PREFIX}/qml/AlembicEntity) 32 | install(TARGETS alembicEntityQmlPlugin 33 | DESTINATION "${CMAKE_INSTALL_PREFIX}/qml/AlembicEntity") 34 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # qmlAlembic - Alembic QML plugin for Qt3D 2 | 3 | qmlAlembic is a C++ QML plugin providing classes to load and visualize Alembic point cloud files in Qt3D. 4 | It has been developed to load [AliceVision](https://github.com/alicevision/AliceVision) sparse reconstruction results inside [Meshroom](https://github.com/alicevision/meshroom). 5 | 6 | ![qmlAlembic - Meshroom](docs/img/qmlAlembic.jpg) 7 | 8 | For now, it only handles point clouds and cameras. 9 | 10 | Continuous integration: 11 | * Windows: [![Build status](https://ci.appveyor.com/api/projects/status/g256moy4i36w7cpi/branch/develop?svg=true)](https://ci.appveyor.com/project/AliceVision/qmlalembic/branch/develop) 12 | 13 | ## License 14 | 15 | The project is released under MPLv2, see [**COPYING.md**](COPYING.md). 16 | 17 | 18 | ## Get the project 19 | 20 | Get the source code: 21 | ```bash 22 | git clone --recursive git://github.com/alicevision/qmlAlembic 23 | cd qmlAlembic 24 | ``` 25 | See [**INSTALL.md**](INSTALL.md) to build and install the project. 26 | 27 | 28 | ## Usage 29 | 30 | Once built and with the plugin installation folder in `QML2_IMPORT_PATH`: 31 | 32 | ```js 33 | import AlembicEntity 1.0 34 | 35 | Scene3D { 36 | AlembicEntity { 37 | url: "myfile.abc" 38 | } 39 | } 40 | ``` 41 | -------------------------------------------------------------------------------- /src/BaseAlembicObject.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | namespace abcentity 8 | { 9 | 10 | /** 11 | * @brief BaseAlembicObject is the base class for QEntities instantiated by AlembicEntity 12 | */ 13 | class BaseAlembicObject : public Qt3DCore::QEntity 14 | { 15 | Q_OBJECT 16 | 17 | Q_PROPERTY(QVariantMap arbProperties READ arbProperties CONSTANT) 18 | Q_PROPERTY(QVariantMap userProperties READ userProperties CONSTANT) 19 | 20 | public: 21 | 22 | explicit BaseAlembicObject(Qt3DCore::QNode* = nullptr); 23 | ~BaseAlembicObject() override = default; 24 | 25 | void setTransform(const Alembic::Abc::M44d&); 26 | 27 | const QVariantMap& arbProperties() const { return _arbProperties; } 28 | const QVariantMap& userProperties() const { return _userProperties; } 29 | 30 | void fillArbProperties(const Alembic::Abc::ICompoundProperty& iParent); 31 | void fillUserProperties(const Alembic::Abc::ICompoundProperty& iParent); 32 | 33 | protected: 34 | /// report alembic properties to the given variantMap 35 | void fillPropertyMap(const Alembic::Abc::ICompoundProperty& iParent, QVariantMap& variantMap); 36 | 37 | template 38 | void addScalarProperty(QVariantMap& data, const Alembic::Abc::IScalarProperty& prop); 39 | 40 | template 41 | void addArrayProperty(QVariantMap &data, const Alembic::Abc::IArrayProperty& prop); 42 | 43 | template 44 | void addProperty(QVariantMap& data, const Alembic::Abc::ICompoundProperty& iParent, 45 | const Alembic::Abc::PropertyHeader& propHeader); 46 | 47 | protected: 48 | QVariantMap _arbProperties; 49 | QVariantMap _userProperties; 50 | Qt3DCore::QTransform* _transform; 51 | }; 52 | 53 | } 54 | -------------------------------------------------------------------------------- /INSTALL.md: -------------------------------------------------------------------------------- 1 | # Development 2 | This guide will help you build and install qmlAlembic plugin. 3 | 4 | ## Requirements 5 | qmlAlembic requires: 6 | * [Qt5](https://www.qt.io/) (== 5.15.2, make sure to use the **same version** as the target application) 7 | * [Alembic](https://github.com/alembic/alembic) (>= 1.7) 8 | * [CMake](https://cmake.org/) (>= 3.3) 9 | * On Windows platform: Microsoft Visual Studio (>= 2015.3) 10 | 11 | > **Note for Windows**: 12 | We recommend using [VCPKG](https://github.com/Microsoft/vcpkg) to get Alembic. Qt can either be installed with VCPKG or the official installer. 13 | 14 | ## Build instructions 15 | 16 | In the following steps, replace with the installation path of your choice. 17 | 18 | 19 | #### Windows 20 | > We will use "NMake Makefiles" generators here to have one-line build/installation, 21 | but Visual Studio solutions can be generated if need be. 22 | 23 | From a developer command-line, using Qt 5.15.2 (built with VS2019) and VCPKG for Alembic: 24 | ``` 25 | set QT_DIR=/path/to/qt/5.15.2/msvc2019_64 26 | cmake .. -DCMAKE_TOOLCHAIN_FILE=%VCPKG_ROOT%\scripts\buildsystems\vcpkg.cmake -DCMAKE_PREFIX_PATH=%QT_DIR% -DVCPKG_TARGET_TRIPLET=x64-windows -G "NMake Makefiles" -DCMAKE_INSTALL_PREFIX= -DCMAKE_BUILD_TYPE=Release 27 | nmake install 28 | ``` 29 | 30 | #### Linux 31 | 32 | ```bash 33 | export QT_DIR=/path/to/qt/5.15.2/gcc_64 34 | export ALEMBIC_DIR=/path/to/alembic/config 35 | cmake .. -DAlembic_DIR=$ALEMBIC_DIR -DCMAKE_PREFIX_PATH=$QT_DIR -DCMAKE_INSTALL_PREFIX= -DCMAKE_BUILD_TYPE=Release 36 | make install 37 | ``` 38 | 39 | ## Usage 40 | Once built, add the install folder of this plugin to the `QML2_IMPORT_PATH` before launching your application: 41 | 42 | ```bash 43 | # Windows: 44 | set QML2_IMPORT_PATH=/qml;%QML2_IMPORT_PATH% 45 | 46 | # Linux: 47 | export QML2_IMPORT_PATH=/qml:$QML2_IMPORT_PATH 48 | ``` 49 | -------------------------------------------------------------------------------- /src/AlembicEntity.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | 12 | namespace abcentity 13 | { 14 | class CameraLocatorEntity; 15 | class PointCloudEntity; 16 | class IOThread; 17 | 18 | class AlembicEntity : public Qt3DCore::QEntity 19 | { 20 | Q_OBJECT 21 | Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged) 22 | Q_PROPERTY(bool skipHidden MEMBER _skipHidden NOTIFY skipHiddenChanged) 23 | Q_PROPERTY(float pointSize READ pointSize WRITE setPointSize NOTIFY pointSizeChanged) 24 | Q_PROPERTY(float locatorScale READ locatorScale WRITE setLocatorScale NOTIFY locatorScaleChanged) 25 | Q_PROPERTY(QQmlListProperty cameras READ cameras NOTIFY camerasChanged) 26 | Q_PROPERTY(QQmlListProperty pointClouds READ pointClouds NOTIFY pointCloudsChanged) 27 | 28 | Q_PROPERTY(Status status READ status NOTIFY statusChanged) 29 | 30 | public: 31 | // Identical to SceneLoader.Status 32 | enum Status { 33 | None = 0, 34 | Loading, 35 | Ready, 36 | Error 37 | }; 38 | Q_ENUM(Status) 39 | 40 | explicit AlembicEntity(Qt3DCore::QNode* = nullptr); 41 | ~AlembicEntity() override = default; 42 | 43 | Q_SLOT const QUrl& source() const { return _source; } 44 | Q_SLOT float pointSize() const { return _pointSize; } 45 | Q_SLOT float locatorScale() const { return _locatorScale; } 46 | Q_SLOT void setSource(const QUrl& source); 47 | Q_SLOT void setPointSize(const float& value); 48 | Q_SLOT void setLocatorScale(const float& value); 49 | 50 | Status status() const { return _status; } 51 | void setStatus(Status status) { 52 | if(status == _status) 53 | return; 54 | _status = status; 55 | Q_EMIT statusChanged(_status); 56 | } 57 | 58 | private: 59 | /// Delete all child entities/components 60 | void clear(); 61 | void createMaterials(); 62 | void loadAbcArchive(); 63 | void visitAbcObject(const Alembic::Abc::IObject&, QEntity* parent); 64 | 65 | QQmlListProperty cameras() { 66 | return {this, _cameras}; 67 | } 68 | 69 | QQmlListProperty pointClouds() { 70 | return {this, _pointClouds}; 71 | } 72 | 73 | public: 74 | Q_SIGNAL void sourceChanged(); 75 | Q_SIGNAL void camerasChanged(); 76 | Q_SIGNAL void pointSizeChanged(); 77 | Q_SIGNAL void pointCloudsChanged(); 78 | Q_SIGNAL void locatorScaleChanged(); 79 | Q_SIGNAL void objectPicked(Qt3DCore::QTransform* transform); 80 | Q_SIGNAL void statusChanged(Status status); 81 | Q_SIGNAL void skipHiddenChanged(); 82 | 83 | protected: 84 | /// Scale child locators 85 | void scaleLocators() const; 86 | 87 | void onIOThreadFinished(); 88 | 89 | private: 90 | Status _status = AlembicEntity::None; 91 | QUrl _source; 92 | bool _skipHidden = false; 93 | float _pointSize = 0.5f; 94 | float _locatorScale = 1.0f; 95 | Qt3DRender::QParameter* _pointSizeParameter; 96 | Qt3DRender::QMaterial* _cloudMaterial; 97 | Qt3DRender::QMaterial* _cameraMaterial; 98 | QList _cameras; 99 | QList _pointClouds; 100 | std::unique_ptr _ioThread; 101 | }; 102 | 103 | } // namespace 104 | -------------------------------------------------------------------------------- /src/PointCloudEntity.cpp: -------------------------------------------------------------------------------- 1 | #include "PointCloudEntity.hpp" 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | namespace abcentity 8 | { 9 | 10 | PointCloudEntity::PointCloudEntity(Qt3DCore::QNode* parent) 11 | : BaseAlembicObject(parent) 12 | { 13 | } 14 | 15 | void PointCloudEntity::setData(const Alembic::Abc::IObject& iObj) 16 | { 17 | using namespace Qt3DRender; 18 | using namespace Alembic::Abc; 19 | using namespace Alembic::AbcGeom; 20 | 21 | // create a new geometry renderer 22 | auto customMeshRenderer = new QGeometryRenderer; 23 | auto customGeometry = new QGeometry; 24 | 25 | // read position data 26 | IPoints points(iObj, kWrapExisting); 27 | IPointsSchema schema = points.getSchema(); 28 | P3fArraySamplePtr positions = schema.getValue().getPositions(); 29 | int npoints = static_cast(positions->size()); 30 | 31 | // vertices buffer 32 | QByteArray positionData((const char*)positions->get(), npoints * 3 * static_cast(sizeof(float))); 33 | auto vertexDataBuffer = new QBuffer; 34 | vertexDataBuffer->setData(positionData); 35 | auto positionAttribute = new QAttribute; 36 | positionAttribute->setAttributeType(QAttribute::VertexAttribute); 37 | positionAttribute->setBuffer(vertexDataBuffer); 38 | positionAttribute->setVertexBaseType(QAttribute::Float); 39 | positionAttribute->setVertexSize(3); 40 | positionAttribute->setByteOffset(0); 41 | positionAttribute->setByteStride(3 * sizeof(float)); 42 | positionAttribute->setCount(static_cast(npoints)); 43 | positionAttribute->setName(QAttribute::defaultPositionAttributeName()); 44 | customGeometry->addAttribute(positionAttribute); 45 | customGeometry->setBoundingVolumePositionAttribute(positionAttribute); 46 | 47 | // read color data 48 | auto colorDataBuffer = new QBuffer; 49 | 50 | // check if we have a color property 51 | ICompoundProperty cProp = schema.getArbGeomParams(); 52 | if(cProp) 53 | { 54 | std::size_t numProps = cProp.getNumProperties(); 55 | for(std::size_t i = 0; i < numProps; ++i) 56 | { 57 | const PropertyHeader& propHeader = cProp.getPropertyHeader(i); 58 | if(propHeader.isArray()) 59 | { 60 | const std::string& propName = propHeader.getName(); 61 | Alembic::Abc::IArrayProperty prop(cProp, propName); 62 | std::string interp = prop.getMetaData().get("interpretation"); 63 | if(interp == "rgb") 64 | { 65 | // Alembic::AbcCoreAbstract::DataType dType = prop.getDataType(); 66 | Alembic::AbcCoreAbstract::ArraySamplePtr samp; 67 | prop.get(samp); 68 | QByteArray colorData((const char*)samp->getData(), 69 | static_cast(samp->size() * 3 * sizeof(float))); 70 | colorDataBuffer->setData(colorData); 71 | break; // set colors only once 72 | } 73 | } 74 | } 75 | } 76 | 77 | // if needed, fill the buffer with a default color 78 | if(colorDataBuffer->data().isEmpty()) 79 | { 80 | auto colors = new float[positions->size() * 3]; 81 | for(size_t i = 0; i < positions->size() * 3; i++) 82 | colors[i] = 0.8f; 83 | QByteArray colorData((const char*)colors, npoints * 3 * static_cast(sizeof(float))); 84 | colorDataBuffer->setData(colorData); 85 | } 86 | 87 | // colors buffer 88 | auto colorAttribute = new QAttribute; 89 | colorAttribute->setAttributeType(QAttribute::VertexAttribute); 90 | colorAttribute->setBuffer(colorDataBuffer); 91 | colorAttribute->setVertexBaseType(QAttribute::Float); 92 | colorAttribute->setVertexSize(3); 93 | colorAttribute->setByteOffset(0); 94 | colorAttribute->setByteStride(3 * sizeof(float)); 95 | colorAttribute->setCount(static_cast(npoints)); 96 | colorAttribute->setName(QAttribute::defaultColorAttributeName()); 97 | customGeometry->addAttribute(colorAttribute); 98 | 99 | // geometry renderer settings 100 | customMeshRenderer->setInstanceCount(1); 101 | customMeshRenderer->setFirstVertex(0); 102 | customMeshRenderer->setFirstInstance(0); 103 | customMeshRenderer->setPrimitiveType(QGeometryRenderer::Points); 104 | customMeshRenderer->setGeometry(customGeometry); 105 | customMeshRenderer->setVertexCount(npoints); 106 | 107 | // add components 108 | addComponent(customMeshRenderer); 109 | } 110 | 111 | 112 | } // namespace 113 | -------------------------------------------------------------------------------- /src/CameraLocatorEntity.cpp: -------------------------------------------------------------------------------- 1 | #include "CameraLocatorEntity.hpp" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | namespace abcentity 9 | { 10 | 11 | CameraLocatorEntity::CameraLocatorEntity(Qt3DCore::QNode* parent) 12 | : BaseAlembicObject(parent) 13 | { 14 | using namespace Qt3DRender; 15 | 16 | // create a new geometry renderer 17 | auto customMeshRenderer = new QGeometryRenderer; 18 | auto customGeometry = new QGeometry; 19 | 20 | // vertices buffer 21 | QVector points = { 22 | // Coord system 23 | 0.f, 0.f, 0.f, 0.5f, 0.0f, 0.0f, // X 24 | 0.f, 0.f, 0.f, 0.0f, -0.5f, 0.0f, // Y 25 | 0.f, 0.f, 0.f, 0.0f, 0.0f, -0.5f, // Z 26 | 27 | // Pyramid 28 | 0.f, 0.f, 0.f, -0.3f, 0.2f, -0.3f, // TL 29 | 0.f, 0.f, 0.f, -0.3f, -0.2f, -0.3f, // BL 30 | 0.f, 0.f, 0.f, 0.3f, -0.2f, -0.3f, // BR 31 | 0.f, 0.f, 0.f, 0.3f, 0.2f, -0.3f, // TR 32 | 33 | // Image plane 34 | -0.3f, -0.2f, -0.3f, -0.3f, 0.2f, -0.3f, // L 35 | -0.3f, 0.2f, -0.3f, 0.3f, 0.2f, -0.3f, // B 36 | 0.3f, 0.2f, -0.3f, 0.3f, -0.2f, -0.3f, // R 37 | 0.3f, -0.2f, -0.3f, -0.3f, -0.2f, -0.3f, // T 38 | 39 | // Camera Up 40 | -0.3f, 0.2f, -0.3f, 0.0f, 0.25f, -0.3f, // L 41 | 0.3f, 0.2f, -0.3f, 0.0f, 0.25f, -0.3f, // R 42 | }; 43 | 44 | 45 | QByteArray positionData((const char*)points.data(), points.size() * static_cast(sizeof(float))); 46 | auto vertexDataBuffer = new QBuffer; 47 | vertexDataBuffer->setData(positionData); 48 | auto positionAttribute = new QAttribute; 49 | positionAttribute->setAttributeType(QAttribute::VertexAttribute); 50 | positionAttribute->setBuffer(vertexDataBuffer); 51 | positionAttribute->setVertexBaseType(QAttribute::Float); 52 | positionAttribute->setVertexSize(3); 53 | positionAttribute->setByteOffset(0); 54 | positionAttribute->setByteStride(3 * sizeof(float)); 55 | positionAttribute->setCount(static_cast(points.size() / 3)); 56 | positionAttribute->setName(QAttribute::defaultPositionAttributeName()); 57 | customGeometry->addAttribute(positionAttribute); 58 | 59 | // colors buffer 60 | QVector colors { 61 | // Coord system 62 | 1.f, 0.f, 0.f, 1.f, 0.f, 0.f, // R 63 | 0.f, 1.f, 0.f, 0.f, 1.f, 0.f, // G 64 | 0.f, 0.f, 1.f, 0.f, 0.f, 1.f, // B 65 | // Pyramid 66 | 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 67 | 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 68 | 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 69 | 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 70 | // Image Plane 71 | 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 72 | 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 73 | 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 74 | 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 75 | // Camera Up direction 76 | 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 77 | 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 78 | }; 79 | 80 | QByteArray colorData((const char*)colors.data(), colors.size() * static_cast(sizeof(float))); 81 | auto colorDataBuffer = new QBuffer; 82 | colorDataBuffer->setData(colorData); 83 | auto colorAttribute = new QAttribute; 84 | colorAttribute->setAttributeType(QAttribute::VertexAttribute); 85 | colorAttribute->setBuffer(colorDataBuffer); 86 | colorAttribute->setVertexBaseType(QAttribute::Float); 87 | colorAttribute->setVertexSize(3); 88 | colorAttribute->setByteOffset(0); 89 | colorAttribute->setByteStride(3 * sizeof(float)); 90 | colorAttribute->setCount(static_cast(colors.size() / 3)); 91 | colorAttribute->setName(QAttribute::defaultColorAttributeName()); 92 | customGeometry->addAttribute(colorAttribute); 93 | 94 | // geometry renderer settings 95 | customMeshRenderer->setInstanceCount(1); 96 | customMeshRenderer->setFirstVertex(0); 97 | customMeshRenderer->setFirstInstance(0); 98 | customMeshRenderer->setPrimitiveType(QGeometryRenderer::Lines); 99 | customMeshRenderer->setGeometry(customGeometry); 100 | customMeshRenderer->setVertexCount(points.size() / 3); 101 | 102 | /* 103 | QCamera* camera = new QCamera(this); 104 | camera->setProjectionType(QCameraLens::PerspectiveProjection); 105 | camera->setAspectRatio(4.0f/3.0f); 106 | camera->setUpVector(QVector3D(0.0f, 1.0f, 0.0f)); 107 | camera->setViewCenter(QVector3D(0.0f, 3.5f, 0.0f)); 108 | camera->setPosition(QVector3D(0.0f, 3.5f, 25.0f)); 109 | */ 110 | 111 | // add components 112 | addComponent(customMeshRenderer); 113 | } 114 | 115 | } // namespace 116 | -------------------------------------------------------------------------------- /src/BaseAlembicObject.cpp: -------------------------------------------------------------------------------- 1 | #include "BaseAlembicObject.hpp" 2 | 3 | namespace abcentity 4 | { 5 | 6 | BaseAlembicObject::BaseAlembicObject(Qt3DCore::QNode* parent) 7 | : Qt3DCore::QEntity(parent) 8 | { 9 | _transform = new Qt3DCore::QTransform; 10 | addComponent(_transform); 11 | } 12 | 13 | void BaseAlembicObject::fillArbProperties(const Alembic::Abc::ICompoundProperty &iParent) 14 | { 15 | fillPropertyMap(iParent, _arbProperties); 16 | } 17 | 18 | void BaseAlembicObject::fillUserProperties(const Alembic::Abc::ICompoundProperty &iParent) 19 | { 20 | fillPropertyMap(iParent, _userProperties); 21 | } 22 | 23 | void BaseAlembicObject::setTransform(const Alembic::Abc::M44d& mat) 24 | { 25 | QMatrix4x4 qmat(mat[0][0], mat[1][0], mat[2][0], mat[3][0], mat[0][1], mat[1][1], mat[2][1], 26 | mat[3][1], mat[0][2], mat[1][2], mat[2][2], mat[3][2], mat[0][3], mat[1][3], 27 | mat[2][3], mat[3][3]); 28 | _transform->setMatrix(qmat); 29 | } 30 | 31 | 32 | template 33 | void BaseAlembicObject::addScalarProperty(QVariantMap& data, const Alembic::Abc::IScalarProperty& prop) 34 | { 35 | static const Alembic::Abc::ISampleSelector iss((Alembic::Abc::index_t)0); 36 | 37 | // TODO: handle extent and interpretation 38 | PODTYPE val; 39 | prop.get(&val, iss); 40 | data[prop.getName().c_str()] = val; 41 | } 42 | 43 | template<> 44 | void BaseAlembicObject::addScalarProperty(QVariantMap& data, const Alembic::Abc::IScalarProperty& prop) 45 | { 46 | std::string val; 47 | static const Alembic::Abc::ISampleSelector iss((Alembic::Abc::index_t)0); 48 | prop.get(&val, iss); 49 | data[prop.getName().c_str()] = QString::fromStdString(val); 50 | } 51 | 52 | 53 | template 54 | void BaseAlembicObject::addArrayProperty(QVariantMap& data, const Alembic::Abc::IArrayProperty& prop) 55 | { 56 | Alembic::AbcCoreAbstract::ArraySamplePtr val; 57 | prop.get(val); 58 | const PODTYPE* _data = static_cast(val->getData()); 59 | QVariantList l; 60 | l.reserve(static_cast(val->size())); 61 | for(size_t k=0; k < val->size(); k++) 62 | { 63 | l.append(_data[k]); 64 | } 65 | data[prop.getName().c_str()] = l; 66 | } 67 | 68 | template<> 69 | void BaseAlembicObject::addArrayProperty(QVariantMap& data, const Alembic::Abc::IArrayProperty& prop) 70 | { 71 | Alembic::AbcCoreAbstract::ArraySamplePtr val; 72 | prop.get(val); 73 | const std::string* _data = static_cast(val->getData()); 74 | QVariantList l; 75 | l.reserve(static_cast(val->size())); 76 | for(size_t k=0; k < val->size(); k++) 77 | { 78 | l.append(QString::fromStdString(_data[k])); 79 | } 80 | data[prop.getName().c_str()] = l; 81 | } 82 | 83 | template 84 | void BaseAlembicObject::addProperty(QVariantMap& data, const Alembic::Abc::ICompoundProperty& iParent, 85 | const Alembic::Abc::PropertyHeader& propHeader) 86 | { 87 | if(propHeader.isArray()) 88 | { 89 | Alembic::Abc::IArrayProperty prop(iParent, propHeader.getName()); 90 | if(!prop.isConstant()) 91 | return; 92 | addArrayProperty(data, prop); 93 | } 94 | else if(propHeader.isScalar()) 95 | { 96 | Alembic::Abc::IScalarProperty prop(iParent, propHeader.getName()); 97 | if(!prop.isConstant()) 98 | return; 99 | addScalarProperty(data, prop); 100 | } 101 | } 102 | 103 | void BaseAlembicObject::fillPropertyMap(const Alembic::Abc::ICompoundProperty& iParent, QVariantMap& variantMap) 104 | { 105 | if(!iParent.valid()) 106 | return; 107 | std::size_t numProps = iParent.getNumProperties(); 108 | for (std::size_t i = 0; i < numProps; ++i) 109 | { 110 | const Alembic::Abc::PropertyHeader & propHeader = iParent.getPropertyHeader(i); 111 | Alembic::AbcCoreAbstract::DataType dtype = propHeader.getDataType(); 112 | 113 | switch(dtype.getPod()) 114 | { 115 | case Alembic::Abc::kBooleanPOD: 116 | addProperty(variantMap, iParent, propHeader); break; 117 | case Alembic::Abc::kUint8POD: 118 | addProperty(variantMap, iParent, propHeader); break; 119 | case Alembic::Abc::kUint16POD: 120 | addProperty(variantMap, iParent, propHeader); break; 121 | case Alembic::Abc::kUint32POD: 122 | addProperty(variantMap, iParent, propHeader); break; 123 | case Alembic::Abc::kUint64POD: 124 | addProperty(variantMap, iParent, propHeader); break; 125 | case Alembic::Abc::kInt8POD: 126 | addProperty(variantMap, iParent, propHeader); break; 127 | case Alembic::Abc::kInt16POD: 128 | addProperty(variantMap, iParent, propHeader); break; 129 | case Alembic::Abc::kInt32POD: 130 | addProperty(variantMap, iParent, propHeader); break; 131 | case Alembic::Abc::kInt64POD: 132 | addProperty(variantMap, iParent, propHeader); break; 133 | case Alembic::Abc::kFloat16POD: 134 | addProperty(variantMap, iParent, propHeader); break; 135 | case Alembic::Abc::kFloat32POD: 136 | addProperty(variantMap, iParent, propHeader); break; 137 | case Alembic::Abc::kFloat64POD: 138 | addProperty(variantMap, iParent, propHeader); break; 139 | case Alembic::Abc::kStringPOD: 140 | addProperty(variantMap, iParent, propHeader); break; 141 | case Alembic::Abc::kUnknownPOD: 142 | default: 143 | break; 144 | } 145 | } 146 | } 147 | 148 | } 149 | -------------------------------------------------------------------------------- /src/AlembicEntity.cpp: -------------------------------------------------------------------------------- 1 | #include "AlembicEntity.hpp" 2 | #include "IOThread.hpp" 3 | #include "CameraLocatorEntity.hpp" 4 | #include "PointCloudEntity.hpp" 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | using namespace Alembic::Abc; 15 | using namespace Alembic::AbcGeom; 16 | 17 | namespace abcentity 18 | { 19 | 20 | AlembicEntity::AlembicEntity(Qt3DCore::QNode* parent) 21 | : Qt3DCore::QEntity(parent) 22 | , _pointSizeParameter(new Qt3DRender::QParameter) 23 | , _ioThread(new IOThread()) 24 | { 25 | connect(_ioThread.get(), &IOThread::finished, this, &AlembicEntity::onIOThreadFinished); 26 | createMaterials(); 27 | } 28 | 29 | void AlembicEntity::setSource(const QUrl& value) 30 | { 31 | if(_source == value) 32 | return; 33 | _source = value; 34 | loadAbcArchive(); 35 | Q_EMIT sourceChanged(); 36 | } 37 | 38 | void AlembicEntity::setPointSize(const float& value) 39 | { 40 | if(_pointSize == value) 41 | return; 42 | _pointSize = value; 43 | _pointSizeParameter->setValue(value); 44 | _cloudMaterial->setEnabled(_pointSize > 0.0f); 45 | Q_EMIT pointSizeChanged(); 46 | } 47 | 48 | void AlembicEntity::setLocatorScale(const float& value) 49 | { 50 | if(_locatorScale == value) 51 | return; 52 | _locatorScale = value; 53 | scaleLocators(); 54 | Q_EMIT locatorScaleChanged(); 55 | } 56 | 57 | void AlembicEntity::scaleLocators() const 58 | { 59 | for(auto* entity : _cameras) 60 | { 61 | for(auto* transform : entity->findChildren()) 62 | transform->setScale(_locatorScale); 63 | } 64 | } 65 | 66 | // private 67 | void AlembicEntity::createMaterials() 68 | { 69 | using namespace Qt3DRender; 70 | using namespace Qt3DExtras; 71 | 72 | _cloudMaterial = new QMaterial(this); 73 | _cameraMaterial = new QPerVertexColorMaterial(this); 74 | 75 | // configure cloud material 76 | auto effect = new QEffect; 77 | auto technique = new QTechnique; 78 | auto renderPass = new QRenderPass; 79 | auto shaderProgram = new QShaderProgram; 80 | 81 | shaderProgram->setVertexShaderCode(R"(#version 130 82 | in vec3 vertexPosition; 83 | in vec3 vertexColor; 84 | out vec3 color; 85 | uniform mat4 mvp; 86 | uniform mat4 projectionMatrix; 87 | uniform mat4 viewportMatrix; 88 | uniform float pointSize; 89 | void main() 90 | { 91 | color = vertexColor; 92 | gl_Position = mvp * vec4(vertexPosition, 1.0); 93 | gl_PointSize = max(viewportMatrix[1][1] * projectionMatrix[1][1] * pointSize / gl_Position.w, 1.0); 94 | } 95 | )"); 96 | 97 | // set fragment shader 98 | shaderProgram->setFragmentShaderCode(R"(#version 130 99 | in vec3 color; 100 | out vec4 fragColor; 101 | void main(void) 102 | { 103 | fragColor = vec4(color, 1.0); 104 | } 105 | )"); 106 | 107 | // add a pointSize uniform 108 | _pointSizeParameter->setName("pointSize"); 109 | _pointSizeParameter->setValue(_pointSize); 110 | _cloudMaterial->addParameter(_pointSizeParameter); 111 | 112 | // build the material 113 | renderPass->setShaderProgram(shaderProgram); 114 | technique->addRenderPass(renderPass); 115 | effect->addTechnique(technique); 116 | _cloudMaterial->setEffect(effect); 117 | } 118 | 119 | void AlembicEntity::clear() 120 | { 121 | // clear entity (remove direct children & all components) 122 | auto entities = findChildren(QString(), Qt::FindDirectChildrenOnly); 123 | for(auto entity : entities) 124 | { 125 | entity->setParent((QNode*)nullptr); 126 | entity->deleteLater(); 127 | } 128 | for(auto& component : components()) 129 | removeComponent(component); 130 | _cameras.clear(); 131 | _pointClouds.clear(); 132 | } 133 | 134 | // private 135 | void AlembicEntity::loadAbcArchive() 136 | { 137 | clear(); 138 | if(_source.isEmpty()) 139 | { 140 | setStatus(AlembicEntity::None); 141 | return; 142 | } 143 | setStatus(AlembicEntity::Loading); 144 | _ioThread->read(_source); 145 | } 146 | 147 | void AlembicEntity::onIOThreadFinished() 148 | { 149 | const auto& archive = _ioThread->archive(); 150 | if(!archive.valid()) 151 | { 152 | setStatus(AlembicEntity::Error); 153 | return; 154 | } 155 | // visit the abc tree 156 | try 157 | { 158 | visitAbcObject(archive.getTop(), this); 159 | 160 | // store pointers to cameras and point clouds 161 | _cameras = findChildren(); 162 | _pointClouds = findChildren(); 163 | 164 | // perform initial locator scaling 165 | scaleLocators(); 166 | 167 | setStatus(AlembicEntity::Ready); 168 | } 169 | catch(...) 170 | { 171 | clear(); 172 | setStatus(AlembicEntity::Error); 173 | } 174 | _ioThread->clear(); 175 | Q_EMIT camerasChanged(); 176 | Q_EMIT pointCloudsChanged(); 177 | } 178 | 179 | // private 180 | void AlembicEntity::visitAbcObject(const Alembic::Abc::IObject& iObj, QEntity* parent) 181 | { 182 | using namespace Alembic::Abc; 183 | using namespace Alembic::AbcGeom; 184 | 185 | const auto createEntity = [&](const IObject&) -> BaseAlembicObject* { 186 | const MetaData& md = iObj.getMetaData(); 187 | 188 | if(IPoints::matches(md)) 189 | { 190 | IPoints points(iObj, Alembic::Abc::kWrapExisting); 191 | PointCloudEntity* entity = new PointCloudEntity(parent); 192 | entity->setData(iObj); 193 | entity->addComponent(_cloudMaterial); 194 | entity->fillArbProperties(points.getSchema().getArbGeomParams()); 195 | entity->fillUserProperties(points.getSchema().getUserProperties()); 196 | return entity; 197 | } 198 | else if(IXform::matches(md)) 199 | { 200 | IXform xform(iObj, kWrapExisting); 201 | BaseAlembicObject* entity = new BaseAlembicObject(parent); 202 | XformSample xs; 203 | xform.getSchema().get(xs); 204 | entity->setTransform(xs.getMatrix()); 205 | entity->fillArbProperties(xform.getSchema().getArbGeomParams()); 206 | entity->fillUserProperties(xform.getSchema().getUserProperties()); 207 | return entity; 208 | } 209 | else if(ICamera::matches(md)) 210 | { 211 | ICamera cam(iObj, Alembic::Abc::kWrapExisting); 212 | CameraLocatorEntity* entity = new CameraLocatorEntity(parent); 213 | entity->addComponent(_cameraMaterial); 214 | entity->fillArbProperties(cam.getSchema().getArbGeomParams()); 215 | entity->fillUserProperties(cam.getSchema().getUserProperties()); 216 | return entity; 217 | } 218 | else 219 | { 220 | // fallback: create empty object to preserve hierarchy 221 | return new BaseAlembicObject(parent); 222 | } 223 | }; 224 | 225 | if(_skipHidden) 226 | { 227 | // Skip objects with visibilityProperty explicitly set to hidden 228 | const auto& prop = iObj.getProperties(); 229 | 230 | if(prop.getPropertyHeader(kVisibilityPropertyName)) 231 | { 232 | IVisibilityProperty visibilityProperty(prop, kVisibilityPropertyName); 233 | if(ObjectVisibility(visibilityProperty.getValue()) == kVisibilityHidden) 234 | return; 235 | } 236 | } 237 | 238 | BaseAlembicObject* entity = createEntity(iObj); 239 | entity->setObjectName(iObj.getName().c_str()); 240 | 241 | // visit children 242 | for(size_t i = 0; i < iObj.getNumChildren(); i++) 243 | visitAbcObject(iObj.getChild(i), entity); 244 | } 245 | 246 | } // namespace 247 | -------------------------------------------------------------------------------- /LICENSE-MPL2.md: -------------------------------------------------------------------------------- 1 | Mozilla Public License Version 2.0 2 | ================================== 3 | 4 | 1. Definitions 5 | -------------- 6 | 7 | 1.1. "Contributor" 8 | means each individual or legal entity that creates, contributes to 9 | the creation of, or owns Covered Software. 10 | 11 | 1.2. "Contributor Version" 12 | means the combination of the Contributions of others (if any) used 13 | by a Contributor and that particular Contributor's Contribution. 14 | 15 | 1.3. "Contribution" 16 | means Covered Software of a particular Contributor. 17 | 18 | 1.4. "Covered Software" 19 | means Source Code Form to which the initial Contributor has attached 20 | the notice in Exhibit A, the Executable Form of such Source Code 21 | Form, and Modifications of such Source Code Form, in each case 22 | including portions thereof. 23 | 24 | 1.5. "Incompatible With Secondary Licenses" 25 | means 26 | 27 | (a) that the initial Contributor has attached the notice described 28 | in Exhibit B to the Covered Software; or 29 | 30 | (b) that the Covered Software was made available under the terms of 31 | version 1.1 or earlier of the License, but not also under the 32 | terms of a Secondary License. 33 | 34 | 1.6. "Executable Form" 35 | means any form of the work other than Source Code Form. 36 | 37 | 1.7. "Larger Work" 38 | means a work that combines Covered Software with other material, in 39 | a separate file or files, that is not Covered Software. 40 | 41 | 1.8. "License" 42 | means this document. 43 | 44 | 1.9. "Licensable" 45 | means having the right to grant, to the maximum extent possible, 46 | whether at the time of the initial grant or subsequently, any and 47 | all of the rights conveyed by this License. 48 | 49 | 1.10. "Modifications" 50 | means any of the following: 51 | 52 | (a) any file in Source Code Form that results from an addition to, 53 | deletion from, or modification of the contents of Covered 54 | Software; or 55 | 56 | (b) any new file in Source Code Form that contains any Covered 57 | Software. 58 | 59 | 1.11. "Patent Claims" of a Contributor 60 | means any patent claim(s), including without limitation, method, 61 | process, and apparatus claims, in any patent Licensable by such 62 | Contributor that would be infringed, but for the grant of the 63 | License, by the making, using, selling, offering for sale, having 64 | made, import, or transfer of either its Contributions or its 65 | Contributor Version. 66 | 67 | 1.12. "Secondary License" 68 | means either the GNU General Public License, Version 2.0, the GNU 69 | Lesser General Public License, Version 2.1, the GNU Affero General 70 | Public License, Version 3.0, or any later versions of those 71 | licenses. 72 | 73 | 1.13. "Source Code Form" 74 | means the form of the work preferred for making modifications. 75 | 76 | 1.14. "You" (or "Your") 77 | means an individual or a legal entity exercising rights under this 78 | License. For legal entities, "You" includes any entity that 79 | controls, is controlled by, or is under common control with You. For 80 | purposes of this definition, "control" means (a) the power, direct 81 | or indirect, to cause the direction or management of such entity, 82 | whether by contract or otherwise, or (b) ownership of more than 83 | fifty percent (50%) of the outstanding shares or beneficial 84 | ownership of such entity. 85 | 86 | 2. License Grants and Conditions 87 | -------------------------------- 88 | 89 | 2.1. Grants 90 | 91 | Each Contributor hereby grants You a world-wide, royalty-free, 92 | non-exclusive license: 93 | 94 | (a) under intellectual property rights (other than patent or trademark) 95 | Licensable by such Contributor to use, reproduce, make available, 96 | modify, display, perform, distribute, and otherwise exploit its 97 | Contributions, either on an unmodified basis, with Modifications, or 98 | as part of a Larger Work; and 99 | 100 | (b) under Patent Claims of such Contributor to make, use, sell, offer 101 | for sale, have made, import, and otherwise transfer either its 102 | Contributions or its Contributor Version. 103 | 104 | 2.2. Effective Date 105 | 106 | The licenses granted in Section 2.1 with respect to any Contribution 107 | become effective for each Contribution on the date the Contributor first 108 | distributes such Contribution. 109 | 110 | 2.3. Limitations on Grant Scope 111 | 112 | The licenses granted in this Section 2 are the only rights granted under 113 | this License. No additional rights or licenses will be implied from the 114 | distribution or licensing of Covered Software under this License. 115 | Notwithstanding Section 2.1(b) above, no patent license is granted by a 116 | Contributor: 117 | 118 | (a) for any code that a Contributor has removed from Covered Software; 119 | or 120 | 121 | (b) for infringements caused by: (i) Your and any other third party's 122 | modifications of Covered Software, or (ii) the combination of its 123 | Contributions with other software (except as part of its Contributor 124 | Version); or 125 | 126 | (c) under Patent Claims infringed by Covered Software in the absence of 127 | its Contributions. 128 | 129 | This License does not grant any rights in the trademarks, service marks, 130 | or logos of any Contributor (except as may be necessary to comply with 131 | the notice requirements in Section 3.4). 132 | 133 | 2.4. Subsequent Licenses 134 | 135 | No Contributor makes additional grants as a result of Your choice to 136 | distribute the Covered Software under a subsequent version of this 137 | License (see Section 10.2) or under the terms of a Secondary License (if 138 | permitted under the terms of Section 3.3). 139 | 140 | 2.5. Representation 141 | 142 | Each Contributor represents that the Contributor believes its 143 | Contributions are its original creation(s) or it has sufficient rights 144 | to grant the rights to its Contributions conveyed by this License. 145 | 146 | 2.6. Fair Use 147 | 148 | This License is not intended to limit any rights You have under 149 | applicable copyright doctrines of fair use, fair dealing, or other 150 | equivalents. 151 | 152 | 2.7. Conditions 153 | 154 | Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted 155 | in Section 2.1. 156 | 157 | 3. Responsibilities 158 | ------------------- 159 | 160 | 3.1. Distribution of Source Form 161 | 162 | All distribution of Covered Software in Source Code Form, including any 163 | Modifications that You create or to which You contribute, must be under 164 | the terms of this License. You must inform recipients that the Source 165 | Code Form of the Covered Software is governed by the terms of this 166 | License, and how they can obtain a copy of this License. You may not 167 | attempt to alter or restrict the recipients' rights in the Source Code 168 | Form. 169 | 170 | 3.2. Distribution of Executable Form 171 | 172 | If You distribute Covered Software in Executable Form then: 173 | 174 | (a) such Covered Software must also be made available in Source Code 175 | Form, as described in Section 3.1, and You must inform recipients of 176 | the Executable Form how they can obtain a copy of such Source Code 177 | Form by reasonable means in a timely manner, at a charge no more 178 | than the cost of distribution to the recipient; and 179 | 180 | (b) You may distribute such Executable Form under the terms of this 181 | License, or sublicense it under different terms, provided that the 182 | license for the Executable Form does not attempt to limit or alter 183 | the recipients' rights in the Source Code Form under this License. 184 | 185 | 3.3. Distribution of a Larger Work 186 | 187 | You may create and distribute a Larger Work under terms of Your choice, 188 | provided that You also comply with the requirements of this License for 189 | the Covered Software. If the Larger Work is a combination of Covered 190 | Software with a work governed by one or more Secondary Licenses, and the 191 | Covered Software is not Incompatible With Secondary Licenses, this 192 | License permits You to additionally distribute such Covered Software 193 | under the terms of such Secondary License(s), so that the recipient of 194 | the Larger Work may, at their option, further distribute the Covered 195 | Software under the terms of either this License or such Secondary 196 | License(s). 197 | 198 | 3.4. Notices 199 | 200 | You may not remove or alter the substance of any license notices 201 | (including copyright notices, patent notices, disclaimers of warranty, 202 | or limitations of liability) contained within the Source Code Form of 203 | the Covered Software, except that You may alter any license notices to 204 | the extent required to remedy known factual inaccuracies. 205 | 206 | 3.5. Application of Additional Terms 207 | 208 | You may choose to offer, and to charge a fee for, warranty, support, 209 | indemnity or liability obligations to one or more recipients of Covered 210 | Software. However, You may do so only on Your own behalf, and not on 211 | behalf of any Contributor. You must make it absolutely clear that any 212 | such warranty, support, indemnity, or liability obligation is offered by 213 | You alone, and You hereby agree to indemnify every Contributor for any 214 | liability incurred by such Contributor as a result of warranty, support, 215 | indemnity or liability terms You offer. You may include additional 216 | disclaimers of warranty and limitations of liability specific to any 217 | jurisdiction. 218 | 219 | 4. Inability to Comply Due to Statute or Regulation 220 | --------------------------------------------------- 221 | 222 | If it is impossible for You to comply with any of the terms of this 223 | License with respect to some or all of the Covered Software due to 224 | statute, judicial order, or regulation then You must: (a) comply with 225 | the terms of this License to the maximum extent possible; and (b) 226 | describe the limitations and the code they affect. Such description must 227 | be placed in a text file included with all distributions of the Covered 228 | Software under this License. Except to the extent prohibited by statute 229 | or regulation, such description must be sufficiently detailed for a 230 | recipient of ordinary skill to be able to understand it. 231 | 232 | 5. Termination 233 | -------------- 234 | 235 | 5.1. The rights granted under this License will terminate automatically 236 | if You fail to comply with any of its terms. However, if You become 237 | compliant, then the rights granted under this License from a particular 238 | Contributor are reinstated (a) provisionally, unless and until such 239 | Contributor explicitly and finally terminates Your grants, and (b) on an 240 | ongoing basis, if such Contributor fails to notify You of the 241 | non-compliance by some reasonable means prior to 60 days after You have 242 | come back into compliance. Moreover, Your grants from a particular 243 | Contributor are reinstated on an ongoing basis if such Contributor 244 | notifies You of the non-compliance by some reasonable means, this is the 245 | first time You have received notice of non-compliance with this License 246 | from such Contributor, and You become compliant prior to 30 days after 247 | Your receipt of the notice. 248 | 249 | 5.2. If You initiate litigation against any entity by asserting a patent 250 | infringement claim (excluding declaratory judgment actions, 251 | counter-claims, and cross-claims) alleging that a Contributor Version 252 | directly or indirectly infringes any patent, then the rights granted to 253 | You by any and all Contributors for the Covered Software under Section 254 | 2.1 of this License shall terminate. 255 | 256 | 5.3. In the event of termination under Sections 5.1 or 5.2 above, all 257 | end user license agreements (excluding distributors and resellers) which 258 | have been validly granted by You or Your distributors under this License 259 | prior to termination shall survive termination. 260 | 261 | ************************************************************************ 262 | * * 263 | * 6. Disclaimer of Warranty * 264 | * ------------------------- * 265 | * * 266 | * Covered Software is provided under this License on an "as is" * 267 | * basis, without warranty of any kind, either expressed, implied, or * 268 | * statutory, including, without limitation, warranties that the * 269 | * Covered Software is free of defects, merchantable, fit for a * 270 | * particular purpose or non-infringing. The entire risk as to the * 271 | * quality and performance of the Covered Software is with You. * 272 | * Should any Covered Software prove defective in any respect, You * 273 | * (not any Contributor) assume the cost of any necessary servicing, * 274 | * repair, or correction. This disclaimer of warranty constitutes an * 275 | * essential part of this License. No use of any Covered Software is * 276 | * authorized under this License except under this disclaimer. * 277 | * * 278 | ************************************************************************ 279 | 280 | ************************************************************************ 281 | * * 282 | * 7. Limitation of Liability * 283 | * -------------------------- * 284 | * * 285 | * Under no circumstances and under no legal theory, whether tort * 286 | * (including negligence), contract, or otherwise, shall any * 287 | * Contributor, or anyone who distributes Covered Software as * 288 | * permitted above, be liable to You for any direct, indirect, * 289 | * special, incidental, or consequential damages of any character * 290 | * including, without limitation, damages for lost profits, loss of * 291 | * goodwill, work stoppage, computer failure or malfunction, or any * 292 | * and all other commercial damages or losses, even if such party * 293 | * shall have been informed of the possibility of such damages. This * 294 | * limitation of liability shall not apply to liability for death or * 295 | * personal injury resulting from such party's negligence to the * 296 | * extent applicable law prohibits such limitation. Some * 297 | * jurisdictions do not allow the exclusion or limitation of * 298 | * incidental or consequential damages, so this exclusion and * 299 | * limitation may not apply to You. * 300 | * * 301 | ************************************************************************ 302 | 303 | 8. Litigation 304 | ------------- 305 | 306 | Any litigation relating to this License may be brought only in the 307 | courts of a jurisdiction where the defendant maintains its principal 308 | place of business and such litigation shall be governed by laws of that 309 | jurisdiction, without reference to its conflict-of-law provisions. 310 | Nothing in this Section shall prevent a party's ability to bring 311 | cross-claims or counter-claims. 312 | 313 | 9. Miscellaneous 314 | ---------------- 315 | 316 | This License represents the complete agreement concerning the subject 317 | matter hereof. If any provision of this License is held to be 318 | unenforceable, such provision shall be reformed only to the extent 319 | necessary to make it enforceable. Any law or regulation which provides 320 | that the language of a contract shall be construed against the drafter 321 | shall not be used to construe this License against a Contributor. 322 | 323 | 10. Versions of the License 324 | --------------------------- 325 | 326 | 10.1. New Versions 327 | 328 | Mozilla Foundation is the license steward. Except as provided in Section 329 | 10.3, no one other than the license steward has the right to modify or 330 | publish new versions of this License. Each version will be given a 331 | distinguishing version number. 332 | 333 | 10.2. Effect of New Versions 334 | 335 | You may distribute the Covered Software under the terms of the version 336 | of the License under which You originally received the Covered Software, 337 | or under the terms of any subsequent version published by the license 338 | steward. 339 | 340 | 10.3. Modified Versions 341 | 342 | If you create software not governed by this License, and you want to 343 | create a new license for such software, you may create and use a 344 | modified version of this License if you rename the license and remove 345 | any references to the name of the license steward (except to note that 346 | such modified license differs from this License). 347 | 348 | 10.4. Distributing Source Code Form that is Incompatible With Secondary 349 | Licenses 350 | 351 | If You choose to distribute Source Code Form that is Incompatible With 352 | Secondary Licenses under the terms of this version of the License, the 353 | notice described in Exhibit B of this License must be attached. 354 | 355 | Exhibit A - Source Code Form License Notice 356 | ------------------------------------------- 357 | 358 | This Source Code Form is subject to the terms of the Mozilla Public 359 | License, v. 2.0. If a copy of the MPL was not distributed with this 360 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 361 | 362 | If it is not possible or desirable to put the notice in a particular 363 | file, then You may include the notice in a location (such as a LICENSE 364 | file in a relevant directory) where a recipient would be likely to look 365 | for such a notice. 366 | 367 | You may add additional accurate notices of copyright ownership. 368 | 369 | Exhibit B - "Incompatible With Secondary Licenses" Notice 370 | --------------------------------------------------------- 371 | 372 | This Source Code Form is "Incompatible With Secondary Licenses", as 373 | defined by the Mozilla Public License, v. 2.0. 374 | --------------------------------------------------------------------------------