// ----------------------------------------------------------------------------
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
// ----------------------------------------------------------------------------
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;
        }
    }
Beispiel #5
0
/** 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