text:
package com.cinnamon.object;

import com.cinnamon.system.ComponentFactory;
import com.cinnamon.utils.*;

import java.util.ArrayList;
import java.util.List;

/**
 *

 *     A BodyComponent represents the 2D collision polygon for a {@link GObject} as well as a body for the
 *     {@link Solver} to manipulate during physics computations.
 *

 *
 *

 *     The current collision detection algorithm is performed via SAT (Separating Axis Theorem) to accurately
 *     determine if a collision has taken place. For contact point generation, clipping is used with the
 *     separating axis of minimum translation found during the detection step.
 *

 *
 *

 *     Information about a collision is stored in a {@link Manifold} that is given to
 *     {@link #collidesWith(BodyComponent, Manifold)}. This includes contact points, each point's penetration depth,
 *     and a unit collision normal facing in the direction of the BodyComponent that calls collidesWith
 *     (BodyComponent, Manifold) to the BodyComponent passed in as an argument.
 *

 *
 *

 *     Aside from collision operations, BodyComponents also hold quantities used during physics computations in the
 *     {@link Solver}. These include (but are not limited to) mass, velocity, and coefficients of restitution and
 *     friction, the first two being measured in kilograms and meters per second, respectively.
 *

 *
 *

 *     Toggles are available for disabling or enabling certain features such as collision with
 *     {@link #setCollidable(boolean)}.
 *

 *
 *

 *     Both the SAT detection and contact point generation algorithms were originally learned from http://www.dyn4j
 *     .org/.
 *

 */
public final class BodyComponent extends ComponentFactory.Component implements Positional, Rotatable
{
    /**
     * Collision testing vars to be reused for each SAT run for collidesSAT()
     */

    // Separating axis to be used during SAT
    private final Vector2F mSeparatingAxis = new Vector2F();

    // An edge's start and end points
    private final float[] mEdgePt0 = new float[2];
    private final float[] mEdgePt1 = new float[2];

    // Minimum and maximum containers for each Shape's projection
    private final Vector2F mMinMax0 = new Vector2F();
    private final Vector2F mMinMax1 = new Vector2F();

    // Separating axis with minimum depth overlap as a result of SAT, for use in contact gen
    private final Vector2F mMinDepthVec = new Vector2F();

    // Minimum projection used during SAT to find minimum dist to separate
    private float mMinDepth;

    /**
     * Contact generation vars for getContacts()
     */

    // Reference edge used during contact point generation
    private final CollidingEdge mRefEdge = new CollidingEdge();

    // Incident edge used during contact point generation
    private final CollidingEdge mIncEdge = new CollidingEdge();

    // Container vector representing an edge (one end minus the other) used in computations
    private final Vector2F mEdge = new Vector2F();

    /**
     * BodyComponent instance specific properties
     */

    // Anchor in tree that allows O(1) lookup
    private BoundingTree.Node mContainer;

    // Anchor in graph for O(1) lookup
    private ContactGraph.Node mContactNode;

    // Polygon for fine-grain collision checking
    private Shape mShape;

    // Toggle to allow selection
    private boolean mSelectable = true;

    // Toggle to disable collision reactions
    private boolean mCollidable = true;

    // True to ignore collisions with GObject's parent
    private boolean mIgnoreGObjectParent = false;

    /**
     * Physics
     */

    // Kilograms
    private float mMass = 70f;

    // Inverse mass (in kilograms)
    private float mInvMass = 1f / mMass;

    // Meters per second
    private final Vector2F mVelocity = new Vector2F();

    // Velocity from previous physics update
    private final Vector2F mOldVelocity = new Vector2F();

    // Impulse vector to be applied during each move() and cleared afterwards
    private final Vector2F mImpulse = new Vector2F();

    // Coefficient of friction
    private float mCOF = 0.5f;

    // Coefficient of restitution
    private float mCOR = 0.8f;

    // Sleep optimization flag
    private boolean mSleeping = false;

    /**
     *
Constructs a BodyComponent with a specific {@link Shape}. The stored Shape is a copy of the given Shape.

     *
     * @param shape Shape.
     */
    public BodyComponent(Shape shape)
    {
        mShape = new Shape(shape);
    }

    /**
     *
Checks whether or not another BodyComponent's {@link Shape} is intersecting and, if so, populates a given
     * {@link Manifold} with information about the collision.

     *
     * @param other BodyComponent.
     * @param manifold container for collision info.
     * @return true if the Shapes intersect.
     */
    public final boolean collidesWith(BodyComponent other, Manifold manifold)
    {
        // If either body isn't collidable, no collision ops can be done
        if (!isCollidable() || !other.isCollidable()) {
            return false;
        }

        // No separation axis implies no collision
        final Vector2F sepAxis = collidesSAT(other, true);
        if (sepAxis == null) {
            return false;
        }

        // Make sure separating axis' direction to point towards the other body
        if (isPointingTowards(getCenterX(), getCenterY(), sepAxis, other.getCenterX(), other.getCenterY())) {
            sepAxis.negate();
        }

        // Erase old collision data and get contact lists
        manifold.clear();
        final List<Vector2F> contacts = manifold.mPoints;
        final List<Float> depths = manifold.mDepths;

        // Compute contact points for current collision
        getContacts(contacts, depths, other, sepAxis);

        // There should be points of contact if a collision occurred
        assert (!contacts.isEmpty());

        // Compute collision normal from the reference edge chosen in contact gen
        final Vector2F collisionNormal = mRefEdge.mEnd;
        collisionNormal.subtract(mRefEdge.mBegin);
        collisionNormal.normal(true);
        collisionNormal.normalize();

        // Make sure collision normal points towards other object
        if (isPointingTowards(getCenterX(), getCenterY(), collisionNormal, other.getCenterX(), other.getCenterY())) {
            collisionNormal.negate();
        }

        // Fill manifold with collision info
        manifold.setContactNormal(collisionNormal);
        manifold.setContactPoint(0, contacts.get(0), depths.get(0));
        if (contacts.size() > 1) {
            manifold.setContactPoint(1, contacts.get(1), depths.get(1));
        }

        return true;
    }

    /**
     *
Checks if a position and a pseudo velocity vector is headed in the direction of another position. The
     * second position's velocity is assumed to be the zero vector.

     *
     * @param x0 first position's x.
     * @param y0 first position's y.
     * @param velocity pseudo velocity.
     * @param x1 second position's x.
     * @param y1 second position's y.
     * @return true if the first position is pointing towards the second.
     */
    private boolean isPointingTowards(float x0, float y0, Vector2F velocity, float x1, float y1)
    {
        final float xDiff = x0 - x1;
        final float yDiff = y0 - y1;

        final float dot = (velocity.getX() * xDiff) + (velocity.getY() * yDiff);
        return dot > 0f;
    }

