<commit_before>// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "config.h"
#include "core/rendering/style/GridResolvedPosition.h"

#include "core/rendering/RenderBox.h"
#include "core/rendering/style/GridCoordinate.h"

namespace blink {

static const NamedGridLinesMap& gridLinesForSide(const RenderStyle& style, GridPositionSide side)
{
    return (side == ColumnStartSide || side == ColumnEndSide) ? style.namedGridColumnLines() : style.namedGridRowLines();
}

static inline String implicitNamedGridLineForSide(const String& lineName, GridPositionSide side)
{
    return lineName + ((side == ColumnStartSide || side == RowStartSide) ? "-start" : "-end");
}

static bool isValidNamedLineOrArea(const String& lineName, const RenderStyle& style, GridPositionSide side)
{
    const NamedGridLinesMap& gridLineNames = gridLinesForSide(style, side);

    return gridLineNames.contains(implicitNamedGridLineForSide(lineName, side)) || gridLineNames.contains(lineName);
}

static GridPositionSide calculateInitialPositionSide(GridTrackSizingDirection direction)
{
    return (direction == ForColumns) ? ColumnStartSide : RowStartSide;
}

static GridPositionSide calculateFinalPositionSide(GridTrackSizingDirection direction)
{
    return (direction == ForColumns) ? ColumnEndSide : RowEndSide;
}

void GridResolvedPosition::initialAndFinalPositionsFromStyle(const RenderStyle& gridContainerStyle, const RenderBox& gridItem, GridTrackSizingDirection direction, GridPosition& initialPosition, GridPosition& finalPosition)
{
    initialPosition = (direction == ForColumns) ? gridItem.style()->gridColumnStart() : gridItem.style()->gridRowStart();
    finalPosition = (direction == ForColumns) ? gridItem.style()->gridColumnEnd() : gridItem.style()->gridRowEnd();
    GridPositionSide initialPositionSide = calculateInitialPositionSide(direction);
    GridPositionSide finalPositionSide = calculateFinalPositionSide(direction);

    // We must handle the placement error handling code here instead of in the StyleAdjuster because we don't want to
    // overwrite the specified values.
    if (initialPosition.isSpan() && finalPosition.isSpan())
        finalPosition.setAutoPosition();

    // Try to early detect the case of non existing named grid lines. This way we could assume later that
    // GridResolvedPosition::resolveGrisPositionFromStyle() always return a valid resolved position.
    if (initialPosition.isNamedGridArea() && !isValidNamedLineOrArea(initialPosition.namedGridLine(), gridContainerStyle, initialPositionSide))
        initialPosition.setAutoPosition();

    if (finalPosition.isNamedGridArea() && !isValidNamedLineOrArea(finalPosition.namedGridLine(), gridContainerStyle, finalPositionSide))
        finalPosition.setAutoPosition();

    // If the grid item has an automatic position and a grid span for a named line in a given dimension, instead treat the grid span as one.
    if (initialPosition.isAuto() && finalPosition.isSpan() && !finalPosition.namedGridLine().isNull())
        finalPosition.setSpanPosition(1, String());
    if (finalPosition.isAuto() && initialPosition.isSpan() && !initialPosition.namedGridLine().isNull())
        initialPosition.setSpanPosition(1, String());
}

GridSpan GridResolvedPosition::resolveGridPositionsFromAutoPlacementPosition(const RenderStyle& gridContainerStyle, const RenderBox& gridItem, GridTrackSizingDirection direction, const GridResolvedPosition& resolvedInitialPosition)
{
    GridPosition initialPosition, finalPosition;
    initialAndFinalPositionsFromStyle(gridContainerStyle, gridItem, direction, initialPosition, finalPosition);

    GridPositionSide finalPositionSide = calculateFinalPositionSide(direction);

    // This method will only be used when both positions need to be resolved against the opposite one.
    ASSERT(initialPosition.shouldBeResolvedAgainstOppositePosition() && finalPosition.shouldBeResolvedAgainstOppositePosition());

    GridResolvedPosition resolvedFinalPosition = resolvedInitialPosition;

    if (initialPosition.isSpan()) {
        resolvedFinalPosition = resolveGridPositionAgainstOppositePosition(gridContainerStyle, resolvedInitialPosition, initialPosition, finalPositionSide)->resolvedFinalPosition;
    } else if (finalPosition.isSpan()) {
        resolvedFinalPosition = resolveGridPositionAgainstOppositePosition(gridContainerStyle, resolvedInitialPosition, finalPosition, finalPositionSide)->resolvedFinalPosition;
    }

    return GridSpan(resolvedInitialPosition, resolvedFinalPosition);
}

PassOwnPtr<GridSpan> GridResolvedPosition::resolveGridPositionsFromStyle(const RenderStyle& gridContainerStyle, const RenderBox& gridItem, GridTrackSizingDirection direction)
{
    GridPosition initialPosition, finalPosition;
    initialAndFinalPositionsFromStyle(gridContainerStyle, gridItem, direction, initialPosition, finalPosition);

    GridPositionSide initialPositionSide = calculateInitialPositionSide(direction);
    GridPositionSide finalPositionSide = calculateFinalPositionSide(direction);

    if (initialPosition.shouldBeResolvedAgainstOppositePosition() && finalPosition.shouldBeResolvedAgainstOppositePosition()) {
        // FIXME: Implement properly "stack" value in auto-placement algorithm.
        if (gridContainerStyle.isGridAutoFlowAlgorithmStack())
            return adoptPtr(new GridSpan(0, 0));

        // We can't get our grid positions without running the auto placement algorithm.
        return nullptr;
    }

    if (initialPosition.shouldBeResolvedAgainstOppositePosition()) {
        // Infer the position from the final position ('auto / 1' or 'span 2 / 3' case).
        GridResolvedPosition finalResolvedPosition = resolveGridPositionFromStyle(gridContainerStyle, finalPosition, finalPositionSide);
        return resolveGridPositionAgainstOppositePosition(gridContainerStyle, finalResolvedPosition, initialPosition, initialPositionSide);
    }

    if (finalPosition.shouldBeResolvedAgainstOppositePosition()) {
        // Infer our position from the initial position ('1 / auto' or '3 / span 2' case).
        GridResolvedPosition initialResolvedPosition = resolveGridPositionFromStyle(gridContainerStyle, initialPosition, initialPositionSide);
        return resolveGridPositionAgainstOppositePosition(gridContainerStyle, initialResolvedPosition, finalPosition, finalPositionSide);
    }

    GridResolvedPosition resolvedInitialPosition = resolveGridPositionFromStyle(gridContainerStyle, initialPosition, initialPositionSide);
    GridResolvedPosition resolvedFinalPosition = resolveGridPositionFromStyle(gridContainerStyle, finalPosition, finalPositionSide);

    // If 'grid-after' specifies a line at or before that specified by 'grid-before', it computes to 'span 1'.
    if (resolvedFinalPosition < resolvedInitialPosition)
        resolvedFinalPosition = resolvedInitialPosition;

    return adoptPtr(new GridSpan(resolvedInitialPosition, resolvedFinalPosition));
}

size_t GridResolvedPosition::explicitGridColumnCount(const RenderStyle& gridContainerStyle)
{
    return std::min(gridContainerStyle.gridTemplateColumns().size(), kGridMaxTracks);
}

size_t GridResolvedPosition::explicitGridRowCount(const RenderStyle& gridContainerStyle)
{
    return std::min(gridContainerStyle.gridTemplateRows().size(), kGridMaxTracks);
}

size_t GridResolvedPosition::explicitGridSizeForSide(const RenderStyle& gridContainerStyle, GridPositionSide side)
{
    return (side == ColumnStartSide || side == ColumnEndSide) ? explicitGridColumnCount(gridContainerStyle) : explicitGridRowCount(gridContainerStyle);
}

GridResolvedPosition GridResolvedPosition::resolveNamedGridLinePositionFromStyle(const RenderStyle& gridContainerStyle, const GridPosition& position, GridPositionSide side)
{
    ASSERT(!position.namedGridLine().isNull());

    const NamedGridLinesMap& gridLinesNames = gridLinesForSide(gridContainerStyle, side);
    NamedGridLinesMap::const_iterator it = gridLinesNames.find(position.namedGridLine());
    if (it == gridLinesNames.end()) {
        if (position.isPositive())
            return GridResolvedPosition(0);
        const size_t lastLine = explicitGridSizeForSide(gridContainerStyle, side);
        return adjustGridPositionForSide(lastLine, side);
    }

    size_t namedGridLineIndex;
    if (position.isPositive())
        namedGridLineIndex = std::min<size_t>(position.integerPosition(), it->value.size()) - 1;
    else
        namedGridLineIndex = std::max<int>(it->value.size() - abs(position.integerPosition()), 0);
    return adjustGridPositionForSide(it->value[namedGridLineIndex], side);
}

GridResolvedPosition GridResolvedPosition::resolveGridPositionFromStyle(const RenderStyle& gridContainerStyle, const GridPosition& position, GridPositionSide side)
{
    switch (position.type()) {
    case ExplicitPosition: {
        ASSERT(position.integerPosition());

        if (!position.namedGridLine().isNull())
            return resolveNamedGridLinePositionFromStyle(gridContainerStyle, position, side);

        // Handle <integer> explicit position.
        if (position.isPositive())
            return adjustGridPositionForSide(position.integerPosition() - 1, side);

        size_t resolvedPosition = abs(position.integerPosition()) - 1;
        const size_t endOfTrack = explicitGridSizeForSide(gridContainerStyle, side);

        // Per http://lists.w3.org/Archives/Public/www-style/2013Mar/0589.html, we clamp negative value to the first line.
        if (endOfTrack < resolvedPosition)
            return GridResolvedPosition(0);

        return adjustGridPositionForSide(endOfTrack - resolvedPosition, side);
    }
    case NamedGridAreaPosition:
    {
        // First attempt to match the grid area’s edge to a named grid area: if there is a named line with the name
        // ''<custom-ident>-start (for grid-*-start) / <custom-ident>-end'' (for grid-*-end), contributes the first such
        // line to the grid item’s placement.
        String namedGridLine = position.namedGridLine();
        ASSERT(isValidNamedLineOrArea(namedGridLine, gridContainerStyle, side));

        const NamedGridLinesMap& gridLineNames = gridLinesForSide(gridContainerStyle, side);
        NamedGridLinesMap::const_iterator implicitLineIter = gridLineNames.find(implicitNamedGridLineForSide(namedGridLine, side));
        if (implicitLineIter != gridLineNames.end())
            return adjustGridPositionForSide(implicitLineIter->value[0], side);

        // Otherwise, if there is a named line with the specified name, contributes the first such line to the grid
        // item’s placement.
        NamedGridLinesMap::const_iterator explicitLineIter = gridLineNames.find(namedGridLine);
        if (explicitLineIter != gridLineNames.end())
            return adjustGridPositionForSide(explicitLineIter->value[0], side);

        // If none of the above works specs mandate us to treat it as auto BUT we should have detected it before calling
        // this function in GridResolvedPosition::resolveGridPositionsFromStyle(). We should be also covered by the
        // ASSERT at the beginning of this block.
        ASSERT_NOT_REACHED();
        return GridResolvedPosition(0);
    }
    case AutoPosition:
    case SpanPosition:
        // 'auto' and span depend on the opposite position for resolution (e.g. grid-row: auto / 1 or grid-column: span 3 / "myHeader").
        ASSERT_NOT_REACHED();
        return GridResolvedPosition(0);
    }
    ASSERT_NOT_REACHED();
    return GridResolvedPosition(0);
}

PassOwnPtr<GridSpan> GridResolvedPosition::resolveGridPositionAgainstOppositePosition(const RenderStyle& gridContainerStyle, const GridResolvedPosition& resolvedOppositePosition, const GridPosition& position, GridPositionSide side)
{
    if (position.isAuto())
        return GridSpan::create(resolvedOppositePosition, resolvedOppositePosition);

    ASSERT(position.isSpan());
    ASSERT(position.spanPosition() > 0);

    if (!position.namedGridLine().isNull()) {
        // span 2 'c' -> we need to find the appropriate grid line before / after our opposite position.
        return resolveNamedGridLinePositionAgainstOppositePosition(gridContainerStyle, resolvedOppositePosition, position, side);
    }

    return GridSpan::createWithSpanAgainstOpposite(resolvedOppositePosition, position, side);
}

PassOwnPtr<GridSpan> GridResolvedPosition::resolveNamedGridLinePositionAgainstOppositePosition(const RenderStyle& gridContainerStyle, const GridResolvedPosition& resolvedOppositePosition, const GridPosition& position, GridPositionSide side)
{
    ASSERT(position.isSpan());
    ASSERT(!position.namedGridLine().isNull());
    // Negative positions are not allowed per the specification and should have been handled during parsing.
    ASSERT(position.spanPosition() > 0);

    const NamedGridLinesMap& gridLinesNames = gridLinesForSide(gridContainerStyle, side);
    NamedGridLinesMap::const_iterator it = gridLinesNames.find(position.namedGridLine());

    // If there is no named grid line of that name, we resolve the position to 'auto' (which is equivalent to 'span 1' in this case).
    // See http://lists.w3.org/Archives/Public/www-style/2013Jun/0394.html.
    if (it == gridLinesNames.end())
        return GridSpan::create(resolvedOppositePosition, resolvedOppositePosition);

    return GridSpan::createWithNamedSpanAgainstOpposite(resolvedOppositePosition, position, side, it->value);
}

} // namespace blink
<commit_msg>[CSS Grid Layout] Crash when spanning an autoplaced item over grid limit<commit_after>// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "config.h"
#include "core/rendering/style/GridResolvedPosition.h"

