new game-menu option 'Record Game Physics to Ipo'

including implementation. hope it works, and doesn't break to much.
it bakes physics objects transform into ipo, every frame of the running gameengine.
When you disable and run the game again, it clears the ipo's again. just for physics objects at the moment.

(perhaps some better UI in the future?)
This commit is contained in:
Erwin Coumans 2005-08-23 13:16:02 +00:00
parent 0192536102
commit 056a33ac69
15 changed files with 328 additions and 28 deletions

@ -182,6 +182,7 @@ typedef struct Global {
#define G_FILE_SIGN (1 << 8)
#define G_FILE_PUBLISH (1 << 9)
#define G_FILE_NO_UI (1 << 10)
#define G_FILE_GAME_TO_IPO (1 << 11)
/* G.windowstate */
#define G_WINDOWSTATE_USERDEF 0

@ -55,6 +55,22 @@ void freeAllRad(void){}
void free_editText(void){}
void free_editArmature(void){}
char* getIpoCurveName( struct IpoCurve * icu )
{
return 0;
};
struct IpoCurve *get_ipocurve(struct ID *from, short type, int adrcode, struct Ipo *useipo)
{
return 0;
}
void insert_vert_ipo(struct IpoCurve *icu, float x, float y)
{
}
void setscreen(struct bScreen *sc){}
void force_draw_all(int header){}

@ -1262,6 +1262,7 @@ static void do_info_gamemenu(void *arg, int event)
case G_FILE_SHOW_FRAMERATE:
case G_FILE_SHOW_DEBUG_PROPS:
case G_FILE_AUTOPLAY:
case G_FILE_GAME_TO_IPO:
G.fileflags ^= event;
break;
default:
@ -1289,6 +1290,15 @@ static uiBlock *info_gamemenu(void *arg_unused)
} else {
uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_DEHLT, "Enable All Frames", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, G_FILE_ENABLE_ALL_FRAMES, "");
}
if(G.fileflags & G_FILE_GAME_TO_IPO) {
uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Record Game Physics to IPO", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, G_FILE_GAME_TO_IPO, "");
} else {
uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_DEHLT, "Record Game Physics to IPO", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, G_FILE_GAME_TO_IPO, "");
}
if(G.fileflags & G_FILE_SHOW_FRAMERATE) {
uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Show Framerate and Profile", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, G_FILE_SHOW_FRAMERATE, "");

@ -155,7 +155,8 @@
#include "SYS_System.h" /* for the user def menu ... should move elsewhere. */
extern void StartKetsjiShell(ScrArea *area, char* startscenename, struct Main* maggie, int always_use_expand_framing);
extern void StartKetsjiShell(ScrArea *area, char* startscenename, struct Main* maggie, struct SpaceIpo* sipo,int always_use_expand_framing);
/**
* When the mipmap setting changes, we want to redraw the view right
@ -358,6 +359,11 @@ void space_set_commmandline_options(void) {
a= (G.fileflags & G_FILE_ENABLE_ALL_FRAMES);
SYS_WriteCommandLineInt(syshandle, "fixedtime", a);
a= (G.fileflags & G_FILE_GAME_TO_IPO);
SYS_WriteCommandLineInt(syshandle, "game2ipo", a);
}
}
@ -399,7 +405,9 @@ static LinkNode *save_and_reset_all_scene_cfra(void)
for (sc= G.main->scene.first; sc; sc= sc->id.next) {
BLI_linklist_prepend(&storelist, (void*) (long) sc->r.cfra);
sc->r.cfra= 1;
//why is this reset to 1 ?
//sc->r.cfra= 1;
set_scene_bg(sc);
}
@ -472,7 +480,7 @@ void start_game(void)
space_set_commmandline_options();
SaveState();
StartKetsjiShell(curarea, startscene->id.name+2, G.main, 1);
StartKetsjiShell(curarea, startscene->id.name+2, G.main,G.sipo, 1);
RestoreState();
/* Restart BPY - unload the game engine modules. */

@ -91,10 +91,13 @@ static BlendFileData *load_game_data(char *filename) {
extern "C" void StartKetsjiShell(struct ScrArea *area,
char* scenename,
struct Main* maggie,
struct SpaceIpo *sipo,
int always_use_expand_framing)
{
int exitrequested = KX_EXIT_REQUEST_NO_REQUEST;
Main* blenderdata = maggie;
char* startscenename = scenename;
char pathname[160];
strcpy (pathname, maggie->name);
@ -113,7 +116,8 @@ extern "C" void StartKetsjiShell(struct ScrArea *area,
bool usefixed = (SYS_GetCommandLineInt(syshandle, "fixedtime", 0) != 0);
bool profile = (SYS_GetCommandLineInt(syshandle, "show_profile", 0) != 0);
bool frameRate = (SYS_GetCommandLineInt(syshandle, "show_framerate", 0) != 0);
bool game2ipo = (SYS_GetCommandLineInt(syshandle, "game2ipo", 0) != 0);
// create the canvas, rasterizer and rendertools
RAS_ICanvas* canvas = new KX_BlenderCanvas(area);
canvas->SetMouseState(RAS_ICanvas::MOUSE_INVISIBLE);
@ -159,7 +163,9 @@ extern "C" void StartKetsjiShell(struct ScrArea *area,
ketsjiengine->SetAudioDevice(audiodevice);
ketsjiengine->SetUseFixedTime(usefixed);
ketsjiengine->SetTimingDisplay(frameRate, profile, properties);
// some blender stuff
MT_CmMatrix4x4 projmat;
MT_CmMatrix4x4 viewmat;
@ -239,6 +245,13 @@ extern "C" void StartKetsjiShell(struct ScrArea *area,
blscene = bfd->curscene;
}
if (blscene)
{
int startFrame = blscene->r.cfra;
ketsjiengine->SetGame2IpoMode(game2ipo,startFrame);
}
// Quad buffered needs a special window.
if (blscene->r.stereomode != RAS_IRasterizer::RAS_STEREO_QUADBUFFERED)
rasterizer->SetStereoMode((RAS_IRasterizer::StereoMode) blscene->r.stereomode);
@ -254,7 +267,7 @@ extern "C" void StartKetsjiShell(struct ScrArea *area,
}
// create a scene converter, create and convert the startingscene
KX_ISceneConverter* sceneconverter = new KX_BlenderSceneConverter(blenderdata, ketsjiengine);
KX_ISceneConverter* sceneconverter = new KX_BlenderSceneConverter(maggie,sipo, ketsjiengine);
ketsjiengine->SetSceneConverter(sceneconverter);
if (always_use_expand_framing)

@ -1032,6 +1032,7 @@ void BL_ConvertBlenderObjects(struct Main* maggie,
bool alwaysUseExpandFraming
)
{
Scene *blenderscene = GetSceneForName(maggie, scenename);
// Get the frame settings of the canvas.

@ -77,16 +77,27 @@
#include "DNA_world_types.h"
#include "BKE_main.h"
extern "C"
{
#include "DNA_object_types.h"
#include "DNA_ipo_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)
{
@ -472,6 +483,68 @@ void KX_BlenderSceneConverter::RegisterWorldInfo(
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; i<G.sipo->totipo; 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 *get_ipocurve(struct ID *from, short type, int adrcode, struct Ipo *useipo);
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()
{
@ -498,18 +571,35 @@ void KX_BlenderSceneConverter::ResetPhysicsObjectsAnimationIpo()
if (blenderObject)
{
//erase existing ipo's
Ipo* ipo = blenderObject->ipo;
Ipo* ipo = findIpoForName(blenderObject->id.name+2);
if (ipo)
{
IpoCurve *icu;
//clear the curve data
IpoCurve *icu1;
int numCurves = 0;
for( icu = (IpoCurve*)ipo->curve.first; icu; icu = icu->next ) {
numCurves++;
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;
}
}
}
@ -522,9 +612,146 @@ void KX_BlenderSceneConverter::ResetPhysicsObjectsAnimationIpo()
}
///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;i<numScenes;i++)
{
KX_Scene* scene = scenes->at(i);
//PHY_IPhysicsEnvironment* physEnv = scene->GetPhysicsEnvironment();
CListValue* parentList = scene->GetRootParentList();
int numObjects = parentList->GetCount();
int g;
for (g=0;g<numObjects;g++)
{
KX_GameObject* gameObj = (KX_GameObject*)parentList->GetValue(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 = get_ipocurve( NULL, ipo->blocktype, OB_LOC_X, ipo );
icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"LocY");
if (!icu1)
icu1 = get_ipocurve( NULL, ipo->blocktype, OB_LOC_Y, ipo );
icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"LocZ");
if (!icu1)
icu1 = get_ipocurve( NULL, ipo->blocktype, OB_LOC_Z, ipo );
icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"RotX");
if (!icu1)
icu1 = get_ipocurve( NULL, ipo->blocktype, OB_ROT_X, ipo );
icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"RotY");
if (!icu1)
icu1 = get_ipocurve( NULL, ipo->blocktype, OB_ROT_Y, ipo );
icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"RotZ");
if (!icu1)
icu1 = get_ipocurve( NULL, ipo->blocktype, OB_ROT_Z, ipo );
//fill the curves with data
icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"LocX");
if (icu1)
{
float curVal = position.x();
insert_vert_ipo(icu1, frameNumber, curVal);
testhandles_ipocurve(icu1);
}
icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"LocY");
if (icu1)
{
float curVal = position.y();
insert_vert_ipo(icu1, frameNumber, curVal);
testhandles_ipocurve(icu1);
}
icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"LocZ");
if (icu1)
{
float curVal = position.z();
insert_vert_ipo(icu1, frameNumber, curVal);
testhandles_ipocurve(icu1);
}
icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"RotX");
if (icu1)
{
float curVal = eulerAngles[0];
insert_vert_ipo(icu1, frameNumber, curVal);
testhandles_ipocurve(icu1);
}
icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"RotY");
if (icu1)
{
float curVal = eulerAngles[1];
insert_vert_ipo(icu1, frameNumber, curVal);
testhandles_ipocurve(icu1);
}
icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"RotZ");
if (icu1)
{
float curVal = eulerAngles[2];
insert_vert_ipo(icu1, frameNumber, curVal);
testhandles_ipocurve(icu1);
}
}
}
}
}
}
//todo, before 2.38/2.40 release, Erwin
#ifdef TURN_THIS_PYTHON_CODE_INTO_CPP