    /**
     *
Performs collision testing against another {@link BodyComponent}'s {@link Shape} using the Separating Axis
     * Theorem.

     *
     * @param other other BodyComponent.
     * @param reverseRoles true to perform SAT from the other body's point of view as well.
     * @return the separating axis with the minimum distance needed for separation, or null if there was no collision.
     */
    private Vector2F collidesSAT(BodyComponent other, boolean reverseRoles)
    {
        final Shape otherShape = other.getShape();

        mMinDepth = Float.MAX_VALUE;

        // Find min/max projected points of first shape
        for (int i = 0, sz = mShape.getPointCount(); i < sz; i++) {

            // Get points forming an edge
            mShape.getPoint(i, mEdgePt0);
            mShape.getPoint((i + 1) % sz, mEdgePt1);

            // Compute separation axis
            mSeparatingAxis.set(mEdgePt1[0] - mEdgePt0[0], mEdgePt1[1] - mEdgePt0[1]);

            // Make it a unit vector and transform perpendicular
            mSeparatingAxis.normalize();
            mSeparatingAxis.normal(false);

            // Find the min/max projections of each shape onto the axis
            BodyComponent.findMinMaxProjections(mShape, mSeparatingAxis, mMinMax0);
            BodyComponent.findMinMaxProjections(otherShape, mSeparatingAxis, mMinMax1);

            // Bail out as soon as a separation is found (min = x, max = y)
            final boolean case0 = (mMinMax0.getX() > mMinMax1.getY() || Point2F.isEqual(mMinMax0.getX(),
                    mMinMax1.getY()));
            final boolean case1 = (mMinMax0.getY() < mMinMax1.getX() || Point2F.isEqual(mMinMax0.getY(),
                    mMinMax1.getX()));
            if (case0 || case1) {
                return null;
            }

            // Compute shape's projection overlap on current separating axis
            final float depth = Math.min(Math.abs(mMinMax0.getX() - mMinMax1.getY()), Math.abs(mMinMax1.getX() -
                    mMinMax0.getY()));

            // Track separating axis with the minimum overlap
            if (depth < mMinDepth) {
                mMinDepth = depth;
                mMinDepthVec.copy(mSeparatingAxis);
            }
        }

        // Test SAT once more but switch BodyComponent's roles
        if (reverseRoles) {

            // Bail out if a space was found from the other shape's pov
            final Vector2F otherMinVec = other.collidesSAT(this, false);
            if (otherMinVec == null) {
                return null;
            }

            // Return separating axis with min overlap between both Shapes
            return new Vector2F((mMinDepth < other.mMinDepth) ? mMinDepthVec : otherMinVec);
        }

        // Return separating axis with min overlap amongst all local axes
        return new Vector2F(mMinDepthVec);
    }

    /**
     *
Finds the minimum and maximum projections of a given {@link Shape} onto an axis. The min-max values are
     * stored in a {@link Vector2F} where x is minimum and y is maximum.

     *
     * @param shape Shape with points to project.
     * @param axis axis to project on to.
     * @param container holds min-max values when done.
     */
    private static void findMinMaxProjections(Shape shape, Vector2F axis, Vector2F container)
    {
        float min = Float.MAX_VALUE;
        float max = -Float.MAX_VALUE;

        // Project each point onto the vector
        for (int i = 0, sz = shape.getPointCount(); i < sz; i++) {
            // Convert point to vector for methods
            shape.getPoint(i, container);

            // Compute projection constant and track min/max
            final float constant = axis.dotProduct(container);
            if (constant < min || Point2F.isEqual(constant, min)) {
                min = constant;
            }
            if (constant > max || Point2F.isEqual(constant, max)) {
                max = constant;
            }
        }

        // Store values in vector
        container.set(min, max);
    }

    /**
     *
Checks whether or not an (x,y) point is found within the BodyComponent.

     *
     * @param x x.
     * @param y y.
     * @return true if the point exists within.
     */
    public final boolean contains(float x, float y)
    {
        // Check if point does not exist within the bounding box
        if (!mShape.getBounds().contains(x, y)) {
            return false;
        }

        // Check if point is within shape
        return mShape.contains(x, y);
    }

    /**
     *
Gets the {@link Shape} used for narrow phase collision detection.

     *
     * @return Shape.
     */
    public final Shape getShape()
    {
        return mShape;
    }

    /**
     *
Sets the {@link Shape} to use for narrow phase collision detection.

     *
     * @param shape Shape.
     */
    public final void setShape(Shape shape)
    {
        mShape = new Shape(shape);

        // Ensure shape can't be modified after set
        mShape.lock();
    }
    /**
     *
Gets the {@link Rect2D} to use as a bounding box for broad phase collision detection.

     *
     * @return bounding box.
     */
    public final Rect2D getBounds()
    {
        return mShape.getBounds();
    }

    @Override
    public final float getWidth()
    {
        return mShape.getWidth();
    }

    @Override
    public final void setWidth(float width)
    {
        mShape.setWidth(width);
    }

    @Override
    public final float getHeight()
    {
        return mShape.getHeight();
    }

    @Override
    public final void setHeight(float height)
    {
        mShape.setHeight(height);
    }

    @Override
    public float getCenterX()
    {
        return getX() + (getWidth() / 2f);
    }

    @Override
    public float getCenterY()
    {
        return getY() + (getHeight() / 2f);
    }

    @Override
    public double getRotation()
    {
        return mShape.getRotation();
    }

    @Override
    public void rotateTo(double angle)
    {
        mShape.rotateTo(angle);
    }

    @Override
    public void rotateBy(double angle)
    {
        mShape.rotateBy(angle);
    }

    /**
     *
Gets the coefficient of friction used when computing collision reactions.

     *
     * @return coefficient of friction.
     */
    public final float getFriction()
    {
        return mCOF;
    }

    /**
     *
Sets the coefficient of friction.

     *
     * @param coefficient coefficient.
     */
    public final void setFriction(float coefficient)
    {
        mCOF = coefficient;
    }

    /**
     *
Gets the coefficient of restitution used when computing collision reactions.

     *
     * @return coefficient of restitution.
     */
    public final float getRestitution()
    {
        return mCOR;
    }

    /**
     *
Sets the coefficient of restitution.

     *
     * @param coefficient coefficient.
     */
    public final void setRestitution(float coefficient)
    {
        mCOR = coefficient;
    }

    /**
     *
Gets the velocity.

     *
     * @return velocity vector.
     */
    public final Vector2F getVelocity()
    {
        return new Vector2F(mVelocity);
    }

    /**
     *
Copies the velocity into a given vector.

     *
     * @param container vector to copy to.
     */
    public final void getVelocity(Vector2F container)
    {
        container.copy(mVelocity);
    }

    /**
     *
Sets the velocity. If null is given, the current velocity is zeroed.

     *
     * @param velocity velocity vector.
     */
    public final void setVelocity(Vector2F velocity)
    {
        // Clear the velocity if given null
        if (velocity == null) {
            mVelocity.set(0f, 0f);
            return;
        }

        mVelocity.copy(velocity);
    }

    /**
     *
Gets the velocity from before the most recent physics update.

     *
     * @param container container.
     */
    final void getPreviousVelocity(Vector2F container)
    {
        container.copy(mOldVelocity);
    }

    /**
     *
Version of {@link #setVelocity(Vector2F)} for use in computing the new BodyComponent's new velocity during a
     * physics update. This changes the velocity returned by {@link #getPreviousVelocity(Vector2F)} to the vector
     * before this method is called.

     *
     * @param velocity new velocity.
     */
    final void updateVelocity(Vector2F velocity)
    {
        mOldVelocity.copy(mVelocity);
        mVelocity.copy(velocity);
    }

    /**
     *
Gets the current speed in meters per second.

     *
     * @return current speed.
     */
    public final float getSpeed()
    {
        return mVelocity.magnitude();
    }

    /**
     *
Gets the impulse vector to be applied in the next motion step.

     *
     * @return impulse.
     */
    public final Vector2F getImpulse()
    {
        return new Vector2F(mImpulse);
    }

    /**
     *
Copies the impulse into a given vector.

     *
     * @param container vector to copy to.
     */
    public final void getImpulse(Vector2F container)
    {
        container.copy(mImpulse);
    }

    /**
     *
Sets the impulse to be added during the next motion step.

     *
     * @param impulse impulse.
     */
    public final void setImpulse(Vector2F impulse)
    {
        if (impulse == null) {
            mImpulse.set(0f, 0f);
            return;
        }

        mImpulse.copy(impulse);
    }

    /**
     *
Adds an impulse to be added during the next motion step.

     *
     * @param impulse impulse.
     */
    public final void addImpulse(Vector2F impulse)
    {
        mImpulse.add(impulse);
    }

    /**
     *
Gets the acceleration.

     *
     *
This is the difference between the current and previous velocity.

     *
     * @return acceleration vector.
     */
    public final Vector2F getAcceleration()
    {
        return new Vector2F(mVelocity).subtract(mOldVelocity);
    }

    /**
     *
Copies the acceleration into a given vector.

     *
     *
This is the difference between the current and previous velocity.

     *
     * @param container vector to copy to.
     */
    public final void getAcceleration(Vector2F container)
    {
        container.copy(mVelocity);
        container.subtract(mOldVelocity);
    }

    /**
     *
Gets the mass in kilograms.

     *
     * @return kilograms.
     */
    public final float getMass()
    {
        return mMass;
    }