#include "core/rendering/RenderBox.h"
#include "core/rendering/style/GridCoordinate.h"

namespace blink {

static const NamedGridLinesMap& gridLinesForSide(const RenderStyle& style, GridPositionSide side)
{
    return (side == ColumnStartSide || side == ColumnEndSide) ? style.namedGridColumnLines() : style.namedGridRowLines();
}

static inline String implicitNamedGridLineForSide(const String& lineName, GridPositionSide side)
{
    return lineName + ((side == ColumnStartSide || side == RowStartSide) ? "-start" : "-end");
}

static bool isValidNamedLineOrArea(const String& lineName, const RenderStyle& style, GridPositionSide side)
{
    const NamedGridLinesMap& gridLineNames = gridLinesForSide(style, side);

    return gridLineNames.contains(implicitNamedGridLineForSide(lineName, side)) || gridLineNames.contains(lineName);
}

static GridPositionSide calculateInitialPositionSide(GridTrackSizingDirection direction)
{
    return (direction == ForColumns) ? ColumnStartSide : RowStartSide;
}

static GridPositionSide calculateFinalPositionSide(GridTrackSizingDirection direction)
{
    return (direction == ForColumns) ? ColumnEndSide : RowEndSide;
}

void GridResolvedPosition::initialAndFinalPositionsFromStyle(const RenderStyle& gridContainerStyle, const RenderBox& gridItem, GridTrackSizingDirection direction, GridPosition& initialPosition, GridPosition& finalPosition)
{
    initialPosition = (direction == ForColumns) ? gridItem.style()->gridColumnStart() : gridItem.style()->gridRowStart();
    finalPosition = (direction == ForColumns) ? gridItem.style()->gridColumnEnd() : gridItem.style()->gridRowEnd();
    GridPositionSide initialPositionSide = calculateInitialPositionSide(direction);
    GridPositionSide finalPositionSide = calculateFinalPositionSide(direction);

    // We must handle the placement error handling code here instead of in the StyleAdjuster because we don't want to
    // overwrite the specified values.
    if (initialPosition.isSpan() && finalPosition.isSpan())
        finalPosition.setAutoPosition();

    // Try to early detect the case of non existing named grid lines. This way we could assume later that
    // GridResolvedPosition::resolveGrisPositionFromStyle() always return a valid resolved position.
    if (initialPosition.isNamedGridArea() && !isValidNamedLineOrArea(initialPosition.namedGridLine(), gridContainerStyle, initialPositionSide))
        initialPosition.setAutoPosition();

    if (finalPosition.isNamedGridArea() && !isValidNamedLineOrArea(finalPosition.namedGridLine(), gridContainerStyle, finalPositionSide))
        finalPosition.setAutoPosition();

    // If the grid item has an automatic position and a grid span for a named line in a given dimension, instead treat the grid span as one.
    if (initialPosition.isAuto() && finalPosition.isSpan() && !finalPosition.namedGridLine().isNull())
        finalPosition.setSpanPosition(1, String());
    if (finalPosition.isAuto() && initialPosition.isSpan() && !initialPosition.namedGridLine().isNull())
        initialPosition.setSpanPosition(1, String());
}

GridSpan GridResolvedPosition::resolveGridPositionsFromAutoPlacementPosition(const RenderStyle& gridContainerStyle, const RenderBox& gridItem, GridTrackSizingDirection direction, const GridResolvedPosition& resolvedInitialPosition)
{
    GridPosition initialPosition, finalPosition;
    initialAndFinalPositionsFromStyle(gridContainerStyle, gridItem, direction, initialPosition, finalPosition);

    GridPositionSide finalPositionSide = calculateFinalPositionSide(direction);

    // This method will only be used when both positions need to be resolved against the opposite one.
    ASSERT(initialPosition.shouldBeResolvedAgainstOppositePosition() && finalPosition.shouldBeResolvedAgainstOppositePosition());

    GridResolvedPosition resolvedFinalPosition = resolvedInitialPosition;

    if (initialPosition.isSpan()) {
        return *resolveGridPositionAgainstOppositePosition(gridContainerStyle, resolvedInitialPosition, initialPosition, finalPositionSide);
    } else if (finalPosition.isSpan()) {
        return *resolveGridPositionAgainstOppositePosition(gridContainerStyle, resolvedInitialPosition, finalPosition, finalPositionSide);
    }

    return GridSpan(resolvedInitialPosition, resolvedFinalPosition);
}

PassOwnPtr<GridSpan> GridResolvedPosition::resolveGridPositionsFromStyle(const RenderStyle& gridContainerStyle, const RenderBox& gridItem, GridTrackSizingDirection direction)
{
    GridPosition initialPosition, finalPosition;
    initialAndFinalPositionsFromStyle(gridContainerStyle, gridItem, direction, initialPosition, finalPosition);

    GridPositionSide initialPositionSide = calculateInitialPositionSide(direction);
    GridPositionSide finalPositionSide = calculateFinalPositionSide(direction);

    if (initialPosition.shouldBeResolvedAgainstOppositePosition() && finalPosition.shouldBeResolvedAgainstOppositePosition()) {
        // FIXME: Implement properly "stack" value in auto-placement algorithm.
        if (gridContainerStyle.isGridAutoFlowAlgorithmStack())
            return adoptPtr(new GridSpan(0, 0));

        // We can't get our grid positions without running the auto placement algorithm.
        return nullptr;
    }

    if (initialPosition.shouldBeResolvedAgainstOppositePosition()) {
        // Infer the position from the final position ('auto / 1' or 'span 2 / 3' case).
        GridResolvedPosition finalResolvedPosition = resolveGridPositionFromStyle(gridContainerStyle, finalPosition, finalPositionSide);
        return resolveGridPositionAgainstOppositePosition(gridContainerStyle, finalResolvedPosition, initialPosition, initialPositionSide);
    }

    if (finalPosition.shouldBeResolvedAgainstOppositePosition()) {
        // Infer our position from the initial position ('1 / auto' or '3 / span 2' case).
        GridResolvedPosition initialResolvedPosition = resolveGridPositionFromStyle(gridContainerStyle, initialPosition, initialPositionSide);
        return resolveGridPositionAgainstOppositePosition(gridContainerStyle, initialResolvedPosition, finalPosition, finalPositionSide);
    }

    GridResolvedPosition resolvedInitialPosition = resolveGridPositionFromStyle(gridContainerStyle, initialPosition, initialPositionSide);
    GridResolvedPosition resolvedFinalPosition = resolveGridPositionFromStyle(gridContainerStyle, finalPosition, finalPositionSide);

    // If 'grid-after' specifies a line at or before that specified by 'grid-before', it computes to 'span 1'.
    if (resolvedFinalPosition < resolvedInitialPosition)
        resolvedFinalPosition = resolvedInitialPosition;

    return adoptPtr(new GridSpan(resolvedInitialPosition, resolvedFinalPosition));
}

size_t GridResolvedPosition::explicitGridColumnCount(const RenderStyle& gridContainerStyle)
{
    return std::min(gridContainerStyle.gridTemplateColumns().size(), kGridMaxTracks);
}

size_t GridResolvedPosition::explicitGridRowCount(const RenderStyle& gridContainerStyle)
{
    return std::min(gridContainerStyle.gridTemplateRows().size(), kGridMaxTracks);
}

size_t GridResolvedPosition::explicitGridSizeForSide(const RenderStyle& gridContainerStyle, GridPositionSide side)
{
    return (side == ColumnStartSide || side == ColumnEndSide) ? explicitGridColumnCount(gridContainerStyle) : explicitGridRowCount(gridContainerStyle);
}

GridResolvedPosition GridResolvedPosition::resolveNamedGridLinePositionFromStyle(const RenderStyle& gridContainerStyle, const GridPosition& position, GridPositionSide side)
{
    ASSERT(!position.namedGridLine().isNull());

    const NamedGridLinesMap& gridLinesNames = gridLinesForSide(gridContainerStyle, side);
    NamedGridLinesMap::const_iterator it = gridLinesNames.find(position.namedGridLine());
    if (it == gridLinesNames.end()) {
        if (position.isPositive())
            return GridResolvedPosition(0);
        const size_t lastLine = explicitGridSizeForSide(gridContainerStyle, side);
        return adjustGridPositionForSide(lastLine, side);
    }

    size_t namedGridLineIndex;
    if (position.isPositive())
        namedGridLineIndex = std::min<size_t>(position.integerPosition(), it->value.size()) - 1;
    else
        namedGridLineIndex = std::max<int>(it->value.size() - abs(position.integerPosition()), 0);
    return adjustGridPositionForSide(it->value[namedGridLineIndex], side);
}

GridResolvedPosition GridResolvedPosition::resolveGridPositionFromStyle(const RenderStyle& gridContainerStyle, const GridPosition& position, GridPositionSide side)
{
    switch (position.type()) {
    case ExplicitPosition: {
        ASSERT(position.integerPosition());

        if (!position.namedGridLine().isNull())
            return resolveNamedGridLinePositionFromStyle(gridContainerStyle, position, side);

        // Handle <integer> explicit position.
        if (position.isPositive())
            return adjustGridPositionForSide(position.integerPosition() - 1, side);

        size_t resolvedPosition = abs(position.integerPosition()) - 1;
        const size_t endOfTrack = explicitGridSizeForSide(gridContainerStyle, side);

        // Per http://lists.w3.org/Archives/Public/www-style/2013Mar/0589.html, we clamp negative value to the first line.
        if (endOfTrack < resolvedPosition)
            return GridResolvedPosition(0);

        return adjustGridPositionForSide(endOfTrack - resolvedPosition, side);
    }
    case NamedGridAreaPosition:
    {
        // First attempt to match the grid area’s edge to a named grid area: if there is a named line with the name
        // ''<custom-ident>-start (for grid-*-start) / <custom-ident>-end'' (for grid-*-end), contributes the first such
        // line to the grid item’s placement.
        String namedGridLine = position.namedGridLine();
        ASSERT(isValidNamedLineOrArea(namedGridLine, gridContainerStyle, side));

        const NamedGridLinesMap& gridLineNames = gridLinesForSide(gridContainerStyle, side);
        NamedGridLinesMap::const_iterator implicitLineIter = gridLineNames.find(implicitNamedGridLineForSide(namedGridLine, side));
        if (implicitLineIter != gridLineNames.end())
            return adjustGridPositionForSide(implicitLineIter->value[0], side);

        // Otherwise, if there is a named line with the specified name, contributes the first such line to the grid
        // item’s placement.
        NamedGridLinesMap::const_iterator explicitLineIter = gridLineNames.find(namedGridLine);
        if (explicitLineIter != gridLineNames.end())
            return adjustGridPositionForSide(explicitLineIter->value[0], side);

        // If none of the above works specs mandate us to treat it as auto BUT we should have detected it before calling
        // this function in GridResolvedPosition::resolveGridPositionsFromStyle(). We should be also covered by the
        // ASSERT at the beginning of this block.
        ASSERT_NOT_REACHED();
        return GridResolvedPosition(0);
    }
    case AutoPosition:
    case SpanPosition:
        // 'auto' and span depend on the opposite position for resolution (e.g. grid-row: auto / 1 or grid-column: span 3 / "myHeader").
        ASSERT_NOT_REACHED();
        return GridResolvedPosition(0);
    }
    ASSERT_NOT_REACHED();
    return GridResolvedPosition(0);
}

PassOwnPtr<GridSpan> GridResolvedPosition::resolveGridPositionAgainstOppositePosition(const RenderStyle& gridContainerStyle, const GridResolvedPosition& resolvedOppositePosition, const GridPosition& position, GridPositionSide side)
{
    if (position.isAuto())
        return GridSpan::create(resolvedOppositePosition, resolvedOppositePosition);

    ASSERT(position.isSpan());
    ASSERT(position.spanPosition() > 0);

    if (!position.namedGridLine().isNull()) {
        // span 2 'c' -> we need to find the appropriate grid line before / after our opposite position.
        return resolveNamedGridLinePositionAgainstOppositePosition(gridContainerStyle, resolvedOppositePosition, position, side);
    }

    return GridSpan::createWithSpanAgainstOpposite(resolvedOppositePosition, position, side);
}

PassOwnPtr<GridSpan> GridResolvedPosition::resolveNamedGridLinePositionAgainstOppositePosition(const RenderStyle& gridContainerStyle, const GridResolvedPosition& resolvedOppositePosition, const GridPosition& position, GridPositionSide side)
{
    ASSERT(position.isSpan());
    ASSERT(!position.namedGridLine().isNull());
    // Negative positions are not allowed per the specification and should have been handled during parsing.
    ASSERT(position.spanPosition() > 0);

    const NamedGridLinesMap& gridLinesNames = gridLinesForSide(gridContainerStyle, side);
    NamedGridLinesMap::const_iterator it = gridLinesNames.find(position.namedGridLine());

    // If there is no named grid line of that name, we resolve the position to 'auto' (which is equivalent to 'span 1' in this case).
    // See http://lists.w3.org/Archives/Public/www-style/2013Jun/0394.html.
    if (it == gridLinesNames.end())
        return GridSpan::create(resolvedOppositePosition, resolvedOppositePosition);

    return GridSpan::createWithNamedSpanAgainstOpposite(resolvedOppositePosition, position, side, it->value);
}

} // namespace blink
<|endoftext|>


