/** ******************************************************************************* @file /gui/engine/Controllers.cpp @brief Zaklad animacniho enginu, zakladni kontrolery @author Vajicek @version 0.1 ******************************************************************************/ #include "gui/engine/Controllers.h" // #include "gui/common/mymath.h" #include "gui/common/KTime.h" #include "common/Log.h" using namespace std; namespace gui { #ifdef _DEBUG static TLog controllers(1); #endif #define CLOG //controllers.LogMsg //----------------------------------------------------------------------------- /* updatuje potomky hierarchie kontroleru */ void TController::updateTree(int absoluteTime){ iActiveChilds = 0; // for(int i = 0; i < childs_c; i++){ childs[i]->updateTree(absoluteTime); iActiveChilds += childs[i]->iActiveChilds + childs[i]->iActived; } // if(iActived && !iDisposed) update(absoluteTime); //odstrani se smazane int j = 0; while( j < childs_c ) { if(childs[j]->iDisposed){ delete childs[j]; childs[j] = childs[--childs_c]; } else { j++; } }//while } void TController::update(int absoluteTime){ } void TController::RTTID(char* ident){ strncpy(szIdent, ident, 10); } void TController::dispose(){ iDisposed = 1; } void TController::printSubtree(int level, FILE* f){ // for(int i = 0; i < level; i++)fprintf(f,"\t"); fprintf(f,szIdent); fprintf(f,"\n"); // for(int j = 0; j < childs_c; j++) if(childs[j]) childs[j]->printSubtree(level+1,f); } /* aktivuje celou podhierarchii */ void TController::activate(int absoluteTime, int recursive){ iActivationTime = absoluteTime; iLastTime = absoluteTime; iActived = 1; // if(recursive){ for(int i = 0; i < childs_c; i++){ if(childs[i]) childs[i]->activate(absoluteTime); } } } /* deaktivuj podhierarchii */ void TController::deactivate(int recursive){ iActived = 0; if(recursive){ for(int i = 0; i < childs_c; i++){ if(childs[i]) childs[i]->deactivate(); } } } void TController::setTimeRatio(float tr, int recursive){ fTimeRatio = tr; if(recursive) for(int i = 0; i < childs_c; i++){ if(childs[i]) childs[i]->setTimeRatio(tr,1); } } void TController::changeSpeedBy(float tr, int recursive){ setTimeRatio(fTimeRatio + tr, 0); if(recursive) for(int i = 0; i < childs_c; i++){ if(childs[i]) childs[i]->changeSpeedBy(tr,1); } } void TController::addChildControler(TController* con) { // childs = (TController**)KExtArrayRealloc( childs, sizeof(TController*), childs_c + 1, childs_c); childs[childs_c] = con; childs_c++; // con->parent_controller = this; } void TController::removeChildControler(TController* ctrl) { for(int i = 0; i < childs_c; i++){ if(childs[i] == ctrl){ CLOG("Removing: %p from %p\n", ctrl, this); childs[i]->dispose(); break; } } } TController::TController(){ parent_controller = NULL; childs = NULL; childs_c = 0; data = NULL; iActived = 0; fTimeRatio = 1; iActiveChilds = 0; iLastTime = 0; RTTID("unknown"); iDisposed = 0; //statistika TController::iControllers++; } TController::~TController(){ CLOG("Disposing: %p(%s)\n", this, szIdent); //smazu dovnou vsechny potomky, jsem si jist, ze nejsem uvnitr for(int i = 0; i < childs_c; i++){ if(childs[i]) delete childs[i]; } // if(childs){ KMemFree(childs); childs=NULL; } //statistika TController::iControllers--; } int TController::iControllers = 0; //----------------------------------------------------------------------------- void TTRSController::InterpolateRotation(QUATER* q1, QUATER* q2, float t){ QUATER qt; SLERP(q1, q2, t, &qt); QTOAA(&qt , &(rot->ax) , &(rot->ang) ); rot->ang = (float)Rad2Deg(rot->ang); } void TTRSController::InterpolateTranslation(P3F* pos1, P3F* pos2, float t) { pos->x = ( 1 - t ) * pos1->x + t * pos2->x; pos->y = ( 1 - t ) * pos1->y + t * pos2->y; pos->z = ( 1 - t ) * pos1->z + t * pos2->z; } void TTRSController::setParametr(P3F* pos, AXISANG* rot){ this->pos = pos; this->rot = rot; } TTRSController::TTRSController() :TController() { RTTID("trs_ctrl"); } //----------------------------------------------------------------------------- void TNodeAnimationController::setData(TAnimTable* at, int tr_chid, int rot_chid) { data = (void*)at; rot_i = rot_chid; tr_i = tr_chid; } void TNodeAnimationController::update(int absoluteTime){ //najdi v tabulce odpovidajici hodnotu, nastav pos, rot PAnimTable at = (PAnimTable)data; // int rtime = (int)((absoluteTime - iActivationTime)*fTimeRatio); //if(rtime<0)return;//jiny reseni je out-bound values // if(rot_i >= 0){ TTrack* tr = at->Tracks + rot_i; // int frame = (int)floor( double(rtime) /tr->KPS); while( frameKeys_l && tr->Stamps[frame]=0 && tr->Stamps[frame]>rtime )frame--; // float t; if( frame >= 0 && frame < (tr->Keys_l-1) ) t = float( rtime - tr->Stamps[frame] ) / (tr->Stamps[frame+1] - tr->Stamps[frame]); // if(frame >= tr->Keys_l) deactivate(0); //out-of-range hodnoty if(frame >= tr->Keys_l-1){ t=1; frame = tr->Keys_l-2; } if(frame < 0){ t=0; frame = 0; } InterpolateRotation( &(tr->Keys[frame].rot_val), &(tr->Keys[frame+1].rot_val), t ); } if(tr_i >= 0){ TTrack* tr = at->Tracks + tr_i; // int frame = (int)floor( double(rtime) /tr->KPS); while( frameKeys_l && tr->Stamps[frame]=0 && tr->Stamps[frame]>rtime )frame--; // float t; if( frame >= 0 && frame < (tr->Keys_l-1) ) t = float( rtime - tr->Stamps[frame] ) / (tr->Stamps[frame+1] - tr->Stamps[frame]); // if(frame >= tr->Keys_l) deactivate(0); if(frame >= tr->Keys_l-1){ t=1; frame = tr->Keys_l-2; } if(frame < 0){ t=0; frame = 0; } InterpolateTranslation( &(tr->Keys[frame].pos_val), &(tr->Keys[frame+1].pos_val), t ); } } TNodeAnimationController::TNodeAnimationController() :TTRSController() { RTTID("nodeanim"); } //----------------------------------------------------------------------------- void TModelAnimationController::play(int at){ CLOG("TModelAnimationController::play\n"); iLoop = 0; activate(at); } void TModelAnimationController::playLoop(int at){ CLOG("TModelAnimationController::playLoop\n"); iLoop = 1; activate(at); } void TModelAnimationController::stopLoop(){ iLoop = 0; } void TModelAnimationController::update(int absoluteTime){ if(iActiveChilds == 0){ if(iLoop){ CLOG("update: start new loop\n"); activate(absoluteTime); } else{ CLOG("update: deactivate\n"); deactivate(0); } } } void TModelAnimationController::stop(){ deactivate(); } int TModelAnimationController::getLength(){ return ((PAnimTable)data)->iAnimLen; } float TModelAnimationController::getRelativePosition(int time){ return ((float)time-iActivationTime)/((PAnimTable)data)->iAnimLen; } TModelAnimationController::TModelAnimationController(int id, PAnimTable at) :TController() { RTTID("modanim_c"); iID = id; iLoop = 0; data = at; } //----------------------------------------------------------------------------- void TPuppetController::update(int absoluteTime){ } void TPuppetController::addAnimation(TModelAnimationController* c, int id){ addChildControler(c); } int TPuppetController::playAnimation(int id, int flag){ return playAnimation(id, flag, KTime()); } int TPuppetController::playAnimation(int id, int flag, int acttime){ CLOG("playAnimation\n"); for(int i = 0; i < childs_c; i++) { TModelAnimationController* mac = ((TModelAnimationController*)childs[i]); if( mac->iID == id){ if(flag & PC_LOOP) mac->playLoop(acttime); else mac->play(acttime); activate(acttime, 0); return mac->getLength(); }//if iID == id }//for CLOG("animation id = %d not loaded\n", id); return -1; } void TPuppetController::stopAnimation(int id, int flag){ CLOG("stopAnimation\n"); // for(int i = 0; i < childs_c; i++) { if( ((TModelAnimationController*)childs[i])->iID == id){ if(flag & PC_IMMEDIATE_STOP){ ((TModelAnimationController*)childs[i])->stop(); deactivate(0); } else if(flag & PC_STOP_LOOPING){ ((TModelAnimationController*)childs[i])->stopLoop(); } return; }//if iID == id }//for CLOG("animation id = %d not loaded\n",id); } void TPuppetController::stopAllAnimations(int flag){ for(int i = 0; i < childs_c; i++) { if( ((TModelAnimationController*)childs[i])->iActived ){ stopAnimation(((TModelAnimationController*)childs[i])->iID, flag); }//if iActived }//for } void TPuppetController::buildHierarchy(PMeshNode mod_mn, PMeshNode inst_mn, TController *parent, PAnimTable at) { TNodeAnimationController *nac; int rot_i, tr_i; //nastavit data nodu tr_i = GetTrack(at, PID(mod_mn)); rot_i = GetTrack(at, PID(mod_mn)+1); if(tr_i != -1 || rot_i != -1){ nac = new TNodeAnimationController(); nac->setData( at, tr_i, rot_i); nac->setParametr( &(inst_mn->translate), &(inst_mn->rotate) ); parent->addChildControler(nac); parent = nac; } //kontrolery pro vsechny potomky for( int i = 0; i < mod_mn->childs_c ; i++){ buildHierarchy(mod_mn->childs[i], inst_mn->childs[i], parent, at); } } void TPuppetController::initControler(TModelInstance *inst){ data = (void*)inst; PAnimTable at; int at_i = 0; TModelAnimationController *ac; // while(1){ at = ACache_GetTable( PID(inst->model_class) + at_i ); if(!at)break; //kompletni animace ac = new TModelAnimationController(at_i, at); addAnimation(ac, at_i); //projdi hierarchii for( int i = 0; i < inst->model_class->hierarchy_c; i++){ // buildHierarchy(inst->model_class->hierarchy[i], inst->hierarchy[i], ac, at); } at_i++; } } TPuppetController::TPuppetController(TModelInstance *inst) :TController() { RTTID("puppet_c"); initControler(inst); } //----------------------------------------------------------------------------- void TSceneObjectManipulator::setData(Uint8 **k, TModelSceneObject *mod){ keys = k; data = (void*)mod; } void TSceneObjectManipulator::update(int absoluteTime){ TModelSceneObject* mod = (TModelSceneObject*)data; if( (*keys) && ((absoluteTime - iActivationTime) > 30) ){ if((*keys)[SDLK_n]) mod->rotateBy(0,-0.01f,0); if((*keys)[SDLK_m]) mod->rotateBy(0,0.01f,0); if((*keys)[SDLK_y]) mod->moveBy(0,0,0.1f); if((*keys)[SDLK_b]) mod->moveBy(0,0,-0.1f); if((*keys)[SDLK_u]) mod->moveBy(0,0.1f,0); if((*keys)[SDLK_j]) mod->moveBy(0,-0.1f,0); if((*keys)[SDLK_k]) mod->rotateBy(0,0,-0.01f); if((*keys)[SDLK_h]) mod->rotateBy(0,0,0.01f); absoluteTime = iActivationTime; } } TSceneObjectManipulator::TSceneObjectManipulator(Uint8 **k, TModelSceneObject *mod) :TController() { setData(k, mod); } //----------------------------------------------------------------------------- void TControllerManager::setSpeed(int sf){ iSpeed = sf; setTimeRatio((float)sf, true); } int TControllerManager::getSpeed(){ return iSpeed; } void TControllerManager::addController(TController* con) { addChildControler(con); } void TControllerManager::removeController(TController* con){ removeChildControler(con); } void TControllerManager::updateControlers(int absTime) { updateTree(absTime); } TControllerManager::TControllerManager() :TController() { RTTID("CTRL_MNG"); activate(0,0); iSpeed = 0; } void TControllerManager::destroyAllControllers(){ } //----------------------------------------------------------------------------- TScheduler::TScheduler() :TController() { RTTID("scheduler"); } TScheduler::~TScheduler() { //zrus naplanovany removeAllActions(); //zrus zruseny deleted_actions.unique(); for(std::list::iterator dit = deleted_actions.begin(); dit != deleted_actions.end(); dit++) disposeAction(*dit); deleted_actions.clear(); } void TScheduler::linkActionAfterLast(TSheduledAction* act){ std::list::iterator it, it2; TSheduledAction* sa; // it = actions.begin(); it2 = it; // int p; int max = 0; while(it != actions.end()) { p = (*it)->iStart+(*it)->iDuration; if( p > max ){ it2 = it; max = p; } it++; } //pripoj if(it2 == actions.end()){ insertAction(act); } //nalinkuj za else{ sa = *it2; //nakonec while(sa->next) sa = sa->next; //pripoj act->iStart = -1; act->next = NULL; sa->next = act; } } void TScheduler::insertActionAfter(TSheduledAction* sa, TSheduledAction* act){ //napoj na akci if(sa){ act->iStart = sa->iStarted + (int)(sa->iDuration/fTimeRatio); } insertAction(act); } void TScheduler::insertAction(TSheduledAction* act) { actions.push_back(act); } TSheduledAction* TScheduler::createAction(int act, void* data, int start, int dur){ TSheduledAction* sa = (TSheduledAction*)KMemAlloc(sizeof(TSheduledAction)); // sa->iAction = act; sa->pData = data; sa->iStart = start; sa->iDuration = dur; sa->iStarted = 0; sa->next = NULL; sa->iUpdated = KTime(); // return sa; } void TScheduler::disposeAction(TSheduledAction* ac){ KMemFree( ac); } void TScheduler::removeActions(int type){ TSheduledAction **sapp; TSheduledAction *sap; for(std::list::iterator it = actions.begin(); it != actions.end(); it++) { //zkontroluj nalinkovany akce sapp = &((*it)->next); while(*sapp){ //zrus if( ((*sapp)->iAction == type) ){ sap = (*sapp); *sapp=(*sapp)->next; deleted_actions.push_back(sap); } //posun else sapp=&((*sapp)->next); } // if( (*it)->iAction == type){ deleted_actions.push_back(*it); (*it) = NULL; } } actions.remove(NULL); } void TScheduler::removeAllActions(){ for(std::list::iterator it = actions.begin(); it != actions.end(); it++) { deleted_actions.push_back(*it); //vsechny zretezeny TSheduledAction* sa = (*it)->next; while( sa ){ deleted_actions.push_back(sa); sa = sa->next; } } // actions.clear(); } void TScheduler::removeAction(TSheduledAction* act){ actions.remove(act); deleted_actions.push_back(act); } void TScheduler::update(int absoluteTime){ // TSheduledAction* cur = NULL; int rtime; //opakuj dokud tu jsou nejake akce while(!actions.empty()){ //pruchod cur = *(actions.begin()); //akce uz byla updatovana(kazda bude v tomhle kole jen jednou), //pri navratu znamena, ze uz sem obehl vsechny if( cur->iUpdated >= absoluteTime )break; cur->iUpdated = absoluteTime; actions.pop_front(); //akce zapocata okamzite if(cur->iStart == -1){ cur->iStart = absoluteTime; } //updatuj akci if( cur->iStart <= absoluteTime ){ rtime = (int)((absoluteTime - cur->iStart)*fTimeRatio); //test jestli byl odstranen, musi se okamzite ukoncit if( !updateAction(rtime, cur) )return; //< smaz akci if( ( cur->iStart + cur->iDuration/fTimeRatio ) <= absoluteTime ){ //naplanuj nalinkovanou akci if(cur->next){ actions.push_back(cur->next); } deleted_actions.push_back(cur); } else{ actions.push_back(cur); } } //smazane akce deleted_actions.unique(); for(std::list::iterator dit = deleted_actions.begin(); dit != deleted_actions.end(); dit++) disposeAction(*dit); deleted_actions.clear(); } void TScheduler::dumpActions(){ TSheduledAction *sap; printf("sheduler: %p, now=%d\n", this, KTime()); for(std::list::iterator it = actions.begin(); it != actions.end(); it++) { printf("\taction=%p id = %d, start = %d\n", (*it), (*it)->iAction, (*it)->iStart ); sap = (*it)->next; while(sap){ printf("\t\tsubaction=%p id = %d, start = %d\n", sap, sap->iAction, sap->iStart ); sap = sap->next; } }//for } }//namespace /*****************************************************************************/