    /**
     *
Sets the mass in kilograms.

     *
     * @param mass kilograms.
     * @throws IllegalArgumentException if mass < 0.
     */
    final void setMass(float mass)
    {
        // Ensure no negative masses
        if (mass < 0f) {
            throw new IllegalArgumentException("Mass should be >= 0: " + mass);
        }

        mMass = mass;

        // Precompute inverse mass; store inverse infinite as 0
        mInvMass = (mass == 0f) ? 0f : 1f / mass;
    }

    /**
     *
Gets the inverse mass in kilograms. This value is often used in physics.

     *
     * @return (1 / mass) kilograms
     */
    public final float getInverseMass()
    {
        return mInvMass;
    }

    @Override
    public final Point3F getPosition()
    {
        return mShape.getPosition();
    }

    @Override
    public final float getX()
    {
        return mShape.getX();
    }

    @Override
    public final float getY()
    {
        return mShape.getY();
    }

    @Override
    public final float getZ()
    {
        return mShape.getZ();
    }

    @Override
    public final void moveTo(float x, float y)
    {
        // Move shape along
        mShape.moveTo(x, y);
    }

    @Override
    public final void moveTo(float x, float y, float z)
    {
        // Move shape along
        mShape.moveTo(x, y, z);
    }

    @Override
    public final void moveBy(float x, float y)
    {
        moveBy(x, y, 0f);
    }

    @Override
    public final void moveBy(float x, float y, float z)
    {
        // Move shape along
        mShape.moveBy(x, y, z);
    }

    @Override
    public void moveToCenter(float x, float y)
    {
        mShape.moveTo(mShape.getX() - (mShape.getWidth() / 2f), mShape.getY() - (mShape.getHeight() / 2f));
    }

    /**
     *
Checks whether the BodyComponent can be selected.

     *
     * @return true if selection is allowed.
     */
    public final boolean isSelectable()
    {
        return mSelectable;
    }

    /**
     *
Sets whether or not the BodyComponent can be selected.

     *
     * @param enable true to allow selection.
     */
    public final void setSelectable(boolean enable)
    {
        mSelectable = enable;
    }

    /**
     *
Checks if the BodyComponent has infinite mass and is not meant to move during physics updates.

     *
     * @return true if not meant to move through physics.
     */
    public final boolean isStatic()
    {
        return mMass == 0f;
    }

    /**
     *
Checks if the BodyComponent should process collisions with other BodyComponents.

     *
     * @return true if collisions are allowed.
     */
    public final boolean isCollidable()
    {
        return mCollidable;
    }

    /**
     *
Sets whether or not the BodyComponent is allowed to process collisions with other BodyComponents.

     *
     *
Using {@link #collidesWith(BodyComponent, Manifold)} with a non-collidable BodyComponent, whether
     * caller or argument, will return false.

     *
     * @param enable true to allow collisions.
     */
    public final void setCollidable(boolean enable)
    {
        mCollidable = enable;
    }

    /**
     *
Checks if collisions with the owning {@link GObject}'s parent are ignored.

     *
     * @return true if collisions with the GObject's parent are ignored.
     */
    public final boolean isIgnoreParentEnabled()
    {
        return mIgnoreGObjectParent;
    }

    /**
     *
Sets whether to ignore collisions with the {@link GObject}'s parent.

     *
     * @param enable true to ignore collisions with the GObject's parent.
     */
    public final void setIgnoreGObjectParent(boolean enable)
    {
        mIgnoreGObjectParent = enable;
    }

    /**
     *
Gets the {@link BoundingTree.Node} containing the BodyComponent for fast lookup.

     *
     * @return BoundingTree's Node.
     */
    BoundingTree.Node getContainer()
    {
        return mContainer;
    }

    /**
     *
Sets the {@link BoundingTree.Node} to represent the BodyComponent within the tree.

     *
     * @param container Node.
     */
    void setContainer(BoundingTree.Node container)
    {
        mContainer = container;
    }

    /**
     *
Gets the {@link ContactGraph.Node} representing the BodyComponent in a {@link ContactGraph} for fast
     * lookup.

     *
     * @return ContactGraph's Node.
     */
    ContactGraph.Node getContactNode()
    {
        return mContactNode;
    }

