Skip to content

Commit

Permalink
Blender exporter plugin - first draft
Browse files Browse the repository at this point in the history
pybind11 required

Signed-off-by: Matteo De Carlo <[email protected]>
  • Loading branch information
portaloffreedom committed Jan 3, 2024
1 parent 26ae5cf commit bf018ec
Show file tree
Hide file tree
Showing 6 changed files with 581 additions and 0 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ bld/
[Bb]in/
[Oo]bj/

# Python build results
*.pyc
*.cpython*.so

# Roslyn cache directories
*.ide/

Expand Down
10 changes: 10 additions & 0 deletions BlenderExporter/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
set (SOURCE_FILES
python_bindings.cpp
)

find_package(pybind11 CONFIG REQUIRED)
pybind11_add_module(pywickedengine MODULE ${SOURCE_FILES})
target_compile_definitions(pywickedengine PUBLIC PYTHON_BINDINGS)
target_link_libraries(pywickedengine PUBLIC WickedEngine)
target_compile_definitions(pywickedengine PUBLIC "WICKED_ROOT_DIR=\"${WICKED_ROOT_DIR}\"")
install(TARGETS pywickedengine DESTINATION "~/.config/blender/4.0/scripts/addons/pywickedengine/")
311 changes: 311 additions & 0 deletions BlenderExporter/python_bindings.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,311 @@
#include "wiArchive.h"
#include "wiResourceManager.h"
#include "wiScene.h"
#include "wiInitializer.h"
#include "wiApplication.h"
#include "wiECS.h"
#include "wiRenderer.h"

#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/stl_bind.h>
#include <wiScene_Components.h>

namespace py = pybind11;

PYBIND11_MAKE_OPAQUE(wi::vector<XMFLOAT2>);
PYBIND11_MAKE_OPAQUE(wi::vector<XMFLOAT3>);
PYBIND11_MAKE_OPAQUE(wi::vector<XMFLOAT4>);
PYBIND11_MAKE_OPAQUE(wi::vector<XMUINT4>);
PYBIND11_MAKE_OPAQUE(wi::vector<uint8_t>);
PYBIND11_MAKE_OPAQUE(wi::vector<uint32_t>);
PYBIND11_MAKE_OPAQUE(wi::vector<wi::scene::MeshComponent::MeshSubset>);
PYBIND11_MAKE_OPAQUE(wi::scene::NameComponent);
PYBIND11_MAKE_OPAQUE(wi::scene::MeshComponent);
PYBIND11_MAKE_OPAQUE(wi::scene::MaterialComponent);
PYBIND11_MAKE_OPAQUE(wi::scene::TransformComponent);
PYBIND11_MAKE_OPAQUE(wi::scene::ObjectComponent);

static wi::Application app;

void init_wicked(py::module_& mod)
{
//TODO we can probably initialize less stuff

sdl2::sdlsystem_ptr_t system = sdl2::make_sdlsystem(SDL_INIT_VIDEO);
if (!system) {
throw sdl2::SDLError("Error creating SDL2 system");
}

sdl2::window_ptr_t window = sdl2::make_window("WickedBlenderExporter",
SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED,
50, 50,
SDL_WINDOW_HIDDEN | SDL_WINDOW_VULKAN);
if (!window) {
throw sdl2::SDLError("Error creating window");
}

app.SetWindow(window.get());
wi::renderer::SetShaderSourcePath(WICKED_ROOT_DIR"/WickedEngine/shaders/");
wi::renderer::SetShaderPath(WICKED_ROOT_DIR"/build/BlenderExporter/shaders/");

wi::initializer::InitializeComponentsImmediate();
app.Initialize();
app.Update(0.33);
}

