CanadianMachines / CanadianExperienceLib / HeadTop.cpp
HeadTop.cpp
Raw
/**
 * @file HeadTop.cpp
 * @author Charles Owen
 */

#include "pch.h"

#include <sstream>
#include <iomanip>

#include "HeadTop.h"
#include "Actor.h"
#include "Timeline.h"

using namespace std;

/**
 * Constructor
 * @param name Drawable name
 * @param filename File to load for the head
 */
HeadTop::HeadTop(const std::wstring& name, const std::wstring& filename)
        : ImageDrawable(name, filename)
{

}


/**
 * Set the actor. This is where we set the channel name
 * @param actor Actor to set
 */
void HeadTop::SetActor(Actor *actor)
{
    ImageDrawable::SetActor(actor);

    // Set the channel name
    mPositionChannel.SetName(actor->GetName() + L":" + GetName() + L":position");
}


/**
 * Set the timeline. The tells the channel the timeline
 * @param timeline Timeline to set
 */
void HeadTop::SetTimeline(Timeline *timeline)
{
    ImageDrawable::SetTimeline(timeline);

    timeline->AddChannel(&mPositionChannel);
}

/**
 * Set the keyframe based on the current status.
*/
void HeadTop::SetKeyframe()
{
    ImageDrawable::SetKeyframe();

    mPositionChannel.SetKeyframe(GetPosition());
}

/**
 * Get the current channel from the animation system.
*/
void HeadTop::GetKeyframe()
{
    ImageDrawable::GetKeyframe();

    if (mPositionChannel.IsValid())
    {
        SetPosition(mPositionChannel.GetPoint());
    }
}



/**
 * Draw the head top
 * @param graphics
 */
void HeadTop::Draw(std::shared_ptr<wxGraphicsContext> graphics)
{
    ImageDrawable::Draw(graphics);

//    wxPoint eb1 = TransformPoint(wxPoint(32, 63));
//    wxPoint eb2 = TransformPoint(wxPoint(46, 61));
//
//    wxPen eyebrowPen(*wxBLACK, 2);
//    graphics->SetPen(eyebrowPen);
//    graphics->StrokeLine(eb1.x, eb1.y, eb2.x, eb2.y);

//    DrawEyebrow(graphics, wxPoint(32, 63), wxPoint(46, 61));
//    DrawEyebrow(graphics, wxPoint(64, 59), wxPoint(77, 61));
//
//    DrawEye(graphics, wxPoint(42, 79));
//    DrawEye(graphics, wxPoint(69, 79));


    // Distance horizontally from each eye center to the center
    int d2 = mInterocularDistance / 2;

    // Compute a left and right eye center X location
    int rightX = mEyesCenter.x - d2;
    int leftX = mEyesCenter.x + d2;

    // Eye center Y value
    int eyeY = mEyesCenter.y;

//    DrawEyebrow(graphics, wxPoint(rightX - 10, eyeY - 16), wxPoint(rightX + 4, eyeY - 18));
//    DrawEyebrow(graphics, wxPoint(leftX - 4, eyeY - 20), wxPoint(leftX + 9, eyeY - 18));
//
//    DrawEye(graphics, wxPoint(leftX, eyeY));
//    DrawEye(graphics, wxPoint(rightX, eyeY));

    if (mLeftEye.IsLoaded() && mRightEye.IsLoaded())
    {
        // Determine the point on the screen were we will draw the left eye
        wxPoint leye = TransformPoint(wxPoint(leftX, eyeY));
        // And draw the bitmap there
        mLeftEye.DrawImage(graphics, leye, mPlacedR);

        // Repeat the process for the right eye.
        wxPoint reye = TransformPoint(wxPoint(rightX, eyeY));
        mRightEye.DrawImage(graphics, reye, mPlacedR);
    }
    else
    {
        DrawEyebrow(graphics, wxPoint(rightX - 10, eyeY - 16), wxPoint(rightX + 4, eyeY - 18));
        DrawEyebrow(graphics, wxPoint(leftX - 4, eyeY - 20), wxPoint(leftX + 9, eyeY - 18));

        DrawEye(graphics, wxPoint(leftX, eyeY));
        DrawEye(graphics, wxPoint(rightX, eyeY));
    }

}


/**
 * Draw an eyebrow, automatically transforming the points
 *
 * Draw a line from (x1, y1) to (x2, y2) after transformation
 * to the local coordinate system.
 * @param graphics Graphics context to draw on
 * @param p1 First point
 * @param p2 Second point
 */
void HeadTop::DrawEyebrow(std::shared_ptr<wxGraphicsContext> graphics,
        wxPoint p1, wxPoint p2)
{
    auto eb1 = TransformPoint(p1);
    auto eb2 = TransformPoint(p2);

    wxPen eyebrowPen(*wxBLACK, 2);
    graphics->SetPen(eyebrowPen);
    graphics->StrokeLine(eb1.x, eb1.y, eb2.x, eb2.y);
}


/**
 * Draw an eye using an Ellipse
 * @param graphics The graphics context to draw on
 * @param p1 Where to draw before transformation */
void HeadTop::DrawEye(std::shared_ptr<wxGraphicsContext> graphics, wxPoint p1)
{
    graphics->SetBrush(*wxBLACK_BRUSH);
    graphics->SetPen(*wxTRANSPARENT_PEN);

    auto e1 = TransformPoint(p1);

    float wid = 15.0f;
    float hit = 20.0f;

    graphics->PushState();
    graphics->Translate(e1.x, e1.y);
    graphics->Rotate(-mPlacedR);
    graphics->DrawEllipse(-wid/2, -hit/2, wid, hit);
    graphics->PopState();
}


/** Transform a point from a location on the bitmap to
*  a location on the screen.
* @param  p Point to transform
* @returns Transformed point
*/
wxPoint HeadTop::TransformPoint(wxPoint p)
{
    // Make p relative to the image center
    p = p - GetCenter();

    // Rotate as needed and offset
    return RotatePoint(p, mPlacedR) + mPlacedPosition;
}