@ -44,6 +44,9 @@ class SCA_IController;
class RAS_MeshObject;
class RAS_IPolyMaterial;
class BL_InterpolatorList;
struct IpoCurve;
struct Main;
struct SpaceIpo;
class KX_BlenderSceneConverter : public KX_ISceneConverter
{
@ -62,14 +65,20 @@ class KX_BlenderSceneConverter : public KX_ISceneConverter
GEN_Map<CHashedPtr,BL_InterpolatorList*> m_map_blender_to_gameipolist;
struct Main* m_maggie;
Main* m_maggie;
SpaceIpo* m_sipo;
STR_String m_newfilename;
class KX_KetsjiEngine* m_ketsjiEngine;
bool m_alwaysUseExpandFraming;
void localDel_ipoCurve ( IpoCurve * icu ,struct SpaceIpo* sipo);
struct Ipo* findIpoForName(char* objName);
public:
KX_BlenderSceneConverter(
struct Main* maggie,
Main* maggie,
SpaceIpo *sipo,
class KX_KetsjiEngine* engine
);

@ -185,7 +185,7 @@ bool GPC_Engine::StartKetsji(void)
m_portal = new KetsjiPortal(ketsjieng);
m_portal->setSecurity(psl_Highest);
KX_ISceneConverter *sceneconverter = new KX_BlenderSceneConverter(G.main, ketsjieng);
KX_ISceneConverter *sceneconverter = new KX_BlenderSceneConverter(&G, ketsjieng);
m_portal->Enter(
startSceneName,

@ -107,9 +107,9 @@ static void frameTimerProc(GHOST_ITimerTask* task, GHOST_TUns64 time);
static GHOST_ISystem* fSystem = 0;
static const int kTimerFreq = 10;
GPG_Application::GPG_Application(GHOST_ISystem* system, struct Main *maggie, STR_String startSceneName)
GPG_Application::GPG_Application(GHOST_ISystem* system, struct Main* maggie, STR_String startSceneName)
: m_startSceneName(startSceneName),
m_maggie(maggie),
m_maggie(maggie),
m_exitRequested(0),
m_system(system),
m_mainWindow(0),
@ -141,7 +141,7 @@ GPG_Application::~GPG_Application(void)
bool GPG_Application::SetGameEngineData(struct Main *maggie, STR_String startSceneName)
bool GPG_Application::SetGameEngineData(struct Main* maggie, STR_String startSceneName)
{
bool result = false;
@ -598,7 +598,7 @@ bool GPG_Application::startEngine(void)
*/
// create a scene converter, create and convert the stratingscene
m_sceneconverter = new KX_BlenderSceneConverter(m_maggie, m_ketsjiengine);
m_sceneconverter = new KX_BlenderSceneConverter(m_maggie,0, m_ketsjiengine);
if (m_sceneconverter)
{
STR_String startscenename = m_startSceneName.Ptr();

@ -57,10 +57,10 @@ struct Main;
class GPG_Application : public GHOST_IEventConsumer
{
public:
GPG_Application(GHOST_ISystem* system, struct Main *maggie, STR_String startSceneName);
GPG_Application(GHOST_ISystem* system, struct Main* maggie, STR_String startSceneName);
~GPG_Application(void);
bool SetGameEngineData(struct Main *maggie, STR_String startSceneName);
bool SetGameEngineData(struct Main* maggie,STR_String startSceneName);
bool startWindow(STR_String& title, int windowLeft, int windowTop, int windowWidth, int windowHeight,
const bool stereoVisual, const int stereoMode);
bool startFullScreen(int width, int height, int bpp, int frequency, const bool stereoVisual, const int stereoMode);

@ -866,7 +866,7 @@ void KX_ConvertBulletObject( class KX_GameObject* gameobj,
assert(env);
bool dyna = false;
bool isbulletdyna = false;
CcdConstructionInfo ci;
class PHY_IMotionState* motionstate = new KX_MotionState(gameobj->GetSGNode());
@ -874,7 +874,8 @@ void KX_ConvertBulletObject( class KX_GameObject* gameobj,
ci.m_gravity = SimdVector3(0,0,0);
ci.m_localInertiaTensor =SimdVector3(0,0,0);
ci.m_mass = objprop->m_dyna ? shapeprops->m_mass : 0.f;
isbulletdyna = objprop->m_dyna;
ci.m_localInertiaTensor = SimdVector3(ci.m_mass/3.f,ci.m_mass/3.f,ci.m_mass/3.f);
SimdTransform trans;
@ -1008,11 +1009,11 @@ void KX_ConvertBulletObject( class KX_GameObject* gameobj,
//need a bit of damping, else system doesn't behave well
KX_BulletPhysicsController* physicscontroller = new KX_BulletPhysicsController(ci,dyna);
KX_BulletPhysicsController* physicscontroller = new KX_BulletPhysicsController(ci,isbulletdyna);
env->addCcdPhysicsController( physicscontroller);
gameobj->SetPhysicsController(physicscontroller,dyna);
gameobj->SetPhysicsController(physicscontroller,isbulletdyna);
physicscontroller->setNewClientInfo(gameobj->getClientInfo());
bool isActor = objprop->m_isactor;
gameobj->getClientInfo()->m_type = (isActor ? KX_ClientObjectInfo::ACTOR : KX_ClientObjectInfo::STATIC);

@ -120,6 +120,7 @@ KX_KetsjiEngine::KX_KetsjiEngine(KX_ISystem* system)
m_bInitialized(false),
m_activecam(0),
m_bFixedTime(false),
m_game2ipo(false),
m_firstframe(true),
@ -397,7 +398,10 @@ void KX_KetsjiEngine::NextFrame()
scene->GetPhysicsEnvironment()->proceedDeltaTime(localtime,realDeltaTime);
m_previoustime = curtime;
m_sceneconverter->WritePhysicsObjectToAnimationIpo(m_currentFrame++);
if (m_game2ipo)
{
m_sceneconverter->WritePhysicsObjectToAnimationIpo(m_currentFrame++);
}
} // suspended
@ -1197,6 +1201,11 @@ void KX_KetsjiEngine::SetUseFixedTime(bool bUseFixedTime)
}
void KX_KetsjiEngine::SetGame2IpoMode(bool game2ipo,int startFrame)
{
m_game2ipo = game2ipo;
m_currentFrame = startFrame;
}
bool KX_KetsjiEngine::GetUseFixedTime(void) const
{

@ -155,6 +155,9 @@ private:
bool m_show_debug_properties;
/** record physics into keyframes */
bool m_game2ipo;
/** Hide cursor every frame? */
bool m_hideCursor;
@ -189,6 +192,8 @@ public:
void SetRasterizer(RAS_IRasterizer* rasterizer);
void SetPythonDictionary(PyObject* pythondictionary);
void SetSceneConverter(KX_ISceneConverter* sceneconverter);
void SetGame2IpoMode(bool game2ipo,int startFrame);
void NextFrame();
void Render();

@ -107,7 +107,7 @@ MT_Matrix3x3 EulToMat3(float *eul)
/* old function from Blender */
void Mat3ToEul(MT_Matrix3x3 mat, float *eul)
void Mat3ToEulOld(MT_Matrix3x3 mat, float *eul)
{
MT_Scalar cy;
@ -154,8 +154,8 @@ MT_Matrix3x3 matrix3x3_interpol(MT_Matrix3x3 oldmat, MT_Matrix3x3 mat, int m_tim
{
float eul[3], oldeul[3];
Mat3ToEul(oldmat, oldeul);
Mat3ToEul(mat, eul);
Mat3ToEulOld(oldmat, oldeul);
Mat3ToEulOld(mat, eul);
compatible_eulFast(eul, oldeul);
eul[0]= (m_time*oldeul[0] + eul[0])/(1.0+m_time);