void export_primitives(py::module_& mod)
{
py::class_<XMFLOAT2>(mod, "XMFLOAT2")
.def(py::init<>())
.def(py::init<float, float>())
;
py::class_<XMFLOAT3>(mod, "XMFLOAT3")
.def(py::init<>())
.def(py::init<float, float, float>())
;
py::class_<XMFLOAT4>(mod, "XMFLOAT4")
.def(py::init<>())
.def(py::init<float, float, float, float>())
;
py::class_<XMUINT4>(mod, "XMUINT4")
.def(py::init<>())
.def(py::init<uint32_t, uint32_t, uint32_t, uint32_t>())
;

py::bind_vector<wi::vector<XMFLOAT2>>(mod, "VectorXMFLOAT2");
py::bind_vector<wi::vector<XMFLOAT3>>(mod, "VectorXMFLOAT3");
py::bind_vector<wi::vector<XMFLOAT4>>(mod, "VectorXMFLOAT4");
py::bind_vector<wi::vector<XMUINT4 >>(mod, "VectorXMUINT4");
py::bind_vector<wi::vector<uint8_t >>(mod, "VectorU8");
py::bind_vector<wi::vector<uint32_t>>(mod, "VectorU32");
py::bind_vector<wi::vector<wi::scene::MeshComponent::MeshSubset>>(mod, "VectorMeshSubset");

}

void export_resourcemanager(py::module_& mod)
{
py::enum_<wi::resourcemanager::Mode>(mod, "ResourceManagerMode")
.value("DISCARD_FILEDATA_AFTER_LOAD", wi::resourcemanager::Mode::DISCARD_FILEDATA_AFTER_LOAD)
.value("ALLOW_RETAIN_FILEDATA", wi::resourcemanager::Mode::ALLOW_RETAIN_FILEDATA)
.value("ALLOW_RETAIN_FILEDATA_BUT_DISABLE_EMBEDDING", wi::resourcemanager::Mode::ALLOW_RETAIN_FILEDATA_BUT_DISABLE_EMBEDDING)
.export_values();

mod.def("resourcemanager_SetMode", &wi::resourcemanager::SetMode);
}

void export_Archive(py::module_& mod)
{
py::class_<wi::Archive>(mod, "Archive")
.def(py::init<>())
.def(py::init<const std::string&, bool>())
.def("IsOpen", &wi::Archive::IsOpen)
.def("Close", &wi::Archive::Close)
.def("SaveFile", &wi::Archive::SaveFile)
.def("SaveHeaderFile", &wi::Archive::SaveHeaderFile)
;
}

