Skip to content

Commit

Permalink
UPBGE: Implement mesh duplication in python.
Browse files Browse the repository at this point in the history
The user is now able to duplicate a KX_Mesh using the python function
mesh.copy().

Internally this function copy construct KX_Mesh and RAS_Mesh and its
RAS_MeshMaterial, then the mesh conversion is finalized and registered
to the converter.
For this last operation it was needed to store a KX_Scene pointer into
KX_Mesh and to be able to replace it in case of lib loading.
  • Loading branch information
panzergame committed Dec 24, 2017
1 parent 6a5f431 commit 1df87c0
Show file tree
Hide file tree
Showing 12 changed files with 93 additions and 13 deletions.
6 changes: 6 additions & 0 deletions doc/python_api/rst/bge_types/bge.types.KX_Mesh.rst
Original file line number Diff line number Diff line change
Expand Up @@ -151,3 +151,9 @@ base class --- :class:`EXP_Value`

Changing the material of a mesh used by many objects can be slow. This function should be not called every frames

.. method:: copy()

Return a duplicated mesh.

:return: a duplicated mesh of the current used.
:rtype: :class:`KX_Mesh`.
19 changes: 14 additions & 5 deletions source/gameengine/Converter/BL_BlenderConverter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -237,8 +237,12 @@ void BL_BlenderConverter::ConvertScene(BL_BlenderSceneConverter& converter, bool
m_sceneSlots.emplace(scene, converter);
}