<commit_before>// BulletPhysicsSystem.cpp - Copyright 2013-2016 Will Cassella, All Rights Reserved

#include <BulletCollision/CollisionDispatch/btGhostObject.h>
#include <Engine/World.h>
#include "../include/BulletPhysics/BulletPhysicsSystem.h"
#include "DebugDrawer.h"
#include "PhysicsWorld.h"
#include "RigidBody.h"
#include "BulletTriangleMesh.h"

//////////////////////
///   Reflection   ///

BUILD_REFLECTION(Willow::BulletPhysicsSystem);

namespace Willow
{
	////////////////////////
	///   Constructors   ///

	BulletPhysicsSystem::BulletPhysicsSystem()
	{
		_physicsWorld = std::make_unique<PhysicsWorld>();
	}

	BulletPhysicsSystem::~BulletPhysicsSystem()
	{
		_physicsWorld = nullptr;
	}

	///////////////////
	///   Methods   ///

	void BulletPhysicsSystem::Update(const World& world)
	{
		_physicsWorld->GetDynamicsWorld().stepSimulation(world.TimeStep, 1);
	}

	void BulletPhysicsSystem::DebugDraw(RenderSystem& render)
	{
		DebugDrawer drawer{ render };
		_physicsWorld->GetDynamicsWorld().setDebugDrawer(&drawer);
		_physicsWorld->GetDynamicsWorld().debugDrawWorld();
		_physicsWorld->GetDynamicsWorld().setDebugDrawer(nullptr);
	}

	void BulletPhysicsSystem::CreateEntity(EntityHandle entity, EntityHandle parent, Transform& transform, Entity::PhysicsMode mode, Entity::PhysicsState state)
	{
		// Create the physics data for this Entity
		auto* data = _entityPhysicsData.New();
		_entityDataTable[entity] = data;
		data->State = state;
		data->Mode = mode;
		data->Parent = parent;
		data->Transform = &transform;

		// Set the entitie's collider scaling
		data->Collider.setLocalScaling(ConvertToBullet(transform.Scale));

		// If the entity is at least a ghost
		if (mode >= Entity::PhysicsMode::Ghost)
		{
			auto* ghost = _ghostBodies.New();
			ghost->setCollisionShape(&data->Collider);
			//_physicsWorld->GetDynamicsWorld().addCollisionObject(ghost);
			data->GhostBody = ghost;
		}

		// If the entity is at least kinematic
		if (mode >= Entity::PhysicsMode::Kinematic)
		{
			auto* rigidBody = _rigidBodies.New(*data);
			_physicsWorld->GetDynamicsWorld().addRigidBody(rigidBody);
			data->GhostBody->setIgnoreCollisionCheck(rigidBody, true);
			data->RigidBody = rigidBody;

			// If the entity IS kinematic
			if (mode == Entity::PhysicsMode::Kinematic)
			{
				rigidBody->setMassProps(0, { 0, 0, 0 });
				rigidBody->setActivationState(DISABLE_DEACTIVATION);
				rigidBody->setCollisionFlags(rigidBody->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT);
			}
		}
	}

	void BulletPhysicsSystem::DestroyEntity(EntityHandle /*entity*/)
	{
		// TODO
	}

	void BulletPhysicsSystem::SetEntityParent(EntityHandle /*entity*/, EntityHandle /*parent*/)
	{
		// TODO
	}

	void BulletPhysicsSystem::UpdateEntityTransform(EntityHandle entity)
	{
		_entityDataTable.Find(entity, [&](EntityPhysicsData* data)
		{
			data->Collider.setLocalScaling(ConvertToBullet(data->Transform->Scale));
			btTransform transform{ ConvertToBullet(data->Transform->Rotation), ConvertToBullet(data->Transform->Location) };

			// If we have a GhostBody
			if (data->GhostBody)
			{
				data->GhostBody->setWorldTransform(transform);
			}

			// If we have a RigidBody
			if (data->RigidBody)
			{
				data->RigidBody->setWorldTransform(transform);
			}
		});
	}

	void BulletPhysicsSystem::SetEntityPhysicsMode(EntityHandle entity, Entity::PhysicsMode mode)
	{
		_entityDataTable.Find(entity, [=](EntityPhysicsData* data)
		{
			// Set the new mode
			data->Mode = mode;

			// If we have a RigidBody
			if (data->RigidBody)
			{
				// If we don't want to have one
				if (mode < Entity::PhysicsMode::Kinematic)
				{
					// If we don't have any constraints
					if (data->RigidBody->getNumConstraintRefs() == 0)
					{
						// Destroy it
						_physicsWorld->GetDynamicsWorld().removeRigidBody(data->RigidBody);
						_rigidBodies.Destroy(data->RigidBody);
						data->RigidBody = nullptr;
					}
					else
					{
						// Set it up purely for constraints
						data->RigidBody->setCollisionShape(nullptr);
						data->RigidBody->setCollisionFlags(btCollisionObject::CF_KINEMATIC_OBJECT);
					}
				}
			}
			else
			{
				// If we want to have one
				if (mode >= Entity::PhysicsMode::Kinematic)
				{
					// Create one
					auto* rigidBody = _rigidBodies.New(*data);
					_physicsWorld->GetDynamicsWorld().addRigidBody(rigidBody);
					data->RigidBody = rigidBody;

					if (mode == Entity::PhysicsMode::Kinematic)
					{
						rigidBody->setMassProps(0, { 0, 0, 0 });
						rigidBody->setActivationState(DISABLE_DEACTIVATION);
						rigidBody->setCollisionFlags(rigidBody->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT);
					}
				}
			}

			// If we have a Ghost body
			if (data->GhostBody)
			{
				// If we don't want to have a ghost body
				if (mode == Entity::PhysicsMode::Transient)
				{
					// Destroy it
					_physicsWorld->GetDynamicsWorld().removeCollisionObject(data->GhostBody);
					_ghostBodies.Destroy(data->GhostBody);
					data->GhostBody = nullptr;
				}
			}
			else
			{
				// If we want to have a GhostBody
				if (mode >= Entity::PhysicsMode::Ghost)
				{
					auto* ghost = _ghostBodies.New();
					ghost->setCollisionShape(&data->Collider);
					//_physicsWorld->GetDynamicsWorld().addCollisionObject(ghost);
					data->GhostBody = ghost;

					// If we have a RigidBody
					if (data->RigidBody)
					{
						ghost->setIgnoreCollisionCheck(data->RigidBody, true);
					}
				}
			}
		});
	}

	void BulletPhysicsSystem::SetEntityPhysicsState(EntityHandle entity, Entity::PhysicsState state)
	{
		// If the PhysicsObject exists
		_entityDataTable.Find(entity, [&](EntityPhysicsData* data)
		{
			data->State = state;

			// If it's a Kinematic or Rigid body
			if (data->Mode >= Entity::PhysicsMode::Kinematic)
			{
				data->RigidBody->setAngularFactor(ConvertToBullet(state.AngularMotionFactor));
				data->RigidBody->setLinearFactor(ConvertToBullet(state.LinearMotionFactor));
				data->RigidBody->setFriction(state.Friction);
				data->RigidBody->setRollingFriction(state.RollingFriction);

				// If it's a rigid body
				if (data->Mode == Entity::PhysicsMode::Dynamic)
				{
					btVector3 inertia;
					data->Collider.calculateLocalInertia(state.Mass, inertia);
					data->RigidBody->setMassProps(state.Mass, inertia);
				}
			}
		});
	}

	void BulletPhysicsSystem::GetEntityLinearVelocity(Vec3& outLinearVelocity, EntityHandle entity)
	{
		auto* entityData = _entityDataTable[entity];

		if (entityData->RigidBody)
		{
			outLinearVelocity = ConvertFromBullet(entityData->RigidBody->getLinearVelocity());
		}
	}

	void BulletPhysicsSystem::SetEntityLinearVelocity(EntityHandle entity, const Vec3& linearVelocity)
	{
		auto* entityData = _entityDataTable[entity];

		if (entityData->RigidBody)
		{
			entityData->RigidBody->setLinearVelocity(ConvertToBullet(linearVelocity));
		}
	}

	void BulletPhysicsSystem::GetEntityAngularVelocity(Vec3& outAngularVelocity, EntityHandle entity)
	{
		auto* entityData = _entityDataTable[entity];

		if (entityData->RigidBody)
		{
			outAngularVelocity = ConvertFromBullet(entityData->RigidBody->getAngularVelocity());
		}
	}

	void BulletPhysicsSystem::SetEntityAngularVelocity(EntityHandle entity, const Vec3& angularVelocity)
	{
		auto* entityData = _entityDataTable[entity];

		if (entityData->RigidBody)
		{
			entityData->RigidBody->setAngularVelocity(ConvertToBullet(angularVelocity));
		}
	}

	void BulletPhysicsSystem::ApplyForce(EntityHandle entity, const Vec3& force, const Vec3& offset)
	{
		_entityDataTable.Find(entity, [&](EntityPhysicsData* data)
		{
			if (data->RigidBody)
			{
				data->RigidBody->applyForce(ConvertToBullet(force), ConvertToBullet(offset));
			}
		});
	}