void export_Scene(py::module_& mod)
{
py::class_<wi::scene::Scene>(mod, "Scene")
.def(py::init<>())
//.def_readwrite("componentLibrary", &wi::scene::Scene::componentLibrary)
.def("names", [](const wi::scene::Scene &_this){ return &_this.names; })
.def("meshes", [](const wi::scene::Scene &_this){ return &_this.meshes; })
.def("transforms", [](const wi::scene::Scene &_this){ return &_this.transforms; })
.def("materials", [](const wi::scene::Scene &_this){ return &_this.materials; })
.def("objects", [](const wi::scene::Scene &_this){ return &_this.objects; })
.def("Serialize", &wi::scene::Scene::Serialize)
.def("Entity_CreateTransform", &wi::scene::Scene::Entity_CreateTransform)
.def("Entity_CreateMaterial", &wi::scene::Scene::Entity_CreateMaterial)
.def("Entity_CreateObject", &wi::scene::Scene::Entity_CreateObject)
.def("Entity_CreateMesh", &wi::scene::Scene::Entity_CreateMesh)
.def("Entity_CreateLight", &wi::scene::Scene::Entity_CreateLight)
.def("Entity_CreateForce", &wi::scene::Scene::Entity_CreateForce)
.def("Entity_CreateEnvironmentProbe", &wi::scene::Scene::Entity_CreateEnvironmentProbe)
.def("Entity_CreateDecal", &wi::scene::Scene::Entity_CreateDecal)
.def("Entity_CreateCamera", &wi::scene::Scene::Entity_CreateCamera)
.def("Entity_CreateEmitter", &wi::scene::Scene::Entity_CreateEmitter)
.def("Entity_CreateHair", &wi::scene::Scene::Entity_CreateHair)
.def("Entity_CreateSound", &wi::scene::Scene::Entity_CreateSound)
.def("Entity_CreateVideo", &wi::scene::Scene::Entity_CreateVideo)
.def("Entity_CreateCube", &wi::scene::Scene::Entity_CreateCube)
.def("Entity_CreatePlane", &wi::scene::Scene::Entity_CreatePlane)
.def("Entity_CreateSphere", &wi::scene::Scene::Entity_CreateSphere)
.def("Component_Attach", &wi::scene::Scene::Component_Attach)
.def("Component_Attach", [](wi::scene::Scene& _this, wi::ecs::Entity entity, wi::ecs::Entity parent) { return _this.Component_Attach(entity, parent); })
.def("Component_Detach", &wi::scene::Scene::Component_Detach)
.def("Component_DetachChildren", &wi::scene::Scene::Component_DetachChildren)
.def("RunAnimationUpdateSystem", &wi::scene::Scene::RunAnimationUpdateSystem)
.def("RunTransformUpdateSystem", &wi::scene::Scene::RunTransformUpdateSystem)
.def("RunHierarchyUpdateSystem", &wi::scene::Scene::RunHierarchyUpdateSystem)
.def("RunExpressionUpdateSystem", &wi::scene::Scene::RunExpressionUpdateSystem)
.def("RunProceduralAnimationUpdateSystem", &wi::scene::Scene::RunProceduralAnimationUpdateSystem)
.def("RunArmatureUpdateSystem", &wi::scene::Scene::RunArmatureUpdateSystem)
.def("RunMeshUpdateSystem", &wi::scene::Scene::RunMeshUpdateSystem)
.def("RunMaterialUpdateSystem", &wi::scene::Scene::RunMaterialUpdateSystem)
.def("RunImpostorUpdateSystem", &wi::scene::Scene::RunImpostorUpdateSystem)
.def("RunObjectUpdateSystem", &wi::scene::Scene::RunObjectUpdateSystem)
.def("RunCameraUpdateSystem", &wi::scene::Scene::RunCameraUpdateSystem)
.def("RunDecalUpdateSystem", &wi::scene::Scene::RunDecalUpdateSystem)
.def("RunProbeUpdateSystem", &wi::scene::Scene::RunProbeUpdateSystem)
.def("RunForceUpdateSystem", &wi::scene::Scene::RunForceUpdateSystem)
.def("RunLightUpdateSystem", &wi::scene::Scene::RunLightUpdateSystem)
.def("RunParticleUpdateSystem", &wi::scene::Scene::RunParticleUpdateSystem)
.def("RunWeatherUpdateSystem", &wi::scene::Scene::RunWeatherUpdateSystem)
.def("RunSoundUpdateSystem", &wi::scene::Scene::RunSoundUpdateSystem)
.def("RunVideoUpdateSystem", &wi::scene::Scene::RunVideoUpdateSystem)
.def("RunScriptUpdateSystem", &wi::scene::Scene::RunScriptUpdateSystem)
.def("RunSpriteUpdateSystem", &wi::scene::Scene::RunSpriteUpdateSystem)
.def("RunFontUpdateSystem", &wi::scene::Scene::RunFontUpdateSystem)
;
}

template<typename T>
void register_component_manager(py::module_& mod, const char* name)
{
typedef wi::ecs::ComponentManager<T> Manager;
py::class_<Manager, std::unique_ptr<Manager, py::nodelete>>(mod, name)
.def("Clear", &Manager::Clear)
// .def("Copy", &Manager::Copy)
// .def("Merge", &Manager::Merge)
.def("Create", &Manager::Create)
.def("Remove", &Manager::Remove)
.def("MoveItem", &Manager::MoveItem)
.def("Contains", &Manager::Contains)
.def("GetComponent", [](Manager* _this, wi::ecs::Entity entity) { return static_cast<T*>(_this->GetComponent(entity)); })
.def("GetIndex", &Manager::GetIndex)
.def("GetCount", [](const Manager* _this) { return _this->GetCount(); })
.def("GetEntity", &Manager::GetEntity)
.def("GetEntityArray", &Manager::GetEntityArray)
.def("GetComponentArray", &Manager::GetComponentArray)
;
}

