// Ryzom - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // 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 Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #include "stdpch.h" ///////////// // INCLUDE // ///////////// // Misc. #include "nel/misc/path.h" #include "nel/misc/debug.h" #include "nel/misc/matrix.h" // 3D Interface. #include "nel/3d/u_driver.h" #include "nel/3d/u_scene.h" #include "nel/3d/u_play_list.h" #include "nel/3d/u_track.h" #include "nel/3d/u_camera.h" // Client. #include "scene_parser.h" #include "entities.h" #include "entity_cl.h" #include "animated_scene_object.h" #include "ig_client.h" #include "user_controls.h" #include "time_client.h" // Game Share #include "game_share/entity.h" /////////// // USING // /////////// using namespace NLMISC; using namespace NL3D; using namespace std; //////////// // EXTERN // //////////// extern UDriver *Driver; extern UScene *Scene; extern UScene *SceneRoot; ///////////// // METHODS // ///////////// const uint CSceneParser::MAX_LINE_SIZE = 500; const char *CSceneParser::delimiter = " \t"; //----------------------------------------------- // CSceneParser : // Constructor. //----------------------------------------------- CSceneParser::CSceneParser() { _FrameRate = 30.0; _Line = 0; _AnimationSet = 0; _TimeStart = -1; _AnimationSet = 0; _Apply = false; _Day = true; _ItScene = _Scene.end(); _SceneStart = -1.f; }// CSceneParser // //----------------------------------------------- // load : // Load the file with the scene. //----------------------------------------------- void CSceneParser::load(const string &filename) { // Look for the file -> nlwarning and return if sceneFile is empty. string sceneFile = CPath::lookup(filename, false); if(sceneFile.empty()) { nlwarning("CSceneParser::load : Can't find file \"%s\".", filename.c_str()); return; } // Open the file. ifstream file(sceneFile.c_str(), ios::in); if(file.is_open()) { // Load the capture speed. ifstream speedFile("capture_speed.txt", ios::in); if(speedFile.is_open()) { char tmpBuff[MAX_LINE_SIZE]; // Set the default fram rate (30fps). _FrameRate = 30.0; // Init Lines. _Line = 0; // While the end of the file is not reached -> parse the script. while(!speedFile.eof()) { // Get next valid line. getNextValidLine(speedFile, tmpBuff); char *ptr = strtok(tmpBuff, delimiter); if(ptr != NULL) NLMISC::fromString(ptr, _FrameRate); } // Close the speed file. speedFile.close(); } else nlwarning("CSceneParser::load : 'capture_speed.txt' can't be open, default frame rate is %f.", _FrameRate); // Init Lines. _Line = 0; // Parse the File. parse(file); // Initialize Actors Position and rotation . initActors(); // Close the File. file.close(); } else { nlwarning("CSceneParser::load : File \"%s\" can't be open.", sceneFile.c_str()); return; } }// load // //----------------------------------------------- // parse : // Parse the file. //----------------------------------------------- void CSceneParser::parse(ifstream &file) { char tmpBuff[MAX_LINE_SIZE]; // While the end of the file is not reached -> parse the script. while(!file.eof()) { // Get next valid line. getNextValidLine(file, tmpBuff); char *ptr = strtok(tmpBuff, delimiter); if(ptr != NULL) { // Time (Day/Night) if(strcmp(ptr, "Time:") == 0) parseTime(); // Filename of the File with all IG to load for the scene. else if(strcmp(ptr, "IG:") == 0) parseIG(file, tmpBuff); // Ig for the init. else if(strcmp(ptr, "IG_Init:") == 0) parseIGInit(); // Particle. else if(strcmp(ptr, "Particle:") == 0) parseParticle(file, tmpBuff); // Actor. else if(strcmp(ptr, "Actor:") == 0) parseActor(file, tmpBuff); // Camera. else if(strcmp(ptr, "Camera:") == 0) parseCamAnims(file, tmpBuff); // Action. else if(strcmp(ptr, "Sequence:") == 0) parseSequence(file, tmpBuff); // Bad Keyword else nlwarning("Unknown keyword '%s' at line %d.", ptr, _Line); } } }// parse // //----------------------------------------------- // getNextValidLine : // Skip empty lines and comment lines. //----------------------------------------------- void CSceneParser::getNextValidLine(ifstream &file, char *buff) { while(!file.eof()) { // Get the line. file.getline(buff, MAX_LINE_SIZE); // Increase line nnumber. _Line++; // Skip comments. if(buff[0] != 0) { // First char is not the beginning of a comment. if(buff[0] != '/') break; // Second char is not the end of a coment. else if(buff[1] != '/') break; } } }// getNextValidLine // //----------------------------------------------- // parseTime : // Day or Night. //----------------------------------------------- void CSceneParser::parseTime() { char *ptr = strtok(NULL, delimiter); if(ptr != NULL) { if(atoi(ptr)) _Day = true; else _Day = false; } }// parseTime // //----------------------------------------------- // parseIG : // Parse the list of IG to load for the scene //----------------------------------------------- void CSceneParser::parseIG(ifstream &file, char *buff) { while(!file.eof()) { // Get next valid line. getNextValidLine(file, buff); char *ptr = strtok(buff, delimiter); if(ptr != NULL) { // End of the actor definition. if(strcmp(ptr, "End_IG") == 0) break; // IG Name. else _IG.push_back(ptr); } } }// parseIG // //----------------------------------------------- // parseIGInit : // Get the name of the IG to initialize entities. //----------------------------------------------- void CSceneParser::parseIGInit() { char *ptr = strtok(NULL, delimiter); if(ptr != NULL) _IG_Init = ptr; }// parseIGInit // /////////////// // PARTICLES // //----------------------------------------------- // parseParticle : // Parse Particle. //----------------------------------------------- void CSceneParser::parseParticle(ifstream &file, char *buff) { // Reset the current particle. _CurrentParticle.reset(); while(!file.eof()) { // Get next valid line. getNextValidLine(file, buff); char *ptr = strtok(buff, delimiter); if(ptr != NULL) { // End of the actor definition. if(strcmp(ptr, "End_Particle") == 0) break; // Particle's Id else if(strcmp(ptr, "Id:") == 0) parseParticleId(); // Particle's IG else if(strcmp(ptr, "IG:") == 0) parseParticleIG(); // Particle's Cluster else if(strcmp(ptr, "Cluster:") == 0) parseParticleCluster(); // Actor father of the particle is there is one. else if(strcmp(ptr, "Actor:") == 0) parseParticleActor(); // Particle's Anims else if(strcmp(ptr, "Anims:") == 0) parseParticleAnims(file, buff); // Bad Keyword else nlwarning("Unknown keyword '%s' at line %d.", ptr, _Line); } } // If the current particle Id is Valid -> create the particle. if(_CurrentParticle.Id >= 0) { map::iterator it = _Particles.find((uint)_CurrentParticle.Id); // Id already exists. if(it != _Particles.end()) nlwarning("Particle before line %d has the ID %d that already exists -> Particle Not Created.", _Line, _CurrentParticle.Id); // Insert the new Particle. else _Particles.insert(make_pair((uint)_CurrentParticle.Id, _CurrentParticle)); } else nlwarning("Particle before line %d has no ID or a Bad one -> Particle Not Created.", _Line); }// parseParticle // //----------------------------------------------- // parseParticleId : // Parse Particle's Id. //----------------------------------------------- void CSceneParser::parseParticleId() { char *ptr = strtok(NULL, delimiter); if(ptr != NULL) _CurrentParticle.Id = atoi(ptr); }// parseParticleId // //----------------------------------------------- // parseParticleIG : // Parse Particle's IG. //----------------------------------------------- void CSceneParser::parseParticleIG() { char *ptr = strtok(NULL, delimiter); if(ptr != NULL) _CurrentParticle.IG = ptr; }// parseParticleIG // //----------------------------------------------- // parseParticleCluster : // Parse Particle's Cluster. //----------------------------------------------- void CSceneParser::parseParticleCluster() { char *ptr = strtok(NULL, delimiter); if(ptr != NULL) _CurrentParticle.Cluster = ptr; }// parseParticleCluster // //----------------------------------------------- // parseParticleActor : // Parse Particle's Actor. //----------------------------------------------- void CSceneParser::parseParticleActor() { char *ptr = strtok(NULL, delimiter); if(ptr != NULL) _CurrentParticle.Actor = atoi(ptr); }// parseParticleActor // //----------------------------------------------- // parseParticleAnims : // Parse Particle's anims. //----------------------------------------------- void CSceneParser::parseParticleAnims(ifstream &file, char *buff) { while(!file.eof()) { // Get next valid line. getNextValidLine(file, buff); char *ptr = strtok(buff, delimiter); if(ptr != NULL) { // End of the actor definition. if(strcmp(ptr, "End_Anims") == 0) break; // Meshes Name. else _CurrentParticle.Anims.push_back(ptr); } } }// parseParticleAnims // //////////// // ACTORS // //----------------------------------------------- // parseActor : // Parse an actor. //----------------------------------------------- void CSceneParser::parseActor(ifstream &file, char *buff) { // Reset the current actor. _CurrentActor.reset(); while(!file.eof()) { // Get next valid line. getNextValidLine(file, buff); char *ptr = strtok(buff, delimiter); if(ptr != NULL) { // End of the actor definition. if(strcmp(ptr, "End_Actor") == 0) break; // Actor's Id else if(strcmp(ptr, "Id:") == 0) parseId(); // Actor's Name else if(strcmp(ptr, "Name:") == 0) parseName(); // Is the Actor a flyer. else if(strcmp(ptr, "Fly:") == 0) parseFly(); // Actor father of the particle is there is one. else if(strcmp(ptr, "Actor:") == 0) parseActorActor(); // Actor's Skeleton else if(strcmp(ptr, "Skel:") == 0) parseSkel(); // Actor's Meshes else if(strcmp(ptr, "Meshes:") == 0) parseMeshes(file, buff); // Actor's Anims else if(strcmp(ptr, "Anims:") == 0) parseAnims(file, buff); // Bad Keyword else nlwarning("Unknown keyword '%s' at line %d.", ptr, _Line); } } // If the current actor Id is Valid -> create the actor. if(_CurrentActor.Id >= 0) { map::iterator it = _Actors.find((uint)_CurrentActor.Id); // Id already exists. if(it != _Actors.end()) nlwarning("Actor before line %d has the ID %d that already exists -> Actor Not Created.", _Line, _CurrentActor.Id); // Insert the new actor. else _Actors.insert(make_pair((uint)_CurrentActor.Id, _CurrentActor)); } else nlwarning("Actor before line %d has no ID or a Bad one -> Actor Not Created.", _Line); }// parseActor // //----------------------------------------------- // parseId : // Parse the current actor Id. //----------------------------------------------- void CSceneParser::parseId() { char *ptr = strtok(NULL, delimiter); if(ptr != NULL) _CurrentActor.Id = atoi(ptr); }// parseId // //----------------------------------------------- // parseName : // Parse the current actor Name. //----------------------------------------------- void CSceneParser::parseName() { char *ptr = strtok(NULL, delimiter); if(ptr != NULL) _CurrentActor.Name = ptr; }// parseName // //----------------------------------------------- // parseFly : // Is the Actor a flyer. //----------------------------------------------- void CSceneParser::parseFly() { char *ptr = strtok(NULL, delimiter); if(ptr != NULL) { if(atoi(ptr)) _CurrentActor.Fly = true; else _CurrentActor.Fly = false; } }// parseFly // //----------------------------------------------- // parseActorActor : // Parse Actor's Actor. //----------------------------------------------- void CSceneParser::parseActorActor() { char *ptr = strtok(NULL, delimiter); if(ptr != NULL) { _CurrentActor.Actor = atoi(ptr); nlwarning("Actor: %d Follow : %d", _CurrentActor.Id, _CurrentActor.Actor); } }// parseActorActor // //----------------------------------------------- // parseSkel : // Parse the current actor Skeleton Name. //----------------------------------------------- void CSceneParser::parseSkel() { char *ptr = strtok(NULL, delimiter); if(ptr != NULL) _CurrentActor.Skeleton = ptr; }// parseSkel // //----------------------------------------------- // parseMeshes : // Parse meshes used for the current actor. //----------------------------------------------- void CSceneParser::parseMeshes(ifstream &file, char *buff) { while(!file.eof()) { // Get next valid line. getNextValidLine(file, buff); char *ptr = strtok(buff, delimiter); if(ptr != NULL) { // End of the actor definition. if(strcmp(ptr, "End_Meshes") == 0) break; // Meshes Name. else _CurrentActor.Meshes.push_back(ptr); } } }// parseMeshes // //----------------------------------------------- // parseAnims : // Parse anims used for the current actor. //----------------------------------------------- void CSceneParser::parseAnims(ifstream &file, char *buff) { while(!file.eof()) { // Get next valid line. getNextValidLine(file, buff); char *ptr = strtok(buff, delimiter); if(ptr != NULL) { // End of the actor definition. if(strcmp(ptr, "End_Anims") == 0) break; // Meshes Name. else _CurrentActor.Anims.push_back(ptr); } } }// parseAnims // //////////// // CAMERA // //----------------------------------------------- // parseCamAnims : // Parse all anims used for the camera in all sequence. //----------------------------------------------- void CSceneParser::parseCamAnims(ifstream &file, char *buff) { while(!file.eof()) { // Get next valid line. getNextValidLine(file, buff); char *ptr = strtok(buff, delimiter); if(ptr != NULL) { // End of Anims for the camera. if(strcmp(ptr, "End_Camera") == 0) break; // Meshes Name. else _CamAnims.push_back(ptr); } } }// parseCamAnims // /////////////// // SEQUENCES // //----------------------------------------------- // parseSequence : // Parse a sequence. //----------------------------------------------- void CSceneParser::parseSequence(ifstream &file, char *buff) { // Reset the current sequence. _CurrentSequence.reset(); while(!file.eof()) { // Get next valid line. getNextValidLine(file, buff); char *ptr = strtok(buff, delimiter); if(ptr != NULL) { // End of the actor definition. if(strcmp(ptr, "End_Sequence") == 0) break; // Sequence Id. else if(strcmp(ptr, "Id:") == 0) parseSeqId(); // Particle for the sequence. else if(strcmp(ptr, "Particle:") == 0) parseSeqParticle(file, buff); // Actor for the sequence. else if(strcmp(ptr, "Actor:") == 0) parseSeqActor(file, buff); // Camera for the sequence. else if(strcmp(ptr, "Camera:") == 0) parseSeqCam(file, buff); // Bad Keyword else nlwarning("Unknown keyword '%s' at line %d.", ptr, _Line); } } // If the sequence Id is Valid -> create the sequence. if(_CurrentSequence.Id >= 0) { map::iterator itSeq = _Sequences.find((uint)_CurrentSequence.Id); // Id already exists. if(itSeq != _Sequences.end()) nlwarning("Sequence before line %d has the ID %d that already exists -> Sequence Not Created.", _Line, _CurrentSequence.Id); // Insert the new actor. else _Sequences.insert(make_pair((uint)_CurrentSequence.Id, _CurrentSequence)); } else nlwarning("Sequence before line %d has no ID or a Bad one -> Sequence Not Created.", _Line); }// parseSequence // //----------------------------------------------- // parseSeqId : // Parse the current sequence Id. //----------------------------------------------- void CSceneParser::parseSeqId() { char *ptr = strtok(NULL, delimiter); if(ptr != NULL) _CurrentSequence.Id = atoi(ptr); }// parseSeqId // //----------------------------------------------- // parseSeqParticle : // Parse particle in the sequence. //----------------------------------------------- void CSceneParser::parseSeqParticle(ifstream &file, char *buff) { // Reset the current particle in the sequence. _CurParticleSeq.reset(); while(!file.eof()) { // Get next valid line. getNextValidLine(file, buff); char *ptr = strtok(buff, delimiter); if(ptr != NULL) { // End of the actor definition. if(strcmp(ptr, "End_Particle") == 0) break; // Actor in Sequence Id. else if(strcmp(ptr, "Id:") == 0) parseSeqParticleId(); // Actor in Sequence anims. else if(strcmp(ptr, "Anims:") == 0) parseSeqParticleAnims(file, buff); // Bad Keyword else nlwarning("Unknown keyword '%s' at line %d.", ptr, _Line); } } // If the particle's Id in the sequence is Valid -> create the particleSeq. if(_CurParticleSeq.Id >= 0) { map::iterator itPartSeq = _CurrentSequence.ParticlesSeq.find((uint)_CurParticleSeq.Id); // Id already exists. if(itPartSeq != _CurrentSequence.ParticlesSeq.end()) nlwarning("Particle in Sequence before line %d has the ID %d that already exists -> Particle in the sequence Not Created.", _Line, _CurParticleSeq.Id); // Insert the new particle in the sequence. else _CurrentSequence.ParticlesSeq.insert(make_pair((uint)_CurParticleSeq.Id, _CurParticleSeq)); } else nlwarning("Particle in Sequence before line %d has no ID or a Bad one -> Particle in the sequence Not Created.", _Line); }// parseSeqParticle // //----------------------------------------------- // parseSeqParticleId : // Parse the current particle's Id in the current sequence. //----------------------------------------------- void CSceneParser::parseSeqParticleId() { char *ptr = strtok(NULL, delimiter); if(ptr != NULL) _CurParticleSeq.Id = atoi(ptr); }// parseSeqParticleId // //----------------------------------------------- // parseSeqParticleAnims : // Parse anims used for the current particle in the current sequence. //----------------------------------------------- void CSceneParser::parseSeqParticleAnims(ifstream &file, char *buff) { while(!file.eof()) { // Get next valid line. getNextValidLine(file, buff); char *ptr = strtok(buff, delimiter); if(ptr != NULL) { // End of the actor definition. if(strcmp(ptr, "End_Anims") == 0) break; // Meshes Name. else _CurParticleSeq.Anims.push_back(ptr); } } }// parseSeqParticleAnims // //----------------------------------------------- // parseSeqActor : // Parse an actor in a sequence. //----------------------------------------------- void CSceneParser::parseSeqActor(ifstream &file, char *buff) { // Reset the current sequence. _CurrentActorSeq.reset(); while(!file.eof()) { // Get next valid line. getNextValidLine(file, buff); char *ptr = strtok(buff, delimiter); if(ptr != NULL) { // End of the actor definition. if(strcmp(ptr, "End_Actor") == 0) break; // Actor in Sequence Id. else if(strcmp(ptr, "Id:") == 0) parseSeqActorId(); // Actor in Sequence anims. else if(strcmp(ptr, "Anims:") == 0) parseSeqActorAnims(file, buff); // Bad Keyword else nlwarning("Unknown keyword '%s' at line %d.", ptr, _Line); } } // If the actor's Id in the sequence is Valid -> create the actorSeq. if(_CurrentActorSeq.Id >= 0) { map::iterator itActSeq = _CurrentSequence.ActorsSeq.find((uint)_CurrentActorSeq.Id); // Id already exists. if(itActSeq != _CurrentSequence.ActorsSeq.end()) nlwarning("Actor in Sequence before line %d has the ID %d that already exists -> Actor in the sequence Not Created.", _Line, _CurrentActorSeq.Id); // Insert the new actor. else _CurrentSequence.ActorsSeq.insert(make_pair((uint)_CurrentActorSeq.Id, _CurrentActorSeq)); } else nlwarning("Actor in Sequence before line %d has no ID or a Bad one -> Actor in the sequence Not Created.", _Line); }// parseSeqActor // //----------------------------------------------- // parseSeqActorId : // Parse the current actor's Id in the current sequence. //----------------------------------------------- void CSceneParser::parseSeqActorId() { char *ptr = strtok(NULL, delimiter); if(ptr != NULL) _CurrentActorSeq.Id = atoi(ptr); }// parseSeqActorId // //----------------------------------------------- // parseSeqActorAnims : // Parse anims used for the current actor in the current sequence. //----------------------------------------------- void CSceneParser::parseSeqActorAnims(ifstream &file, char *buff) { while(!file.eof()) { // Get next valid line. getNextValidLine(file, buff); char *ptr = strtok(buff, delimiter); if(ptr != NULL) { // End of the actor definition. if(strcmp(ptr, "End_Anims") == 0) break; // Meshes Name. else _CurrentActorSeq.Anims.push_back(ptr); } } }// parseSeqActorAnims // //----------------------------------------------- // parseSeqCam : // Parse camera in the sequence. //----------------------------------------------- void CSceneParser::parseSeqCam(ifstream &file, char *buff) { while(!file.eof()) { // Get next valid line. getNextValidLine(file, buff); char *ptr = strtok(buff, delimiter); if(ptr != NULL) { // End of the actor definition. if(strcmp(ptr, "End_Camera") == 0) break; // Meshes Name. else _CurrentSequence.CamAnims.push_back(ptr); } } }// parseSeqCam // //////////////// // INIT AFTER // //----------------------------------------------- // initActors : // Initialize Actors Position and rotation . //----------------------------------------------- void CSceneParser::initActors() { if(_IG_Init.empty()) return; // Create the instance group with all start positions and rotations. UInstanceGroup *IGInit = UInstanceGroup::createInstanceGroup(_IG_Init); if(IGInit) { int nbInst = IGInit->getNumInstance(); map::iterator itActor; for(int i = 0; i < nbInst; ++i ) { sint id = atoi(IGInit->getInstanceName(i).c_str()); itActor = _Actors.find(id); if(itActor != _Actors.end()) { CActor &actor = (*itActor).second; actor.Pos = IGInit->getInstancePos(i); actor.Rot = IGInit->getInstanceRot(i); } else nlwarning("CSceneParser::initActors : Actor %d is in the IG \"%s\" but is not in the script.", id, _IG_Init.c_str()); } // Destroy the IG to initialize (all is already backup now). delete IGInit; IGInit = 0; } else nlwarning("CSceneParser::initActors : Can't create the Instance group to initialize actors."); }// initActors /// ////////////// // PLAY SEQ // //----------------------------------------------- // apply : // Initialize the scene with the parameters loaded from the script. //----------------------------------------------- void CSceneParser::apply() { // If the scene is already initialized -> reset the scene. if(_Apply) { reset(); return; } // Create a play list manager for the scene. _PlayListManager = Scene->createPlayListManager(); // Initialize the Camera and reset it the second time. applyCamera(); // Initialize IG for the scenery (IG present from start to end like trees or torch. applyIG(); // Initialize Particles. applyParticles(); // Initialize Actors. applyActors(); // Scene already aplly now. _Apply = true; }// apply // //----------------------------------------------- // reset : // Reset the scene. //----------------------------------------------- void CSceneParser::reset() { // Camera in scene mode. UserControls.mode(CUserControls::InterfaceMode); // Reset all particles. resetParticles(); // Reset all actors. resetActors(); }// reset // //----------------------------------------------- // resetParticles : // Reset all particles. //----------------------------------------------- void CSceneParser::resetParticles() { map::iterator itPart = _Particles.begin(); for(itPart = _Particles.begin(); itPart != _Particles.end(); ++itPart) { // Get a reference on the particule. CParticle &particle = (*itPart).second; // Check if the IG of particles is not already in the scene. if(particle.IGPtr && _IGInScene.find(particle.IGPtr) != _IGInScene.end()) { // Reset the playlist. particle.PlayList->resetAllChannels(); // Remove from the set with all particle in the scene. _IGInScene.erase(particle.IGPtr); // Remove particles from scene. particle.IGPtr->removeFromScene(*Scene); Scene->deleteInstanceGroup (particle.IGPtr); // Load the IG of the particle. particle.IGPtr = 0; try { particle.IGPtr = UInstanceGroup::createInstanceGroup((*itPart).second.IG); } catch(Exception &e){nlwarning("CSceneParser::resetParticles : %s", e.what());} } } }// resetParticles // //----------------------------------------------- // resetActors : // Reset all actors. //----------------------------------------------- void CSceneParser::resetActors() { // Create new entities from actors map::iterator itActor; for(itActor = _Actors.begin(); itActor != _Actors.end(); ++itActor) { // Get a reference on the actor. CActor &actor = (*itActor).second; // Get the Sid. Sid entityId(Sid::npc, (uint64)actor.Id); // Find the actor. CEntityCL *entity = getEntity(entityId); if(entity) { // Position the entity. entity->pacsPos(actor.Pos); // Position the skeleton at the same position as the entity. if(entity->skeleton()) { entity->skeleton()->setPos(actor.Pos); entity->skeleton()->setRotQuat(actor.Rot); } } // Reset entity animations. resetAnimatedSceneObject(entityId); } }// resetActors // //----------------------------------------------- // applyParticles : // Initialize the scene with the parameters loaded from the script for particles. //----------------------------------------------- void CSceneParser::applyParticles() { map::iterator itPart = _Particles.begin(); for(itPart = _Particles.begin(); itPart != _Particles.end(); ++itPart) { // Get a reference on the particule. CParticle &particle = (*itPart).second; // Create the animation set for the particule. particle.AnimationSet = Driver->createAnimationSet(); // Add animations to the animation set. list::iterator itPartAnim; for(itPartAnim = particle.Anims.begin(); itPartAnim != particle.Anims.end(); ++itPartAnim) { uint idAnim = UAnimationSet::NotFound; try { idAnim = particle.AnimationSet->addAnimation((*itPartAnim + string(".anim")).c_str(), (*itPartAnim).c_str()); } catch(Exception &e) {nlwarning("%s", e.what());} if(idAnim != UAnimationSet::NotFound) { particle.AnimToId.insert(make_pair((*itPartAnim).c_str(), idAnim)); } else nlwarning("CSceneParser::applyParticles : Anim %s cannot be add in the animation set", (*itPartAnim).c_str()); } // Build animation set particle.AnimationSet->build(); // Create playlist. particle.PlayList = _PlayListManager->createPlayList(particle.AnimationSet); if(particle.PlayList) { // Load the IG of the particle. particle.IGPtr = 0; try { particle.IGPtr = UInstanceGroup::createInstanceGroup((*itPart).second.IG); } catch(Exception &e) {nlwarning("%s", e.what());} if(particle.IGPtr) { // Get the position of Instances in IG. for(uint i = 0; i < particle.IGPtr->getNumInstance(); ++i ) particle.IGPos.push_back(particle.IGPtr->getInstancePos(i)); } } } }// applyParticles // //----------------------------------------------- // applyCamera : // Initialize the Camera and reset it the second time. //----------------------------------------------- void CSceneParser::applyCamera() { // Create the animation set for the camera if not already done. _AnimationSet = Driver->createAnimationSet(); if(_AnimationSet) { list::iterator itCamAnims; for(itCamAnims = _CamAnims.begin(); itCamAnims != _CamAnims.end(); ++itCamAnims) { uint idAnim = UAnimationSet::NotFound; try { idAnim = _AnimationSet->addAnimation((*itCamAnims + string(".anim")).c_str(), (*itCamAnims).c_str()); } catch(Exception &e) {nlwarning("%s", e.what());} if(idAnim != UAnimationSet::NotFound) _AnimCamToId.insert(make_pair((*itCamAnims).c_str(), idAnim)); else nlwarning("CSceneParser::apply : Camera Anim %s cannot be add in the animation set", (*itCamAnims).c_str()); } // Build animation set _AnimationSet->build(); // create playlist _PlayList = _PlayListManager->createPlayList( _AnimationSet ); } else nlwarning("CSceneParser::apply : AnimationSet cannot be created."); }// applyCamera // //----------------------------------------------- // applyIG : // Initialize IG for the scenery (IG present from start to end like trees or torch. //----------------------------------------------- void CSceneParser::applyIG() { // Load Instances Groups for the scene. for(list::iterator itIG = _IG.begin(); itIG != _IG.end(); ++itIG) { UInstanceGroup *IGTemp = 0; try { IGTemp = UInstanceGroup::createInstanceGroup(*itIG); } catch(Exception &e) {nlwarning("CSceneParser::applyIG : %s", e.what());} // Add Instance Group in the scene. if(IGTemp) IGTemp->addToScene(*Scene, Driver); } }// applyIG // //----------------------------------------------- // applyActors : // Initialize actors. //----------------------------------------------- void CSceneParser::applyActors() { // Create new entities from actors map::iterator itActor; for(itActor = _Actors.begin(); itActor != _Actors.end(); ++itActor) { // Get a reference on the actor. CActor &actor = (*itActor).second; // Create the entity Sid. Sid entityId(Sid::npc, (uint64)actor.Id); // Create the entity type. CTypeEntity typeEntity; typeEntity.TypeInfo.TypeEntity = CTypeEntity::npc; typeEntity.TypeInfo.Kind = CTypeEntity::zorai; typeEntity.TypeInfo.Age = CTypeEntity::adult; typeEntity.TypeInfo.Sex = CTypeEntity::male; // Create the entity. CEntityCL *entityTmp = createEntity(entityId, typeEntity); if(entityTmp) { // Get a reference on the entity. CEntityCL &entity = *entityTmp; // True if the entity fly. entity.flyer(actor.Fly); // Set the name of the entity entity.name(actor.Name); // Time for the current frame. entity.time(T1); // Set the entity position. entity.pacsPos(actor.Pos); // Set the Front. CMatrix m; m.identity(); m.setRot(actor.Rot); entity.front((m * CVector::J).normed()); // Set the direction like the front. entity.dir(entity.front()); // Set the vector UP. entity.up(CVector(0.f,0.f,1.f)); // Assign a skeleton. entity.skeleton(actor.Skeleton); // Position the entity. entity.pacsPos(actor.Pos); // Position the skeleton at the same position as the entity. if(entity.skeleton()) { entity.skeleton()->setPos(actor.Pos); entity.skeleton()->setRotQuat(actor.Rot); } // Assign meshes used for the entity. uint count = 0; list::iterator itMeshes; for(itMeshes = actor.Meshes.begin(); itMeshes != actor.Meshes.end(); ++itMeshes) { // If there are too many meshes. if(count >= (uint)CEntityCL::NB_SLOT) { nlwarning("CSceneParser::applyActors : Too many meshes for Actor %d.", actor.Id); break; } entity.slot((CEntityCL::ESlots)count, *itMeshes); ++count; } // Create the playlist addEntityClAnimatedSceneObject(entityId, actor.Anims); } else nlwarning("CSceneParser::applyActors : Entity %d Not created", actor.Id); } }// applyActors // //----------------------------------------------- // playSeq : // Play the sequence with the ID 'seq'. //----------------------------------------------- void CSceneParser::playSeq(uint seq, double timeInSec) { // If the scene is not initialized -> return. if(!_Apply) return; // Camera in scene mode. UserControls.mode(CUserControls::SceneMode); _TimeStart = timeInSec; map::iterator itSeq = _Sequences.find(seq); if(itSeq != _Sequences.end()) { // Get a reference on the sequence. CSequence &sequence = (*itSeq).second; // Log the time used for the sequence. nlwarning("Sequence: %d, Time: %f", seq, timeInSec); // Camera in the sequence. if(!sequence.CamAnims.empty()) { if(_PlayList) { map::iterator itAnimCamId; for(itAnimCamId = _AnimCamToId.begin(); itAnimCamId != _AnimCamToId.end(); ++itAnimCamId) { _PlayList->setTimeOrigin(0, timeInSec); _PlayList->setAnimation(0, (*itAnimCamId).second); } } } // Particles in the sequence. map::iterator itPartSeq; for(itPartSeq = sequence.ParticlesSeq.begin(); itPartSeq != sequence.ParticlesSeq.end(); ++itPartSeq) { CParticleSeq &particleSeq = (*itPartSeq).second; map::iterator itPart = _Particles.find(particleSeq.Id); if(itPart != _Particles.end()) { // Get a reference on the particle. CParticle &particle = (*itPart).second; // Check if the IG has been created. if(particle.IGPtr) { // Check if the IG of particles is not already in the scene. if(_IGInScene.find(particle.IGPtr) == _IGInScene.end()) { // Insert IG in the set of IG in the scene. _IGInScene.insert(particle.IGPtr); // Cluster. if(IGCity.find(particle.Cluster) == IGCity.end()) Scene->setToGlobalInstanceGroup(particle.IGPtr); else particle.IGPtr->setClusterSystem(IGCity[particle.Cluster]); // Add particles to the scene. particle.IGPtr->addToScene(*Scene, Driver); // Unfreeze the IG. particle.IGPtr->unfreezeHRC(); // Register all instances in the IG to a playlist. for(uint i = 0; i < particle.IGPtr->getNumInstance(); ++i ) { std::string iName = particle.IGPtr->getInstanceName( i ); UInstance instance = particle.IGPtr->getByName( iName ); particle.PlayList->registerTransform(instance); particle.PlayList->registerTransform(instance, (iName + ".").c_str()); } } // Start the particle animation. map::iterator itAnimId; for(itAnimId = particle.AnimToId.begin(); itAnimId != particle.AnimToId.end(); ++itAnimId) { particle.PlayList->setTimeOrigin(0, timeInSec); particle.PlayList->setAnimation(0, (*itAnimId).second); } } } } // Actors in the sequence. map::iterator itActSeq; for(itActSeq = sequence.ActorsSeq.begin(); itActSeq != sequence.ActorsSeq.end(); ++itActSeq) { CActorSeq &actorSeq = (*itActSeq).second; updateAnimationSequence(Sid(Sid::npc, (uint64)actorSeq.Id), actorSeq.Anims, 0 ); } } }// playSeq // //----------------------------------------------- // update : // Update the scene. //----------------------------------------------- void CSceneParser::update(double timeInSec) { // Nothing to update if the scene is not applied. if(!_Apply) return; // Update the scene currently playing. updateScene(timeInSec); // Update particles. updateParticles(timeInSec); // Animate the camera. updateCamera(timeInSec); // Update particle anims. if(_PlayListManager) _PlayListManager->animate(timeInSec); // Update actor position (for actor on another actor). updateActors(); }// update // //----------------------------------------------- // updateCamera : // Update the camera (position, target, roll, fov) //----------------------------------------------- void CSceneParser::updateCamera(double timeInSec) { // If there is a play list for the camera. if(_PlayList) { // Get the Id of the animation in the slot 0. uint idAnim = _PlayList->getAnimation(0); if(idAnim != UPlayList::empty) { UAnimation *animation = _AnimationSet->getAnimation(idAnim); if(animation) { // Get Camera information from the animation (Pos, Target, Roll). UTrack* trackRollCam = animation->getTrackByName("Camera.roll"); UTrack* trackFovCam = animation->getTrackByName("Camera.fov"); UTrack* trackPosCam = animation->getTrackByName("Camera.PathPos"); UTrack* trackPosTarget = animation->getTrackByName("Camera.Target.PathPos"); if(trackPosCam && trackPosTarget) { float rollCam = 0.f; CVector posCam; CVector posTarget; float difTime = (float)(timeInSec-_TimeStart); if(trackRollCam) trackRollCam->interpolate(difTime, rollCam); trackPosCam->interpolate(difTime, posCam); trackPosTarget->interpolate(difTime, posTarget); // Update camera transformations. UCamera cam = Scene->getCam(); if(cam) { cam->setTransformMode(UTransformable::RotQuat); cam->lookAt(posCam, posTarget, rollCam); if(trackFovCam) { float fov; trackFovCam->interpolate(difTime, fov); CFrustum fr= cam->getFrustum(); // change only the fov cam->setPerspective(fov, fr.getAspectRatio(), fr.Near, fr.Far); } } // Update camera transformations for the Root. cam = SceneRoot->getCam(); if(cam) { cam->setTransformMode(UTransformable::RotQuat); cam->lookAt(posCam, posTarget, rollCam); if(trackFovCam) { float fov; trackFovCam->interpolate(difTime, fov); CFrustum fr= cam->getFrustum(); // change only the fov cam->setPerspective(fov, fr.getAspectRatio(), fr.Near, fr.Far); } } } } } } }// updateCamera // //----------------------------------------------- // updateActors : // Update Actors. //----------------------------------------------- void CSceneParser::updateActors() { // All actors in the scene. for(map::iterator itActor = _Actors.begin(); itActor != _Actors.end(); ++itActor) { // Get a reference on the actor. CActor &actor = (*itActor).second; // If there is no actor to follow -> next actor. if(actor.Actor < 0) continue; // Get the entity pointer. CEntityCL *entity = getEntity(Sid(Sid::npc, (uint64)actor.Id)); if(!entity) { nlwarning("CSceneParser::updateActors : Cannot get the actor %d.", actor.Id); continue; } // Get the target entity pointer. CEntityCL *entityTarget = getEntity(Sid(Sid::npc, (uint64)actor.Actor)); if(!entityTarget) { nlwarning("CSceneParser::updateActors : Cannot get the targeted actor %d.", actor.Actor); continue; } // Changes the entity position. entity->pacsPos(entityTarget->pos()); } }// updateActors // //----------------------------------------------- // updateParticles : // Update particles. //----------------------------------------------- void CSceneParser::updateParticles(double timeInSec) { for(map::iterator itPart = _Particles.begin(); itPart != _Particles.end(); ++itPart) { // Get a reference on the particule. CParticle &particle = (*itPart).second; // If the IG pointer is null -> Next particle. if(!(particle.IGPtr)) continue; // If the play list is NULL -> Next particle if(!(particle.PlayList)) continue; // Get the Id of the animation in the slot 0 -> if empty -> Next particle. uint idAnim = particle.PlayList->getAnimation(0); if(idAnim == UPlayList::empty) continue; // Get the animation pointer. UAnimation *animation = particle.AnimationSet->getAnimation(idAnim); if(!animation) continue; // Get the time difference. float difTime = (float)(timeInSec-_TimeStart); // Particle do not follow anything. if(particle.Actor < 0) { updateParticlesNoActor(difTime, particle, *animation); } // Particle follow an actor. else { updateParticlesActor(difTime, particle, *animation); } } }// updateParticles // //----------------------------------------------- // updateParticlesNoActor : // //----------------------------------------------- void CSceneParser::updateParticlesNoActor(float difTime, CParticle &particle, UAnimation &animation) { // Animate all instances. for(uint i = 0; i < particle.IGPtr->getNumInstance(); ++i ) { std::string iName = particle.IGPtr->getInstanceName(i); UInstance instance = particle.IGPtr->getByName(iName); if(!instance) continue; instance->setTransformMode(UTransformable::RotQuat); // If the animation has no track of position. UTrack* trackPos = animation.getTrackByName("PathPos"); if(!trackPos) trackPos = animation.getTrackByName(string(iName + "." + "PathPos").c_str()); if(trackPos) { CVector pos; trackPos->interpolate(difTime, pos); instance->setPos(pos); } // If the animation has no track of rotation. UTrack* trackRot = animation.getTrackByName("PathRotQuat"); if(!trackRot) trackRot = animation.getTrackByName(string(iName + "." + "PathRotQuat").c_str()); if(trackRot) { CQuat rot; if(trackRot->interpolate(difTime, rot)) instance->setRotQuat(rot); else nlwarning("CSceneParser::updateParticles : Not a Quat!"); } } }// updateParticlesNoActor // //----------------------------------------------- // updateParticlesActor : // //----------------------------------------------- void CSceneParser::updateParticlesActor(float difTime, CParticle &particle, UAnimation &animation) { // Get the entity pointer. CEntityCL *entity = getEntity(Sid(Sid::npc, (uint64)particle.Actor)); if(!entity) { nlwarning("CSceneParser::updateParticlesActor : cannot get the actor %d.", (uint64)particle.Actor); return; } // If the entity has no skeleton -> Next particle. if(!entity->skeleton()) { nlwarning("The particle follow an entity %d without a skeleton.", (uint64)particle.Actor); return; } // Matrix 90 degrees CMatrix m90; m90.identity(); m90.rotateZ((float)(Pi/2.0)); // Matrix of the entity. CMatrix mChar = entity->skeleton()->getMatrix(); mChar.setPos(entity->pos()); // Animate all instances. for(uint i = 0; i < particle.IGPtr->getNumInstance(); ++i ) { std::string iName = particle.IGPtr->getInstanceName(i); UInstance instance = particle.IGPtr->getByName(iName); if(!instance) continue; instance->setTransformMode(UTransformable::RotQuat); CMatrix mAnim; mAnim.identity(); // If the animation has no track of position. UTrack* trackPos = animation.getTrackByName("PathPos"); if(!trackPos) trackPos = animation.getTrackByName(string(iName + "." + "PathPos").c_str()); if(trackPos) { CVector pos; trackPos->interpolate(difTime, pos); mAnim.setPos(pos); } // If the animation has no track of rotation. UTrack* trackRot = animation.getTrackByName("PathRotQuat"); if(!trackRot) trackRot = animation.getTrackByName(string(iName + "." + "PathRotQuat").c_str()); if(trackRot) { CQuat rot; trackPos->interpolate(difTime, rot); mAnim.setRot(rot); } CMatrix mFinal = mChar * m90 * mAnim; instance->setPos(mFinal.getPos()); instance->setRotQuat(mFinal.getRot()); } }// updateParticlesActor // //----------------------------------------------- // loadScene : // Load a scene from a file and put it in memory. // \param filename : filename for the file that contains the scene. // \warning This function clear the old scene. //----------------------------------------------- void CSceneParser::loadScene(const string &filename) { // Look for the file -> nlwarning and return if sceneFile is empty. string sceneFile = CPath::lookup(filename, false); if(sceneFile.empty()) { nlwarning("CSceneParser::loadScene : Can't find file \"%s\".", filename.c_str()); return; } // Open the file. ifstream file(sceneFile.c_str(), ios::in); if(file.is_open()) { // ... char tmpBuff[MAX_LINE_SIZE]; // While the end of the file is not reached -> parse the script. while(!file.eof()) { // Get next valid line. getNextValidLine(file, tmpBuff); pair seq; // ... char *ptr = strtok(tmpBuff, delimiter); if(ptr != NULL) { seq.first = atoi(ptr); ptr = strtok(NULL, delimiter); if(ptr != NULL) { NLMISC::fromString(ptr, seq.second); _Scene.push_back(seq); } } } // Close the File. file.close(); } else { nlwarning("CSceneParser::loadScene : File \"%s\" can't be open.", sceneFile.c_str()); return; } }// loadScene // //----------------------------------------------- // playScene : // Play a scene in memory. // \param timeInSec : current time in second. //----------------------------------------------- void CSceneParser::playScene(double timeInSec) { // Initialize the Iterator for the scene. _ItScene = _Scene.begin(); // Initialize the time for the scene. _SceneStart = timeInSec; // Initialize or Reset the scene. apply(); // Play the first sequence to play for this scene. updateScene(timeInSec); }// playScene // //----------------------------------------------- // updateScene : // Update the scene currently playing. // \param timeInSec : current time in second. //----------------------------------------------- void CSceneParser::updateScene(double timeInSec) { // If there are still sequences in the scene. if(_ItScene != _Scene.end()) { double time = timeInSec-_SceneStart; if((*_ItScene).second <= time) { // If the scene is finish -> Stop it. if((*_ItScene).first < 0) { stopScene(); } else { // Play the sequence. playSeq((*_ItScene).first, timeInSec); // Next sequence. _ItScene++; } } } }// updateScene // //----------------------------------------------- // stopScene : // Stop the scene currently playing. //----------------------------------------------- void CSceneParser::stopScene() { _ItScene = _Scene.end(); _SceneStart = -1.f; }// stopScene // //----------------------------------------------- // Function to know if there is a scene currently playing. // \return bool : 'true' if there is a scene currently playing. //----------------------------------------------- bool CSceneParser::isScenePlaying() { return (_ItScene != _Scene.end()); }// isScenePlaying //