leocad/common/lc_viewcube.cpp
2018-09-29 19:45:21 -07:00

357 lines
13 KiB
C++

#include "lc_global.h"
#include "lc_viewcube.h"
#include "view.h"
#include "lc_context.h"
#include "lc_stringcache.h"
#include "lc_application.h"
//todo: move these
const float BoxSize = 10.0f;
const float EdgeSize = BoxSize * 1.0f / 3.0f;
const float CenterSize = BoxSize * 2.0f / 3.0f;
lcViewCube::lcViewCube(View* View)
: mView(View)
{
mMouseDown = false;
}
lcMatrix44 lcViewCube::GetViewMatrix() const
{
lcMatrix44 ViewMatrix = mView->mCamera->mWorldView;
ViewMatrix.SetTranslation(lcVector3(0, 0, 0));
return ViewMatrix;
}
lcMatrix44 lcViewCube::GetProjectionMatrix() const
{
return lcMatrix44Ortho(-BoxSize * 2, BoxSize * 2, -BoxSize * 2, BoxSize * 2, -50, 50);
}
void lcViewCube::Draw()
{
const lcPreferences& Preferences = lcGetPreferences();
lcViewCubeLocation Location = Preferences.mViewCubeLocation;
if (Location == lcViewCubeLocation::DISABLED)
return;
lcContext* Context = mView->mContext;
int Width = mView->mWidth;
int Height = mView->mHeight;
int ViewportSize = Preferences.mViewCubeSize;
int Left = (Location == lcViewCubeLocation::BOTTOM_LEFT || Location == lcViewCubeLocation::TOP_LEFT) ? 0 : Width - ViewportSize;
int Bottom = (Location == lcViewCubeLocation::BOTTOM_LEFT || Location == lcViewCubeLocation::BOTTOM_RIGHT) ? 0 : Height - ViewportSize;
Context->SetViewport(Left, Bottom, ViewportSize, ViewportSize);
const lcVector3 BoxVerts[56] =
{
lcVector3( BoxSize, -CenterSize, -CenterSize), lcVector3( BoxSize, CenterSize, -CenterSize), lcVector3( BoxSize, -CenterSize, CenterSize), lcVector3( BoxSize, CenterSize, CenterSize),
lcVector3(-BoxSize, -CenterSize, -CenterSize), lcVector3(-BoxSize, CenterSize, -CenterSize), lcVector3(-BoxSize, -CenterSize, CenterSize), lcVector3(-BoxSize, CenterSize, CenterSize),
lcVector3(-CenterSize, BoxSize, -CenterSize), lcVector3(CenterSize, BoxSize, -CenterSize), lcVector3(-CenterSize, BoxSize, CenterSize), lcVector3(CenterSize, BoxSize, CenterSize),
lcVector3(-CenterSize, -BoxSize, -CenterSize), lcVector3(CenterSize, -BoxSize, -CenterSize), lcVector3(-CenterSize, -BoxSize, CenterSize), lcVector3(CenterSize, -BoxSize, CenterSize),
lcVector3(-CenterSize, -CenterSize, BoxSize), lcVector3(CenterSize, -CenterSize, BoxSize), lcVector3(-CenterSize, CenterSize, BoxSize), lcVector3(CenterSize, CenterSize, BoxSize),
lcVector3(-CenterSize, -CenterSize, -BoxSize), lcVector3(CenterSize, -CenterSize, -BoxSize), lcVector3(-CenterSize, CenterSize, -BoxSize), lcVector3(CenterSize, CenterSize, -BoxSize),
lcVector3( BoxSize, -BoxSize, -CenterSize), lcVector3( BoxSize, BoxSize, -CenterSize), lcVector3( BoxSize, -BoxSize, CenterSize), lcVector3( BoxSize, BoxSize, CenterSize),
lcVector3(-BoxSize, -BoxSize, -CenterSize), lcVector3(-BoxSize, BoxSize, -CenterSize), lcVector3(-BoxSize, -BoxSize, CenterSize), lcVector3(-BoxSize, BoxSize, CenterSize),
lcVector3(-CenterSize, BoxSize, -BoxSize), lcVector3(CenterSize, BoxSize, -BoxSize), lcVector3(-CenterSize, BoxSize, BoxSize), lcVector3(CenterSize, BoxSize, BoxSize),
lcVector3(-CenterSize, -BoxSize, -BoxSize), lcVector3(CenterSize, -BoxSize, -BoxSize), lcVector3(-CenterSize, -BoxSize, BoxSize), lcVector3(CenterSize, -BoxSize, BoxSize),
lcVector3(-BoxSize, -CenterSize, BoxSize), lcVector3(BoxSize, -CenterSize, BoxSize), lcVector3(-BoxSize, CenterSize, BoxSize), lcVector3(BoxSize, CenterSize, BoxSize),
lcVector3(-BoxSize, -CenterSize, -BoxSize), lcVector3(BoxSize, -CenterSize, -BoxSize), lcVector3(-BoxSize, CenterSize, -BoxSize), lcVector3(BoxSize, CenterSize, -BoxSize),
lcVector3( BoxSize, -BoxSize, -BoxSize), lcVector3( BoxSize, BoxSize, -BoxSize), lcVector3( BoxSize, -BoxSize, BoxSize), lcVector3( BoxSize, BoxSize, BoxSize),
lcVector3(-BoxSize, -BoxSize, -BoxSize), lcVector3(-BoxSize, BoxSize, -BoxSize), lcVector3(-BoxSize, -BoxSize, BoxSize), lcVector3(-BoxSize, BoxSize, BoxSize)
};
const GLushort BoxIndices[36 + 144 + 144 + 24] =
{
0, 1, 2, 3, 2, 1, 5, 6, 7, 6, 5, 4,
10, 9, 8, 9, 10, 11, 13, 15, 14, 12, 13, 14,
16, 17, 18, 19, 18, 17, 21, 22, 23, 22, 21, 20,
25, 3, 1, 3, 25, 27, 9, 11, 25, 27, 25, 11,
0, 2, 24, 26, 24, 2, 24, 15, 13, 15, 24, 26,
2, 3, 43, 2, 43, 41, 19, 17, 43, 41, 43, 17,
47, 1, 0, 45, 47, 0, 47, 21, 23, 21, 47, 45,
5, 7, 29, 31, 29, 7, 10, 8, 31, 8, 29, 31,
28, 6, 4, 6, 28, 30, 12, 14, 28, 30, 28, 14,
42, 7, 6, 40, 42, 6, 42, 16, 18, 16, 42, 40,
4, 5, 46, 4, 46, 44, 22, 20, 46, 44, 46, 20,
34, 11, 10, 34, 35, 11, 35, 34, 19, 18, 19, 34,
8, 9, 32, 9, 33, 32, 23, 32, 33, 32, 23, 22,
14, 15, 38, 15, 39, 38, 17, 38, 39, 38, 17, 16,
36, 13, 12, 36, 37, 13, 37, 36, 21, 20, 21, 36,
51, 3, 27, 43, 3, 51, 27, 11, 51, 51, 11, 35, 35, 19, 51, 51, 19, 43,
25, 1, 49, 49, 1, 47, 49, 9, 25, 33, 9, 49, 49, 23, 33, 47, 23, 49,
26, 2, 50, 50, 2, 41, 50, 15, 26, 39, 15, 50, 50, 17, 39, 41, 17, 50,
48, 0, 24, 45, 0, 48, 24, 13, 48, 48, 13, 37, 37, 21, 48, 48, 21, 45,
31, 7, 55, 55, 7, 42, 55, 10, 31, 34, 10, 55, 55, 18, 34, 42, 18, 55,
53, 5, 29, 46, 5, 53, 29, 8, 53, 53, 8, 32, 32, 22, 53, 53, 22, 46,
54, 6, 30, 40, 6, 54, 30, 14, 54, 54, 14, 38, 38, 16, 54, 54, 16, 40,
28, 4, 52, 52, 4, 44, 52, 12, 28, 36, 12, 52, 52, 20, 36, 44, 20, 52,
48, 52, 49, 53, 50, 54, 51, 55, 48, 49, 50, 51, 52, 53, 54, 55, 48, 50, 49, 51, 52, 54, 53, 55
};
Context->SetMaterial(LC_MATERIAL_UNLIT_COLOR);
Context->SetWorldMatrix(lcMatrix44Identity());
Context->SetViewMatrix(GetViewMatrix());
Context->SetProjectionMatrix(GetProjectionMatrix());
Context->SetVertexBufferPointer(BoxVerts);
Context->SetVertexFormatPosition(3);
Context->SetIndexBufferPointer(BoxIndices);
glDepthFunc(GL_ALWAYS);
glEnable(GL_CULL_FACE);
Context->SetColor(1.0f, 1.0f, 1.0f, 1.0f);
Context->DrawIndexedPrimitives(GL_TRIANGLES, 36 + 144 + 144, GL_UNSIGNED_SHORT, 0);
int IntersectionType = mIntersectionFlags.count();
if (IntersectionType == 1)
{
for (int FlagIdx = 0; FlagIdx < 6; FlagIdx++)
{
if (mIntersectionFlags.test(FlagIdx))
{
Context->SetColor(1.0f, 0.0f, 0.0f, 1.0f);
Context->DrawIndexedPrimitives(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, FlagIdx * 6 * 2);
break;
}
}
}
else if (IntersectionType == 2)
{
int First;
if (mIntersectionFlags.test(0))
{
if (mIntersectionFlags.test(2))
First = 36;
else if (mIntersectionFlags.test(3))
First = 36 + 12;
else if (mIntersectionFlags.test(4))
First = 36 + 24;
else
First = 36 + 36;
}
else if (mIntersectionFlags.test(1))
{
if (mIntersectionFlags.test(2))
First = 36 + 48;
else if (mIntersectionFlags.test(3))
First = 36 + 48 + 12;
else if (mIntersectionFlags.test(4))
First = 36 + 48 + 24;
else
First = 36 + 48 + 36;
}
else if (mIntersectionFlags.test(2))
{
if (mIntersectionFlags.test(4))
First = 36 + 96;
else
First = 36 + 96 + 12;
}
else
{
if (mIntersectionFlags.test(4))
First = 36 + 96 + 24;
else
First = 36 + 96 + 36;
}
Context->SetColor(1.0f, 0.0f, 0.0f, 1.0f);
Context->DrawIndexedPrimitives(GL_TRIANGLES, 12, GL_UNSIGNED_SHORT, First * 2);
}
else if (IntersectionType == 3)
{
int First = 36 + 144;
if (mIntersectionFlags.test(1))
First += 72;
if (mIntersectionFlags.test(3))
First += 36;
if (mIntersectionFlags.test(5))
First += 18;
Context->SetColor(1.0f, 0.0f, 0.0f, 1.0f);
Context->DrawIndexedPrimitives(GL_TRIANGLES, 18, GL_UNSIGNED_SHORT, First * 2);
}
glDepthFunc(GL_LEQUAL);
Context->SetColor(0.0f, 0.0f, 0.0f, 1.0f);
Context->DrawIndexedPrimitives(GL_LINES, 24, GL_UNSIGNED_SHORT, (36 + 144 + 144) * 2);
Context->SetMaterial(LC_MATERIAL_UNLIT_TEXTURE_MODULATE);
glEnable(GL_BLEND);
glDepthFunc(GL_ALWAYS);
QStringList ViewNames =
{
QT_TRANSLATE_NOOP("ViewName", "Front"),
QT_TRANSLATE_NOOP("ViewName", "Back"),
QT_TRANSLATE_NOOP("ViewName", "Top"),
QT_TRANSLATE_NOOP("ViewName", "Bottom"),
QT_TRANSLATE_NOOP("ViewName", "Left"),
QT_TRANSLATE_NOOP("ViewName", "Right")
};
int MaxText = 0;
for (int FaceIdx = 0; FaceIdx < 6; FaceIdx++)
{
int Width, Height;
gStringCache.GetStringDimensions(&Width, &Height, ViewNames[FaceIdx]);
if (Width > MaxText)
MaxText = Width;
if (Height > MaxText)
MaxText = Height;
}
float Scale = BoxSize * 4.0f / 3.0f / (float)MaxText;
lcMatrix44 ViewMatrices[6] =
{
lcMatrix44(lcVector4(Scale, 0.0f, 0.0f, 0.0f), lcVector4(0.0f, 0.0f, Scale, 0.0f), lcVector4(0.0f, 1.0f, 0.0f, 0.0f), lcVector4(0.0f, -BoxSize - 0.01f, 0.0f, 1.0f)),
lcMatrix44(lcVector4(-Scale, 0.0f, 0.0f, 0.0f), lcVector4(0.0f, 0.0f, Scale, 0.0f), lcVector4(0.0f, 1.0f, 0.0f, 0.0f), lcVector4(0.0f, BoxSize + 0.01f, 0.0f, 1.0f)),
lcMatrix44(lcVector4(Scale, 0.0f, 0.0f, 0.0f), lcVector4(0.0f, Scale, 0.0f, 0.0f), lcVector4(0.0f, 0.0f, 1.0f, 0.0f), lcVector4(0.0f, 0.0f, BoxSize + 0.01f, 1.0f)),
lcMatrix44(lcVector4(Scale, 0.0f, 0.0f, 0.0f), lcVector4(0.0f, -Scale, 0.0f, 0.0f), lcVector4(0.0f, 0.0f, 1.0f, 0.0f), lcVector4(0.0f, 0.0f, -BoxSize - 0.01f, 1.0f)),
lcMatrix44(lcVector4(0.0f, Scale, 0.0f, 0.0f), lcVector4(0.0f, 0.0f, Scale, 0.0f), lcVector4(1.0f, 0.0f, 0.0f, 0.0f), lcVector4(BoxSize + 0.01f, 0.0f, 0.0f, 1.0f)),
lcMatrix44(lcVector4(0.0f, -Scale, 0.0f, 0.0f), lcVector4(0.0f, 0.0f, Scale, 0.0f), lcVector4(1.0f, 0.0f, 0.0f, 0.0f), lcVector4(-BoxSize - 0.01f, 0.0f, 0.0f, 1.0f))
};
gStringCache.CacheStrings(ViewNames); // todo: precache earlier because the texture only gets uploaded on the next frame
gStringCache.DrawStrings(Context, ViewMatrices, ViewNames);
glDisable(GL_BLEND);
glDisable(GL_CULL_FACE);
glDepthFunc(GL_LEQUAL);
Context->SetViewport(0, 0, Width, Height);
}
bool lcViewCube::OnLeftButtonDown()
{
const lcPreferences& Preferences = lcGetPreferences();
if (Preferences.mViewCubeLocation == lcViewCubeLocation::DISABLED)
return false;
mIntersectionFlags = GetIntersectionFlags(mIntersection);
if (!mIntersectionFlags.any())
return false;
mMouseDownX = mView->mInputState.x;
mMouseDownY = mView->mInputState.y;
mMouseDown = true;
return true;
}
bool lcViewCube::OnLeftButtonUp()
{
const lcPreferences& Preferences = lcGetPreferences();
if (Preferences.mViewCubeLocation == lcViewCubeLocation::DISABLED)
return false;
if (!mMouseDown)
return false;
mMouseDown = false;
if (!mIntersectionFlags.any())
return false;
lcVector3 Position(0.0f, 0.0f, 0.0f);
for (int AxisIdx = 0; AxisIdx < 3; AxisIdx++)
{
if (mIntersectionFlags.test(AxisIdx * 2))
Position[AxisIdx] = 1250.0f;
else if (mIntersectionFlags.test(AxisIdx * 2 + 1))
Position[AxisIdx] = -1250.0f;
}
mView->SetViewpoint(Position);
return true;
}
bool lcViewCube::OnMouseMove()
{
const lcPreferences& Preferences = lcGetPreferences();
lcViewCubeLocation Location = Preferences.mViewCubeLocation;
if (Location == lcViewCubeLocation::DISABLED)
return false;
if (IsDragging())
{
mIntersectionFlags.reset();
mView->StartOrbitTracking();
return true;
}
if (mView->IsTracking())
return false;
std::bitset<6> IntersectionFlags = GetIntersectionFlags(mIntersection);
if (IntersectionFlags != mIntersectionFlags)
{
mIntersectionFlags = IntersectionFlags;
mView->Redraw();
}
return mIntersectionFlags.any();
}
bool lcViewCube::IsDragging() const
{
return mMouseDown && (qAbs(mMouseDownX - mView->mInputState.x) > 3 || qAbs(mMouseDownY - mView->mInputState.y) > 3);
}
std::bitset<6> lcViewCube::GetIntersectionFlags(lcVector3& Intersection) const
{
const lcPreferences& Preferences = lcGetPreferences();
lcViewCubeLocation Location = Preferences.mViewCubeLocation;
int Width = mView->mWidth;
int Height = mView->mHeight;
int ViewportSize = Preferences.mViewCubeSize;
int Left = (Location == lcViewCubeLocation::BOTTOM_LEFT || Location == lcViewCubeLocation::TOP_LEFT) ? 0 : Width - ViewportSize;
int Bottom = (Location == lcViewCubeLocation::BOTTOM_LEFT || Location == lcViewCubeLocation::BOTTOM_RIGHT) ? 0 : Height - ViewportSize;
int x = mView->mInputState.x - Left;
int y = mView->mInputState.y - Bottom;
std::bitset<6> IntersectionFlags;
if (x < 0 || x > Width || y < 0 || y > Height)
return IntersectionFlags;
lcVector3 StartEnd[2] = { lcVector3(x, y, 0), lcVector3(x, y, 1) };
const int Viewport[4] = { 0, 0, ViewportSize, ViewportSize };
lcUnprojectPoints(StartEnd, 2, GetViewMatrix(), GetProjectionMatrix(), Viewport);
float Distance;
if (lcBoundingBoxRayIntersectDistance(lcVector3(-BoxSize, -BoxSize, -BoxSize), lcVector3(BoxSize, BoxSize, BoxSize), StartEnd[0], StartEnd[1], &Distance, &Intersection))
{
for (int AxisIdx = 0; AxisIdx < 3; AxisIdx++)
{
if (mIntersection[AxisIdx] > BoxSize * 2 / 3)
IntersectionFlags.set(2 * AxisIdx);
else if (mIntersection[AxisIdx] < -BoxSize * 2 / 3)
IntersectionFlags.set(2 * AxisIdx + 1);
}
}
return IntersectionFlags;
}