	void BulletPhysicsSystem::ApplyImpulse(EntityHandle entity, const Vec3& force, const Vec3& offset)
	{
		_entityDataTable.Find(entity, [&](EntityPhysicsData* data)
		{
			if (data->RigidBody)
			{
				data->RigidBody->applyImpulse(ConvertToBullet(force), ConvertToBullet(offset));
			}
		});
	}

	void BulletPhysicsSystem::ApplyTorque(EntityHandle entity, const Vec3& torque)
	{
		_entityDataTable.Find(entity, [&](EntityPhysicsData* data)
		{
			if (data->RigidBody)
			{
				data->RigidBody->applyTorque(ConvertToBullet(torque));
			}
		});
	}

	void BulletPhysicsSystem::ApplyTorqueImpulse(EntityHandle entity, const Vec3& torque)
	{
		_entityDataTable.Find(entity, [&](EntityPhysicsData* data)
		{
			if (data->RigidBody)
			{
				data->RigidBody->applyTorqueImpulse(ConvertToBullet(torque));
			}
		});
	}

	void BulletPhysicsSystem::CreateCollider(GHandle<SphereColliderComponent> component, EntityHandle entity, const Transform& transform, SphereColliderComponent::Shape shape)
	{
		auto* entityData = _entityDataTable[entity];

		// Create the sphere collider
		auto* collider = _sphereColliders.New(shape.Radius);
		collider->setLocalScaling(ConvertToBullet(transform.Scale));
		collider->setUserPointer(entityData);

		// Add it to the EntityCollider
		entityData->Collider.AddChild(*collider, transform.Location, transform.Rotation);
		UpdateInertia(*entityData);

		// Add it to the table
		_sphereColliderTable[component] = collider;
	}

	void BulletPhysicsSystem::CreateCollider(GHandle<CapsuleColliderComponent> component, EntityHandle entity, const Transform& transform, CapsuleColliderComponent::Shape shape)
	{
		auto* entityData = _entityDataTable[entity];

		// Create the capsule collider
		btCapsuleShape* collider = nullptr;
		switch (shape.Axis)
		{
		case ColliderComponent::ShapeAxis::X:
			collider = _capsuleColliders.New<btCapsuleShapeX>(shape.Radius, shape.Height);
			break;
		case ColliderComponent::ShapeAxis::Y:
			collider = _capsuleColliders.New<btCapsuleShape>(shape.Radius, shape.Height);
			break;
		case ColliderComponent::ShapeAxis::Z:
			collider = _capsuleColliders.New<btCapsuleShapeZ>(shape.Radius, shape.Height);
			break;
		}
		collider->setLocalScaling(ConvertToBullet(transform.Scale));
		collider->setUserPointer(entityData);

		// Add it to the entity collider
		entityData->Collider.AddChild(*collider, transform.Location, transform.Rotation);
		UpdateInertia(*entityData);

		// Add it to the table
		_capsuleColliderTable[component] = collider;
	}

	void BulletPhysicsSystem::CreateCollider(GHandle<StaticMeshColliderComponent> component, EntityHandle entity, const Transform& transform, StaticMeshColliderComponent::Shape shape)
	{
		auto* entityData = _entityDataTable[entity];

		// Find or create a mesh for this collider
		auto& mesh = _triangleMeshes[shape.Mesh];
		if (!mesh)
		{
			mesh = std::make_unique<BulletTriangleMesh>(shape.Mesh);
		}

		// Create the collider
		auto* collider = _staticMeshColliders.New(mesh.get(), true);
		collider->setLocalScaling(ConvertToBullet(transform.Scale));
		collider->setUserPointer(entityData);

		// Add it to the entity collider
		entityData->Collider.AddChild(*collider, transform.Location, transform.Rotation);
		UpdateInertia(*entityData);

		// Add it to the table
		_staticMeshColliderTable[component] = collider;
	}

	void BulletPhysicsSystem::DestroyCollider(GHandle<SphereColliderComponent> component)
	{
		// Get the collider and its compound
		auto* collider = _sphereColliderTable[component];
		auto* entityData = static_cast<EntityPhysicsData*>(collider->getUserPointer());

		// Destroy it
		entityData->Collider.RemoveChild(*collider);
		_sphereColliders.Destroy(collider);
		_sphereColliderTable.Remove(component);
	}

	void BulletPhysicsSystem::DestroyCollider(GHandle<CapsuleColliderComponent> component)
	{
		// Get the collider and its compound
		auto* collider = _capsuleColliderTable[component];
		auto* entityData = static_cast<EntityPhysicsData*>(collider->getUserPointer());

		// Destroy it
		entityData->Collider.RemoveChild(*collider);
		_capsuleColliderTable.Remove(component);
		_capsuleColliders.Destroy(collider);
	}

	void BulletPhysicsSystem::DestroyCollider(GHandle<StaticMeshColliderComponent> /*component*/)
	{
		// TODO
	}

	void BulletPhysicsSystem::SetColliderTransform(GHandle<SphereColliderComponent> component, const Transform& transform)
	{
		_sphereColliderTable.Find(component, [&](auto* collider)
		{
			collider->setLocalScaling(ConvertToBullet(transform.Scale));
			auto* entityData = static_cast<EntityPhysicsData*>(collider->getUserPointer());
			entityData->Collider.UpdateChildLocationRotation(*collider, transform.Location, transform.Rotation);
		});
	}

	void BulletPhysicsSystem::SetColliderTransform(GHandle<CapsuleColliderComponent> component, const Transform& transform)
	{
		_capsuleColliderTable.Find(component, [&](auto* collider)
		{
			collider->setLocalScaling(ConvertToBullet(transform.Scale));
			auto* entityData = static_cast<EntityPhysicsData*>(collider->getUserPointer());
			entityData->Collider.UpdateChildLocationRotation(*collider, transform.Location, transform.Rotation);
		});
	}

	void BulletPhysicsSystem::SetColliderTransform(GHandle<StaticMeshColliderComponent> /*component*/, const Transform& /*transform*/)
	{
		// TODO
	}

	void BulletPhysicsSystem::SetColliderShape(GHandle<SphereColliderComponent> component, SphereColliderComponent::Shape /*shape*/)
	{
		// TODO
	}

	void BulletPhysicsSystem::SetColliderShape(GHandle<CapsuleColliderComponent> component, CapsuleColliderComponent::Shape shape)
	{
		// TODO
	}

	void BulletPhysicsSystem::SetColliderShape(GHandle<StaticMeshColliderComponent> component, StaticMeshColliderComponent::Shape shape)
	{
		// TODO
	}
}
<commit_msg>Fixed linux warnings<commit_after>// BulletPhysicsSystem.cpp - Copyright 2013-2016 Will Cassella, All Rights Reserved

#include <BulletCollision/CollisionDispatch/btGhostObject.h>
#include <Engine/World.h>
#include "../include/BulletPhysics/BulletPhysicsSystem.h"
#include "DebugDrawer.h"
#include "PhysicsWorld.h"
#include "RigidBody.h"
#include "BulletTriangleMesh.h"

//////////////////////
///   Reflection   ///

BUILD_REFLECTION(Willow::BulletPhysicsSystem);

namespace Willow
{
	////////////////////////
	///   Constructors   ///

	BulletPhysicsSystem::BulletPhysicsSystem()
	{
		_physicsWorld = std::make_unique<PhysicsWorld>();
	}

	BulletPhysicsSystem::~BulletPhysicsSystem()
	{
		_physicsWorld = nullptr;
	}

	///////////////////
	///   Methods   ///

	void BulletPhysicsSystem::Update(const World& world)
	{
		_physicsWorld->GetDynamicsWorld().stepSimulation(world.TimeStep, 1);
	}

	void BulletPhysicsSystem::DebugDraw(RenderSystem& render)
	{
		DebugDrawer drawer{ render };
		_physicsWorld->GetDynamicsWorld().setDebugDrawer(&drawer);
		_physicsWorld->GetDynamicsWorld().debugDrawWorld();
		_physicsWorld->GetDynamicsWorld().setDebugDrawer(nullptr);
	}

	void BulletPhysicsSystem::CreateEntity(EntityHandle entity, EntityHandle parent, Transform& transform, Entity::PhysicsMode mode, Entity::PhysicsState state)
	{
		// Create the physics data for this Entity
		auto* data = _entityPhysicsData.New();
		_entityDataTable[entity] = data;
		data->State = state;
		data->Mode = mode;
		data->Parent = parent;
		data->Transform = &transform;

		// Set the entitie's collider scaling
		data->Collider.setLocalScaling(ConvertToBullet(transform.Scale));

		// If the entity is at least a ghost
		if (mode >= Entity::PhysicsMode::Ghost)
		{
			auto* ghost = _ghostBodies.New();
			ghost->setCollisionShape(&data->Collider);
			//_physicsWorld->GetDynamicsWorld().addCollisionObject(ghost);
			data->GhostBody = ghost;
		}

		// If the entity is at least kinematic
		if (mode >= Entity::PhysicsMode::Kinematic)
		{
			auto* rigidBody = _rigidBodies.New(*data);
			_physicsWorld->GetDynamicsWorld().addRigidBody(rigidBody);
			data->GhostBody->setIgnoreCollisionCheck(rigidBody, true);
			data->RigidBody = rigidBody;

			// If the entity IS kinematic
			if (mode == Entity::PhysicsMode::Kinematic)
			{
				rigidBody->setMassProps(0, { 0, 0, 0 });
				rigidBody->setActivationState(DISABLE_DEACTIVATION);
				rigidBody->setCollisionFlags(rigidBody->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT);
			}
		}
	}

	void BulletPhysicsSystem::DestroyEntity(EntityHandle /*entity*/)
	{
		// TODO
	}

	void BulletPhysicsSystem::SetEntityParent(EntityHandle /*entity*/, EntityHandle /*parent*/)
	{
		// TODO
	}

	void BulletPhysicsSystem::UpdateEntityTransform(EntityHandle entity)
	{
		_entityDataTable.Find(entity, [&](EntityPhysicsData* data)
		{
			data->Collider.setLocalScaling(ConvertToBullet(data->Transform->Scale));
			btTransform transform{ ConvertToBullet(data->Transform->Rotation), ConvertToBullet(data->Transform->Location) };

			// If we have a GhostBody
			if (data->GhostBody)
			{
				data->GhostBody->setWorldTransform(transform);
			}

			// If we have a RigidBody
			if (data->RigidBody)
			{
				data->RigidBody->setWorldTransform(transform);
			}
		});
	}

	void BulletPhysicsSystem::SetEntityPhysicsMode(EntityHandle entity, Entity::PhysicsMode mode)
	{
		_entityDataTable.Find(entity, [=](EntityPhysicsData* data)
		{
			// Set the new mode
			data->Mode = mode;

			// If we have a RigidBody
			if (data->RigidBody)
			{
				// If we don't want to have one
				if (mode < Entity::PhysicsMode::Kinematic)
				{
					// If we don't have any constraints
					if (data->RigidBody->getNumConstraintRefs() == 0)
					{
						// Destroy it
						_physicsWorld->GetDynamicsWorld().removeRigidBody(data->RigidBody);
						_rigidBodies.Destroy(data->RigidBody);
						data->RigidBody = nullptr;
					}
					else
					{
						// Set it up purely for constraints
						data->RigidBody->setCollisionShape(nullptr);
						data->RigidBody->setCollisionFlags(btCollisionObject::CF_KINEMATIC_OBJECT);
					}
				}
			}
			else
			{
				// If we want to have one
				if (mode >= Entity::PhysicsMode::Kinematic)
				{
					// Create one
					auto* rigidBody = _rigidBodies.New(*data);
					_physicsWorld->GetDynamicsWorld().addRigidBody(rigidBody);
					data->RigidBody = rigidBody;

					if (mode == Entity::PhysicsMode::Kinematic)
					{
						rigidBody->setMassProps(0, { 0, 0, 0 });
						rigidBody->setActivationState(DISABLE_DEACTIVATION);
						rigidBody->setCollisionFlags(rigidBody->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT);
					}
				}
			}

			// If we have a Ghost body
			if (data->GhostBody)
			{
				// If we don't want to have a ghost body
				if (mode == Entity::PhysicsMode::Transient)
				{
					// Destroy it
					_physicsWorld->GetDynamicsWorld().removeCollisionObject(data->GhostBody);
					_ghostBodies.Destroy(data->GhostBody);
					data->GhostBody = nullptr;
				}
			}
			else
			{
				// If we want to have a GhostBody
				if (mode >= Entity::PhysicsMode::Ghost)
				{
					auto* ghost = _ghostBodies.New();
					ghost->setCollisionShape(&data->Collider);
					//_physicsWorld->GetDynamicsWorld().addCollisionObject(ghost);
					data->GhostBody = ghost;

					// If we have a RigidBody
					if (data->RigidBody)
					{
						ghost->setIgnoreCollisionCheck(data->RigidBody, true);
					}
				}
			}
		});
	}

