// ---------------------------------------------------------------------------- scene::IAnimatedMeshSceneNode* TrackObject::getMesh() { if (getPresentation<TrackObjectPresentationLOD>()) { LODNode* ln = dynamic_cast<LODNode*> (getPresentation<TrackObjectPresentationLOD>()->getNode()); if (ln && !ln->getAllNodes().empty()) { scene::IAnimatedMeshSceneNode* an = dynamic_cast<scene::IAnimatedMeshSceneNode*> (ln->getFirstNode()); if (an) { return an; } } } else if (getPresentation<TrackObjectPresentationMesh>()) { scene::IAnimatedMeshSceneNode* an = dynamic_cast<scene::IAnimatedMeshSceneNode*> (getPresentation<TrackObjectPresentationMesh>()->getNode()); if (an) { return an; } } Log::debug("TrackObject", "No animated mesh"); return NULL; } // getMesh
/** Called when the kart finished the race. It will force the highest LOD * for the kart, since otherwise the end camera can be far away (due to * zooming) and show non-animated karts. */ void KartModel::finishedRace() { // Force the animated model, independent of actual camera distance. LODNode *lod = dynamic_cast<LODNode*>(m_kart->getNode()); if (lod) lod->forceLevelOfDetail(0); } // finishedRace
bool loadTextureToGPU(const LODNode& lodNode, const DataSource& dataSource, const TexturePool& texturePool, const ConstDataObjectPtr& data) const { #ifdef LIVRE_DEBUG_RENDERING std::cout << "Upload " << lodNode.getNodeId().getLevel() << ' ' << lodNode.getRelativePosition() << " to " << _textureState.textureId << std::endl; #endif const Vector3ui& overlap = dataSource.getVolumeInfo().overlap; const Vector3ui& voxSizeVec = lodNode.getBlockSize() + overlap * 2; _textureState.bind(); glTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 0, voxSizeVec[0], voxSizeVec[1], voxSizeVec[2], texturePool.getFormat(), texturePool.getTextureType(), data->getDataPtr()); const GLenum glErr = glGetError(); if (glErr != GL_NO_ERROR) { LBERROR << "Error loading the texture into GPU, error number : " << glErr << std::endl; return false; } return true; }
// ---------------------------------------------------------------------------- TrackObjectPresentationParticles::TrackObjectPresentationParticles( const XMLNode& xml_node, scene::ISceneNode* parent) : TrackObjectPresentationSceneNode(xml_node) { m_emitter = NULL; m_lod_emitter_node = NULL; std::string path; xml_node.get("kind", &path); int clip_distance = -1; xml_node.get("clip_distance", &clip_distance); xml_node.get("conditions", &m_trigger_condition); bool auto_emit = true; xml_node.get("auto_emit", &auto_emit); m_delayed_stop = false; m_delayed_stop_time = 0.0; #ifndef SERVER_ONLY try { ParticleKind* kind = ParticleKindManager::get()->getParticles(path); if (kind == NULL) { throw std::runtime_error(path + " could not be loaded"); } ParticleEmitter* emitter = new ParticleEmitter(kind, m_init_xyz, parent); if (clip_distance > 0) { scene::ISceneManager* sm = irr_driver->getSceneManager(); scene::ISceneNode* sroot = sm->getRootSceneNode(); LODNode* lod = new LODNode("particles", !parent ? sroot : parent, sm); lod->add(clip_distance, (scene::ISceneNode*)emitter->getNode(), true); m_node = lod; m_lod_emitter_node = lod; m_emitter = emitter; } else { m_node = emitter->getNode(); m_emitter = emitter; } if (m_trigger_condition.size() > 0 || !auto_emit) { m_emitter->setCreationRateAbsolute(0.0f); } } catch (std::runtime_error& e) { Log::warn ("Track", "Could not load particles '%s'; cause :\n %s", path.c_str(), e.what()); } #endif } // TrackObjectPresentationParticles
Item::Item(ItemType type, const Vec3& xyz, const Vec3& normal, scene::IMesh* mesh, scene::IMesh* lowres_mesh) { assert(type != ITEM_TRIGGER); // use other constructor for that m_distance_2 = 1.2f; initItem(type, xyz); m_original_rotation = shortestArcQuat(Vec3(0, 1, 0), normal); m_rotation_angle = 0.0f; m_original_mesh = mesh; m_original_lowmesh = lowres_mesh; m_listener = NULL; LODNode* lodnode = new LODNode("item", irr_driver->getSceneManager()->getRootSceneNode(), irr_driver->getSceneManager()); scene::IMeshSceneNode* meshnode = irr_driver->addMesh(mesh, StringUtils::insertValues("item_%i", (int)type)); if (lowres_mesh != NULL) { lodnode->add(35, meshnode, true); scene::IMeshSceneNode* meshnode = irr_driver->addMesh(lowres_mesh, StringUtils::insertValues("item_lo_%i", (int)type)); lodnode->add(100, meshnode, true); } else { lodnode->add(100, meshnode, true); } m_node = lodnode; //m_node = irr_driver->addMesh(mesh); #ifdef DEBUG std::string debug_name("item: "); debug_name += m_type; m_node->setName(debug_name.c_str()); #endif World::getWorld()->getTrack()->adjustForFog(m_node); m_node->setAutomaticCulling(scene::EAC_FRUSTUM_BOX); m_node->setPosition(xyz.toIrrVector()); Vec3 hpr; hpr.setHPR(m_original_rotation); m_node->setRotation(hpr.toIrrHPR()); m_node->grab(); } // Item(type, xyz, normal, mesh, lowres_mesh)
TrackObjectPresentationParticles::TrackObjectPresentationParticles(const XMLNode& xml_node, scene::ISceneNode* parent) : TrackObjectPresentationSceneNode(xml_node) { m_emitter = NULL; m_lod_emitter_node = NULL; std::string path; xml_node.get("kind", &path); int clip_distance = -1; xml_node.get("clip_distance", &clip_distance); xml_node.get("conditions", &m_trigger_condition); try { ParticleKind* kind = ParticleKindManager::get()->getParticles( path.c_str() ); if (kind == NULL) { throw std::runtime_error(path + " could not be loaded"); } ParticleEmitter* emitter = new ParticleEmitter(kind, m_init_xyz, parent); if (clip_distance > 0) { scene::ISceneManager* sm = irr_driver->getSceneManager(); scene::ISceneNode* sroot = sm->getRootSceneNode(); LODNode* lod = new LODNode("particles", parent == NULL ? sroot : parent, sm); lod->add(clip_distance, (scene::ISceneNode*)emitter->getNode(), true); m_node = lod; m_lod_emitter_node = lod; m_emitter = emitter; } else { m_node = emitter->getNode(); m_emitter = emitter; } if (m_trigger_condition.size() > 0) { m_emitter->setCreationRateAbsolute(0.0f); } } catch (std::runtime_error& e) { fprintf(stderr, "[Track] WARNING: Could not load particles '%s'; cause :\n %s", path.c_str(), e.what()); } }
void Character::initNodePath(Player *player, CollisionTraverser *traverser, CollisionTraverser *traverserQueue, CollisionHandlerQueue *colliHandlerQueue, Filename charDir, Filename charWalkDir, Filename charStandDir, std::string lodNodename, std::string colliNodeName) { LODNode *lod = new LODNode(lodNodename); NodePath lodNodePath(lod); lodNodePath.reparent_to(player->getWindow()->get_render()); lod->add_switch(50, 0); // load character and place on the grounds NodePath character = player->getWindow()->load_model(player->getPanda()->get_models(), charDir); character.reparent_to(lodNodePath); character.set_scale(0.203, 0.203, 0.203); // add collision node to character CollisionNode *collNode = new CollisionNode(colliNodeName); collNode->add_solid(new CollisionSphere(0, 0, 0, 2.5)); NodePath fromObj = character.attach_new_node(collNode); CollisionHandlerPusher *colliHandlerPusher = new CollisionHandlerPusher(); colliHandlerPusher->add_collider(fromObj, character); traverser->add_collider(fromObj, colliHandlerPusher); traverserQueue->add_collider(fromObj, colliHandlerQueue); // Load the walk animation player->getWindow()->load_model(character, charStandDir); player->getWindow()->load_model(character, charWalkDir); // bind animation auto_bind(character.node(), animCollection); stopMoving(); nodePath = character; standAnimName = animCollection.get_anim_name(0); walkAnimName = animCollection.get_anim_name(1); // get animation names //for(int i = 0; i < animCollection.get_num_anims(); i++) // cout << animCollection.get_anim_name(i) << endl; }
/** Constructor for an item. * \param type Type of the item. * \param xyz Location of the item. * \param normal The normal upon which the item is placed (so that it can * be aligned properly with the ground). * \param mesh The mesh to be used for this item. * \param owner 'Owner' of this item, i.e. the kart that drops it. This is * used to deactivate this item for the owner, i.e. avoid that a kart * 'collects' its own bubble gum. NULL means no owner, and the item * can be collected immediatley by any kart. */ Item::Item(ItemType type, const Vec3& xyz, const Vec3& normal, scene::IMesh* mesh, scene::IMesh* lowres_mesh, const AbstractKart *owner) : ItemState(type, owner) { m_was_available_previously = true; m_distance_2 = 1.2f; initItem(type, xyz, normal); m_graphical_type = getGrahpicalType(); LODNode* lodnode = new LODNode("item", irr_driver->getSceneManager()->getRootSceneNode(), irr_driver->getSceneManager()); scene::ISceneNode* meshnode = irr_driver->addMesh(mesh, StringUtils::insertValues("item_%i", (int)type)); if (lowres_mesh != NULL) { lodnode->add(35, meshnode, true); scene::ISceneNode* meshnode = irr_driver->addMesh(lowres_mesh, StringUtils::insertValues("item_lo_%i", (int)type)); lodnode->add(100, meshnode, true); } else { lodnode->add(100, meshnode, true); } m_node = lodnode; setType(type); handleNewMesh(getGrahpicalType()); #ifdef DEBUG std::string debug_name("item: "); debug_name += getType(); m_node->setName(debug_name.c_str()); #endif m_node->setAutomaticCulling(scene::EAC_FRUSTUM_BOX); m_node->setPosition(xyz.toIrrVector()); Vec3 hpr; hpr.setHPR(getOriginalRotation()); m_node->setRotation(hpr.toIrrHPR()); m_node->grab(); } // Item(type, xyz, normal, mesh, lowres_mesh)
void visit( const LODNode& lodNode, VisitState& state ) { const Boxf& worldBox = lodNode.getWorldBox(); if( !_frustum.isInFrustum( worldBox ) || _clipPlanes.isClipped( worldBox )) { state.setVisitChild( false ); return; } Vector3f vmin, vmax; const Plane& nearPlane = _frustum.getNearPlane(); worldBox.computeNearFar( nearPlane, vmin, vmax ); Vector4f hVmin = vmin; hVmin[ 3 ] = 1.0f; Vector4f hVmax = vmax; hVmax[ 3 ] = 1.0f; // The bounding box intersects the plane if( _frustum.getNearPlane().dot( hVmin ) < 0 || _frustum.getNearPlane().dot( hVmax ) < 0 ) { // Where eye direction intersects with near plane vmin = _frustum.getEyePos() - _frustum.getViewDir() * _frustum.nearPlane(); } const Vector3f& voxelBox = lodNode.getVoxelBox().getSize(); const Vector3f& worldSpacePerVoxel = worldBox.getSize() / voxelBox; bool lodVisible = isLODVisible( vmin, worldSpacePerVoxel.find_min( )); const VolumeInformation& volInfo = _dataSource.getVolumeInfo(); const uint32_t depth = volInfo.rootNode.getDepth(); lodVisible = ( lodVisible && lodNode.getRefLevel() >= _minLOD ) || ( lodNode.getRefLevel() == _maxLOD ) || ( lodNode.getRefLevel() == depth - 1 ); if( lodVisible ) _visibles.push_back( lodNode.getNodeId( )); state.setVisitChild( !lodVisible ); }
/** Resets the kart model. It stops animation from being played and resets * the wheels to the correct position (i.e. no suspension). */ void KartModel::reset() { for (unsigned int i = 0; i < 4; i++) { if (m_wheel_node[i]) { core::vector3df rotation(btScalar(rand() % 360), 0, 0); m_wheel_node[i]->setRotation(rotation); } } update(0.0f, 0.0f, 0.0f, 0.0f, 0.0f); // Stop any animations currently being played. setAnimation(KartModel::AF_DEFAULT); // Don't force any LOD. Non-animated karts are not LOD nodes. LODNode *lod = dynamic_cast<LODNode*>(m_kart->getNode()); if (lod) lod->forceLevelOfDetail(-1); } // reset
LODNode* SceneLoader::LoadLODNode(QDomElement element) { if (element.nodeName() != QString ("node") || QString::compare(element.attribute("type"), "lod", Qt::CaseInsensitive) != 0) { printf ("ceXMLDataLoader::LoadLODNode: Illegal data format: '%s' != 'group'\n", element.attribute("type").toStdString().c_str()); fflush (stdout); } LODNode* lod = new LODNode (); QString name = element.attribute("name"); if (!name.isNull()) { lod->SetName(name.toStdString()); } for (QDomElement groupElement = element.firstChildElement(); !groupElement.isNull(); groupElement = groupElement.nextSiblingElement()) { ceNode* node = LoadNode (groupElement); if (node) { lod->Get().Add(node); } } lod->GetSolver()->SetNum(lod->Get().GetNumberOfLevels()); lod->UpdateBoundingBox(); return lod; }
bool visit(const LODNode& lodNode) { const Boxf& worldBox = lodNode.getWorldBox(); if (!_frustum.isInFrustum(worldBox) || _clipPlanes.isOutside(worldBox)) return false; Vector3f vmin, vmax; const Plane& nearPlane = _frustum.getNearPlane(); worldBox.computeNearFar(nearPlane, vmin, vmax); Vector4f hVmin = vmin; hVmin[3] = 1.0f; Vector4f hVmax = vmax; hVmax[3] = 1.0f; // The bounding box intersects the plane if (_frustum.getNearPlane().dot(hVmin) < 0 || _frustum.getNearPlane().dot(hVmax) < 0) { // Where eye direction intersects with near plane vmin = _frustum.getEyePos() - _frustum.getViewDir() * _frustum.nearPlane(); } const Vector3f& voxelBox = lodNode.getVoxelBox().getSize(); const Vector3f& worldSpacePerVoxel = worldBox.getSize() / voxelBox; const auto level = lodNode.getRefLevel(); bool lodVisible = isLODVisible(vmin, worldSpacePerVoxel.find_min()) && level >= _minLOD; if (level == _maxLOD) lodVisible = true; if (lodVisible) _visibles.push_back(lodNode.getNodeId()); return !lodVisible; }
// ---------------------------------------------------------------------------- void TrackObjectPresentationLOD::reset() { LODNode* ln = dynamic_cast<LODNode*>(m_node); if (ln) { for (scene::ISceneNode* node : ln->getAllNodes()) { scene::IAnimatedMeshSceneNode* a_node = dynamic_cast<scene::IAnimatedMeshSceneNode*>(node); if (a_node) { a_node->setLoopMode(true); a_node->setAnimationEndCallback(NULL); RandomGenerator rg; int animation_set = 0; if (a_node->getAnimationSetNum() > 0) animation_set = rg.get(a_node->getAnimationSetNum()); a_node->useAnimationSet(animation_set); } } } } // reset
/** Initialises the track object based on the specified XML data. * \param xml_node The XML data. * \param parent The parent scene node. * \param model_def_loader Used to load level-of-detail nodes. */ void TrackObject::init(const XMLNode &xml_node, scene::ISceneNode* parent, ModelDefinitionLoader& model_def_loader, TrackObject* parent_library) { m_init_xyz = core::vector3df(0,0,0); m_init_hpr = core::vector3df(0,0,0); m_init_scale = core::vector3df(1,1,1); m_enabled = true; m_initially_visible = false; m_presentation = NULL; m_animator = NULL; m_parent_library = parent_library; m_physical_object = NULL; xml_node.get("id", &m_id ); xml_node.get("model", &m_name ); xml_node.get("xyz", &m_init_xyz ); xml_node.get("hpr", &m_init_hpr ); xml_node.get("scale", &m_init_scale); xml_node.get("enabled", &m_enabled ); m_interaction = "static"; xml_node.get("interaction", &m_interaction); xml_node.get("lod_group", &m_lod_group); m_is_driveable = false; xml_node.get("driveable", &m_is_driveable); bool lod_instance = false; xml_node.get("lod_instance", &lod_instance); m_soccer_ball = false; xml_node.get("soccer_ball", &m_soccer_ball); std::string type; xml_node.get("type", &type ); m_type = type; m_initially_visible = true; xml_node.get("if", &m_visibility_condition); if (m_visibility_condition == "false") { m_initially_visible = false; } if (!m_initially_visible) setEnabled(false); if (xml_node.getName() == "particle-emitter") { m_type = "particle-emitter"; m_presentation = new TrackObjectPresentationParticles(xml_node, parent); } else if (xml_node.getName() == "light") { m_type = "light"; m_presentation = new TrackObjectPresentationLight(xml_node, parent); } else if (xml_node.getName() == "library") { xml_node.get("name", &m_name); m_presentation = new TrackObjectPresentationLibraryNode(this, xml_node, model_def_loader); if (parent_library != NULL) { Track::getCurrentTrack()->addMetaLibrary(parent_library, this); } } else if (type == "sfx-emitter") { // FIXME: at this time sound emitters are just disabled in multiplayer // otherwise the sounds would be constantly heard if (race_manager->getNumLocalPlayers() < 2) m_presentation = new TrackObjectPresentationSound(xml_node, parent); } else if (type == "action-trigger") { std::string action; xml_node.get("action", &action); m_name = action; //adds action as name so that it can be found by using getName() m_presentation = new TrackObjectPresentationActionTrigger(xml_node, parent_library); } else if (type == "billboard") { m_presentation = new TrackObjectPresentationBillboard(xml_node, parent); } else if (type=="cutscene_camera") { m_presentation = new TrackObjectPresentationEmpty(xml_node); } else { // Colorization settings std::string model_name; xml_node.get("model", &model_name); #ifndef SERVER_ONLY if (CVS->isGLSL()) { scene::IMesh* mesh = NULL; // Use the first material in mesh to determine hue Material* colorized = NULL; if (model_name.size() > 0) { mesh = irr_driver->getMesh(model_name); if (mesh != NULL) { for (u32 j = 0; j < mesh->getMeshBufferCount(); j++) { SP::SPMeshBuffer* mb = static_cast<SP::SPMeshBuffer*> (mesh->getMeshBuffer(j)); std::vector<Material*> mbs = mb->getAllSTKMaterials(); for (Material* m : mbs) { if (m->isColorizable() && m->hasRandomHue()) { colorized = m; break; } } if (colorized != NULL) { break; } } } } else { std::string group_name = ""; xml_node.get("lod_group", &group_name); // Try to get the first mesh from lod groups mesh = model_def_loader.getFirstMeshFor(group_name); if (mesh != NULL) { for (u32 j = 0; j < mesh->getMeshBufferCount(); j++) { SP::SPMeshBuffer* mb = static_cast<SP::SPMeshBuffer*> (mesh->getMeshBuffer(j)); std::vector<Material*> mbs = mb->getAllSTKMaterials(); for (Material* m : mbs) { if (m->isColorizable() && m->hasRandomHue()) { colorized = m; break; } } if (colorized != NULL) { break; } } } } // If at least one material is colorizable, add RenderInfo for it if (colorized != NULL) { const float hue = colorized->getRandomHue(); if (hue > 0.0f) { m_render_info = std::make_shared<RenderInfo>(hue); } } } #endif scene::ISceneNode *glownode = NULL; bool is_movable = false; if (lod_instance) { m_type = "lod"; TrackObjectPresentationLOD* lod_node = new TrackObjectPresentationLOD(xml_node, parent, model_def_loader, m_render_info); m_presentation = lod_node; LODNode* node = (LODNode*)lod_node->getNode(); if (type == "movable" && parent != NULL) { // HACK: unparent movables from their parent library object if any, // because bullet provides absolute transforms, not transforms relative // to the parent object node->updateAbsolutePosition(); core::matrix4 absTransform = node->getAbsoluteTransformation(); node->setParent(irr_driver->getSceneManager()->getRootSceneNode()); node->setPosition(absTransform.getTranslation()); node->setRotation(absTransform.getRotationDegrees()); node->setScale(absTransform.getScale()); } glownode = node->getAllNodes()[0]; } else { m_type = "mesh"; m_presentation = new TrackObjectPresentationMesh(xml_node, m_enabled, parent, m_render_info); scene::ISceneNode* node = ((TrackObjectPresentationMesh *)m_presentation)->getNode(); if (type == "movable" && parent != NULL) { // HACK: unparent movables from their parent library object if any, // because bullet provides absolute transforms, not transforms relative // to the parent object node->updateAbsolutePosition(); core::matrix4 absTransform = node->getAbsoluteTransformation(); node->setParent(irr_driver->getSceneManager()->getRootSceneNode()); node->setPosition(absTransform.getTranslation()); // Doesn't seem necessary to set rotation here, TODO: not sure why //node->setRotation(absTransform.getRotationDegrees()); node->setScale(absTransform.getScale()); is_movable = true; } glownode = node; } std::string render_pass; xml_node.get("renderpass", &render_pass); if (m_interaction != "ghost" && m_interaction != "none" && render_pass != "skybox" ) { m_physical_object = PhysicalObject::fromXML(type == "movable", xml_node, this); } if (parent_library != NULL) { if (is_movable) parent_library->addMovableChild(this); else parent_library->addChild(this); } video::SColor glow; if (xml_node.get("glow", &glow) && glownode) { float r, g, b; r = glow.getRed() / 255.0f; g = glow.getGreen() / 255.0f; b = glow.getBlue() / 255.0f; SP::SPMeshNode* spmn = dynamic_cast<SP::SPMeshNode*>(glownode); if (spmn) { spmn->setGlowColor(video::SColorf(r, g, b)); } } bool is_in_shadowpass = true; if (xml_node.get("shadow-pass", &is_in_shadowpass) && glownode) { SP::SPMeshNode* spmn = dynamic_cast<SP::SPMeshNode*>(glownode); if (spmn) { spmn->setInShadowPass(is_in_shadowpass); } } bool forcedbloom = false; if (xml_node.get("forcedbloom", &forcedbloom) && forcedbloom && glownode) { float power = 1; xml_node.get("bloompower", &power); btClamp(power, 0.5f, 10.0f); irr_driver->addForcedBloomNode(glownode, power); } } if (type == "animation" || xml_node.hasChildNamed("curve")) { m_animator = new ThreeDAnimation(xml_node, this); } reset(); if (!m_initially_visible) setEnabled(false); if (parent_library != NULL && !parent_library->isEnabled()) setEnabled(false); } // TrackObject
void GrandPrixWin::setKarts(const std::string idents_arg[3]) { TrackObjectManager* tobjman = Track::getCurrentTrack()->getTrackObjectManager(); // reorder in "podium order" (i.e. second player to the left, first player // in the middle, last at the right) std::string idents[3]; idents[0] = idents_arg[1]; idents[1] = idents_arg[0]; idents[2] = idents_arg[2]; for (int i = 0; i < 3; i++) { const KartProperties* kp = kart_properties_manager->getKart(idents[i]); if (kp == NULL) continue; KartModel* kart_model = kp->getKartModelCopy(); m_all_kart_models.push_back(kart_model); scene::ISceneNode* kart_main_node = kart_model->attachModel(true, false); LODNode* lnode = dynamic_cast<LODNode*>(kart_main_node); if (lnode) { // Lod node has to be animated auto* a_node = static_cast<scene::IAnimatedMeshSceneNode*> (lnode->getAllNodes()[0]); const unsigned start_frame = kart_model->getFrame(KartModel::AF_WIN_LOOP_START) > -1 ? kart_model->getFrame(KartModel::AF_WIN_LOOP_START) : kart_model->getFrame(KartModel::AF_WIN_START) > -1 ? kart_model->getFrame(KartModel::AF_WIN_START) : kart_model->getFrame(KartModel::AF_STRAIGHT); const unsigned end_frame = kart_model->getFrame(KartModel::AF_WIN_END) > -1 ? kart_model->getFrame(KartModel::AF_WIN_END) : kart_model->getFrame(KartModel::AF_STRAIGHT); a_node->setLoopMode(true); a_node->setFrameLoop(start_frame, end_frame); } m_kart_x[i] = KARTS_INITIAL_X[i]; m_kart_y[i] = KARTS_INITIAL_Y[i]; m_kart_z[i] = KARTS_INITIAL_Z[i]; m_kart_rotation[i] = KARTS_AND_PODIUMS_INITIAL_ROTATION[i]; core::vector3df kart_pos(m_kart_x[i], m_kart_y[i], m_kart_z[i]); core::vector3df kart_rot(0, 0, 0); core::vector3df kart_scale(1.0f, 1.0f, 1.0f); //FIXME: it's not ideal that both the track object and the presentation // know the initial coordinates of the object TrackObjectPresentationSceneNode* presentation = new TrackObjectPresentationSceneNode(kart_pos, kart_rot, kart_scale, kart_main_node); TrackObject* tobj = new TrackObject(kart_pos, kart_rot, kart_scale, "ghost", presentation, false /* isDynamic */, NULL /* physics settings */); tobjman->insertObject(tobj); m_kart_node[i] = tobj; } TrackObject* currObj; PtrVector<TrackObject>& objects = tobjman->getObjects(); for_in(currObj, objects) { TrackObjectPresentationMesh* meshPresentation = currObj->getPresentation<TrackObjectPresentationMesh>(); if (meshPresentation != NULL) { if (meshPresentation->getModelFile() == "gpwin_podium1.spm") m_podium_steps[0] = currObj; else if (meshPresentation->getModelFile() == "gpwin_podium2.spm") m_podium_steps[1] = currObj; else if (meshPresentation->getModelFile() == "gpwin_podium3.spm") m_podium_steps[2] = currObj; } }
/** Initialises the track object based on the specified XML data. * \param xml_node The XML data. * \param parent The parent scene node. * \param model_def_loader Used to load level-of-detail nodes. */ void TrackObject::init(const XMLNode &xml_node, scene::ISceneNode* parent, ModelDefinitionLoader& model_def_loader, TrackObject* parent_library) { m_init_xyz = core::vector3df(0,0,0); m_init_hpr = core::vector3df(0,0,0); m_init_scale = core::vector3df(1,1,1); m_enabled = true; m_initially_visible = false; m_presentation = NULL; m_animator = NULL; m_parent_library = parent_library; m_physical_object = NULL; xml_node.get("id", &m_id ); xml_node.get("model", &m_name ); xml_node.get("xyz", &m_init_xyz ); xml_node.get("hpr", &m_init_hpr ); xml_node.get("scale", &m_init_scale); xml_node.get("enabled", &m_enabled ); m_interaction = "static"; xml_node.get("interaction", &m_interaction); xml_node.get("lod_group", &m_lod_group); m_is_driveable = false; xml_node.get("driveable", &m_is_driveable); bool lod_instance = false; xml_node.get("lod_instance", &lod_instance); m_soccer_ball = false; xml_node.get("soccer_ball", &m_soccer_ball); std::string type; xml_node.get("type", &type ); m_type = type; m_initially_visible = true; xml_node.get("if", &m_visibility_condition); if (m_visibility_condition == "false") { m_initially_visible = false; } if (!m_initially_visible) setEnabled(false); if (xml_node.getName() == "particle-emitter") { m_type = "particle-emitter"; m_presentation = new TrackObjectPresentationParticles(xml_node, parent); } else if (xml_node.getName() == "light") { m_type = "light"; m_presentation = new TrackObjectPresentationLight(xml_node, parent); } else if (xml_node.getName() == "library") { m_presentation = new TrackObjectPresentationLibraryNode(this, xml_node, model_def_loader); } else if (type == "sfx-emitter") { // FIXME: at this time sound emitters are just disabled in multiplayer // otherwise the sounds would be constantly heard if (race_manager->getNumLocalPlayers() < 2) m_presentation = new TrackObjectPresentationSound(xml_node, parent); } else if (type == "action-trigger") { std::string action; xml_node.get("action", &action); m_name = action; //adds action as name so that it can be found by using getName() m_presentation = new TrackObjectPresentationActionTrigger(xml_node); } else if (type == "billboard") { m_presentation = new TrackObjectPresentationBillboard(xml_node, parent); } else if (type=="cutscene_camera") { m_presentation = new TrackObjectPresentationEmpty(xml_node); } else { scene::ISceneNode *glownode = NULL; bool is_movable = false; if (lod_instance) { m_type = "lod"; TrackObjectPresentationLOD* lod_node = new TrackObjectPresentationLOD(xml_node, parent, model_def_loader); m_presentation = lod_node; LODNode* node = (LODNode*)lod_node->getNode(); if (type == "movable" && parent != NULL) { // HACK: unparent movables from their parent library object if any, // because bullet provides absolute transforms, not transforms relative // to the parent object node->updateAbsolutePosition(); core::matrix4 absTransform = node->getAbsoluteTransformation(); node->setParent(irr_driver->getSceneManager()->getRootSceneNode()); node->setPosition(absTransform.getTranslation()); node->setRotation(absTransform.getRotationDegrees()); node->setScale(absTransform.getScale()); } glownode = node->getAllNodes()[0]; } else { m_type = "mesh"; m_presentation = new TrackObjectPresentationMesh(xml_node, m_enabled, parent); scene::ISceneNode* node = ((TrackObjectPresentationMesh *)m_presentation)->getNode(); if (type == "movable" && parent != NULL) { // HACK: unparent movables from their parent library object if any, // because bullet provides absolute transforms, not transforms relative // to the parent object node->updateAbsolutePosition(); core::matrix4 absTransform = node->getAbsoluteTransformation(); node->setParent(irr_driver->getSceneManager()->getRootSceneNode()); node->setPosition(absTransform.getTranslation()); node->setRotation(absTransform.getRotationDegrees()); node->setScale(absTransform.getScale()); is_movable = true; } glownode = node; } std::string render_pass; xml_node.get("renderpass", &render_pass); if (m_interaction != "ghost" && m_interaction != "none" && render_pass != "skybox" ) { m_physical_object = PhysicalObject::fromXML(type == "movable", xml_node, this); } if (parent_library != NULL) { if (is_movable) parent_library->addMovableChild(this); else parent_library->addChild(this); } video::SColor glow; if (xml_node.get("glow", &glow) && glownode) { float r, g, b; r = glow.getRed() / 255.0f; g = glow.getGreen() / 255.0f; b = glow.getBlue() / 255.0f; irr_driver->addGlowingNode(glownode, r, g, b); } bool forcedbloom = false; if (xml_node.get("forcedbloom", &forcedbloom) && forcedbloom && glownode) { float power = 1; xml_node.get("bloompower", &power); power = clampf(power, 0.5f, 10); irr_driver->addForcedBloomNode(glownode, power); } } if (type == "animation" || xml_node.hasChildNamed("curve")) { m_animator = new ThreeDAnimation(xml_node, this); } reset(); if (!m_initially_visible) setEnabled(false); if (parent_library != NULL && !parent_library->isEnabled()) setEnabled(false); } // TrackObject