/** * $Id$ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. The Blender * Foundation also sells licenses for use in proprietary software under * the Blender License. See http://www.blender.org/BL/ for information * about this. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. * All rights reserved. * * The Original Code is: all of this file. * * Contributor(s): none yet. * * ***** END GPL/BL DUAL LICENSE BLOCK ***** */ #ifdef WIN32 #pragma warning (disable:4786) // suppress stl-MSVC debug info warning #endif #include "KX_Scene.h" #include "KX_GameObject.h" #include "KX_BlenderSceneConverter.h" #include "KX_IpoConvert.h" #include "RAS_MeshObject.h" #include "KX_PhysicsEngineEnums.h" #include "PHY_IPhysicsEnvironment.h" #include "KX_KetsjiEngine.h" #include "KX_IPhysicsController.h" #include "BL_Material.h" #include "DummyPhysicsEnvironment.h" //to decide to use sumo/ode or dummy physics - defines USE_ODE #include "KX_ConvertPhysicsObject.h" #ifdef USE_BULLET #include "CcdPhysicsEnvironment.h" #endif #ifdef USE_ODE #include "OdePhysicsEnvironment.h" #endif //USE_ODE #ifdef USE_SUMO_SOLID #include "SumoPhysicsEnvironment.h" #endif #include "KX_BlenderSceneConverter.h" #include "KX_BlenderScalarInterpolator.h" #include "BL_BlenderDataConversion.h" #include "BlenderWorldInfo.h" #include "KX_Scene.h" /* This little block needed for linking to Blender... */ #ifdef WIN32 #include "BLI_winstuff.h" #endif /* This list includes only data type definitions */ #include "DNA_scene_types.h" #include "DNA_world_types.h" #include "BKE_main.h" extern "C" { #include "DNA_object_types.h" #include "DNA_curve_types.h" #include "BLI_blenlib.h" #include "MEM_guardedalloc.h" #include "BSE_editipo.h" #include "BSE_editipo_types.h" #include "DNA_ipo_types.h" #include "BKE_global.h" #include "DNA_space_types.h" } KX_BlenderSceneConverter::KX_BlenderSceneConverter( struct Main* maggie, struct SpaceIpo* sipo, class KX_KetsjiEngine* engine ) : m_maggie(maggie), m_sipo(sipo), m_ketsjiEngine(engine), m_alwaysUseExpandFraming(false), m_usemat(false) { m_newfilename = ""; } KX_BlenderSceneConverter::~KX_BlenderSceneConverter() { // clears meshes, and hashmaps from blender to gameengine data int i; // delete sumoshapes int numipolists = m_map_blender_to_gameipolist.size(); for (i=0; i::iterator itw = m_worldinfos.begin(); while (itw != m_worldinfos.end()) { delete (*itw); itw++; } vector::iterator itp = m_polymaterials.begin(); while (itp != m_polymaterials.end()) { delete (*itp); itp++; } // delete after RAS_IPolyMaterial vector::iterator itmat = m_materials.begin(); while (itmat != m_materials.end()) { delete (*itmat); itmat++; } vector::iterator itm = m_meshobjects.begin(); while (itm != m_meshobjects.end()) { delete (*itm); itm++; } #ifdef USE_SUMO_SOLID KX_ClearSumoSharedShapes(); #endif #ifdef USE_BULLET KX_ClearBulletSharedShapes(); #endif } void KX_BlenderSceneConverter::SetNewFileName(const STR_String& filename) { m_newfilename = filename; } bool KX_BlenderSceneConverter::TryAndLoadNewFile() { bool result = false; // find the file /* if () { result = true; } // if not, clear the newfilename else { m_newfilename = ""; } */ return result; } /** * Find the specified scene by name, or the first * scene if nothing matches (shouldn't happen). */ static struct Scene *GetSceneForName2(struct Main *maggie, const STR_String& scenename) { Scene *sce; for (sce= (Scene*) maggie->scene.first; sce; sce= (Scene*) sce->id.next) if (scenename == (sce->id.name+2)) return sce; return (Scene*) maggie->scene.first; } #include "KX_PythonInit.h" #ifdef USE_BULLET #include "IDebugDraw.h" struct BlenderDebugDraw : public IDebugDraw { BlenderDebugDraw () : m_debugMode(0) { } int m_debugMode; virtual void DrawLine(const SimdVector3& from,const SimdVector3& to,const SimdVector3& color) { if (m_debugMode >0) { MT_Vector3 kxfrom(from[0],from[1],from[2]); MT_Vector3 kxto(to[0],to[1],to[2]); MT_Vector3 kxcolor(color[0],color[1],color[2]); KX_RasterizerDrawDebugLine(kxfrom,kxto,kxcolor); } } virtual void DrawContactPoint(const SimdVector3& PointOnB,const SimdVector3& normalOnB,float distance,int lifeTime,const SimdVector3& color) { //not yet } virtual void SetDebugMode(int debugMode) { m_debugMode = debugMode; } virtual int GetDebugMode() const { return m_debugMode; } }; #endif void KX_BlenderSceneConverter::ConvertScene(const STR_String& scenename, class KX_Scene* destinationscene, PyObject* dictobj, class SCA_IInputDevice* keyinputdev, class RAS_IRenderTools* rendertools, class RAS_ICanvas* canvas) { //find out which physics engine Scene *blenderscene = GetSceneForName2(m_maggie, scenename); e_PhysicsEngine physics_engine = UseBullet; if (blenderscene) { if (blenderscene->world) { switch (blenderscene->world->physicsEngine) { case WOPHY_BULLET: { physics_engine = UseBullet; break; } case WOPHY_ODE: { physics_engine = UseODE; break; } case WOPHY_DYNAMO: { physics_engine = UseDynamo; break; } case WOPHY_SUMO: { physics_engine = UseSumo; break; } case WOPHY_NONE: { physics_engine = UseNone; } } } } switch (physics_engine) { #ifdef USE_BULLET case UseBullet: { CcdPhysicsEnvironment* ccdPhysEnv = new CcdPhysicsEnvironment(); ccdPhysEnv->setDebugDrawer(new BlenderDebugDraw()); ccdPhysEnv->setDeactivationLinearTreshold(0.8f); // default, can be overridden by Python ccdPhysEnv->setDeactivationAngularTreshold(1.0f); // default, can be overridden by Python //todo: get a button in blender ? //disable / enable debug drawing (contact points, aabb's etc) //ccdPhysEnv->setDebugMode(1); destinationscene->SetPhysicsEnvironment(ccdPhysEnv); break; } #endif #ifdef USE_SUMO_SOLID case UseSumo: destinationscene ->SetPhysicsEnvironment(new SumoPhysicsEnvironment()); break; #endif #ifdef USE_ODE case UseODE: destinationscene ->SetPhysicsEnvironment(new ODEPhysicsEnvironment()); break; #endif //USE_ODE case UseDynamo: { } default: case UseNone: physics_engine = UseNone; destinationscene ->SetPhysicsEnvironment(new DummyPhysicsEnvironment()); break; } BL_ConvertBlenderObjects(m_maggie, scenename, destinationscene, m_ketsjiEngine, physics_engine, dictobj, keyinputdev, rendertools, canvas, this, m_alwaysUseExpandFraming ); m_map_blender_to_gameactuator.clear(); m_map_blender_to_gamecontroller.clear(); m_map_blender_to_gameobject.clear(); m_map_mesh_to_gamemesh.clear(); //don't clear it yet, it is needed for the baking physics into ipo animation //m_map_gameobject_to_blender.clear(); } // use blender materials void KX_BlenderSceneConverter::SetMaterials(bool val) { m_usemat = val; } bool KX_BlenderSceneConverter::GetMaterials() { return m_usemat; } void KX_BlenderSceneConverter::RegisterBlenderMaterial(BL_Material *mat) { m_materials.push_back(mat); } void KX_BlenderSceneConverter::SetAlwaysUseExpandFraming( bool to_what) { m_alwaysUseExpandFraming= to_what; } void KX_BlenderSceneConverter::RegisterGameObject( KX_GameObject *gameobject, struct Object *for_blenderobject) { m_map_gameobject_to_blender.insert(CHashedPtr(gameobject),for_blenderobject); m_map_blender_to_gameobject.insert(CHashedPtr(for_blenderobject),gameobject); } KX_GameObject *KX_BlenderSceneConverter::FindGameObject( struct Object *for_blenderobject) { KX_GameObject **obp= m_map_blender_to_gameobject[CHashedPtr(for_blenderobject)]; return obp?*obp:NULL; } struct Object *KX_BlenderSceneConverter::FindBlenderObject( KX_GameObject *for_gameobject) { struct Object **obp= m_map_gameobject_to_blender[CHashedPtr(for_gameobject)]; return obp?*obp:NULL; } void KX_BlenderSceneConverter::RegisterGameMesh( RAS_MeshObject *gamemesh, struct Mesh *for_blendermesh) { m_map_mesh_to_gamemesh.insert(CHashedPtr(for_blendermesh),gamemesh); m_meshobjects.push_back(gamemesh); } RAS_MeshObject *KX_BlenderSceneConverter::FindGameMesh( struct Mesh *for_blendermesh, unsigned int onlayer) { RAS_MeshObject** meshp = m_map_mesh_to_gamemesh[CHashedPtr(for_blendermesh)]; if (meshp && onlayer==(*meshp)->GetLightLayer()) { return *meshp; } else { return NULL; } } void KX_BlenderSceneConverter::RegisterPolyMaterial(RAS_IPolyMaterial *polymat) { m_polymaterials.push_back(polymat); } void KX_BlenderSceneConverter::RegisterInterpolatorList( BL_InterpolatorList *ipoList, struct Ipo *for_ipo) { m_map_blender_to_gameipolist.insert(CHashedPtr(for_ipo), ipoList); } BL_InterpolatorList *KX_BlenderSceneConverter::FindInterpolatorList( struct Ipo *for_ipo) { BL_InterpolatorList **listp = m_map_blender_to_gameipolist[CHashedPtr(for_ipo)]; return listp?*listp:NULL; } void KX_BlenderSceneConverter::RegisterGameActuator( SCA_IActuator *act, struct bActuator *for_actuator) { m_map_blender_to_gameactuator.insert(CHashedPtr(for_actuator), act); } SCA_IActuator *KX_BlenderSceneConverter::FindGameActuator( struct bActuator *for_actuator) { SCA_IActuator **actp = m_map_blender_to_gameactuator[CHashedPtr(for_actuator)]; return actp?*actp:NULL; } void KX_BlenderSceneConverter::RegisterGameController( SCA_IController *cont, struct bController *for_controller) { m_map_blender_to_gamecontroller.insert(CHashedPtr(for_controller), cont); } SCA_IController *KX_BlenderSceneConverter::FindGameController( struct bController *for_controller) { SCA_IController **contp = m_map_blender_to_gamecontroller[CHashedPtr(for_controller)]; return contp?*contp:NULL; } void KX_BlenderSceneConverter::RegisterWorldInfo( KX_WorldInfo *worldinfo) { m_worldinfos.push_back(worldinfo); } /* * When deleting an IPO curve from Python, check if the IPO is being * edited and if so clear the pointer to the old curve. */ void KX_BlenderSceneConverter::localDel_ipoCurve ( IpoCurve * icu ,struct SpaceIpo* sipo) { if (!sipo) return; int i; EditIpo *ei= (EditIpo *)sipo->editipo; if (!ei) return; for(i=0; itotipo; i++, ei++) { if ( ei->icu == icu ) { ei->flag &= ~(IPO_SELECT | IPO_EDIT); ei->icu= 0; return; } } } //quick hack extern "C" { Ipo *add_ipo( char *name, int idcode ); char *getIpoCurveName( IpoCurve * icu ); struct IpoCurve *verify_ipocurve(struct ID *, short, char *, char *, int); void testhandles_ipocurve(struct IpoCurve *icu); void Mat3ToEul(float tmat[][3], float *eul); } IpoCurve* findIpoCurve(IpoCurve* first,char* searchName) { IpoCurve* icu1; for( icu1 = first; icu1; icu1 = icu1->next ) { char* curveName = getIpoCurveName( icu1 ); if( !strcmp( curveName, searchName) ) { return icu1; } } return 0; } Ipo* KX_BlenderSceneConverter::findIpoForName(char* objName) { Ipo* ipo_iter = (Ipo*)m_maggie->ipo.first; while( ipo_iter ) { if( strcmp( objName, ipo_iter->id.name + 2 ) == 0 ) { return ipo_iter; } ipo_iter = (Ipo*)ipo_iter->id.next; } return 0; } void KX_BlenderSceneConverter::ResetPhysicsObjectsAnimationIpo() { KX_SceneList* scenes = m_ketsjiEngine->CurrentScenes(); int numScenes = scenes->size(); int i; for (i=0;iat(i); //PHY_IPhysicsEnvironment* physEnv = scene->GetPhysicsEnvironment(); CListValue* parentList = scene->GetRootParentList(); int numObjects = parentList->GetCount(); int g; for (g=0;gGetValue(g); if (gameObj->IsDynamic()) { //KX_IPhysicsController* physCtrl = gameObj->GetPhysicsController(); Object* blenderObject = FindBlenderObject(gameObj); if (blenderObject) { //erase existing ipo's Ipo* ipo = findIpoForName(blenderObject->id.name+2); if (ipo) { //clear the curve data IpoCurve *icu1; int numCurves = 0; for( icu1 = (IpoCurve*)ipo->curve.first; icu1; ) { IpoCurve* tmpicu = icu1; icu1 = icu1->next; numCurves++; BLI_remlink( &( blenderObject->ipo->curve ), tmpicu ); if( tmpicu->bezt ) MEM_freeN( tmpicu->bezt ); MEM_freeN( tmpicu ); localDel_ipoCurve( tmpicu ,m_sipo); } } else { ipo = add_ipo(blenderObject->id.name+2, ID_OB); blenderObject->ipo = ipo; } } } } } } #define TEST_HANDLES_GAME2IPO 0 ///this generates ipo curves for position, rotation, allowing to use game physics in animation void KX_BlenderSceneConverter::WritePhysicsObjectToAnimationIpo(int frameNumber) { KX_SceneList* scenes = m_ketsjiEngine->CurrentScenes(); int numScenes = scenes->size(); int i; for (i=0;iat(i); //PHY_IPhysicsEnvironment* physEnv = scene->GetPhysicsEnvironment(); CListValue* parentList = scene->GetRootParentList(); int numObjects = parentList->GetCount(); int g; for (g=0;gGetValue(g); if (gameObj->IsDynamic()) { KX_IPhysicsController* physCtrl = gameObj->GetPhysicsController(); Object* blenderObject = FindBlenderObject(gameObj); if (blenderObject) { const MT_Matrix3x3& orn = gameObj->NodeGetWorldOrientation(); float eulerAngles[3]; float tmat[3][3]; for (int r=0;r<3;r++) { for (int c=0;c<3;c++) { tmat[r][c] = orn[c][r]; } } Mat3ToEul(tmat, eulerAngles); for(int x = 0; x < 3; x++) { eulerAngles[x] *= (float) (180 / 3.14159265f); } eulerAngles[0]/=10.f; eulerAngles[1]/=10.f; eulerAngles[2]/=10.f; const MT_Vector3& scale = gameObj->NodeGetWorldScaling(); const MT_Point3& position = gameObj->NodeGetWorldPosition(); Ipo* ipo = blenderObject->ipo; if (ipo) { //create the curves, if not existing IpoCurve *icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"LocX"); if (!icu1) icu1 = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, OB_LOC_X); icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"LocY"); if (!icu1) icu1 = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, OB_LOC_Y); icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"LocZ"); if (!icu1) icu1 = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, OB_LOC_Z); icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"RotX"); if (!icu1) icu1 = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, OB_ROT_X); icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"RotY"); if (!icu1) icu1 = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, OB_ROT_Y); icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"RotZ"); if (!icu1) icu1 = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, OB_ROT_Z); //fill the curves with data icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"LocX"); if (icu1) { float curVal = position.x(); insert_vert_ipo(icu1, frameNumber, curVal); #ifdef TEST_HANDLES_GAME2IPO testhandles_ipocurve(icu1); #endif } icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"LocY"); if (icu1) { float curVal = position.y(); insert_vert_ipo(icu1, frameNumber, curVal); #ifdef TEST_HANDLES_GAME2IPO testhandles_ipocurve(icu1); #endif } icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"LocZ"); if (icu1) { float curVal = position.z(); insert_vert_ipo(icu1, frameNumber, curVal); #ifdef TEST_HANDLES_GAME2IPO testhandles_ipocurve(icu1); #endif } icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"RotX"); if (icu1) { float curVal = eulerAngles[0]; insert_vert_ipo(icu1, frameNumber, curVal); #ifdef TEST_HANDLES_GAME2IPO testhandles_ipocurve(icu1); #endif } icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"RotY"); if (icu1) { float curVal = eulerAngles[1]; insert_vert_ipo(icu1, frameNumber, curVal); #ifdef TEST_HANDLES_GAME2IPO testhandles_ipocurve(icu1); #endif } icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"RotZ"); if (icu1) { float curVal = eulerAngles[2]; insert_vert_ipo(icu1, frameNumber, curVal); #ifdef TEST_HANDLES_GAME2IPO testhandles_ipocurve(icu1); #endif } } } } } } } void KX_BlenderSceneConverter::TestHandlesPhysicsObjectToAnimationIpo() { KX_SceneList* scenes = m_ketsjiEngine->CurrentScenes(); int numScenes = scenes->size(); int i; for (i=0;iat(i); //PHY_IPhysicsEnvironment* physEnv = scene->GetPhysicsEnvironment(); CListValue* parentList = scene->GetRootParentList(); int numObjects = parentList->GetCount(); int g; for (g=0;gGetValue(g); if (gameObj->IsDynamic()) { KX_IPhysicsController* physCtrl = gameObj->GetPhysicsController(); Object* blenderObject = FindBlenderObject(gameObj); if (blenderObject) { const MT_Matrix3x3& orn = gameObj->NodeGetWorldOrientation(); float eulerAngles[3]; float tmat[3][3]; for (int r=0;r<3;r++) { for (int c=0;c<3;c++) { tmat[r][c] = orn[c][r]; } } Mat3ToEul(tmat, eulerAngles); for(int x = 0; x < 3; x++) { eulerAngles[x] *= (float) (180 / 3.14159265f); } eulerAngles[0]/=10.f; eulerAngles[1]/=10.f; eulerAngles[2]/=10.f; const MT_Vector3& scale = gameObj->NodeGetWorldScaling(); const MT_Point3& position = gameObj->NodeGetWorldPosition(); Ipo* ipo = blenderObject->ipo; if (ipo) { //create the curves, if not existing IpoCurve *icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"LocX"); if (!icu1) icu1 = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, OB_LOC_X); icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"LocY"); if (!icu1) icu1 = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, OB_LOC_Y); icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"LocZ"); if (!icu1) icu1 = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, OB_LOC_Z); icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"RotX"); if (!icu1) icu1 = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, OB_ROT_X); icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"RotY"); if (!icu1) icu1 = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, OB_ROT_Y); icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"RotZ"); if (!icu1) icu1 = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, OB_ROT_Z); //fill the curves with data icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"LocX"); if (icu1) { testhandles_ipocurve(icu1); } icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"LocY"); if (icu1) { testhandles_ipocurve(icu1); } icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"LocZ"); if (icu1) { testhandles_ipocurve(icu1); } icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"RotX"); if (icu1) { testhandles_ipocurve(icu1); } icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"RotY"); if (icu1) { testhandles_ipocurve(icu1); } icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"RotZ"); if (icu1) { testhandles_ipocurve(icu1); } } } } } } }