	void BulletPhysicsSystem::SetEntityPhysicsState(EntityHandle entity, Entity::PhysicsState state)
	{
		// If the PhysicsObject exists
		_entityDataTable.Find(entity, [&](EntityPhysicsData* data)
		{
			data->State = state;

			// If it's a Kinematic or Rigid body
			if (data->Mode >= Entity::PhysicsMode::Kinematic)
			{
				data->RigidBody->setAngularFactor(ConvertToBullet(state.AngularMotionFactor));
				data->RigidBody->setLinearFactor(ConvertToBullet(state.LinearMotionFactor));
				data->RigidBody->setFriction(state.Friction);
				data->RigidBody->setRollingFriction(state.RollingFriction);

				// If it's a rigid body
				if (data->Mode == Entity::PhysicsMode::Dynamic)
				{
					btVector3 inertia;
					data->Collider.calculateLocalInertia(state.Mass, inertia);
					data->RigidBody->setMassProps(state.Mass, inertia);
				}
			}
		});
	}

	void BulletPhysicsSystem::GetEntityLinearVelocity(Vec3& outLinearVelocity, EntityHandle entity)
	{
		auto* entityData = _entityDataTable[entity];

		if (entityData->RigidBody)
		{
			outLinearVelocity = ConvertFromBullet(entityData->RigidBody->getLinearVelocity());
		}
	}

	void BulletPhysicsSystem::SetEntityLinearVelocity(EntityHandle entity, const Vec3& linearVelocity)
	{
		auto* entityData = _entityDataTable[entity];

		if (entityData->RigidBody)
		{
			entityData->RigidBody->setLinearVelocity(ConvertToBullet(linearVelocity));
		}
	}

	void BulletPhysicsSystem::GetEntityAngularVelocity(Vec3& outAngularVelocity, EntityHandle entity)
	{
		auto* entityData = _entityDataTable[entity];

		if (entityData->RigidBody)
		{
			outAngularVelocity = ConvertFromBullet(entityData->RigidBody->getAngularVelocity());
		}
	}

	void BulletPhysicsSystem::SetEntityAngularVelocity(EntityHandle entity, const Vec3& angularVelocity)
	{
		auto* entityData = _entityDataTable[entity];

		if (entityData->RigidBody)
		{
			entityData->RigidBody->setAngularVelocity(ConvertToBullet(angularVelocity));
		}
	}

	void BulletPhysicsSystem::ApplyForce(EntityHandle entity, const Vec3& force, const Vec3& offset)
	{
		_entityDataTable.Find(entity, [&](EntityPhysicsData* data)
		{
			if (data->RigidBody)
			{
				data->RigidBody->applyForce(ConvertToBullet(force), ConvertToBullet(offset));
			}
		});
	}

	void BulletPhysicsSystem::ApplyImpulse(EntityHandle entity, const Vec3& force, const Vec3& offset)
	{
		_entityDataTable.Find(entity, [&](EntityPhysicsData* data)
		{
			if (data->RigidBody)
			{
				data->RigidBody->applyImpulse(ConvertToBullet(force), ConvertToBullet(offset));
			}
		});
	}

	void BulletPhysicsSystem::ApplyTorque(EntityHandle entity, const Vec3& torque)
	{
		_entityDataTable.Find(entity, [&](EntityPhysicsData* data)
		{
			if (data->RigidBody)
			{
				data->RigidBody->applyTorque(ConvertToBullet(torque));
			}
		});
	}

	void BulletPhysicsSystem::ApplyTorqueImpulse(EntityHandle entity, const Vec3& torque)
	{
		_entityDataTable.Find(entity, [&](EntityPhysicsData* data)
		{
			if (data->RigidBody)
			{
				data->RigidBody->applyTorqueImpulse(ConvertToBullet(torque));
			}
		});
	}

	void BulletPhysicsSystem::CreateCollider(GHandle<SphereColliderComponent> component, EntityHandle entity, const Transform& transform, SphereColliderComponent::Shape shape)
	{
		auto* entityData = _entityDataTable[entity];

		// Create the sphere collider
		auto* collider = _sphereColliders.New(shape.Radius);
		collider->setLocalScaling(ConvertToBullet(transform.Scale));
		collider->setUserPointer(entityData);

		// Add it to the EntityCollider
		entityData->Collider.AddChild(*collider, transform.Location, transform.Rotation);
		UpdateInertia(*entityData);

		// Add it to the table
		_sphereColliderTable[component] = collider;
	}

	void BulletPhysicsSystem::CreateCollider(GHandle<CapsuleColliderComponent> component, EntityHandle entity, const Transform& transform, CapsuleColliderComponent::Shape shape)
	{
		auto* entityData = _entityDataTable[entity];

		// Create the capsule collider
		btCapsuleShape* collider = nullptr;
		switch (shape.Axis)
		{
		case ColliderComponent::ShapeAxis::X:
			collider = _capsuleColliders.New<btCapsuleShapeX>(shape.Radius, shape.Height);
			break;
		case ColliderComponent::ShapeAxis::Y:
			collider = _capsuleColliders.New<btCapsuleShape>(shape.Radius, shape.Height);
			break;
		case ColliderComponent::ShapeAxis::Z:
			collider = _capsuleColliders.New<btCapsuleShapeZ>(shape.Radius, shape.Height);
			break;
		}
		collider->setLocalScaling(ConvertToBullet(transform.Scale));
		collider->setUserPointer(entityData);

		// Add it to the entity collider
		entityData->Collider.AddChild(*collider, transform.Location, transform.Rotation);
		UpdateInertia(*entityData);

		// Add it to the table
		_capsuleColliderTable[component] = collider;
	}

	void BulletPhysicsSystem::CreateCollider(GHandle<StaticMeshColliderComponent> component, EntityHandle entity, const Transform& transform, StaticMeshColliderComponent::Shape shape)
	{
		auto* entityData = _entityDataTable[entity];

		// Find or create a mesh for this collider
		auto& mesh = _triangleMeshes[shape.Mesh];
		if (!mesh)
		{
			mesh = std::make_unique<BulletTriangleMesh>(shape.Mesh);
		}

		// Create the collider
		auto* collider = _staticMeshColliders.New(mesh.get(), true);
		collider->setLocalScaling(ConvertToBullet(transform.Scale));
		collider->setUserPointer(entityData);

		// Add it to the entity collider
		entityData->Collider.AddChild(*collider, transform.Location, transform.Rotation);
		UpdateInertia(*entityData);

		// Add it to the table
		_staticMeshColliderTable[component] = collider;
	}

	void BulletPhysicsSystem::DestroyCollider(GHandle<SphereColliderComponent> component)
	{
		// Get the collider and its compound
		auto* collider = _sphereColliderTable[component];
		auto* entityData = static_cast<EntityPhysicsData*>(collider->getUserPointer());

		// Destroy it
		entityData->Collider.RemoveChild(*collider);
		_sphereColliders.Destroy(collider);
		_sphereColliderTable.Remove(component);
	}

	void BulletPhysicsSystem::DestroyCollider(GHandle<CapsuleColliderComponent> component)
	{
		// Get the collider and its compound
		auto* collider = _capsuleColliderTable[component];
		auto* entityData = static_cast<EntityPhysicsData*>(collider->getUserPointer());

		// Destroy it
		entityData->Collider.RemoveChild(*collider);
		_capsuleColliderTable.Remove(component);
		_capsuleColliders.Destroy(collider);
	}

	void BulletPhysicsSystem::DestroyCollider(GHandle<StaticMeshColliderComponent> /*component*/)
	{
		// TODO
	}

	void BulletPhysicsSystem::SetColliderTransform(GHandle<SphereColliderComponent> component, const Transform& transform)
	{
		_sphereColliderTable.Find(component, [&](auto* collider)
		{
			collider->setLocalScaling(ConvertToBullet(transform.Scale));
			auto* entityData = static_cast<EntityPhysicsData*>(collider->getUserPointer());
			entityData->Collider.UpdateChildLocationRotation(*collider, transform.Location, transform.Rotation);
		});
	}

	void BulletPhysicsSystem::SetColliderTransform(GHandle<CapsuleColliderComponent> component, const Transform& transform)
	{
		_capsuleColliderTable.Find(component, [&](auto* collider)
		{
			collider->setLocalScaling(ConvertToBullet(transform.Scale));
			auto* entityData = static_cast<EntityPhysicsData*>(collider->getUserPointer());
			entityData->Collider.UpdateChildLocationRotation(*collider, transform.Location, transform.Rotation);
		});
	}

	void BulletPhysicsSystem::SetColliderTransform(GHandle<StaticMeshColliderComponent> /*component*/, const Transform& /*transform*/)
	{
		// TODO
	}

	void BulletPhysicsSystem::SetColliderShape(GHandle<SphereColliderComponent> /*component*/, SphereColliderComponent::Shape /*shape*/)
	{
		// TODO
	}

	void BulletPhysicsSystem::SetColliderShape(GHandle<CapsuleColliderComponent> /*component*/, CapsuleColliderComponent::Shape /*shape*/)
	{
		// TODO
	}

	void BulletPhysicsSystem::SetColliderShape(GHandle<StaticMeshColliderComponent> /*component*/, StaticMeshColliderComponent::Shape /*shape*/)
	{
		// TODO
	}
}
<|endoftext|>


<commit_before>// ----------------------------------------------------------------------------------------------------------
/// @file   runtime_converter.hpp
/// @brief  Header file for the runtime_converter metaclass which can return runtime containers (like
///         std::vector) from nano containers (mainly lists)
// ----------------------------------------------------------------------------------------------------------

/*
 * ----------------------------------------------------------------------------------------------------------
 * runtime_converter header file for nano library.
 * Copyright (C) 2015 Rob Clucas
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 * ----------------------------------------------------------------------------------------------------------
 */

#ifndef NANO_RUNTIME_CONVERTER_HPP
#define NANO_RUNTIME_CONVERTER_HPP

#include <nano/list.hpp>

#include <array>
#include <vector>
#include <type_traits>

namespace nano {

    // For 'behind the scenes' or more involved implementations
    namespace detail {

        // --------------------------------------------------------------------------------------------------
        /// @struct     array_convert
        /// @brief      Converts an element to a std type, like nano::int_t to inr or a nano::list into a
        ///             std::array with N elements
        /// @tparam     Elements    The element(s) to convert to a std type or std::array
        // --------------------------------------------------------------------------------------------------
        template <typename Element>
        struct array_convert
        {
            using type = typename Element::type;

            static constexpr type result() { return Element::value; };
        };

        // Specialization
        template <typename First, typename... Rest>
        struct array_convert<list<First, Rest...>>
        {
            static constexpr std::size_t size = sizeof...(Rest) + 1;

            using type = typename std::array<typename First::type, size>;

            static constexpr type result() {
                return type{ {First::value, Rest::value...} };
            }
        };

        // --------------------------------------------------------------------------------------------------
        /// @struct     vector_convert
        /// @brief      Same as convert, but uses vector's instead of arrays, so the performance is worse
        /// @tparam     Element     The element(s) to convert to a std type or std::vector
        // --------------------------------------------------------------------------------------------------
        template <typename Element>
        struct vector_convert
        {
            using type = typename Element::type;