void export_ECS(py::module_& mod)
{
using namespace wi::ecs;
using namespace wi::scene;
// py::class_<ComponentLibrary>(mod, "ComponentLibrary");

// py::class_<Entity>(mod, "Entity");
mod.def("CreateEntity", &CreateEntity);

//maybe Components need to not handle memory by python
// `std::unique_ptr<TComponent, py::nodelete>`
py::class_<MeshComponent::MeshSubset>(mod, "MeshComponent_MeshSubset")
.def(py::init<>())
.def_readwrite("materialID", &MeshComponent::MeshSubset::materialID)
.def_readwrite("indexOffset", &MeshComponent::MeshSubset::indexOffset)
.def_readwrite("indexCount", &MeshComponent::MeshSubset::indexCount)
.def_readwrite("materialIndex", &MeshComponent::MeshSubset::materialIndex)
;

py::class_<NameComponent, std::unique_ptr<NameComponent, py::nodelete>>(mod, "NameComponent")
.def_readwrite("name", &NameComponent::name)
;

py::class_<MeshComponent, std::unique_ptr<MeshComponent, py::nodelete>>(mod, "MeshComponent")
.def_readwrite("vertex_positions", &MeshComponent::vertex_positions)
.def_readwrite("vertex_normals", &MeshComponent::vertex_normals)
.def_readwrite("vertex_tangents", &MeshComponent::vertex_tangents)
.def_readwrite("vertex_uvset_0", &MeshComponent::vertex_uvset_0)
.def_readwrite("vertex_uvset_1", &MeshComponent::vertex_uvset_1)
.def_readwrite("vertex_boneindices", &MeshComponent::vertex_boneindices)
.def_readwrite("vertex_boneweights", &MeshComponent::vertex_boneweights)
.def_readwrite("vertex_atlas", &MeshComponent::vertex_atlas)
.def_readwrite("vertex_colors", &MeshComponent::vertex_colors)
.def_readwrite("vertex_windweights", &MeshComponent::vertex_windweights)
.def_readwrite("indices", &MeshComponent::indices)
.def_readwrite("subsets", &MeshComponent::subsets)
.def_readwrite("tessellationFactor", &MeshComponent::tessellationFactor)
.def_readwrite("armatureID", &MeshComponent::armatureID)
.def("ComputeNormals", &MeshComponent::ComputeNormals)
.def("ComputeNormals", &MeshComponent::CreateRenderData)
;

py::enum_<MeshComponent::COMPUTE_NORMALS>(mod, "MeshComponentComputeNormals")
.value("HARD", MeshComponent::COMPUTE_NORMALS::COMPUTE_NORMALS_HARD)
.value("SMOOTH", MeshComponent::COMPUTE_NORMALS::COMPUTE_NORMALS_SMOOTH)
.value("SMOOTH_FAST", MeshComponent::COMPUTE_NORMALS::COMPUTE_NORMALS_SMOOTH_FAST)
.export_values()
;

py::class_<TransformComponent>(mod, "TransformComponent")
.def(py::init<>())
.def_readwrite("scale_local", &TransformComponent::scale_local)
.def_readwrite("rotation_local", &TransformComponent::rotation_local)
.def_readwrite("translation_local", &TransformComponent::translation_local)
.def_readwrite("world", &TransformComponent::world)
.def("GetPosition", &TransformComponent::GetPosition)
.def("GetRotation", &TransformComponent::GetRotation)
.def("GetScale", &TransformComponent::GetScale)
.def("GetPositionV", &TransformComponent::GetPositionV)
.def("GetRotationV", &TransformComponent::GetRotationV)
.def("GetScaleV", &TransformComponent::GetScaleV)
.def("GetLocalMatrix", &TransformComponent::GetLocalMatrix)
.def("UpdateTransform", &TransformComponent::UpdateTransform)
.def("UpdateTransform_Parented", &TransformComponent::UpdateTransform_Parented)
.def("ApplyTransform", &TransformComponent::ApplyTransform)
.def("ClearTransform", &TransformComponent::ClearTransform)
// .def("Translate", &TransformComponent::Translate)
// .def("Translate", &TransformComponent::Translate)
.def("RotateRollPitchYaw", &TransformComponent::RotateRollPitchYaw)
// .def("Rotate", &TransformComponent::Rotate)
// .def("Rotate", &TransformComponent::Rotate)
// .def("Scale", &TransformComponent::Scale)
// .def("Scale", &TransformComponent::Scale)
// .def("MatrixTransform", &TransformComponent::MatrixTransform)
// .def("MatrixTransform", &TransformComponent::MatrixTransform)
.def("Lerp", &TransformComponent::Lerp)
.def("CatmullRom", &TransformComponent::CatmullRom)
;


py::class_<MaterialComponent, std::unique_ptr<MaterialComponent, py::nodelete>>(mod, "MaterialComponent")
.def_readwrite("baseColor", &MaterialComponent::baseColor)
;

py::class_<ObjectComponent, std::unique_ptr<ObjectComponent, py::nodelete>>(mod, "ObjectComponent")
.def_readwrite("meshID", &ObjectComponent::meshID)
.def_readwrite("cascadeMask", &ObjectComponent::cascadeMask)
.def_readwrite("filterMask", &ObjectComponent::filterMask)
.def_readwrite("color", &ObjectComponent::color)
.def_readwrite("emissiveColor", &ObjectComponent::emissiveColor)
.def_readwrite("userStencilRef", &ObjectComponent::userStencilRef)
.def_readwrite("lod_distance_multiplier", &ObjectComponent::lod_distance_multiplier)
.def_readwrite("draw_distance", &ObjectComponent::draw_distance)
.def_readwrite("lightmapWidth", &ObjectComponent::lightmapWidth)
.def_readwrite("lightmapHeight", &ObjectComponent::lightmapHeight)
.def_readwrite("lightmapTextureData", &ObjectComponent::lightmapTextureData)
.def_readwrite("sort_priority", &ObjectComponent::sort_priority)
.def_readwrite("filterMaskDynamic", &ObjectComponent::filterMaskDynamic)
.def_readwrite("lightmap", &ObjectComponent::lightmap)
.def_readwrite("lightmapIterationCount", &ObjectComponent::lightmapIterationCount)
.def_readwrite("center", &ObjectComponent::center)
.def_readwrite("radius", &ObjectComponent::radius)
.def_readwrite("fadeDistance", &ObjectComponent::fadeDistance)
.def_readwrite("lod", &ObjectComponent::lod)
.def_readwrite("mesh_index", &ObjectComponent::mesh_index)
.def_readwrite("sort_bits", &ObjectComponent::sort_bits)
;

// MANAGERS -------------------------------------------
register_component_manager<NameComponent>(mod, "NameComponentManager");
register_component_manager<TransformComponent>(mod, "TransformComponentManager");
register_component_manager<MeshComponent>(mod, "MeshComponentManager");
register_component_manager<MaterialComponent>(mod, "MaterialComponentManager");
register_component_manager<ObjectComponent>(mod, "ObjectComponentManager");
}

PYBIND11_MODULE(pywickedengine, mod)
{
init_wicked(mod);
export_primitives(mod);
export_resourcemanager(mod);
export_ECS(mod);
export_Archive(mod);
export_Scene(mod);
}
23 changes: 23 additions & 0 deletions BlenderExporter/test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#!/usr/bin/env python3

import pywickedengine

dump_to_header = False

def main():
filename = "/tmp/test.wiscene"
ar = pywickedengine.Archive() if dump_to_header else pywickedengine.Archive(filename, False)
if not ar.IsOpen():
print("ERROR, ARCHIVE DID NOT OPEN")
return

scene = pywickedengine.Scene()
scene.Serialize(ar)

if dump_to_header:
ar.SaveHeaderFile("/tmp/test.h","test")# wi::helper::RemoveExtension(wi::helper::GetFileNameFromPath(filename)));

ar.Close()

if __name__ == "__main__":
main()
Loading

0 comments on commit bf018ec

Please sign in to comment.