    /**
     *
Sets the {@link ContactGraph.Node} to represent the BodyComponent within a {@link ContactGraph}. This
     * allows for fast lookup in the graph.

     *
     * @param node Node.
     */
    void setContactNode(ContactGraph.Node node)
    {
        mContactNode = node;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException
    {
        throw new CloneNotSupportedException("BodyComponents should only come from the BodyFactory");
    }

    /**
     *
Computes contact points between this BodyComponent and another. This method is step #2 of collision
     * detection from {@link #collidesWith(BodyComponent, Manifold)}.

     *
     * @param contacts container for points.
     * @param depths container for points' penetration depths.
     * @param other colliding body.
     * @param sepAxis separating axis of minimum translation.
     */
    private void getContacts(List<Vector2F> contacts, List<Float> depths, BodyComponent other, Vector2F sepAxis)
    {
        // Find calling Shape's colliding edge
        findContactEdge(mRefEdge, mShape, sepAxis);

        // Find other Shape's colliding edge (flip separating axis to originate from other body)
        sepAxis.negate();
        other.findContactEdge(mIncEdge, other.mShape, sepAxis);
        sepAxis.negate();

        // Swap reference and incident edges if incident is more perpendicular against axis
        if (shouldSwap(mRefEdge, mIncEdge, sepAxis)) {
            swapRoles(mRefEdge, mIncEdge);
        }

        // Clip shapes and save contact points and penetration depths
        clipShapes(contacts, depths, mRefEdge, mIncEdge);
    }

    /**
     *
Swaps the vertices between the reference and incident edges.

     *
     * @param reference reference edge.
     * @param incident incident edge.
     */
    private void swapRoles(CollidingEdge reference, CollidingEdge incident)
    {
        // Set aside reference's data
        final Vector2F begin = reference.mBegin;
        final Vector2F end = reference.mEnd;
        final boolean farthest = reference.mBeginFarthest;

        // Copy incident's data to reference
        reference.mBegin = incident.mBegin;
        reference.mEnd = incident.mEnd;
        reference.mBeginFarthest = incident.mBeginFarthest;

        // Set reference's old data as incident
        incident.mBegin = begin;
        incident.mEnd = end;
        incident.mBeginFarthest = farthest;
    }

    /**
     *
Perform clipping operations between the two edges.

     *
     * @param contacts contact points.
     * @param depths penetration depths.
     * @param reference reference edge.
     * @param incident incident edge.
     */
    private void clipShapes(List<Vector2F> contacts, List<Float> depths, CollidingEdge reference, CollidingEdge incident)
    {
        // Make direction vector from reference edge
        mEdge.copy(reference.mEnd);
        mEdge.subtract(reference.mBegin);
        mEdge.normalize();

        // Clip at reference edge's first vertex
        float offset = mEdge.dotProduct(reference.mBegin);
        clip(contacts, incident.mBegin, incident.mEnd, mEdge, offset);

        assert (contacts.size() >= 2);

        // Clip at reference edge's second vertex with direction reversed
        offset = mEdge.dotProduct(reference.mEnd);
        mEdge.negate();
        clip(contacts, contacts.get(0), contacts.get(1), mEdge, -offset);
        mEdge.negate();

        // Transform ref unit vector into a normal towards the reference edge
        makeNormalTowardsReference(mEdge, reference, incident);

        // Add first contact point if within clip area (depth >= 0f is inside)
        offset = mEdge.dotProduct(reference.getFarthestVertex());
        final float depth0 = mEdge.dotProduct(contacts.get(0)) - offset;
        if (depth0 < 0f) {
            contacts.remove(0);
        } else {
            depths.add(depth0);
        }

        // Add second contact point if within clip area (depth >= 0f is inside)
        final float depth1 = mEdge.dotProduct(contacts.get(contacts.size() - 1)) - offset;
        if (depth1 < 0f) {
            contacts.remove(contacts.size() - 1);
        } else {
            depths.add(depth1);
        }
    }

    /**
     *
Turns the reference unit vector into a perpendicular vector facing towards the reference edge.

     *
     * @param refUnit reference's unit vector.
     * @param refEdge reference edge.
     * @param incEdge incident edge.
     */
    private void makeNormalTowardsReference(Vector2F refUnit, CollidingEdge refEdge, CollidingEdge incEdge)
    {
        final Vector2F incVertex = incEdge.getFarthestVertex();

        // Compute distance from first normal (positioned from ref edge) to the inc edge's farthest vertex
        final Vector2F norm0 = refUnit.getNormal(false);
        norm0.add(refEdge.mBegin);
        final double dist0 = Math.abs(Point2F.distanceBetween(norm0.getX(), norm0.getY(), incVertex.getX(), incVertex
                .getY()));

        // Compute distance from second normal (positioned from ref edge) to the inc edge's farthest vertex
        final Vector2F norm1 = refUnit.getNormal(true);
        norm1.add(refEdge.mBegin);
        final double dist1 = Math.abs(Point2F.distanceBetween(norm1.getX(), norm1.getY(), incVertex.getX(), incVertex
                .getY()));

        if (dist0 < dist1) {
            refUnit.normal(false);
        } else {
            refUnit.normal(true);
        }
    }

    /**
     *
Clips a line segment formed by two points against a normal moved by an offset and adds new points to the
     * list. If a point previously added to the list is outside the new clipping area, the point is removed.

     *
     * @param points container.
     * @param incBegin line's starting point.
     * @param incEnd line's ending point.
     * @param normal normal to clip against.
     * @param offset normal's offset.
     */
    private void clip(List<Vector2F> points, Vector2F incBegin, Vector2F incEnd, Vector2F normal, float offset)
    {
        // Compute dot products of each point on the edge with an offset to origin
        final float edgeDot0 = incBegin.dotProduct(normal) - offset;
        final float edgeDot1 = incEnd.dotProduct(normal) - offset;

        // Check if second point is in list
        final boolean contained0 = points.size() > 0 && points.get(0) == incBegin;
        if ((edgeDot0 > 0f || Point2F.isEqual(edgeDot0, 0f))) {

            // Save beginning point if not inside
            if (!contained0) {
                points.add(incBegin);
            }
        } else if (contained0) {
            points.remove(0);
        }

        // Check if second point is in list
        final boolean contained1 = !points.isEmpty() && points.get(0) == incEnd
                || (points.size() > 1 && points.get(1) == incEnd);
        if ((edgeDot1 > 0f || Point2F.isEqual(edgeDot1, 0f))) {

            // Save second point if not inside
            if (!contained1) {
                points.add(incEnd);
            }
        } else if (contained1) {
            points.remove(points.size() - 1);
        }

        // Negative product means a point was dropped (dropped point's dot prod was > 0)
        if ((edgeDot0 < 0f || edgeDot1 < 0f)) {

            // Make new point out of incident edge
            final Vector2F clippedPt = new Vector2F(incEnd);
            clippedPt.subtract(incBegin);

            // Compute clipped point along edge
            clippedPt.multiply(edgeDot0 / (edgeDot0 - edgeDot1));
            clippedPt.add(incBegin);

            points.add(clippedPt);
        }
    }

    /**
     *
Checks if the reference edge and incident edges should be swapped as the reference edge should be the edge
     * more perpendicular to the separating axis.

     *
     * @param reference reference edge.
     * @param incident incident edge.
     * @param axis separating axis.
     * @return true if given incident edge should be reference.
     */
    private boolean shouldSwap(CollidingEdge reference, CollidingEdge incident, Vector2F axis)
    {
        // Create a vector from reference edge and project onto axis
        mEdge.copy(reference.mEnd);
        mEdge.subtract(reference.mBegin);
        final float refDot = Math.abs(mEdge.dotProduct(axis));

        // Create a vector from incident edge and project onto axis
        mEdge.copy(incident.mEnd);
        mEdge.subtract(incident.mBegin);
        final float incDot = Math.abs(mEdge.dotProduct(axis));

        // Should swap roles so edge less perpendicular to separating axis is "incident edge"
        return incDot < refDot;
    }

    /**
     *
Determines the edge of a {@link Shape} which is most likely colliding with another Shape.

     *
     * @param edge container to fill with the colliding edge.
     * @param shape Shape which the edge belongs to.
     * @param sepAxis separating axis facing outwards from the Shape.
     */
    private void findContactEdge(CollidingEdge edge, Shape shape, Vector2F sepAxis)
    {
        final float[] pt = new float[2];
        final int ptCount = shape.getPointCount();

        // Find edge's first point
        int farthestIndex = 0;
        float maxProj = -Float.MAX_VALUE;
        for (int i = 0; i < ptCount; i++) {
            shape.getPoint(i, pt);

            // Save pt with largest projection onto sep axis (closest pt to other shape)
            final float proj = (pt[0] * sepAxis.getX()) + (pt[1] * sepAxis.getY());
            if (maxProj < proj) {
                maxProj = proj;
                farthestIndex = i;
            }
        }

        // Set closest pt to other shape as edge's beginning point
        shape.getPoint(farthestIndex, pt);
        final Vector2F farthestPt = new Vector2F(pt[0], pt[1]);

        // Figure edge's both possible end points (beginning point's neighbors)
        final int endPtIndex0 = (farthestIndex == 0) ? ptCount - 1 : farthestIndex - 1;
        final int endPtIndex1 = (farthestIndex == (ptCount - 1)) ? 0 : farthestIndex + 1;

        // Compute first possible end point's projection
        shape.getPoint(endPtIndex0, pt);
        final Vector2F endPt = new Vector2F(farthestPt);
        endPt.subtract(pt[0], pt[1]);
        endPt.normalize();
        final float endPtProj0 = Math.abs(endPt.dotProduct(sepAxis));

        // Compute second possible end point's projection
        shape.getPoint(endPtIndex1, pt);
        endPt.copy(farthestPt);
        endPt.subtract(pt[0], pt[1]);
        endPt.normalize();
        final float endPtProj1 = Math.abs(endPt.dotProduct(sepAxis));

        // Choose most perpendicular two vertices to use for colliding edge
        if (endPtProj0 < endPtProj1 || Point2F.isEqual(endPtProj0, endPtProj1)) {

            // Get first possible end pt again since current pt is second possible
            shape.getPoint(endPtIndex0, pt);
            endPt.set(pt[0], pt[1]);

            // Edge starts at end point and ends with farthest point
            edge.update(endPt, farthestPt, false);
        } else {

            shape.getPoint(endPtIndex1, pt);
            endPt.set(pt[0], pt[1]);

            // Edge starts at farthest point and ends with end point
            edge.update(farthestPt, endPt, true);
        }
    }

    boolean isSleeping()
    {
        return mSleeping;
    }

    void setSleeping(boolean enable)
    {
        mSleeping = enable;
    }

    /**
     *
Represents a colliding edge during contact point generation in
     * {@link #getContacts(List, List, BodyComponent, Vector2F)}.

     */
    private class CollidingEdge
    {
        // Beginning vertex
        private Vector2F mBegin;

        // Ending vertex
        private Vector2F mEnd;

        // Whether the beginning vertex is the farthest along the separating axis
        private boolean mBeginFarthest = false;

        /**
         *
Sets the beginning and ending vertices.

         *
         *
The farthest vertex is considered the vertex whose projected position is the farthest along the
         * separating axis when the axis points from the vertex's body to another.

         *
         * @param begin beginning vertex.
         * @param end ending vertex.
         * @param beginIsFarthest whether beginning vertex is farthest along separating axis.
         */
        public void update(Vector2F begin, Vector2F end, boolean beginIsFarthest)
        {
            mBegin = begin;
            mEnd = end;
            mBeginFarthest = beginIsFarthest;
        }

        /**
         *
Gets the vertex whose projection along the separating axis is the farthest away from the
         * {@link BodyComponent}. This is either the beginning or ending vertex of the edge.

         *
         * @return farthest vertex.
         */
        public Vector2F getFarthestVertex()
        {
            return (mBeginFarthest) ? mBegin : mEnd;
        }
    }

    /**
     *

     *     Container for data about the collision of two {@link BodyComponent}s such as contact points and the
     *     collision normal.
     *

     *
     *

     *     The collision normal is a unit vector denoting direction from one BodyComponent to another. The
     *     BodyComponent the collision normal faces away from is always the "owning" body. Each contact point is
     *     two-dimensional and stored with the depth of penetration into the body.
     *

     */
    public static final class Manifold
    {
        // Contact points
        private final List<Vector2F> mPoints = new ArrayList<Vector2F>();

        // Penetration depths for each contact point
        private final List<Float> mDepths = new ArrayList<Float>();

        // Contact normal
        private final Vector2F mNormal = new Vector2F();

        /**
         *
Gets the contact point at an index.

         *
         * @param i index.
         * @return contact point.
         */
        public Vector2F getContactPointAt(int i)
        {
            return mPoints.get(i);
        }

        /**
         *
Sets the contact point at a specific index.

         *
         * @param i index.
         * @param point contact point.
         * @param penetration penetration depth.
         */
        private void setContactPoint(int i, Vector2F point, float penetration)
        {
            mPoints.add(i, point);
            mDepths.add(i, penetration);
        }

        /**
         *
Gets the penetration depth of a contact point.

         *
         * @param i contact point index.
         * @return penetration depth.
         */
        public float getPenetrationDepthAt(int i)
        {
            return mDepths.get(i);
        }

        /**
         *
Gets the number of contact points.

         *
         * @return contact point count.
         */
        public int getContactPointCount()
        {
            return mPoints.size();
        }

        /**
         *
Copies the contact normal into a given vector.

         *
         * @param container vector to hold collision normal.
         */
        public void getCollisionNormal(Vector2F container)
        {
            container.copy(mNormal);
        }

        /**
         *
Copies the stored contact normal to a vector. The contact normal will point in the direction from the
         * host {@link BodyComponent} to the BodyComponent it collided with.

         *
         * @param normal collision normal.
         */
        public void setContactNormal(Vector2F normal)
        {
            mNormal.copy(normal);
            mNormal.normalize();
        }

        /**
         *
Copies the collision data from another Manifold.

         *
         * @param manifold Manifold to copy.
         */
        public void copy(Manifold manifold)
        {
            // Replace points with given Manifold's
            mPoints.clear();
            mPoints.addAll(manifold.mPoints);

            // Replace penetration depths with given Manifold's
            mDepths.clear();
            mDepths.addAll(manifold.mDepths);

            // Replace collision normal
            mNormal.copy(manifold.mNormal);
        }

        /**
         *
Empties the Manifold of all collision information.

         */
        public void clear()
        {
            mPoints.clear();
            mDepths.clear();
            mNormal.set(0f, 0f);
        }
    }
}


To tie in with brand ambassador Serena Williams' appearance at the Australian Open, iconic headphone company Beats By Dre tasked us with designing and running a pop-up photography brand activation in Melbourne's high profile Fed Square location.
We constructed a fully kitted out photography studio and surprised passers-by with the chance to star in their very own campaign image, styled just like Serena's.
Wearing the new Beats wireless headphones while listening to a pumping soundtrack, participants had a mini 1-minute photoshoot, with their best picture edited on the spot and emailed to them instantly to keep and share on social media.
We photographed everyone from international and local celebrities to the general public, with Sharon's mad skills at getting people to have fun and show their personalities on camera really shining through.


text:
Home Documentary Urartu. The Forgotten Kingdom (2020)
Urartu. The Forgotten Kingdom (2020)
In the Bible, Urartu was the most ancient state on Earth. It was there where Noah's ark stopped, and there where humanity found its salvation. The locals had a developed culture, economy, astronomy, and religious life. According to scientists' latest discoveries, the culture of Urartu was the most advanced in the ancient world. And it had a great impact on the Persian Empire of the Achaemenids and ancient Greece. Due to a lack of research, Urartu is probably one of the most mysterious states in history. This documentary will introduce us to its unique background.
Genre: Documentary, Drama, History
Country:Armenia, Russian Federation
Release: 10 Jun 2020
Director:Vaga Vardanyan
Cast:Arman Navasardyan, Arsen Ohanjanyan, Artashes Shahverdyan, Michael Poghosian, Ruben Muradyan, Vahagn Martirosyan
By movieakPosted on August 30, 2021 View: 135 views
Posted in Documentary, Drama, History, HD, Armenia, Russian FederationTagged Bioskop 21, Bioskopkeren, Box-Office, CGV Blitz, Cinema XXI, Cinemaindo, Download Urartu. The Forgotten Kingdom Terbaru, Dunia21, Free Download Urartu. The Forgotten Kingdom, Ganool, GoSemut, imdb movie, indoxxi, layar kaca, lk21, Netflix, Nonton Urartu. The Forgotten Kingdom gratis, Sobatkeren, Streaming Urartu. The Forgotten Kingdom, Watch Urartu. The Forgotten Kingdom Free
SAS: Red Notice (2021)
Action, Drama, Thriller, Hungary, Netherlands, Switzerland, United Kingdom
11 Aug 2021 Magnus Martens
Endgame 2050 (2020)
19 May 2020 Sofia Pineda Ochoa
Crime, Drama, Thriller, China, United Kingdom, USA
03 Sep 2021 Paul Schrader
Action, Animation, Drama, Science Fiction, Japan
08 Mar 2021 Hideaki Anno

redpajama_set_name: RedPajamaCommonCrawl


Are you scared to travel with your allergic child? Having food allergies has never stopped this Allergic Traveler from discovering the world. There is so much to see, it would be a shame not to see what the world has to offer. From an early age, my parents instilled the importance of traveling in me. I went on my first trip at the age of two to Florida.


text:
Famous Relationships
'Batman – The Telltale Series:' Season 1 Finale Set To Release Dec. 13, First Episode Free On Steam
Asma M
The first season of Batman — The Telltale Series is set to wrap up with its fifth episode on December 13. Episode 5 is titled "City of Light," and the trailer is expected to debut on Monday, December 12. PC gamers on Steam who have yet to play the series can now download the first episode, "Realm of Shadows," for free.
It's time to journey back to Arkham Asylum.
Watch the trailer for the season finale of #Batman - The Telltale Series TOMORROW. pic.twitter.com/hQafqZ1Gke
— Telltale Games (@telltalegames) December 11, 2016
Episode 5 is being released digitally for players on all platforms simultaneously. Whether they're playing on PC, Xbox, PlayStation, or even if they've downloaded it to their Android or iOS mobile device, everyone should get to play the final episode on the expected released date.
Although the Mature-rated game is based on the characters from the comic books, and the series is designed to give players an experience that feels like playing a comic book rather than reading one, the game is not an adaptation of any particular Batman series or story arc. The Senior Creative Communications Manager at Telltale Games explains via PlayStation Blog that the game involves putting players front and center with the choices Bruce Wayne and his Dark Knight alter ego are faced with early on in his crime-fighting career.
"How is Telltale's vision of Batman unique? For a start, the series is equally as much about the man behind the mask as it is about Batman himself. In this game, you'll enter the fractured psyche of Bruce Wayne and discover the powerful and far-reaching consequences of your choices as the Dark Knight. It's a gritty and violent new story in which you'll make discoveries that will shatter Bruce Wayne's world, and the already fragile stability of a corrupt Gotham City."
At the start of the season, Bruce Wayne embarks on a mission to clear the reputations of his deceased parents. Rumor has it they were involved with Gotham's murky organized crime rings; and, whether the cape and cowl is on or not, the truths uncovered are not always what they seem to be. The information unearthed also depends on the decisions made, and the ways relationships have been built (or destroyed) with other characters like Selena Kyle, Harvey Dent, and James Gorden. As the player progresses through each episode, they carve into existence a distinctive Batman/Bruce Wayne that reflects the nature of the choices they've made thus far.
Heads or tails?
A trailer for the season finale of #Batman - The Telltale Series drops TOMORROW. pic.twitter.com/WlRlsi7eIa
For the first time in a Telltale series, a group of friends can play the game together using a new feature dubbed Crowd Play. When in this local multiplayer game mode, four to 12 players can simultaneously vote on the choices for the title character. The most popular choice among the group is used to progress the game (unless the game's host decides to veto and decide otherwise). As far as why this feature is limited to local multiplayer, the developer cites technical limitations.
"Crowd Play is not a feature intended for use over streaming services. There is latency introduced by services such as Twitch. This means that everyone isn't seeing that game at the exact same time, which means that everyone doesn't see the choices at the same time. So, the group can't make a choice together at the same time. We are working closely with all the streaming services to address this problem…"
Hosting a Crowd Play session is also currently limited to the console and PC/Mac versions of the game, but players can still use their mobile devices to join in on a hosted game whether they own a copy or not. Everyone just needs to be able to see the main screen featuring the game, while other devices are used like controllers to cast their vote on in-game decisions.
...Which mask will you wear?
'City of Light,' the season finale of #Batman - The Telltale Series, premieres December 13. pic.twitter.com/mIZE0xwl5y
— Telltale Games (@telltalegames) December 7, 2016
The voice cast of the Batman Telltale series is notably different from the Arkham game series but includes actors many are likely familiar with. Troy Baker takes on the role of Batman/Bruce Wayne, Laura Bailey plays Selina Kyle/Catwoman, and Travis Willingham is cast as Harvey Dent/Two-Face. The cast also includes Enn Reitel as Alfred Pennyworth, Murphy Guyer as James Gorden, Richard McGonagle as Carmine Falcone, and Erin Yvette as Vicki Vale.
Are you excited to see the conclusion of Telltale's Batman series? What choices have you made for Bruce Wayne or Batman during the season, and do you think there should be a Season 2? Sound off in the comments below.
[Featured Image by Telltale Games]
US Politics New Hampshire Republican Claims That Owning Slaves Doesn't Make A Person Racist
Celebrities Angela Simmons Rocks A Pink Bikini & Poses On Her Knees
Celebrities Alexina Graham Grabs Her Bare Chest While Laying In Bed
Basketball NBA Rumors: Memphis Grizzlies Could Be Wearing Vancouver Grizzlies Throwbacks For Select Games Next Season
Celebrities Erica Mena Exposes Her Chest In A Criss Cross Swimsuit
Celebrities Brazilian Bombshell Erika Gray Lets It All Hang Out In Skimpy Pink Bikini


text:
Angry Birds Star Wars now available on your favorite device, well mostly
by Calvin November 9, 2012
written by Calvin November 9, 2012
Fans of Angry Birds and/or Star Wars, here's what you've been waiting for as Rovio just launched their Angry Birds Star Wars game to a lot of devices and platform.
The game can be found in Google Play, App Store for both iOS and Mac, Windows Store for both mobile and Windows 8 devices, Amazon, Angry Birds Online Shop for the PC, and even on Intel AppUp. The whole shebang… well except in BlackBerry App World and Nokia Store.
The best deal would be for Android users who can download the game for free while it's $0.99 in the iTunes store for iPhone and iPod Touch, $2.99 for the iPad, $2.99 at the Kindle Fire store. PC users who wants to play the desktop version have to shell out $4.95 to purchase the game from the Angry Birds Online Shop.
Angry Birds Star Wars game brings you 80 levels in iconic locations like Tatooine and the Pig Star plus hidden bonus levels featuring R2D2 and C3PO. There's also a new mechanic where you can level up your birds to improve their skills! For example, your typical, boring red bird (Luke) will get the light saber once it meets the black bird (Jedi) who can use the Force instead of explode. Pigs can now fight back as well with those dressed up as stormtroopers can shoot with their laser guns.
I'm still at the early levels of the game but can't wait to meet the other characters like Chewie and Princess Leia.
Go check the game out at http://angrybirds.tumblr.com/.
angry birdsroviostar wars
ASUS ET2300 All-in-One PC gives you an articulating 23″ multi-touch display
Cherry Mobile Flare Review, is it really worth P3,999?
Experience Augmented Reality like Never Before with Star...
TOP 5 Best Western RPGs Ported to Android
UK audio accessory brand Gear4 now available in...
Samsung brings Angry Birds to motion-controlled Smart TVs
BlackBerry PlayBook finally gets Angry Birds app
Top 10 "Best Gifts Ever" from Power Mac...


text:
Droughtlander Re-Watch: EP102 ("Castle Leoch")
Droughtlander Re-Watch: EP101 ("Sassenach")
A message from Jeff Woodman
OUTLANDER Season 3 will premiere in September!
VOYAGER fan video
Favorite romantic quotes from the OUTLANDER books
What scenes are you most looking forward to in Sea...
January poll results
Droughtlander Re-Watch, Week 2: Episode 102 ("Castle Leoch")
*** SPOILER WARNING! ***
If you haven't watched all of OUTLANDER Seasons 1 and 2, there are SPOILERS in this post. Read at your own risk.
As they arrive at the castle, it's easy to pick out Murtagh, Rupert, and Angus. But I remember very well how hard it was to tell the clansmen apart, on the first few viewings.
Look at Murtagh in that first scene, and think about how he looked in the Paris scenes in Season 2, all cleaned up with his hair combed and his beard neatly trimmed. Looking at him here, it's almost hard to believe it's the same character. <g>
The scene with Jamie and Claire is very much as I always imagined from the book. But after Episode 106 ("The Garrison Commander"), it's impossible to see the scars on Jamie's back without remembering those horrific scenes of the flogging.
Jamie shows a little more humor here than in the book. ("They were holding me prisoner.")
Jenny looks very young in the flashback scene -- more so than I remembered. That whole scene was very well done. I had forgotten the bit with BJR rubbing his thumb over Jenny's face. Ewwww! <shudder>
When Jamie takes Claire into his arms for the first time and holds her as she weeps for Frank, I couldn't help remembering that this is the point where Jamie said much later that he fell in love with her. Awwww!
The dressing scene with Mrs. Fitz is just priceless, and very funny! My favorite part is the bit where Mrs. Fitz snatches the cup of broth out of Claire's hands before she's had more than a couple of sips. <g>
I hadn't realized before that the letter with "1743" on it was lying in plain sight on the desk.
The sight of Colum's legs is shocking, but very much as I'd imagined from the book. The use of CGI here is very clever.
"Is there ever a good reason for rape, Master MacKenzie?" Great line! I had forgotten about that.
"It was all second-hand knowledge, acquired from books, museums, paintings" -- and old Scottish songs, like "Loch Lomond"? <g> Look here for my thoughts on that from my first viewing of the episode in 2014.
When Claire walks into the Great Hall, my impression is that she's showing a lot more cleavage than strictly necessary. <g> Another reminder of her "other-ness". It makes her look like a bit of a slut, by 18th-century standards, IMHO.
Colum's interrogation is very effective, no doubt about it. Claire really is a very bad liar, and she's drinking quite a lot, even before the Rhenish makes its appearance.
And then Hamish shows up, and she puts her foot in it, in no uncertain terms! Oops. <g>
I love the thatched roofs on the little buildings Claire passes on the way to the stables.
"She's just a girl with spirit, is all. That's always a good thing." I love that line, and the way Jamie looks at her.
The whole conversation in the stable is taken almost word-for-word from the book. That's a pleasure to see.
"Try not to get flogged or stabbed today."
"No promises, Sassenach."
I like that very much. <g>
The scene with Claire and Rupert is terrific, a great addition. Listening to Rupert describe Angus, I can't help thinking of so many of the scenes to come involving Angus, up to and including the way he died. It's hard to remember that at this point in the story, he's just one of the clansmen in the background, and we don't know him at all yet.
I liked the scene between Claire and Dougal very much, too. On re-watching, this seems like foreshadowing of several similar confrontations to come. (At St. Ninian's Spring in Episode 106, for example.)
Claire's introduction to Geillis is suitably mysterious. "I know who you are, Claire" -- indeed, she may well know a lot more about Claire than Claire knows about her! (Thinking about the notebook where she kept notes about mysterious occurrences near stone circles, including Claire's own disappearance.)
I had forgotten how much Gaelic is in this episode, particularly throughout the scene in the Hall.
Right before Jamie raises his voice to address Colum and the rest of the people in the Hall, you can see him and Murtagh talking quietly, while the crowd's attention is focused on Laoghaire. Murtagh is definitely not happy -- from his body language alone, you can tell that he knows what Jamie is about to do, and he doesn't like it, but he can't stop him. I totally missed that in previous viewings of this episode.
Jamie is so young here, young and cocky and fearless -- and evidently enjoying himself. <g> Very much as I've always imagined from the book.
I like the way Jamie grins at Rupert after the first blow, as if to say, "Is that all you've got?"
And then Rupert hits him very hard in the injured shoulder, and I gasped. Owwwww! "That's not fair!" I thought, and then I heard the much older Jamie's voice in my head, saying, "Dirty fighting is the only kind there is."
Claire seems much too willing to leave Laoghaire alone with Jamie. "I think someone would like to speak with you." On the other hand, she thinks she's leaving forever, and she has no idea that Jamie is falling in love with her.
The scene with Colum and Claire is terrific! Claire really underestimated him.
"You'll remain here, as my guest."
"You mean as your prisoner, don't you?"
"Only if you try to leave."
What a chilling, and subtly terrifying, way to end the episode! I really felt sorry for Claire at the end, more alone now than she's been since she came through the stones.
Please come back next week for my reactions to Episode 103, "The Way Out".
Posted by Karen Henry at 4:57 AM 3 comments
Looking for a way to pass the time until OUTLANDER Season 3 returns in September? Here's a suggestion that was posted on Compuserve the other day.
There are 29 weeks between now and the beginning of September. By coincidence, there are 29 episodes in Seasons 1 and 2. So the idea is to watch one episode per week, starting from the beginning, and post your impressions. For example:
Has your reaction to the episode changed over time?
Did you notice things on re-watching that you didn't catch before?
Is there anything in the episode that seems like foreshadowing of future events?
What are your favorite (or least favorite) scenes, lines, or moments in the episode?
To start things off, here are my comments on the first episode:
Droughtlander Re-Watch, Week 1: EP101 ("Sassenach")
The opening shot, of the gorgeous Highland scenery, is just breathtaking! In many ways the first season is a "love letter to Scotland", as I think Matt Roberts said of EP105, and this was our first taste of it.
I haven't seen the opening credits of the first half of Season 1 in a long time, and I had forgotten some parts of it, like the glimpse of Frank and Claire sitting on the dock. Seeing Diana's name in the opening credits reminds me what an enormous thrill it was to see this, the first time.
The bit with Frank remembering how he used to doodle the lines in Claire's hand on official reports is cute, and serves to humanize him more than in the book.
Seeing the half-destroyed 1940's Castle Leoch was a shock. I had forgotten that. It looks really WRONG, especially now that i've seen Castle Doune, where they filmed it, with my own eyes.
"You can give me a bath." I still don't care for this. It has to be one of the most un-romantic places ever, for a sex scene! <g>
Good to see the Reverend and Mrs. Graham again. Of course I can't watch the tea-leaf reading scene without hearing the echo of it in Claire's fortune-telling in EP114, "The Search", where she borrows heavily from everything Mrs. Graham told her in this scene.
The mention of Sandringham's death (with the conveniently timed rattle of dishes <g>) now conjures up a whole host of images and bits of dialogue from EP211, of course.
I still don't like the ghost scene. It's nearly impossible to make out the ghost in the dark, and I for one can't tell what he's wearing. Maybe Frank just has much better eyesight than I do?
"I love you, and nothing you could ever do could stop my loving you." I know it's a quote from OUTLANDER, but it occurred to me, watching this, that Jamie said something very similar to her in MOHB. <g>
The scene with the dancers at Craigh na Dun is just mesmerizing, eerie and beautiful, and I love the music as much as I did the first time I saw this episode. Watching the sun rise over Craigh na Dun now makes me think of the final scene of Season 2, of course, with the dawn lighting Claire's face as she realizes Jamie didn't die at Culloden after all.
I had forgotten about "Run, Rabbit, Run." <g> I love the long, lingering look Claire gives Frank as he leaves -- take a good look, you won't see him for a while!
Even though I knew it was coming, I still jumped at the sound of the gunshot. Yikes! The music in the chase scene is just wondeful.
The scene with Claire and BJR is terrific! And I had to laugh, this time, when Murtagh whacked Claire over the head -- his specialty, as we found out later. <g>
When I first watched this episode in 2014, I found it nearly impossible to tell the clansmen apart. Now, of course, it's easy to spot Rupert ('We could put her to the test") and Angus.
The first meeting between Jamie and Claire is just wonderful, every bit as I had always imagined it from the book!
And here's the Jamie and Claire theme music, for the first time. <g> I love that!
As they mount up to ride away, it's absolutely pouring rain. I hadn't remembered that, and I feel sorry for the actors having to film in those conditions. But Jamie's "You're shakin' so hard it's making my teeth rattle" is a great line!
When Jamie intercepts Claire as she's trying to escape, I thought of the big argument by the roadside in EP109, "The Reckoning". You can see flashes of that here, especially in Claire's facial expressions and body language.
"That ride through the dark together....", as Jamie recalls much later.<g> Cait is more or less channeling Claire in the scene where she dresses Jamie's wound, and it's amazing to see.
When Claire reached down a hand to help him up, I thought at once of the scene in EP201 where Claire comes down off the plane and we're suddenly in 1744, with Jamie's hand reaching up to clasp hers. <g>
And that "Thank you, Sassenach. Truly." is just wonderful! I've always felt that Jamie was speaking on behalf of all of the fans who waited so many years to see this story come to life on TV.
"On your horse, soldier." It's impossible to hear that now without thinking of the other times TV Claire has said similar things to Jamie. Although, as Claire says in the voiceover that ends this episode, "How could I remember something that hadn't happened yet?" <g>
I plan to continue posting these each week until September. Please come back in a few days to see my impressions of Episode 102.
We had a surprise visitor on the Compuserve Books and Writers Community yesterday. Jeff Woodman, who narrates the Lord John audiobooks, popped in to say hello:
I've retired from audiobook narration, but will continue to do the Lord John books as they emerge because I just LOVE them!
I'm very glad to hear that he will continue to do the narration for any future Lord John books or stories. Diana Gabaldon has said that his voice for Lord John sounds exactly like what she hears in her head.
Here's a very interesting interview from a few years ago where Jeff Woodman goes into some detail about what it's like to be an audiobook narrator.
UPDATE 2/19/2017 7:10 pm: Jeff Woodman has been posting some very interesting comments in the thread on Compuserve. I would really encourage you to take a look.
If you've never listened to the Lord John audiobooks, I would definitely recommend them!
Posted by Karen Henry at 11:45 AM 3 comments
STARZ announced today that Season 3 of OUTLANDER will premiere in September 2017.
Carmi Zlotnik, President of Programming for Starz said "While 'Droughtlander' will last just a little longer, we feel it is important to allow the production the time and number of episodes needed to tell the story of the 'Voyager' book in its entirety. The scale of this book is immense, and we owe the fans the very best show. Returning in September will make that possible."
Steve Kent, Senior Executive Vice President, Programming, Sony Pictures Television said, "With the scope of the production and all of the intricate details that go into the Emmy®-nominated sets and costumes, we had to make sure everything is kept to the high standard of the previous seasons and Diana Gabaldon's beautiful story. We're so proud of the incredible work that Ron and the Outlander team have done."
I know a lot of fans will be disappointed to hear this, but just speaking for myself, I'm glad to hear that they won't have to rush the production to meet an arbitrary deadline, and that they're taking the time they need to do justice to the story.
VOYAGER has always been one of my favorite books in the series, as it is for so many OUTLANDER fans all over the world, and I am really encouraged that they are going to take the time they need to do the best possible adaptation of Diana Gabaldon's wonderful story.
And I admit to being relieved that for the first time since 2013, I'll be able to enjoy the spring and summer without spending all my spare time managing "thread explosions" on Compuserve.
To those of you who may be tempted to take out your frustrations on social media by attacking STARZ, Ronald D. Moore, Maril Davis, Sam Heughan, Caitriona Balfe, or anyone else involved in the production of the TV series: PLEASE DON'T!! They are working very hard to bring VOYAGER to life for fans all over the world, and getting mad at them because of this delay isn't going to help.
Here's a bit of Gaelic that some of you may have heard before: "Fuirich agus chi thu", which means "Wait and see." It's one of Diana Gabaldon's favorite phrases.
Yes, it will take a while longer, but Season 3 will be worth the wait. I'm sure of it!
Posted by Karen Henry at 7:12 PM 4 comments
If you've read Diana Gabaldon's VOYAGER, book 3 of the OUTLANDER series, you'll love this video!
If you haven't read the book, there are SPOILERS for part of Season 3 here, so don't say I didn't warn you!
In honor of Valentine's Day, here are some of my all-time favorite romantic Jamie quotes from Diana Gabaldon's OUTLANDER books. It was hard to pick just one per book! I hope you enjoy them.
OUTLANDER:
"Ye are Blood of my Blood, and Bone of my Bone. I give ye my Body, that we Two might be One. I give ye my Spirit, 'til our Life shall be Done."
(From OUTLANDER by Diana Gabaldon, chapter 14, "A Marriage Takes Place". Copyright© 1991 by Diana Gabaldon. All rights reserved.)
DRAGONFLY IN AMBER:
"I'm honest enough to say that I dinna care what the right and wrong of it may be, so long as you are here wi' me, Claire," he said softly. "If it was a sin for you to choose me...then I would go to the Devil himself and bless him for tempting ye to it."
(From DRAGONFLY IN AMBER by Diana Gabaldon, chapter 22, "The Royal Stud". Copyright© 1992 by Diana Gabaldon. All rights reserved.)
VOYAGER:
"To have ye with me again--to talk wi' you--to know I can say anything, not guard my words or hide my thoughts--God, Sassenach," he said, "the Lord knows I am lust-crazed as a lad, and I canna keep my hands from you--or anything else--" he added, wryly, "but I would count that all well lost, had I no more than the pleasure of havin' ye by me, and to tell ye all my heart."
(From VOYAGER by Diana Gabaldon, chapter 27, "Up in Flames". Copyright© 1994 by Diana Gabaldon. All rights reserved.)
DRUMS OF AUTUMN:
"And when my body shall cease, my soul will still be yours. Claire--I swear by my hope of heaven, I will not be parted from you."
(From DRUMS OF AUTUMN by Diana Gabaldon, chapter 16, "The First Law of Thermodynamics". Copyright© 1997 by Diana Gabaldon. All rights reserved.)
THE FIERY CROSS:
"When the day shall come, that we do part," he said softly, and turned to look at me, "if my last words are not 'I love you'--ye'll ken it was because I didna have time."
(From THE FIERY CROSS by Diana Gabaldon, chapter 111, "And Yet Go Out to Meet It". Copyright© 2001 by Diana Gabaldon. All rights reserved.)
A BREATH OF SNOW AND ASHES:
"Claire," he said, quite gently, "it was you. It's always been you, and it always will be."
(From A BREATH OF SNOW AND ASHES by Diana Gabaldon, chapter 31, "And So To Bed". Copyright© 2005 by Diana Gabaldon. All rights reserved.)
AN ECHO IN THE BONE:
"Ever heard of coup de foudre, Sassenach? It didna take me more than one good look at you."
(From AN ECHO IN THE BONE by Diana Gabaldon, chapter 68, "Despoiler". Copyright© 2009 by Diana Gabaldon. All rights reserved.)
WRITTEN IN MY OWN HEART'S BLOOD:
"I have loved ye since I saw you, Sassenach," he said very quietly, holding my eyes with his own, bloodshot and lined with tiredness but very blue. "I will love ye forever. It doesna matter if ye sleep with the whole English army--well, no," he corrected himself, "it would matter, but it wouldna stop me loving you."
(From WRITTEN IN MY OWN HEART'S BLOOD by Diana Gabaldon, chapter 24, "Welcome Coolness in the Heat, Comfort in the Midst of Woe". Copyright© 2014 by Diana Gabaldon. All rights reserved.)
And here's a bonus quote from TV Jamie, from OUTLANDER Episode 107 ("The Wedding"):
"To a lady of grace, a woman of strength, and a bride of astonishing beauty."
What scenes are you most looking forward to in Season 3?
The OUTLANDER cast and crew wrapped up filming in Scotland this week. Now they head to South Africa, to film the remaining episodes of Season 3.
While we wait, I thought it might be fun to talk about the scenes from VOYAGER that we're most looking forward to seeing brought to life on TV in Season 3.
*** SPOILER WARNING!! ***
If you haven't yet read VOYAGER by Diana Gabaldon (Book 3 of the OUTLANDER series), there are Major Spoilers below! Read at your own risk.
My personal list includes:
The reunion! (Of course)
The "Daddy" scene and Jamie and Claire's big argument afterward
Claire's terrible, horrible, very bad day home alone with baby Bree
Claire and Frank's fight on the night Frank died
What about the rest of you? Which scenes are you most looking forward to, and why?
Posted by Karen Henry at 5:47 AM 14 comments
Here are the results of the January poll, which asked the question, "Which of Diana Gabaldon's books are you currently reading or listening to?"
4.69% - OUTLANDER / CROSS STITCH
3.27% - DRAGONFLY IN AMBER
19.35% - VOYAGER
11.24% - DRUMS OF AUTUMN
9.96% - THE FIERY CROSS
7.68% - A BREATH OF SNOW AND ASHES
6.54% - AN ECHO IN THE BONE
5.97% - WRITTEN IN MY OWN HEART'S BLOOD
1.14% - LORD JOHN AND THE PRIVATE MATTER
1.71% - LORD JOHN AND THE BROTHERHOOD OF THE BLADE
0.14% - LORD JOHN AND THE HAND OF DEVILS
3.70% - THE SCOTTISH PRISONER
1.85% - THE OUTLANDISH COMPANION (Volume 1 or 2)
3.84% - A TRAIL OF FIRE, VIRGINS, or one of the novellas or short stories.
14.08% - I'm reading other things right now.
Here are the responses for "Other":
A Plague of Zombies audiobook
gyuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
Reading VOYAGER, listening to DRUMS OF AUTUMN :)
Rereading all for 4th time from beginning
Wish I had time to read but I'm sewing for our high school musical
I have read all of Diana's books, even with increasing #s, once a year since 199
The Exile: An Outlander Graphic Novel
Your website, since I've read the series and the novellas and need a teensybreak
listening to & watching Outlander, re reading LJ #2 and rereading DofA, Crazy!
I'm reading, or listening to movie scores & recorded books of the 1st 3 novels,
I have read all the books twice but I'm now the fiery cross for the third time.
Always listening. Love Davina Porter.
planing to start a re-read
Sixth time around with the series. Currently listening to Drums of Autumn.
Im reading ALL of them - I pick up one at random.
2nd time
I already read it all
Fogmeister from The Highway Kind
have already read all books and novellas at least 3 times. Waiting for Bees.
Listening to Phil Rickman's Merrily Watkins Series
I Give You My Body
As soon as Virgins arrives, I'll be reading it.
Waiting for 9
I'm reading The Exile graphic novel.
I'm rereading all the books. Now I'm reading Voyager.
Watching S2 again
I'm listening to "Voyager" and "LJ & Brotherhood"
Just started re-reading the series. Again.
(Second reading, plus 1cycle of the audio books)
Voyager and Moby
This is perhaps the 5th or 6th read thru all books
Just started rereading the "big books." Book 1!
Read them all so I am reading other books
There were 703 responses to this month's poll. Thanks very much to everyone who participated! I didn't vote in the poll myself, but I am currently re-listening to VOYAGER.
Please take a moment to vote in the February poll, which asks the question, "Do you read excerpts or #DailyLines from Diana Gabaldon's upcoming books or stories?" Thanks!