            static constexpr type result() { return Element::value; };
        };

        // Specialization for lists
        template <typename First, typename... Rest>
        struct vector_convert<list<First, Rest...>>
        {
            using type = typename std::vector<typename First::type>;

            static constexpr type result() {
                return type{ {First::value, Rest::value...} };
            }
        };
    }

    // -------------------------------------------------------------------------------------------------------
    /// @struct      runtime_converter
    /// @brief       Wrapper class to provide the conversion functions for converting to runtime containers
    /// @tparam      List    The nano::list from which to create the runtime container
    // -------------------------------------------------------------------------------------------------------
    template <typename List>
    struct runtime_converter;

    // Specialization for list inputs
    template <typename Head, typename... Tail>
    struct runtime_converter<list<Head, Tail...>>
    {
        // Define type of the list elements (i.e int, float etc ...)
        // The types are assumed to be the same for a vector
        //using element_type = typename Head::type;

        // --------------------------------------------------------------------------------------------------
        /// @brief      Converts a nano list into a std vector
        /// @return     A std::vector with elements from the nano::list
        // --------------------------------------------------------------------------------------------------
        //static constexpr std::vector<element_type> to_vector()
        //{
        //    return std::vector<element_type>({Head::value, Tail::value...});
        //}

        // Number of elements in the external array - for readability of below function
        static constexpr std::size_t num_elements = sizeof...(Tail) + 1;

        using array_type = typename detail::array_convert<Head>::type;

        // --------------------------------------------------------------------------------------------------
        /// @brief      Converts a nano::list to a std::array, if the nano::list just contains elements. If
        ///             the nano::list contains nano::lists, then a std::array of std::array's is created
        /// @return     A std::array of elements, where the element type depends on the elements of the
        ///             nano::list from which it is created.
        // --------------------------------------------------------------------------------------------------
        static constexpr std::array<array_type, num_elements> to_array() {
            return std::array<array_type, num_elements>{ {detail::array_convert<Head>::result(),
                                                          detail::array_convert<Tail>::result()...} };
        }

        using vector_type = typename detail::vector_convert<Head>::type;

        // --------------------------------------------------------------------------------------------------
        /// @brief      Converts a nano::list to a std::vector, if the nano::list just contains elements. If
        ///             the nano::list contains nano::lists, then a std::vector of std::vector's is created.
        /// @return     A std::vector of elements, where the element type depends on the elements of the
        ///             nano::list from which it is created.
        // --------------------------------------------------------------------------------------------------
        static constexpr std::vector<vector_type> to_vector() {
            return std::vector<vector_type>{ {detail::vector_convert<Head>::result(),
                                              detail::vector_convert<Tail>::result()...} };
        }
    };

}           // End namespace nano

#endif      // NANO_RUNTIME_VECTOR_HPP

<commit_msg>Minor cleanup for runtime conversion<commit_after>// ----------------------------------------------------------------------------------------------------------
/// @file   runtime_converter.hpp
/// @brief  Header file for the runtime_converter metaclass which can return runtime containers (like
///         std::vector) from nano containers (mainly lists)
// ----------------------------------------------------------------------------------------------------------

/*
 * ----------------------------------------------------------------------------------------------------------
 * runtime_converter header file for nano library.
 * Copyright (C) 2015 Rob Clucas
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 * ----------------------------------------------------------------------------------------------------------
 */

#ifndef NANO_RUNTIME_CONVERTER_HPP
#define NANO_RUNTIME_CONVERTER_HPP

#include <nano/list.hpp>

#include <array>
#include <vector>
#include <type_traits>

namespace nano {

    // For 'behind the scenes' or more involved implementations
    namespace detail {

        // --------------------------------------------------------------------------------------------------
        /// @struct     array_convert
        /// @brief      Converts an element to a std type, like nano::int_t to inr or a nano::list into a
        ///             std::array with N elements
        /// @tparam     Elements    The element(s) to convert to a std type or std::array
        // --------------------------------------------------------------------------------------------------
        template <typename Element>
        struct array_convert
        {
            using type = typename Element::type;

            static constexpr type result() { return Element::value; };
        };

        // Specialization
        template <typename First, typename... Rest>
        struct array_convert<list<First, Rest...>>
        {
            static constexpr std::size_t size = sizeof...(Rest) + 1;

            using type = typename std::array<typename First::type, size>;

            static constexpr type result() {
                return type{ {First::value, Rest::value...} };
            }
        };

        // --------------------------------------------------------------------------------------------------
        /// @struct     vector_convert
        /// @brief      Same as convert, but uses vector's instead of arrays, so the performance is worse
        /// @tparam     Element     The element(s) to convert to a std type or std::vector
        // --------------------------------------------------------------------------------------------------
        template <typename Element>
        struct vector_convert
        {
            using type = typename Element::type;

            static constexpr type result() { return Element::value; };
        };

        // Specialization for lists
        template <typename First, typename... Rest>
        struct vector_convert<list<First, Rest...>>
        {
            using type = typename std::vector<typename First::type>;

            static constexpr type result() {
                return type{ {First::value, Rest::value...} };
            }
        };
    }

    // -------------------------------------------------------------------------------------------------------
    /// @struct      runtime_converter
    /// @brief       Wrapper class to provide the conversion functions for converting to runtime containers
    /// @tparam      List    The nano::list from which to create the runtime container
    // -------------------------------------------------------------------------------------------------------
    template <typename List>
    struct runtime_converter;

    // Specialization for list inputs
    template <typename Head, typename... Tail>
    struct runtime_converter<list<Head, Tail...>>
    {
        // Number of elements in the external array - for readability of below function
        static constexpr std::size_t num_elements = sizeof...(Tail) + 1;

        using array_internal_type   = typename detail::array_convert<Head>::type;
        using array_type            = typename std::array<array_internal_type, num_elements>;

        // --------------------------------------------------------------------------------------------------
        /// @brief      Converts a nano::list to a std::array, if the nano::list just contains elements. If
        ///             the nano::list contains nano::lists, then a std::array of std::array's is created
        /// @return     A std::array of elements, where the element type depends on the elements of the
        ///             nano::list from which it is created.
        // --------------------------------------------------------------------------------------------------
        static constexpr array_type to_array() {
            return array_type{ {detail::array_convert<Head>::result(),
                                detail::array_convert<Tail>::result()...} };
        }

        using vector_internal_type  = typename detail::vector_convert<Head>::type;
        using vector_type           = typename std::vector<vector_internal_type>;

        // --------------------------------------------------------------------------------------------------
        /// @brief      Converts a nano::list to a std::vector, if the nano::list just contains elements. If
        ///             the nano::list contains nano::lists, then a std::vector of std::vector's is created.
        /// @return     A std::vector of elements, where the element type depends on the elements of the
        ///             nano::list from which it is created.
        // --------------------------------------------------------------------------------------------------
        static constexpr vector_type to_vector() {
            return vector_type{ {detail::vector_convert<Head>::result(),
                                 detail::vector_convert<Tail>::result()...} };
        }
    };

}           // End namespace nano

#endif      // NANO_RUNTIME_VECTOR_HPP

<|endoftext|>


<commit_before>/*
 * MWMService.cpp
 *
 *  Created on: May 11, 2012
 *      Author: siarheirachytski
 */

#include "Framework.hpp"

#include "../core/jni_helper.hpp"

#include "../platform/Platform.hpp"

#include "../../../../../map/information_display.hpp"
#include "../../../../../map/location_state.hpp"
#include "../../../../../map/dialog_settings.hpp"

#include "../../../../../platform/settings.hpp"

extern "C"
{
  JNIEXPORT void JNICALL
  Java_com_mapswithme_maps_MWMApplication_nativeInit(JNIEnv * env,
                                                    jobject thiz,
                                                    jstring apkPath,
                                                    jstring storagePath,
                                                    jstring tmpPath,
                                                    jstring extTmpPath,
                                                    jboolean isPro)
  {
    android::Platform::Instance().Initialize(env,
                                             apkPath,
                                             storagePath,
                                             tmpPath,
                                             extTmpPath,
                                             isPro);

    if (!g_framework)
      g_framework = new android::Framework();
  }

  JNIEXPORT jboolean JNICALL
  Java_com_mapswithme_maps_MWMApplication_nativeIsBenchmarking(JNIEnv * env,
                                                               jobject thiz)
  {
    return static_cast<jboolean>(g_framework->NativeFramework()->IsBenchmarking());
  }

  JNIEXPORT jboolean JNICALL
  Java_com_mapswithme_maps_MWMApplication_shouldShowDialog(
      JNIEnv * env, jobject thiz, jint dlg)
  {
    return static_cast<jboolean>(dlg_settings::ShouldShow(static_cast<dlg_settings::DialogT>(dlg)));
  }

  JNIEXPORT void JNICALL
  Java_com_mapswithme_maps_MWMApplication_submitDialogResult(
      JNIEnv * env, jobject thiz, jint dlg, jint res)
  {
    dlg_settings::SaveResult(static_cast<dlg_settings::DialogT>(dlg),
                             static_cast<dlg_settings::ResultT>(res));
  }

  JNIEXPORT jboolean JNICALL
  Java_com_mapswithme_maps_MWMApplication_nativeGetBoolean(JNIEnv * env,
                                                           jobject thiz,
                                                           jstring name,
                                                           jboolean defaultVal)
  {
    bool val = defaultVal;
    Settings::Get(jni::ToNativeString(env, name), val);
    return val;
  }

  JNIEXPORT void JNICALL
  Java_com_mapswithme_maps_MWMApplication_nativeSetBoolean(JNIEnv * env,
                                                           jobject thiz,
                                                           jstring name,
                                                           jboolean val)
  {
    bool flag = val;
    (void)Settings::Set(jni::ToNativeString(env, name), flag);
  }

  JNIEXPORT jboolean JNICALL
  Java_com_mapswithme_maps_MWMApplication_hasFreeSpace(JNIEnv * env, jobject thiz, jlong size)
  {
    return android::Platform::Instance().HasAvailableSpaceForWriting(size);
  }
}
<commit_msg>[android] Add some debug logs.<commit_after>/*
 * MWMService.cpp
 *
 *  Created on: May 11, 2012
 *      Author: siarheirachytski
 */

#include "Framework.hpp"

#include "../core/jni_helper.hpp"

#include "../platform/Platform.hpp"

#include "../../../../../map/information_display.hpp"
#include "../../../../../map/location_state.hpp"
#include "../../../../../map/dialog_settings.hpp"

#include "../../../../../platform/settings.hpp"

extern "C"
{
  JNIEXPORT void JNICALL
  Java_com_mapswithme_maps_MWMApplication_nativeInit(JNIEnv * env,
                                                    jobject thiz,
                                                    jstring apkPath,
                                                    jstring storagePath,
                                                    jstring tmpPath,
                                                    jstring extTmpPath,
                                                    jboolean isPro)
  {
    android::Platform::Instance().Initialize(env,
                                             apkPath,
                                             storagePath,
                                             tmpPath,
                                             extTmpPath,
                                             isPro);

    LOG(LDEBUG, ("Creating android::Framework instance ..."));

    if (!g_framework)
      g_framework = new android::Framework();

    LOG(LDEBUG, ("android::Framework created"));
  }

  JNIEXPORT jboolean JNICALL
  Java_com_mapswithme_maps_MWMApplication_nativeIsBenchmarking(JNIEnv * env,
                                                               jobject thiz)
  {
    return static_cast<jboolean>(g_framework->NativeFramework()->IsBenchmarking());
  }

  JNIEXPORT jboolean JNICALL
  Java_com_mapswithme_maps_MWMApplication_shouldShowDialog(
      JNIEnv * env, jobject thiz, jint dlg)
  {
    return static_cast<jboolean>(dlg_settings::ShouldShow(static_cast<dlg_settings::DialogT>(dlg)));
  }

  JNIEXPORT void JNICALL
  Java_com_mapswithme_maps_MWMApplication_submitDialogResult(
      JNIEnv * env, jobject thiz, jint dlg, jint res)
  {
    dlg_settings::SaveResult(static_cast<dlg_settings::DialogT>(dlg),
                             static_cast<dlg_settings::ResultT>(res));
  }

  JNIEXPORT jboolean JNICALL
  Java_com_mapswithme_maps_MWMApplication_nativeGetBoolean(JNIEnv * env,
                                                           jobject thiz,
                                                           jstring name,
                                                           jboolean defaultVal)
  {
    bool val = defaultVal;
    Settings::Get(jni::ToNativeString(env, name), val);
    return val;
  }

  JNIEXPORT void JNICALL
  Java_com_mapswithme_maps_MWMApplication_nativeSetBoolean(JNIEnv * env,
                                                           jobject thiz,
                                                           jstring name,
                                                           jboolean val)
  {
    bool flag = val;
    (void)Settings::Set(jni::ToNativeString(env, name), flag);
  }

  JNIEXPORT jboolean JNICALL
  Java_com_mapswithme_maps_MWMApplication_hasFreeSpace(JNIEnv * env, jobject thiz, jlong size)
  {
    return android::Platform::Instance().HasAvailableSpaceForWriting(size);
  }
}
<|endoftext|>


