void MCObjectTest::testVelocityAndPreventSleeping()
{
    MCWorld world;
    MCObject object("TestObject");
    object.addToWorld();

    object.physicsComponent().setVelocity(MCVector3dF(1, 1, 1));

    QVERIFY(object.physicsComponent().isSleeping() == false);
    QVERIFY(object.index() >= 0);
    vector3dCompare(object.physicsComponent().velocity(), MCVector3dF(1, 1, 1));

    object.physicsComponent().preventSleeping(true);

    object.physicsComponent().setVelocity(MCVector3dF(0, 0, 0));

    vector3dCompare(object.physicsComponent().velocity(), MCVector3dF(0, 0, 0));

    world.stepTime(1);
    QVERIFY(object.physicsComponent().isSleeping() == false);
    QVERIFY(object.index() >= 0);

    object.physicsComponent().preventSleeping(false);

    world.stepTime(1);
    QVERIFY(object.physicsComponent().isSleeping() == true);
    QVERIFY(object.index() == -1);
}
void MCObjectTest::testChildTranslate()
{
    MCWorld world;
    world.setDimensions(0, 1024, 0, 768, 0, 100, 1);

    MCObject root("root");
    MCObjectPtr child1(new MCObject("child1"));
    MCObjectPtr child2(new MCObject("child2"));

    root.addChildObject(child1, MCVector3dF(1, 1, 1));
    root.addChildObject(child2, MCVector3dF(2, 2, 2));

    root.addToWorld();

    // Root at (0, 0, 0)

    vector3dCompare(root.location(), MCVector3dF(0, 0, 0));
    vector3dCompare(child1->location(), MCVector3dF(0, 0, 0));
    vector3dCompare(child2->location(), MCVector3dF(0, 0, 0));

    // Now move the root

    root.translate(MCVector3dF(1, 2, 3)); // Translate children only when root translates

    vector3dCompare(root.location(), MCVector3dF(1, 2, 3));
    vector3dCompare(child1->location(), MCVector3dF(2, 3, 4));
    vector3dCompare(child2->location(), MCVector3dF(3, 4, 5));
}
void MCObjectTest::testTranslate()
{
    MCWorld world;
    MCObject object("TestObject");
    object.addToWorld();

    vector3dCompare(object.location(), MCVector3dF(0, 0, 0));

    object.translate(MCVector3dF(1, 2, 3));

    vector3dCompare(object.location(), MCVector3dF(1, 2, 3));
}
void MCObjectTest::testInitialLocation()
{
    MCObject object("TestObject");
    vector3dCompare(object.initialLocation(), MCVector3dF(0, 0, 0));
    const MCVector3dF initialLocation(1, 2, 3);
    object.setInitialLocation(initialLocation);
    vector3dCompare(object.initialLocation(), initialLocation);
}
void MCObjectTest::testChildRotate()
{
    MCWorld world;
    world.setDimensions(0, 1024, 0, 768, 0, 100, 1);

    MCObject root("root");
    MCObjectPtr child1(new MCObject("child1"));
    MCObjectPtr child2(new MCObject("child2"));

    float child1Angle = 45;
    root.addChildObject(child1, MCVector3dF(1, 1, 1), child1Angle);

    const float child2Angle = 90;
    root.addChildObject(child2, MCVector3dF(2, 2, 2), 90);

    root.addToWorld();

    // Root at (0, 0, 0)

    const float rootAngle = 69;
    root.rotate(rootAngle); // Rotate children only when root rotates

    QVERIFY(root.angle() == rootAngle);
    QVERIFY(child1->angle() == child1Angle + rootAngle);
    QVERIFY(child2->angle() == child2Angle + rootAngle);

    vector3dCompare(child1->location(),
        MCVector3dF(MCTrigonom::rotatedVector(MCVector2dF(1.0, 1.0), rootAngle), 1.0f));

    vector3dCompare(child2->location(),
        MCVector3dF(MCTrigonom::rotatedVector(MCVector2dF(2.0, 2.0), rootAngle), 2.0f));

    // Now move the root

    const MCVector3dF rootLocation(3, 4, 5);
    root.translate(rootLocation);

    QVERIFY(root.angle() == rootAngle);
    QVERIFY(child1->angle() == child1Angle + rootAngle);
    QVERIFY(child2->angle() == child2Angle + rootAngle);

    vector3dCompare(child1->location(),
        rootLocation + MCVector3dF(MCTrigonom::rotatedVector(MCVector2dF(1.0, 1.0), rootAngle), 1.0f));

    vector3dCompare(child2->location(),
        rootLocation + MCVector3dF(MCTrigonom::rotatedVector(MCVector2dF(2.0, 2.0), rootAngle), 2.0f));

    // Rotate child relatively

    child1Angle = 47;
    child1->rotateRelative(child1Angle);
    root.translate(rootLocation);

    vector3dCompare(child1->location(),
        rootLocation + MCVector3dF(MCTrigonom::rotatedVector(MCVector2dF(1.0, 1.0), rootAngle), 1.0f));

    QVERIFY(child1->angle() == rootAngle + child1Angle);
}
void MCObjectTest::testVelocityIntegration()
{
    MCWorld world;
    world.setDimensions(0, 1024, 0, 768, 0, 100, 1);
    MCObject object("TestObject");
    object.addToWorld();

    vector3dCompare(object.location(), MCVector3dF(0, 0, 0));
    vector3dCompare(object.physicsComponent().velocity(), MCVector3dF(0, 0, 0));

    MCVector3dF velocity(1, 2, 3);
    object.physicsComponent().setVelocity(velocity);

    world.stepTime(1);

    vector3dCompare(object.location(), velocity * DAMPING);
    const MCVector3dF location = object.location();

    world.stepTime(1);
    velocity *= DAMPING;

    vector3dCompare(object.location(), location + velocity * DAMPING);
}
void StartlightsOverlay::renderLights(int rows, int litRows, float glowScale, bool glowAlways) const
{
    const int cols = 8;

    const float x = m_model.pos().i() - (cols - 1) * m_startLightOn.width()  / 2;
    const float y = m_model.pos().j() - (rows - 1) * m_startLightOn.height() / 2;
    const float h = rows * m_startLightOn.height();

    // Body
    for (int row = 0; row < rows; row++)
    {
        for (int col = 0; col < cols; col++)
        {
            const MCVector3dF pos(
                x + col * m_startLightOff.width(),
                y + h - row * m_startLightOff.height());

            if (row < litRows)
            {
                if (row == 0 && col == 0)
                {
                    m_startLightOnCorner.render(nullptr, pos, 0);
                }
                else if (row == rows - 1 && col == 0)
                {
                    m_startLightOnCorner.render(nullptr, pos, 90);
                }
                else if (row == rows - 1 && col == cols - 1)
                {
                    m_startLightOnCorner.render(nullptr, pos, 180);
                }
                else if (row == 0 && col == cols - 1)
                {
                    m_startLightOnCorner.render(nullptr, pos, 270);
                }
                else
                {
                    m_startLightOn.render(nullptr, pos, 0);
                }
            }
            else
            {
                if (row == 0 && col == 0)
                {
                    m_startLightOffCorner.render(nullptr, pos, 0);
                }
                else if (row == rows - 1 && col == 0)
                {
                    m_startLightOffCorner.render(nullptr, pos, 90);
                }
                else if (row == rows - 1 && col == cols - 1)
                {
                    m_startLightOffCorner.render(nullptr, pos, 180);
                }
                else if (row == 0 && col == cols - 1)
                {
                    m_startLightOffCorner.render(nullptr, pos, 270);
                }
                else
                {
                    m_startLightOff.render(nullptr, pos, 0);
                }
            }
        }
    }

    // Glow
    for (int row = 0; row < rows; row++)
    {
        for (int col = 0; col < cols; col++)
        {
            if (row < litRows || glowAlways)
            {
                m_startLightGlow.setScale(MCVector3dF(glowScale, glowScale, 1.0f));
                m_startLightGlow.render(
                    nullptr,
                    MCVector3dF(
                        x + col * m_startLightOn.width(),
                        y + h - row * m_startLightOn.height()),
                    0);
            }
        }
    }
}
Exemple #8
0
void Minimap::initialize(Car & carToFollow, const MapBase & trackMap, int x, int y, int size)
{
    m_carToFollow = &carToFollow;

    m_center = MCVector3dF(x, y);

    // Set m_tileW and m_tileH so that they are squares
    m_tileW = size / trackMap.cols();
    m_tileH = size / trackMap.rows();

    if (m_tileW > m_tileH)
    {
        m_tileW = m_tileH;
    }
    else
    {
        m_tileH = m_tileW;
    }

    float initX, initY;

    // Center the map
    if (trackMap.cols() % 2 == 0)
    {
        initX = x - trackMap.cols() * m_tileW / 2 + m_tileW / 4;
    }
    else
    {
        initX = x - trackMap.cols() * m_tileW / 2;
    }

    initY = y - trackMap.rows() * m_tileH / 2;

    m_map.clear();

    // Loop through the visible tile matrix and store relevant tiles
    float tileX, tileY;
    tileY = initY;
    for (unsigned int j = 0; j < trackMap.rows(); j++)
    {
        tileX = initX;
        for (unsigned int i = 0; i < trackMap.cols(); i++)
        {
            auto tile = std::static_pointer_cast<TrackTile>(trackMap.getTile(i, j));
            auto surface = tile->previewSurface();
            if (surface && !tile->excludeFromMinimap())
            {
                surface->setShaderProgram(Renderer::instance().program("menu"));
                surface->setColor(MCGLColor(1.0, 1.0, 1.0));
                surface->setSize(m_tileH, m_tileW);

                MinimapTile minimapTile;
                minimapTile.pos = MCVector3dF(tileX + m_tileW / 2, tileY + m_tileH / 2);
                minimapTile.rotation = tile->rotation();

                m_map[surface].push_back(minimapTile);
            }

            tileX += m_tileW;
        }

        tileY += m_tileH;
    }

    m_sceneW = trackMap.cols() * TrackTile::TILE_W;
    m_sceneH = trackMap.rows() * TrackTile::TILE_H;

    m_size = MCVector3dF(trackMap.cols() * m_tileW, trackMap.rows() * m_tileH);
}
TrackObject * TrackObjectFactory::build(
    QString category, QString role, MCVector2dF location, int angle)
{
    MCObjectPtr object;

    if (role == "brake" || role == "left" || role == "right")
    {
        MCSurfaceObjectData data(role.toStdString());
        data.setInitialLocation(location);
        data.setInitialAngle(angle);
        data.setBatchMode(true);
        data.setXYFriction(1.0);
        data.setRestitution(0.5);
        data.setMass(1000);
        data.setSurfaceId(role.toStdString());
        data.setRenderLayer(static_cast<int>(Layers::Render::Objects));

        object = m_objectFactory.build(data);
        object->shape()->view()->setShaderProgram(Renderer::instance().program("defaultSpecular"));

        // Wrap the MCObject in a TrackObject
        return new TrackObject(category, role, object);
    }
    else if (role == "bushArea")
    {
        MCSurfaceObjectData data(role.toStdString());
        data.setInitialLocation(location);
        data.setInitialAngle(angle);
        data.setBatchMode(true);
        data.setIsStationary(true);
        data.setSurfaceId(role.toStdString());
        data.setRenderLayer(static_cast<int>(Layers::Render::Objects));

        object = m_objectFactory.build(data);
        object->setIsPhysicsObject(false);
    }
    else if (role == "crate")
    {
        MCMeshObjectData data(role.toStdString());
        data.setInitialLocation(MCVector3dF(location.i(), location.j(), 12));
        data.setInitialAngle(angle);
        data.setBatchMode(true);
        data.setXYFriction(1.0);
        data.setMass(1000);
        data.setMeshId(role.toStdString());
        data.setSurfaceId(role.toStdString());
        data.setRestitution(0.9);
        data.setRenderLayer(static_cast<int>(Layers::Render::Objects));

        object = m_objectFactory.build(data);
    }
    else if (role == "dustRacing2DBanner")
    {
        MCSurfaceObjectData data(role.toStdString());
        data.setInitialLocation(location);
        data.setInitialAngle(angle);
        data.setBatchMode(true);
        data.setXYFriction(1.0);
        data.setRestitution(0.5);
        data.setIsStationary(true);
        data.setSurfaceId(role.toStdString());
        data.setRenderLayer(static_cast<int>(Layers::Render::Objects));

        object = m_objectFactory.build(data);
        object->shape()->view()->setShaderProgram(Renderer::instance().program("defaultSpecular"));

        // Wrap the MCObject in a TrackObject
        return new TrackObject(category, role, object);
    }
    else if (role == "grandstand")
    {
        MCSurfaceObjectData data(role.toStdString());
        data.setInitialLocation(location);
        data.setInitialAngle(angle);
        data.setBatchMode(true);
        data.setXYFriction(1.0);
        data.setRestitution(0.5);
        data.setIsStationary(true);
        data.setSurfaceId(role.toStdString());
        data.setRenderLayer(static_cast<int>(Layers::Render::Objects));

        object = m_objectFactory.build(data);
    }
    else if (role == "plant")
    {
        const MCFloat plantBodyRadius = 4;

        MCSurfaceObjectData data(role.toStdString());
        data.setInitialLocation(location);
        data.setInitialAngle(angle);
        data.setBatchMode(true);
        data.setXYFriction(1.0);
        data.setIsStationary(true);
        data.setSurfaceId(role.toStdString());
        data.setRestitution(0.25);
        data.setShapeWidth(plantBodyRadius);
        data.setShapeHeight(plantBodyRadius);
        data.setRenderLayer(static_cast<int>(Layers::Render::Objects));

        object = m_objectFactory.build(data);
    }
    else if (role == "rock")
    {
        MCSurfaceObjectData data(role.toStdString());
        data.setInitialLocation(location);
        data.setInitialAngle(angle);
        data.setBatchMode(true);
        data.setXYFriction(1.0);
        data.setMass(5000);
        data.setSurfaceId(role.toStdString());
        data.setRestitution(0.9);
        data.setRenderLayer(static_cast<int>(Layers::Render::Objects));

        object = m_objectFactory.build(data);
    }
    else if (
        role == "grid"          ||
        role == "sandAreaCurve" ||
        role == "sandAreaBig")
    {
        MCSurfaceObjectData data(role.toStdString());
        data.setInitialLocation(location);
        data.setInitialAngle(angle);
        data.setBatchMode(true);
        data.setIsStationary(true);
        data.setSurfaceId(role.toStdString());
        data.setRenderLayer(static_cast<int>(Layers::Render::Ground));

        object = m_objectFactory.build(data);
        object->setIsPhysicsObject(false);
        object->shape()->view()->setHasShadow(false);
    }
    else if (role == "pit")
    {
        object = MCObjectPtr(new Pit(MCAssetManager::surfaceManager().surface("pit")));
        object->setInitialLocation(location);
        object->setInitialAngle(angle);
        object->physicsComponent().setMass(1, true); // Stationary
        object->setRenderLayer(static_cast<int>(Layers::Render::Ground));
        object->setIsPhysicsObject(false);
        object->setIsTriggerObject(true);
        object->shape()->view()->setHasShadow(false);
        object->shape()->view()->setBatchMode(true);
    }
    else if (role == "tire")
    {
        MCSurfaceObjectData data(role.toStdString());
        data.setDefaultCircleShape(true);
        data.setInitialLocation(location);
        data.setInitialAngle(angle);
        data.setBatchMode(true);
        data.setXYFriction(1.0);
        data.setRestitution(0.5);
        data.setMass(500); // Exaggerate the mass on purpose
        data.setSurfaceId(role.toStdString());
        data.setXYFriction(0.25);
        data.setRenderLayer(static_cast<int>(Layers::Render::Objects));

        object = m_objectFactory.build(data);
        object->shape()->view()->setShaderProgram(Renderer::instance().program("defaultSpecular"));

        // Wrap the MCObject in a TrackObject
        return new TrackObject(category, role, object);
    }
    else if (role == "tree")
    {
        const MCFloat treeViewRadius = 48;
        const MCFloat treeBodyRadius = 8;

        MCSurfaceObjectData data(role.toStdString());
        data.setInitialLocation(location);
        data.setInitialAngle(angle);
        data.setBatchMode(true);
        data.setXYFriction(1.0);
        data.setIsStationary(true);
        data.setRestitution(0.25);
        data.setShapeWidth(treeBodyRadius);
        data.setShapeHeight(treeBodyRadius);
        data.setRenderLayer(static_cast<int>(Layers::Render::Objects));

        // Create a custom view.
        MCShapeViewPtr view(new TreeView(
            MCAssetManager::surfaceManager().surface("tree"), treeViewRadius, 2, 120, 5));
        MCObjectPtr object = m_objectFactory.build(data, view);

        // Wrap the MCObject in a TrackObject
        return new TrackObject(category, role, object);
    }
    else if (role == "wall" || role == "wallLong")
    {
        MCSurfaceObjectData data(role.toStdString());
        data.setInitialLocation(location);
        data.setInitialAngle(angle);
        data.setBatchMode(true);
        data.setXYFriction(1.0);
        data.setIsStationary(true);
        data.setSurfaceId(role.toStdString());
        data.setRestitution(0.9);
        data.setRenderLayer(static_cast<int>(Layers::Render::Objects));
        data.setInitialLocation(MCVector3dF(location.i(), location.j(), 8));

        object = m_objectFactory.build(data);
        object->shape()->view()->setShaderProgram(Renderer::instance().program("defaultSpecular"));

        // Wrap the MCObject in a TrackObject
        return new TrackObject(category, role, object);
    }

    if (!object)
    {
        MCLogger().warning() << "Unknown or deprecated object '" << role.toStdString() << "'";
        return nullptr;
    }
    else
    {
        // Wrap the MCObject in a TrackObject
        return new TrackObject(category, role, object);
    }
}