void BL_BlenderConverter::InitSceneShaders(const BL_BlenderSceneConverter& converter, KX_Scene *mergeScene)
void BL_BlenderConverter::FinalizeSceneData(const BL_BlenderSceneConverter& converter, KX_Scene *mergeScene)
{
for (KX_Mesh *mesh : converter.m_meshobjects) {
mesh->ReplaceScene(mergeScene);
}

for (KX_BlenderMaterial *mat : converter.m_materials) {
// Do this after lights are available so materials can use the lights in shaders.
mat->InitScene(mergeScene);
Expand Down Expand Up @@ -286,6 +290,11 @@ BL_InterpolatorList *BL_BlenderConverter::FindInterpolatorList(KX_Scene *scene,
return m_sceneSlots[scene].m_actionToInterp[for_act];
}

void BL_BlenderConverter::RegisterMesh(KX_Scene *scene, KX_Mesh *mesh)
{
m_sceneSlots[scene].m_meshobjects.emplace_back(mesh);
}

Main *BL_BlenderConverter::CreateMainDynamic(const std::string& path)
{
Main *maggie = BKE_main_new();
Expand Down Expand Up @@ -321,7 +330,7 @@ void BL_BlenderConverter::MergeAsyncLoads()
KX_Scene *scene = converter.GetScene();
MergeScene(mergeScene, scene);
// Finalize material and mesh conversion.
InitSceneShaders(converter, mergeScene);
FinalizeSceneData(converter, mergeScene);
delete scene;
}

Expand Down Expand Up @@ -479,7 +488,7 @@ KX_LibLoadStatus *BL_BlenderConverter::LinkBlendFile(BlendHandle *blendlib, cons
}

// Finalize material and mesh conversion.
InitSceneShaders(sceneConverter, scene_merge);
FinalizeSceneData(sceneConverter, scene_merge);
m_sceneSlots[scene_merge].Merge(sceneConverter);
}
else if (idcode == ID_AC) {
Expand Down Expand Up @@ -525,7 +534,7 @@ KX_LibLoadStatus *BL_BlenderConverter::LinkBlendFile(BlendHandle *blendlib, cons
MergeScene(scene_merge, other);

// Finalize material and mesh conversion.
InitSceneShaders(sceneConverter, scene_merge);
FinalizeSceneData(sceneConverter, scene_merge);

delete other;
}
Expand Down Expand Up @@ -836,7 +845,7 @@ KX_Mesh *BL_BlenderConverter::ConvertMeshSpecial(KX_Scene *kx_scene, Main *maggi
kx_scene->GetLogicManager()->RegisterMeshName(meshobj->GetName(), meshobj);

// Finalize material and mesh conversion.
InitSceneShaders(sceneConverter, kx_scene);
FinalizeSceneData(sceneConverter, kx_scene);
m_sceneSlots[kx_scene].Merge(sceneConverter);

return meshobj;
Expand Down
4 changes: 3 additions & 1 deletion source/gameengine/Converter/BL_BlenderConverter.h
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ class BL_BlenderConverter
* \param converter The scene convert to finalize.
* \param mergeScene The scene used to generate shaders.
*/
void InitSceneShaders(const BL_BlenderSceneConverter& converter, KX_Scene *mergeScene);
void FinalizeSceneData(const BL_BlenderSceneConverter& converter, KX_Scene *mergeScene);

/** This function removes all entities stored in the converter for that scene
* It should be used instead of direct delete scene
Expand All @@ -133,6 +133,8 @@ class BL_BlenderConverter

void RegisterInterpolatorList(KX_Scene *scene, BL_InterpolatorList *interpolator, bAction *for_act);
BL_InterpolatorList *FindInterpolatorList(KX_Scene *scene, bAction *for_act);
/// Register a mesh object copy.
void RegisterMesh(KX_Scene *scene, KX_Mesh *mesh);

Scene *GetBlenderSceneForName(const std::string& name);
EXP_ListValue<EXP_StringValue> *GetInactiveSceneNames();
Expand Down
2 changes: 1 addition & 1 deletion source/gameengine/Converter/BL_BlenderDataConversion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -453,7 +453,7 @@ KX_Mesh *BL_ConvertMesh(Mesh *me, Object *blenderobj, KX_Scene *scene, BL_Blende
vertformat.uvSize = max_ii(1, uvCount);
vertformat.colorSize = max_ii(1, colorCount);

meshobj = new KX_Mesh(me, layersInfo);
meshobj = new KX_Mesh(scene, me, layersInfo);

const unsigned short totmat = max_ii(me->totcol, 1);
std::vector<BL_MeshMaterial> mats(totmat);
Expand Down
2 changes: 1 addition & 1 deletion source/gameengine/Ketsji/KX_GameObject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3127,7 +3127,7 @@ PyObject *KX_GameObject::pyattr_get_meshes(EXP_PyObjectPlus *self_v, const EXP_P
Py_INCREF(item);
PyList_SET_ITEM(meshes, i, item);
}

return meshes;
}

Expand Down
2 changes: 1 addition & 1 deletion source/gameengine/Ketsji/KX_KetsjiEngine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1353,7 +1353,7 @@ void KX_KetsjiEngine::ConvertScene(KX_Scene *scene)
BL_BlenderSceneConverter sceneConverter(scene);
m_converter->ConvertScene(sceneConverter, false);
// Finalize material and mesh conversion.
m_converter->InitSceneShaders(sceneConverter, scene);
m_converter->FinalizeSceneData(sceneConverter, scene);
}

void KX_KetsjiEngine::AddScheduledScenes()
Expand Down
34 changes: 32 additions & 2 deletions source/gameengine/Ketsji/KX_Mesh.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@

#include "KX_Mesh.h"
#include "KX_Scene.h"
#include "KX_Globals.h"
#include "KX_KetsjiEngine.h"

#include "BL_BlenderConverter.h"

#include "RAS_IPolygonMaterial.h"
#include "RAS_DisplayArray.h"
#include "RAS_BucketManager.h"
Expand All @@ -48,15 +53,27 @@
#include "EXP_PyObjectPlus.h"
#include "EXP_ListWrapper.h"

KX_Mesh::KX_Mesh(Mesh *mesh, const RAS_Mesh::LayersInfo& layersInfo)
:RAS_Mesh(mesh, layersInfo)
KX_Mesh::KX_Mesh(KX_Scene *scene, Mesh *mesh, const RAS_Mesh::LayersInfo& layersInfo)
:RAS_Mesh(mesh, layersInfo),
m_scene(scene)
{
}

KX_Mesh::KX_Mesh(const KX_Mesh& other)
:RAS_Mesh(other),
m_scene(other.m_scene)
{
}

KX_Mesh::~KX_Mesh()
{
}

void KX_Mesh::ReplaceScene(KX_Scene *scene)
{
m_scene = scene;
}

#ifdef WITH_PYTHON

PyTypeObject KX_Mesh::Type = {
Expand Down Expand Up @@ -90,6 +107,7 @@ PyMethodDef KX_Mesh::Methods[] = {
{"transform", (PyCFunction) KX_Mesh::sPyTransform, METH_VARARGS},
{"transformUV", (PyCFunction) KX_Mesh::sPyTransformUV, METH_VARARGS},
{"replaceMaterial", (PyCFunction) KX_Mesh::sPyReplaceMaterial, METH_VARARGS},
{"copy", (PyCFunction) KX_Mesh::sPyCopy, METH_NOARGS},
{nullptr, nullptr} //Sentinel
};

Expand Down Expand Up @@ -359,6 +377,18 @@ PyObject *KX_Mesh::PyReplaceMaterial(PyObject *args, PyObject *kwds)
Py_RETURN_NONE;
}

PyObject *KX_Mesh::PyCopy()
{
KX_Mesh *dupli = new KX_Mesh(*this);
// Create bounding box.
dupli->EndConversion(m_scene->GetBoundingBoxManager());

// Transfer ownership to converter.
KX_GetActiveEngine()->GetConverter()->RegisterMesh(m_scene, dupli);

return dupli->GetProxy();
}

PyObject *KX_Mesh::pyattr_get_materials(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef)
{
KX_Mesh *self = static_cast<KX_Mesh *>(self_v);
Expand Down
10 changes: 9 additions & 1 deletion source/gameengine/Ketsji/KX_Mesh.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@

class KX_Mesh;
class SCA_LogicManager;
class KX_Scene;

#ifdef WITH_PYTHON
// utility conversion function
Expand All @@ -49,13 +50,19 @@ class KX_Mesh : public EXP_Value, public RAS_Mesh
{
Py_Header

private:
KX_Scene *m_scene;

public:
KX_Mesh(Mesh *mesh, const LayersInfo& layersInfo);
KX_Mesh(KX_Scene *scene, Mesh *mesh, const LayersInfo& layersInfo);
KX_Mesh(const KX_Mesh& other);
virtual ~KX_Mesh();

// stuff for cvalue related things
virtual std::string GetName();

void ReplaceScene(KX_Scene *scene);

#ifdef WITH_PYTHON

EXP_PYMETHOD(KX_Mesh, GetMaterialName);
Expand All @@ -68,6 +75,7 @@ class KX_Mesh : public EXP_Value, public RAS_Mesh
EXP_PYMETHOD(KX_Mesh, Transform);
EXP_PYMETHOD(KX_Mesh, TransformUV);
EXP_PYMETHOD(KX_Mesh, ReplaceMaterial);
EXP_PYMETHOD_NOARGS(KX_Mesh, Copy);

static PyObject *pyattr_get_materials(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef);
static PyObject *pyattr_get_numMaterials(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef);
Expand Down
12 changes: 12 additions & 0 deletions source/gameengine/Rasterizer/RAS_Mesh.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,18 @@ RAS_Mesh::RAS_Mesh(Mesh *mesh, const LayersInfo& layersInfo)
{
}

RAS_Mesh::RAS_Mesh(const RAS_Mesh& other)
:m_name(other.m_name),
m_layersInfo(other.m_layersInfo),
m_boundingBox(nullptr),
m_mesh(other.m_mesh)
{
for (RAS_MeshMaterial *meshmat : other.m_materials) {
RAS_MeshMaterial *newmeshmat = new RAS_MeshMaterial(*meshmat, this);
m_materials.push_back(newmeshmat);
}
}

RAS_Mesh::~RAS_Mesh()
{
for (RAS_MeshMaterial *meshmat : m_materials) {
Expand Down
2 changes: 1 addition & 1 deletion source/gameengine/Rasterizer/RAS_Mesh.h
Original file line number Diff line number Diff line change
Expand Up @@ -131,8 +131,8 @@ class RAS_Mesh
Mesh *m_mesh;

public:
// for now, meshes need to be in a certain layer (to avoid sorting on lights in realtime)
RAS_Mesh(Mesh *mesh, const LayersInfo& layersInfo);
RAS_Mesh(const RAS_Mesh& other);
virtual ~RAS_Mesh();

// materials
Expand Down
8 changes: 8 additions & 0 deletions source/gameengine/Rasterizer/RAS_MeshMaterial.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,14 @@ RAS_MeshMaterial::RAS_MeshMaterial(RAS_Mesh *mesh, RAS_MaterialBucket *bucket, u
m_displayArrayBucket = new RAS_DisplayArrayBucket(bucket, m_displayArray, mesh, this, nullptr);
}

RAS_MeshMaterial::RAS_MeshMaterial(const RAS_MeshMaterial& other, RAS_Mesh *mesh)
:m_bucket(other.m_bucket),
m_index(other.m_index)
{
m_displayArray = other.m_displayArray->GetReplica();
m_displayArrayBucket = new RAS_DisplayArrayBucket(m_bucket, m_displayArray, mesh, this, nullptr);
}

RAS_MeshMaterial::~RAS_MeshMaterial()
{
delete m_displayArrayBucket;
Expand Down
5 changes: 5 additions & 0 deletions source/gameengine/Rasterizer/RAS_MeshMaterial.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,13 @@ class RAS_MeshMaterial

public:
RAS_MeshMaterial(RAS_Mesh *mesh, RAS_MaterialBucket *bucket, unsigned int index, const RAS_VertexFormat& format);
/** Copy mesh material for a given mesh object.
* \param mesh Owner of copied mesh material.
*/
RAS_MeshMaterial(const RAS_MeshMaterial& other, RAS_Mesh *mesh);
~RAS_MeshMaterial();


unsigned int GetIndex() const;
RAS_MaterialBucket *GetBucket() const;
RAS_IDisplayArray *GetDisplayArray() const;
Expand Down

0 comments on commit 1df87c0

Please sign in to comment.