<commit_before>/*
    Copyright (C) 2000 by Jorrit Tyberghein
    With additions by Samuel Humphreys

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library 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
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public
    License along with this library; if not, write to the Free
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include "cssysdef.h"
#include "cssys/system.h"
#include "apps/perftest/perftest.h"
#include "apps/perftest/ptests3d.h"
#include "apps/perftest/ptests2d.h"
#include "csgfxldr/csimage.h"
#include "igraph3d.h"
#include "itxtmgr.h"
#include "iconsole.h"

//-----------------------------------------------------------------------------

PerfTest::PerfTest ()
{
  draw_3d = true;
  draw_2d = true;
}

PerfTest::~PerfTest ()
{
}

void cleanup ()
{
  System->console_out ("Cleaning up...\n");
  delete System;
}

iMaterialHandle* PerfTest::LoadMaterial (char* file)
{
  iTextureManager* txtmgr = G3D->GetTextureManager ();
  iImage* image;
  iDataBuffer *buf = VFS->ReadFile (file);
  if (!buf || !data->GetSize ())
  {
    Printf (MSG_FATAL_ERROR, "Error loading texture '%s'!\n", file);
    exit (-1);
  }
  image = csImageLoader::Load (buf->GetUint8 (), buf->GetSize (),
  	txtmgr->GetTextureFormat ());
  buf->DecRef ();
  if (!image) exit (-1);
  iTextureHandle* texture = txtmgr->RegisterTexture (image, CS_TEXTURE_3D);
  if (!texture) exit (-1);
  image->DecRef ();
  iMaterialHandle* mat = txtmgr->RegisterMaterial (texture);
  return mat;
}

bool PerfTest::Initialize (int argc, const char* const argv[],
  const char *iConfigName)
{
  if (!superclass::Initialize (argc, argv, iConfigName))
    return false;

  // Open the main system. This will open all the previously loaded plug-ins.
  if (!Open ("Crystal Space Graphics Performance Tester"))
  {
    Printf (MSG_FATAL_ERROR, "Error opening system!\n");
    cleanup ();
    exit (1);
  }

  // Setup the texture manager
  iTextureManager* txtmgr = G3D->GetTextureManager ();
  txtmgr->SetVerbose (true);

  // Initialize the texture manager
  txtmgr->ResetPalette ();

  // Initialize textures.
  materials[0] = LoadMaterial ("/lib/std/stone4.gif");
  materials[1] = LoadMaterial ("/lib/std/mystone2.gif");
  materials[2] = LoadMaterial ("/lib/std/andrew_marble4.gif");
  materials[3] = LoadMaterial ("/lib/std/andrew_wood.gif");
  txtmgr->PrepareTextures ();

  // Allocate a uniformly distributed in R,G,B space palette for console
  // The console will crash on some platforms if this isn't initialize properly
  int r,g,b;
  for (r = 0; r < 8; r++)
    for (g = 0; g < 8; g++)
      for (b = 0; b < 4; b++)
	txtmgr->ReserveColor (r * 32, g * 32, b * 64);
  txtmgr->SetPalette ();

  // Initialize the console
  if (Console != NULL)
    // Don't let messages before this one appear
    Console->Clear ();

  // Some commercials...
  Printf (MSG_INITIALIZATION,
    "Crystal Space 3D Performance Tester 0.1.\n");

  txtmgr->SetPalette ();

  const char *val;
  if ((val = GetOptionCL ("2d")))
  {
    current_tester = new StringTester ();
    draw_3d = false;
  }
  else
    current_tester = new SinglePolygonTester ();

  if ((val = GetOptionCL ("3d")))
    draw_2d = false;

  needs_setup = true;

  return true;
}

static cs_time last_time;

void PerfTest::NextFrame ()
{
  SysSystemDriver::NextFrame ();
  cs_time elapsed_time, current_time;
  GetElapsedTime (elapsed_time, current_time);

  // Tell 3D driver we're going to display 3D things.
  if (!G3D->BeginDraw (draw_3d ? CSDRAW_3DGRAPHICS : CSDRAW_2DGRAPHICS))
    return;

  // Setup if needed.
  if (needs_setup)
  {
    current_tester->Setup (G3D, this);
    last_time = current_time;
  }

  // Do the test frame.
  if (current_tester)
  {
    current_tester->Draw (G3D);
    if (current_time-last_time >= 10000)
    {
      Printf (MSG_INITIALIZATION, "%f FPS\n",
      	current_tester->GetCount ()/10.);
      Tester* next_tester = current_tester->NextTester ();
      delete current_tester;
      current_tester = next_tester;
      if (current_tester)
      {
        needs_setup = true;
	current_tester->Setup (G3D, this);
      }
      else
      {
	if (draw_3d && draw_2d)
	{
	  draw_3d = false;
	  current_tester = new LineTester2D ();
	  needs_setup = true;
	  current_tester->Setup (G3D, this);
	}
	else
	  Shutdown = true;
      }
    }
  }

  // Start drawing 2D graphics.
  if (needs_setup)
  {
    if (!G3D->BeginDraw (CSDRAW_2DGRAPHICS)) return;
    if (Console) Console->Clear ();
    last_time = current_time;
    char desc[255];
    current_tester->Description (desc);
    Printf (MSG_INITIALIZATION, desc);
    needs_setup = false;
  }

  // Drawing code ends here.
  G3D->FinishDraw ();
  // Print the final output.
  G3D->Print (NULL);
}

bool PerfTest::HandleEvent (iEvent &Event)
{
  if (superclass::HandleEvent (Event))
    return true;

  if ((Event.Type == csevKeyDown) && (Event.Key.Code == CSKEY_ESC))
  {
    Shutdown = true;
    return true;
  }
  else if ((Event.Type == csevKeyDown) && (Event.Key.Code == ' '))
  {
    last_time -= 10000;
    return true;
  }

  return false;
}

/*---------------------------------------------------------------------*
 * Main function
 *---------------------------------------------------------------------*/
int main (int argc, char* argv[])
{
  srand (time (NULL));

  // Create our main class.
  System = new PerfTest ();

  // We want at least the minimal set of plugins
  System->RequestPlugin ("crystalspace.kernel.vfs:VFS");
  System->RequestPlugin ("crystalspace.graphics3d.software:VideoDriver");
  System->RequestPlugin ("crystalspace.console.output.standard:Console");

  // Initialize the main system. This will load all needed plug-ins
  // (3D, 2D, network, sound, ...) and initialize them.
  if (!System->Initialize (argc, argv, NULL))
  {
    System->Printf (MSG_FATAL_ERROR, "Error initializing system!\n");
    cleanup ();
    exit (1);
  }

  // Main loop.
  System->Loop ();

  // Cleanup.
  cleanup ();

  return 0;
}
<commit_msg>Once again compiles following Andrew's Big Change(tm).<commit_after>/*
    Copyright (C) 2000 by Jorrit Tyberghein
    With additions by Samuel Humphreys

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library 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
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public
    License along with this library; if not, write to the Free
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include "cssysdef.h"
#include "cssys/system.h"
#include "apps/perftest/perftest.h"
#include "apps/perftest/ptests3d.h"
#include "apps/perftest/ptests2d.h"
#include "csgfxldr/csimage.h"
#include "igraph3d.h"
#include "itxtmgr.h"
#include "iconsole.h"

//-----------------------------------------------------------------------------

PerfTest::PerfTest ()
{
  draw_3d = true;
  draw_2d = true;
}

PerfTest::~PerfTest ()
{
}

void cleanup ()
{
  System->console_out ("Cleaning up...\n");
  delete System;
}

iMaterialHandle* PerfTest::LoadMaterial (char* file)
{
  iTextureManager* txtmgr = G3D->GetTextureManager ();
  iImage* image;
  iDataBuffer *buf = VFS->ReadFile (file);
  if (!buf || !buf->GetSize ())
  {
    Printf (MSG_FATAL_ERROR, "Error loading texture '%s'!\n", file);
    exit (-1);
  }
  image = csImageLoader::Load (buf->GetUint8 (), buf->GetSize (),
  	txtmgr->GetTextureFormat ());
  buf->DecRef ();
  if (!image) exit (-1);
  iTextureHandle* texture = txtmgr->RegisterTexture (image, CS_TEXTURE_3D);
  if (!texture) exit (-1);
  image->DecRef ();
  iMaterialHandle* mat = txtmgr->RegisterMaterial (texture);
  return mat;
}

bool PerfTest::Initialize (int argc, const char* const argv[],
  const char *iConfigName)
{
  if (!superclass::Initialize (argc, argv, iConfigName))
    return false;

  // Open the main system. This will open all the previously loaded plug-ins.
  if (!Open ("Crystal Space Graphics Performance Tester"))
  {
    Printf (MSG_FATAL_ERROR, "Error opening system!\n");
    cleanup ();
    exit (1);
  }

  // Setup the texture manager
  iTextureManager* txtmgr = G3D->GetTextureManager ();
  txtmgr->SetVerbose (true);

  // Initialize the texture manager
  txtmgr->ResetPalette ();

  // Initialize textures.
  materials[0] = LoadMaterial ("/lib/std/stone4.gif");
  materials[1] = LoadMaterial ("/lib/std/mystone2.gif");
  materials[2] = LoadMaterial ("/lib/std/andrew_marble4.gif");
  materials[3] = LoadMaterial ("/lib/std/andrew_wood.gif");
  txtmgr->PrepareTextures ();

  // Allocate a uniformly distributed in R,G,B space palette for console
  // The console will crash on some platforms if this isn't initialize properly
  int r,g,b;
  for (r = 0; r < 8; r++)
    for (g = 0; g < 8; g++)
      for (b = 0; b < 4; b++)
	txtmgr->ReserveColor (r * 32, g * 32, b * 64);
  txtmgr->SetPalette ();

  // Initialize the console
  if (Console != NULL)
    // Don't let messages before this one appear
    Console->Clear ();

  // Some commercials...
  Printf (MSG_INITIALIZATION,
    "Crystal Space 3D Performance Tester 0.1.\n");

  txtmgr->SetPalette ();

  const char *val;
  if ((val = GetOptionCL ("2d")))
  {
    current_tester = new StringTester ();
    draw_3d = false;
  }
  else
    current_tester = new SinglePolygonTester ();

  if ((val = GetOptionCL ("3d")))
    draw_2d = false;

  needs_setup = true;

  return true;
}

static cs_time last_time;

