#include "TrigClient.h"
#include <DirectXMath.h>
#include <iostream>
using std::cout; using std::endl;
#define rad(x) DirectX::XMConvertToRadians(x)
#define deg(x) DirectX::XMConvertToDegrees(x)
TrigClient::TrigClient(HINSTANCE instance, std::wstring caption, float width, float height)
:D2DApp(instance, caption, width, height), mOriginX{ 0 }, mOriginY{ 0 }, mAngle{ 0 }, mAngleChange{ 70.f },
mWaveBox{}, mMouse{ 0 }, mDashedLine{ nullptr }, mTriangleGeo{ nullptr }
{
}
TrigClient::~TrigClient()
{
if (mDashedLine) { mDashedLine->Release(); }
if (mTriangleGeo) { mTriangleGeo->Release(); }
}
bool TrigClient::Init()
{
if (!D2DApp::Init())
{
return false;
}
//Additional initialization
mOriginX = { mClientWidth / 2.f };
mOriginY = { mClientHeight / 3.5f };
//waveBox
float waveBoxPadding = 50.f;
float waveBoxWidth = 350.f;
float waveBoxHeight = 250.f;
mWaveBox.bottom = mClientHeight - waveBoxPadding;
mWaveBox.top = mWaveBox.bottom - waveBoxHeight;
mWaveBox.left = waveBoxPadding;
mWaveBox.right = mWaveBox.left + waveBoxWidth;
D2D1_STROKE_STYLE_PROPERTIES dashedLineProp{};
dashedLineProp.startCap = D2D1_CAP_STYLE_FLAT;
dashedLineProp.endCap = D2D1_CAP_STYLE_FLAT;
dashedLineProp.dashCap = D2D1_CAP_STYLE_ROUND;
dashedLineProp.lineJoin = D2D1_LINE_JOIN_MITER;
dashedLineProp.miterLimit = 60.f;
dashedLineProp.dashStyle = D2D1_DASH_STYLE_CUSTOM; //try DOT
dashedLineProp.dashOffset = 3.3f; // might want to use this to animate the dashLine
float dashes[] = { 6.0f, 6.0f, 6.0f };
HRESULT hr = mFactory->CreateStrokeStyle(dashedLineProp, dashes, ARRAYSIZE(dashes), &mDashedLine);
if (hr != S_OK) {
MessageBoxW(mhWindow, L"failed to create dashed line", 0, 0);
return false;
}
return true;
}
void TrigClient::Update(float dt)
{
mAngle += mAngleChange*dt;
float oneCircleTime = 360 / mAngleChange; //time required to complete 1 revolution, in seconds
unsigned pointResolution = 30;
float pointsPerSecond = 1 / pointResolution; //how often points are added, in seconds
static float addPointTimer = 0;
addPointTimer += dt;
//evaluate every t | determines wave resolution
if (addPointTimer >= pointsPerSecond)
{
//function to turn into a wave
D2D1_POINT_2F newPoint = { mTimer.totalTime() ,cos(rad(mAngle)) };
//add new point
mWavePoints.push_back(newPoint);
//remove old Points
for (size_t i = 0; i < mWavePoints.size(); i++)
{
if (mTimer.totalTime() - mWavePoints.front().x >= oneCircleTime) {
mWavePoints.pop_front();
}
else {
break;
}
}
addPointTimer = 0;
}
}
void TrigClient::Draw()
{
//background
mRenderTarger->Clear(D2D1::ColorF(0.41f, 0.41f, 0.41f, 1.0f));
makeGrid(25);
//circle stuff
float radius = 250.f;
D2D1_POINT_2F point1 = D2D1::Point2F(radius * cos(rad(mAngle)), radius * sin(rad(mAngle)));
circileFromOrigin(radius, 3.f, D2D1::ColorF(0.2f, 0.65f, 0.86f, 1.f));
lineFromOrigin(point1, 2.f, D2D1::ColorF(0.46f, 0.76f, 0.86f, 1.f));
drawPointFromOrigin(point1, 6.f, D2D1::ColorF(1.0f, 0.15f, 0.30f, 1.f));
projectionX(point1);
perpX(point1);
triangleAreaDisplay(point1);
//draw wave box
drawWaveBox(cos(rad(mAngle)));
}
void TrigClient::drawWaveBox(const float point)
{
//transparent box base
mBrush->SetColor(D2D1::ColorF(0.4f, 0.4f, 0.4f, 0.65f));
mRenderTarger->FillRectangle(mWaveBox, mBrush);
//box outline
mBrush->SetColor(D2D1::ColorF(0.9f, 0.9f, 0.0f, 0.45f));
mRenderTarger->DrawRectangle(mWaveBox, mBrush);
//horizontal line
mBrush->SetColor(D2D1::ColorF(0.08f, 0.08f, 0.08f, 1.0f));
float boxWidth = mWaveBox.right - mWaveBox.left;
float boxHeight = mWaveBox.bottom - mWaveBox.top;
float marks = 50;
float linePaddingH = 20;
float linePaddingV = 10;
float lineBoundLeft = mWaveBox.left + linePaddingH;
float lineBoundRight = mWaveBox.right - linePaddingH;
float lineBoundBottom = mWaveBox.bottom - linePaddingV;
float lineLength = lineBoundRight - lineBoundLeft;
float intervalSpace = lineLength / marks;
mRenderTarger->DrawLine(D2D1::Point2(lineBoundLeft, lineBoundBottom),
D2D1::Point2(lineBoundRight, lineBoundBottom), mBrush, 1.f);
//horizontal marks
for (size_t i = 0; i <= marks; i++) {
mRenderTarger->DrawLine(D2D1::Point2(lineBoundLeft + (intervalSpace*i), lineBoundBottom - 5),
D2D1::Point2(lineBoundLeft + (intervalSpace*i), lineBoundBottom + 5), mBrush, 1.f);
}
//internal box
float internalBoxTop = mWaveBox.top + (mWaveBox.bottom - lineBoundBottom) + linePaddingV;
float internalBoxBottom = lineBoundBottom - linePaddingV;
mBrush->SetColor(D2D1::ColorF(0.24f, 0.24f, 0.24f, 0.85f));
mRenderTarger->FillRectangle(D2D1::RectF(lineBoundLeft, //left
internalBoxTop, //top
lineBoundRight, //right
internalBoxBottom),// bottom
mBrush);
//draw wave
float internalBoxMidY = internalBoxTop + ((internalBoxBottom - internalBoxTop) / 2);
float oneCircleTime = 360 / mAngleChange;
float graphHSpace = lineBoundRight - lineBoundLeft;
float graphYSpace = internalBoxBottom - internalBoxTop;
for (auto& point : mWavePoints)
{
float pointAge = mTimer.totalTime() - point.x;
drawPoint(D2D1::Point2F(lineBoundLeft + ((graphHSpace / oneCircleTime) * pointAge),//X
internalBoxMidY + (-point.y * graphYSpace / 2.05f))//Y
, 2.6f, D2D1::ColorF(-point.y, point.y, point.y, 0.85f));
}
}
void TrigClient::projectionX(const D2D1_POINT_2F& p)
{
mBrush->SetColor(D2D1::ColorF(0.5f, 0.75f, 0.30f, 1.f));
mRenderTarger->DrawLine(D2D1::Point2F(mOriginX + p.x, mOriginY - p.y), D2D1::Point2F(mOriginX + p.x, mOriginY), mBrush, 1.f, mDashedLine);
drawPointFromOrigin(D2D1::Point2F(p.x, 0), 5.f, D2D1::ColorF(0.5f, 0.75f, 0.30f, 1.f));
}
void TrigClient::perpX(const D2D1_POINT_2F& p)
{
mBrush->SetColor(D2D1::ColorF(0.5f, 0.75f, 0.30f, 1.f));
mRenderTarger->DrawLine(D2D1::Point2F(mOriginX + p.x, mOriginY - p.y), D2D1::Point2F(mOriginX, mOriginY - p.y), mBrush, 1.f, mDashedLine);
drawPointFromOrigin(D2D1::Point2F(0, p.y), 5.f, D2D1::ColorF(0.5f, 0.75f, 0.30f, 1.f));
}
void TrigClient::triangleAreaDisplay(const D2D1_POINT_2F& p)
{
//free previous triangle
if (mTriangleGeo) { mTriangleGeo->Release(); }
//create triangle path geo
HRESULT hr = mFactory->CreatePathGeometry(&mTriangleGeo);
if (hr != S_OK) {
assert(hr == S_OK);
MessageBoxW(mhWindow, L"failed to create triangle path geo", 0, 0);
}
ID2D1GeometrySink* pSink;
D2D1_POINT_2F tringle[3] = {
{ mOriginX + p.x,mOriginY},
{ mOriginX + p.x , mOriginY - p.y},
{ mOriginX, mOriginY }
};
mTriangleGeo->Open(&pSink);
pSink->BeginFigure(D2D1::Point2F(mOriginX, mOriginY), D2D1_FIGURE_BEGIN_FILLED);
//build shape here//
pSink->AddLines(tringle, 3);
////////////
pSink->EndFigure(D2D1_FIGURE_END_CLOSED);
pSink->Close();
pSink->Release();
//draw shape
float point = cos(rad(mAngle));
mBrush->SetColor(D2D1::ColorF(-point, point, point, 0.7f));
mRenderTarger->FillGeometry(mTriangleGeo, mBrush);
}
void TrigClient::makeGrid(float spacing)
{
mBrush->SetColor(D2D1::ColorF(0.0f, 0.0f, 0.0f, 1.0f));
//Major Horizontal and Vertical lines
mRenderTarger->DrawLine(D2D1::Point2F(0.0f, mOriginY),
D2D1::Point2F(mClientWidth, mOriginY),
mBrush, 2.f);
mRenderTarger->DrawLine(D2D1::Point2F(mOriginX, 0.0f),
D2D1::Point2F(mOriginX, mClientHeight),
mBrush, 2.f);
//Vertical lines
unsigned leftLines = (int)(mOriginX / spacing);
unsigned righttLines = (int)((mClientWidth - mOriginX) / spacing);
unsigned verticalLines = leftLines > righttLines ? leftLines : righttLines;
for (size_t i = 1; i <= verticalLines; i++)
{
//left
mRenderTarger->DrawLine(D2D1::Point2F(mOriginX - (i*spacing), 0.f),
D2D1::Point2F(mOriginX - (i*spacing), mClientHeight),
mBrush, 0.25f);
//right
mRenderTarger->DrawLine(D2D1::Point2F(mOriginX + (i*spacing), 0.f),
D2D1::Point2F(mOriginX + (i*spacing), mClientHeight),
mBrush, 0.25f);
}
//Horizontal lines
unsigned topLines = (int)(mOriginY / spacing);
unsigned bottomtLines = (int)((mClientHeight - mOriginY) / spacing);
unsigned horizontalLines = topLines > bottomtLines ? topLines : bottomtLines;
for (size_t i = 1; i <= horizontalLines; i++)
{
//up
mRenderTarger->DrawLine(D2D1::Point2F(0.f, mOriginY - (i*spacing)),
D2D1::Point2F(mClientWidth, mOriginY - (i*spacing)),
mBrush, 0.25f);
//down
mRenderTarger->DrawLine(D2D1::Point2F(0.f, mOriginY + (i*spacing)),
D2D1::Point2F(mClientWidth, mOriginY + (i*spacing)),
mBrush, 0.25f);
}
}
void TrigClient::lineFromOrigin(const D2D1_POINT_2F& p, float strokeSize, const D2D1_COLOR_F& color)
{
if (color.a != -1.f) {
mBrush->SetColor(color);
}
mRenderTarger->DrawLine(D2D1::Point2F(mOriginX, mOriginY),
D2D1::Point2F(mOriginX + p.x, mOriginY - p.y), mBrush, strokeSize);
}
void TrigClient::circileFromOrigin(const float radius, float strokeSize, const D2D1_COLOR_F& color)
{
if (color.a != -1.f) {
mBrush->SetColor(color);
}
mRenderTarger->DrawEllipse(D2D1::Ellipse(D2D1::Point2F(mOriginX, mOriginY), radius, radius),
mBrush, strokeSize);
}
void TrigClient::drawPoint(const D2D1_POINT_2F& p, float radius, const D2D1_COLOR_F& color)
{
if (color.a != -1.f) {
mBrush->SetColor(color);
}
mRenderTarger->FillEllipse(D2D1::Ellipse(D2D1::Point2F(p.x, p.y), radius, radius), mBrush);
}
void TrigClient::drawPointFromOrigin(const D2D1_POINT_2F& p, float radius, const D2D1_COLOR_F& color)
{
if (color.a != -1.f) {
mBrush->SetColor(color);
}
mRenderTarger->FillEllipse(D2D1::Ellipse(D2D1::Point2F(mOriginX + p.x, mOriginY - p.y), radius, radius),
mBrush);
}