| | |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | #include "GuiDisplay.h" |
| | #include "OpenGlWrapper.h" |
| | #include "MillSimulation.h" |
| | #include <cstddef> |
| | #include <QToolTip> |
| | #include <QPoint> |
| | #include <QCoreApplication> |
| |
|
| |
|
| | using namespace MillSim; |
| |
|
| | |
| | |
| | GuiItem guiItems[] = { |
| | {.name=eGuiItemSlider, .vbo=0, .vao=0, .sx=28, .sy=-80, .actionKey=0, .hidden=false, .flags=0}, |
| | {.name=eGuiItemThumb, .vbo=0, .vao=0, .sx=328, .sy=-94, .actionKey=1, .hidden=false, .flags=0}, |
| | {.name=eGuiItemPause, .vbo=0, .vao=0, .sx=28, .sy=-50, .actionKey='P', .hidden=true, .flags=0}, |
| | {.name=eGuiItemPlay, .vbo=0, .vao=0, .sx=28, .sy=-50, .actionKey='S', .hidden=false, .flags=0}, |
| | {.name=eGuiItemSingleStep, .vbo=0, .vao=0, .sx=68, .sy=-50, .actionKey='T', .hidden=false, .flags=0}, |
| | {.name=eGuiItemSlower, .vbo=0, .vao=0, .sx=113, .sy=-50, .actionKey=' ', .hidden=false, .flags=0}, |
| | {.name=eGuiItemFaster, .vbo=0, .vao=0, .sx=158, .sy=-50, .actionKey='F', .hidden=false, .flags=0}, |
| | {.name=eGuiItemX, .vbo=0, .vao=0, .sx=208, .sy=-45, .actionKey=0, .hidden=false, .flags=0}, |
| | {.name=eGuiItem1, .vbo=0, .vao=0, .sx=230, .sy=-50, .actionKey=0, .hidden=false, .flags=0}, |
| | {.name=eGuiItem5, .vbo=0, .vao=0, .sx=230, .sy=-50, .actionKey=0, .hidden=true, .flags=0}, |
| | {.name=eGuiItem10, .vbo=0, .vao=0, .sx=230, .sy=-50, .actionKey=0, .hidden=true, .flags=0}, |
| | {.name=eGuiItem25, .vbo=0, .vao=0, .sx=230, .sy=-50, .actionKey=0, .hidden=true, .flags=0}, |
| | {.name=eGuiItem50, .vbo=0, .vao=0, .sx=230, .sy=-50, .actionKey=0, .hidden=true, .flags=0}, |
| | {.name=eGuiItemRotate, .vbo=0, .vao=0, .sx=-140, .sy=-50, .actionKey=' ', .hidden=false, .flags=GUIITEM_CHECKABLE}, |
| | {.name=eGuiItemPath, .vbo=0, .vao=0, .sx=-100, .sy=-50, .actionKey='L', .hidden=false, .flags=GUIITEM_CHECKABLE}, |
| | {.name=eGuiItemAmbientOclusion, .vbo=0, .vao=0, .sx=-60, .sy=-50, .actionKey='A', .hidden=false, .flags=GUIITEM_CHECKABLE}, |
| | {.name=eGuiItemView, .vbo=0, .vao=0, .sx=-180, .sy=-50, .actionKey='V', .hidden=false, .flags=0}, |
| | {.name=eGuiItemHome, .vbo=0, .vao=0, .sx=-220, .sy=-50, .actionKey='H', .hidden=false, .flags=0}, |
| | }; |
| | |
| | |
| |
|
| | #define NUM_GUI_ITEMS (sizeof(guiItems) / sizeof(GuiItem)) |
| | #define TEX_SIZE 256 |
| |
|
| | std::vector<std::string> guiFileNames = { |
| | "Slider.png", |
| | "Thumb.png", |
| | "Pause.png", |
| | "Play.png", |
| | "SingleStep.png", |
| | "Slower.png", |
| | "Faster.png", |
| | "x.png", |
| | "1.png", |
| | "5.png", |
| | "10.png", |
| | "25.png", |
| | "50.png", |
| | "Rotate.png", |
| | "Path.png", |
| | "AmbientOclusion.png", |
| | "View.png", |
| | "Home.png" |
| | }; |
| |
|
| | void GuiDisplay::UpdateProjection() |
| | { |
| | mat4x4 projmat; |
| | |
| | mat4x4_ortho(projmat, 0, gWindowSizeW, gWindowSizeH, 0, -1, 1); |
| | mShader.Activate(); |
| | mShader.UpdateProjectionMat(projmat); |
| | mThumbMaxMotion = guiItems[eGuiItemAmbientOclusion].posx() |
| | + guiItems[eGuiItemAmbientOclusion].texItem.w |
| | - guiItems[eGuiItemSlider].posx(); |
| | HStretchGlItem(&(guiItems[eGuiItemSlider]), mThumbMaxMotion, 10.0f); |
| | } |
| |
|
| | bool GuiDisplay::GenerateGlItem(GuiItem* guiItem) |
| | { |
| | Vertex2D verts[4]; |
| | int x = guiItem->texItem.tx; |
| | int y = guiItem->texItem.ty; |
| | int w = guiItem->texItem.w; |
| | int h = guiItem->texItem.h; |
| |
|
| | verts[0] = {0, (float)h, mTexture.getTexX(x), mTexture.getTexY(y + h)}; |
| | verts[1] = {(float)w, (float)h, mTexture.getTexX(x + w), mTexture.getTexY(y + h)}; |
| | verts[2] = {0, 0, mTexture.getTexX(x), mTexture.getTexY(y)}; |
| | verts[3] = {(float)w, 0, mTexture.getTexX(x + w), mTexture.getTexY(y)}; |
| |
|
| | |
| | glGenBuffers(1, &(guiItem->vbo)); |
| | glBindBuffer(GL_ARRAY_BUFFER, guiItem->vbo); |
| | glBufferData(GL_ARRAY_BUFFER, 4 * sizeof(Vertex2D), verts, GL_STATIC_DRAW); |
| |
|
| | |
| | |
| | glGenVertexArrays(1, &(guiItem->vao)); |
| | glBindVertexArray(guiItem->vao); |
| | glEnableVertexAttribArray(0); |
| | glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex2D), (void*)offsetof(Vertex2D, x)); |
| | glEnableVertexAttribArray(1); |
| | glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex2D), (void*)offsetof(Vertex2D, tx)); |
| | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIbo); |
| | glBindVertexArray(0); |
| |
|
| | return true; |
| | } |
| |
|
| | bool MillSim::GuiDisplay::HStretchGlItem(GuiItem* guiItem, float newWidth, float edgeWidth) |
| | { |
| | if (guiItem->vbo == 0) { |
| | return false; |
| | } |
| |
|
| | DestroyGlItem(guiItem); |
| | Vertex2D verts[12]; |
| |
|
| | int x = guiItem->texItem.tx; |
| | int y = guiItem->texItem.ty; |
| | int h = guiItem->texItem.h; |
| | int w = guiItem->texItem.w; |
| |
|
| | |
| | verts[0] = {0, (float)h, mTexture.getTexX(x), mTexture.getTexY(y + h)}; |
| | verts[1] = {edgeWidth, (float)h, mTexture.getTexX(x + edgeWidth), mTexture.getTexY(y + h)}; |
| | verts[2] = {0, 0, mTexture.getTexX(x), mTexture.getTexY(y)}; |
| | verts[3] = {edgeWidth, 0, mTexture.getTexX(x + edgeWidth), mTexture.getTexY(y)}; |
| |
|
| | |
| | float px = newWidth - edgeWidth; |
| | verts[4] = {px, (float)h, mTexture.getTexX(x + w - edgeWidth), mTexture.getTexY(y + h)}; |
| | verts[5] = {newWidth, (float)h, mTexture.getTexX(x + w), mTexture.getTexY(y + h)}; |
| | verts[6] = {px, 0, mTexture.getTexX(x + w - edgeWidth), mTexture.getTexY(y)}; |
| | verts[7] = {newWidth, 0, mTexture.getTexX(x + w), mTexture.getTexY(y)}; |
| |
|
| | |
| | verts[8] = {edgeWidth, (float)h, mTexture.getTexX(x + edgeWidth), mTexture.getTexY(y + h)}; |
| | verts[9] = {px, (float)h, mTexture.getTexX(x + w - edgeWidth), mTexture.getTexY(y + h)}; |
| | verts[10] = {edgeWidth, 0, mTexture.getTexX(x + edgeWidth), mTexture.getTexY(y)}; |
| | verts[11] = {px, 0, mTexture.getTexX(x + w - edgeWidth), mTexture.getTexY(y)}; |
| |
|
| | guiItem->flags |= GUIITEM_STRETCHED; |
| |
|
| | |
| | glGenBuffers(1, &(guiItem->vbo)); |
| | glBindBuffer(GL_ARRAY_BUFFER, guiItem->vbo); |
| | glBufferData(GL_ARRAY_BUFFER, 12 * sizeof(Vertex2D), verts, GL_STATIC_DRAW); |
| |
|
| | glGenVertexArrays(1, &(guiItem->vao)); |
| | glBindVertexArray(guiItem->vao); |
| | glEnableVertexAttribArray(0); |
| | glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex2D), (void*)offsetof(Vertex2D, x)); |
| | glEnableVertexAttribArray(1); |
| | glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex2D), (void*)offsetof(Vertex2D, tx)); |
| | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIbo); |
| | glBindVertexArray(0); |
| |
|
| | return true; |
| | } |
| |
|
| | void GuiDisplay::DestroyGlItem(GuiItem* guiItem) |
| | { |
| | GLDELETE_BUFFER((guiItem->vbo)); |
| | GLDELETE_VERTEXARRAY((guiItem->vao)); |
| | } |
| |
|
| | bool GuiDisplay::InitGui() |
| | { |
| | if (guiInitiated) { |
| | return true; |
| | } |
| | |
| | SetupTooltips(); |
| | glGenBuffers(1, &mIbo); |
| | GLshort indices[18] = {0, 2, 3, 0, 3, 1, 4, 6, 7, 4, 7, 5, 8, 10, 11, 8, 11, 9}; |
| | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIbo); |
| | glBufferData(GL_ELEMENT_ARRAY_BUFFER, 18 * sizeof(GLushort), indices, GL_STATIC_DRAW); |
| | TextureLoader tLoader(":/gl_simulator/", guiFileNames, TEX_SIZE); |
| | unsigned int* buffer = tLoader.GetRawData(); |
| | if (buffer == nullptr) { |
| | return false; |
| | } |
| | mTexture.LoadImage(buffer, TEX_SIZE, TEX_SIZE); |
| | for (unsigned int i = 0; i < NUM_GUI_ITEMS; i++) { |
| | guiItems[i].texItem = *tLoader.GetTextureItem(i); |
| | GenerateGlItem(&(guiItems[i])); |
| | } |
| |
|
| | mThumbStartX = guiItems[eGuiItemSlider].posx() - guiItems[eGuiItemThumb].texItem.w / 2; |
| | mThumbMaxMotion = (float)guiItems[eGuiItemSlider].texItem.w; |
| |
|
| | |
| | mShader.CompileShader("GuiDisplay", (char*)VertShader2DTex, (char*)FragShader2dTex); |
| | mShader.UpdateTextureSlot(0); |
| |
|
| | UpdateSimSpeed(1); |
| | UpdateProjection(); |
| | guiInitiated = true; |
| | return true; |
| | } |
| |
|
| | void GuiDisplay::ResetGui() |
| | { |
| | mShader.Destroy(); |
| | for (unsigned int i = 0; i < NUM_GUI_ITEMS; i++) { |
| | DestroyGlItem(&(guiItems[i])); |
| | } |
| | mTexture.DestroyTexture(); |
| | GLDELETE_BUFFER(mIbo); |
| | guiInitiated = false; |
| | } |
| |
|
| | void GuiDisplay::RenderItem(int itemId) |
| | { |
| | GuiItem* item = &(guiItems[itemId]); |
| | if (item->hidden) { |
| | return; |
| | } |
| | mat4x4 model; |
| | mat4x4_translate(model, (float)item->posx(), (float)item->posy(), 0); |
| | mShader.UpdateModelMat(model, nullptr); |
| | if (item == mPressedItem) { |
| | mShader.UpdateObjColor(mPressedColor); |
| | } |
| | else if (item->mouseOver) { |
| | mShader.UpdateObjColor(mHighlightColor); |
| | } |
| | else if (itemId > 1 && item->actionKey == 0) { |
| | mShader.UpdateObjColor(mTextColor); |
| | } |
| | else if (item->flags & GUIITEM_CHECKED) { |
| | mShader.UpdateObjColor(mToggleColor); |
| | } |
| | else { |
| | mShader.UpdateObjColor(mStdColor); |
| | } |
| |
|
| | glBindVertexArray(item->vao); |
| | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIbo); |
| | int nTriangles = (item->flags & GUIITEM_STRETCHED) == 0 ? 6 : 18; |
| | glDrawElements(GL_TRIANGLES, nTriangles, GL_UNSIGNED_SHORT, nullptr); |
| | } |
| |
|
| | void MillSim::GuiDisplay::SetupTooltips() |
| | { |
| | guiItems[eGuiItemPause].toolTip |
| | = QCoreApplication::translate("CAM:Simulator:Tooltips", "Pause simulation", nullptr); |
| | guiItems[eGuiItemPlay].toolTip |
| | = QCoreApplication::translate("CAM:Simulator:Tooltips", "Play simulation", nullptr); |
| | guiItems[eGuiItemSingleStep].toolTip |
| | = QCoreApplication::translate("CAM:Simulator:Tooltips", "Single step simulation", nullptr); |
| | guiItems[eGuiItemSlower].toolTip |
| | = QCoreApplication::translate("CAM:Simulator:Tooltips", "Decrease simulation speed", nullptr); |
| | guiItems[eGuiItemFaster].toolTip |
| | = QCoreApplication::translate("CAM:Simulator:Tooltips", "Increase simulation speed", nullptr); |
| | guiItems[eGuiItemPath].toolTip |
| | = QCoreApplication::translate("CAM:Simulator:Tooltips", "Show/Hide tool path", nullptr); |
| | guiItems[eGuiItemRotate].toolTip = QCoreApplication::translate( |
| | "CAM:Simulator:Tooltips", |
| | "Toggle turn table animation", |
| | nullptr |
| | ); |
| | guiItems[eGuiItemAmbientOclusion].toolTip |
| | = QCoreApplication::translate("CAM:Simulator:Tooltips", "Toggle ambient occlusion", nullptr); |
| | guiItems[eGuiItemView].toolTip = QCoreApplication::translate( |
| | "CAM:Simulator:Tooltips", |
| | "Toggle view simulation/model", |
| | nullptr |
| | ); |
| | guiItems[eGuiItemHome].toolTip |
| | = QCoreApplication::translate("CAM:Simulator:Tooltips", "Reset camera", nullptr); |
| | } |
| |
|
| | void GuiDisplay::MouseCursorPos(int x, int y) |
| | { |
| | GuiItem* prevMouseOver = mMouseOverItem; |
| | mMouseOverItem = nullptr; |
| | for (unsigned int i = 0; i < NUM_GUI_ITEMS; i++) { |
| | GuiItem* g = &(guiItems[i]); |
| | if (g->actionKey == 0) { |
| | continue; |
| | } |
| | bool mouseCursorContained = x > g->posx() && x < (g->posx() + g->texItem.w) && y > g->posy() |
| | && y < (g->posy() + g->texItem.h); |
| |
|
| | g->mouseOver = !g->hidden && mouseCursorContained; |
| |
|
| | if (g->mouseOver) { |
| | mMouseOverItem = g; |
| | } |
| | } |
| | if (mMouseOverItem != prevMouseOver) { |
| | if (mMouseOverItem != nullptr && !mMouseOverItem->toolTip.isEmpty()) { |
| | QPoint pos(x, y); |
| | QPoint globPos = CAMSimulator::DlgCAMSimulator::GetInstance()->mapToGlobal(pos); |
| | QToolTip::showText(globPos, mMouseOverItem->toolTip); |
| | } |
| | else { |
| | QToolTip::hideText(); |
| | } |
| | } |
| | } |
| |
|
| | void MillSim::GuiDisplay::HandleActionItem(GuiItem* guiItem) |
| | { |
| | if (guiItem->actionKey >= ' ') { |
| | if (guiItem->flags & GUIITEM_CHECKABLE) { |
| | guiItem->flags ^= GUIITEM_CHECKED; |
| | } |
| | bool isChecked = (guiItem->flags & GUIITEM_CHECKED) != 0; |
| | mMillSim->HandleGuiAction(guiItem->name, isChecked); |
| | } |
| | } |
| |
|
| | void GuiDisplay::MousePressed(int button, bool isPressed, bool isSimRunning) |
| | { |
| | if (button == MS_MOUSE_LEFT) { |
| | if (isPressed) { |
| | if (mMouseOverItem != nullptr) { |
| | mPressedItem = mMouseOverItem; |
| | HandleActionItem(mPressedItem); |
| | } |
| | } |
| | else |
| | { |
| | UpdatePlayState(isSimRunning); |
| | if (mPressedItem != nullptr) { |
| | MouseCursorPos(mPressedItem->posx() + 1, mPressedItem->posy() + 1); |
| | mPressedItem = nullptr; |
| | } |
| | } |
| | } |
| | } |
| |
|
| | void GuiDisplay::MouseDrag(int , int dx, int ) |
| | { |
| | if (mPressedItem == nullptr) { |
| | return; |
| | } |
| | if (mPressedItem->name == eGuiItemThumb) { |
| | int newx = mPressedItem->posx() + dx; |
| | if (newx < mThumbStartX) { |
| | newx = mThumbStartX; |
| | } |
| | if (newx > ((int)mThumbMaxMotion + mThumbStartX)) { |
| | newx = (int)mThumbMaxMotion + mThumbStartX; |
| | } |
| | if (newx != mPressedItem->posx()) { |
| | mMillSim->SetSimulationStage((float)(newx - mThumbStartX) / mThumbMaxMotion); |
| | mPressedItem->setPosx(newx); |
| | } |
| | } |
| | } |
| |
|
| | void GuiDisplay::UpdatePlayState(bool isRunning) |
| | { |
| | guiItems[eGuiItemPause].hidden = !isRunning; |
| | guiItems[eGuiItemPlay].hidden = isRunning; |
| | } |
| |
|
| | void MillSim::GuiDisplay::UpdateSimSpeed(int speed) |
| | { |
| | guiItems[eGuiItem1].hidden = speed != 1; |
| | guiItems[eGuiItem5].hidden = speed != 5; |
| | guiItems[eGuiItem10].hidden = speed != 10; |
| | guiItems[eGuiItem25].hidden = speed != 25; |
| | guiItems[eGuiItem50].hidden = speed != 50; |
| | } |
| |
|
| | void MillSim::GuiDisplay::HandleKeyPress(int key) |
| | { |
| | for (unsigned int i = 0; i < NUM_GUI_ITEMS; i++) { |
| | GuiItem* g = &(guiItems[i]); |
| | if (g->actionKey == key) { |
| | HandleActionItem(g); |
| | } |
| | } |
| | } |
| |
|
| | bool MillSim::GuiDisplay::IsChecked(eGuiItems item) |
| | { |
| | return (guiItems[item].flags & GUIITEM_CHECKED) != 0; |
| | } |
| |
|
| | void MillSim::GuiDisplay::UpdateWindowScale() |
| | { |
| | UpdateProjection(); |
| | } |
| |
|
| | void GuiDisplay::Render(float progress) |
| | { |
| | if (mPressedItem == nullptr || mPressedItem->name != eGuiItemThumb) { |
| | guiItems[eGuiItemThumb].setPosx((int)(mThumbMaxMotion * progress) + mThumbStartX); |
| | } |
| | glDisable(GL_CULL_FACE); |
| | glDisable(GL_DEPTH_TEST); |
| |
|
| | mTexture.Activate(); |
| | mShader.Activate(); |
| | mShader.UpdateTextureSlot(0); |
| | glEnable(GL_BLEND); |
| | glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); |
| | for (int i = 0; i < (int)NUM_GUI_ITEMS; i++) { |
| | RenderItem(i); |
| | } |
| | } |
| |
|