void PerfTest::NextFrame ()
{
  SysSystemDriver::NextFrame ();
  cs_time elapsed_time, current_time;
  GetElapsedTime (elapsed_time, current_time);

  // Tell 3D driver we're going to display 3D things.
  if (!G3D->BeginDraw (draw_3d ? CSDRAW_3DGRAPHICS : CSDRAW_2DGRAPHICS))
    return;

  // Setup if needed.
  if (needs_setup)
  {
    current_tester->Setup (G3D, this);
    last_time = current_time;
  }

  // Do the test frame.
  if (current_tester)
  {
    current_tester->Draw (G3D);
    if (current_time-last_time >= 10000)
    {
      Printf (MSG_INITIALIZATION, "%f FPS\n",
      	current_tester->GetCount ()/10.);
      Tester* next_tester = current_tester->NextTester ();
      delete current_tester;
      current_tester = next_tester;
      if (current_tester)
      {
        needs_setup = true;
	current_tester->Setup (G3D, this);
      }
      else
      {
	if (draw_3d && draw_2d)
	{
	  draw_3d = false;
	  current_tester = new LineTester2D ();
	  needs_setup = true;
	  current_tester->Setup (G3D, this);
	}
	else
	  Shutdown = true;
      }
    }
  }

  // Start drawing 2D graphics.
  if (needs_setup)
  {
    if (!G3D->BeginDraw (CSDRAW_2DGRAPHICS)) return;
    if (Console) Console->Clear ();
    last_time = current_time;
    char desc[255];
    current_tester->Description (desc);
    Printf (MSG_INITIALIZATION, desc);
    needs_setup = false;
  }

  // Drawing code ends here.
  G3D->FinishDraw ();
  // Print the final output.
  G3D->Print (NULL);
}

bool PerfTest::HandleEvent (iEvent &Event)
{
  if (superclass::HandleEvent (Event))
    return true;

  if ((Event.Type == csevKeyDown) && (Event.Key.Code == CSKEY_ESC))
  {
    Shutdown = true;
    return true;
  }
  else if ((Event.Type == csevKeyDown) && (Event.Key.Code == ' '))
  {
    last_time -= 10000;
    return true;
  }

  return false;
}

/*---------------------------------------------------------------------*
 * Main function
 *---------------------------------------------------------------------*/
int main (int argc, char* argv[])
{
  srand (time (NULL));

  // Create our main class.
  System = new PerfTest ();

  // We want at least the minimal set of plugins
  System->RequestPlugin ("crystalspace.kernel.vfs:VFS");
  System->RequestPlugin ("crystalspace.graphics3d.software:VideoDriver");
  System->RequestPlugin ("crystalspace.console.output.standard:Console");

  // Initialize the main system. This will load all needed plug-ins
  // (3D, 2D, network, sound, ...) and initialize them.
  if (!System->Initialize (argc, argv, NULL))
  {
    System->Printf (MSG_FATAL_ERROR, "Error initializing system!\n");
    cleanup ();
    exit (1);
  }

  // Main loop.
  System->Loop ();

  // Cleanup.
  cleanup ();

  return 0;
}
<|endoftext|>


<commit_before>/** @file
    @brief Implementation of the "multiserver" plugin that offers the stock VRPN
   devices.

    @date 2014

    @author
    Ryan Pavlik
    <ryan@sensics.com>
    <http://sensics.com>
*/

// Copyright 2014 Sensics, Inc.
//
// All rights reserved.
//
// (Final version intended to be licensed under
// the Apache License, Version 2.0)

// Internal Includes
#include "VRPNMultiserver.h"
#include "DevicesWithParameters.h"
#include <osvr/PluginKit/PluginKit.h>
#include <osvr/Util/UniquePtr.h>
#include <osvr/VRPNServer/VRPNDeviceRegistration.h>

// Library/third-party includes
#include "hidapi/hidapi.h"
#include "vrpn_Connection.h"
#include "vrpn_Tracker_RazerHydra.h"
#include "vrpn_Tracker_OSVRHackerDevKit.h"
#include "vrpn_Tracker_Filter.h"
#include <boost/noncopyable.hpp>

// Standard includes
#include <iostream>
#include <map>
#include <string>
#include <sstream>
#include <vector>
#include <algorithm>

class VRPNHardwareDetect : boost::noncopyable {
  public:
    VRPNHardwareDetect(VRPNMultiserverData &data) : m_data(data) {}
    OSVR_ReturnCode operator()(OSVR_PluginRegContext ctx) {
        bool gotDevice;
        do {
            gotDevice = false;
            struct hid_device_info *enumData = hid_enumerate(0, 0);
            for (struct hid_device_info *dev = enumData; dev != nullptr;
                 dev = dev->next) {

                if (m_isPathHandled(dev->path)) {
                    continue;
                }

                if (gotDevice) {
                    continue;
                }
                // Razer Hydra
                if (dev->vendor_id == 0x1532 && dev->product_id == 0x0300) {
                    gotDevice = true;
                    m_handlePath(dev->path);
                    /// Decorated name for Hydra
                    std::string name;
                    {
                        // Razer Hydra
                        osvr::vrpnserver::VRPNDeviceRegistration reg(ctx);
                        name =
                            reg.useDecoratedName(m_data.getName("RazerHydra"));
                        reg.registerDevice(new vrpn_Tracker_RazerHydra(
                            name.c_str(), reg.getVRPNConnection()));
                    }
                    std::string localName = "*" + name;

                    {
                        // Corresponding filter
                        osvr::vrpnserver::VRPNDeviceRegistration reg(ctx);
                        reg.registerDevice(new vrpn_Tracker_FilterOneEuro(
                            reg.useDecoratedName(
                                    m_data.getName("OneEuroFilter")).c_str(),
                            reg.getVRPNConnection(), localName.c_str(), 2, 1.15,
                            1.0, 1.2, 1.5, 5.0, 1.2));
                    }
                    continue;
                }

                // OSVR Hacker Dev Kit
                if ((dev->vendor_id == 0x1532 && dev->product_id == 0x0300) ||
                    (dev->vendor_id == 0x03EB && dev->product_id == 0x2421)) {
                    gotDevice = true;
                    m_handlePath(dev->path);
                    osvr::vrpnserver::VRPNDeviceRegistration reg(ctx);
                    reg.constructAndRegisterDevice<
                        vrpn_Tracker_OSVRHackerDevKit>(
                        m_data.getName("OSVRHackerDevKit"));
                    continue;
                }
            }
            hid_free_enumeration(enumData);
        } while (gotDevice);
        return OSVR_RETURN_SUCCESS;
    }

  private:
    bool m_isPathHandled(const char *path) {
        return std::find(begin(m_handledPaths), end(m_handledPaths),
                         std::string(path)) != end(m_handledPaths);
    }
    void m_handlePath(const char *path) {
        m_handledPaths.push_back(std::string(path));
    }
    VRPNMultiserverData &m_data;
    std::vector<std::string> m_handledPaths;
};

OSVR_PLUGIN(org_opengoggles_bundled_Multiserver) {
    osvr::pluginkit::PluginContext context(ctx);

    VRPNMultiserverData &data =
        *context.registerObjectForDeletion(new VRPNMultiserverData);
    context.registerHardwareDetectCallback(new VRPNHardwareDetect(data));

    osvrRegisterDriverInstantiationCallback(
        ctx, "YEI_3Space_Sensor", &wrappedConstructor<&createYEI>, &data);

    return OSVR_RETURN_SUCCESS;
}
<commit_msg>Compile-time optional verbose output during USB HID enumeration.<commit_after>/** @file
    @brief Implementation of the "multiserver" plugin that offers the stock VRPN
   devices.

    @date 2014

    @author
    Ryan Pavlik
    <ryan@sensics.com>
    <http://sensics.com>
*/

// Copyright 2014 Sensics, Inc.
//
// All rights reserved.
//
// (Final version intended to be licensed under
// the Apache License, Version 2.0)

// Define this for verbose output during polling.
#undef OSVR_MULTISERVER_VERBOSE

// Internal Includes
#include "VRPNMultiserver.h"
#include "DevicesWithParameters.h"
#include <osvr/PluginKit/PluginKit.h>
#include <osvr/Util/UniquePtr.h>
#include <osvr/VRPNServer/VRPNDeviceRegistration.h>

// Library/third-party includes
#include "hidapi/hidapi.h"
#include "vrpn_Connection.h"
#include "vrpn_Tracker_RazerHydra.h"
#include "vrpn_Tracker_OSVRHackerDevKit.h"
#include "vrpn_Tracker_Filter.h"
#include <boost/noncopyable.hpp>

#ifdef OSVR_MULTISERVER_VERBOSE
#include <boost/format.hpp>
#endif

// Standard includes
#include <iostream>
#include <map>
#include <string>
#include <sstream>
#include <vector>
#include <algorithm>

#ifdef OSVR_MULTISERVER_VERBOSE
#include <iostream>
#endif

class VRPNHardwareDetect : boost::noncopyable {
  public:
    VRPNHardwareDetect(VRPNMultiserverData &data) : m_data(data) {}
    OSVR_ReturnCode operator()(OSVR_PluginRegContext ctx) {
        bool gotDevice;
#ifdef OSVR_MULTISERVER_VERBOSE
        bool first = true;
#endif
        do {
            gotDevice = false;
            struct hid_device_info *enumData = hid_enumerate(0, 0);
            for (struct hid_device_info *dev = enumData; dev != nullptr;
                 dev = dev->next) {

                if (m_isPathHandled(dev->path)) {
                    continue;
                }

#ifdef OSVR_MULTISERVER_VERBOSE
                if (first) {
                    std::cout << "[OSVR Multiserver] HID Enumeration: "
                              << boost::format("0x%04x") % dev->vendor_id << ":"
                              << boost::format("0x%04x") % dev->product_id
                              << std::endl;
                }
#endif

                if (gotDevice) {
                    continue;
                }
                // Razer Hydra
                if (dev->vendor_id == 0x1532 && dev->product_id == 0x0300) {
                    gotDevice = true;
                    m_handlePath(dev->path);
                    /// Decorated name for Hydra
                    std::string name;
                    {
                        // Razer Hydra
                        osvr::vrpnserver::VRPNDeviceRegistration reg(ctx);
                        name =
                            reg.useDecoratedName(m_data.getName("RazerHydra"));
                        reg.registerDevice(new vrpn_Tracker_RazerHydra(
                            name.c_str(), reg.getVRPNConnection()));
                    }
                    std::string localName = "*" + name;

                    {
                        // Corresponding filter
                        osvr::vrpnserver::VRPNDeviceRegistration reg(ctx);
                        reg.registerDevice(new vrpn_Tracker_FilterOneEuro(
                            reg.useDecoratedName(
                                    m_data.getName("OneEuroFilter")).c_str(),
                            reg.getVRPNConnection(), localName.c_str(), 2, 1.15,
                            1.0, 1.2, 1.5, 5.0, 1.2));
                    }
                    continue;
                }

                // OSVR Hacker Dev Kit
                if ((dev->vendor_id == 0x1532 && dev->product_id == 0x0300) ||
                    (dev->vendor_id == 0x03EB && dev->product_id == 0x2421)) {
                    gotDevice = true;
                    m_handlePath(dev->path);
                    osvr::vrpnserver::VRPNDeviceRegistration reg(ctx);
                    reg.constructAndRegisterDevice<
                        vrpn_Tracker_OSVRHackerDevKit>(
                        m_data.getName("OSVRHackerDevKit"));
                    continue;
                }
            }
            hid_free_enumeration(enumData);

#ifdef OSVR_MULTISERVER_VERBOSE
            first = false;
#endif

        } while (gotDevice);
        return OSVR_RETURN_SUCCESS;
    }

  private:
    bool m_isPathHandled(const char *path) {
        return std::find(begin(m_handledPaths), end(m_handledPaths),
                         std::string(path)) != end(m_handledPaths);
    }
    void m_handlePath(const char *path) {
        m_handledPaths.push_back(std::string(path));
    }
    VRPNMultiserverData &m_data;
    std::vector<std::string> m_handledPaths;
};

OSVR_PLUGIN(org_opengoggles_bundled_Multiserver) {
    osvr::pluginkit::PluginContext context(ctx);

    VRPNMultiserverData &data =
        *context.registerObjectForDeletion(new VRPNMultiserverData);
    context.registerHardwareDetectCallback(new VRPNHardwareDetect(data));

    osvrRegisterDriverInstantiationCallback(
        ctx, "YEI_3Space_Sensor", &wrappedConstructor<&createYEI>, &data);

    return OSVR_RETURN_SUCCESS;
}
<|endoftext|>